typing: remove cache in FlowContext
[nit.git] / src / semantize / typing.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Intraprocedural resolution of static types and OO-services
18 # By OO-services we mean message sending, attribute access, instantiation, etc.
19 module typing
20
21 import modelize
22 import local_var_init
23
24 redef class ToolContext
25 var typing_phase: Phase = new TypingPhase(self, [flow_phase, modelize_property_phase, local_var_init_phase])
26 end
27
28 private class TypingPhase
29 super Phase
30 redef fun process_npropdef(npropdef) do npropdef.do_typing(toolcontext.modelbuilder)
31 end
32
33 private class TypeVisitor
34 var modelbuilder: ModelBuilder
35
36 # The module of the analysis
37 # Used to correctly query the model
38 var mmodule: MModule
39
40 # The static type of the receiver
41 # Mainly used for type tests and type resolutions
42 var anchor: nullable MClassType = null
43
44 # The analyzed mclassdef
45 var mclassdef: nullable MClassDef = null
46
47 # The analyzed property
48 var mpropdef: nullable MPropDef
49
50 var selfvariable = new Variable("self")
51
52 # Is `self` use restricted?
53 # * no explicit `self`
54 # * method called on the implicit self must be top-level
55 # Currently only used for `new` factory since there is no valid receiver inside
56 var is_toplevel_context = false
57
58 init
59 do
60 var mpropdef = self.mpropdef
61
62 if mpropdef != null then
63 self.mpropdef = mpropdef
64 var mclassdef = mpropdef.mclassdef
65 self.mclassdef = mclassdef
66 self.anchor = mclassdef.bound_mtype
67
68 var mclass = mclassdef.mclass
69
70 var selfvariable = new Variable("self")
71 self.selfvariable = selfvariable
72 selfvariable.declared_type = mclass.mclass_type
73
74 var mprop = mpropdef.mproperty
75 if mprop isa MMethod and mprop.is_new then
76 is_toplevel_context = true
77 end
78 end
79 end
80
81 fun anchor_to(mtype: MType): MType
82 do
83 var anchor = anchor
84 if anchor == null then
85 assert not mtype.need_anchor
86 return mtype
87 end
88 return mtype.anchor_to(mmodule, anchor)
89 end
90
91 fun is_subtype(sub, sup: MType): Bool
92 do
93 return sub.is_subtype(mmodule, anchor, sup)
94 end
95
96 fun resolve_for(mtype, subtype: MType, for_self: Bool): MType
97 do
98 #print "resolve_for {mtype} sub={subtype} forself={for_self} mmodule={mmodule} anchor={anchor}"
99 var res = mtype.resolve_for(subtype, anchor, mmodule, not for_self)
100 return res
101 end
102
103 # Check that `sub` is a subtype of `sup`.
104 # If `sub` is not a valid suptype, then display an error on `node` an return null.
105 # If `sub` is a safe subtype of `sup` then return `sub`.
106 # If `sub` is an unsafe subtype (ie an implicit cast is required), then return `sup`.
107 #
108 # The point of the return type is to determinate the usable type on an expression:
109 # If the suptype is safe, then the return type is the one on the expression typed by `sub`.
110 # Is the subtype is unsafe, then the return type is the one of an implicit cast on `sup`.
111 fun check_subtype(node: ANode, sub, sup: MType): nullable MType
112 do
113 if self.is_subtype(sub, sup) then return sub
114 if self.is_subtype(sub, self.anchor_to(sup)) then
115 # FIXME workaround to the current unsafe typing policy. To remove once fixed virtual types exists.
116 #node.debug("Unsafe typing: expected {sup}, got {sub}")
117 return sup
118 end
119 if sub.need_anchor then
120 var u = anchor_to(sub)
121 self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}: {u}")
122 else
123 self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}")
124 end
125 return null
126 end
127
128 # Visit an expression and do not care about the return value
129 fun visit_stmt(nexpr: nullable AExpr)
130 do
131 if nexpr == null then return
132 nexpr.accept_typing(self)
133 end
134
135 # Visit an expression and expects that it is not a statement
136 # Return the type of the expression
137 # Display an error and return null if:
138 # * the type cannot be determined or
139 # * `nexpr` is a statement
140 fun visit_expr(nexpr: AExpr): nullable MType
141 do
142 nexpr.accept_typing(self)
143 var mtype = nexpr.mtype
144 if mtype != null then return mtype
145 if not nexpr.is_typed then
146 if not self.modelbuilder.toolcontext.error_count > 0 then # check that there is really an error
147 if self.modelbuilder.toolcontext.verbose_level > 1 then
148 nexpr.debug("No return type but no error.")
149 end
150 end
151 return null # forward error
152 end
153 self.error(nexpr, "Type error: expected expression.")
154 return null
155 end
156
157 # Visit an expression and expect its static type is a least a `sup`
158 # Return the type of the expression or null if
159 # * the type cannot be determined or
160 # * `nexpr` is a statement or
161 # * `nexpr` is not a `sup`
162 fun visit_expr_subtype(nexpr: AExpr, sup: nullable MType): nullable MType
163 do
164 var sub = visit_expr(nexpr)
165 if sub == null then return null # Forward error
166
167 if sup == null then return null # Forward error
168
169 var res = check_subtype(nexpr, sub, sup)
170 if res != sub then
171 nexpr.implicit_cast_to = res
172 end
173 return res
174 end
175
176 # Visit an expression and expect its static type is a `Bool`
177 # Return the type of the expression or null if
178 # * the type cannot be determined or
179 # * `nexpr` is a statement or
180 # * `nexpr` is not a `Bool`
181 fun visit_expr_bool(nexpr: AExpr): nullable MType
182 do
183 return self.visit_expr_subtype(nexpr, self.type_bool(nexpr))
184 end
185
186
187 fun visit_expr_cast(node: ANode, nexpr: AExpr, ntype: AType): nullable MType
188 do
189 var sub = visit_expr(nexpr)
190 if sub == null then return null # Forward error
191
192 var sup = self.resolve_mtype(ntype)
193 if sup == null then return null # Forward error
194
195 if sup == sub then
196 self.modelbuilder.warning(node, "useless-type-test", "Warning: Expression is already a {sup}.")
197 else if self.is_subtype(sub, sup) then
198 self.modelbuilder.warning(node, "useless-type-test", "Warning: Expression is already a {sup} since it is a {sub}.")
199 end
200 return sup
201 end
202
203 # Can `mtype` be null (up to the current knowledge)?
204 fun can_be_null(mtype: MType): Bool
205 do
206 if mtype isa MNullableType or mtype isa MNullType then return true
207 if mtype isa MFormalType then
208 var x = anchor_to(mtype)
209 if x isa MNullableType or x isa MNullType then return true
210 end
211 return false
212 end
213
214 # Check that `mtype` can be null (up to the current knowledge).
215 #
216 # If not then display a `useless-null-test` warning on node and return false.
217 # Else return true.
218 fun check_can_be_null(anode: ANode, mtype: MType): Bool
219 do
220 if can_be_null(mtype) then return true
221
222 if mtype isa MFormalType then
223 var res = anchor_to(mtype)
224 modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}: {res}`.")
225 else
226 modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}`.")
227 end
228 return false
229 end
230
231 # Special verification on != and == for null
232 # Return true
233 fun null_test(anode: ABinopExpr)
234 do
235 var mtype = anode.n_expr.mtype
236 var mtype2 = anode.n_expr2.mtype
237
238 if mtype == null or mtype2 == null then return
239
240 if not mtype2 isa MNullType then return
241
242 if mtype isa MNullType then return
243
244 # Check of useless null
245 if not check_can_be_null(anode.n_expr, mtype) then return
246
247 mtype = mtype.as_notnull
248
249 # Check for type adaptation
250 var variable = anode.n_expr.its_variable
251 if variable == null then return
252
253 # One is null (mtype2 see above) the other is not null
254 if anode isa AEqExpr then
255 anode.after_flow_context.when_true.set_var(variable, mtype2)
256 anode.after_flow_context.when_false.set_var(variable, mtype)
257 else if anode isa ANeExpr then
258 anode.after_flow_context.when_false.set_var(variable, mtype2)
259 anode.after_flow_context.when_true.set_var(variable, mtype)
260 else
261 abort
262 end
263 end
264
265 fun try_get_mproperty_by_name2(anode: ANode, mtype: MType, name: String): nullable MProperty
266 do
267 return self.modelbuilder.try_get_mproperty_by_name2(anode, mmodule, mtype, name)
268 end
269
270 fun resolve_mtype(node: AType): nullable MType
271 do
272 return self.modelbuilder.resolve_mtype(mmodule, mclassdef, node)
273 end
274
275 fun try_get_mclass(node: ANode, name: String): nullable MClass
276 do
277 var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
278 return mclass
279 end
280
281 fun get_mclass(node: ANode, name: String): nullable MClass
282 do
283 var mclass = modelbuilder.get_mclass_by_name(node, mmodule, name)
284 return mclass
285 end
286
287 fun type_bool(node: ANode): nullable MType
288 do
289 var mclass = self.get_mclass(node, "Bool")
290 if mclass == null then return null
291 return mclass.mclass_type
292 end
293
294 fun get_method(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable CallSite
295 do
296 var unsafe_type = self.anchor_to(recvtype)
297
298 #debug("recv: {recvtype} (aka {unsafe_type})")
299 if recvtype isa MNullType then
300 # `null` only accepts some methods of object.
301 if name == "==" or name == "!=" or name == "is_same_instance" then
302 var objclass = get_mclass(node, "Object")
303 if objclass == null then return null # Forward error
304 unsafe_type = objclass.mclass_type
305 else
306 self.error(node, "Error: Method '{name}' call on 'null'.")
307 return null
308 end
309 end
310
311 var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
312 if name == "new" and mproperty == null then
313 name = "init"
314 mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
315 end
316
317 if mproperty == null then
318 #self.modelbuilder.error(node, "Type error: property {name} not found in {unsafe_type} (ie {recvtype})")
319 if recv_is_self then
320 self.modelbuilder.error(node, "Error: Method or variable '{name}' unknown in {recvtype}.")
321 else
322 self.modelbuilder.error(node, "Error: Method '{name}' doesn't exists in {recvtype}.")
323 end
324 return null
325 end
326
327 assert mproperty isa MMethod
328
329 if is_toplevel_context and recv_is_self and not mproperty.is_toplevel then
330 error(node, "Error: '{name}' is not a top-level method, thus need a receiver.")
331 end
332 if not recv_is_self and mproperty.is_toplevel then
333 error(node, "Error: cannot call '{name}', a top-level method, with a receiver.")
334 end
335
336 if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility and not modelbuilder.toolcontext.opt_ignore_visibility.value then
337 self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self.")
338 return null
339 end
340
341 var info = mproperty.deprecation
342 if info != null and self.mpropdef.mproperty.deprecation == null then
343 var mdoc = info.mdoc
344 if mdoc != null then
345 self.modelbuilder.warning(node, "deprecated-method", "Deprecation Warning: Method '{name}' is deprecated: {mdoc.content.first}")
346 else
347 self.modelbuilder.warning(node, "deprecated-method", "Deprecation Warning: Method '{name}' is deprecated.")
348 end
349 end
350
351 var propdefs = mproperty.lookup_definitions(self.mmodule, unsafe_type)
352 var mpropdef
353 if propdefs.length == 0 then
354 self.modelbuilder.error(node, "Type error: no definition found for property {name} in {unsafe_type}")
355 return null
356 else if propdefs.length == 1 then
357 mpropdef = propdefs.first
358 else
359 self.modelbuilder.warning(node, "property-conflict", "Warning: conflicting property definitions for property {name} in {unsafe_type}: {propdefs.join(" ")}")
360 mpropdef = mproperty.intro
361 end
362
363
364 var msignature = mpropdef.new_msignature or else mpropdef.msignature
365 if msignature == null then return null # skip error
366 msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
367
368 var erasure_cast = false
369 var rettype = mpropdef.msignature.return_mtype
370 if not recv_is_self and rettype != null then
371 rettype = rettype.undecorate
372 if rettype isa MParameterType then
373 var erased_rettype = msignature.return_mtype
374 assert erased_rettype != null
375 #node.debug("Erasure cast: Really a {rettype} but unsafely a {erased_rettype}")
376 erasure_cast = true
377 end
378 end
379
380 var callsite = new CallSite(node, recvtype, mmodule, anchor, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
381 return callsite
382 end
383
384 fun try_get_method(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable CallSite
385 do
386 var unsafe_type = self.anchor_to(recvtype)
387 var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
388 if mproperty == null then return null
389 return get_method(node, recvtype, name, recv_is_self)
390 end
391
392
393 # Visit the expressions of args and check their conformity with the corresponding type in signature
394 # The point of this method is to handle varargs correctly
395 # Note: The signature must be correctly adapted
396 fun check_signature(node: ANode, args: Array[AExpr], name: String, msignature: MSignature): Bool
397 do
398 var vararg_rank = msignature.vararg_rank
399 if vararg_rank >= 0 then
400 if args.length < msignature.arity then
401 #self.modelbuilder.error(node, "Error: Incorrect number of parameters. Got {args.length}, expected at least {msignature.arity}. Signature is {msignature}")
402 self.modelbuilder.error(node, "Error: arity mismatch; prototype is '{name}{msignature}'")
403 return false
404 end
405 else if args.length != msignature.arity then
406 self.modelbuilder.error(node, "Error: Incorrect number of parameters. Got {args.length}, expected {msignature.arity}. Signature is {msignature}")
407 return false
408 end
409
410 #debug("CALL {unsafe_type}.{msignature}")
411
412 var vararg_decl = args.length - msignature.arity
413 for i in [0..msignature.arity[ do
414 var j = i
415 if i == vararg_rank then continue # skip the vararg
416 if i > vararg_rank then
417 j = i + vararg_decl
418 end
419 var paramtype = msignature.mparameters[i].mtype
420 self.visit_expr_subtype(args[j], paramtype)
421 end
422 if vararg_rank >= 0 then
423 var paramtype = msignature.mparameters[vararg_rank].mtype
424 var first = args[vararg_rank]
425 if vararg_decl == 0 and first isa AVarargExpr then
426 var mclass = get_mclass(node, "Array")
427 if mclass == null then return false # Forward error
428 var array_mtype = mclass.get_mtype([paramtype])
429 self.visit_expr_subtype(first.n_expr, array_mtype)
430 first.mtype = first.n_expr.mtype
431 else
432 for j in [vararg_rank..vararg_rank+vararg_decl] do
433 self.visit_expr_subtype(args[j], paramtype)
434 end
435 end
436 end
437 return true
438 end
439
440 fun error(node: ANode, message: String)
441 do
442 self.modelbuilder.toolcontext.error(node.hot_location, message)
443 end
444
445 fun get_variable(node: AExpr, variable: Variable): nullable MType
446 do
447 var flow = node.after_flow_context
448 if flow == null then
449 self.error(node, "No context!")
450 return null
451 end
452
453 if flow.vars.has_key(variable) then
454 return flow.vars[variable]
455 else
456 #node.debug("*** START Collected for {variable}")
457 var mtypes = flow.collect_types(variable)
458 #node.debug("**** END Collected for {variable}")
459 if mtypes == null or mtypes.length == 0 then
460 return variable.declared_type
461 else if mtypes.length == 1 then
462 return mtypes.first
463 else
464 var res = merge_types(node,mtypes)
465 if res == null then res = variable.declared_type
466 return res
467 end
468 end
469 end
470
471 fun set_variable(node: AExpr, variable: Variable, mtype: nullable MType)
472 do
473 var flow = node.after_flow_context
474 assert flow != null
475
476 flow.set_var(variable, mtype)
477 end
478
479 fun merge_types(node: ANode, col: Array[nullable MType]): nullable MType
480 do
481 if col.length == 1 then return col.first
482 for t1 in col do
483 if t1 == null then continue # return null
484 var found = true
485 for t2 in col do
486 if t2 == null then continue # return null
487 if can_be_null(t2) and not can_be_null(t1) then
488 t1 = t1.as_nullable
489 end
490 if not is_subtype(t2, t1) then found = false
491 end
492 if found then
493 #print "merge {col.join(" ")} -> {t1}"
494 return t1
495 end
496 end
497 #self.modelbuilder.warning(node, "Type Error: {col.length} conflicting types: <{col.join(", ")}>")
498 return null
499 end
500 end
501
502 # A specific method call site with its associated informations.
503 class CallSite
504 # The associated node for location
505 var node: ANode
506
507 # The static type of the receiver (possibly unresolved)
508 var recv: MType
509
510 # The module where the callsite is present
511 var mmodule: MModule
512
513 # The anchor to use with `recv` or `msignature`
514 var anchor: nullable MClassType
515
516 # Is the receiver self?
517 # If "for_self", virtual types of the signature are kept
518 # If "not_for_self", virtual type are erased
519 var recv_is_self: Bool
520
521 # The designated method
522 var mproperty: MMethod
523
524 # The statically designated method definition
525 # The most specif one, it is.
526 var mpropdef: MMethodDef
527
528 # The resolved signature for the receiver
529 var msignature: MSignature
530
531 # Is a implicit cast required on erasure typing policy?
532 var erasure_cast: Bool
533
534 private fun check_signature(v: TypeVisitor, args: Array[AExpr]): Bool
535 do
536 return v.check_signature(self.node, args, self.mproperty.name, self.msignature)
537 end
538 end
539
540 redef class Variable
541 # The declared type of the variable
542 var declared_type: nullable MType
543 end
544
545 redef class FlowContext
546 # Store changes of types because of type evolution
547 private var vars = new HashMap[Variable, nullable MType]
548
549 # Adapt the variable to a static type
550 # Warning1: do not modify vars directly.
551 # Warning2: sub-flow may have cached a unadapted variable
552 private fun set_var(variable: Variable, mtype: nullable MType)
553 do
554 self.vars[variable] = mtype
555 end
556
557 private fun collect_types(variable: Variable): nullable Array[nullable MType]
558 do
559 var res: nullable Array[nullable MType] = null
560 if vars.has_key(variable) then
561 var mtype = vars[variable]
562 res = [mtype]
563 else if self.previous.is_empty then
564 # Root flow
565 res = [variable.declared_type]
566 else
567 for flow in self.previous do
568 if flow.is_unreachable then continue
569 var r2 = flow.collect_types(variable)
570 if r2 == null then continue
571 if res == null then
572 res = r2.to_a
573 else
574 for t in r2 do
575 if not res.has(t) then res.add(t)
576 end
577 end
578 end
579 end
580 return res
581 end
582 end
583
584 redef class APropdef
585 # The entry point of the whole typing analysis
586 fun do_typing(modelbuilder: ModelBuilder)
587 do
588 end
589
590 # The variable associated to the receiver (if any)
591 var selfvariable: nullable Variable
592 end
593
594 redef class AMethPropdef
595 redef fun do_typing(modelbuilder: ModelBuilder)
596 do
597 var nblock = self.n_block
598 if nblock == null then return
599
600 var mpropdef = self.mpropdef
601 if mpropdef == null then return # skip error
602
603 var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
604 self.selfvariable = v.selfvariable
605
606 var mmethoddef = self.mpropdef.as(not null)
607 var msignature = mmethoddef.msignature
608 if msignature == null then return # skip error
609 for i in [0..msignature.arity[ do
610 var mtype = msignature.mparameters[i].mtype
611 if msignature.vararg_rank == i then
612 var arrayclass = v.get_mclass(self.n_signature.n_params[i], "Array")
613 if arrayclass == null then return # Skip error
614 mtype = arrayclass.get_mtype([mtype])
615 end
616 var variable = self.n_signature.n_params[i].variable
617 assert variable != null
618 variable.declared_type = mtype
619 end
620 v.visit_stmt(nblock)
621
622 if not nblock.after_flow_context.is_unreachable and msignature.return_mtype != null then
623 # We reach the end of the function without having a return, it is bad
624 v.error(self, "Control error: Reached end of function (a 'return' with a value was expected).")
625 end
626 end
627 end
628
629 redef class AAttrPropdef
630 redef fun do_typing(modelbuilder: ModelBuilder)
631 do
632 if not has_value then return
633
634 var mpropdef = self.mpropdef
635 if mpropdef == null then return # skip error
636
637 var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
638 self.selfvariable = v.selfvariable
639
640 var nexpr = self.n_expr
641 if nexpr != null then
642 var mtype = self.mpropdef.static_mtype
643 v.visit_expr_subtype(nexpr, mtype)
644 end
645 var nblock = self.n_block
646 if nblock != null then
647 v.visit_stmt(nblock)
648 if not nblock.after_flow_context.is_unreachable then
649 # We reach the end of the init without having a return, it is bad
650 v.error(self, "Control error: Reached end of block (a 'return' with a value was expected).")
651 end
652 end
653 end
654 end
655
656 ###
657
658 redef class AExpr
659 # The static type of the expression.
660 # null if self is a statement or in case of error
661 var mtype: nullable MType = null
662
663 # Is the statement correctly typed?
664 # Used to distinguish errors and statements when `mtype == null`
665 var is_typed: Bool = false
666
667 # If required, the following implicit cast `.as(XXX)`
668 # Such a cast may by required after evaluating the expression when
669 # a unsafe operation is detected (silently accepted by the Nit language).
670 # The attribute is computed by `check_subtype`
671 var implicit_cast_to: nullable MType = null
672
673 # Return the variable read (if any)
674 # Used to perform adaptive typing
675 fun its_variable: nullable Variable do return null
676
677 private fun accept_typing(v: TypeVisitor)
678 do
679 v.error(self, "no implemented accept_typing for {self.class_name}")
680 end
681
682 # Is non-null if `self` is a leaf of a comprehension array construction.
683 # In this case, the enclosing literal array node is designated.
684 # The result of the evaluation of `self` must be
685 # stored inside the designated array (there is an implicit `push`)
686 var comprehension: nullable AArrayExpr = null
687 end
688
689 redef class ABlockExpr
690 redef fun accept_typing(v)
691 do
692 for e in self.n_expr do v.visit_stmt(e)
693 self.is_typed = true
694 end
695
696 # The type of a blockexpr is the one of the last expression (or null if empty)
697 redef fun mtype
698 do
699 if self.n_expr.is_empty then return null
700 return self.n_expr.last.mtype
701 end
702 end
703
704 redef class AVardeclExpr
705 redef fun accept_typing(v)
706 do
707 var variable = self.variable
708 if variable == null then return # Skip error
709
710 var ntype = self.n_type
711 var mtype: nullable MType
712 if ntype == null then
713 mtype = null
714 else
715 mtype = v.resolve_mtype(ntype)
716 if mtype == null then return # Skip error
717 end
718
719 var nexpr = self.n_expr
720 if nexpr != null then
721 if mtype != null then
722 var etype = v.visit_expr_subtype(nexpr, mtype)
723 if etype == mtype then
724 assert ntype != null
725 v.modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition for variable `{variable.name}`")
726 end
727 else
728 mtype = v.visit_expr(nexpr)
729 if mtype == null then return # Skip error
730 end
731 end
732
733 var decltype = mtype
734 if mtype == null or mtype isa MNullType then
735 var objclass = v.get_mclass(self, "Object")
736 if objclass == null then return # skip error
737 decltype = objclass.mclass_type.as_nullable
738 if mtype == null then mtype = decltype
739 end
740
741 variable.declared_type = decltype
742 v.set_variable(self, variable, mtype)
743
744 #debug("var {variable}: {mtype}")
745
746 self.mtype = mtype
747 self.is_typed = true
748 end
749 end
750
751 redef class AVarExpr
752 redef fun its_variable do return self.variable
753 redef fun accept_typing(v)
754 do
755 var variable = self.variable
756 if variable == null then return # Skip error
757
758 var mtype = v.get_variable(self, variable)
759 if mtype != null then
760 #debug("{variable} is {mtype}")
761 else
762 #debug("{variable} is untyped")
763 end
764
765 self.mtype = mtype
766 end
767 end
768
769 redef class AVarAssignExpr
770 redef fun accept_typing(v)
771 do
772 var variable = self.variable
773 assert variable != null
774
775 var mtype = v.visit_expr_subtype(n_value, variable.declared_type)
776
777 v.set_variable(self, variable, mtype)
778
779 self.is_typed = true
780 end
781 end
782
783 redef class AReassignFormExpr
784 # The method designed by the reassign operator.
785 var reassign_callsite: nullable CallSite
786
787 var read_type: nullable MType = null
788
789 # Determine the `reassign_property`
790 # `readtype` is the type of the reading of the left value.
791 # `writetype` is the type of the writing of the left value.
792 # (Because of `ACallReassignExpr`, both can be different.
793 # Return the static type of the value to store.
794 private fun resolve_reassignment(v: TypeVisitor, readtype, writetype: MType): nullable MType
795 do
796 var reassign_name: String
797 if self.n_assign_op isa APlusAssignOp then
798 reassign_name = "+"
799 else if self.n_assign_op isa AMinusAssignOp then
800 reassign_name = "-"
801 else
802 abort
803 end
804
805 self.read_type = readtype
806
807 var callsite = v.get_method(self, readtype, reassign_name, false)
808 if callsite == null then return null # Skip error
809 self.reassign_callsite = callsite
810
811 var msignature = callsite.msignature
812 var rettype = msignature.return_mtype
813 assert msignature.arity == 1 and rettype != null
814
815 var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype)
816 if value_type == null then return null # Skip error
817
818 v.check_subtype(self, rettype, writetype)
819 return rettype
820 end
821 end
822
823 redef class AVarReassignExpr
824 redef fun accept_typing(v)
825 do
826 var variable = self.variable
827 assert variable != null
828
829 var readtype = v.get_variable(self, variable)
830 if readtype == null then return
831
832 read_type = readtype
833
834 var writetype = variable.declared_type
835 if writetype == null then return
836
837 var rettype = self.resolve_reassignment(v, readtype, writetype)
838
839 v.set_variable(self, variable, rettype)
840
841 self.is_typed = true
842 end
843 end
844
845
846 redef class AContinueExpr
847 redef fun accept_typing(v)
848 do
849 var nexpr = self.n_expr
850 if nexpr != null then
851 v.visit_expr(nexpr)
852 end
853 self.is_typed = true
854 end
855 end
856
857 redef class ABreakExpr
858 redef fun accept_typing(v)
859 do
860 var nexpr = self.n_expr
861 if nexpr != null then
862 v.visit_expr(nexpr)
863 end
864 self.is_typed = true
865 end
866 end
867
868 redef class AReturnExpr
869 redef fun accept_typing(v)
870 do
871 var nexpr = self.n_expr
872 var ret_type
873 var mpropdef = v.mpropdef
874 if mpropdef isa MMethodDef then
875 ret_type = mpropdef.msignature.return_mtype
876 else if mpropdef isa MAttributeDef then
877 ret_type = mpropdef.static_mtype
878 else
879 abort
880 end
881 if nexpr != null then
882 if ret_type != null then
883 v.visit_expr_subtype(nexpr, ret_type)
884 else
885 v.visit_expr(nexpr)
886 v.error(self, "Error: Return with value in a procedure.")
887 end
888 else if ret_type != null then
889 v.error(self, "Error: Return without value in a function.")
890 end
891 self.is_typed = true
892 end
893 end
894
895 redef class AAbortExpr
896 redef fun accept_typing(v)
897 do
898 self.is_typed = true
899 end
900 end
901
902 redef class AIfExpr
903 redef fun accept_typing(v)
904 do
905 v.visit_expr_bool(n_expr)
906
907 v.visit_stmt(n_then)
908 v.visit_stmt(n_else)
909
910 self.is_typed = true
911
912 if n_then != null and n_else == null then
913 self.mtype = n_then.mtype
914 end
915 end
916 end
917
918 redef class AIfexprExpr
919 redef fun accept_typing(v)
920 do
921 v.visit_expr_bool(n_expr)
922
923 var t1 = v.visit_expr(n_then)
924 var t2 = v.visit_expr(n_else)
925
926 if t1 == null or t2 == null then
927 return # Skip error
928 end
929
930 var t = v.merge_types(self, [t1, t2])
931 if t == null then
932 v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
933 end
934 self.mtype = t
935 end
936 end
937
938 redef class ADoExpr
939 redef fun accept_typing(v)
940 do
941 v.visit_stmt(n_block)
942 self.is_typed = true
943 end
944 end
945
946 redef class AWhileExpr
947 redef fun accept_typing(v)
948 do
949 v.visit_expr_bool(n_expr)
950
951 v.visit_stmt(n_block)
952 self.is_typed = true
953 end
954 end
955
956 redef class ALoopExpr
957 redef fun accept_typing(v)
958 do
959 v.visit_stmt(n_block)
960 self.is_typed = true
961 end
962 end
963
964 redef class AForExpr
965 var coltype: nullable MClassType
966
967 var method_iterator: nullable CallSite
968 var method_is_ok: nullable CallSite
969 var method_item: nullable CallSite
970 var method_next: nullable CallSite
971 var method_key: nullable CallSite
972 var method_finish: nullable CallSite
973
974 var method_lt: nullable CallSite
975 var method_successor: nullable CallSite
976
977 private fun do_type_iterator(v: TypeVisitor, mtype: MType)
978 do
979 if mtype isa MNullType then
980 v.error(self, "Type error: 'for' cannot iterate over 'null'")
981 return
982 end
983
984 # get obj class
985 var objcla = v.get_mclass(self, "Object")
986 if objcla == null then return
987
988 # check iterator method
989 var itdef = v.get_method(self, mtype, "iterator", n_expr isa ASelfExpr)
990 if itdef == null then
991 v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
992 return
993 end
994 self.method_iterator = itdef
995
996 # check that iterator return something
997 var ittype = itdef.msignature.return_mtype
998 if ittype == null then
999 v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
1000 return
1001 end
1002
1003 # get iterator type
1004 var colit_cla = v.try_get_mclass(self, "Iterator")
1005 var mapit_cla = v.try_get_mclass(self, "MapIterator")
1006 var is_col = false
1007 var is_map = false
1008
1009 if colit_cla != null and v.is_subtype(ittype, colit_cla.get_mtype([objcla.mclass_type.as_nullable])) then
1010 # Iterator
1011 var coltype = ittype.supertype_to(v.mmodule, v.anchor, colit_cla)
1012 var variables = self.variables
1013 if variables.length != 1 then
1014 v.error(self, "Type Error: 'for' expects only one variable when using 'Iterator'.")
1015 else
1016 variables.first.declared_type = coltype.arguments.first
1017 end
1018 is_col = true
1019 end
1020
1021 if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type.as_nullable, objcla.mclass_type.as_nullable])) then
1022 # Map Iterator
1023 var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
1024 var variables = self.variables
1025 if variables.length != 2 then
1026 v.error(self, "Type Error: 'for' expects two variables when using 'MapIterator'.")
1027 else
1028 variables[0].declared_type = coltype.arguments[0]
1029 variables[1].declared_type = coltype.arguments[1]
1030 end
1031 is_map = true
1032 end
1033
1034 if not is_col and not is_map then
1035 v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
1036 return
1037 end
1038
1039 # anchor formal and virtual types
1040 if mtype.need_anchor then mtype = v.anchor_to(mtype)
1041
1042 mtype = mtype.undecorate
1043 self.coltype = mtype.as(MClassType)
1044
1045 # get methods is_ok, next, item
1046 var ikdef = v.get_method(self, ittype, "is_ok", false)
1047 if ikdef == null then
1048 v.error(self, "Type Error: 'for' expects a method 'is_ok' in 'Iterator' type {ittype}.")
1049 return
1050 end
1051 self.method_is_ok = ikdef
1052
1053 var itemdef = v.get_method(self, ittype, "item", false)
1054 if itemdef == null then
1055 v.error(self, "Type Error: 'for' expects a method 'item' in 'Iterator' type {ittype}.")
1056 return
1057 end
1058 self.method_item = itemdef
1059
1060 var nextdef = v.get_method(self, ittype, "next", false)
1061 if nextdef == null then
1062 v.error(self, "Type Error: 'for' expects a method 'next' in 'Iterator' type {ittype}.")
1063 return
1064 end
1065 self.method_next = nextdef
1066
1067 self.method_finish = v.try_get_method(self, ittype, "finish", false)
1068
1069 if is_map then
1070 var keydef = v.get_method(self, ittype, "key", false)
1071 if keydef == null then
1072 v.error(self, "Type Error: 'for' expects a method 'key' in 'Iterator' type {ittype}.")
1073 return
1074 end
1075 self.method_key = keydef
1076 end
1077
1078 if self.variables.length == 1 and n_expr isa ARangeExpr then
1079 var variable = variables.first
1080 var vtype = variable.declared_type.as(not null)
1081
1082 if n_expr isa AOrangeExpr then
1083 self.method_lt = v.get_method(self, vtype, "<", false)
1084 else
1085 self.method_lt = v.get_method(self, vtype, "<=", false)
1086 end
1087
1088 self.method_successor = v.get_method(self, vtype, "successor", false)
1089 end
1090 end
1091
1092 redef fun accept_typing(v)
1093 do
1094 var mtype = v.visit_expr(n_expr)
1095 if mtype == null then return
1096
1097 self.do_type_iterator(v, mtype)
1098
1099 v.visit_stmt(n_block)
1100 self.mtype = n_block.mtype
1101 self.is_typed = true
1102 end
1103 end
1104
1105 redef class AWithExpr
1106 var method_start: nullable CallSite
1107 var method_finish: nullable CallSite
1108
1109 redef fun accept_typing(v: TypeVisitor)
1110 do
1111 var mtype = v.visit_expr(n_expr)
1112 if mtype == null then return
1113
1114 method_start = v.get_method(self, mtype, "start", n_expr isa ASelfExpr)
1115 method_finish = v.get_method(self, mtype, "finish", n_expr isa ASelfExpr)
1116
1117 v.visit_stmt(n_block)
1118 self.mtype = n_block.mtype
1119 self.is_typed = true
1120 end
1121 end
1122
1123 redef class AAssertExpr
1124 redef fun accept_typing(v)
1125 do
1126 v.visit_expr_bool(n_expr)
1127
1128 v.visit_stmt(n_else)
1129 self.is_typed = true
1130 end
1131 end
1132
1133 redef class AOrExpr
1134 redef fun accept_typing(v)
1135 do
1136 v.visit_expr_bool(n_expr)
1137 v.visit_expr_bool(n_expr2)
1138 self.mtype = v.type_bool(self)
1139 end
1140 end
1141
1142 redef class AImpliesExpr
1143 redef fun accept_typing(v)
1144 do
1145 v.visit_expr_bool(n_expr)
1146 v.visit_expr_bool(n_expr2)
1147 self.mtype = v.type_bool(self)
1148 end
1149 end
1150
1151 redef class AAndExpr
1152 redef fun accept_typing(v)
1153 do
1154 v.visit_expr_bool(n_expr)
1155 v.visit_expr_bool(n_expr2)
1156 self.mtype = v.type_bool(self)
1157 end
1158 end
1159
1160
1161 redef class ANotExpr
1162 redef fun accept_typing(v)
1163 do
1164 v.visit_expr_bool(n_expr)
1165 self.mtype = v.type_bool(self)
1166 end
1167 end
1168
1169 redef class AOrElseExpr
1170 redef fun accept_typing(v)
1171 do
1172 var t1 = v.visit_expr(n_expr)
1173 var t2 = v.visit_expr(n_expr2)
1174
1175 if t1 == null or t2 == null then
1176 return # Skip error
1177 end
1178
1179 if t1 isa MNullType then
1180 v.error(n_expr, "Type error: or else on null")
1181 else if v.check_can_be_null(n_expr, t1) then
1182 t1 = t1.as_notnull
1183 end
1184
1185 var t = v.merge_types(self, [t1, t2])
1186 if t == null then
1187 var c = v.get_mclass(self, "Object")
1188 if c == null then return # forward error
1189 t = c.mclass_type
1190 if v.can_be_null(t2) then
1191 t = t.as_nullable
1192 end
1193 #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
1194 end
1195 self.mtype = t
1196 end
1197 end
1198
1199 redef class ATrueExpr
1200 redef fun accept_typing(v)
1201 do
1202 self.mtype = v.type_bool(self)
1203 end
1204 end
1205
1206 redef class AFalseExpr
1207 redef fun accept_typing(v)
1208 do
1209 self.mtype = v.type_bool(self)
1210 end
1211 end
1212
1213 redef class AIntExpr
1214 redef fun accept_typing(v)
1215 do
1216 var mclass = v.get_mclass(self, "Int")
1217 if mclass == null then return # Forward error
1218 self.mtype = mclass.mclass_type
1219 end
1220 end
1221
1222 redef class AFloatExpr
1223 redef fun accept_typing(v)
1224 do
1225 var mclass = v.get_mclass(self, "Float")
1226 if mclass == null then return # Forward error
1227 self.mtype = mclass.mclass_type
1228 end
1229 end
1230
1231 redef class ACharExpr
1232 redef fun accept_typing(v)
1233 do
1234 var mclass = v.get_mclass(self, "Char")
1235 if mclass == null then return # Forward error
1236 self.mtype = mclass.mclass_type
1237 end
1238 end
1239
1240 redef class AStringFormExpr
1241 redef fun accept_typing(v)
1242 do
1243 var mclass = v.get_mclass(self, "String")
1244 if mclass == null then return # Forward error
1245 self.mtype = mclass.mclass_type
1246 end
1247 end
1248
1249 redef class ASuperstringExpr
1250 redef fun accept_typing(v)
1251 do
1252 var mclass = v.get_mclass(self, "String")
1253 if mclass == null then return # Forward error
1254 self.mtype = mclass.mclass_type
1255 var objclass = v.get_mclass(self, "Object")
1256 if objclass == null then return # Forward error
1257 var objtype = objclass.mclass_type
1258 for nexpr in self.n_exprs do
1259 v.visit_expr_subtype(nexpr, objtype)
1260 end
1261 end
1262 end
1263
1264 redef class AArrayExpr
1265 # The `with_capacity` method on Array
1266 var with_capacity_callsite: nullable CallSite
1267
1268 # The `push` method on arrays
1269 var push_callsite: nullable CallSite
1270
1271 # The element of each type
1272 var element_mtype: nullable MType
1273
1274 # Set that `self` is a part of comprehension array `na`
1275 # If `self` is a `for`, or a `if`, then `set_comprehension` is recursively applied.
1276 private fun set_comprehension(n: nullable AExpr)
1277 do
1278 if n == null then
1279 return
1280 else if n isa AForExpr then
1281 set_comprehension(n.n_block)
1282 else if n isa AIfExpr then
1283 set_comprehension(n.n_then)
1284 set_comprehension(n.n_else)
1285 else
1286 # is a leave
1287 n.comprehension = self
1288 end
1289 end
1290 redef fun accept_typing(v)
1291 do
1292 var mtype: nullable MType = null
1293 var ntype = self.n_type
1294 if ntype != null then
1295 mtype = v.resolve_mtype(ntype)
1296 if mtype == null then return # Skip error
1297 end
1298 var mtypes = new Array[nullable MType]
1299 var useless = false
1300 for e in self.n_exprs do
1301 var t = v.visit_expr(e)
1302 if t == null then
1303 return # Skip error
1304 end
1305 set_comprehension(e)
1306 if mtype != null then
1307 if v.check_subtype(e, t, mtype) == null then return # Skip error
1308 if t == mtype then useless = true
1309 else
1310 mtypes.add(t)
1311 end
1312 end
1313 if mtype == null then
1314 mtype = v.merge_types(self, mtypes)
1315 end
1316 if mtype == null or mtype isa MNullType then
1317 v.error(self, "Type Error: ambiguous array type {mtypes.join(" ")}")
1318 return
1319 end
1320 if useless then
1321 assert ntype != null
1322 v.modelbuilder.warning(ntype, "useless-type", "Warning: useless type declaration `{mtype}` in literal Array since it can be inferred from the elements type.")
1323 end
1324
1325 self.element_mtype = mtype
1326
1327 var mclass = v.get_mclass(self, "Array")
1328 if mclass == null then return # Forward error
1329 var array_mtype = mclass.get_mtype([mtype])
1330
1331 with_capacity_callsite = v.get_method(self, array_mtype, "with_capacity", false)
1332 push_callsite = v.get_method(self, array_mtype, "push", false)
1333
1334 self.mtype = array_mtype
1335 end
1336 end
1337
1338 redef class ARangeExpr
1339 var init_callsite: nullable CallSite
1340
1341 redef fun accept_typing(v)
1342 do
1343 var discrete_class = v.get_mclass(self, "Discrete")
1344 if discrete_class == null then return # Forward error
1345 var discrete_type = discrete_class.intro.bound_mtype
1346 var t1 = v.visit_expr_subtype(self.n_expr, discrete_type)
1347 var t2 = v.visit_expr_subtype(self.n_expr2, discrete_type)
1348 if t1 == null or t2 == null then return
1349 var mclass = v.get_mclass(self, "Range")
1350 if mclass == null then return # Forward error
1351 var mtype
1352 if v.is_subtype(t1, t2) then
1353 mtype = mclass.get_mtype([t2])
1354 else if v.is_subtype(t2, t1) then
1355 mtype = mclass.get_mtype([t1])
1356 else
1357 v.error(self, "Type Error: Cannot create range: {t1} vs {t2}")
1358 return
1359 end
1360
1361 self.mtype = mtype
1362
1363 # get the constructor
1364 var callsite
1365 if self isa ACrangeExpr then
1366 callsite = v.get_method(self, mtype, "init", false)
1367 else if self isa AOrangeExpr then
1368 callsite = v.get_method(self, mtype, "without_last", false)
1369 else
1370 abort
1371 end
1372 init_callsite = callsite
1373 end
1374 end
1375
1376 redef class ANullExpr
1377 redef fun accept_typing(v)
1378 do
1379 self.mtype = v.mmodule.model.null_type
1380 end
1381 end
1382
1383 redef class AIsaExpr
1384 # The static type to cast to.
1385 # (different from the static type of the expression that is `Bool`).
1386 var cast_type: nullable MType
1387 redef fun accept_typing(v)
1388 do
1389 var mtype = v.visit_expr_cast(self, self.n_expr, self.n_type)
1390 self.cast_type = mtype
1391
1392 var variable = self.n_expr.its_variable
1393 if variable != null then
1394 #var orig = self.n_expr.mtype
1395 #var from = if orig != null then orig.to_s else "invalid"
1396 #var to = if mtype != null then mtype.to_s else "invalid"
1397 #debug("adapt {variable}: {from} -> {to}")
1398 self.after_flow_context.when_true.set_var(variable, mtype)
1399 end
1400
1401 self.mtype = v.type_bool(self)
1402 end
1403 end
1404
1405 redef class AAsCastExpr
1406 redef fun accept_typing(v)
1407 do
1408 self.mtype = v.visit_expr_cast(self, self.n_expr, self.n_type)
1409 end
1410 end
1411
1412 redef class AAsNotnullExpr
1413 redef fun accept_typing(v)
1414 do
1415 var mtype = v.visit_expr(self.n_expr)
1416 if mtype == null then return # Forward error
1417
1418 if mtype isa MNullType then
1419 v.error(self, "Type error: as(not null) on null")
1420 return
1421 end
1422
1423 if v.check_can_be_null(n_expr, mtype) then
1424 mtype = mtype.as_notnull
1425 end
1426
1427 self.mtype = mtype
1428 end
1429 end
1430
1431 redef class AParExpr
1432 redef fun accept_typing(v)
1433 do
1434 self.mtype = v.visit_expr(self.n_expr)
1435 end
1436 end
1437
1438 redef class AOnceExpr
1439 redef fun accept_typing(v)
1440 do
1441 self.mtype = v.visit_expr(self.n_expr)
1442 end
1443 end
1444
1445 redef class ASelfExpr
1446 redef var its_variable: nullable Variable
1447 redef fun accept_typing(v)
1448 do
1449 if v.is_toplevel_context and not self isa AImplicitSelfExpr then
1450 v.error(self, "Error: self cannot be used in top-level method.")
1451 end
1452 var variable = v.selfvariable
1453 self.its_variable = variable
1454 self.mtype = v.get_variable(self, variable)
1455 end
1456 end
1457
1458 redef class AImplicitSelfExpr
1459 # Is the implicit receiver `sys`?
1460 #
1461 # By default, the implicit receiver is `self`.
1462 # But when there is not method for `self`, `sys` is used as a fall-back.
1463 # Is this case this flag is set to `true`.
1464 var is_sys = false
1465 end
1466
1467 ## MESSAGE SENDING AND PROPERTY
1468
1469 redef class ASendExpr
1470 # The property invoked by the send.
1471 var callsite: nullable CallSite
1472
1473 redef fun accept_typing(v)
1474 do
1475 var nrecv = self.n_expr
1476 var recvtype = v.visit_expr(nrecv)
1477 var name = self.property_name
1478
1479 if recvtype == null then return # Forward error
1480
1481 var callsite = null
1482 var unsafe_type = v.anchor_to(recvtype)
1483 var mproperty = v.try_get_mproperty_by_name2(self, unsafe_type, name)
1484 if mproperty == null and nrecv isa AImplicitSelfExpr then
1485 # Special fall-back search in `sys` when noting found in the implicit receiver.
1486 var sysclass = v.try_get_mclass(self, "Sys")
1487 if sysclass != null then
1488 var systype = sysclass.mclass_type
1489 mproperty = v.try_get_mproperty_by_name2(self, systype, name)
1490 if mproperty != null then
1491 callsite = v.get_method(self, systype, name, false)
1492 if callsite == null then return # Forward error
1493 # Update information, we are looking at `sys` now, not `self`
1494 nrecv.is_sys = true
1495 nrecv.its_variable = null
1496 nrecv.mtype = systype
1497 recvtype = systype
1498 end
1499 end
1500 end
1501 if callsite == null then
1502 # If still nothing, just exit
1503 callsite = v.get_method(self, recvtype, name, nrecv isa ASelfExpr)
1504 if callsite == null then return
1505 end
1506
1507 self.callsite = callsite
1508 var msignature = callsite.msignature
1509
1510 var args = compute_raw_arguments
1511
1512 callsite.check_signature(v, args)
1513
1514 if callsite.mproperty.is_init then
1515 var vmpropdef = v.mpropdef
1516 if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
1517 v.error(self, "Can call a init only in another init")
1518 end
1519 if vmpropdef isa MMethodDef and vmpropdef.mproperty.is_root_init and not callsite.mproperty.is_root_init then
1520 v.error(self, "Error: {vmpropdef} cannot call a factory {callsite.mproperty}")
1521 end
1522 end
1523
1524 var ret = msignature.return_mtype
1525 if ret != null then
1526 self.mtype = ret
1527 else
1528 self.is_typed = true
1529 end
1530 end
1531
1532 # The name of the property
1533 # Each subclass simply provide the correct name.
1534 private fun property_name: String is abstract
1535
1536 # An array of all arguments (excluding self)
1537 fun raw_arguments: Array[AExpr] do return compute_raw_arguments
1538
1539 private fun compute_raw_arguments: Array[AExpr] is abstract
1540 end
1541
1542 redef class ABinopExpr
1543 redef fun compute_raw_arguments do return [n_expr2]
1544 end
1545 redef class AEqExpr
1546 redef fun property_name do return "=="
1547 redef fun accept_typing(v)
1548 do
1549 super
1550 v.null_test(self)
1551 end
1552 end
1553 redef class ANeExpr
1554 redef fun property_name do return "!="
1555 redef fun accept_typing(v)
1556 do
1557 super
1558 v.null_test(self)
1559 end
1560 end
1561 redef class ALtExpr
1562 redef fun property_name do return "<"
1563 end
1564 redef class ALeExpr
1565 redef fun property_name do return "<="
1566 end
1567 redef class ALlExpr
1568 redef fun property_name do return "<<"
1569 end
1570 redef class AGtExpr
1571 redef fun property_name do return ">"
1572 end
1573 redef class AGeExpr
1574 redef fun property_name do return ">="
1575 end
1576 redef class AGgExpr
1577 redef fun property_name do return ">>"
1578 end
1579 redef class APlusExpr
1580 redef fun property_name do return "+"
1581 end
1582 redef class AMinusExpr
1583 redef fun property_name do return "-"
1584 end
1585 redef class AStarshipExpr
1586 redef fun property_name do return "<=>"
1587 end
1588 redef class AStarExpr
1589 redef fun property_name do return "*"
1590 end
1591 redef class AStarstarExpr
1592 redef fun property_name do return "**"
1593 end
1594 redef class ASlashExpr
1595 redef fun property_name do return "/"
1596 end
1597 redef class APercentExpr
1598 redef fun property_name do return "%"
1599 end
1600
1601 redef class AUminusExpr
1602 redef fun property_name do return "unary -"
1603 redef fun compute_raw_arguments do return new Array[AExpr]
1604 end
1605
1606
1607 redef class ACallExpr
1608 redef fun property_name do return n_id.text
1609 redef fun compute_raw_arguments do return n_args.to_a
1610 end
1611
1612 redef class ACallAssignExpr
1613 redef fun property_name do return n_id.text + "="
1614 redef fun compute_raw_arguments
1615 do
1616 var res = n_args.to_a
1617 res.add(n_value)
1618 return res
1619 end
1620 end
1621
1622 redef class ABraExpr
1623 redef fun property_name do return "[]"
1624 redef fun compute_raw_arguments do return n_args.to_a
1625 end
1626
1627 redef class ABraAssignExpr
1628 redef fun property_name do return "[]="
1629 redef fun compute_raw_arguments
1630 do
1631 var res = n_args.to_a
1632 res.add(n_value)
1633 return res
1634 end
1635 end
1636
1637 redef class ASendReassignFormExpr
1638 # The property invoked for the writing
1639 var write_callsite: nullable CallSite
1640
1641 redef fun accept_typing(v)
1642 do
1643 var recvtype = v.visit_expr(self.n_expr)
1644 var name = self.property_name
1645
1646 if recvtype == null then return # Forward error
1647
1648 var for_self = self.n_expr isa ASelfExpr
1649 var callsite = v.get_method(self, recvtype, name, for_self)
1650
1651 if callsite == null then return
1652 self.callsite = callsite
1653
1654 var args = compute_raw_arguments
1655
1656 callsite.check_signature(v, args)
1657
1658 var readtype = callsite.msignature.return_mtype
1659 if readtype == null then
1660 v.error(self, "Error: {name} is not a function")
1661 return
1662 end
1663
1664 var wcallsite = v.get_method(self, recvtype, name + "=", self.n_expr isa ASelfExpr)
1665 if wcallsite == null then return
1666 self.write_callsite = wcallsite
1667
1668 var wtype = self.resolve_reassignment(v, readtype, wcallsite.msignature.mparameters.last.mtype)
1669 if wtype == null then return
1670
1671 args = args.to_a # duplicate so raw_arguments keeps only the getter args
1672 args.add(self.n_value)
1673 wcallsite.check_signature(v, args)
1674
1675 self.is_typed = true
1676 end
1677 end
1678
1679 redef class ACallReassignExpr
1680 redef fun property_name do return n_id.text
1681 redef fun compute_raw_arguments do return n_args.to_a
1682 end
1683
1684 redef class ABraReassignExpr
1685 redef fun property_name do return "[]"
1686 redef fun compute_raw_arguments do return n_args.to_a
1687 end
1688
1689 redef class AInitExpr
1690 redef fun property_name do return "init"
1691 redef fun compute_raw_arguments do return n_args.to_a
1692 end
1693
1694 redef class AExprs
1695 fun to_a: Array[AExpr] do return self.n_exprs.to_a
1696 end
1697
1698 ###
1699
1700 redef class ASuperExpr
1701 # The method to call if the super is in fact a 'super init call'
1702 # Note: if the super is a normal call-next-method, then this attribute is null
1703 var callsite: nullable CallSite
1704
1705 # The method to call is the super is a standard `call-next-method` super-call
1706 # Note: if the super is a special super-init-call, then this attribute is null
1707 var mpropdef: nullable MMethodDef
1708
1709 redef fun accept_typing(v)
1710 do
1711 var anchor = v.anchor
1712 assert anchor != null
1713 var recvtype = v.get_variable(self, v.selfvariable)
1714 assert recvtype != null
1715 var mproperty = v.mpropdef.mproperty
1716 if not mproperty isa MMethod then
1717 v.error(self, "Error: super only usable in a method")
1718 return
1719 end
1720 var superprops = mproperty.lookup_super_definitions(v.mmodule, anchor)
1721 if superprops.length == 0 then
1722 if mproperty.is_init and v.mpropdef.is_intro then
1723 process_superinit(v)
1724 return
1725 end
1726 v.error(self, "Error: No super method to call for {mproperty}.")
1727 return
1728 end
1729 # FIXME: covariance of return type in linear extension?
1730 var superprop = superprops.first
1731
1732 var msignature = superprop.msignature.as(not null)
1733 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
1734 var args = self.n_args.to_a
1735 if args.length > 0 then
1736 v.check_signature(self, args, mproperty.name, msignature)
1737 end
1738 self.mtype = msignature.return_mtype
1739 self.is_typed = true
1740 v.mpropdef.has_supercall = true
1741 mpropdef = v.mpropdef.as(MMethodDef)
1742 end
1743
1744 private fun process_superinit(v: TypeVisitor)
1745 do
1746 var anchor = v.anchor
1747 assert anchor != null
1748 var recvtype = v.get_variable(self, v.selfvariable)
1749 assert recvtype != null
1750 var mpropdef = v.mpropdef
1751 assert mpropdef isa MMethodDef
1752 var mproperty = mpropdef.mproperty
1753 var superprop: nullable MMethodDef = null
1754 for msupertype in mpropdef.mclassdef.supertypes do
1755 msupertype = msupertype.anchor_to(v.mmodule, anchor)
1756 var errcount = v.modelbuilder.toolcontext.error_count
1757 var candidate = v.try_get_mproperty_by_name2(self, msupertype, mproperty.name).as(nullable MMethod)
1758 if candidate == null then
1759 if v.modelbuilder.toolcontext.error_count > errcount then return # Forward error
1760 continue # Try next super-class
1761 end
1762 if superprop != null and candidate.is_root_init then
1763 continue
1764 end
1765 if superprop != null and superprop.mproperty != candidate and not superprop.mproperty.is_root_init then
1766 v.error(self, "Error: conflicting super constructor to call for {mproperty}: {candidate.full_name}, {superprop.mproperty.full_name}")
1767 return
1768 end
1769 var candidatedefs = candidate.lookup_definitions(v.mmodule, anchor)
1770 if superprop != null and superprop.mproperty == candidate then
1771 if superprop == candidatedefs.first then continue
1772 candidatedefs.add(superprop)
1773 end
1774 if candidatedefs.length > 1 then
1775 v.error(self, "Error: conflicting property definitions for property {mproperty} in {recvtype}: {candidatedefs.join(", ")}")
1776 return
1777 end
1778 superprop = candidatedefs.first
1779 end
1780 if superprop == null then
1781 v.error(self, "Error: No super method to call for {mproperty}.")
1782 return
1783 end
1784
1785 var msignature = superprop.new_msignature or else superprop.msignature.as(not null)
1786 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
1787
1788 var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
1789 self.callsite = callsite
1790
1791 var args = self.n_args.to_a
1792 if args.length > 0 then
1793 callsite.check_signature(v, args)
1794 else
1795 # Check there is at least enough parameters
1796 if mpropdef.msignature.arity < msignature.arity then
1797 v.error(self, "Error: Not enough implicit arguments to pass. Got {mpropdef.msignature.arity}, expected at least {msignature.arity}. Signature is {msignature}")
1798 return
1799 end
1800 # Check that each needed parameter is conform
1801 var i = 0
1802 for sp in msignature.mparameters do
1803 var p = mpropdef.msignature.mparameters[i]
1804 if not v.is_subtype(p.mtype, sp.mtype) then
1805 v.error(self, "Type error: expected argument #{i} of type {sp.mtype}, got implicit argument {p.name} of type {p.mtype}. Signature is {msignature}")
1806 return
1807 end
1808 i += 1
1809 end
1810 end
1811
1812 self.is_typed = true
1813 end
1814 end
1815
1816 ####
1817
1818 redef class ANewExpr
1819 # The constructor invoked by the new.
1820 var callsite: nullable CallSite
1821
1822 # The designated type
1823 var recvtype: nullable MClassType
1824
1825 redef fun accept_typing(v)
1826 do
1827 var recvtype = v.resolve_mtype(self.n_type)
1828 if recvtype == null then return
1829
1830 if not recvtype isa MClassType then
1831 if recvtype isa MNullableType then
1832 v.error(self, "Type error: cannot instantiate the nullable type {recvtype}.")
1833 return
1834 else
1835 v.error(self, "Type error: cannot instantiate the formal type {recvtype}.")
1836 return
1837 end
1838 end
1839
1840 self.recvtype = recvtype
1841
1842 var name: String
1843 var nid = self.n_id
1844 if nid != null then
1845 name = nid.text
1846 else
1847 name = "new"
1848 end
1849 var callsite = v.get_method(self, recvtype, name, false)
1850 if callsite == null then return
1851
1852 if not callsite.mproperty.is_new then
1853 var kind = recvtype.mclass.kind
1854 if kind != concrete_kind then
1855 v.error(self, "Type Error: Cannot instantiate {kind} {recvtype}.")
1856 return
1857 end
1858 self.mtype = recvtype
1859 else
1860 self.mtype = callsite.msignature.return_mtype
1861 assert self.mtype != null
1862 end
1863
1864 self.callsite = callsite
1865
1866 if not callsite.mproperty.is_init_for(recvtype.mclass) then
1867 v.error(self, "Error: {name} is not a constructor.")
1868 return
1869 end
1870
1871 var args = n_args.to_a
1872 callsite.check_signature(v, args)
1873 end
1874 end
1875
1876 ####
1877
1878 redef class AAttrFormExpr
1879 # The attribute acceded.
1880 var mproperty: nullable MAttribute
1881
1882 # The static type of the attribute.
1883 var attr_type: nullable MType
1884
1885 # Resolve the attribute acceded.
1886 private fun resolve_property(v: TypeVisitor)
1887 do
1888 var recvtype = v.visit_expr(self.n_expr)
1889 if recvtype == null then return # Skip error
1890 var name = self.n_id.text
1891 if recvtype isa MNullType then
1892 v.error(self, "Error: Attribute '{name}' access on 'null'.")
1893 return
1894 end
1895
1896 var unsafe_type = v.anchor_to(recvtype)
1897 var mproperty = v.try_get_mproperty_by_name2(self, unsafe_type, name)
1898 if mproperty == null then
1899 v.modelbuilder.error(self, "Error: Attribute {name} doesn't exists in {recvtype}.")
1900 return
1901 end
1902 assert mproperty isa MAttribute
1903 self.mproperty = mproperty
1904
1905 var mpropdefs = mproperty.lookup_definitions(v.mmodule, unsafe_type)
1906 assert mpropdefs.length == 1
1907 var mpropdef = mpropdefs.first
1908 var attr_type = mpropdef.static_mtype
1909 if attr_type == null then return # skip error
1910 attr_type = v.resolve_for(attr_type, recvtype, self.n_expr isa ASelfExpr)
1911 self.attr_type = attr_type
1912 end
1913 end
1914
1915 redef class AAttrExpr
1916 redef fun accept_typing(v)
1917 do
1918 self.resolve_property(v)
1919 self.mtype = self.attr_type
1920 end
1921 end
1922
1923
1924 redef class AAttrAssignExpr
1925 redef fun accept_typing(v)
1926 do
1927 self.resolve_property(v)
1928 var mtype = self.attr_type
1929
1930 v.visit_expr_subtype(self.n_value, mtype)
1931 self.is_typed = true
1932 end
1933 end
1934
1935 redef class AAttrReassignExpr
1936 redef fun accept_typing(v)
1937 do
1938 self.resolve_property(v)
1939 var mtype = self.attr_type
1940 if mtype == null then return # Skip error
1941
1942 self.resolve_reassignment(v, mtype, mtype)
1943
1944 self.is_typed = true
1945 end
1946 end
1947
1948 redef class AIssetAttrExpr
1949 redef fun accept_typing(v)
1950 do
1951 self.resolve_property(v)
1952 var mtype = self.attr_type
1953 if mtype == null then return # Skip error
1954
1955 var recvtype = self.n_expr.mtype.as(not null)
1956 var bound = v.resolve_for(mtype, recvtype, false)
1957 if bound isa MNullableType then
1958 v.error(self, "Error: isset on a nullable attribute.")
1959 end
1960 self.mtype = v.type_bool(self)
1961 end
1962 end
1963
1964 redef class AVarargExpr
1965 redef fun accept_typing(v)
1966 do
1967 # This kind of pseudo-expression can be only processed trough a signature
1968 # See `check_signature`
1969 # Other cases are a syntax error.
1970 v.error(self, "Syntax error: unexpected `...`")
1971 end
1972 end
1973
1974 ###
1975
1976 redef class ADebugTypeExpr
1977 redef fun accept_typing(v)
1978 do
1979 var expr = v.visit_expr(self.n_expr)
1980 if expr == null then return
1981 var unsafe = v.anchor_to(expr)
1982 var ntype = self.n_type
1983 var mtype = v.resolve_mtype(ntype)
1984 if mtype != null and mtype != expr then
1985 var umtype = v.anchor_to(mtype)
1986 v.modelbuilder.warning(self, "debug", "Found type {expr} (-> {unsafe}), expected {mtype} (-> {umtype})")
1987 end
1988 self.is_typed = true
1989 end
1990 end