typing: shortcut `get_variable` on never-adapted variables
[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(self, variable, mtype2)
256 anode.after_flow_context.when_false.set_var(self, variable, mtype)
257 else if anode isa ANeExpr then
258 anode.after_flow_context.when_false.set_var(self, variable, mtype2)
259 anode.after_flow_context.when_true.set_var(self, 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 if not variable.is_adapted then return variable.declared_type
448
449 var flow = node.after_flow_context
450 if flow == null then
451 self.error(node, "No context!")
452 return null
453 end
454
455 if flow.vars.has_key(variable) then
456 return flow.vars[variable]
457 else
458 #node.debug("*** START Collected for {variable}")
459 var mtypes = flow.collect_types(variable)
460 #node.debug("**** END Collected for {variable}")
461 if mtypes.length == 0 then
462 return variable.declared_type
463 else if mtypes.length == 1 then
464 return mtypes.first
465 else
466 var res = merge_types(node,mtypes)
467 if res == null then res = variable.declared_type
468 return res
469 end
470 end
471 end
472
473 # Some variables where type-adapted during the visit
474 var dirty = false
475
476 # Some loops had been visited during the visit
477 var has_loop = false
478
479 fun set_variable(node: AExpr, variable: Variable, mtype: nullable MType)
480 do
481 var flow = node.after_flow_context
482 assert flow != null
483
484 flow.set_var(self, variable, mtype)
485 end
486
487 fun merge_types(node: ANode, col: Array[nullable MType]): nullable MType
488 do
489 if col.length == 1 then return col.first
490 for t1 in col do
491 if t1 == null then continue # return null
492 var found = true
493 for t2 in col do
494 if t2 == null then continue # return null
495 if can_be_null(t2) and not can_be_null(t1) then
496 t1 = t1.as_nullable
497 end
498 if not is_subtype(t2, t1) then found = false
499 end
500 if found then
501 #print "merge {col.join(" ")} -> {t1}"
502 return t1
503 end
504 end
505 #self.modelbuilder.warning(node, "Type Error: {col.length} conflicting types: <{col.join(", ")}>")
506 return null
507 end
508 end
509
510 # A specific method call site with its associated informations.
511 class CallSite
512 # The associated node for location
513 var node: ANode
514
515 # The static type of the receiver (possibly unresolved)
516 var recv: MType
517
518 # The module where the callsite is present
519 var mmodule: MModule
520
521 # The anchor to use with `recv` or `msignature`
522 var anchor: nullable MClassType
523
524 # Is the receiver self?
525 # If "for_self", virtual types of the signature are kept
526 # If "not_for_self", virtual type are erased
527 var recv_is_self: Bool
528
529 # The designated method
530 var mproperty: MMethod
531
532 # The statically designated method definition
533 # The most specif one, it is.
534 var mpropdef: MMethodDef
535
536 # The resolved signature for the receiver
537 var msignature: MSignature
538
539 # Is a implicit cast required on erasure typing policy?
540 var erasure_cast: Bool
541
542 private fun check_signature(v: TypeVisitor, args: Array[AExpr]): Bool
543 do
544 return v.check_signature(self.node, args, self.mproperty.name, self.msignature)
545 end
546 end
547
548 redef class Variable
549 # The declared type of the variable
550 var declared_type: nullable MType
551
552 # Was the variable type-adapted?
553 # This is used to speedup type retrieval while it remains `false`
554 private var is_adapted = false
555 end
556
557 redef class FlowContext
558 # Store changes of types because of type evolution
559 private var vars = new HashMap[Variable, nullable MType]
560
561 # Adapt the variable to a static type
562 # Warning1: do not modify vars directly.
563 # Warning2: sub-flow may have cached a unadapted variable
564 private fun set_var(v: TypeVisitor, variable: Variable, mtype: nullable MType)
565 do
566 if variable.declared_type == mtype and not variable.is_adapted then return
567 if vars.has_key(variable) and vars[variable] == mtype then return
568 self.vars[variable] = mtype
569 v.dirty = true
570 variable.is_adapted = true
571 #node.debug "set {variable} to {mtype or else "X"}"
572 end
573
574 # Look in the flow and previous flow and collect all first reachable type adaptation of a local variable
575 private fun collect_types(variable: Variable): Array[nullable MType]
576 do
577 #node.debug "flow for {variable}"
578 var res = new Array[nullable MType]
579
580 var todo = [self]
581 var seen = new HashSet[FlowContext]
582 while not todo.is_empty do
583 var f = todo.pop
584 if f.is_unreachable then continue
585 if seen.has(f) then continue
586 seen.add f
587
588 if f.vars.has_key(variable) then
589 # Found something. Collect it and do not process further on this path
590 res.add f.vars[variable]
591 #f.node.debug "process {variable}: got {f.vars[variable] or else "X"}"
592 else
593 todo.add_all f.previous
594 todo.add_all f.loops
595 if f.previous.is_empty then
596 # Root flowcontext mean a parameter or something related
597 res.add variable.declared_type
598 #f.node.debug "root process {variable}: got {variable.declared_type or else "X"}"
599 end
600 end
601 end
602 #self.node.debug "##### end flow for {variable}: {res.join(" ")}"
603 return res
604 end
605 end
606
607 redef class APropdef
608 # The entry point of the whole typing analysis
609 fun do_typing(modelbuilder: ModelBuilder)
610 do
611 end
612
613 # The variable associated to the receiver (if any)
614 var selfvariable: nullable Variable
615 end
616
617 redef class AMethPropdef
618 redef fun do_typing(modelbuilder: ModelBuilder)
619 do
620 var nblock = self.n_block
621 if nblock == null then return
622
623 var mpropdef = self.mpropdef
624 if mpropdef == null then return # skip error
625
626 var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
627 self.selfvariable = v.selfvariable
628
629 var mmethoddef = self.mpropdef.as(not null)
630 var msignature = mmethoddef.msignature
631 if msignature == null then return # skip error
632 for i in [0..msignature.arity[ do
633 var mtype = msignature.mparameters[i].mtype
634 if msignature.vararg_rank == i then
635 var arrayclass = v.get_mclass(self.n_signature.n_params[i], "Array")
636 if arrayclass == null then return # Skip error
637 mtype = arrayclass.get_mtype([mtype])
638 end
639 var variable = self.n_signature.n_params[i].variable
640 assert variable != null
641 variable.declared_type = mtype
642 end
643
644 loop
645 v.dirty = false
646 v.visit_stmt(nblock)
647 if not v.has_loop or not v.dirty then break
648 end
649
650 if not nblock.after_flow_context.is_unreachable and msignature.return_mtype != null then
651 # We reach the end of the function without having a return, it is bad
652 v.error(self, "Control error: Reached end of function (a 'return' with a value was expected).")
653 end
654 end
655 end
656
657 redef class AAttrPropdef
658 redef fun do_typing(modelbuilder: ModelBuilder)
659 do
660 if not has_value then return
661
662 var mpropdef = self.mpropdef
663 if mpropdef == null then return # skip error
664
665 var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
666 self.selfvariable = v.selfvariable
667
668 var nexpr = self.n_expr
669 if nexpr != null then
670 var mtype = self.mpropdef.static_mtype
671 v.visit_expr_subtype(nexpr, mtype)
672 end
673 var nblock = self.n_block
674 if nblock != null then
675 v.visit_stmt(nblock)
676 if not nblock.after_flow_context.is_unreachable then
677 # We reach the end of the init without having a return, it is bad
678 v.error(self, "Control error: Reached end of block (a 'return' with a value was expected).")
679 end
680 end
681 end
682 end
683
684 ###
685
686 redef class AExpr
687 # The static type of the expression.
688 # null if self is a statement or in case of error
689 var mtype: nullable MType = null
690
691 # Is the statement correctly typed?
692 # Used to distinguish errors and statements when `mtype == null`
693 var is_typed: Bool = false
694
695 # If required, the following implicit cast `.as(XXX)`
696 # Such a cast may by required after evaluating the expression when
697 # a unsafe operation is detected (silently accepted by the Nit language).
698 # The attribute is computed by `check_subtype`
699 var implicit_cast_to: nullable MType = null
700
701 # Return the variable read (if any)
702 # Used to perform adaptive typing
703 fun its_variable: nullable Variable do return null
704
705 private fun accept_typing(v: TypeVisitor)
706 do
707 v.error(self, "no implemented accept_typing for {self.class_name}")
708 end
709
710 # Is non-null if `self` is a leaf of a comprehension array construction.
711 # In this case, the enclosing literal array node is designated.
712 # The result of the evaluation of `self` must be
713 # stored inside the designated array (there is an implicit `push`)
714 var comprehension: nullable AArrayExpr = null
715 end
716
717 redef class ABlockExpr
718 redef fun accept_typing(v)
719 do
720 for e in self.n_expr do v.visit_stmt(e)
721 self.is_typed = true
722 end
723
724 # The type of a blockexpr is the one of the last expression (or null if empty)
725 redef fun mtype
726 do
727 if self.n_expr.is_empty then return null
728 return self.n_expr.last.mtype
729 end
730 end
731
732 redef class AVardeclExpr
733 redef fun accept_typing(v)
734 do
735 var variable = self.variable
736 if variable == null then return # Skip error
737
738 var ntype = self.n_type
739 var mtype: nullable MType
740 if ntype == null then
741 mtype = null
742 else
743 mtype = v.resolve_mtype(ntype)
744 if mtype == null then return # Skip error
745 end
746
747 var nexpr = self.n_expr
748 if nexpr != null then
749 if mtype != null then
750 var etype = v.visit_expr_subtype(nexpr, mtype)
751 if etype == mtype then
752 assert ntype != null
753 v.modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition for variable `{variable.name}`")
754 end
755 else
756 mtype = v.visit_expr(nexpr)
757 if mtype == null then return # Skip error
758 end
759 end
760
761 var decltype = mtype
762 if mtype == null or mtype isa MNullType then
763 var objclass = v.get_mclass(self, "Object")
764 if objclass == null then return # skip error
765 decltype = objclass.mclass_type.as_nullable
766 if mtype == null then mtype = decltype
767 end
768
769 variable.declared_type = decltype
770 v.set_variable(self, variable, mtype)
771
772 #debug("var {variable}: {mtype}")
773
774 self.mtype = mtype
775 self.is_typed = true
776 end
777 end
778
779 redef class AVarExpr
780 redef fun its_variable do return self.variable
781 redef fun accept_typing(v)
782 do
783 var variable = self.variable
784 if variable == null then return # Skip error
785
786 var mtype = v.get_variable(self, variable)
787 if mtype != null then
788 #debug("{variable} is {mtype}")
789 else
790 #debug("{variable} is untyped")
791 end
792
793 self.mtype = mtype
794 end
795 end
796
797 redef class AVarAssignExpr
798 redef fun accept_typing(v)
799 do
800 var variable = self.variable
801 assert variable != null
802
803 var mtype = v.visit_expr_subtype(n_value, variable.declared_type)
804
805 v.set_variable(self, variable, mtype)
806
807 self.is_typed = true
808 end
809 end
810
811 redef class AReassignFormExpr
812 # The method designed by the reassign operator.
813 var reassign_callsite: nullable CallSite
814
815 var read_type: nullable MType = null
816
817 # Determine the `reassign_property`
818 # `readtype` is the type of the reading of the left value.
819 # `writetype` is the type of the writing of the left value.
820 # (Because of `ACallReassignExpr`, both can be different.
821 # Return the static type of the value to store.
822 private fun resolve_reassignment(v: TypeVisitor, readtype, writetype: MType): nullable MType
823 do
824 var reassign_name: String
825 if self.n_assign_op isa APlusAssignOp then
826 reassign_name = "+"
827 else if self.n_assign_op isa AMinusAssignOp then
828 reassign_name = "-"
829 else
830 abort
831 end
832
833 self.read_type = readtype
834
835 var callsite = v.get_method(self, readtype, reassign_name, false)
836 if callsite == null then return null # Skip error
837 self.reassign_callsite = callsite
838
839 var msignature = callsite.msignature
840 var rettype = msignature.return_mtype
841 assert msignature.arity == 1 and rettype != null
842
843 var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype)
844 if value_type == null then return null # Skip error
845
846 v.check_subtype(self, rettype, writetype)
847 return rettype
848 end
849 end
850
851 redef class AVarReassignExpr
852 redef fun accept_typing(v)
853 do
854 var variable = self.variable
855 assert variable != null
856
857 var readtype = v.get_variable(self, variable)
858 if readtype == null then return
859
860 read_type = readtype
861
862 var writetype = variable.declared_type
863 if writetype == null then return
864
865 var rettype = self.resolve_reassignment(v, readtype, writetype)
866
867 v.set_variable(self, variable, rettype)
868
869 self.is_typed = true
870 end
871 end
872
873
874 redef class AContinueExpr
875 redef fun accept_typing(v)
876 do
877 var nexpr = self.n_expr
878 if nexpr != null then
879 v.visit_expr(nexpr)
880 end
881 self.is_typed = true
882 end
883 end
884
885 redef class ABreakExpr
886 redef fun accept_typing(v)
887 do
888 var nexpr = self.n_expr
889 if nexpr != null then
890 v.visit_expr(nexpr)
891 end
892 self.is_typed = true
893 end
894 end
895
896 redef class AReturnExpr
897 redef fun accept_typing(v)
898 do
899 var nexpr = self.n_expr
900 var ret_type
901 var mpropdef = v.mpropdef
902 if mpropdef isa MMethodDef then
903 ret_type = mpropdef.msignature.return_mtype
904 else if mpropdef isa MAttributeDef then
905 ret_type = mpropdef.static_mtype
906 else
907 abort
908 end
909 if nexpr != null then
910 if ret_type != null then
911 v.visit_expr_subtype(nexpr, ret_type)
912 else
913 v.visit_expr(nexpr)
914 v.error(self, "Error: Return with value in a procedure.")
915 end
916 else if ret_type != null then
917 v.error(self, "Error: Return without value in a function.")
918 end
919 self.is_typed = true
920 end
921 end
922
923 redef class AAbortExpr
924 redef fun accept_typing(v)
925 do
926 self.is_typed = true
927 end
928 end
929
930 redef class AIfExpr
931 redef fun accept_typing(v)
932 do
933 v.visit_expr_bool(n_expr)
934
935 v.visit_stmt(n_then)
936 v.visit_stmt(n_else)
937
938 self.is_typed = true
939
940 if n_then != null and n_else == null then
941 self.mtype = n_then.mtype
942 end
943 end
944 end
945
946 redef class AIfexprExpr
947 redef fun accept_typing(v)
948 do
949 v.visit_expr_bool(n_expr)
950
951 var t1 = v.visit_expr(n_then)
952 var t2 = v.visit_expr(n_else)
953
954 if t1 == null or t2 == null then
955 return # Skip error
956 end
957
958 var t = v.merge_types(self, [t1, t2])
959 if t == null then
960 v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
961 end
962 self.mtype = t
963 end
964 end
965
966 redef class ADoExpr
967 redef fun accept_typing(v)
968 do
969 v.visit_stmt(n_block)
970 self.is_typed = true
971 end
972 end
973
974 redef class AWhileExpr
975 redef fun accept_typing(v)
976 do
977 v.has_loop = true
978 v.visit_expr_bool(n_expr)
979 v.visit_stmt(n_block)
980 self.is_typed = true
981 end
982 end
983
984 redef class ALoopExpr
985 redef fun accept_typing(v)
986 do
987 v.has_loop = true
988 v.visit_stmt(n_block)
989 self.is_typed = true
990 end
991 end
992
993 redef class AForExpr
994 var coltype: nullable MClassType
995
996 var method_iterator: nullable CallSite
997 var method_is_ok: nullable CallSite
998 var method_item: nullable CallSite
999 var method_next: nullable CallSite
1000 var method_key: nullable CallSite
1001 var method_finish: nullable CallSite
1002
1003 var method_lt: nullable CallSite
1004 var method_successor: nullable CallSite
1005
1006 private fun do_type_iterator(v: TypeVisitor, mtype: MType)
1007 do
1008 if mtype isa MNullType then
1009 v.error(self, "Type error: 'for' cannot iterate over 'null'")
1010 return
1011 end
1012
1013 # get obj class
1014 var objcla = v.get_mclass(self, "Object")
1015 if objcla == null then return
1016
1017 # check iterator method
1018 var itdef = v.get_method(self, mtype, "iterator", n_expr isa ASelfExpr)
1019 if itdef == null then
1020 v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
1021 return
1022 end
1023 self.method_iterator = itdef
1024
1025 # check that iterator return something
1026 var ittype = itdef.msignature.return_mtype
1027 if ittype == null then
1028 v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
1029 return
1030 end
1031
1032 # get iterator type
1033 var colit_cla = v.try_get_mclass(self, "Iterator")
1034 var mapit_cla = v.try_get_mclass(self, "MapIterator")
1035 var is_col = false
1036 var is_map = false
1037
1038 if colit_cla != null and v.is_subtype(ittype, colit_cla.get_mtype([objcla.mclass_type.as_nullable])) then
1039 # Iterator
1040 var coltype = ittype.supertype_to(v.mmodule, v.anchor, colit_cla)
1041 var variables = self.variables
1042 if variables.length != 1 then
1043 v.error(self, "Type Error: 'for' expects only one variable when using 'Iterator'.")
1044 else
1045 variables.first.declared_type = coltype.arguments.first
1046 end
1047 is_col = true
1048 end
1049
1050 if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type.as_nullable, objcla.mclass_type.as_nullable])) then
1051 # Map Iterator
1052 var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
1053 var variables = self.variables
1054 if variables.length != 2 then
1055 v.error(self, "Type Error: 'for' expects two variables when using 'MapIterator'.")
1056 else
1057 variables[0].declared_type = coltype.arguments[0]
1058 variables[1].declared_type = coltype.arguments[1]
1059 end
1060 is_map = true
1061 end
1062
1063 if not is_col and not is_map then
1064 v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
1065 return
1066 end
1067
1068 # anchor formal and virtual types
1069 if mtype.need_anchor then mtype = v.anchor_to(mtype)
1070
1071 mtype = mtype.undecorate
1072 self.coltype = mtype.as(MClassType)
1073
1074 # get methods is_ok, next, item
1075 var ikdef = v.get_method(self, ittype, "is_ok", false)
1076 if ikdef == null then
1077 v.error(self, "Type Error: 'for' expects a method 'is_ok' in 'Iterator' type {ittype}.")
1078 return
1079 end
1080 self.method_is_ok = ikdef
1081
1082 var itemdef = v.get_method(self, ittype, "item", false)
1083 if itemdef == null then
1084 v.error(self, "Type Error: 'for' expects a method 'item' in 'Iterator' type {ittype}.")
1085 return
1086 end
1087 self.method_item = itemdef
1088
1089 var nextdef = v.get_method(self, ittype, "next", false)
1090 if nextdef == null then
1091 v.error(self, "Type Error: 'for' expects a method 'next' in 'Iterator' type {ittype}.")
1092 return
1093 end
1094 self.method_next = nextdef
1095
1096 self.method_finish = v.try_get_method(self, ittype, "finish", false)
1097
1098 if is_map then
1099 var keydef = v.get_method(self, ittype, "key", false)
1100 if keydef == null then
1101 v.error(self, "Type Error: 'for' expects a method 'key' in 'Iterator' type {ittype}.")
1102 return
1103 end
1104 self.method_key = keydef
1105 end
1106
1107 if self.variables.length == 1 and n_expr isa ARangeExpr then
1108 var variable = variables.first
1109 var vtype = variable.declared_type.as(not null)
1110
1111 if n_expr isa AOrangeExpr then
1112 self.method_lt = v.get_method(self, vtype, "<", false)
1113 else
1114 self.method_lt = v.get_method(self, vtype, "<=", false)
1115 end
1116
1117 self.method_successor = v.get_method(self, vtype, "successor", false)
1118 end
1119 end
1120
1121 redef fun accept_typing(v)
1122 do
1123 v.has_loop = true
1124 var mtype = v.visit_expr(n_expr)
1125 if mtype == null then return
1126
1127 self.do_type_iterator(v, mtype)
1128
1129 v.visit_stmt(n_block)
1130
1131 self.mtype = n_block.mtype
1132 self.is_typed = true
1133 end
1134 end
1135
1136 redef class AWithExpr
1137 var method_start: nullable CallSite
1138 var method_finish: nullable CallSite
1139
1140 redef fun accept_typing(v: TypeVisitor)
1141 do
1142 var mtype = v.visit_expr(n_expr)
1143 if mtype == null then return
1144
1145 method_start = v.get_method(self, mtype, "start", n_expr isa ASelfExpr)
1146 method_finish = v.get_method(self, mtype, "finish", n_expr isa ASelfExpr)
1147
1148 v.visit_stmt(n_block)
1149 self.mtype = n_block.mtype
1150 self.is_typed = true
1151 end
1152 end
1153
1154 redef class AAssertExpr
1155 redef fun accept_typing(v)
1156 do
1157 v.visit_expr_bool(n_expr)
1158
1159 v.visit_stmt(n_else)
1160 self.is_typed = true
1161 end
1162 end
1163
1164 redef class AOrExpr
1165 redef fun accept_typing(v)
1166 do
1167 v.visit_expr_bool(n_expr)
1168 v.visit_expr_bool(n_expr2)
1169 self.mtype = v.type_bool(self)
1170 end
1171 end
1172
1173 redef class AImpliesExpr
1174 redef fun accept_typing(v)
1175 do
1176 v.visit_expr_bool(n_expr)
1177 v.visit_expr_bool(n_expr2)
1178 self.mtype = v.type_bool(self)
1179 end
1180 end
1181
1182 redef class AAndExpr
1183 redef fun accept_typing(v)
1184 do
1185 v.visit_expr_bool(n_expr)
1186 v.visit_expr_bool(n_expr2)
1187 self.mtype = v.type_bool(self)
1188 end
1189 end
1190
1191
1192 redef class ANotExpr
1193 redef fun accept_typing(v)
1194 do
1195 v.visit_expr_bool(n_expr)
1196 self.mtype = v.type_bool(self)
1197 end
1198 end
1199
1200 redef class AOrElseExpr
1201 redef fun accept_typing(v)
1202 do
1203 var t1 = v.visit_expr(n_expr)
1204 var t2 = v.visit_expr(n_expr2)
1205
1206 if t1 == null or t2 == null then
1207 return # Skip error
1208 end
1209
1210 if t1 isa MNullType then
1211 v.error(n_expr, "Type error: or else on null")
1212 else if v.check_can_be_null(n_expr, t1) then
1213 t1 = t1.as_notnull
1214 end
1215
1216 var t = v.merge_types(self, [t1, t2])
1217 if t == null then
1218 var c = v.get_mclass(self, "Object")
1219 if c == null then return # forward error
1220 t = c.mclass_type
1221 if v.can_be_null(t2) then
1222 t = t.as_nullable
1223 end
1224 #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
1225 end
1226 self.mtype = t
1227 end
1228 end
1229
1230 redef class ATrueExpr
1231 redef fun accept_typing(v)
1232 do
1233 self.mtype = v.type_bool(self)
1234 end
1235 end
1236
1237 redef class AFalseExpr
1238 redef fun accept_typing(v)
1239 do
1240 self.mtype = v.type_bool(self)
1241 end
1242 end
1243
1244 redef class AIntExpr
1245 redef fun accept_typing(v)
1246 do
1247 var mclass = v.get_mclass(self, "Int")
1248 if mclass == null then return # Forward error
1249 self.mtype = mclass.mclass_type
1250 end
1251 end
1252
1253 redef class AFloatExpr
1254 redef fun accept_typing(v)
1255 do
1256 var mclass = v.get_mclass(self, "Float")
1257 if mclass == null then return # Forward error
1258 self.mtype = mclass.mclass_type
1259 end
1260 end
1261
1262 redef class ACharExpr
1263 redef fun accept_typing(v)
1264 do
1265 var mclass = v.get_mclass(self, "Char")
1266 if mclass == null then return # Forward error
1267 self.mtype = mclass.mclass_type
1268 end
1269 end
1270
1271 redef class AStringFormExpr
1272 redef fun accept_typing(v)
1273 do
1274 var mclass = v.get_mclass(self, "String")
1275 if mclass == null then return # Forward error
1276 self.mtype = mclass.mclass_type
1277 end
1278 end
1279
1280 redef class ASuperstringExpr
1281 redef fun accept_typing(v)
1282 do
1283 var mclass = v.get_mclass(self, "String")
1284 if mclass == null then return # Forward error
1285 self.mtype = mclass.mclass_type
1286 var objclass = v.get_mclass(self, "Object")
1287 if objclass == null then return # Forward error
1288 var objtype = objclass.mclass_type
1289 for nexpr in self.n_exprs do
1290 v.visit_expr_subtype(nexpr, objtype)
1291 end
1292 end
1293 end
1294
1295 redef class AArrayExpr
1296 # The `with_capacity` method on Array
1297 var with_capacity_callsite: nullable CallSite
1298
1299 # The `push` method on arrays
1300 var push_callsite: nullable CallSite
1301
1302 # The element of each type
1303 var element_mtype: nullable MType
1304
1305 # Set that `self` is a part of comprehension array `na`
1306 # If `self` is a `for`, or a `if`, then `set_comprehension` is recursively applied.
1307 private fun set_comprehension(n: nullable AExpr)
1308 do
1309 if n == null then
1310 return
1311 else if n isa AForExpr then
1312 set_comprehension(n.n_block)
1313 else if n isa AIfExpr then
1314 set_comprehension(n.n_then)
1315 set_comprehension(n.n_else)
1316 else
1317 # is a leave
1318 n.comprehension = self
1319 end
1320 end
1321 redef fun accept_typing(v)
1322 do
1323 var mtype: nullable MType = null
1324 var ntype = self.n_type
1325 if ntype != null then
1326 mtype = v.resolve_mtype(ntype)
1327 if mtype == null then return # Skip error
1328 end
1329 var mtypes = new Array[nullable MType]
1330 var useless = false
1331 for e in self.n_exprs do
1332 var t = v.visit_expr(e)
1333 if t == null then
1334 return # Skip error
1335 end
1336 set_comprehension(e)
1337 if mtype != null then
1338 if v.check_subtype(e, t, mtype) == null then return # Skip error
1339 if t == mtype then useless = true
1340 else
1341 mtypes.add(t)
1342 end
1343 end
1344 if mtype == null then
1345 # Ensure monotony for type adaptation on loops
1346 if self.element_mtype != null then mtypes.add self.element_mtype
1347 mtype = v.merge_types(self, mtypes)
1348 end
1349 if mtype == null or mtype isa MNullType then
1350 v.error(self, "Type Error: ambiguous array type {mtypes.join(" ")}")
1351 return
1352 end
1353 if useless then
1354 assert ntype != null
1355 v.modelbuilder.warning(ntype, "useless-type", "Warning: useless type declaration `{mtype}` in literal Array since it can be inferred from the elements type.")
1356 end
1357
1358 self.element_mtype = mtype
1359
1360 var mclass = v.get_mclass(self, "Array")
1361 if mclass == null then return # Forward error
1362 var array_mtype = mclass.get_mtype([mtype])
1363
1364 with_capacity_callsite = v.get_method(self, array_mtype, "with_capacity", false)
1365 push_callsite = v.get_method(self, array_mtype, "push", false)
1366
1367 self.mtype = array_mtype
1368 end
1369 end
1370
1371 redef class ARangeExpr
1372 var init_callsite: nullable CallSite
1373
1374 redef fun accept_typing(v)
1375 do
1376 var discrete_class = v.get_mclass(self, "Discrete")
1377 if discrete_class == null then return # Forward error
1378 var discrete_type = discrete_class.intro.bound_mtype
1379 var t1 = v.visit_expr_subtype(self.n_expr, discrete_type)
1380 var t2 = v.visit_expr_subtype(self.n_expr2, discrete_type)
1381 if t1 == null or t2 == null then return
1382 var mclass = v.get_mclass(self, "Range")
1383 if mclass == null then return # Forward error
1384 var mtype
1385 if v.is_subtype(t1, t2) then
1386 mtype = mclass.get_mtype([t2])
1387 else if v.is_subtype(t2, t1) then
1388 mtype = mclass.get_mtype([t1])
1389 else
1390 v.error(self, "Type Error: Cannot create range: {t1} vs {t2}")
1391 return
1392 end
1393
1394 self.mtype = mtype
1395
1396 # get the constructor
1397 var callsite
1398 if self isa ACrangeExpr then
1399 callsite = v.get_method(self, mtype, "init", false)
1400 else if self isa AOrangeExpr then
1401 callsite = v.get_method(self, mtype, "without_last", false)
1402 else
1403 abort
1404 end
1405 init_callsite = callsite
1406 end
1407 end
1408
1409 redef class ANullExpr
1410 redef fun accept_typing(v)
1411 do
1412 self.mtype = v.mmodule.model.null_type
1413 end
1414 end
1415
1416 redef class AIsaExpr
1417 # The static type to cast to.
1418 # (different from the static type of the expression that is `Bool`).
1419 var cast_type: nullable MType
1420 redef fun accept_typing(v)
1421 do
1422 var mtype = v.visit_expr_cast(self, self.n_expr, self.n_type)
1423 self.cast_type = mtype
1424
1425 var variable = self.n_expr.its_variable
1426 if variable != null then
1427 #var orig = self.n_expr.mtype
1428 #var from = if orig != null then orig.to_s else "invalid"
1429 #var to = if mtype != null then mtype.to_s else "invalid"
1430 #debug("adapt {variable}: {from} -> {to}")
1431 self.after_flow_context.when_true.set_var(v, variable, mtype)
1432 end
1433
1434 self.mtype = v.type_bool(self)
1435 end
1436 end
1437
1438 redef class AAsCastExpr
1439 redef fun accept_typing(v)
1440 do
1441 self.mtype = v.visit_expr_cast(self, self.n_expr, self.n_type)
1442 end
1443 end
1444
1445 redef class AAsNotnullExpr
1446 redef fun accept_typing(v)
1447 do
1448 var mtype = v.visit_expr(self.n_expr)
1449 if mtype == null then return # Forward error
1450
1451 if mtype isa MNullType then
1452 v.error(self, "Type error: as(not null) on null")
1453 return
1454 end
1455
1456 if v.check_can_be_null(n_expr, mtype) then
1457 mtype = mtype.as_notnull
1458 end
1459
1460 self.mtype = mtype
1461 end
1462 end
1463
1464 redef class AParExpr
1465 redef fun accept_typing(v)
1466 do
1467 self.mtype = v.visit_expr(self.n_expr)
1468 end
1469 end
1470
1471 redef class AOnceExpr
1472 redef fun accept_typing(v)
1473 do
1474 self.mtype = v.visit_expr(self.n_expr)
1475 end
1476 end
1477
1478 redef class ASelfExpr
1479 redef var its_variable: nullable Variable
1480 redef fun accept_typing(v)
1481 do
1482 if v.is_toplevel_context and not self isa AImplicitSelfExpr then
1483 v.error(self, "Error: self cannot be used in top-level method.")
1484 end
1485 var variable = v.selfvariable
1486 self.its_variable = variable
1487 self.mtype = v.get_variable(self, variable)
1488 end
1489 end
1490
1491 redef class AImplicitSelfExpr
1492 # Is the implicit receiver `sys`?
1493 #
1494 # By default, the implicit receiver is `self`.
1495 # But when there is not method for `self`, `sys` is used as a fall-back.
1496 # Is this case this flag is set to `true`.
1497 var is_sys = false
1498 end
1499
1500 ## MESSAGE SENDING AND PROPERTY
1501
1502 redef class ASendExpr
1503 # The property invoked by the send.
1504 var callsite: nullable CallSite
1505
1506 redef fun accept_typing(v)
1507 do
1508 var nrecv = self.n_expr
1509 var recvtype = v.visit_expr(nrecv)
1510 var name = self.property_name
1511
1512 if recvtype == null then return # Forward error
1513
1514 var callsite = null
1515 var unsafe_type = v.anchor_to(recvtype)
1516 var mproperty = v.try_get_mproperty_by_name2(self, unsafe_type, name)
1517 if mproperty == null and nrecv isa AImplicitSelfExpr then
1518 # Special fall-back search in `sys` when noting found in the implicit receiver.
1519 var sysclass = v.try_get_mclass(self, "Sys")
1520 if sysclass != null then
1521 var systype = sysclass.mclass_type
1522 mproperty = v.try_get_mproperty_by_name2(self, systype, name)
1523 if mproperty != null then
1524 callsite = v.get_method(self, systype, name, false)
1525 if callsite == null then return # Forward error
1526 # Update information, we are looking at `sys` now, not `self`
1527 nrecv.is_sys = true
1528 nrecv.its_variable = null
1529 nrecv.mtype = systype
1530 recvtype = systype
1531 end
1532 end
1533 end
1534 if callsite == null then
1535 # If still nothing, just exit
1536 callsite = v.get_method(self, recvtype, name, nrecv isa ASelfExpr)
1537 if callsite == null then return
1538 end
1539
1540 self.callsite = callsite
1541 var msignature = callsite.msignature
1542
1543 var args = compute_raw_arguments
1544
1545 callsite.check_signature(v, args)
1546
1547 if callsite.mproperty.is_init then
1548 var vmpropdef = v.mpropdef
1549 if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
1550 v.error(self, "Can call a init only in another init")
1551 end
1552 if vmpropdef isa MMethodDef and vmpropdef.mproperty.is_root_init and not callsite.mproperty.is_root_init then
1553 v.error(self, "Error: {vmpropdef} cannot call a factory {callsite.mproperty}")
1554 end
1555 end
1556
1557 var ret = msignature.return_mtype
1558 if ret != null then
1559 self.mtype = ret
1560 else
1561 self.is_typed = true
1562 end
1563 end
1564
1565 # The name of the property
1566 # Each subclass simply provide the correct name.
1567 private fun property_name: String is abstract
1568
1569 # An array of all arguments (excluding self)
1570 fun raw_arguments: Array[AExpr] do return compute_raw_arguments
1571
1572 private fun compute_raw_arguments: Array[AExpr] is abstract
1573 end
1574
1575 redef class ABinopExpr
1576 redef fun compute_raw_arguments do return [n_expr2]
1577 end
1578 redef class AEqExpr
1579 redef fun property_name do return "=="
1580 redef fun accept_typing(v)
1581 do
1582 super
1583 v.null_test(self)
1584 end
1585 end
1586 redef class ANeExpr
1587 redef fun property_name do return "!="
1588 redef fun accept_typing(v)
1589 do
1590 super
1591 v.null_test(self)
1592 end
1593 end
1594 redef class ALtExpr
1595 redef fun property_name do return "<"
1596 end
1597 redef class ALeExpr
1598 redef fun property_name do return "<="
1599 end
1600 redef class ALlExpr
1601 redef fun property_name do return "<<"
1602 end
1603 redef class AGtExpr
1604 redef fun property_name do return ">"
1605 end
1606 redef class AGeExpr
1607 redef fun property_name do return ">="
1608 end
1609 redef class AGgExpr
1610 redef fun property_name do return ">>"
1611 end
1612 redef class APlusExpr
1613 redef fun property_name do return "+"
1614 end
1615 redef class AMinusExpr
1616 redef fun property_name do return "-"
1617 end
1618 redef class AStarshipExpr
1619 redef fun property_name do return "<=>"
1620 end
1621 redef class AStarExpr
1622 redef fun property_name do return "*"
1623 end
1624 redef class AStarstarExpr
1625 redef fun property_name do return "**"
1626 end
1627 redef class ASlashExpr
1628 redef fun property_name do return "/"
1629 end
1630 redef class APercentExpr
1631 redef fun property_name do return "%"
1632 end
1633
1634 redef class AUminusExpr
1635 redef fun property_name do return "unary -"
1636 redef fun compute_raw_arguments do return new Array[AExpr]
1637 end
1638
1639
1640 redef class ACallExpr
1641 redef fun property_name do return n_id.text
1642 redef fun compute_raw_arguments do return n_args.to_a
1643 end
1644
1645 redef class ACallAssignExpr
1646 redef fun property_name do return n_id.text + "="
1647 redef fun compute_raw_arguments
1648 do
1649 var res = n_args.to_a
1650 res.add(n_value)
1651 return res
1652 end
1653 end
1654
1655 redef class ABraExpr
1656 redef fun property_name do return "[]"
1657 redef fun compute_raw_arguments do return n_args.to_a
1658 end
1659
1660 redef class ABraAssignExpr
1661 redef fun property_name do return "[]="
1662 redef fun compute_raw_arguments
1663 do
1664 var res = n_args.to_a
1665 res.add(n_value)
1666 return res
1667 end
1668 end
1669
1670 redef class ASendReassignFormExpr
1671 # The property invoked for the writing
1672 var write_callsite: nullable CallSite
1673
1674 redef fun accept_typing(v)
1675 do
1676 var recvtype = v.visit_expr(self.n_expr)
1677 var name = self.property_name
1678
1679 if recvtype == null then return # Forward error
1680
1681 var for_self = self.n_expr isa ASelfExpr
1682 var callsite = v.get_method(self, recvtype, name, for_self)
1683
1684 if callsite == null then return
1685 self.callsite = callsite
1686
1687 var args = compute_raw_arguments
1688
1689 callsite.check_signature(v, args)
1690
1691 var readtype = callsite.msignature.return_mtype
1692 if readtype == null then
1693 v.error(self, "Error: {name} is not a function")
1694 return
1695 end
1696
1697 var wcallsite = v.get_method(self, recvtype, name + "=", self.n_expr isa ASelfExpr)
1698 if wcallsite == null then return
1699 self.write_callsite = wcallsite
1700
1701 var wtype = self.resolve_reassignment(v, readtype, wcallsite.msignature.mparameters.last.mtype)
1702 if wtype == null then return
1703
1704 args = args.to_a # duplicate so raw_arguments keeps only the getter args
1705 args.add(self.n_value)
1706 wcallsite.check_signature(v, args)
1707
1708 self.is_typed = true
1709 end
1710 end
1711
1712 redef class ACallReassignExpr
1713 redef fun property_name do return n_id.text
1714 redef fun compute_raw_arguments do return n_args.to_a
1715 end
1716
1717 redef class ABraReassignExpr
1718 redef fun property_name do return "[]"
1719 redef fun compute_raw_arguments do return n_args.to_a
1720 end
1721
1722 redef class AInitExpr
1723 redef fun property_name do return "init"
1724 redef fun compute_raw_arguments do return n_args.to_a
1725 end
1726
1727 redef class AExprs
1728 fun to_a: Array[AExpr] do return self.n_exprs.to_a
1729 end
1730
1731 ###
1732
1733 redef class ASuperExpr
1734 # The method to call if the super is in fact a 'super init call'
1735 # Note: if the super is a normal call-next-method, then this attribute is null
1736 var callsite: nullable CallSite
1737
1738 # The method to call is the super is a standard `call-next-method` super-call
1739 # Note: if the super is a special super-init-call, then this attribute is null
1740 var mpropdef: nullable MMethodDef
1741
1742 redef fun accept_typing(v)
1743 do
1744 var anchor = v.anchor
1745 assert anchor != null
1746 var recvtype = v.get_variable(self, v.selfvariable)
1747 assert recvtype != null
1748 var mproperty = v.mpropdef.mproperty
1749 if not mproperty isa MMethod then
1750 v.error(self, "Error: super only usable in a method")
1751 return
1752 end
1753 var superprops = mproperty.lookup_super_definitions(v.mmodule, anchor)
1754 if superprops.length == 0 then
1755 if mproperty.is_init and v.mpropdef.is_intro then
1756 process_superinit(v)
1757 return
1758 end
1759 v.error(self, "Error: No super method to call for {mproperty}.")
1760 return
1761 end
1762 # FIXME: covariance of return type in linear extension?
1763 var superprop = superprops.first
1764
1765 var msignature = superprop.msignature.as(not null)
1766 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
1767 var args = self.n_args.to_a
1768 if args.length > 0 then
1769 v.check_signature(self, args, mproperty.name, msignature)
1770 end
1771 self.mtype = msignature.return_mtype
1772 self.is_typed = true
1773 v.mpropdef.has_supercall = true
1774 mpropdef = v.mpropdef.as(MMethodDef)
1775 end
1776
1777 private fun process_superinit(v: TypeVisitor)
1778 do
1779 var anchor = v.anchor
1780 assert anchor != null
1781 var recvtype = v.get_variable(self, v.selfvariable)
1782 assert recvtype != null
1783 var mpropdef = v.mpropdef
1784 assert mpropdef isa MMethodDef
1785 var mproperty = mpropdef.mproperty
1786 var superprop: nullable MMethodDef = null
1787 for msupertype in mpropdef.mclassdef.supertypes do
1788 msupertype = msupertype.anchor_to(v.mmodule, anchor)
1789 var errcount = v.modelbuilder.toolcontext.error_count
1790 var candidate = v.try_get_mproperty_by_name2(self, msupertype, mproperty.name).as(nullable MMethod)
1791 if candidate == null then
1792 if v.modelbuilder.toolcontext.error_count > errcount then return # Forward error
1793 continue # Try next super-class
1794 end
1795 if superprop != null and candidate.is_root_init then
1796 continue
1797 end
1798 if superprop != null and superprop.mproperty != candidate and not superprop.mproperty.is_root_init then
1799 v.error(self, "Error: conflicting super constructor to call for {mproperty}: {candidate.full_name}, {superprop.mproperty.full_name}")
1800 return
1801 end
1802 var candidatedefs = candidate.lookup_definitions(v.mmodule, anchor)
1803 if superprop != null and superprop.mproperty == candidate then
1804 if superprop == candidatedefs.first then continue
1805 candidatedefs.add(superprop)
1806 end
1807 if candidatedefs.length > 1 then
1808 v.error(self, "Error: conflicting property definitions for property {mproperty} in {recvtype}: {candidatedefs.join(", ")}")
1809 return
1810 end
1811 superprop = candidatedefs.first
1812 end
1813 if superprop == null then
1814 v.error(self, "Error: No super method to call for {mproperty}.")
1815 return
1816 end
1817
1818 var msignature = superprop.new_msignature or else superprop.msignature.as(not null)
1819 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
1820
1821 var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
1822 self.callsite = callsite
1823
1824 var args = self.n_args.to_a
1825 if args.length > 0 then
1826 callsite.check_signature(v, args)
1827 else
1828 # Check there is at least enough parameters
1829 if mpropdef.msignature.arity < msignature.arity then
1830 v.error(self, "Error: Not enough implicit arguments to pass. Got {mpropdef.msignature.arity}, expected at least {msignature.arity}. Signature is {msignature}")
1831 return
1832 end
1833 # Check that each needed parameter is conform
1834 var i = 0
1835 for sp in msignature.mparameters do
1836 var p = mpropdef.msignature.mparameters[i]
1837 if not v.is_subtype(p.mtype, sp.mtype) then
1838 v.error(self, "Type error: expected argument #{i} of type {sp.mtype}, got implicit argument {p.name} of type {p.mtype}. Signature is {msignature}")
1839 return
1840 end
1841 i += 1
1842 end
1843 end
1844
1845 self.is_typed = true
1846 end
1847 end
1848
1849 ####
1850
1851 redef class ANewExpr
1852 # The constructor invoked by the new.
1853 var callsite: nullable CallSite
1854
1855 # The designated type
1856 var recvtype: nullable MClassType
1857
1858 redef fun accept_typing(v)
1859 do
1860 var recvtype = v.resolve_mtype(self.n_type)
1861 if recvtype == null then return
1862
1863 if not recvtype isa MClassType then
1864 if recvtype isa MNullableType then
1865 v.error(self, "Type error: cannot instantiate the nullable type {recvtype}.")
1866 return
1867 else
1868 v.error(self, "Type error: cannot instantiate the formal type {recvtype}.")
1869 return
1870 end
1871 end
1872
1873 self.recvtype = recvtype
1874
1875 var name: String
1876 var nid = self.n_id
1877 if nid != null then
1878 name = nid.text
1879 else
1880 name = "new"
1881 end
1882 var callsite = v.get_method(self, recvtype, name, false)
1883 if callsite == null then return
1884
1885 if not callsite.mproperty.is_new then
1886 var kind = recvtype.mclass.kind
1887 if kind != concrete_kind then
1888 v.error(self, "Type Error: Cannot instantiate {kind} {recvtype}.")
1889 return
1890 end
1891 self.mtype = recvtype
1892 else
1893 self.mtype = callsite.msignature.return_mtype
1894 assert self.mtype != null
1895 end
1896
1897 self.callsite = callsite
1898
1899 if not callsite.mproperty.is_init_for(recvtype.mclass) then
1900 v.error(self, "Error: {name} is not a constructor.")
1901 return
1902 end
1903
1904 var args = n_args.to_a
1905 callsite.check_signature(v, args)
1906 end
1907 end
1908
1909 ####
1910
1911 redef class AAttrFormExpr
1912 # The attribute acceded.
1913 var mproperty: nullable MAttribute
1914
1915 # The static type of the attribute.
1916 var attr_type: nullable MType
1917
1918 # Resolve the attribute acceded.
1919 private fun resolve_property(v: TypeVisitor)
1920 do
1921 var recvtype = v.visit_expr(self.n_expr)
1922 if recvtype == null then return # Skip error
1923 var name = self.n_id.text
1924 if recvtype isa MNullType then
1925 v.error(self, "Error: Attribute '{name}' access on 'null'.")
1926 return
1927 end
1928
1929 var unsafe_type = v.anchor_to(recvtype)
1930 var mproperty = v.try_get_mproperty_by_name2(self, unsafe_type, name)
1931 if mproperty == null then
1932 v.modelbuilder.error(self, "Error: Attribute {name} doesn't exists in {recvtype}.")
1933 return
1934 end
1935 assert mproperty isa MAttribute
1936 self.mproperty = mproperty
1937
1938 var mpropdefs = mproperty.lookup_definitions(v.mmodule, unsafe_type)
1939 assert mpropdefs.length == 1
1940 var mpropdef = mpropdefs.first
1941 var attr_type = mpropdef.static_mtype
1942 if attr_type == null then return # skip error
1943 attr_type = v.resolve_for(attr_type, recvtype, self.n_expr isa ASelfExpr)
1944 self.attr_type = attr_type
1945 end
1946 end
1947
1948 redef class AAttrExpr
1949 redef fun accept_typing(v)
1950 do
1951 self.resolve_property(v)
1952 self.mtype = self.attr_type
1953 end
1954 end
1955
1956
1957 redef class AAttrAssignExpr
1958 redef fun accept_typing(v)
1959 do
1960 self.resolve_property(v)
1961 var mtype = self.attr_type
1962
1963 v.visit_expr_subtype(self.n_value, mtype)
1964 self.is_typed = true
1965 end
1966 end
1967
1968 redef class AAttrReassignExpr
1969 redef fun accept_typing(v)
1970 do
1971 self.resolve_property(v)
1972 var mtype = self.attr_type
1973 if mtype == null then return # Skip error
1974
1975 self.resolve_reassignment(v, mtype, mtype)
1976
1977 self.is_typed = true
1978 end
1979 end
1980
1981 redef class AIssetAttrExpr
1982 redef fun accept_typing(v)
1983 do
1984 self.resolve_property(v)
1985 var mtype = self.attr_type
1986 if mtype == null then return # Skip error
1987
1988 var recvtype = self.n_expr.mtype.as(not null)
1989 var bound = v.resolve_for(mtype, recvtype, false)
1990 if bound isa MNullableType then
1991 v.error(self, "Error: isset on a nullable attribute.")
1992 end
1993 self.mtype = v.type_bool(self)
1994 end
1995 end
1996
1997 redef class AVarargExpr
1998 redef fun accept_typing(v)
1999 do
2000 # This kind of pseudo-expression can be only processed trough a signature
2001 # See `check_signature`
2002 # Other cases are a syntax error.
2003 v.error(self, "Syntax error: unexpected `...`")
2004 end
2005 end
2006
2007 ###
2008
2009 redef class ADebugTypeExpr
2010 redef fun accept_typing(v)
2011 do
2012 var expr = v.visit_expr(self.n_expr)
2013 if expr == null then return
2014 var unsafe = v.anchor_to(expr)
2015 var ntype = self.n_type
2016 var mtype = v.resolve_mtype(ntype)
2017 if mtype != null and mtype != expr then
2018 var umtype = v.anchor_to(mtype)
2019 v.modelbuilder.warning(self, "debug", "Found type {expr} (-> {unsafe}), expected {mtype} (-> {umtype})")
2020 end
2021 self.is_typed = true
2022 end
2023 end