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