syntax: no isa/as warning for double nullable formal type
[nit.git] / src / syntax / typing.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 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 # Analysis property bodies, statements and expressions
18 package typing
19
20 import syntax_base
21 import escape
22 import control_flow
23
24 redef class MMSrcModule
25 # Walk trough the module and type statments and expressions
26 # Require than supermodules are processed
27 meth do_typing(tc: ToolContext)
28 do
29 var tv = new TypingVisitor(tc, self)
30 tv.visit(node)
31 end
32 end
33
34 # Typing visitor
35 # * Associate local variables to nodes
36 # * Distinguish method call and local variable access
37 # * Resolve call and attribute access
38 # * Check type conformance
39 private class TypingVisitor
40 special AbsSyntaxVisitor
41 redef meth visit(n)
42 do
43 if n != null then n.accept_typing(self)
44 end
45
46 # Current knowledge about variables names and types
47 readable writable attr _variable_ctx: VariableContext
48
49 # Non-bypassable knowledge about variables names and types
50 readable writable attr _base_variable_ctx: VariableContext
51
52 # Current knowledge about escapable blocks
53 readable writable attr _escapable_ctx: EscapableContext = new EscapableContext(self)
54
55 # The current reciever
56 readable writable attr _self_var: ParamVariable
57
58 # Block of the current method
59 readable writable attr _top_block: PExpr
60
61 # List of explicit invocation of constructors of super-classes
62 readable writable attr _explicit_super_init_calls: Array[MMMethod]
63
64 # Is a other constructor of the same class invoked
65 readable writable attr _explicit_other_init_call: Bool
66
67 # Make the if_true_variable_ctx of the expression effective
68 private meth use_if_true_variable_ctx(e: PExpr)
69 do
70 var ctx = e.if_true_variable_ctx
71 if ctx != null then variable_ctx = ctx
72 end
73
74 # Make the if_false_variable_ctx of the expression effective
75 private meth use_if_false_variable_ctx(e: PExpr)
76 do
77 var ctx = e.if_false_variable_ctx
78 if ctx != null then variable_ctx = ctx
79 end
80
81 # Number of nested once
82 readable writable attr _once_count: Int = 0
83
84 init(tc, module) do super
85
86 private meth get_default_constructor_for(n: PNode, c: MMLocalClass, prop: MMSrcMethod): MMMethod
87 do
88 var v = self
89 #var prop = v.local_property
90 #assert prop isa MMMethod
91 var candidates = new Array[MMMethod]
92 var false_candidates = new Array[MMMethod]
93 var parity = prop.signature.arity
94 for g in c.global_properties do
95 if not g.is_init_for(c) then continue
96 var gp = c[g]
97 var gps = gp.signature_for(c.get_type)
98 assert gp isa MMSrcMethod
99 var garity = gps.arity
100 if prop != null and gp.name == prop.name then
101 if garity == 0 or (parity == garity and prop.signature < gps) then
102 return gp
103 else
104 false_candidates.add(gp)
105 end
106 else if garity == 0 and gp.name == once ("init".to_symbol) then
107 candidates.add(gp)
108 false_candidates.add(gp)
109 else
110 false_candidates.add(gp)
111 end
112 end
113 if candidates.length == 1 then
114 return candidates.first
115 else if candidates.length > 0 then
116 var a = new Array[String]
117 for p in candidates do
118 a.add("{p.full_name}{p.signature}")
119 end
120 v.error(n, "Error: Conflicting default constructor to call for {c}: {a.join(", ")}.")
121 return null
122 else if false_candidates.length > 0 then
123 var a = new Array[String]
124 for p in false_candidates do
125 a.add("{p.full_name}{p.signature}")
126 end
127 v.error(n, "Error: there is no available compatible constrctor in {c}. Discarded candidates are {a.join(", ")}.")
128 return null
129 else
130 v.error(n, "Error: there is no available compatible constrctor in {c}.")
131 return null
132 end
133 end
134 end
135
136
137 ###############################################################################
138
139 redef class PNode
140 private meth accept_typing(v: TypingVisitor)
141 do
142 accept_abs_syntax_visitor(v)
143 after_typing(v)
144 end
145 private meth after_typing(v: TypingVisitor) do end
146 end
147
148 redef class PClassdef
149 redef meth accept_typing(v)
150 do
151 v.self_var = new ParamVariable("self".to_symbol, self)
152 v.self_var.stype = local_class.get_type
153 super
154 end
155 end
156
157 redef class AAttrPropdef
158 redef meth accept_typing(v)
159 do
160 super
161 if n_expr != null then
162 v.check_conform_expr(n_expr, prop.signature.return_type)
163 end
164 end
165 end
166
167 redef class AMethPropdef
168 redef readable attr _self_var: ParamVariable
169 redef meth accept_typing(v)
170 do
171 v.variable_ctx = new RootVariableContext(v, self)
172 v.base_variable_ctx = v.variable_ctx
173 _self_var = v.self_var
174 super
175 end
176 end
177
178 redef class AConcreteMethPropdef
179 redef meth accept_typing(v)
180 do
181 super
182 if v.variable_ctx.unreash == false and method.signature.return_type != null then
183 v.error(self, "Control error: Reached end of function (a 'return' with a value was expected).")
184 end
185 end
186 end
187
188 redef class AConcreteInitPropdef
189 readable attr _super_init_calls: Array[MMMethod] = new Array[MMMethod]
190 readable attr _explicit_super_init_calls: Array[MMMethod] = new Array[MMMethod]
191 redef meth accept_typing(v)
192 do
193 v.top_block = n_block
194 v.explicit_super_init_calls = explicit_super_init_calls
195 v.explicit_other_init_call = false
196 super
197 if v.explicit_other_init_call or method.global.intro != method then
198 # TODO: something?
199 else
200 var i = 0
201 var l = explicit_super_init_calls.length
202 var cur_m: MMMethod = null
203 var cur_c: MMLocalClass = null
204 if i < l then
205 cur_m = explicit_super_init_calls[i]
206 cur_c = cur_m.global.intro.local_class.for_module(v.module)
207 end
208 var j = 0
209 while j < v.local_class.cshe.direct_greaters.length do
210 var c = v.local_class.cshe.direct_greaters[j]
211 if c.global.is_interface or c.global.is_universal or c.global.is_mixin then
212 j += 1
213 else if cur_c != null and (c.cshe <= cur_c or cur_c.global.is_mixin) then
214 if c == cur_c then j += 1
215 super_init_calls.add(cur_m)
216 i += 1
217 if i < l then
218 cur_m = explicit_super_init_calls[i]
219 cur_c = cur_m.global.intro.local_class.for_module(v.module)
220 else
221 cur_m = null
222 cur_c = null
223 end
224 else
225 var p = v.get_default_constructor_for(self, c, method)
226 if p != null then
227 super_init_calls.add(p)
228 end
229 j += 1
230 end
231 end
232 end
233 end
234 end
235
236 redef class PParam
237 redef meth after_typing(v)
238 do
239 # TODO: why the test?
240 if v.variable_ctx != null then
241 v.variable_ctx.add(variable)
242 end
243 end
244 end
245
246 redef class AClosureDecl
247 # The corresponding escapable object
248 readable attr _escapable: EscapableBlock
249
250 redef meth accept_typing(v)
251 do
252 # Register the closure for ClosureCallExpr
253 v.variable_ctx.add(variable)
254
255 var old_var_ctx = v.variable_ctx
256 var old_base_var_ctx = v.base_variable_ctx
257 v.base_variable_ctx = v.variable_ctx
258 v.variable_ctx = v.variable_ctx.sub(self)
259
260 _escapable = new EscapableClosure(self, variable.closure, null)
261 v.escapable_ctx.push(_escapable)
262
263 super
264
265 if n_expr != null then
266 if v.variable_ctx.unreash == false then
267 if variable.closure.signature.return_type != null then
268 v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
269 else if variable.closure.is_break then
270 v.error(self, "Control error: Reached end of break block (an 'abort' was expected).")
271 end
272 end
273 end
274
275 old_var_ctx.merge(v.variable_ctx)
276 v.variable_ctx = old_var_ctx
277 v.base_variable_ctx = old_base_var_ctx
278 v.escapable_ctx.pop
279 end
280 end
281
282 redef class PType
283 readable attr _stype: MMType
284 redef meth after_typing(v)
285 do
286 _stype = get_stype(v)
287 end
288 end
289
290 redef class PExpr
291 redef readable attr _is_typed: Bool = false
292 redef meth is_statement: Bool do return _stype == null
293 redef meth stype
294 do
295 if not is_typed then
296 print "{locate}: not is_typed"
297 abort
298 end
299 if is_statement then
300 print "{locate}: is_statement"
301 abort
302 end
303 return _stype
304 end
305 attr _stype: MMType
306
307 # Is the expression the implicit receiver
308 meth is_implicit_self: Bool do return false
309
310 # Is the expression the current receiver (implicit or explicit)
311 meth is_self: Bool do return false
312
313 # The variable accessed is any
314 meth its_variable: Variable do return null
315
316 # The variable type information if current boolean expression is true
317 readable private attr _if_true_variable_ctx: VariableContext
318
319 # The variable type information if current boolean expression is false
320 readable private attr _if_false_variable_ctx: VariableContext
321 end
322
323 redef class AVardeclExpr
324 redef meth after_typing(v)
325 do
326 var va = new VarVariable(n_id.to_symbol, self)
327 variable = va
328 v.variable_ctx.add(va)
329 if n_expr != null then v.variable_ctx.mark_is_set(va)
330
331 if n_type != null then
332 va.stype = n_type.stype
333 if n_expr != null then
334 v.check_conform_expr(n_expr, va.stype)
335 end
336 else
337 if not v.check_expr(n_expr) then return
338 va.stype = n_expr.stype
339 end
340 _is_typed = true
341 end
342 end
343
344 redef class ABlockExpr
345 redef meth accept_typing(v)
346 do
347 var old_var_ctx = v.variable_ctx
348 v.variable_ctx = v.variable_ctx.sub(self)
349
350 for e in n_expr do
351 if v.variable_ctx.unreash and not v.variable_ctx.already_unreash then
352 v.variable_ctx.already_unreash = true
353 v.warning(e, "Warning: unreachable statement.")
354 end
355 v.visit(e)
356 end
357
358 old_var_ctx.merge(v.variable_ctx)
359 v.variable_ctx = old_var_ctx
360 _is_typed = true
361 end
362 end
363
364 redef class AReturnExpr
365 redef meth after_typing(v)
366 do
367 v.variable_ctx.unreash = true
368 var t = v.local_property.signature.return_type
369 if n_expr == null and t != null then
370 v.error(self, "Error: Return without value in a function.")
371 else if n_expr != null and t == null then
372 v.error(self, "Error: Return with value in a procedure.")
373 else if n_expr != null and t != null then
374 v.check_conform_expr(n_expr, t)
375 end
376 _is_typed = true
377 end
378 end
379
380 redef class AContinueExpr
381 redef meth after_typing(v)
382 do
383 v.variable_ctx.unreash = true
384 var esc = compute_escapable_block(v.escapable_ctx)
385 if esc == null then return
386
387 if esc.is_break_block then
388 v.error(self, "Error: 'continue' forbiden in break blocks.")
389 return
390 end
391
392 var t = esc.continue_stype
393 if n_expr == null and t != null then
394 v.error(self, "Error: continue with a value required in this block.")
395 else if n_expr != null and t == null then
396 v.error(self, "Error: continue without value required in this block.")
397 else if n_expr != null and t != null then
398 v.check_conform_expr(n_expr, t)
399 end
400 _is_typed = true
401 end
402 end
403
404 redef class ABreakExpr
405 redef meth after_typing(v)
406 do
407 v.variable_ctx.unreash = true
408 var esc = compute_escapable_block(v.escapable_ctx)
409 if esc == null then return
410
411 var bl = esc.break_list
412 if n_expr == null and bl != null then
413 v.error(self, "Error: break with a value required in this block.")
414 else if n_expr != null and bl == null then
415 v.error(self, "Error: break without value required in this block.")
416 else if n_expr != null and bl != null then
417 # Typing check can only be done later
418 bl.add(n_expr)
419 end
420 _is_typed = true
421 end
422 end
423
424 redef class AAbortExpr
425 redef meth after_typing(v)
426 do
427 v.variable_ctx.unreash = true
428 end
429 end
430
431 redef class AIfExpr
432 redef meth accept_typing(v)
433 do
434 var old_var_ctx = v.variable_ctx
435 v.visit(n_expr)
436 v.check_conform_expr(n_expr, v.type_bool)
437
438 # Prepare 'then' context
439 v.use_if_true_variable_ctx(n_expr)
440
441 # Process the 'then'
442 if n_then != null then
443 v.variable_ctx = v.variable_ctx.sub(n_then)
444 v.visit(n_then)
445 end
446
447 # Remember what appened in the 'then'
448 var then_var_ctx = v.variable_ctx
449
450 # Prepare 'else' context
451 v.variable_ctx = old_var_ctx
452 v.use_if_false_variable_ctx(n_expr)
453
454 # Process the 'else'
455 if n_else != null then
456 v.variable_ctx = v.variable_ctx.sub(n_else)
457 v.visit(n_else)
458 end
459
460 # Merge 'then' and 'else' contexts
461 old_var_ctx.merge2(then_var_ctx, v.variable_ctx, v.base_variable_ctx)
462 v.variable_ctx = old_var_ctx
463 _is_typed = true
464 end
465 end
466
467 redef class AWhileExpr
468 # The corresponding escapable block
469 readable attr _escapable: EscapableBlock
470
471 redef meth accept_typing(v)
472 do
473 _escapable = new EscapableBlock(self)
474 v.escapable_ctx.push(_escapable)
475 var old_var_ctx = v.variable_ctx
476 var old_base_var_ctx = v.base_variable_ctx
477 v.base_variable_ctx = v.variable_ctx
478 v.variable_ctx = v.variable_ctx.sub(self)
479
480 # Process condition
481 v.visit(n_expr)
482 v.check_conform_expr(n_expr, v.type_bool)
483
484 # Prepare inside context (assert cond)
485 v.use_if_true_variable_ctx(n_expr)
486
487 # Process inside
488 if n_block != null then
489 v.variable_ctx = v.variable_ctx.sub(n_block)
490 v.visit(n_block)
491 end
492
493 v.variable_ctx = old_var_ctx
494 v.base_variable_ctx = old_base_var_ctx
495 v.escapable_ctx.pop
496 _is_typed = true
497 end
498 end
499
500 redef class AForExpr
501 # The corresponding escapable block
502 readable attr _escapable: EscapableBlock
503
504 readable attr _meth_iterator: MMMethod
505 readable attr _meth_is_ok: MMMethod
506 readable attr _meth_item: MMMethod
507 readable attr _meth_next: MMMethod
508 redef meth accept_typing(v)
509 do
510 _escapable = new EscapableBlock(self)
511 v.escapable_ctx.push(_escapable)
512
513 var old_var_ctx = v.variable_ctx
514 var old_base_var_ctx = v.base_variable_ctx
515 v.base_variable_ctx = v.variable_ctx
516 v.variable_ctx = v.variable_ctx.sub(self)
517 var va = new AutoVariable(n_id.to_symbol, self)
518 variable = va
519 v.variable_ctx.add(va)
520
521 v.visit(n_expr)
522
523 if not v.check_conform_expr(n_expr, v.type_collection) then return
524 var expr_type = n_expr.stype
525 _meth_iterator = expr_type.local_class.select_method(once ("iterator".to_symbol))
526 if _meth_iterator == null then
527 v.error(self, "Error: Collection MUST have an iterate method")
528 return
529 end
530 var iter_type = _meth_iterator.signature_for(expr_type).return_type
531 _meth_is_ok = iter_type.local_class.select_method(once ("is_ok".to_symbol))
532 if _meth_is_ok == null then
533 v.error(self, "Error: {iter_type} MUST have an is_ok method")
534 return
535 end
536 _meth_item = iter_type.local_class.select_method(once ("item".to_symbol))
537 if _meth_item == null then
538 v.error(self, "Error: {iter_type} MUST have an item method")
539 return
540 end
541 _meth_next = iter_type.local_class.select_method(once ("next".to_symbol))
542 if _meth_next == null then
543 v.error(self, "Error: {iter_type} MUST have a next method")
544 return
545 end
546 var t = _meth_item.signature_for(iter_type).return_type
547 if not n_expr.is_self then t = t.not_for_self
548 va.stype = t
549
550 if n_block != null then v.visit(n_block)
551
552 # pop context
553 v.variable_ctx = old_var_ctx
554 v.base_variable_ctx = old_base_var_ctx
555 v.escapable_ctx.pop
556 _is_typed = true
557 end
558 end
559
560 redef class AAssertExpr
561 redef meth after_typing(v)
562 do
563 v.check_conform_expr(n_expr, v.type_bool)
564 v.use_if_true_variable_ctx(n_expr)
565 _is_typed = true
566 end
567 end
568
569 redef class AVarExpr
570 redef meth its_variable do return variable
571
572 redef meth after_typing(v)
573 do
574 v.variable_ctx.check_is_set(self, variable)
575 _stype = v.variable_ctx.stype(variable)
576 _is_typed = _stype != null
577 end
578 end
579
580 redef class AVarAssignExpr
581 redef meth after_typing(v)
582 do
583 v.variable_ctx.mark_is_set(variable)
584 var t = v.variable_ctx.stype(variable)
585
586 # Check the base type
587 var btype = v.base_variable_ctx.stype(variable)
588 if not v.check_conform_expr(n_value, btype) then return
589
590 # Always cast
591 v.variable_ctx.stype(variable) = n_value.stype
592
593 _is_typed = true
594 end
595 end
596
597 redef class AReassignFormExpr
598 # Compute and check method used through the reassigment operator
599 # On success return the static type of the result of the reassigment operator
600 # Else display an error and return null
601 private meth do_rvalue_typing(v: TypingVisitor, type_lvalue: MMType): MMType
602 do
603 if type_lvalue == null then
604 return null
605 end
606 var name = n_assign_op.method_name
607 var lc = type_lvalue.local_class
608 if not lc.has_global_property_by_name(name) then
609 v.error(self, "Error: Method '{name}' doesn't exists in {type_lvalue}.")
610 return null
611 end
612 var prop = lc.select_method(name)
613 prop.global.check_visibility(v, self, v.module, false)
614 var psig = prop.signature_for(type_lvalue)
615 _assign_method = prop
616 if not v.check_conform_expr(n_value, psig[0].not_for_self) then return null
617 return psig.return_type.not_for_self
618 end
619
620 # Method used through the reassigment operator (once computed)
621 readable attr _assign_method: MMMethod
622 end
623
624 redef class AVarReassignExpr
625 redef meth after_typing(v)
626 do
627 v.variable_ctx.check_is_set(self, variable)
628 v.variable_ctx.mark_is_set(variable)
629 var t = v.variable_ctx.stype(variable)
630 var t2 = do_rvalue_typing(v, t)
631 if t2 == null then return
632
633 # Check the base type
634 var btype = v.base_variable_ctx.stype(variable)
635 if not v.check_conform(n_value, t2, btype) then return
636
637 # Always cast
638 v.variable_ctx.stype(variable) = t2
639
640 _is_typed = true
641 end
642 end
643
644 redef class PAssignOp
645 meth method_name: Symbol is abstract
646 end
647 redef class APlusAssignOp
648 redef meth method_name do return once "+".to_symbol
649 end
650 redef class AMinusAssignOp
651 redef meth method_name do return once "-".to_symbol
652 end
653
654 redef class ASelfExpr
655 redef meth its_variable do return variable
656
657 redef meth after_typing(v)
658 do
659 variable = v.self_var
660 _stype = v.variable_ctx.stype(variable)
661 _is_typed = true
662 end
663
664 redef meth is_self do return true
665 end
666
667 redef class AImplicitSelfExpr
668 redef meth is_implicit_self do return true
669 end
670
671 redef class AIfexprExpr
672 redef meth accept_typing(v)
673 do
674 var old_var_ctx = v.variable_ctx
675
676 v.visit(n_expr)
677 v.use_if_true_variable_ctx(n_expr)
678 v.visit(n_then)
679 v.variable_ctx = old_var_ctx
680 v.use_if_false_variable_ctx(n_expr)
681 v.visit(n_else)
682
683 v.check_conform_expr(n_expr, v.type_bool)
684
685 _stype = v.check_conform_multiexpr(null, [n_then, n_else])
686 _is_typed = _stype != null
687 end
688 end
689
690 redef class ABoolExpr
691 redef meth after_typing(v)
692 do
693 _stype = v.type_bool
694 _is_typed = true
695 end
696 end
697
698 redef class AOrExpr
699 redef meth accept_typing(v)
700 do
701 var old_var_ctx = v.variable_ctx
702
703 v.visit(n_expr)
704 v.use_if_false_variable_ctx(n_expr)
705
706 v.visit(n_expr2)
707 if n_expr2.if_false_variable_ctx != null then
708 _if_false_variable_ctx = n_expr2.if_false_variable_ctx
709 else
710 _if_false_variable_ctx = v.variable_ctx
711 end
712
713 v.variable_ctx = old_var_ctx
714
715 v.check_conform_expr(n_expr, v.type_bool)
716 v.check_conform_expr(n_expr2, v.type_bool)
717 _stype = v.type_bool
718 _is_typed = true
719 end
720 end
721
722 redef class AAndExpr
723 redef meth accept_typing(v)
724 do
725 var old_var_ctx = v.variable_ctx
726
727 v.visit(n_expr)
728 v.use_if_true_variable_ctx(n_expr)
729
730 v.visit(n_expr2)
731 if n_expr2.if_true_variable_ctx != null then
732 _if_true_variable_ctx = n_expr2.if_true_variable_ctx
733 else
734 _if_true_variable_ctx = v.variable_ctx
735 end
736
737 v.variable_ctx = old_var_ctx
738
739 v.check_conform_expr(n_expr, v.type_bool)
740 v.check_conform_expr(n_expr2, v.type_bool)
741 _stype = v.type_bool
742 _is_typed = true
743 end
744 end
745
746 redef class ANotExpr
747 redef meth after_typing(v)
748 do
749 v.check_conform_expr(n_expr, v.type_bool)
750
751 # Invert if_true/if_false information
752 _if_false_variable_ctx = n_expr._if_true_variable_ctx
753 _if_true_variable_ctx = n_expr._if_false_variable_ctx
754
755 _stype = v.type_bool
756 _is_typed = true
757 end
758 end
759
760 redef class AIntExpr
761 redef meth after_typing(v)
762 do
763 _stype = v.type_int
764 _is_typed = true
765 end
766 end
767
768 redef class AFloatExpr
769 redef meth after_typing(v)
770 do
771 _stype = v.type_float
772 _is_typed = true
773 end
774 end
775
776 redef class ACharExpr
777 redef meth after_typing(v)
778 do
779 _stype = v.type_char
780 _is_typed = true
781 end
782 end
783
784 redef class AStringFormExpr
785 readable attr _meth_with_native: MMMethod
786 redef meth after_typing(v)
787 do
788 _stype = v.type_string
789 _is_typed = true
790 _meth_with_native = _stype.local_class.select_method(once "with_native".to_symbol)
791 if _meth_with_native == null then v.error(self, "{_stype} MUST have a with_native method.")
792 end
793 end
794
795 redef class ASuperstringExpr
796 readable attr _meth_with_capacity: MMMethod
797 readable attr _meth_add: MMMethod
798 readable attr _meth_to_s: MMMethod
799 readable attr _atype: MMType
800 redef meth after_typing(v)
801 do
802 _stype = v.type_string
803 _atype = v.type_array(_stype)
804 _meth_with_capacity = _atype.local_class.select_method(once "with_capacity".to_symbol)
805 if _meth_with_capacity == null then v.error(self, "{_atype} MUST have a with_capacity method.")
806 _meth_add = _atype.local_class.select_method(once "add".to_symbol)
807 if _meth_add == null then v.error(self, "{_atype} MUST have an add method.")
808 _meth_to_s = v.type_object.local_class.select_method(once "to_s".to_symbol)
809 if _meth_to_s == null then v.error(self, "Object MUST have a to_s method.")
810 _is_typed = true
811 end
812 end
813
814 redef class ANullExpr
815 redef meth after_typing(v)
816 do
817 _stype = v.type_none
818 _is_typed = true
819 end
820 end
821
822 redef class AArrayExpr
823 readable attr _meth_with_capacity: MMMethod
824 readable attr _meth_add: MMMethod
825
826 redef meth after_typing(v)
827 do
828 var stype = v.check_conform_multiexpr(null, n_exprs)
829 if stype == null then return
830 do_typing(v, stype)
831 end
832
833 private meth do_typing(v: TypingVisitor, element_type: MMType)
834 do
835 _stype = v.type_array(element_type)
836
837 _meth_with_capacity = _stype.local_class.select_method(once "with_capacity".to_symbol)
838 if _meth_with_capacity == null then v.error(self, "{_stype} MUST have a with_capacity method.")
839 _meth_add = _stype.local_class.select_method(once "add".to_symbol)
840 if _meth_add == null then v.error(self, "{_stype} MUST have an add method.")
841
842 _is_typed = true
843 end
844 end
845
846 redef class ARangeExpr
847 readable attr _meth_init: MMMethod
848 redef meth after_typing(v)
849 do
850 if not v.check_expr(n_expr) or not v.check_expr(n_expr2) then return
851 var ntype = n_expr.stype
852 var ntype2 = n_expr2.stype
853 if ntype < ntype2 then
854 ntype = ntype2
855 else if not ntype2 < ntype then
856 v.error(self, "Type error: {ntype} incompatible with {ntype2}.")
857 return
858 end
859 var dtype = v.type_discrete
860 if not v.check_conform_expr(n_expr, dtype) or not v.check_conform_expr(n_expr2, dtype) then return
861 _stype = v.type_range(ntype)
862 _is_typed = true
863 end
864 end
865
866 redef class ACrangeExpr
867 redef meth after_typing(v)
868 do
869 super
870 _meth_init = stype.local_class.select_method(once "init".to_symbol)
871 end
872 end
873 redef class AOrangeExpr
874 redef meth after_typing(v)
875 do
876 super
877 _meth_init = stype.local_class.select_method(once "without_last".to_symbol)
878 end
879 end
880
881
882 redef class ASuperExpr
883 special ASuperInitCall
884 # readable attr _prop: MMSrcMethod
885 readable attr _init_in_superclass: MMMethod
886 redef meth after_typing(v)
887 do
888 var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters
889 if not precs.is_empty then
890 v.local_property.need_super = true
891 else if v.local_property.global.is_init then
892 var base_precs = v.local_class.super_methods_named(v.local_property.name)
893 for p in base_precs do
894 if not p.global.is_init then
895 v.error(self, "Error: {p.local_class}::{p} is not a constructor.")
896 else
897 precs.add(v.local_class[p.global])
898 end
899 end
900 if precs.is_empty then
901 v.error(self, "Error: No contructor named {v.local_property.name} in superclasses.")
902 return
903 else if precs.length > 1 then
904 v.error(self, "Error: Conflicting contructors named {v.local_property.name} in superclasses: {precs.join(", ")}.")
905 return
906 end
907 var p = base_precs.first
908 assert p isa MMMethod
909 _init_in_superclass = p
910 register_super_init_call(v, p)
911 if n_args.length > 0 then
912 var signature = get_signature(v, v.self_var.stype, p, true)
913 _arguments = process_signature(v, signature, p.name, n_args.to_a)
914 end
915 else
916 v.error(self, "Error: No super method to call for {v.local_property}.")
917 return
918 end
919
920 if precs.first.signature_for(v.self_var.stype).return_type != null then
921 var stypes = new Array[MMType]
922 var stype: MMType = null
923 for prop in precs do
924 assert prop isa MMMethod
925 var t = prop.signature_for(v.self_var.stype).return_type.for_module(v.module).adapt_to(v.local_property.signature.recv)
926 stypes.add(t)
927 if stype == null or stype < t then
928 stype = t
929 end
930 end
931 for t in stypes do
932 v.check_conform(self, t, stype)
933 end
934 _stype = stype
935 end
936 var p = v.local_property
937 assert p isa MMSrcMethod
938 _prop = p
939 _is_typed = true
940 end
941 end
942
943 redef class AAttrFormExpr
944 # Attribute accessed
945 readable attr _prop: MMAttribute
946
947 # Attribute type of the acceded attribute
948 readable attr _attr_type: MMType
949
950 # Compute the attribute accessed
951 private meth do_typing(v: TypingVisitor)
952 do
953 if not v.check_expr(n_expr) then return
954 var type_recv = n_expr.stype
955 var name = n_id.to_symbol
956 var lc = type_recv.local_class
957 if not lc.has_global_property_by_name(name) then
958 v.error(self, "Error: Attribute {name} doesn't exists in {type_recv}.")
959 return
960 end
961 var prop = lc.select_attribute(name)
962 if v.module.visibility_for(prop.global.local_class.module) < 3 then
963 v.error(self, "Error: Attribute {name} from {prop.global.local_class.module} is invisible in {v.module}")
964 end
965 _prop = prop
966 var at = prop.signature_for(type_recv).return_type
967 if not n_expr.is_self then at = at.not_for_self
968 _attr_type = at
969 end
970 end
971
972 redef class AAttrExpr
973 redef meth after_typing(v)
974 do
975 do_typing(v)
976 if prop == null then return
977 _stype = attr_type
978 _is_typed = true
979 end
980 end
981
982 redef class AAttrAssignExpr
983 redef meth after_typing(v)
984 do
985 do_typing(v)
986 if prop == null then return
987 if not v.check_conform_expr(n_value, attr_type) then return
988 _is_typed = true
989 end
990 end
991
992 redef class AAttrReassignExpr
993 redef meth after_typing(v)
994 do
995 do_typing(v)
996 if prop == null then return
997 var t = do_rvalue_typing(v, attr_type)
998 if t == null then return
999 v.check_conform(self, t, n_value.stype)
1000 _is_typed = true
1001 end
1002 end
1003
1004 class AAbsAbsSendExpr
1005 special PExpr
1006 # The signature of the called property
1007 readable attr _prop_signature: MMSignature
1008
1009 # The real arguments used (after star transformation) (once computed)
1010 readable attr _arguments: Array[PExpr]
1011
1012 # Check the conformity of a set of arguments `raw_args' to a signature.
1013 private meth process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: Array[PExpr]): Array[PExpr]
1014 do
1015 var par_vararg = psig.vararg_rank
1016 var par_arity = psig.arity
1017 var raw_arity: Int
1018 if raw_args == null then raw_arity = 0 else raw_arity = raw_args.length
1019 if par_arity > raw_arity or (par_arity != raw_arity and par_vararg == -1) then
1020 v.error(self, "Error: '{name}' arity missmatch.")
1021 return null
1022 end
1023 var arg_idx = 0
1024 var args = new Array[PExpr]
1025 for par_idx in [0..par_arity[ do
1026 var a: PExpr
1027 var par_type = psig[par_idx]
1028 if par_idx == par_vararg then
1029 var star = new Array[PExpr]
1030 for i in [0..(raw_arity-par_arity)] do
1031 a = raw_args[arg_idx]
1032 v.check_conform_expr(a, par_type)
1033 star.add(a)
1034 arg_idx = arg_idx + 1
1035 end
1036 var aa = new AArrayExpr.init_aarrayexpr(star)
1037 aa.do_typing(v, par_type)
1038 a = aa
1039 else
1040 a = raw_args[arg_idx]
1041 v.check_conform_expr(a, par_type)
1042 arg_idx = arg_idx + 1
1043 end
1044 args.add(a)
1045 end
1046 return args
1047 end
1048
1049 # Check the conformity of a set of defined closures
1050 private meth process_closures(v: TypingVisitor, psig: MMSignature, name: Symbol, cd: Array[PClosureDef]): MMType
1051 do
1052 var t = psig.return_type
1053 var cs = psig.closures # Declared closures
1054 var min_arity = 0
1055 for c in cs do
1056 if not c.is_optional then min_arity += 1
1057 end
1058 if cd != null then
1059 if cs.length == 0 then
1060 v.error(self, "Error: {name} does not require blocks.")
1061 else if cd.length > cs.length or cd.length < min_arity then
1062 v.error(self, "Error: {name} requires {cs.length} blocks, {cd.length} found.")
1063 else
1064 # Initialize the break list if a value is required for breaks (ie. if the method is a function)
1065 var break_list: Array[ABreakExpr] = null
1066 if t != null then break_list = new Array[ABreakExpr]
1067
1068 # Process each closure definition
1069 for i in [0..cd.length[ do
1070 var csi = cs[i]
1071 var cdi = cd[i]
1072 var esc = new EscapableClosure(cdi, csi, break_list)
1073 v.escapable_ctx.push(esc)
1074 cdi.accept_typing2(v, esc)
1075 v.escapable_ctx.pop
1076 end
1077
1078 # Check break type conformity
1079 if break_list != null then
1080 t = v.check_conform_multiexpr(t, break_list)
1081 end
1082 end
1083 else if min_arity != 0 then
1084 v.error(self, "Error: {name} requires {cs.length} blocks.")
1085 end
1086 return t
1087 end
1088 end
1089
1090 class AAbsSendExpr
1091 special AAbsAbsSendExpr
1092 # Compute the called global property
1093 private meth do_typing(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, recv_is_self: Bool, name: Symbol, raw_args: Array[PExpr], closure_defs: Array[PClosureDef])
1094 do
1095 var prop = get_property(v, type_recv, is_implicit_self, name)
1096 if prop == null then return
1097 var sig = get_signature(v, type_recv, prop, recv_is_self)
1098 if sig == null then return
1099 var args = process_signature(v, sig, prop.name, raw_args)
1100 if args == null then return
1101 var rtype = process_closures(v, sig, prop.name, closure_defs)
1102 if rtype == null and sig.return_type != null then return
1103 _prop = prop
1104 _prop_signature = sig
1105 _arguments = args
1106 _return_type = rtype
1107 end
1108
1109 private meth get_property(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, name: Symbol): MMMethod
1110 do
1111 if type_recv == null then return null
1112 var lc = type_recv.local_class
1113 var prop: MMMethod = null
1114 if lc.has_global_property_by_name(name) then prop = lc.select_method(name)
1115 if prop == null and v.local_property.global.is_init then
1116 var props = type_recv.local_class.super_methods_named(name)
1117 if props.length > 1 then
1118 v.error(self, "Error: Ambigous method name '{name}' for {props.join(", ")}. Use explicit designation.")
1119 return null
1120 else if props.length == 1 then
1121 var p = type_recv.local_class[props.first.global]
1122 assert p isa MMMethod
1123 prop = p
1124 end
1125
1126 end
1127 if prop == null then
1128 if is_implicit_self then
1129 v.error(self, "Error: Method or variable '{name}' unknown in {type_recv}.")
1130 else
1131 v.error(self, "Error: Method '{name}' doesn't exists in {type_recv}.")
1132 end
1133 return null
1134 end
1135 return prop
1136 end
1137
1138 # Get the signature for a local property and a receiver
1139 private meth get_signature(v: TypingVisitor, type_recv: MMType, prop: MMMethod, recv_is_self: Bool): MMSignature
1140 do
1141 prop.global.check_visibility(v, self, v.module, recv_is_self)
1142 var psig = prop.signature_for(type_recv)
1143 if not recv_is_self then psig = psig.not_for_self
1144 return psig
1145 end
1146
1147 # The invoked method (once computed)
1148 readable attr _prop: MMMethod
1149
1150 # The return type (if any) (once computed)
1151 readable attr _return_type: MMType
1152 end
1153
1154 # A possible call of constructor in a super class
1155 # Could be an explicit call or with the 'super' keyword
1156 class ASuperInitCall
1157 special AAbsSendExpr
1158 private meth register_super_init_call(v: TypingVisitor, property: MMMethod)
1159 do
1160 if parent != v.top_block and self != v.top_block then
1161 v.error(self, "Error: Constructor invocation {property} must not be in nested block.")
1162 end
1163 var cla = v.module[property.global.intro.local_class.global]
1164 var prev_class: MMLocalClass = null
1165 if not v.explicit_super_init_calls.is_empty then
1166 prev_class = v.explicit_super_init_calls.last.global.intro.local_class
1167 end
1168 var order = v.local_class.cshe.reverse_linear_extension
1169 if cla == v.local_class then
1170 v.explicit_other_init_call = true
1171 else if not order.has(cla) then
1172 v.error(self, "Error: Constructor of class {cla} must be one in {order.join(", ")}.")
1173 else if cla == prev_class then
1174 v.error(self, "Error: Only one super constructor invocation of class {cla} is allowed.")
1175 else
1176 var last_is_found = prev_class == null
1177 for c in order do
1178 if c == prev_class then
1179 last_is_found = true
1180 else if c == cla then
1181 if not last_is_found then
1182 v.error(self, "Error: Constructor of {c} must be invoked before constructor of {prev_class}")
1183 end
1184 v.explicit_super_init_calls.add(property)
1185 break
1186 end
1187 end
1188 end
1189 end
1190
1191 end
1192
1193 redef class ANewExpr
1194 special AAbsSendExpr
1195 redef meth after_typing(v)
1196 do
1197 var t = n_type.stype
1198 if t == null then return
1199 if t.local_class.global.is_abstract then
1200 v.error(self, "Error: try to instantiate abstract class {t.local_class}.")
1201 return
1202 end
1203 var name: Symbol
1204 if n_id == null then
1205 name = once "init".to_symbol
1206 else
1207 name = n_id.to_symbol
1208 end
1209
1210 do_typing(v, t, false, false, name, n_args.to_a, null)
1211 if prop == null then return
1212
1213 if not prop.global.is_init then
1214 v.error(self, "Error: {prop} is not a constructor.")
1215 return
1216 end
1217 _stype = t
1218 _is_typed = true
1219 end
1220 end
1221
1222
1223 redef class ASendExpr
1224 special ASuperInitCall
1225 # Name of the invoked property
1226 meth name: Symbol is abstract
1227
1228 # Raw arguments used (withour star transformation)
1229 meth raw_arguments: Array[PExpr] is abstract
1230
1231 # Closure definitions
1232 meth closure_defs: Array[PClosureDef] do return null
1233
1234 redef meth after_typing(v)
1235 do
1236 do_all_typing(v)
1237 end
1238
1239 private meth do_all_typing(v: TypingVisitor)
1240 do
1241 if not v.check_expr(n_expr) then return
1242 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_arguments, closure_defs)
1243 if prop == null then return
1244
1245 if prop.global.is_init then
1246 if not v.local_property.global.is_init then
1247 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1248 else if not n_expr.is_self then
1249 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1250 else
1251 register_super_init_call(v, prop)
1252 end
1253 end
1254
1255 _stype = return_type
1256 _is_typed = true
1257 end
1258 end
1259
1260 class ASendReassignExpr
1261 special ASendExpr
1262 special AReassignFormExpr
1263 readable attr _read_prop: MMMethod
1264 redef meth do_all_typing(v)
1265 do
1266 if not v.check_expr(n_expr) then return
1267 var raw_args = raw_arguments
1268 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_args, null)
1269 if prop == null then return
1270 if prop.global.is_init then
1271 if not v.local_property.global.is_init then
1272 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1273 else if not n_expr.is_self then
1274 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1275 end
1276 end
1277 var t = prop.signature_for(n_expr.stype).return_type
1278 if not n_expr.is_self then t = t.not_for_self
1279
1280 var t2 = do_rvalue_typing(v, t)
1281 if t2 == null then return
1282 v.check_conform(self, t2, n_value.stype)
1283
1284 _read_prop = prop
1285 var old_args = arguments
1286 raw_args.add(n_value)
1287
1288 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, "{name}=".to_symbol, raw_args, null)
1289 if prop == null then return
1290 if prop.global.is_init then
1291 if not v.local_property.global.is_init then
1292 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1293 else if not n_expr.is_self then
1294 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1295 end
1296 end
1297
1298 _arguments = old_args # FIXME: What if star parameters do not match betwen the two methods?
1299 _is_typed = true
1300 end
1301 end
1302
1303 redef class ABinopExpr
1304 redef meth raw_arguments do return [n_expr2]
1305 end
1306 redef class AEqExpr
1307 redef meth name do return once "==".to_symbol
1308 redef meth after_typing(v)
1309 do
1310 super
1311 if not is_typed then return
1312 if n_expr.stype isa MMTypeNone and not n_expr2.stype.is_nullable or
1313 n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
1314 v.warning(self, "Warning: comparaison between null and a non nullable value.")
1315 end
1316
1317 if n_expr.stype isa MMTypeNone then
1318 try_to_isa(v, n_expr2)
1319 else if n_expr2.stype isa MMTypeNone then
1320 try_to_isa(v, n_expr)
1321 end
1322 end
1323
1324 private meth try_to_isa(v: TypingVisitor, n: PExpr)
1325 do
1326 var variable = n.its_variable
1327 if variable != null then
1328 _if_false_variable_ctx = v.variable_ctx.sub_with(self, variable, n.stype.as_notnull)
1329 end
1330 end
1331 end
1332 redef class ANeExpr
1333 redef meth name do return once "!=".to_symbol
1334 redef meth after_typing(v)
1335 do
1336 super
1337 if not is_typed then return
1338 if n_expr.stype isa MMTypeNone and not n_expr2.stype.is_nullable or
1339 n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
1340 v.warning(self, "Warning: comparaison between null and a non nullable value.")
1341 end
1342
1343 if n_expr.stype isa MMTypeNone then
1344 try_to_isa(v, n_expr2)
1345 else if n_expr2.stype isa MMTypeNone then
1346 try_to_isa(v, n_expr)
1347 end
1348 end
1349
1350 private meth try_to_isa(v: TypingVisitor, n: PExpr)
1351 do
1352 var variable = n.its_variable
1353 if variable != null then
1354 _if_true_variable_ctx = v.variable_ctx.sub_with(self, variable, n.stype.as_notnull)
1355 end
1356 end
1357 end
1358 redef class ALtExpr
1359 redef meth name do return once "<".to_symbol
1360 end
1361 redef class ALeExpr
1362 redef meth name do return once "<=".to_symbol
1363 end
1364 redef class AGtExpr
1365 redef meth name do return once ">".to_symbol
1366 end
1367 redef class AGeExpr
1368 redef meth name do return once ">=".to_symbol
1369 end
1370 redef class APlusExpr
1371 redef meth name do return once "+".to_symbol
1372 end
1373 redef class AMinusExpr
1374 redef meth name do return once "-".to_symbol
1375 end
1376 redef class AStarshipExpr
1377 redef meth name do return once "<=>".to_symbol
1378 end
1379 redef class AStarExpr
1380 redef meth name do return once "*".to_symbol
1381 end
1382 redef class ASlashExpr
1383 redef meth name do return once "/".to_symbol
1384 end
1385 redef class APercentExpr
1386 redef meth name do return once "%".to_symbol
1387 end
1388
1389 redef class AUminusExpr
1390 redef meth name do return once "unary -".to_symbol
1391 redef meth raw_arguments do return null
1392 end
1393
1394 redef class ACallFormExpr
1395 redef meth after_typing(v)
1396 do
1397 if n_expr != null and n_expr.is_implicit_self then
1398 var name = n_id.to_symbol
1399 var variable = v.variable_ctx[name]
1400 if variable != null then
1401 if variable isa ClosureVariable then
1402 var n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs)
1403 replace_with(n)
1404 n.variable = variable
1405 n.after_typing(v)
1406 return
1407 else
1408 if not n_args.is_empty then
1409 v.error(self, "Error: {name} is variable, not a function.")
1410 return
1411 end
1412 var vform = variable_create(variable)
1413 vform.variable = variable
1414 replace_with(vform)
1415 vform.after_typing(v)
1416 return
1417 end
1418 end
1419 end
1420
1421 super
1422 end
1423
1424 redef meth closure_defs
1425 do
1426 if n_closure_defs == null or n_closure_defs.is_empty then
1427 return null
1428 else
1429 return n_closure_defs.to_a
1430 end
1431 end
1432
1433 # Create a variable acces corresponding to the call form
1434 meth variable_create(variable: Variable): AVarFormExpr is abstract
1435 end
1436
1437 redef class ACallExpr
1438 redef meth variable_create(variable)
1439 do
1440 return new AVarExpr.init_avarexpr(n_id)
1441 end
1442
1443 redef meth name do return n_id.to_symbol
1444 redef meth raw_arguments do return n_args.to_a
1445 end
1446
1447 redef class ACallAssignExpr
1448 redef meth variable_create(variable)
1449 do
1450 return new AVarAssignExpr.init_avarassignexpr(n_id, n_assign, n_value)
1451 end
1452
1453 redef meth name do return (n_id.text + "=").to_symbol
1454 redef meth raw_arguments do
1455 var res = n_args.to_a
1456 res.add(n_value)
1457 return res
1458 end
1459 end
1460
1461 redef class ACallReassignExpr
1462 special ASendReassignExpr
1463 redef meth variable_create(variable)
1464 do
1465 return new AVarReassignExpr.init_avarreassignexpr(n_id, n_assign_op, n_value)
1466 end
1467
1468 redef meth name do return n_id.to_symbol
1469 redef meth raw_arguments do return n_args.to_a
1470 end
1471
1472 redef class ABraExpr
1473 redef meth name do return once "[]".to_symbol
1474 redef meth raw_arguments do return n_args.to_a
1475 end
1476
1477 redef class ABraAssignExpr
1478 redef meth name do return once "[]=".to_symbol
1479 redef meth raw_arguments do
1480 var res = n_args.to_a
1481 res.add(n_value)
1482 return res
1483 end
1484 end
1485
1486 redef class ABraReassignExpr
1487 special ASendReassignExpr
1488 redef meth name do return once "[]".to_symbol
1489 redef meth raw_arguments do return n_args.to_a
1490 end
1491
1492 redef class AInitExpr
1493 redef meth name do return once "init".to_symbol
1494 redef meth raw_arguments do return n_args.to_a
1495 end
1496
1497 redef class AClosureCallExpr
1498 special AAbsAbsSendExpr
1499 redef meth after_typing(v)
1500 do
1501 var va = variable
1502 if va.closure.is_break then v.variable_ctx.unreash = true
1503 var sig = va.closure.signature
1504 var args = process_signature(v, sig, n_id.to_symbol, n_args.to_a)
1505 if not n_closure_defs.is_empty then
1506 process_closures(v, sig, n_id.to_symbol, n_closure_defs.to_a)
1507 end
1508 if args == null then return
1509 _prop_signature = sig
1510 _arguments = args
1511 _stype = sig.return_type
1512 _is_typed = true
1513 end
1514 end
1515
1516 redef class PClosureDef
1517 # The corresponding escapable object
1518 readable attr _escapable: EscapableBlock
1519
1520 attr _accept_typing2: Bool
1521 redef meth accept_typing(v)
1522 do
1523 # Typing is deferred, wait accept_typing2(v)
1524 if _accept_typing2 then super
1525 end
1526
1527 private meth accept_typing2(v: TypingVisitor, esc: EscapableClosure) is abstract
1528 end
1529
1530 redef class AClosureDef
1531 redef meth accept_typing2(v, esc)
1532 do
1533 _escapable = esc
1534
1535 var sig = esc.closure.signature
1536 if sig.arity != n_id.length then
1537 v.error(self, "Error: {sig.arity} automatic variable names expected, {n_id.length} found.")
1538 return
1539 end
1540
1541 closure = esc.closure
1542
1543 var old_var_ctx = v.variable_ctx
1544 var old_base_var_ctx = v.base_variable_ctx
1545 v.base_variable_ctx = v.variable_ctx
1546 v.variable_ctx = v.variable_ctx.sub(self)
1547 variables = new Array[AutoVariable]
1548 for i in [0..n_id.length[ do
1549 var va = new AutoVariable(n_id[i].to_symbol, self)
1550 variables.add(va)
1551 va.stype = sig[i]
1552 v.variable_ctx.add(va)
1553 end
1554
1555 _accept_typing2 = true
1556 accept_typing(v)
1557
1558 if v.variable_ctx.unreash == false then
1559 if closure.signature.return_type != null then
1560 v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
1561 else if closure.is_break then
1562 v.error(self, "Control error: Reached end of break block (a 'break' was expected).")
1563 end
1564 end
1565 v.variable_ctx = old_var_ctx
1566 v.base_variable_ctx = old_base_var_ctx
1567 end
1568 end
1569
1570 class ATypeCheckExpr
1571 special PExpr
1572 private meth check_expr_cast(v: TypingVisitor, n_expr: PExpr, n_type: PType)
1573 do
1574 if not v.check_expr(n_expr) then return
1575 var etype = n_expr.stype
1576 var ttype = n_type.stype
1577 if etype == ttype then
1578 v.warning(self, "Warning: Expression is already a {ttype}.")
1579 else if etype < ttype then
1580 v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.")
1581 else if etype.is_nullable and etype.as_notnull == ttype then
1582 if ttype isa MMTypeFormal and ttype.bound.is_nullable then
1583 # No warning in this case since with
1584 # type T: nullable A
1585 # var x: nullable T
1586 # 'x.as(not null)' != 'x.as(T)'
1587 # 'x != null' != 'x isa T'
1588 else if self isa AIsaExpr then
1589 v.warning(self, "Warning: Prefer '!= null'.")
1590 else
1591 v.warning(self, "Warning: Prefer '.as(not null)'.")
1592 end
1593 end
1594 end
1595 end
1596
1597 redef class AIsaExpr
1598 special ATypeCheckExpr
1599 redef meth after_typing(v)
1600 do
1601 check_expr_cast(v, n_expr, n_type)
1602 var variable = n_expr.its_variable
1603 if variable != null then
1604 _if_true_variable_ctx = v.variable_ctx.sub_with(self, variable, n_type.stype)
1605 end
1606 _stype = v.type_bool
1607 _is_typed = true
1608 end
1609 end
1610
1611 redef class AAsCastExpr
1612 special ATypeCheckExpr
1613 redef meth after_typing(v)
1614 do
1615 check_expr_cast(v, n_expr, n_type)
1616 _stype = n_type.stype
1617 _is_typed = _stype != null
1618 end
1619 end
1620
1621 redef class AAsNotnullExpr
1622 redef meth after_typing(v)
1623 do
1624 if not v.check_expr(n_expr) then return
1625 var t = n_expr.stype
1626 if t isa MMTypeNone then
1627 v.error(n_expr, "Type error: 'as(not null)' on 'null' value.")
1628 return
1629 else if not t.is_nullable then
1630 v.warning(n_expr, "Warning: 'as(not null)' on non nullable type.")
1631 end
1632 _stype = n_expr.stype.as_notnull
1633 _is_typed = true
1634 end
1635 end
1636
1637 redef class AProxyExpr
1638 redef meth after_typing(v)
1639 do
1640 if not n_expr.is_typed then return
1641 _is_typed = true
1642 if n_expr.is_statement then return
1643 _stype = n_expr.stype
1644 end
1645 end
1646
1647 redef class AOnceExpr
1648 redef meth accept_typing(v)
1649 do
1650 if v.once_count > 0 then
1651 v.warning(self, "Useless once in a once expression.")
1652 end
1653 v.once_count = v.once_count + 1
1654
1655 super
1656
1657 v.once_count = v.once_count - 1
1658 end
1659 end
1660