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