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