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