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