firefly-compiler 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/.firefly-workspace +1 -0
  2. package/.vscode/settings.json +5 -0
  3. package/LICENSE.txt +21 -0
  4. package/README.md +96 -0
  5. package/bin/firefly.mjs +2 -0
  6. package/compiler/.firefly/package.ff +1 -0
  7. package/compiler/Builder.ff +218 -0
  8. package/compiler/Compiler.ff +241 -0
  9. package/compiler/Dependencies.ff +179 -0
  10. package/compiler/Deriver.ff +647 -0
  11. package/compiler/Dictionaries.ff +205 -0
  12. package/compiler/Environment.ff +166 -0
  13. package/compiler/Inference.ff +1117 -0
  14. package/compiler/JsEmitter.ff +861 -0
  15. package/compiler/JsImporter.ff +56 -0
  16. package/compiler/LspHook.ff +188 -0
  17. package/compiler/Main.ff +237 -0
  18. package/compiler/Parser.ff +1383 -0
  19. package/compiler/Patterns.ff +111 -0
  20. package/compiler/Resolver.ff +620 -0
  21. package/compiler/Substitution.ff +178 -0
  22. package/compiler/Syntax.ff +299 -0
  23. package/compiler/Token.ff +180 -0
  24. package/compiler/Tokenizer.ff +278 -0
  25. package/compiler/Unification.ff +220 -0
  26. package/compiler/Wildcards.ff +50 -0
  27. package/compiler/Workspace.ff +88 -0
  28. package/core/.firefly/package.ff +2 -0
  29. package/core/Any.ff +30 -0
  30. package/core/Array.ff +249 -0
  31. package/core/AssetSystem.ff +61 -0
  32. package/core/Atomic.ff +64 -0
  33. package/core/Bool.ff +13 -0
  34. package/core/BrowserSystem.ff +14 -0
  35. package/core/Buffer.ff +211 -0
  36. package/core/BuildSystem.ff +144 -0
  37. package/core/Channel.ff +131 -0
  38. package/core/Char.ff +18 -0
  39. package/core/Core.ff +58 -0
  40. package/core/Duration.ff +15 -0
  41. package/core/Equal.ff +52 -0
  42. package/core/Error.ff +20 -0
  43. package/core/FileHandle.ff +41 -0
  44. package/core/Float.ff +41 -0
  45. package/core/HttpClient.ff +84 -0
  46. package/core/Instant.ff +9 -0
  47. package/core/Int.ff +61 -0
  48. package/core/IntMap.ff +85 -0
  49. package/core/JsSystem.ff +66 -0
  50. package/core/JsValue.ff +240 -0
  51. package/core/List.ff +440 -0
  52. package/core/Lock.ff +144 -0
  53. package/core/Log.ff +24 -0
  54. package/core/Map.ff +126 -0
  55. package/core/NodeSystem.ff +88 -0
  56. package/core/Nothing.ff +1 -0
  57. package/core/Option.ff +133 -0
  58. package/core/Ordering.ff +157 -0
  59. package/core/Pair.ff +55 -0
  60. package/core/Path.ff +393 -0
  61. package/core/RbMap.ff +216 -0
  62. package/core/Serializable.ff +173 -0
  63. package/core/Set.ff +38 -0
  64. package/core/Show.ff +43 -0
  65. package/core/Stack.ff +263 -0
  66. package/core/Stream.ff +406 -0
  67. package/core/String.ff +175 -0
  68. package/core/StringMap.ff +85 -0
  69. package/core/Task.ff +138 -0
  70. package/core/Try.ff +81 -0
  71. package/core/Unit.ff +3 -0
  72. package/experimental/random/AltGeneric.ff +44 -0
  73. package/experimental/random/Async.ff +68 -0
  74. package/experimental/random/Buffer2.ff +77 -0
  75. package/experimental/random/Cat.ff +12 -0
  76. package/experimental/random/Dictionary.ff +52 -0
  77. package/experimental/random/Example.ff +46 -0
  78. package/experimental/random/Generic.ff +102 -0
  79. package/experimental/random/HappyEyeballs.ff +40 -0
  80. package/experimental/random/HashMap.ff +72 -0
  81. package/experimental/random/IfElseUnit.ff +9 -0
  82. package/experimental/random/InputOutput.ff +23 -0
  83. package/experimental/random/ListVsArray.ff +45 -0
  84. package/experimental/random/Main.ff +44 -0
  85. package/experimental/random/MapTest.ff +67 -0
  86. package/experimental/random/OldTaskSystem.ff +210 -0
  87. package/experimental/random/PatternTest.ff +39 -0
  88. package/experimental/random/Patterns.ff +226 -0
  89. package/experimental/random/ReadBytesTest.ff +10 -0
  90. package/experimental/random/RunLength.ff +65 -0
  91. package/experimental/random/Scrape.ff +51 -0
  92. package/experimental/random/Serialization.ff +217 -0
  93. package/experimental/random/SerializationTest.ff +46 -0
  94. package/experimental/random/Serializer.ff +36 -0
  95. package/experimental/random/StdInOutErr.ff +4 -0
  96. package/experimental/random/Symbols.ff +74 -0
  97. package/experimental/random/Tag.ff +49 -0
  98. package/experimental/random/Tensor.ff +52 -0
  99. package/experimental/random/Try.ff +56 -0
  100. package/experimental/random/Tsv.ff +9 -0
  101. package/experimental/random/TypesAreModules.ff +87 -0
  102. package/experimental/random/blueprints/Blueprint.ff +52 -0
  103. package/experimental/random/blueprints/Main.ff +11 -0
  104. package/experimental/random/blueprints/Pretty.ff +58 -0
  105. package/experimental/random/blueprints/User.ff +64 -0
  106. package/experimental/random/blueprintsystem/BlueprintSystem.ff +48 -0
  107. package/experimental/random/blueprintsystem/Deserialize.ff +53 -0
  108. package/experimental/random/blueprintsystem/ReadJs.ff +13 -0
  109. package/experimental/random/blueprintsystem/User.ff +2 -0
  110. package/experimental/random/kahrs/Kahrs.ff +112 -0
  111. package/experimental/random/kahrs/TestKahrs.ff +22 -0
  112. package/experimental/random/kahrs/TestMap.ff +18 -0
  113. package/experimental/random/streaming/Gzip.ff +3 -0
  114. package/experimental/random/streaming/Main.ff +34 -0
  115. package/experimental/random/streaming/S3Bucket.ff +11 -0
  116. package/experimental/random/streaming/Tar.ff +5 -0
  117. package/experimental/rhymeapp/Main.ff +81 -0
  118. package/experimental/rhymeapp/index.html +14 -0
  119. package/firefly.sh +5 -0
  120. package/fireflysite/Main.ff +13 -0
  121. package/httpserver/.firefly/package.ff +1 -0
  122. package/httpserver/HttpServer.ff +184 -0
  123. package/lsp/.firefly/package.ff +1 -0
  124. package/lsp/CompletionHandler.ff +814 -0
  125. package/lsp/Handler.ff +551 -0
  126. package/lsp/HoverHandler.ff +82 -0
  127. package/lsp/LanguageServer.ff +229 -0
  128. package/lsp/SignatureHelpHandler.ff +55 -0
  129. package/lsp/SymbolHandler.ff +167 -0
  130. package/output/js/ff/compiler/Builder.mjs +483 -0
  131. package/output/js/ff/compiler/Compiler.mjs +410 -0
  132. package/output/js/ff/compiler/Dependencies.mjs +388 -0
  133. package/output/js/ff/compiler/Deriver.mjs +1166 -0
  134. package/output/js/ff/compiler/Dictionaries.mjs +1305 -0
  135. package/output/js/ff/compiler/Environment.mjs +1005 -0
  136. package/output/js/ff/compiler/Inference.mjs +4264 -0
  137. package/output/js/ff/compiler/JsEmitter.mjs +5353 -0
  138. package/output/js/ff/compiler/JsImporter.mjs +262 -0
  139. package/output/js/ff/compiler/LspHook.mjs +789 -0
  140. package/output/js/ff/compiler/Main.mjs +1695 -0
  141. package/output/js/ff/compiler/Parser.mjs +4004 -0
  142. package/output/js/ff/compiler/Patterns.mjs +923 -0
  143. package/output/js/ff/compiler/Resolver.mjs +2303 -0
  144. package/output/js/ff/compiler/Substitution.mjs +1146 -0
  145. package/output/js/ff/compiler/Syntax.mjs +12430 -0
  146. package/output/js/ff/compiler/Token.mjs +3092 -0
  147. package/output/js/ff/compiler/Tokenizer.mjs +589 -0
  148. package/output/js/ff/compiler/Unification.mjs +1748 -0
  149. package/output/js/ff/compiler/Wildcards.mjs +604 -0
  150. package/output/js/ff/compiler/Workspace.mjs +683 -0
  151. package/output/js/ff/core/Any.mjs +139 -0
  152. package/output/js/ff/core/Array.mjs +594 -0
  153. package/output/js/ff/core/AssetSystem.mjs +270 -0
  154. package/output/js/ff/core/Atomic.mjs +186 -0
  155. package/output/js/ff/core/Bool.mjs +141 -0
  156. package/output/js/ff/core/BrowserSystem.mjs +122 -0
  157. package/output/js/ff/core/Buffer.mjs +467 -0
  158. package/output/js/ff/core/BuildSystem.mjs +320 -0
  159. package/output/js/ff/core/Channel.mjs +268 -0
  160. package/output/js/ff/core/Char.mjs +145 -0
  161. package/output/js/ff/core/Core.mjs +300 -0
  162. package/output/js/ff/core/Duration.mjs +112 -0
  163. package/output/js/ff/core/Equal.mjs +175 -0
  164. package/output/js/ff/core/Error.mjs +138 -0
  165. package/output/js/ff/core/FileHandle.mjs +164 -0
  166. package/output/js/ff/core/Float.mjs +214 -0
  167. package/output/js/ff/core/HttpClient.mjs +210 -0
  168. package/output/js/ff/core/Instant.mjs +105 -0
  169. package/output/js/ff/core/Int.mjs +254 -0
  170. package/output/js/ff/core/IntMap.mjs +282 -0
  171. package/output/js/ff/core/JsSystem.mjs +234 -0
  172. package/output/js/ff/core/JsValue.mjs +678 -0
  173. package/output/js/ff/core/List.mjs +2335 -0
  174. package/output/js/ff/core/Lock.mjs +322 -0
  175. package/output/js/ff/core/Log.mjs +159 -0
  176. package/output/js/ff/core/Map.mjs +358 -0
  177. package/output/js/ff/core/NodeSystem.mjs +288 -0
  178. package/output/js/ff/core/Nothing.mjs +100 -0
  179. package/output/js/ff/core/Option.mjs +1002 -0
  180. package/output/js/ff/core/Ordering.mjs +734 -0
  181. package/output/js/ff/core/Pair.mjs +318 -0
  182. package/output/js/ff/core/Path.mjs +768 -0
  183. package/output/js/ff/core/RbMap.mjs +1936 -0
  184. package/output/js/ff/core/Serializable.mjs +434 -0
  185. package/output/js/ff/core/Set.mjs +250 -0
  186. package/output/js/ff/core/Show.mjs +201 -0
  187. package/output/js/ff/core/Stack.mjs +595 -0
  188. package/output/js/ff/core/Stream.mjs +1300 -0
  189. package/output/js/ff/core/String.mjs +433 -0
  190. package/output/js/ff/core/StringMap.mjs +282 -0
  191. package/output/js/ff/core/Task.mjs +345 -0
  192. package/output/js/ff/core/Try.mjs +503 -0
  193. package/output/js/ff/core/Unit.mjs +103 -0
  194. package/package.json +29 -0
  195. package/postgresql/.firefly/include/package-lock.json +250 -0
  196. package/postgresql/.firefly/include/package.json +5 -0
  197. package/postgresql/.firefly/include/prepare.sh +2 -0
  198. package/postgresql/.firefly/package.ff +3 -0
  199. package/postgresql/Pg.ff +530 -0
  200. package/unsafejs/.firefly/package.ff +1 -0
  201. package/unsafejs/UnsafeJs.ff +19 -0
  202. package/vscode/.vscode/launch.json +18 -0
  203. package/vscode/.vscode/tasks.json +33 -0
  204. package/vscode/LICENSE.txt +21 -0
  205. package/vscode/Prepublish.ff +15 -0
  206. package/vscode/README.md +17 -0
  207. package/vscode/client/package-lock.json +544 -0
  208. package/vscode/client/package.json +22 -0
  209. package/vscode/client/src/extension.ts +64 -0
  210. package/vscode/client/tsconfig.json +12 -0
  211. package/vscode/icons/firefly-icon.png +0 -0
  212. package/vscode/icons/firefly-icon.svg +10 -0
  213. package/vscode/icons/firefly-logo-notext.png +0 -0
  214. package/vscode/icons/firefly-logo.png +0 -0
  215. package/vscode/language-configuration.json +39 -0
  216. package/vscode/package-lock.json +3623 -0
  217. package/vscode/package.json +144 -0
  218. package/vscode/snippets-none.json +1 -0
  219. package/vscode/snippets.json +241 -0
  220. package/vscode/syntaxes/firefly.tmLanguage.json +294 -0
  221. package/vscode/tsconfig.json +20 -0
