nullable: type, compile and test 'isset _attr'
[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 redef class AIssetAttrExpr
1005 redef meth after_typing(v)
1006 do
1007 do_typing(v)
1008 if prop == null then return
1009 if attr_type.is_nullable then
1010 v.error(self, "Error: isset on a nullable attribute.")
1011 end
1012 _stype = v.type_bool
1013 _is_typed = true
1014 end
1015 end
1016
1017 class AAbsAbsSendExpr
1018 special PExpr
1019 # The signature of the called property
1020 readable attr _prop_signature: MMSignature
1021
1022 # The real arguments used (after star transformation) (once computed)
1023 readable attr _arguments: Array[PExpr]
1024
1025 # Check the conformity of a set of arguments `raw_args' to a signature.
1026 private meth process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: Array[PExpr]): Array[PExpr]
1027 do
1028 var par_vararg = psig.vararg_rank
1029 var par_arity = psig.arity
1030 var raw_arity: Int
1031 if raw_args == null then raw_arity = 0 else raw_arity = raw_args.length
1032 if par_arity > raw_arity or (par_arity != raw_arity and par_vararg == -1) then
1033 v.error(self, "Error: '{name}' arity missmatch.")
1034 return null
1035 end
1036 var arg_idx = 0
1037 var args = new Array[PExpr]
1038 for par_idx in [0..par_arity[ do
1039 var a: PExpr
1040 var par_type = psig[par_idx]
1041 if par_idx == par_vararg then
1042 var star = new Array[PExpr]
1043 for i in [0..(raw_arity-par_arity)] do
1044 a = raw_args[arg_idx]
1045 v.check_conform_expr(a, par_type)
1046 star.add(a)
1047 arg_idx = arg_idx + 1
1048 end
1049 var aa = new AArrayExpr.init_aarrayexpr(star)
1050 aa.do_typing(v, par_type)
1051 a = aa
1052 else
1053 a = raw_args[arg_idx]
1054 v.check_conform_expr(a, par_type)
1055 arg_idx = arg_idx + 1
1056 end
1057 args.add(a)
1058 end
1059 return args
1060 end
1061
1062 # Check the conformity of a set of defined closures
1063 private meth process_closures(v: TypingVisitor, psig: MMSignature, name: Symbol, cd: Array[PClosureDef]): MMType
1064 do
1065 var t = psig.return_type
1066 var cs = psig.closures # Declared closures
1067 var min_arity = 0
1068 for c in cs do
1069 if not c.is_optional then min_arity += 1
1070 end
1071 if cd != null then
1072 if cs.length == 0 then
1073 v.error(self, "Error: {name} does not require blocks.")
1074 else if cd.length > cs.length or cd.length < min_arity then
1075 v.error(self, "Error: {name} requires {cs.length} blocks, {cd.length} found.")
1076 else
1077 # Initialize the break list if a value is required for breaks (ie. if the method is a function)
1078 var break_list: Array[ABreakExpr] = null
1079 if t != null then break_list = new Array[ABreakExpr]
1080
1081 # Process each closure definition
1082 for i in [0..cd.length[ do
1083 var csi = cs[i]
1084 var cdi = cd[i]
1085 var esc = new EscapableClosure(cdi, csi, break_list)
1086 v.escapable_ctx.push(esc)
1087 cdi.accept_typing2(v, esc)
1088 v.escapable_ctx.pop
1089 end
1090
1091 # Check break type conformity
1092 if break_list != null then
1093 t = v.check_conform_multiexpr(t, break_list)
1094 end
1095 end
1096 else if min_arity != 0 then
1097 v.error(self, "Error: {name} requires {cs.length} blocks.")
1098 end
1099 return t
1100 end
1101 end
1102
1103 class AAbsSendExpr
1104 special AAbsAbsSendExpr
1105 # Compute the called global property
1106 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])
1107 do
1108 var prop = get_property(v, type_recv, is_implicit_self, name)
1109 if prop == null then return
1110 var sig = get_signature(v, type_recv, prop, recv_is_self)
1111 if sig == null then return
1112 var args = process_signature(v, sig, prop.name, raw_args)
1113 if args == null then return
1114 var rtype = process_closures(v, sig, prop.name, closure_defs)
1115 if rtype == null and sig.return_type != null then return
1116 _prop = prop
1117 _prop_signature = sig
1118 _arguments = args
1119 _return_type = rtype
1120 end
1121
1122 private meth get_property(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, name: Symbol): MMMethod
1123 do
1124 if type_recv == null then return null
1125 var lc = type_recv.local_class
1126 var prop: MMMethod = null
1127 if lc.has_global_property_by_name(name) then prop = lc.select_method(name)
1128 if prop == null and v.local_property.global.is_init then
1129 var props = type_recv.local_class.super_methods_named(name)
1130 if props.length > 1 then
1131 v.error(self, "Error: Ambigous method name '{name}' for {props.join(", ")}. Use explicit designation.")
1132 return null
1133 else if props.length == 1 then
1134 var p = type_recv.local_class[props.first.global]
1135 assert p isa MMMethod
1136 prop = p
1137 end
1138
1139 end
1140 if prop == null then
1141 if is_implicit_self then
1142 v.error(self, "Error: Method or variable '{name}' unknown in {type_recv}.")
1143 else
1144 v.error(self, "Error: Method '{name}' doesn't exists in {type_recv}.")
1145 end
1146 return null
1147 end
1148 return prop
1149 end
1150
1151 # Get the signature for a local property and a receiver
1152 private meth get_signature(v: TypingVisitor, type_recv: MMType, prop: MMMethod, recv_is_self: Bool): MMSignature
1153 do
1154 prop.global.check_visibility(v, self, v.module, recv_is_self)
1155 var psig = prop.signature_for(type_recv)
1156 if not recv_is_self then psig = psig.not_for_self
1157 return psig
1158 end
1159
1160 # The invoked method (once computed)
1161 readable attr _prop: MMMethod
1162
1163 # The return type (if any) (once computed)
1164 readable attr _return_type: MMType
1165 end
1166
1167 # A possible call of constructor in a super class
1168 # Could be an explicit call or with the 'super' keyword
1169 class ASuperInitCall
1170 special AAbsSendExpr
1171 private meth register_super_init_call(v: TypingVisitor, property: MMMethod)
1172 do
1173 if parent != v.top_block and self != v.top_block then
1174 v.error(self, "Error: Constructor invocation {property} must not be in nested block.")
1175 end
1176 var cla = v.module[property.global.intro.local_class.global]
1177 var prev_class: MMLocalClass = null
1178 if not v.explicit_super_init_calls.is_empty then
1179 prev_class = v.explicit_super_init_calls.last.global.intro.local_class
1180 end
1181 var order = v.local_class.cshe.reverse_linear_extension
1182 if cla == v.local_class then
1183 v.explicit_other_init_call = true
1184 else if not order.has(cla) then
1185 v.error(self, "Error: Constructor of class {cla} must be one in {order.join(", ")}.")
1186 else if cla == prev_class then
1187 v.error(self, "Error: Only one super constructor invocation of class {cla} is allowed.")
1188 else
1189 var last_is_found = prev_class == null
1190 for c in order do
1191 if c == prev_class then
1192 last_is_found = true
1193 else if c == cla then
1194 if not last_is_found then
1195 v.error(self, "Error: Constructor of {c} must be invoked before constructor of {prev_class}")
1196 end
1197 v.explicit_super_init_calls.add(property)
1198 break
1199 end
1200 end
1201 end
1202 end
1203
1204 end
1205
1206 redef class ANewExpr
1207 special AAbsSendExpr
1208 redef meth after_typing(v)
1209 do
1210 var t = n_type.stype
1211 if t == null then return
1212 if t.local_class.global.is_abstract then
1213 v.error(self, "Error: try to instantiate abstract class {t.local_class}.")
1214 return
1215 end
1216 var name: Symbol
1217 if n_id == null then
1218 name = once "init".to_symbol
1219 else
1220 name = n_id.to_symbol
1221 end
1222
1223 do_typing(v, t, false, false, name, n_args.to_a, null)
1224 if prop == null then return
1225
1226 if not prop.global.is_init then
1227 v.error(self, "Error: {prop} is not a constructor.")
1228 return
1229 end
1230 _stype = t
1231 _is_typed = true
1232 end
1233 end
1234
1235
1236 redef class ASendExpr
1237 special ASuperInitCall
1238 # Name of the invoked property
1239 meth name: Symbol is abstract
1240
1241 # Raw arguments used (withour star transformation)
1242 meth raw_arguments: Array[PExpr] is abstract
1243
1244 # Closure definitions
1245 meth closure_defs: Array[PClosureDef] do return null
1246
1247 redef meth after_typing(v)
1248 do
1249 do_all_typing(v)
1250 end
1251
1252 private meth do_all_typing(v: TypingVisitor)
1253 do
1254 if not v.check_expr(n_expr) then return
1255 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_arguments, closure_defs)
1256 if prop == null then return
1257
1258 if prop.global.is_init then
1259 if not v.local_property.global.is_init then
1260 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1261 else if not n_expr.is_self then
1262 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1263 else
1264 register_super_init_call(v, prop)
1265 end
1266 end
1267
1268 _stype = return_type
1269 _is_typed = true
1270 end
1271 end
1272
1273 class ASendReassignExpr
1274 special ASendExpr
1275 special AReassignFormExpr
1276 readable attr _read_prop: MMMethod
1277 redef meth do_all_typing(v)
1278 do
1279 if not v.check_expr(n_expr) then return
1280 var raw_args = raw_arguments
1281 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_args, null)
1282 if prop == null then return
1283 if prop.global.is_init then
1284 if not v.local_property.global.is_init then
1285 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1286 else if not n_expr.is_self then
1287 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1288 end
1289 end
1290 var t = prop.signature_for(n_expr.stype).return_type
1291 if not n_expr.is_self then t = t.not_for_self
1292
1293 var t2 = do_rvalue_typing(v, t)
1294 if t2 == null then return
1295 v.check_conform(self, t2, n_value.stype)
1296
1297 _read_prop = prop
1298 var old_args = arguments
1299 raw_args.add(n_value)
1300
1301 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, "{name}=".to_symbol, raw_args, null)
1302 if prop == null then return
1303 if prop.global.is_init then
1304 if not v.local_property.global.is_init then
1305 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1306 else if not n_expr.is_self then
1307 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1308 end
1309 end
1310
1311 _arguments = old_args # FIXME: What if star parameters do not match betwen the two methods?
1312 _is_typed = true
1313 end
1314 end
1315
1316 redef class ABinopExpr
1317 redef meth raw_arguments do return [n_expr2]
1318 end
1319 redef class AEqExpr
1320 redef meth name do return once "==".to_symbol
1321 redef meth after_typing(v)
1322 do
1323 super
1324 if not is_typed then return
1325 if n_expr.stype isa MMTypeNone and not n_expr2.stype.is_nullable or
1326 n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
1327 v.warning(self, "Warning: comparaison between null and a non nullable value.")
1328 end
1329
1330 if n_expr.stype isa MMTypeNone then
1331 try_to_isa(v, n_expr2)
1332 else if n_expr2.stype isa MMTypeNone then
1333 try_to_isa(v, n_expr)
1334 end
1335 end
1336
1337 private meth try_to_isa(v: TypingVisitor, n: PExpr)
1338 do
1339 var variable = n.its_variable
1340 if variable != null then
1341 _if_false_variable_ctx = v.variable_ctx.sub_with(self, variable, n.stype.as_notnull)
1342 end
1343 end
1344 end
1345 redef class ANeExpr
1346 redef meth name do return once "!=".to_symbol
1347 redef meth after_typing(v)
1348 do
1349 super
1350 if not is_typed then return
1351 if n_expr.stype isa MMTypeNone and not n_expr2.stype.is_nullable or
1352 n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
1353 v.warning(self, "Warning: comparaison between null and a non nullable value.")
1354 end
1355
1356 if n_expr.stype isa MMTypeNone then
1357 try_to_isa(v, n_expr2)
1358 else if n_expr2.stype isa MMTypeNone then
1359 try_to_isa(v, n_expr)
1360 end
1361 end
1362
1363 private meth try_to_isa(v: TypingVisitor, n: PExpr)
1364 do
1365 var variable = n.its_variable
1366 if variable != null then
1367 _if_true_variable_ctx = v.variable_ctx.sub_with(self, variable, n.stype.as_notnull)
1368 end
1369 end
1370 end
1371 redef class ALtExpr
1372 redef meth name do return once "<".to_symbol
1373 end
1374 redef class ALeExpr
1375 redef meth name do return once "<=".to_symbol
1376 end
1377 redef class AGtExpr
1378 redef meth name do return once ">".to_symbol
1379 end
1380 redef class AGeExpr
1381 redef meth name do return once ">=".to_symbol
1382 end
1383 redef class APlusExpr
1384 redef meth name do return once "+".to_symbol
1385 end
1386 redef class AMinusExpr
1387 redef meth name do return once "-".to_symbol
1388 end
1389 redef class AStarshipExpr
1390 redef meth name do return once "<=>".to_symbol
1391 end
1392 redef class AStarExpr
1393 redef meth name do return once "*".to_symbol
1394 end
1395 redef class ASlashExpr
1396 redef meth name do return once "/".to_symbol
1397 end
1398 redef class APercentExpr
1399 redef meth name do return once "%".to_symbol
1400 end
1401
1402 redef class AUminusExpr
1403 redef meth name do return once "unary -".to_symbol
1404 redef meth raw_arguments do return null
1405 end
1406
1407 redef class ACallFormExpr
1408 redef meth after_typing(v)
1409 do
1410 if n_expr != null and n_expr.is_implicit_self then
1411 var name = n_id.to_symbol
1412 var variable = v.variable_ctx[name]
1413 if variable != null then
1414 if variable isa ClosureVariable then
1415 var n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs)
1416 replace_with(n)
1417 n.variable = variable
1418 n.after_typing(v)
1419 return
1420 else
1421 if not n_args.is_empty then
1422 v.error(self, "Error: {name} is variable, not a function.")
1423 return
1424 end
1425 var vform = variable_create(variable)
1426 vform.variable = variable
1427 replace_with(vform)
1428 vform.after_typing(v)
1429 return
1430 end
1431 end
1432 end
1433
1434 super
1435 end
1436
1437 redef meth closure_defs
1438 do
1439 if n_closure_defs == null or n_closure_defs.is_empty then
1440 return null
1441 else
1442 return n_closure_defs.to_a
1443 end
1444 end
1445
1446 # Create a variable acces corresponding to the call form
1447 meth variable_create(variable: Variable): AVarFormExpr is abstract
1448 end
1449
1450 redef class ACallExpr
1451 redef meth variable_create(variable)
1452 do
1453 return new AVarExpr.init_avarexpr(n_id)
1454 end
1455
1456 redef meth name do return n_id.to_symbol
1457 redef meth raw_arguments do return n_args.to_a
1458 end
1459
1460 redef class ACallAssignExpr
1461 redef meth variable_create(variable)
1462 do
1463 return new AVarAssignExpr.init_avarassignexpr(n_id, n_assign, n_value)
1464 end
1465
1466 redef meth name do return (n_id.text + "=").to_symbol
1467 redef meth raw_arguments do
1468 var res = n_args.to_a
1469 res.add(n_value)
1470 return res
1471 end
1472 end
1473
1474 redef class ACallReassignExpr
1475 special ASendReassignExpr
1476 redef meth variable_create(variable)
1477 do
1478 return new AVarReassignExpr.init_avarreassignexpr(n_id, n_assign_op, n_value)
1479 end
1480
1481 redef meth name do return n_id.to_symbol
1482 redef meth raw_arguments do return n_args.to_a
1483 end
1484
1485 redef class ABraExpr
1486 redef meth name do return once "[]".to_symbol
1487 redef meth raw_arguments do return n_args.to_a
1488 end
1489
1490 redef class ABraAssignExpr
1491 redef meth name do return once "[]=".to_symbol
1492 redef meth raw_arguments do
1493 var res = n_args.to_a
1494 res.add(n_value)
1495 return res
1496 end
1497 end
1498
1499 redef class ABraReassignExpr
1500 special ASendReassignExpr
1501 redef meth name do return once "[]".to_symbol
1502 redef meth raw_arguments do return n_args.to_a
1503 end
1504
1505 redef class AInitExpr
1506 redef meth name do return once "init".to_symbol
1507 redef meth raw_arguments do return n_args.to_a
1508 end
1509
1510 redef class AClosureCallExpr
1511 special AAbsAbsSendExpr
1512 redef meth after_typing(v)
1513 do
1514 var va = variable
1515 if va.closure.is_break then v.variable_ctx.unreash = true
1516 var sig = va.closure.signature
1517 var args = process_signature(v, sig, n_id.to_symbol, n_args.to_a)
1518 if not n_closure_defs.is_empty then
1519 process_closures(v, sig, n_id.to_symbol, n_closure_defs.to_a)
1520 end
1521 if args == null then return
1522 _prop_signature = sig
1523 _arguments = args
1524 _stype = sig.return_type
1525 _is_typed = true
1526 end
1527 end
1528
1529 redef class PClosureDef
1530 # The corresponding escapable object
1531 readable attr _escapable: EscapableBlock
1532
1533 attr _accept_typing2: Bool
1534 redef meth accept_typing(v)
1535 do
1536 # Typing is deferred, wait accept_typing2(v)
1537 if _accept_typing2 then super
1538 end
1539
1540 private meth accept_typing2(v: TypingVisitor, esc: EscapableClosure) is abstract
1541 end
1542
1543 redef class AClosureDef
1544 redef meth accept_typing2(v, esc)
1545 do
1546 _escapable = esc
1547
1548 var sig = esc.closure.signature
1549 if sig.arity != n_id.length then
1550 v.error(self, "Error: {sig.arity} automatic variable names expected, {n_id.length} found.")
1551 return
1552 end
1553
1554 closure = esc.closure
1555
1556 var old_var_ctx = v.variable_ctx
1557 var old_base_var_ctx = v.base_variable_ctx
1558 v.base_variable_ctx = v.variable_ctx
1559 v.variable_ctx = v.variable_ctx.sub(self)
1560 variables = new Array[AutoVariable]
1561 for i in [0..n_id.length[ do
1562 var va = new AutoVariable(n_id[i].to_symbol, self)
1563 variables.add(va)
1564 va.stype = sig[i]
1565 v.variable_ctx.add(va)
1566 end
1567
1568 _accept_typing2 = true
1569 accept_typing(v)
1570
1571 if v.variable_ctx.unreash == false then
1572 if closure.signature.return_type != null then
1573 v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
1574 else if closure.is_break then
1575 v.error(self, "Control error: Reached end of break block (a 'break' was expected).")
1576 end
1577 end
1578 v.variable_ctx = old_var_ctx
1579 v.base_variable_ctx = old_base_var_ctx
1580 end
1581 end
1582
1583 class ATypeCheckExpr
1584 special PExpr
1585 private meth check_expr_cast(v: TypingVisitor, n_expr: PExpr, n_type: PType)
1586 do
1587 if not v.check_expr(n_expr) then return
1588 var etype = n_expr.stype
1589 var ttype = n_type.stype
1590 if etype == ttype then
1591 v.warning(self, "Warning: Expression is already a {ttype}.")
1592 else if etype < ttype then
1593 v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.")
1594 else if etype.is_nullable and etype.as_notnull == ttype then
1595 if ttype isa MMTypeFormal and ttype.bound.is_nullable then
1596 # No warning in this case since with
1597 # type T: nullable A
1598 # var x: nullable T
1599 # 'x.as(not null)' != 'x.as(T)'
1600 # 'x != null' != 'x isa T'
1601 else if self isa AIsaExpr then
1602 v.warning(self, "Warning: Prefer '!= null'.")
1603 else
1604 v.warning(self, "Warning: Prefer '.as(not null)'.")
1605 end
1606 end
1607 end
1608 end
1609
1610 redef class AIsaExpr
1611 special ATypeCheckExpr
1612 redef meth after_typing(v)
1613 do
1614 check_expr_cast(v, n_expr, n_type)
1615 var variable = n_expr.its_variable
1616 if variable != null then
1617 _if_true_variable_ctx = v.variable_ctx.sub_with(self, variable, n_type.stype)
1618 end
1619 _stype = v.type_bool
1620 _is_typed = true
1621 end
1622 end
1623
1624 redef class AAsCastExpr
1625 special ATypeCheckExpr
1626 redef meth after_typing(v)
1627 do
1628 check_expr_cast(v, n_expr, n_type)
1629 _stype = n_type.stype
1630 _is_typed = _stype != null
1631 end
1632 end
1633
1634 redef class AAsNotnullExpr
1635 redef meth after_typing(v)
1636 do
1637 if not v.check_expr(n_expr) then return
1638 var t = n_expr.stype
1639 if t isa MMTypeNone then
1640 v.error(n_expr, "Type error: 'as(not null)' on 'null' value.")
1641 return
1642 else if not t.is_nullable then
1643 v.warning(n_expr, "Warning: 'as(not null)' on non nullable type.")
1644 end
1645 _stype = n_expr.stype.as_notnull
1646 _is_typed = true
1647 end
1648 end
1649
1650 redef class AProxyExpr
1651 redef meth after_typing(v)
1652 do
1653 if not n_expr.is_typed then return
1654 _is_typed = true
1655 if n_expr.is_statement then return
1656 _stype = n_expr.stype
1657 end
1658 end
1659
1660 redef class AOnceExpr
1661 redef meth accept_typing(v)
1662 do
1663 if v.once_count > 0 then
1664 v.warning(self, "Useless once in a once expression.")
1665 end
1666 v.once_count = v.once_count + 1
1667
1668 super
1669
1670 v.once_count = v.once_count - 1
1671 end
1672 end
1673