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