@@ -0,0 +1,1117 @@
1
+ import Syntax
2
+ import Unification
3
+ import Environment
4
+ import Substitution
5
+ import LspHook
6
+
7
+ class Inference(
8
+ unification: Unification
9
+ missing: StringMap[Pair[Instantiated, Option[List[Argument]]]]
10
+ lspHook: LspHook
11
+ )
12
+
13
+ make(modules: List[Module], lspHook: LspHook): Inference {
14
+ Inference(
15
+ unification = Unification.make(modules, attemptFixes = lspHook.isEnabled())
16
+ missing = StringMap.make()
17
+ lspHook = lspHook
18
+ )
19
+ }
20
+
21
+ fail[T](at: Location, message: String): T {
22
+ throw(CompileError(at, message))
23
+ }
24
+
25
+ core(name: String): String {
26
+ "ff:core/" + name + "." + name
27
+ }
28
+
29
+ extend self: Inference {
30
+
31
+ inferModule(module: Module, otherModules: List[Module]): Module {
32
+ let environment = Environment.make(module, otherModules, alreadyFlat = False)
33
+
34
+ let traits = module.traits.map {self.inferTraitDefinition(environment, _)}
35
+ let instances = module.instances.map {self.inferInstanceDefinition(environment, _)}
36
+ let lets = module.lets.map {self.inferLetDefinition(environment, _)}
37
+ let functions = module.functions.map {self.inferFunctionDefinition(environment, _)}
38
+ let extends = module.extends.map {self.inferExtendDefinition(environment, _)}
39
+ let result = module.Module(
40
+ traits = traits
41
+ instances = instances
42
+ extends = extends
43
+ lets = lets
44
+ functions = functions
45
+ )
46
+ let subsititution = Substitution(self.unification.substitution)
47
+ subsititution.substituteModule(result)
48
+ }
49
+
50
+ inferTraitDefinition(environment: Environment, definition: DTrait): DTrait {
51
+ definition.DTrait(
52
+
53
+ )
54
+ }
55
+
56
+ inferInstanceDefinition(environment: Environment, definition: DInstance): DInstance {
57
+ if(self.lspHook.isEnabled() && definition.derived) {definition} else:
58
+ let instances = constraintsToInstances(definition.constraints)
59
+ self.unification.withLocalInstances(instances) {
60
+ let traitName = definition.traitName
61
+ let traitDefinition = environment.traits.get(traitName).else {
62
+ throw(CompileError(definition.at
63
+ "No such trait: " + traitName
64
+ ))
65
+ }
66
+
67
+ if(traitDefinition.generics.size() != definition.typeArguments.size()) {
68
+ throw(CompileError(definition.at
69
+ "Wrong number of type arguments for " + traitName +
70
+ ", expected " + (traitDefinition.generics.size() - 1) +
71
+ ", got " + (definition.typeArguments.size() - 1)
72
+ ))
73
+ }
74
+
75
+ let instantiationMap = traitDefinition.generics.zip(definition.typeArguments).toMap()
76
+
77
+ traitDefinition.methods.each {traitMethod =>
78
+ let found = definition.methods.filter {_.signature.name == traitMethod.name}
79
+ if(found.isEmpty()) {
80
+ throw(CompileError(definition.at
81
+ "Missing instance method: " + traitMethod.name
82
+ ))
83
+ }
84
+ found.dropFirst().each {duplicateMethod =>
85
+ throw(CompileError(duplicateMethod.at
86
+ "Duplicated instance method: " + traitMethod.name
87
+ ))
88
+ }
89
+ }
90
+
91
+ definition.DInstance(
92
+ methods = definition.methods.map {instanceFunction =>
93
+ let methodName = instanceFunction.signature.name
94
+ let traitMethodName = traitName.reverse().dropWhile {_ != '.'}.reverse() + methodName
95
+ let traitMethodScheme = environment.symbols.get(traitMethodName).else {
96
+ throw(CompileError(instanceFunction.at
97
+ "Trait " + traitName + " has no such method: " + methodName
98
+ ))
99
+ }
100
+ let parameters = traitMethodScheme.signature.parameters.map {p =>
101
+ p.Parameter(valueType = self.unification.instantiate(instantiationMap, p.valueType))
102
+ }
103
+ let returnType = self.unification.instantiate(instantiationMap, traitMethodScheme.signature.returnType)
104
+
105
+ instanceFunction.signature.parameters.dropFirst(parameters.size()).each {instanceParameter =>
106
+ throw(CompileError(instanceParameter.at, "Unexpected parameter: " + instanceParameter.name))
107
+ }
108
+
109
+ parameters.dropFirst(instanceFunction.signature.parameters.size()).each {traitParameter =>
110
+ throw(CompileError(instanceFunction.at, "Missing parameter: " + traitParameter.name))
111
+ }
112
+
113
+ parameters.zip(instanceFunction.signature.parameters).each {| Pair(traitParameter, instanceParameter) =>
114
+ self.unification.unify(instanceParameter.valueType.at, traitParameter.valueType, instanceParameter.valueType)
115
+ }
116
+
117
+ self.unification.unify(instanceFunction.signature.returnType.at, returnType, instanceFunction.signature.returnType)
118
+
119
+ if(self.lspHook.isAt(instanceFunction.at) || self.lspHook.isDefinedAt(traitMethodScheme.signature.at)) {
120
+ let symbolHook = SymbolHook(instanceFunction.signature.name, instanceFunction.at, traitMethodScheme.signature.at)
121
+ let h = InferLookupHook(self.unification, environment, instanceFunction.signature.returnType, None, Box(symbolHook), Box(None))
122
+ self.lspHook.emit(h)
123
+ }
124
+
125
+ self.inferFunctionDefinition(environment, instanceFunction)
126
+ }
127
+ )
128
+ }
129
+ }
130
+
131
+ inferLetDefinition(environment: Environment, definition: DLet): DLet {
132
+ let value = self.inferTerm(environment, definition.variableType, definition.value)
133
+ definition.DLet(
134
+ value = value
135
+ )
136
+ }
137
+
138
+ inferExtendDefinition(environment: Environment, definition: DExtend): DExtend {
139
+ let selfParameter = Parameter(
140
+ at = definition.at
141
+ mutable = False
142
+ name = definition.name
143
+ valueType = definition.type
144
+ default = None
145
+ )
146
+ let functions = definition.methods.map {method =>
147
+ let signature = method.signature.Signature(
148
+ generics = [...definition.generics, ...method.signature.generics]
149
+ constraints = [...definition.constraints, ...method.signature.constraints]
150
+ parameters = [selfParameter, ...method.signature.parameters]
151
+ )
152
+ let body = method.body.mapFirefly {lambda =>
153
+ lambda.Lambda(
154
+ cases = lambda.cases.map {case =>
155
+ case.MatchCase(
156
+ patterns = [PVariable(method.at, None), ...case.patterns]
157
+ )
158
+ }
159
+ )
160
+ }
161
+ let function = method.DFunction(
162
+ signature = signature
163
+ body = body
164
+ )
165
+ self.inferFunctionDefinition(environment.Environment(selfVariable = Some(definition.name)), function)
166
+ }
167
+ definition.DExtend(
168
+ methods = functions
169
+ )
170
+ }
171
+
172
+ inferFunctionDefinition(environment: Environment, definition: DFunction): DFunction {
173
+ if(self.lspHook.isAt(definition.at)) {
174
+ self.lspHook.emit(
175
+ InferFunctionDefinitionHook(self.unification, environment, definition, self.missing)
176
+ )
177
+ }
178
+ let parameters = definition.signature.parameters.map {p =>
179
+ let noEffect = TConstructor(p.at, "ff:core/Nothing.Nothing", [])
180
+ let scheme = Scheme(True, False, False, False
181
+ Signature(p.at, p.name, False, [], [], [], p.valueType, noEffect)
182
+ )
183
+ if(self.lspHook.isAt(p.at)) {
184
+ self.lspHook.emit(
185
+ InferParameterHook(self.unification, environment, p, self.missing)
186
+ )
187
+ }
188
+ Pair(p.name, scheme)
189
+ }
190
+ let parameterMap = parameters.toMap()
191
+ let environment2 = environment.Environment(symbols = environment.symbols.addAll(parameterMap))
192
+ let parameterTypes = parameters.map {_.second.signature.returnType}
193
+ let functionType = TConstructor(
194
+ definition.at
195
+ "Function$" + parameterTypes.size()
196
+ [definition.signature.effect, ...parameterTypes, definition.signature.returnType]
197
+ )
198
+ let instances = constraintsToInstances(definition.signature.constraints)
199
+ self.unification.withLocalInstances(instances) {
200
+ definition.DFunction(
201
+ body = definition.body.mapFirefly {self.inferLambda(environment2, functionType, _)}
202
+ )
203
+ }
204
+ }
205
+
206
+ inferLambda(environment: Environment, expected: Type, lambda: Lambda): Lambda {
207
+ let unitName = core("Unit")
208
+ let returnsUnit = self.unification.substitute(expected).{
209
+ | TConstructor(_, name, ts) {name.startsWith("Function$")} =>
210
+ ts.grabLast().{
211
+ | TConstructor(_, n, []) => n == unitName
212
+ | _ => False
213
+ }
214
+ | _ => False
215
+ }
216
+ let cases = if(!returnsUnit) {lambda.cases} else {
217
+ lambda.cases.map {c =>
218
+ c.MatchCase(body = ESequential(c.at, c.body, EVariant(c.at, unitName, [], None)))
219
+ }
220
+ }
221
+ let newEnvironment = environment.Environment(effect = lambda.effect)
222
+ lambda.Lambda(
223
+ cases = cases.map {self.inferMatchCase(newEnvironment, expected, _)}
224
+ )
225
+ }
226
+
227
+ inferMatchCase(environment: Environment, expected: Type, case: MatchCase): MatchCase {
228
+ let parameterTypes = case.patterns.map {self.unification.freshUnificationVariable(_.at)}
229
+ let returnType = self.unification.freshUnificationVariable(case.at)
230
+ let functionType = TConstructor(
231
+ case.at
232
+ "Function$" + case.patterns.size()
233
+ [environment.effect, ...parameterTypes, returnType]
234
+ )
235
+ self.unification.unify(case.at, expected, functionType)
236
+ let environment1 = parameterTypes.zip(case.patterns).foldLeft(environment) {| environment1, Pair(t, c) =>
237
+ let symbols = self.inferPattern(environment, t, c).mapValues {| name, Pair(at, type) =>
238
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
239
+ Scheme(True, False, False, False, Signature(at, name, False, [], [], [], type, noEffect))
240
+ }
241
+ environment.Environment(symbols = environment1.symbols.addAll(symbols))
242
+ }
243
+ mutable guards = []
244
+ let environment3 = case.guards.foldLeft(environment1) {environment2, g =>
245
+ let guardType = self.unification.freshUnificationVariable(g.at)
246
+ let guardTerm = self.inferTerm(environment2, guardType, g.term)
247
+ let symbols = self.inferPattern(environment2, guardType, g.pattern).mapValues {| name, Pair(at, type) =>
248
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
249
+ Scheme(True, False, False, False, Signature(at, name, False, [], [], [], type, noEffect))
250
+ }
251
+ guards = [g.MatchGuard(term = guardTerm), ...guards]
252
+ environment2.Environment(symbols = environment2.symbols.addAll(symbols))
253
+ }
254
+ case.MatchCase(
255
+ body = self.inferTerm(environment3, returnType, case.body)
256
+ guards = guards.reverse()
257
+ )
258
+ }
259
+
260
+ inferPattern(environment: Environment, expected: Type, pattern: MatchPattern): Map[String, Pair[Location, Type]] {
261
+ if(self.lspHook.isEnabled()) {
262
+ if(pattern.{
263
+ | PVariantAs(at, _, variableAt, _) =>
264
+ self.lspHook.isAt(at) || self.lspHook.isAt(variableAt) || self.lspHook.isDefinedAt(variableAt)
265
+ | PAlias(at, _, _) =>
266
+ self.lspHook.isAt(at) || self.lspHook.isDefinedAt(at)
267
+ | _ =>
268
+ self.lspHook.isAt(pattern.at)
269
+ }) {
270
+ self.lspHook.emit(
271
+ InferPatternHook(self.unification, environment, expected, pattern)
272
+ )
273
+ }
274
+ }
275
+ function literal(coreTypeName: String): Map[String, Pair[Location, Type]] {
276
+ self.unification.unify(pattern.at, expected, TConstructor(pattern.at, core(coreTypeName), []))
277
+ Map.empty()
278
+ }
279
+ pattern.{
280
+ | PString _ =>
281
+ literal("String")
282
+ | PInt _ =>
283
+ literal("Int")
284
+ | PChar _ =>
285
+ literal("Char")
286
+ | PVariable(at, None) =>
287
+ Map.empty()
288
+ | PVariable(at, Some(name)) =>
289
+ [Pair(name, Pair(at, expected))].toMap()
290
+ | PAlias(at, pattern, variable) =>
291
+ self.inferPattern(environment, expected, pattern).add(variable, Pair(at, expected))
292
+ | PVariantAs(at, name, variableAt, variableOption) =>
293
+ let instantiated = self.lookup(environment, expected, at, name, [], None).else {
294
+ throw(CompileError(at, "No such variant: " + name))
295
+ }
296
+ if(instantiated.scheme.isNewtype) {
297
+ throw(CompileError(at, "This kind of pattern is not allowed for newtypes"))
298
+ }
299
+ self.unification.unify(at, expected, instantiated.scheme.signature.returnType)
300
+ let parameters = instantiated.scheme.signature.parameters.sortBy {_.name}
301
+ let recordType =
302
+ TConstructor(at, "Record$" + parameters.map {_.name}.join("$"), parameters.map {_.valueType})
303
+ variableOption.toList().map {Pair(_, Pair(variableAt, recordType))}.toMap()
304
+ | PVariant(at, name, patterns) =>
305
+ let instantiated = self.lookup(environment, expected, at, name, [], None).else {
306
+ throw(CompileError(at, "No such variant: " + name))
307
+ }
308
+ self.unification.unify(at, expected, instantiated.scheme.signature.returnType)
309
+ if(patterns.size() != instantiated.scheme.signature.parameters.size() && !self.lspHook.isEnabled()) {
310
+ throw(CompileError(at, "Wrong number of subpatterns, expected " +
311
+ instantiated.scheme.signature.parameters.size() + ", got " + patterns.size() + "."
312
+ ))
313
+ }
314
+ patterns.zip(instantiated.scheme.signature.parameters).map {| Pair(pattern, parameter) =>
315
+ self.inferPattern(environment, parameter.valueType, pattern)
316
+ }.foldLeft(Map.empty[String, Pair[Location, Type]]()) {_.addAll(_)}
317
+ }
318
+ }
319
+
320
+ inferTerm(environment: Environment, expected: Type, term: Term): Term {
321
+ let hookRecordTypeBox = if(self.lspHook.isAt(term.at)) {
322
+ let box = Box(None)
323
+ self.lspHook.emit(
324
+ InferTermHook(self.unification, environment, expected, term, box, self.missing)
325
+ )
326
+ box
327
+ }
328
+ function literal(coreTypeName: String): Term {
329
+ self.unification.unify(term.at, expected, TConstructor(term.at, core(coreTypeName), []))
330
+ term
331
+ }
332
+ term.{
333
+ | EString _ => literal("String")
334
+ | EChar _ => literal("Char")
335
+ | EInt _ => literal("Int")
336
+ | EFloat _ => literal("Float")
337
+ | EVariable e =>
338
+ self.lookup(environment, expected, e.at, e.name, [], None).map {instantiated =>
339
+ if(instantiated.scheme.isVariable) {
340
+ self.unification.unify(e.at, expected, instantiated.scheme.signature.returnType)
341
+ term
342
+ } else {
343
+ self.inferEtaExpansion(
344
+ environment
345
+ expected
346
+ e.at
347
+ instantiated.scheme.signature
348
+ term
349
+ )
350
+ }
351
+ }.else {
352
+ throw(CompileError(e.at, "Symbol not in scope: " + e.name))
353
+ }
354
+ | EField e =>
355
+ let recordType = self.unification.freshUnificationVariable(e.at)
356
+ if(self.lspHook.isAt(term.at)) {
357
+ hookRecordTypeBox.each {_.value = Some(recordType)}
358
+ }
359
+ let record = self.inferTerm(environment, recordType, e.record)
360
+ self.unification.substitute(recordType).{
361
+ | TConstructor(_, name, typeArguments)@t {name.startsWith("Record$")} =>
362
+ if(self.lspHook.isAt(e.at)) {
363
+ let symbolHook = SymbolHook(e.field, e.at, e.at)
364
+ let noEffect = self.unification.freshUnificationVariable(e.at)
365
+ self.lspHook.emit(
366
+ InferRecordFieldHook(self.unification, environment, expected, t, e.field)
367
+ )
368
+ }
369
+ let fieldNames = name.split('$').toList().dropFirst(1)
370
+ fieldNames.pairs().find {_.second == e.field}.map {_.first}.map {index =>
371
+ let t1 = typeArguments.grab(index)
372
+ self.unification.unify(e.at, expected, t1)
373
+ e.EField(record = record)
374
+ }.elseIf {self.lspHook.isEnabled()} {
375
+ term
376
+ }.else {
377
+ throw(CompileError(e.at, "No such field " + e.field + " on type: " + t.show([])))
378
+ }
379
+ | TConstructor(_, name, typeArguments)@t =>
380
+ let memberPrefix = name + "_"
381
+ let memberName = memberPrefix + e.field
382
+ self.lookup(environment, expected, e.at, memberName, typeArguments, None).{
383
+ | Some(instantiated) {!instantiated.scheme.isVariable} =>
384
+ let signature = instantiated.scheme.signature.Signature(
385
+ // Drop self for eta expansion
386
+ parameters = instantiated.scheme.signature.parameters.dropFirst(1)
387
+ )
388
+ self.unification.unify(
389
+ e.at
390
+ recordType
391
+ instantiated.scheme.signature.parameters.grab(0).valueType
392
+ )
393
+ self.inferEtaExpansion(environment, expected, e.at, signature, term)
394
+ | Some(instantiated) =>
395
+ /*self.unification.unify(
396
+ e.at,
397
+ recordType,
398
+ instantiated.scheme.signature.parameters.grab(0).valueType
399
+ )*/
400
+ self.unification.unify(e.at, expected, instantiated.scheme.signature.returnType)
401
+ e.EField(newtype = instantiated.scheme.isNewtype, record = record)
402
+ | None =>
403
+ throw(CompileError(e.at, "No such field " + e.field + " on type: " + t.show([])))
404
+ }
405
+ | TVariable(_, _) {self.lspHook.isEnabled()} =>
406
+ term
407
+ | TVariable(_, index) =>
408
+ throw(CompileError(e.at, "No such field " + e.field + " on unknown type: $" + index))
409
+ }
410
+ | EWildcard e =>
411
+ self.lookup(environment, expected, e.at, "_w" + e.index, [], None).map {instantiated =>
412
+ self.unification.unify(e.at, expected, instantiated.scheme.signature.returnType)
413
+ term
414
+ }.grab()
415
+ | EList(at, t, items) =>
416
+ let listType = TConstructor(term.at, core("List"), [t])
417
+ self.unification.unify(at, expected, listType)
418
+ EList(at, t, items.map {| Pair(item, spread) =>
419
+ Pair(self.inferTerm(environment, if(spread) {listType} else {t}, item), spread)
420
+ })
421
+ | ESequential(at, before, after) =>
422
+ if(self.lspHook.isAt(before.at)) {
423
+ self.lspHook.emit(
424
+ InferSequentialStartHook(self.unification, term, self.missing)
425
+ )
426
+ }
427
+ let newExpected = self.unification.freshUnificationVariable(at)
428
+ before.{
429
+ | EPipe(at1, value, effect1, ELambda(at2, Lambda(at3, effect3, cases))) =>
430
+ let e = EVariant(at, "ff:core/Unit.Unit", [], None)
431
+ let newCases = cases.map {case => case.MatchCase(body = ESequential(case.at, case.body, e))}
432
+ let newPipe = EPipe(at1, value, effect1, ELambda(at2, Lambda(at3, effect3, newCases)))
433
+ after.{
434
+ | EVariant(at, "ff:core/Unit.Unit", _, _) =>
435
+ let unitType = TConstructor(at, core("Unit"), [])
436
+ self.unification.unify(at, expected, unitType)
437
+ self.inferTerm(environment, newExpected, newPipe)
438
+ | _ =>
439
+ ESequential(
440
+ at = at
441
+ before = self.inferTerm(environment, newExpected, newPipe)
442
+ after = self.inferTerm(environment, expected, after)
443
+ )
444
+ }
445
+ | _ =>
446
+ ESequential(
447
+ at = at
448
+ before = self.inferTerm(environment, newExpected, before)
449
+ after = self.inferTerm(environment, expected, after)
450
+ )
451
+ }
452
+ | ELet e =>
453
+ let noEffect = TConstructor(e.at, "ff:core/Nothing.Nothing", [])
454
+ let scheme = Scheme(True, e.mutable, False, False
455
+ Signature(e.at, e.name, False, [], [], [], e.valueType, noEffect)
456
+ )
457
+ let environment2 = environment.Environment(symbols = environment.symbols.add(e.name, scheme))
458
+ e.ELet(
459
+ value = self.inferTerm(environment, e.valueType, e.value)
460
+ body = self.inferTerm(environment2, expected, e.body)
461
+ )
462
+ | ELambda(at, l) =>
463
+ l.cases.{
464
+ | [MatchCase(_, [], [], EVariable(insideAt, ""))] {self.lspHook.isAt(insideAt)} =>
465
+ self.lspHook.emit(InferLambdaStartHook(self.unification, environment, expected))
466
+ | [MatchCase(_, [], [],
467
+ ESequential(_, EVariable(insideAt, ""), EVariant(_, "ff:core/Unit.Unit", _, _))
468
+ )] {self.lspHook.isAt(insideAt)} =>
469
+ self.lspHook.emit(InferLambdaStartHook(self.unification, environment, expected))
470
+ | _ =>
471
+ }
472
+ let lambda = self.inferLambda(environment, expected, l)
473
+ ELambda(at, lambda)
474
+ | EVariant e =>
475
+ let instantiated = self.lookup(environment, expected, e.at, e.name, e.typeArguments, e.arguments).else {
476
+ throw(CompileError(e.at, "Symbol not in scope: " + e.name))
477
+ }
478
+ self.unification.unify(e.at, expected, instantiated.scheme.signature.returnType)
479
+ let arguments = e.arguments.map {
480
+ self.inferArguments(e.at, e.name, environment, instantiated.scheme.signature.parameters, _)
481
+ }
482
+ e.EVariant(
483
+ typeArguments = instantiated.typeArguments.map {_.second}
484
+ arguments = arguments
485
+ )
486
+ | EVariantIs e =>
487
+ let instantiated = self.lookup(environment, expected, e.at, e.name, e.typeArguments, None).else {
488
+ throw(CompileError(e.at, "Symbol not in scope: " + e.name))
489
+ }
490
+ let parameters = instantiated.scheme.signature.parameters.sortBy {_.name}
491
+ let recordType =
492
+ TConstructor(e.at, "Record$" + parameters.map {_.name}.join("$"), parameters.map {_.valueType})
493
+ let functionType = TConstructor(e.at, "Function$1", [
494
+ self.unification.freshUnificationVariable(e.at)
495
+ instantiated.scheme.signature.returnType
496
+ TConstructor(e.at, core("Option"), [recordType])
497
+ ])
498
+ self.unification.unify(e.at, expected, functionType)
499
+ e.EVariantIs(
500
+ typeArguments = instantiated.typeArguments.map {_.second}
501
+ )
502
+ | ECopy e =>
503
+ let scheme = self.lookup(environment, expected, e.at, e.name, [], None).else {
504
+ throw(CompileError(e.at, "Symbol not in scope: " + e.name))
505
+ }.scheme
506
+ if(scheme.isNewtype) {
507
+ throw(CompileError(e.at, "Newtypes can't be copied"))
508
+ }
509
+ let signature = scheme.signature
510
+ if(self.lspHook.isEnabled()) {
511
+ e.arguments.pairs().each {| Pair(i, a) =>
512
+ let p = signature.parameters.find {_.name == a.name}
513
+ if(self.lspHook.isAt(a.at) || p.any {self.lspHook.isDefinedAt(_.at)}) {
514
+ let arguments = e.arguments.map {f => f.Argument(name = Some(f.name))}
515
+ self.lspHook.emit(
516
+ InferArgumentHook(
517
+ self.unification, environment
518
+ True, term.at, e.name, signature.parameters, arguments, i
519
+ )
520
+ )
521
+ }
522
+ }
523
+ }
524
+ let parameterNames = signature.parameters.map {_.name}
525
+ e.arguments.find {a => !parameterNames.any {_ == a.name}}.each {
526
+ | Field(at, name, value) => throw(CompileError(at, "Unknown parameter: " + name))
527
+ }
528
+ let arguments = parameterNames.map {name =>
529
+ e.arguments.find {_.name == name}.map {
530
+ | Field(at, _, value) => Argument(at, Some(name), value)
531
+ }.else {
532
+ let at = e.at.Location(file = e.at.file + "/<copy>")
533
+ Argument(at, Some(name), EField(at, False, EVariable(at, "_c"), name))
534
+ }
535
+ }
536
+ let body = EVariant(e.at, e.name, [], Some(arguments))
537
+ let effect = self.unification.freshUnificationVariable(e.at)
538
+ let e1 = EPipe(e.at, e.record, effect
539
+ ELambda(e.at, Lambda(e.at, effect, [MatchCase(e.at, [PVariable(e.at, Some("_c"))], [], body)]))
540
+ )
541
+ self.inferTerm(environment, expected, e1)
542
+ | EPipe e =>
543
+ let valueType = self.unification.freshUnificationVariable(e.at)
544
+ let functionType = TConstructor(e.at, "Function$1", [
545
+ e.effect
546
+ valueType
547
+ expected
548
+ ])
549
+ let value = self.inferTerm(environment, valueType, e.value)
550
+ let function = self.inferTerm(environment, functionType, e.function)
551
+ self.unification.affect(term.at, e.effect, environment.effect)
552
+ e.EPipe(
553
+ value = value
554
+ function = function
555
+ )
556
+ | ECall e =>
557
+ if((self.lspHook.isEnabled()) && e.target.{| StaticCall _ => True | _ => False}) {term} else:
558
+ let call = e.target.{
559
+ | DynamicCall call => call
560
+ | StaticCall _ => fail(e.at, "Internal error: Static calls not expected in the Inference phase")
561
+ }
562
+ call.function.{
563
+ | EVariable(variableAt, x) =>
564
+ if(x.first().any {c => c != '_' && !c.isAsciiLetter()}) {
565
+ self.inferOperator(environment, expected, x, term)
566
+ } else {
567
+ self.lookup(environment, expected, e.at, x, e.typeArguments, Some(e.arguments)).{
568
+ | Some(instantiated) =>
569
+ if(instantiated.scheme.isVariable) {
570
+ self.inferLambdaCall(environment, expected, term)
571
+ } else {
572
+ let signature = instantiated.scheme.signature
573
+ self.inferFunctionCall(
574
+ environment
575
+ expected
576
+ signature
577
+ instantiated.scheme.isTraitMethod
578
+ instantiated.typeArguments
579
+ term
580
+ x
581
+ )
582
+ }
583
+ | None =>
584
+ throw(CompileError(variableAt, "No such function: " + x))
585
+ }
586
+ }
587
+ | EField f =>
588
+ let recordType = self.unification.freshUnificationVariable(f.at)
589
+ if(self.lspHook.isAt(term.at)) {
590
+ hookRecordTypeBox.each {_.value = Some(recordType)}
591
+ }
592
+ let record = self.inferTerm(environment, recordType, f.record)
593
+ let e2 = e.ECall(target = call.DynamicCall(function = f.EField(record = record)))
594
+ self.unification.substitute(recordType).{
595
+ | TConstructor(_, name, _)@t =>
596
+ let methodName = name + "_" + f.field
597
+ let arguments = [Argument(f.record.at, None, f.record), ...e.arguments]
598
+ self.lookup(environment, expected, f.at, methodName, [], Some(arguments)).{
599
+ | Some(instantiated) {!instantiated.scheme.isVariable} =>
600
+ self.inferMethodCall(
601
+ environment
602
+ expected
603
+ instantiated.scheme.signature
604
+ instantiated.typeArguments
605
+ e2
606
+ record
607
+ recordType
608
+ methodName
609
+ )
610
+ | Some(instantiated) =>
611
+ self.inferLambdaCall(environment, expected, e2)
612
+ | None =>
613
+ throw(CompileError(f.at
614
+ "No such field " + f.field + " on type: " + t.show([])
615
+ ))
616
+ }
617
+ | TVariable _ {self.lspHook.isEnabled()} =>
618
+ self.inferLambdaCall(environment, expected, e2)
619
+ | TVariable(_, index) =>
620
+ throw(CompileError(f.at
621
+ "No such field " + f.field + " on unknown type: $" + index
622
+ ))
623
+ }
624
+ | _ =>
625
+ self.inferLambdaCall(environment, expected, term)
626
+ }
627
+ | ERecord e =>
628
+ let fields = e.fields.sortBy {_.name}
629
+ let fieldTypes = fields.map {self.unification.freshUnificationVariable(_.at)}
630
+ let recordType =
631
+ TConstructor(e.at, "Record$" + fields.map {_.name}.join("$"), fieldTypes)
632
+ self.unification.unify(e.at, expected, recordType)
633
+ let newFields = fields.zip(fieldTypes).map {| Pair(field, t) =>
634
+ field.Field(value = self.inferTerm(environment, t, field.value))
635
+ }
636
+ e.ERecord(
637
+ fields = newFields
638
+ )
639
+ | EFunctions(at, functions, body) =>
640
+ let functionMap = functions.map {f =>
641
+ let scheme = Scheme(False, False, False, False, f.signature)
642
+ Pair(f.signature.name, scheme)
643
+ }.toMap()
644
+ let environment2 = environment.Environment(symbols = environment.symbols.addAll(functionMap))
645
+ let newFunctions = functions.map {self.inferFunctionDefinition(environment2, _)}
646
+ let newBody = self.inferTerm(environment2, expected, body)
647
+ EFunctions(
648
+ at = at
649
+ functions = newFunctions
650
+ body = newBody
651
+ )
652
+ | EAssign e =>
653
+ self.lookup(environment, expected, e.at, e.variable, [], None).map {instantiated =>
654
+ if(instantiated.scheme.isMutable || self.lspHook.isEnabled()) {
655
+ let value = self.inferAssignment(
656
+ environment = environment
657
+ expected = expected
658
+ at = e.at
659
+ operator = e.operator
660
+ value = e.value
661
+ signature = instantiated.scheme.signature
662
+ )
663
+ e.EAssign(
664
+ value = value
665
+ )
666
+ } else {
667
+ throw(CompileError(e.at, "Symbol is not mutable: " + e.variable))
668
+ }
669
+ } else {
670
+ throw(CompileError(e.at, "Symbol not in scope: " + e.variable))
671
+ }
672
+ | EAssignField e =>
673
+ let recordType = self.unification.freshUnificationVariable(e.at)
674
+ let record = self.inferTerm(environment, recordType, e.record)
675
+ self.unification.substitute(recordType).{
676
+ | TConstructor(_, name, typeArguments)@t {name.startsWith("Record$")} =>
677
+ throw(CompileError(e.at, "Can't assign fields of anonymous records: " + e.field))
678
+ | TConstructor(_, name, typeArguments)@t =>
679
+ let methodName = name + "_" + e.field
680
+ self.lookup(environment, expected, e.at, methodName, typeArguments, None).{
681
+ | Some(instantiated) {instantiated.scheme.isMutable || self.lspHook.isEnabled()} =>
682
+ let value = self.inferAssignment(
683
+ environment = environment
684
+ expected = expected
685
+ at = e.at
686
+ operator = e.operator
687
+ value = e.value
688
+ signature = instantiated.scheme.signature
689
+ )
690
+ e.EAssignField(
691
+ record = record
692
+ value = value
693
+ )
694
+ | Some(instantiated) =>
695
+ throw(CompileError(e.at
696
+ "Can't assign an immutable field " + e.field + " on type: " + t.show([])
697
+ ))
698
+ | None =>
699
+ throw(CompileError(e.at, "No such field " + e.field + " on type: " + t.show([])))
700
+ }
701
+ | TVariable(_, _) {self.lspHook.isEnabled()} =>
702
+ term
703
+ | TVariable(_, index) =>
704
+ throw(CompileError(e.at, "No such field " + e.field + " on unknown type: $" + index))
705
+ }
706
+ }
707
+ }
708
+
709
+ inferAssignment(
710
+ environment: Environment
711
+ expected: Type
712
+ at: Location
713
+ operator: String
714
+ value: Term
715
+ signature: Signature
716
+ ): Term {
717
+ let t = signature.returnType
718
+ if(operator == "+" || operator == "-") {
719
+ self.unification.unify(at, t, TConstructor(at, core("Int"), []))
720
+ } elseIf {operator != ""} {
721
+ throw(CompileError(at, "Only +=, -= and = assignments are supported. Got: " + operator + "="))
722
+ }
723
+ let newValue = self.inferTerm(environment, t, value)
724
+ self.unification.unify(at, expected, TConstructor(at, core("Unit"), []))
725
+ newValue
726
+ }
727
+
728
+ inferMethodCall(
729
+ environment: Environment
730
+ expected: Type
731
+ signature: Signature
732
+ instantiation: List[Pair[String, Type]]
733
+ term: Term
734
+ record: Term
735
+ recordType: Type
736
+ name: String
737
+ ): Term {
738
+ let e = term.{| ECall e => e | _ => fail(term.at, "Call expected")}
739
+ let call = e.target.{
740
+ | DynamicCall call => call
741
+ | StaticCall _ => fail(e.at, "Internal error: Static calls not expected in inferMethodCall")
742
+ }
743
+ let selfParameter = signature.parameters.grabFirst()
744
+ let selfArgument = Argument(record.at, Some(selfParameter.name), record) // Be careful not to infer again
745
+ self.unification.unify(term.at, expected, signature.returnType)
746
+ self.unification.unify(term.at, selfParameter.valueType, recordType)
747
+ let arguments = self.inferArguments(term.at, name, environment, signature.parameters.dropFirst(), e.arguments)
748
+ self.unification.affect(term.at, signature.effect, environment.effect)
749
+ e.ECall(
750
+ target = StaticCall(name, instanceCall = False, tailCall = call.tailCall)
751
+ typeArguments = instantiation.map {_.second}
752
+ arguments = [selfArgument, ...arguments]
753
+ effect = signature.effect
754
+ )
755
+ }
756
+
757
+ inferFunctionCall(
758
+ environment: Environment
759
+ expected: Type
760
+ signature: Signature
761
+ instanceCall: Bool
762
+ instantiation: List[Pair[String, Type]]
763
+ term: Term
764
+ name: String
765
+ ): Term {
766
+ let e = term.{| ECall e => e | _ => fail(term.at, "Call expected")}
767
+ let call = e.target.{
768
+ | DynamicCall call => call
769
+ | StaticCall _ => fail(e.at, "Internal error: Static calls not expected in inferFunctionCall")
770
+ }
771
+ self.unification.unify(e.at, expected, signature.returnType)
772
+ let arguments = self.inferArguments(e.at, name, environment, signature.parameters, e.arguments)
773
+ self.unification.affect(term.at, signature.effect, environment.effect)
774
+ e.ECall(
775
+ target = StaticCall(name, instanceCall = instanceCall, tailCall = call.tailCall)
776
+ typeArguments = instantiation.map {_.second}
777
+ arguments = arguments
778
+ effect = signature.effect
779
+ )
780
+ }
781
+
782
+ inferLambdaCall(environment: Environment, expected: Type, term: Term): Term {
783
+ let e = term.{| ECall e => e | _ => fail(term.at, "Call expected")}
784
+ let call = e.target.{
785
+ | DynamicCall call {!call.tailCall} => call
786
+ | DynamicCall _ => throw(CompileError(e.at, "Tailcalls not supported on lambda functions"))
787
+ | StaticCall _ => fail(e.at, "Internal error: Static calls not expected in inferLambdaCall")
788
+ }
789
+ let effect = self.unification.freshUnificationVariable(term.at)
790
+ let argumentTypes = e.arguments.map {self.unification.freshUnificationVariable(_.at)}
791
+ let functionType = TConstructor(e.at, "Function$" + e.arguments.size(), [
792
+ effect
793
+ ...argumentTypes
794
+ expected
795
+ ])
796
+ let function = self.inferTerm(environment, functionType, call.function)
797
+ let arguments = e.arguments.zip(argumentTypes).map {| Pair(argument, t) =>
798
+ argument.name.each {name =>
799
+ throw(CompileError(argument.at, "Named argument not allowed here: " + name))
800
+ }
801
+ argument.Argument(value = self.inferTerm(environment, t, argument.value))
802
+ }
803
+ e.typeArguments.first().each {typeArgument =>
804
+ throw(CompileError(typeArgument.at, "Type arguments not allowed here"))
805
+ }
806
+ self.unification.affect(term.at, effect, environment.effect)
807
+ e.ECall(
808
+ target = call.DynamicCall(function = function)
809
+ typeArguments = []
810
+ arguments = arguments
811
+ effect = effect
812
+ )
813
+ }
814
+
815
+ inferOperator(environment: Environment, expected: Type, operator: String, term: Term): Term {
816
+ let e = term.{| ECall e => e | _ => fail(term.at, "Call expected") }
817
+ let target = StaticCall(operator, instanceCall = False, tailCall = False)
818
+ e.arguments.{
819
+ | [a1] {
820
+ operator == "!"
821
+ } =>
822
+ let t = TConstructor(e.at, core("Bool"), [])
823
+ let e1 = self.inferTerm(environment, t, a1.value)
824
+ self.unification.unify(e.at, expected, t)
825
+ e.ECall(target = target, arguments = [a1.Argument(value = e1)])
826
+ | [a1] {
827
+ operator == "-"
828
+ } =>
829
+ let t1 = self.unification.freshUnificationVariable(e.at)
830
+ let e1 = self.inferTerm(environment, t1, a1.value)
831
+ self.unification.substitute(t1).{
832
+ | TConstructor(_, name, []) {name == core("Float")} =>
833
+ self.unification.unify(e.at, expected, t1)
834
+ | TConstructor(_, name, []) {name == core("Int")} =>
835
+ self.unification.unify(e.at, expected, t1)
836
+ | _ {self.lspHook.isEnabled()} =>
837
+ | _ =>
838
+ throw(CompileError(e.at, "Operators on unknown types not currently supported"))
839
+ }
840
+ e.ECall(target = target, arguments = [a1.Argument(value = e1)])
841
+ | [a1, a2] {
842
+ operator == "||" || operator == "&&"
843
+ } =>
844
+ let t = TConstructor(e.at, core("Bool"), [])
845
+ let e1 = self.inferTerm(environment, t, a1.value)
846
+ let e2 = self.inferTerm(environment, t, a2.value)
847
+ self.unification.unify(e.at, expected, t)
848
+ e.ECall(target = target, arguments = [a1.Argument(value = e1), a2.Argument(value = e2)])
849
+ | [a1, a2] {
850
+ operator == "===" || operator == "!==" // For internal use
851
+ } =>
852
+ let t1 = self.unification.freshUnificationVariable(e.at)
853
+ let e1 = self.inferTerm(environment, t1, a1.value)
854
+ let e2 = self.inferTerm(environment, t1, a2.value)
855
+ self.unification.unify(e.at, expected, TConstructor(e.at, core("Bool"), []))
856
+ e.ECall(target = target, arguments = [a1.Argument(value = e1), a2.Argument(value = e2)])
857
+ | [a1, a2] {
858
+ operator == "+" || operator == "-" ||
859
+ operator == "*" || operator == "/" || operator == "%" ||
860
+ operator == "^"
861
+ } =>
862
+ let t1 = self.unification.freshUnificationVariable(e.at)
863
+ let t2 = self.unification.freshUnificationVariable(e.at)
864
+ let e1 = self.inferTerm(environment, t1, a1.value)
865
+ let e2 = self.inferTerm(environment, t2, a2.value)
866
+ let magic: Type => Option[String] = {t =>
867
+ self.unification.substitute(t).{
868
+ | TConstructor(_, name, []) {name == core("Float")} => Some("Float")
869
+ | TConstructor(_, name, []) {name == core("Int")} => Some("Int")
870
+ | TConstructor(_, name, []) {operator == "+" && name == core("String")} => Some("String")
871
+ | _ => None
872
+ }
873
+ }
874
+ let chooseType: (Option[String], Option[String]) => Unit = {
875
+ | Some("String"), Some(_) => self.unification.unify(e.at, expected, t1)
876
+ | Some(_), Some("String") => self.unification.unify(e.at, expected, t2)
877
+ | Some("Float"), Some(_) => self.unification.unify(e.at, expected, t1)
878
+ | Some(_), Some("Float") => self.unification.unify(e.at, expected, t2)
879
+ | Some("Int"), Some(_) => self.unification.unify(e.at, expected, t1)
880
+ | Some(_), Some("Int") => self.unification.unify(e.at, expected, t2)
881
+ | Some(_), None =>
882
+ self.unification.unify(e.at, t1, t2)
883
+ self.unification.unify(e.at, expected, t1)
884
+ | None, Some(_) =>
885
+ self.unification.unify(e.at, t2, t1)
886
+ self.unification.unify(e.at, expected, t2)
887
+ | _, _ {self.lspHook.isEnabled()} =>
888
+ | Some(_), Some(_) =>
889
+ throw(CompileError(e.at, "Operators on these types not currently supported"))
890
+ | None, None =>
891
+ throw(CompileError(e.at, "Operators on unknown types not currently supported"))
892
+ }
893
+ chooseType(magic(t1), magic(t2))
894
+ e.ECall(target = target, arguments = [a1.Argument(value = e1), a2.Argument(value = e2)])
895
+ | _ {self.lspHook.isEnabled()} =>
896
+ term
897
+ | _ =>
898
+ fail(e.at, "Unknown operator: " + operator)
899
+ }
900
+ }
901
+
902
+ inferEtaExpansion(
903
+ environment: Environment
904
+ expected: Type
905
+ at: Location
906
+ signature: Signature
907
+ term: Term
908
+ ): Term {
909
+ let parameters = signature.parameters.filter {_.default.isEmpty()}.map {p =>
910
+ p.name
911
+ }
912
+ let effect1 = self.unification.freshUnificationVariable(at)
913
+ let body = ECall(at, DynamicCall(term, False), effect1, [], parameters.map {x =>
914
+ Argument(at, Some(x), EVariable(at, x))
915
+ }, [])
916
+ let effect2 = self.unification.freshUnificationVariable(at)
917
+ let lambda = ELambda(at, Lambda(at, effect2, [MatchCase(
918
+ at = at
919
+ patterns = parameters.map {PVariable(at, Some(_))}
920
+ guards = []
921
+ body = body
922
+ )]))
923
+ self.inferTerm(environment.Environment(effect = effect2), expected, lambda)
924
+ }
925
+
926
+ inferArguments(
927
+ callAt: Location
928
+ callName: String
929
+ environment: Environment
930
+ parameters: List[Parameter]
931
+ arguments: List[Argument]
932
+ ): List[Argument] {
933
+ if(self.lspHook.isEnabled()) {
934
+ arguments.pairs().each {| Pair(i, a) =>
935
+ let p = parameters.find {p => a.name.any {_ == p.name}}
936
+ if(self.lspHook.isAt(a.at) || p.any {self.lspHook.isDefinedAt(_.at)}) {
937
+ self.lspHook.emit(
938
+ InferArgumentHook(
939
+ self.unification, environment
940
+ False, callAt, callName, parameters, arguments, i
941
+ )
942
+ )
943
+ }
944
+ }
945
+ }
946
+ mutable remainingArguments = arguments
947
+ let newArguments = parameters.map {p =>
948
+ let t = p.valueType
949
+ function defaultArgument(): Argument {
950
+ p.default.map {e =>
951
+ let e2 = self.inferTerm(environment, t, e)
952
+ Argument(callAt, Some(p.name), e2)
953
+ }.else {
954
+ if(!self.lspHook.isEnabled()) {
955
+ fail(callAt, "Missing argument: " + p.name)
956
+ } else {
957
+ Argument(callAt, Some(p.name), EVariable(callAt, ""))
958
+ }
959
+ }
960
+ }
961
+ remainingArguments.{
962
+ | [] =>
963
+ defaultArgument()
964
+ | [Argument(at, None, e), ...remaining] =>
965
+ remainingArguments = remaining
966
+ let e2 = self.inferTerm(environment, t, e)
967
+ Argument(at, Some(p.name), e2)
968
+ | _ =>
969
+ remainingArguments.find {_.name.contains(p.name)}.map {| Argument(at, _, e) =>
970
+ remainingArguments = remainingArguments.filter {!_.name.contains(p.name)}
971
+ let e2 = self.inferTerm(environment, t, e)
972
+ Argument(at, Some(p.name), e2)
973
+ }.else {
974
+ defaultArgument()
975
+ }
976
+ }
977
+ }
978
+ if(!self.lspHook.isEnabled()) {
979
+ remainingArguments.first().each {
980
+ | Argument(callAt, None, _) => fail(callAt, "Too many arguments")
981
+ | Argument(callAt, Some(n), _) => fail(callAt, "Unknown argument: " + n)
982
+ }
983
+ newArguments
984
+ } else {
985
+ [...newArguments, ...remainingArguments.map {a => a.Argument(
986
+ value = self.inferTerm(environment, self.unification.freshUnificationVariable(a.at), a.value)
987
+ )}]
988
+ }
989
+ }
990
+
991
+ lookup(
992
+ environment: Environment
993
+ expected: Type
994
+ at: Location
995
+ symbol: String
996
+ typeArguments: List[Type]
997
+ arguments: Option[List[Argument]]
998
+ ): Option[Instantiated] {
999
+ self.lookupOption(environment, expected, at, symbol, typeArguments).elseIf {self.lspHook.isEnabled()} {
1000
+ let instantiated = Instantiated([], Scheme(arguments.isEmpty(), False, False, False, Signature(
1001
+ at = at
1002
+ name = symbol
1003
+ member = False // Should be true when looking up a member or method
1004
+ generics = []
1005
+ constraints = []
1006
+ parameters = arguments.toList().flatten().pairs().map {| Pair(i, a) =>
1007
+ let t = self.unification.freshUnificationVariable(at)
1008
+ Parameter(a.at, False, a.name.else {"_p" + i}, t, None)
1009
+ }
1010
+ returnType = self.unification.freshUnificationVariable(at)
1011
+ effect = self.unification.freshUnificationVariable(at)
1012
+ )))
1013
+ if(!self.lspHook.isAt(at) && !self.missing.has(symbol)) {
1014
+ self.missing.set(symbol, Pair(instantiated, arguments))
1015
+ }
1016
+ instantiated
1017
+ }
1018
+ }
1019
+
1020
+ lookupOption(environment: Environment, expected: Type, at: Location, symbol: String, typeArguments: List[Type]): Option[Instantiated] {
1021
+ let hook = if(self.lspHook.isAt(at)) {
1022
+ let symbolHook = SymbolHook(symbol, at, at)
1023
+ let selfName = environment.selfVariable
1024
+ let h = InferLookupHook(self.unification, environment, expected, selfName, Box(symbolHook), Box(None))
1025
+ self.lspHook.emit(h)
1026
+ h
1027
+ }
1028
+
1029
+ environment.symbols.get(symbol).map: scheme =>
1030
+
1031
+ let instantiation =
1032
+ if(!typeArguments.isEmpty()) {
1033
+ let newTypeArguments = if(!scheme.isVariable && scheme.signature.generics.first().any {_ == "Q$"}) {
1034
+ [self.unification.freshUnificationVariable(at), ...typeArguments]
1035
+ } else {
1036
+ typeArguments
1037
+ }
1038
+ if(scheme.signature.generics.size() != newTypeArguments.size() && !self.lspHook.isEnabled()) {
1039
+ let extra = newTypeArguments.size() - typeArguments.size()
1040
+ throw(CompileError(at
1041
+ "Wrong number of type arguments for " + symbol +
1042
+ ", expected " + (scheme.signature.generics.size() - extra) +
1043
+ ", got " + (newTypeArguments.size() - extra)
1044
+ ))
1045
+ }
1046
+ scheme.signature.generics.zip(newTypeArguments)
1047
+ } else {
1048
+ scheme.signature.generics.map {name =>
1049
+ Pair(name, self.unification.freshUnificationVariable(at))
1050
+ }
1051
+ }
1052
+
1053
+ let instantiationMap = instantiation.toMap()
1054
+ let parameters = scheme.signature.parameters.map {p =>
1055
+ p.Parameter(valueType = self.unification.instantiate(instantiationMap, p.valueType))
1056
+ }
1057
+ let returnType = self.unification.instantiate(instantiationMap, scheme.signature.returnType)
1058
+ let effect = self.unification.instantiate(instantiationMap, scheme.signature.effect)
1059
+
1060
+ scheme.signature.constraints.each {c =>
1061
+ let generics = c.generics.map {self.unification.instantiate(instantiationMap, _)}
1062
+ self.unification.constrain(at, generics.grabFirst(), c.name, generics.dropFirst())
1063
+ }
1064
+
1065
+ let signature = scheme.signature.Signature(
1066
+ generics = []
1067
+ constraints = []
1068
+ parameters = parameters
1069
+ returnType = returnType
1070
+ effect = effect
1071
+ )
1072
+
1073
+ let instantiated = Instantiated(
1074
+ typeArguments = instantiation
1075
+ scheme = scheme.Scheme(signature = signature)
1076
+ )
1077
+
1078
+ if(self.lspHook.isAt(at) || self.lspHook.isDefinedAt(scheme.signature.at)) {
1079
+ let symbolHook = SymbolHook(symbol, at, scheme.signature.at)
1080
+ let emittedHook = hook.else {
1081
+ let selfName = environment.selfVariable
1082
+ let h = InferLookupHook(self.unification, environment, expected, selfName, Box(symbolHook), Box(None))
1083
+ self.lspHook.emit(h)
1084
+ h
1085
+ }.{
1086
+ | InferLookupHook h =>
1087
+ h.symbol.value = symbolHook
1088
+ h.instantiated.value = Some(instantiated)
1089
+ | _ =>
1090
+ }
1091
+ }
1092
+
1093
+ instantiated
1094
+
1095
+ }
1096
+
1097
+ }
1098
+
1099
+ constraintsToInstances(constraints: List[Constraint]): Map[InstanceKey, InstanceValue] {
1100
+ constraints.map {c =>
1101
+ let typeName = c.generics.grabFirst().{
1102
+ | TConstructor(_, name, _) => name
1103
+ | TVariable(at, i) => fail(c.at, "Unexpected unification variable: $" + i)
1104
+ }
1105
+ Pair(
1106
+ InstanceKey(c.name, typeName)
1107
+ InstanceValue(
1108
+ generics = []
1109
+ constraints = []
1110
+ packagePair = PackagePair("", "")
1111
+ moduleName = ""
1112
+ traitName = c.name
1113
+ typeArguments = c.generics
1114
+ )
1115
+ )
1116
+ }.toMap()
1117
+ }