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