niti, nitg & rta: use lookup_first_definition
[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 flow
22 import scope
23
24 redef class MMSrcModule
25 # Walk trough the module and type statments and expressions
26 # Require than supermodules are processed
27 fun do_typing(tc: ToolContext)
28 do
29 var tv = new TypingVisitor(tc, self)
30 tv.enter_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 super AbsSyntaxVisitor
41 redef fun visit(n)
42 do
43 if n != null then n.accept_typing(self)
44 end
45
46 # Current knowledge about scoped things (variable, labels, etc.)
47 readable var _scope_ctx: ScopeContext = new ScopeContext(self)
48
49 # Current knowledge about control flow
50 fun flow_ctx: FlowContext do return _flow_ctx.as(not null)
51 writable var _flow_ctx: nullable FlowContext
52
53 # Mark a local variable as set
54 fun mark_is_set(va: Variable)
55 do
56 if flow_ctx.is_set(va) then return
57 flow_ctx = flow_ctx.sub_setvariable(va)
58 end
59
60 # Mark the flow context as unreashable
61 fun mark_unreash(n: ANode)
62 do
63 flow_ctx = flow_ctx.sub_unreash(n)
64 end
65
66 # Enter in an expression as inside a new local variable scope
67 fun enter_visit_block(node: nullable AExpr)
68 do
69 if node == null then return
70 scope_ctx.push(node)
71 enter_visit(node)
72 scope_ctx.pop
73 end
74
75 # Non-bypassable knowledge about variables names and types
76 fun base_flow_ctx: FlowContext do return _base_flow_ctx.as(not null)
77 writable var _base_flow_ctx: nullable FlowContext
78
79 # The current reciever
80 fun self_var: ParamVariable do return _self_var.as(not null)
81 writable var _self_var: nullable ParamVariable
82
83 # Block of the current method
84 readable writable var _top_block: nullable AExpr
85
86 # List of explicit invocation of constructors of super-classes
87 readable writable var _explicit_super_init_calls: nullable Array[MMMethod]
88
89 # Is a other constructor of the same class invoked
90 readable writable var _explicit_other_init_call: Bool = false
91
92 # Make the if_true_flow_ctx of the expression effective
93 private fun use_if_true_flow_ctx(e: AExpr)
94 do
95 var ctx = e.if_true_flow_ctx
96 if ctx != null then flow_ctx = ctx
97 end
98
99 # Make the if_false_flow_ctx of the expression effective
100 private fun use_if_false_flow_ctx(e: AExpr)
101 do
102 var ctx = e.if_false_flow_ctx
103 if ctx != null then flow_ctx = ctx
104 end
105
106 # Are we inside a default closure definition ?
107 readable writable var _is_default_closure_definition: Bool = false
108
109 # Number of nested once
110 readable writable var _once_count: Int = 0
111
112 init(tc, mod) do super
113
114 private fun get_default_constructor_for(n: ANode, c: MMLocalClass, prop: MMSrcMethod): nullable MMMethod
115 do
116 var v = self
117 #var prop = v.local_property
118 #assert prop isa MMMethod
119 var candidates = new Array[MMMethod]
120 var false_candidates = new Array[MMMethod]
121 var parity = prop.signature.arity
122 for g in c.global_properties do
123 if not g.is_init_for(c) then continue
124 var gp = c[g]
125 var gps = gp.signature_for(c.get_type)
126 assert gp isa MMSrcMethod
127 var garity = gps.arity
128 if gp.name == prop.name then
129 if garity == 0 or (parity == garity and prop.signature < gps) then
130 return gp
131 else
132 false_candidates.add(gp)
133 end
134 else if garity == 0 and gp.name == once ("init".to_symbol) then
135 candidates.add(gp)
136 false_candidates.add(gp)
137 else
138 false_candidates.add(gp)
139 end
140 end
141 if candidates.length == 1 then
142 return candidates.first
143 else if candidates.length > 0 then
144 var a = new Array[String]
145 for p in candidates do
146 a.add("{p.full_name}{p.signature.as(not null)}")
147 end
148 v.error(n, "Error: Conflicting default constructor to call for {c}: {a.join(", ")}.")
149 return null
150 else if false_candidates.length > 0 then
151 var a = new Array[String]
152 for p in false_candidates do
153 a.add("{p.full_name}{p.signature.as(not null)}")
154 end
155 v.error(n, "Error: there is no available compatible constructor in {c}. Discarded candidates are {a.join(", ")}.")
156 return null
157 else
158 v.error(n, "Error: there is no available compatible constructor in {c}.")
159 return null
160 end
161 end
162 end
163
164
165 ###############################################################################
166
167 redef class ANode
168 private fun accept_typing(v: TypingVisitor)
169 do
170 accept_abs_syntax_visitor(v)
171 after_typing(v)
172 end
173 private fun after_typing(v: TypingVisitor) do end
174 end
175
176 redef class AClassdef
177 redef fun accept_typing(v)
178 do
179 v.self_var = new ParamVariable("self".to_symbol, self)
180 v.self_var.stype = local_class.get_type
181 super
182 end
183 end
184
185 redef class APropdef
186 redef fun self_var do return _self_var.as(not null)
187 var _self_var: nullable ParamVariable
188 end
189
190 redef class AAttrPropdef
191 redef fun accept_typing(v)
192 do
193 v.flow_ctx = new RootFlowContext(v, self)
194 v.base_flow_ctx = v.flow_ctx
195
196 v.scope_ctx.push(self)
197 _self_var = v.self_var
198 super
199 if n_expr != null then
200 v.check_conform_expr(n_expr.as(not null), prop.signature.return_type.as(not null))
201 end
202 v.scope_ctx.pop
203 end
204 end
205
206 redef class AMethPropdef
207 redef fun accept_typing(v)
208 do
209 v.flow_ctx = new RootFlowContext(v, self)
210 v.base_flow_ctx = v.flow_ctx
211
212 v.scope_ctx.push(self)
213 _self_var = v.self_var
214 super
215 v.scope_ctx.pop
216 end
217 end
218
219 redef class AConcreteMethPropdef
220 redef fun after_typing(v)
221 do
222 super
223 if not v.flow_ctx.unreash and method.signature.return_type != null then
224 v.error(self, "Control error: Reached end of function (a 'return' with a value was expected).")
225 end
226 end
227 end
228
229 redef class AConcreteInitPropdef
230 redef fun accept_typing(v)
231 do
232 v.top_block = n_block
233 v.explicit_super_init_calls = explicit_super_init_calls
234 v.explicit_other_init_call = false
235 super
236 end
237
238 redef fun after_typing(v)
239 do
240 super
241 if v.explicit_other_init_call or method.global.intro != method then
242 # TODO: something?
243 else
244 var i = 0
245 var l = explicit_super_init_calls.length
246 var cur_m: nullable MMMethod = null
247 var cur_c: nullable MMLocalClass = null
248 if i < l then
249 cur_m = explicit_super_init_calls[i]
250 cur_c = cur_m.global.intro.local_class.for_module(v.mmmodule)
251 end
252 var j = 0
253 while j < v.local_class.cshe.direct_greaters.length do
254 var c = v.local_class.cshe.direct_greaters[j]
255 if c.global.is_interface or c.global.is_enum or c.global.is_extern or c.global.is_mixin then
256 j += 1
257 else if cur_c != null and (c.cshe <= cur_c or cur_c.global.is_mixin) then
258 if c == cur_c then j += 1
259 super_init_calls.add(cur_m.as(not null))
260 i += 1
261 if i < l then
262 cur_m = explicit_super_init_calls[i]
263 cur_c = cur_m.global.intro.local_class.for_module(v.mmmodule)
264 else
265 cur_m = null
266 cur_c = null
267 end
268 else
269 var p = v.get_default_constructor_for(self, c, method)
270 if p != null then
271 super_init_calls.add(p)
272 end
273 j += 1
274 end
275 end
276 end
277 end
278 end
279
280 redef class AExternInitPropdef
281 redef fun accept_typing(v)
282 do
283 v.explicit_other_init_call = false
284 super
285 end
286 redef fun after_typing(v)
287 do
288 super
289 end
290 end
291
292 redef class ASignature
293 redef fun after_typing(v)
294 do
295 if self.n_opar != null and self.n_params.is_empty then
296 v.warning(self, "Warning: superfluous parentheses.")
297 end
298 end
299 end
300
301 redef class AParam
302 redef fun after_typing(v)
303 do
304 v.scope_ctx.add_variable(variable)
305 end
306 end
307
308 redef class AClosureDecl
309 # The corresponding escapable object
310 readable var _escapable: nullable EscapableBlock
311
312 redef fun accept_typing(v)
313 do
314 # Register the closure for ClosureCallExpr
315 v.scope_ctx.add_variable(variable)
316
317 var old_flow_ctx = v.flow_ctx
318 var old_base_flow_ctx = v.base_flow_ctx
319 v.base_flow_ctx = v.flow_ctx
320
321 var blist: nullable Array[AExpr] = null
322 var t = v.local_property.signature.return_type
323 if t != null then blist = new Array[AExpr]
324 var escapable = new EscapableClosure(self, variable.closure, blist)
325 _escapable = escapable
326 v.scope_ctx.push_escapable(escapable, null)
327
328 v.is_default_closure_definition = true
329
330 super
331
332 v.is_default_closure_definition = false
333
334 if n_expr != null then
335 if v.flow_ctx.unreash == false then
336 if variable.closure.signature.return_type != null then
337 v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
338 else if variable.closure.is_break and escapable.break_list != null then
339 v.error(self, "Control error: Reached end of break block (a 'break' with a value was expected).")
340 end
341 end
342 end
343 if blist != null then for x in blist do
344 v.check_conform_expr(x, t)
345 end
346
347 v.flow_ctx = old_flow_ctx
348 v.base_flow_ctx = old_base_flow_ctx
349 v.scope_ctx.pop
350 end
351 end
352
353 redef class AType
354 redef fun stype: MMType do return _stype.as(not null)
355 redef fun is_typed: Bool do return _stype != null
356 var _stype: nullable MMType
357
358 redef fun after_typing(v)
359 do
360 _stype = get_stype(v)
361 end
362 end
363
364 redef class AExpr
365 redef readable var _is_typed: Bool = false
366 redef fun is_statement: Bool do return _stype == null
367 redef fun stype
368 do
369 if not is_typed then
370 print "{location}: not is_typed"
371 abort
372 end
373 if is_statement then
374 print "{location}: is_statement"
375 abort
376 end
377 return _stype.as(not null)
378 end
379 var _stype: nullable MMType
380
381 redef fun after_typing(v)
382 do
383 # Default behavior is to be happy
384 _is_typed = true
385 end
386
387 # Is the expression the implicit receiver
388 fun is_implicit_self: Bool do return false
389
390 # Is the expression the current receiver (implicit or explicit)
391 fun is_self: Bool do return false
392
393 # The variable accessed is any
394 fun its_variable: nullable Variable do return null
395
396 # The control flow information if current boolean expression is true
397 readable private var _if_true_flow_ctx: nullable FlowContext
398
399 # The control flow information if current boolean expression is false
400 readable private var _if_false_flow_ctx: nullable FlowContext
401
402 # Wharn in case of superfluous parentheses
403 private fun warn_parentheses(v: AbsSyntaxVisitor)
404 do
405 end
406 end
407
408 redef class AParExpr
409 redef fun warn_parentheses(v)
410 do
411 v.warning(self, "Warning: superfluous parentheses.")
412 end
413 end
414
415 redef class AParExprs
416 redef fun after_typing(v)
417 do
418 if n_exprs.is_empty then
419 v.warning(self, "Warning: superfluous parentheses.")
420 end
421 end
422 end
423
424 redef class AVardeclExpr
425 var _variable: nullable VarVariable
426 redef fun variable do return _variable.as(not null)
427
428 redef fun after_typing(v)
429 do
430 var va = new VarVariable(n_id.to_symbol, n_id)
431 _variable = va
432 v.scope_ctx.add_variable(va)
433 var ne = n_expr
434 if ne != null then v.mark_is_set(va)
435
436 if n_type != null then
437 if not n_type.is_typed then return
438 va.stype = n_type.stype
439 if ne != null then
440 v.check_conform_expr(ne, va.stype)
441 end
442 else if ne != null then
443 if not v.check_expr(ne) then return
444 va.stype = ne.stype
445 else
446 va.stype = v.type_object.as_nullable
447 end
448 _is_typed = true
449 end
450 end
451
452 redef class ABlockExpr
453 redef fun accept_typing(v)
454 do
455 for e in n_expr do
456 if not v.flow_ctx.unreash then
457 v.enter_visit(e)
458 else if not v.flow_ctx.already_unreash then
459 v.flow_ctx.already_unreash = true
460 v.error(e, "Error: unreachable statement.")
461 end
462 end
463
464 _is_typed = true
465 end
466 end
467
468 redef class AReturnExpr
469 redef fun after_typing(v)
470 do
471 v.mark_unreash(self)
472 var t = v.local_property.signature.return_type
473
474 if v.is_default_closure_definition then
475 v.error(self, "Error: 'return' invalid in default closure definitions. Use 'continue' or 'break'.")
476 return
477 end
478
479 var e = n_expr
480 if e == null and t != null then
481 v.error(self, "Error: Return without value in a function.")
482 else if e != null and t == null then
483 v.error(self, "Error: Return with value in a procedure.")
484 else if e != null and t != null then
485 v.check_conform_expr(e, t)
486 end
487 if e != null then
488 e.warn_parentheses(v)
489 end
490 _is_typed = true
491 end
492 end
493
494 redef class AContinueExpr
495 redef fun after_typing(v)
496 do
497 v.mark_unreash(self)
498 var esc = compute_escapable_block(v.scope_ctx)
499 if esc == null then return
500
501 if esc.is_break_block then
502 v.error(self, "Error: cannot 'continue', only 'break'.")
503 return
504 end
505
506 var t = esc.continue_stype
507 var e = n_expr
508 if e == null and t != null then
509 v.error(self, "Error: continue with a value required in this block.")
510 else if e != null and t == null then
511 v.error(self, "Error: continue without value required in this block.")
512 else if e != null and t != null then
513 v.check_conform_expr(e, t)
514 end
515 if e != null then
516 e.warn_parentheses(v)
517 end
518 _is_typed = true
519 end
520 end
521
522 redef class ABreakExpr
523 redef fun after_typing(v)
524 do
525 var old_flow_ctx = v.flow_ctx
526 v.mark_unreash(self)
527 var esc = compute_escapable_block(v.scope_ctx)
528 if esc == null then return
529
530 esc.break_flow_contexts.add(old_flow_ctx)
531
532 var bl = esc.break_list
533 var e = n_expr
534 if e == null and bl != null then
535 v.error(self, "Error: break with a value required in this block.")
536 else if e != null and bl == null then
537 v.error(self, "Error: break without value required in this block.")
538 else if e != null and bl != null then
539 # Typing check can only be done later
540 bl.add(e)
541 end
542 if e != null then
543 e.warn_parentheses(v)
544 end
545 _is_typed = true
546 end
547 end
548
549 redef class AAbortExpr
550 redef fun after_typing(v)
551 do
552 v.mark_unreash(self)
553 _is_typed = true
554 end
555 end
556
557 # An abstract control structure with feature escapable block
558 abstract class AAbsControl
559 super AExpr
560 # The corresponding escapable block
561 readable var _escapable: nullable EscapableBlock
562
563 # Enter and process a control structure
564 private fun process_control(v: TypingVisitor, escapable: EscapableBlock, n_label: nullable ALabel, is_loop: Bool)
565 do
566 # Register the escapable block
567 _escapable = escapable
568 v.scope_ctx.push_escapable(escapable, n_label)
569
570 # Save an prepare the contextes
571 var old_flow_ctx = v.flow_ctx
572 var old_base_flow_ctx = v.base_flow_ctx
573 if is_loop then v.base_flow_ctx = v.flow_ctx
574
575 # Do the main processing
576 process_control_inside(v)
577
578 # Add the end of the block as an exit context
579 if not v.flow_ctx.unreash then
580 escapable.break_flow_contexts.add(v.flow_ctx)
581 end
582
583 # Merge all exit contexts
584 if escapable.break_flow_contexts.is_empty then
585 v.flow_ctx = old_flow_ctx
586 v.mark_unreash(self)
587 else
588 v.flow_ctx = old_base_flow_ctx.merge(self, escapable.break_flow_contexts)
589 end
590
591 if is_loop then v.base_flow_ctx = old_base_flow_ctx
592 v.scope_ctx.pop
593 _is_typed = true
594 end
595
596 # What to do inside the control block?
597 private fun process_control_inside(v: TypingVisitor) is abstract
598 end
599
600 redef class ADoExpr
601 super AAbsControl
602 redef fun accept_typing(v)
603 do
604 process_control(v, new BreakOnlyEscapableBlock(self), n_label, false)
605 end
606
607 redef fun process_control_inside(v)
608 do
609 v.enter_visit_block(n_block)
610 end
611 end
612
613 redef class AIfExpr
614 redef fun accept_typing(v)
615 do
616 v.enter_visit(n_expr)
617 v.check_conform_expr(n_expr, v.type_bool)
618
619 n_expr.warn_parentheses(v)
620
621 # Prepare 'then' context
622 var old_flow_ctx = v.flow_ctx
623 v.use_if_true_flow_ctx(n_expr)
624
625 # Process the 'then'
626 v.enter_visit_block(n_then)
627
628 # Remember what appened in the 'then'
629 var then_flow_ctx = v.flow_ctx
630
631 # Prepare 'else' context
632 v.flow_ctx = old_flow_ctx
633 v.use_if_false_flow_ctx(n_expr)
634
635 # Process the 'else'
636 v.enter_visit_block(n_else)
637
638 # Merge 'then' and 'else' contexts
639 v.flow_ctx = v.base_flow_ctx.merge_reash(self, then_flow_ctx, v.flow_ctx)
640 _is_typed = true
641 end
642 end
643
644 redef class AWhileExpr
645 super AAbsControl
646 redef fun accept_typing(v)
647 do
648 process_control(v, new EscapableBlock(self), n_label, true)
649 end
650
651 redef fun process_control_inside(v)
652 do
653 var old_flow_ctx = v.flow_ctx
654
655 # Process condition
656 v.enter_visit(n_expr)
657 v.check_conform_expr(n_expr, v.type_bool)
658
659 if n_expr isa ATrueExpr then
660 v.warning(self, "Warning: use 'loop' instead of 'while true do'.")
661 else
662 n_expr.warn_parentheses(v)
663 end
664
665 # Prepare inside context (assert cond)
666 v.use_if_true_flow_ctx(n_expr)
667
668 # Process inside
669 v.enter_visit_block(n_block)
670
671 # Compute outside context (assert !cond + all breaks)
672 v.flow_ctx = old_flow_ctx
673 v.use_if_false_flow_ctx(n_expr)
674 escapable.break_flow_contexts.add(v.flow_ctx)
675 end
676 end
677
678 redef class ALoopExpr
679 super AAbsControl
680 redef fun accept_typing(v)
681 do
682 process_control(v, new EscapableBlock(self), n_label, true)
683 end
684
685 redef fun process_control_inside(v)
686 do
687 # Process inside
688 v.enter_visit_block(n_block)
689
690 # Never automatically reach after the loop
691 v.mark_unreash(self)
692 end
693 end
694
695 redef class AForExpr
696 super AAbsControl
697 var _variables: nullable Array[AutoVariable]
698 redef fun variables do return _variables.as(not null)
699
700 redef fun accept_typing(v)
701 do
702 process_control(v, new EscapableBlock(self), n_label, true)
703 end
704
705 redef fun process_control_inside(v)
706 do
707 v.scope_ctx.push(self)
708 var old_flow_ctx = v.flow_ctx
709
710 do_typing(v)
711
712 # Process inside
713 v.enter_visit_block(n_block)
714
715 # end == begin of the loop
716 v.flow_ctx = old_flow_ctx
717 v.scope_ctx.pop
718 end
719
720 private fun do_typing(v: TypingVisitor)
721 do
722 # Create the automatic variables
723 var vas = new Array[AutoVariable]
724 for n_id in n_ids do
725 var va = new AutoVariable(n_id.to_symbol, n_id)
726 v.scope_ctx.add_variable(va)
727 vas.add(va)
728 end
729 _variables = vas
730
731 # Process reciever
732 v.enter_visit(n_expr)
733 if not v.check_expr(n_expr) then return
734 var expr_type = n_expr.stype
735
736 if expr_type.is_nullable then
737 v.error(n_expr, "Type error: 'for' on a nullable expression.")
738 return
739 end
740 n_expr.warn_parentheses(v)
741
742 # Get iterate
743 var iterate_name = once "iterate".to_symbol
744 if not expr_type.local_class.has_global_property_by_name(iterate_name) then
745 v.error(n_expr, "Type error: Expected a type with an 'iterate' method. Found {expr_type}.")
746 return
747 end
748 var prop = expr_type.local_class.select_method(iterate_name)
749 prop.global.check_visibility(v, self, v.mmmodule, n_expr.is_self)
750 var psig = prop.signature_for(expr_type)
751 if not n_expr.is_self then psig = psig.not_for_self
752 if psig.arity != 0 then
753 v.error(self, "Error: 'iterate' incompatible with 'for': require no arguments.")
754 return
755 else if psig.closures.length != 1 then
756 v.error(self, "Error: 'iterate' incompatible with 'for': require one closure.")
757 return
758 end
759 psig = psig.closures.first.signature
760 if psig.return_type != null then
761 v.error(self, "Error: 'iterate' incompatible with 'for': require one procedural closure.")
762 return
763 end
764 if vas.length != psig.arity then
765 if psig.arity == 1 then
766 v.error(self, "Error: Expected {psig.arity} variable {psig}, found {vas.length}.")
767 else
768 v.error(self, "Error: Expected {psig.arity} variables {psig}, found {vas.length}.")
769 end
770 return
771 end
772
773 # Type the automatic variables
774 for i in [0..vas.length[ do
775 vas[i].stype = psig[i]
776 end
777 end
778 end
779
780 redef class AAssertExpr
781 redef fun accept_typing(v)
782 do
783 # Process condition
784 v.enter_visit(n_expr)
785 v.check_conform_expr(n_expr, v.type_bool)
786 n_expr.warn_parentheses(v)
787
788 # Process optional 'else' part
789 if n_else != null then
790 var old_flow_ctx = v.flow_ctx
791 v.use_if_false_flow_ctx(n_expr)
792 v.enter_visit(n_else)
793 v.flow_ctx = old_flow_ctx
794 end
795
796 # Prepare outside
797 v.use_if_true_flow_ctx(n_expr)
798 _is_typed = true
799 end
800 end
801
802 redef class AVarFormExpr
803 var _variable: nullable Variable
804 redef fun variable do return _variable.as(not null)
805 end
806
807 redef class AVarExpr
808 redef fun its_variable do return variable
809
810 redef fun after_typing(v)
811 do
812 v.flow_ctx.check_is_set(self, variable)
813 _stype = v.flow_ctx.stype(variable)
814 _is_typed = _stype != null
815 end
816 end
817
818 redef class AVarAssignExpr
819 redef fun after_typing(v)
820 do
821 v.mark_is_set(variable)
822
823 # Check the base type
824 var btype = v.base_flow_ctx.stype(variable)
825 if not v.check_expr(n_value) then return
826 if btype != null and not v.check_conform_expr(n_value, btype) then return
827
828 # Always cast
829 v.flow_ctx = v.flow_ctx.sub_with(self, variable, n_value.stype)
830
831 _is_typed = true
832 end
833 end
834
835 redef class AReassignFormExpr
836 # Compute and check method used through the reassigment operator
837 # On success return the static type of the result of the reassigment operator
838 # Else display an error and return null
839 private fun do_rvalue_typing(v: TypingVisitor, type_lvalue: nullable MMType): nullable MMType
840 do
841 if type_lvalue == null then
842 return null
843 end
844 var name = n_assign_op.method_name
845 if type_lvalue isa MMTypeNone then
846 v.error(self, "Error: Method '{name}' call on 'null'.")
847 return null
848 end
849 var lc = type_lvalue.local_class
850 if not lc.has_global_property_by_name(name) then
851 v.error(self, "Error: Method '{name}' doesn't exists in {type_lvalue}.")
852 return null
853 end
854 var prop = lc.select_method(name)
855 prop.global.check_visibility(v, self, v.mmmodule, false)
856 var psig = prop.signature_for(type_lvalue)
857 _assign_method = prop
858 if not v.check_conform_expr(n_value, psig[0].not_for_self) then return null
859 return psig.return_type.not_for_self
860 end
861
862 redef fun assign_method do return _assign_method.as(not null)
863 var _assign_method: nullable MMMethod
864 end
865
866 redef class AVarReassignExpr
867 redef fun after_typing(v)
868 do
869 v.flow_ctx.check_is_set(self, variable)
870 v.mark_is_set(variable)
871 var t = v.flow_ctx.stype(variable)
872 var t2 = do_rvalue_typing(v, t)
873 if t2 == null then return
874
875 # Check the base type
876 var btype = v.base_flow_ctx.stype(variable)
877 if not v.check_expr(n_value) then return
878 if btype != null and not v.check_conform(n_value, t2, btype) then return
879
880 # Always cast
881 v.flow_ctx = v.flow_ctx.sub_with(self, variable, t2)
882
883 _is_typed = true
884 end
885 end
886
887 redef class AAssignOp
888 fun method_name: Symbol is abstract
889 end
890 redef class APlusAssignOp
891 redef fun method_name do return once "+".to_symbol
892 end
893 redef class AMinusAssignOp
894 redef fun method_name do return once "-".to_symbol
895 end
896
897 redef class ASelfExpr
898 var _variable: nullable ParamVariable
899 redef fun variable do return _variable.as(not null)
900
901 redef fun its_variable do return variable
902
903 redef fun after_typing(v)
904 do
905 _variable = v.self_var
906 _stype = v.flow_ctx.stype(variable)
907 _is_typed = true
908 end
909
910 redef fun is_self do return true
911 end
912
913 redef class AImplicitSelfExpr
914 redef fun is_implicit_self do return true
915 end
916
917 redef class AIfexprExpr
918 redef fun accept_typing(v)
919 do
920 var old_flow_ctx = v.flow_ctx
921
922 # Process condition
923 v.enter_visit(n_expr)
924 v.check_conform_expr(n_expr, v.type_bool)
925
926 # Prepare 'then' context
927 v.use_if_true_flow_ctx(n_expr)
928
929 # Process 'then'
930 v.enter_visit_block(n_then)
931
932 # Remember what appened in the 'then'
933 var then_flow_ctx = v.flow_ctx
934
935 # Prepare 'else' context
936 v.flow_ctx = old_flow_ctx
937 v.use_if_false_flow_ctx(n_expr)
938
939 # Process 'else'
940 v.enter_visit_block(n_else)
941
942 # Merge 'then' and 'else' contexts
943 v.flow_ctx = v.base_flow_ctx.merge_reash(self, then_flow_ctx, v.flow_ctx)
944
945 var stype = v.check_conform_multiexpr(null, [n_then, n_else])
946 if stype == null then return
947
948 _stype = stype
949 _is_typed = true
950 end
951 end
952
953 redef class ABoolExpr
954 redef fun after_typing(v)
955 do
956 _stype = v.type_bool
957 _is_typed = true
958 end
959 end
960
961 redef class AOrExpr
962 redef fun accept_typing(v)
963 do
964 var old_flow_ctx = v.flow_ctx
965 var stype = v.type_bool
966 _stype = stype
967
968 # Process left operand
969 v.enter_visit(n_expr)
970
971 # Prepare right operand context
972 v.use_if_false_flow_ctx(n_expr)
973
974 # Process right operand
975 v.enter_visit(n_expr2)
976 if n_expr2.if_false_flow_ctx != null then
977 _if_false_flow_ctx = n_expr2.if_false_flow_ctx
978 else
979 _if_false_flow_ctx = v.flow_ctx
980 end
981
982 v.flow_ctx = old_flow_ctx
983
984 v.check_conform_expr(n_expr, stype)
985 v.check_conform_expr(n_expr2, stype)
986 _stype = stype
987 _is_typed = true
988 end
989 end
990
991 redef class AAndExpr
992 redef fun accept_typing(v)
993 do
994 var old_flow_ctx = v.flow_ctx
995 var stype = v.type_bool
996
997 # Process left operand
998 v.enter_visit(n_expr)
999
1000 # Prepare right operand context
1001 v.use_if_true_flow_ctx(n_expr)
1002
1003 # Process right operand
1004 v.enter_visit(n_expr2)
1005 if n_expr2.if_true_flow_ctx != null then
1006 _if_true_flow_ctx = n_expr2.if_true_flow_ctx
1007 else
1008 _if_true_flow_ctx = v.flow_ctx
1009 end
1010
1011 v.flow_ctx = old_flow_ctx
1012
1013 v.check_conform_expr(n_expr, stype)
1014 v.check_conform_expr(n_expr2, stype)
1015 _stype = stype
1016 _is_typed = true
1017 end
1018 end
1019
1020 redef class ANotExpr
1021 redef fun after_typing(v)
1022 do
1023 v.check_conform_expr(n_expr, v.type_bool)
1024
1025 # Invert if_true/if_false information
1026 _if_false_flow_ctx = n_expr._if_true_flow_ctx
1027 _if_true_flow_ctx = n_expr._if_false_flow_ctx
1028
1029 _stype = v.type_bool
1030 _is_typed = true
1031 end
1032 end
1033
1034 redef class AOrElseExpr
1035 redef fun after_typing(v)
1036 do
1037 var old_flow_ctx = v.flow_ctx
1038
1039 # Process left operand
1040 v.enter_visit(n_expr)
1041 v.check_expr(n_expr)
1042
1043 # Consider the type of the left operand
1044 var t = n_expr.stype
1045 if not t.is_nullable then
1046 v.warning(n_expr, "Warning: left operand of a 'or else' is not a nullable type.")
1047 else
1048 t = t.as_notnull
1049 end
1050
1051 # Prepare the else context : ie the first expression is null
1052 var variable = n_expr.its_variable
1053 if variable != null then
1054 v.flow_ctx.sub_with(self, variable, v.type_none)
1055 end
1056
1057 # Process right operand
1058 v.enter_visit(n_expr2)
1059 v.check_expr(n_expr)
1060
1061 # Restore the context
1062 v.flow_ctx = old_flow_ctx
1063
1064 # Merge the types
1065 var stype = v.check_conform_multiexpr(t, [n_expr2])
1066 if stype == null then return
1067
1068 _stype = stype
1069 _is_typed = true
1070 end
1071 end
1072
1073 redef class AIntExpr
1074 redef fun after_typing(v)
1075 do
1076 _stype = v.type_int
1077 _is_typed = true
1078 end
1079 end
1080
1081 redef class AFloatExpr
1082 redef fun after_typing(v)
1083 do
1084 _stype = v.type_float
1085 _is_typed = true
1086 end
1087 end
1088
1089 redef class ACharExpr
1090 redef fun after_typing(v)
1091 do
1092 _stype = v.type_char
1093 _is_typed = true
1094 end
1095 end
1096
1097 redef class AStringFormExpr
1098 redef fun after_typing(v)
1099 do
1100 _stype = v.type_string
1101 _is_typed = true
1102 end
1103 end
1104
1105 redef class ASuperstringExpr
1106 redef fun atype do return _atype.as(not null)
1107 var _atype: nullable MMType
1108 redef fun after_typing(v)
1109 do
1110 var otype = v.type_object
1111 var stype = v.type_string
1112 _stype = stype
1113 for e in n_exprs do v.check_conform_expr(e, otype)
1114 var atype = v.type_array(stype)
1115 _atype = atype
1116 _is_typed = true
1117 end
1118 end
1119
1120 redef class ANullExpr
1121 redef fun after_typing(v)
1122 do
1123 _stype = v.type_none
1124 _is_typed = true
1125 end
1126 end
1127
1128 redef class AArrayExpr
1129 redef fun after_typing(v)
1130 do
1131 var stype = v.check_conform_multiexpr(null, n_exprs.n_exprs)
1132 if stype != null then do_typing(v, stype)
1133 end
1134
1135 private fun do_typing(v: TypingVisitor, element_type: MMType)
1136 do
1137 _stype = v.type_array(element_type)
1138 _is_typed = true
1139 end
1140 end
1141
1142 redef class ARangeExpr
1143 redef fun after_typing(v)
1144 do
1145 if not v.check_expr(n_expr) or not v.check_expr(n_expr2) then return
1146 var ntype = n_expr.stype
1147 var ntype2 = n_expr2.stype
1148 if ntype < ntype2 then
1149 ntype = ntype2
1150 else if not ntype2 < ntype then
1151 v.error(self, "Type error: {ntype} incompatible with {ntype2}.")
1152 return
1153 end
1154 var dtype = v.type_discrete
1155 if not v.check_conform_expr(n_expr, dtype) or not v.check_conform_expr(n_expr2, dtype) then return
1156 _stype = v.type_range(ntype)
1157 _is_typed = true
1158 end
1159 end
1160
1161 redef class ASuperExpr
1162 redef readable var _init_in_superclass: nullable MMMethod
1163 redef fun compute_raw_arguments do return n_args.to_a
1164 redef fun after_typing(v)
1165 do
1166 var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters
1167 if not precs.is_empty then
1168 v.local_property.need_super = true
1169 else if v.local_property.global.is_init then
1170 var base_precs = v.local_class.super_methods_named(v.local_property.name)
1171 for p in base_precs do
1172 if not p.global.is_init then
1173 v.error(self, "Error: {p.local_class}::{p} is not a constructor.")
1174 else
1175 precs.add(v.local_class[p.global])
1176 end
1177 end
1178 if precs.is_empty then
1179 v.error(self, "Error: No contructor named {v.local_property.name} in superclasses.")
1180 return
1181 else if precs.length > 1 then
1182 v.error(self, "Error: Conflicting contructors named {v.local_property.name} in superclasses: {precs.join(", ")}.")
1183 return
1184 end
1185 var p = base_precs.first
1186 assert p isa MMMethod
1187 _init_in_superclass = p
1188 register_super_init_call(v, p)
1189 if n_args.n_exprs.length > 0 then
1190 var signature = get_signature(v, v.self_var.stype.as(not null), p, true)
1191 process_signature(v, signature, p.name, compute_raw_arguments)
1192 end
1193 else
1194 v.error(self, "Error: No super method to call for {v.local_property}.")
1195 return
1196 end
1197
1198 if precs.first.signature_for(v.self_var.stype.as(not null)).return_type != null then
1199 var stypes = new Array[MMType]
1200 var stype: nullable MMType = null
1201 for prop in precs do
1202 assert prop isa MMMethod
1203 var t = prop.signature_for(v.self_var.stype.as(not null)).return_type.for_module(v.mmmodule).adapt_to(v.local_property.signature.recv)
1204 stypes.add(t)
1205 if stype == null or stype < t then
1206 stype = t
1207 end
1208 end
1209 for t in stypes do
1210 v.check_conform(self, t, stype.as(not null))
1211 end
1212 _stype = stype
1213 end
1214 var p = v.local_property
1215 assert p isa MMSrcMethod
1216 _prop = p
1217 _is_typed = true
1218 end
1219 end
1220
1221 redef class AExternCall
1222 fun target_class_name : nullable Symbol do return null
1223 fun target_method_name : Symbol is abstract
1224
1225 redef fun after_typing(v)
1226 do
1227 var target_class_name = self.target_class_name
1228 var target_method_name = self.target_method_name
1229
1230 var target_class : MMLocalClass
1231 var target_method : MMMethod
1232
1233 # find class
1234 # self.target_class_name can be redef'd by sub-classes
1235 if target_class_name == null then
1236 target_class = v.local_property.local_class
1237 else
1238 if v.local_property.mmmodule.has_global_class_named( target_class_name ) then
1239 var global_class = v.local_property.mmmodule.global_class_named( target_class_name )
1240 target_class = v.local_property.mmmodule[ global_class ]
1241 else
1242 v.error( self, "Error: class {target_class_name.to_s}, not found." )
1243 return
1244 end
1245 end
1246
1247 if target_class.has_global_property_by_name( target_method_name ) then
1248 var global_property = target_class.get_property_by_name( target_method_name )
1249
1250 var target_property = target_class[global_property]
1251
1252 if target_property isa MMMethod then
1253 target_method = target_property
1254 else
1255 v.error( self, "Error: property {target_method_name.to_s} is not a method." )
1256 return
1257 end
1258 else
1259 v.error( self, "Error: property {target_method_name.to_s} not found in target class." )
1260 return
1261 end
1262
1263 var explicit_import = new MMExplicitImport( target_class, target_method )
1264 v.local_property.as(MMSrcMethod).explicit_imports.add( explicit_import )
1265 end
1266 end
1267
1268 redef class ALocalPropExternCall
1269 redef fun target_class_name do return null
1270 redef fun target_method_name do return n_methid.name.as(not null)
1271 end
1272
1273 redef class ASuperExternCall
1274 redef fun after_typing(v)
1275 do
1276 var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters
1277 if not precs.is_empty then
1278 v.local_property.need_super = true
1279 else
1280 v.error(self, "Error: No super method to call for {v.local_property}.")
1281 return
1282 end
1283 end
1284 end
1285
1286 redef class AFullPropExternCall
1287 redef fun target_class_name do return n_classid.to_symbol
1288 redef fun target_method_name do return n_methid.name.as(not null)
1289 end
1290
1291 redef class AInitPropExternCall
1292 redef fun target_class_name do return n_classid.to_symbol
1293 redef fun target_method_name do return "init".to_symbol
1294 end
1295
1296 redef class ACastExternCall
1297 fun from_type : MMType is abstract
1298 fun to_type : MMType is abstract
1299
1300 redef fun after_typing(v)
1301 do
1302 if from_type == to_type
1303 then
1304 v.error( self, "Attepting to cast from and to the same type." )
1305 end
1306
1307 var cast = new MMImportedCast( from_type, to_type )
1308 var m = v.local_property
1309 assert m isa MMMethod
1310 m.explicit_casts.add( cast )
1311 end
1312 end
1313
1314 redef class ACastAsExternCall
1315 redef fun from_type do return n_from_type.stype
1316 redef fun to_type do return n_to_type.stype
1317 end
1318
1319 redef class AAsNullableExternCall
1320 redef fun from_type do return n_type.stype
1321 redef fun to_type do return n_type.stype.as_nullable
1322 end
1323
1324 redef class AAsNotNullableExternCall
1325 redef fun from_type
1326 do
1327 var t = n_type.stype
1328 if t.is_nullable
1329 then
1330 return t
1331 else
1332 return t.as_nullable
1333 end
1334 end
1335 redef fun to_type do return n_type.stype.as_notnull
1336 end
1337
1338 redef class AAttrFormExpr
1339 redef fun prop do return _prop.as(not null)
1340 var _prop: nullable MMAttribute
1341
1342 redef fun attr_type do return _attr_type.as(not null)
1343 var _attr_type: nullable MMType
1344
1345 # Compute the attribute accessed
1346 private fun do_typing(v: TypingVisitor)
1347 do
1348 if not v.check_expr(n_expr) then return
1349 var type_recv = n_expr.stype
1350 var name = n_id.to_symbol
1351 if type_recv isa MMTypeNone then
1352 v.error(self, "Error: Attribute '{name}' access on 'null'.")
1353 return
1354 end
1355 var lc = type_recv.local_class
1356 if not lc.has_global_property_by_name(name) then
1357 v.error(self, "Error: Attribute {name} doesn't exists in {type_recv}.")
1358 return
1359 end
1360 var prop = lc.select_attribute(name)
1361 if v.mmmodule.visibility_for(prop.global.local_class.mmmodule) < 3 then
1362 v.error(self, "Error: Attribute {name} from {prop.global.local_class.mmmodule} is invisible in {v.mmmodule}")
1363 end
1364 _prop = prop
1365 var at = prop.signature_for(type_recv).return_type
1366 if not n_expr.is_self then at = at.not_for_self
1367 _attr_type = at
1368 end
1369 end
1370
1371 redef class AAttrExpr
1372 redef fun after_typing(v)
1373 do
1374 do_typing(v)
1375 if _prop == null then return
1376 _stype = attr_type
1377 _is_typed = true
1378 end
1379 end
1380
1381 redef class AAttrAssignExpr
1382 redef fun after_typing(v)
1383 do
1384 do_typing(v)
1385 if _prop == null then return
1386 if not v.check_conform_expr(n_value, attr_type) then return
1387 _is_typed = true
1388 end
1389 end
1390
1391 redef class AAttrReassignExpr
1392 redef fun after_typing(v)
1393 do
1394 do_typing(v)
1395 if _prop == null then return
1396 var t = do_rvalue_typing(v, attr_type)
1397 if t == null then return
1398 v.check_conform(self, t, n_value.stype)
1399 _is_typed = true
1400 end
1401 end
1402
1403 redef class AIssetAttrExpr
1404 redef fun after_typing(v)
1405 do
1406 do_typing(v)
1407 if _prop == null then return
1408 if attr_type.is_nullable then
1409 v.error(self, "Error: isset on a nullable attribute.")
1410 end
1411 _stype = v.type_bool
1412 _is_typed = true
1413 end
1414 end
1415
1416 redef class AAbsAbsSendExpr
1417 # The signature of the called property
1418 redef fun prop_signature do return _prop_signature.as(not null)
1419 var _prop_signature: nullable MMSignature
1420
1421 # Raw arguments used (without vararg transformation)
1422 redef fun raw_arguments: Array[AExpr]
1423 do
1424 var res = _raw_arguments_cache
1425 if res != null then
1426 return res
1427 else
1428 res = compute_raw_arguments
1429 if res == null then res = new Array[AExpr]
1430 _raw_arguments_cache = res
1431 return res
1432 end
1433 end
1434
1435 var _raw_arguments_cache: nullable Array[AExpr] = null
1436
1437 fun compute_raw_arguments: nullable Array[AExpr]
1438 do
1439 print "{location} no compute_raw_arguments"
1440 return null
1441 end
1442
1443 # Check the conformity of a set of arguments `raw_args' to a signature.
1444 private fun process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: nullable Array[AExpr]): Bool
1445 do
1446 var par_vararg = psig.vararg_rank
1447 var par_arity = psig.arity
1448 var raw_arity: Int
1449 if raw_args == null then raw_arity = 0 else raw_arity = raw_args.length
1450 if par_arity > raw_arity or (par_arity != raw_arity and par_vararg == -1) then
1451 v.error(self, "Error: arity mismatch; prototype is '{name}{psig}'.")
1452 return false
1453 end
1454 var arg_idx = 0
1455 for par_idx in [0..par_arity[ do
1456 var a: AExpr
1457 var par_type = psig[par_idx]
1458 if par_idx == par_vararg then
1459 for i in [0..(raw_arity-par_arity)] do
1460 a = raw_args[arg_idx]
1461 v.check_conform_expr(a, par_type)
1462 arg_idx = arg_idx + 1
1463 end
1464 else
1465 a = raw_args[arg_idx]
1466 v.check_conform_expr(a, par_type)
1467 arg_idx = arg_idx + 1
1468 end
1469 end
1470 return true
1471 end
1472
1473 # Check the conformity of a set of defined closures
1474 private fun process_closures(v: TypingVisitor, psig: MMSignature, name: Symbol, cd: nullable Array[AClosureDef]): nullable MMType
1475 do
1476 var t = psig.return_type
1477 var cs = psig.closures # Declared closures
1478 var min_arity = 0
1479 for c in cs do
1480 if not c.is_optional then min_arity += 1
1481 end
1482 var arity = 0
1483 if cd != null then arity = cd.length
1484 if cs.length > 0 then
1485 if arity == 0 and min_arity > 0 then
1486 v.error(self, "Error: {name} requires {cs.length} blocks.")
1487 else if arity > cs.length or arity < min_arity then
1488 v.error(self, "Error: {name} requires {cs.length} blocks, {cd.length} found.")
1489 else
1490 # Initialize the break list if a value is required for breaks (ie. if the method is a function)
1491 var break_list: nullable Array[ABreakExpr] = null
1492 if t != null then break_list = new Array[ABreakExpr]
1493
1494 # The n_label, is any in only set on the last decl
1495 var n_label = if arity > 0 then cd[arity-1].n_label else null
1496
1497 # Process each closure definition
1498 for i in [0..arity[ do
1499 var cdi = cd[i]
1500 var cni = cdi.n_id.to_symbol
1501 var csi = psig.closure_named(cni)
1502 if csi != null then
1503 var esc = new EscapableClosure(cdi, csi, break_list)
1504 v.scope_ctx.push_escapable(esc, n_label)
1505 cdi.accept_typing2(v, esc)
1506 v.scope_ctx.pop
1507 else if cs.length == 1 then
1508 v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closure is !{cs.first.name}.")
1509 else
1510 var a = new Array[String]
1511 for c in cs do
1512 a.add("!{c.name}")
1513 end
1514 v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closures are {a.join(",")}.")
1515 end
1516 end
1517
1518 # Check break type conformity
1519 if break_list != null then
1520 t = v.check_conform_multiexpr(t, break_list)
1521 end
1522 end
1523 else if arity != 0 then
1524 v.error(self, "Error: {name} does not require blocks.")
1525 end
1526 return t
1527 end
1528 end
1529
1530 redef class AAbsSendExpr
1531 # Compute the called global property
1532 private fun do_typing(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, recv_is_self: Bool, name: Symbol, raw_args: nullable Array[AExpr], closure_defs: nullable Array[AClosureDef])
1533 do
1534 var prop = get_property(v, type_recv, is_implicit_self, name)
1535 if prop == null then return
1536 var sig = get_signature(v, type_recv, prop, recv_is_self)
1537 if not process_signature(v, sig, prop.name, raw_args) then return
1538 var rtype = process_closures(v, sig, prop.name, closure_defs)
1539 if rtype == null and sig.return_type != null then return
1540 _prop = prop
1541 _prop_signature = sig
1542 _return_type = rtype
1543 end
1544
1545 private fun get_property(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, name: Symbol): nullable MMMethod
1546 do
1547 if type_recv isa MMTypeNone then
1548 if name == (once "==".to_symbol) or name == (once "!=".to_symbol) then
1549 # Special case on != and == that are allowed for 'null'
1550 type_recv = v.type_object.as_nullable
1551 else
1552 v.error(self, "Error: Method '{name}' call on 'null'.")
1553 return null
1554 end
1555 end
1556 var lc = type_recv.local_class
1557 var prop: nullable MMMethod = null
1558 if lc.has_global_property_by_name(name) then prop = lc.select_method(name)
1559 if prop == null and v.local_property.global.is_init then
1560 var props = lc.super_methods_named(name)
1561 if props.length > 1 then
1562 v.error(self, "Error: Ambigous method name '{name}' for {props.join(", ")}. Use explicit designation.")
1563 return null
1564 else if props.length == 1 then
1565 var p = lc[props.first.global]
1566 assert p isa MMMethod
1567 prop = p
1568 end
1569
1570 end
1571 if prop == null then
1572 if is_implicit_self then
1573 v.error(self, "Error: Method or variable '{name}' unknown in {type_recv}.")
1574 else
1575 v.error(self, "Error: Method '{name}' doesn't exists in {type_recv}.")
1576 end
1577 return null
1578 end
1579 return prop
1580 end
1581
1582 # Get the signature for a local property and a receiver
1583 private fun get_signature(v: TypingVisitor, type_recv: MMType, prop: MMMethod, recv_is_self: Bool): MMSignature
1584 do
1585 prop.global.check_visibility(v, self, v.mmmodule, recv_is_self)
1586 var psig = prop.signature_for(type_recv)
1587 if not recv_is_self then psig = psig.not_for_self
1588 return psig
1589 end
1590
1591 # The invoked method (once computed)
1592 redef fun prop do return _prop.as(not null)
1593 var _prop: nullable MMMethod
1594
1595 # The return type (if any) (once computed)
1596 redef readable var _return_type: nullable MMType
1597 end
1598
1599 # A possible call of constructor in a super class
1600 # Could be an explicit call or with the 'super' keyword
1601 redef class ASuperInitCall
1602 private fun register_super_init_call(v: TypingVisitor, property: MMMethod)
1603 do
1604 if parent != v.top_block and self != v.top_block then
1605 v.error(self, "Error: Constructor invocation {property} must not be in nested block.")
1606 end
1607 var cla = v.mmmodule[property.global.intro.local_class.global]
1608 var prev_class: nullable MMLocalClass = null
1609 var esic = v.explicit_super_init_calls.as(not null)
1610 if not esic.is_empty then
1611 prev_class = esic.last.global.intro.local_class
1612 end
1613 var order = v.local_class.cshe.reverse_linear_extension
1614 if cla == v.local_class then
1615 v.explicit_other_init_call = true
1616 else if not order.has(cla) then
1617 v.error(self, "Error: Constructor of class {cla} must be one in {order.join(", ")}.")
1618 else if cla == prev_class then
1619 v.error(self, "Error: Only one super constructor invocation of class {cla} is allowed.")
1620 else
1621 for c in order do
1622 if c == prev_class then
1623 prev_class = null
1624 else if c == cla then
1625 esic.add(property)
1626 break
1627 end
1628 end
1629 end
1630 end
1631
1632 end
1633
1634 redef class ANewExpr
1635 redef fun compute_raw_arguments do return n_args.to_a
1636 redef fun after_typing(v)
1637 do
1638 if not n_type.is_typed then return
1639 var t = n_type.stype
1640 if t.local_class.global.is_abstract then
1641 v.error(self, "Error: try to instantiate abstract class {t.local_class}.")
1642 return
1643 end
1644 if t.is_nullable then
1645 v.error(self, "Type error: cannot instantiate the nullable type {t}.")
1646 end
1647 var name: Symbol
1648 if n_id == null then
1649 name = once "init".to_symbol
1650 else
1651 name = n_id.to_symbol
1652 end
1653
1654 do_typing(v, t, false, false, name, raw_arguments, null)
1655 if _prop == null then return
1656
1657 if not prop.global.is_init then
1658 v.error(self, "Error: {prop} is not a constructor.")
1659 return
1660 end
1661 _stype = t
1662 _is_typed = true
1663 end
1664 end
1665
1666
1667 redef class ASendExpr
1668 # Name of the invoked property
1669 fun name: Symbol is abstract
1670
1671 # Closure definitions
1672 redef fun closure_defs: nullable Array[AClosureDef] do return null
1673
1674 redef fun after_typing(v)
1675 do
1676 do_all_typing(v)
1677 end
1678
1679 private fun do_all_typing(v: TypingVisitor)
1680 do
1681 if not v.check_expr(n_expr) then return
1682 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_arguments, closure_defs)
1683 if _prop == null then return
1684 var prop = _prop.as(not null)
1685
1686 if prop.global.is_init then
1687 if not v.local_property.global.is_init then
1688 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1689 else if not n_expr.is_self then
1690 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1691 else
1692 register_super_init_call(v, prop)
1693 end
1694 end
1695
1696 _stype = return_type
1697 _is_typed = true
1698 end
1699 end
1700
1701 redef class ASendReassignExpr
1702 redef fun read_prop do return _read_prop.as(not null)
1703 var _read_prop: nullable MMMethod
1704 redef fun do_all_typing(v)
1705 do
1706 if not v.check_expr(n_expr) then return
1707 var raw_args = raw_arguments
1708 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_args, null)
1709 var prop = _prop
1710 if prop == null then return
1711 if prop.global.is_init then
1712 if not v.local_property.global.is_init then
1713 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1714 else if not n_expr.is_self then
1715 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1716 end
1717 end
1718 var t = prop.signature_for(n_expr.stype).return_type.as(not null)
1719 if not n_expr.is_self then t = t.not_for_self
1720
1721 var t2 = do_rvalue_typing(v, t)
1722 if t2 == null then return
1723 v.check_conform(self, t2, n_value.stype)
1724
1725 _read_prop = prop
1726 raw_args = raw_args.to_a
1727 raw_args.add(n_value)
1728
1729 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, "{name}=".to_symbol, raw_args, null)
1730 if prop.global.is_init then
1731 if not v.local_property.global.is_init then
1732 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1733 else if not n_expr.is_self then
1734 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1735 end
1736 end
1737
1738 _is_typed = true
1739 end
1740 end
1741
1742 redef class ABinopExpr
1743 redef fun compute_raw_arguments do return [n_expr2]
1744 end
1745 redef class AEqExpr
1746 redef fun name do return once "==".to_symbol
1747 redef fun after_typing(v)
1748 do
1749 super
1750 if not n_expr.is_typed or not n_expr2.is_typed then return
1751 if n_expr.stype isa MMTypeNone and not n_expr2.stype.is_nullable or
1752 n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
1753 v.warning(self, "Warning: comparaison between null and a non nullable value.")
1754 end
1755
1756 if n_expr.stype isa MMTypeNone then
1757 if n_expr2.stype isa MMTypeNone then
1758 v.warning(self, "Warning: comparaison between two null values.")
1759 else
1760 try_to_isa(v, n_expr2)
1761 end
1762 else if n_expr2.stype isa MMTypeNone then
1763 try_to_isa(v, n_expr)
1764 end
1765 end
1766
1767 private fun try_to_isa(v: TypingVisitor, n: AExpr)
1768 do
1769 var variable = n.its_variable
1770 if variable != null and n.stype isa MMNullableType then
1771 _if_false_flow_ctx = v.flow_ctx.sub_with(self, variable, n.stype.as_notnull)
1772 _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, v.type_none)
1773 end
1774 end
1775 end
1776 redef class ANeExpr
1777 redef fun name do return once "!=".to_symbol
1778 redef fun after_typing(v)
1779 do
1780 super
1781 if not n_expr.is_typed or not n_expr2.is_typed then return
1782 if n_expr.stype isa MMTypeNone and not n_expr2.stype.is_nullable or
1783 n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
1784 v.warning(self, "Warning: comparaison between null and a non nullable value.")
1785 end
1786
1787 if n_expr.stype isa MMTypeNone then
1788 if n_expr2.stype isa MMTypeNone then
1789 v.warning(self, "Warning: comparaison between two null values.")
1790 else
1791 try_to_isa(v, n_expr2)
1792 end
1793 else if n_expr2.stype isa MMTypeNone then
1794 try_to_isa(v, n_expr)
1795 end
1796 end
1797
1798 private fun try_to_isa(v: TypingVisitor, n: AExpr)
1799 do
1800 var variable = n.its_variable
1801 if variable != null and n.stype isa MMNullableType then
1802 _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, n.stype.as_notnull)
1803 _if_false_flow_ctx = v.flow_ctx.sub_with(self, variable, v.type_none)
1804 end
1805 end
1806 end
1807 redef class ALtExpr
1808 redef fun name do return once "<".to_symbol
1809 end
1810 redef class ALeExpr
1811 redef fun name do return once "<=".to_symbol
1812 end
1813 redef class ALlExpr
1814 redef fun name do return once "<<".to_symbol
1815 end
1816 redef class AGtExpr
1817 redef fun name do return once ">".to_symbol
1818 end
1819 redef class AGeExpr
1820 redef fun name do return once ">=".to_symbol
1821 end
1822 redef class AGgExpr
1823 redef fun name do return once ">>".to_symbol
1824 end
1825 redef class APlusExpr
1826 redef fun name do return once "+".to_symbol
1827 end
1828 redef class AMinusExpr
1829 redef fun name do return once "-".to_symbol
1830 end
1831 redef class AStarshipExpr
1832 redef fun name do return once "<=>".to_symbol
1833 end
1834 redef class AStarExpr
1835 redef fun name do return once "*".to_symbol
1836 end
1837 redef class ASlashExpr
1838 redef fun name do return once "/".to_symbol
1839 end
1840 redef class APercentExpr
1841 redef fun name do return once "%".to_symbol
1842 end
1843
1844 redef class AUminusExpr
1845 redef fun name do return once "unary -".to_symbol
1846 redef fun compute_raw_arguments do return null
1847 end
1848
1849 redef class ACallFormExpr
1850 redef fun after_typing(v)
1851 do
1852 if n_expr.is_implicit_self then
1853 var name = n_id.to_symbol
1854 var variable = v.scope_ctx[name]
1855 if variable != null then
1856 var n: AExpr
1857 if variable isa ClosureVariable then
1858 n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs)
1859 n._variable = variable
1860 else
1861 if not n_args.n_exprs.is_empty or n_args isa AParExprs then
1862 v.error(self, "Error: {name} is variable, not a function.")
1863 return
1864 end
1865 n = variable_create(variable)
1866 n._variable = variable
1867 end
1868 replace_with(n)
1869 n.after_typing(v)
1870 return
1871 end
1872 end
1873
1874 super
1875 end
1876
1877 redef fun closure_defs
1878 do
1879 if n_closure_defs.is_empty then
1880 return null
1881 else
1882 return n_closure_defs.to_a
1883 end
1884 end
1885
1886 # Create a variable acces corresponding to the call form
1887 fun variable_create(variable: Variable): AVarFormExpr is abstract
1888 end
1889
1890 redef class ACallExpr
1891 redef fun variable_create(variable)
1892 do
1893 return new AVarExpr.init_avarexpr(n_id)
1894 end
1895
1896 redef fun name do return n_id.to_symbol
1897 redef fun compute_raw_arguments do return n_args.to_a
1898 end
1899
1900 redef class ACallAssignExpr
1901 redef fun variable_create(variable)
1902 do
1903 return new AVarAssignExpr.init_avarassignexpr(n_id, n_assign, n_value)
1904 end
1905
1906 redef fun name do return (n_id.text + "=").to_symbol
1907 redef fun compute_raw_arguments do
1908 var res = n_args.to_a
1909 res.add(n_value)
1910 return res
1911 end
1912 end
1913
1914 redef class ACallReassignExpr
1915 redef fun variable_create(variable)
1916 do
1917 return new AVarReassignExpr.init_avarreassignexpr(n_id, n_assign_op, n_value)
1918 end
1919
1920 redef fun name do return n_id.to_symbol
1921 redef fun compute_raw_arguments do return n_args.to_a
1922 end
1923
1924 redef class ABraExpr
1925 redef fun name do return once "[]".to_symbol
1926 redef fun compute_raw_arguments do return n_args.to_a
1927 redef fun closure_defs
1928 do
1929 if n_closure_defs.is_empty then
1930 return null
1931 else
1932 return n_closure_defs.to_a
1933 end
1934 end
1935 end
1936
1937 redef class ABraAssignExpr
1938 redef fun name do return once "[]=".to_symbol
1939 redef fun compute_raw_arguments do
1940 var res = n_args.to_a
1941 res.add(n_value)
1942 return res
1943 end
1944 end
1945
1946 redef class ABraReassignExpr
1947 redef fun name do return once "[]".to_symbol
1948 redef fun compute_raw_arguments do return n_args.to_a
1949 end
1950
1951 redef class AInitExpr
1952 redef fun name do return once "init".to_symbol
1953 redef fun compute_raw_arguments do return n_args.to_a
1954 end
1955
1956 redef class AClosureCallExpr
1957 var _variable: nullable ClosureVariable
1958 redef fun variable do return _variable.as(not null)
1959 redef fun compute_raw_arguments do return n_args.to_a
1960
1961 redef fun after_typing(v)
1962 do
1963 var va = variable
1964 if va.closure.is_break then v.mark_unreash(self)
1965 var sig = va.closure.signature
1966 var s = process_signature(v, sig, n_id.to_symbol, compute_raw_arguments)
1967 if not n_closure_defs.is_empty then
1968 process_closures(v, sig, n_id.to_symbol, n_closure_defs.to_a)
1969 end
1970 if not s then return
1971 _prop_signature = sig
1972 _stype = sig.return_type
1973 _is_typed = true
1974 end
1975 end
1976
1977 redef class AClosureId
1978 fun to_symbol: Symbol is abstract
1979 end
1980 redef class ASimpleClosureId
1981 redef fun to_symbol: Symbol do return n_id.to_symbol
1982 end
1983 redef class ABreakClosureId
1984 redef fun to_symbol: Symbol do return n_kwbreak.to_symbol
1985 end
1986
1987 redef class AClosureDef
1988 var _closure: nullable MMClosure
1989 redef fun closure do return _closure.as(not null)
1990
1991 # The corresponding escapable object
1992 readable var _escapable: nullable EscapableBlock
1993
1994 var _accept_typing2: Bool = false
1995 redef fun accept_typing(v)
1996 do
1997 # Typing is deferred, wait accept_typing2(v)
1998 if _accept_typing2 then super
1999 end
2000
2001 private fun accept_typing2(v: TypingVisitor, esc: EscapableClosure)
2002 do
2003 _escapable = esc
2004
2005 var sig = esc.closure.signature
2006 if sig.arity != n_ids.length then
2007 v.error(self, "Error: {sig.arity} automatic variable names expected, {n_ids.length} found.")
2008 return
2009 end
2010
2011 _closure = esc.closure
2012
2013 v.scope_ctx.push(self)
2014 var old_flow_ctx = v.flow_ctx
2015 var old_base_flow_ctx = v.base_flow_ctx
2016 v.base_flow_ctx = v.flow_ctx
2017 variables = new Array[AutoVariable]
2018 for i in [0..n_ids.length[ do
2019 var va = new AutoVariable(n_ids[i].to_symbol, n_ids[i])
2020 variables.add(va)
2021 va.stype = sig[i]
2022 v.scope_ctx.add_variable(va)
2023 end
2024
2025 _accept_typing2 = true
2026 accept_typing(v)
2027
2028 if v.flow_ctx.unreash == false then
2029 if closure.signature.return_type != null then
2030 v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
2031 else if closure.is_break and esc.break_list != null then
2032 v.error(self, "Control error: Reached end of break block (a 'break' with a value was expected).")
2033 end
2034 end
2035 v.flow_ctx = old_flow_ctx
2036 v.base_flow_ctx = old_base_flow_ctx
2037 v.scope_ctx.pop
2038 end
2039 end
2040
2041 abstract class ATypeCheckExpr
2042 super AExpr
2043 private fun check_expr_cast(v: TypingVisitor, n_expr: AExpr, n_type: AType)
2044 do
2045 if not v.check_expr(n_expr) then return
2046 if not n_type.is_typed then return
2047 var etype = n_expr.stype
2048 var ttype = n_type.stype
2049 if etype == ttype then
2050 v.warning(self, "Warning: Expression is already a {ttype}.")
2051 else if etype < ttype then
2052 if not ttype isa MMTypeFormal then
2053 # the old metamodel is not that great with formal types
2054 v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.")
2055 end
2056 else if etype isa MMTypeNone then
2057 # ttype is not nullable because of prevous test
2058 v.warning(self, "Warning: Expression is null therefore cannot be a {ttype}.")
2059 else if etype.is_nullable and etype.as_notnull == ttype then
2060 if ttype isa MMTypeFormal and ttype.bound.is_nullable then
2061 # No warning in this case since with
2062 # type T: nullable A
2063 # var x: nullable T
2064 # 'x.as(not null)' != 'x.as(T)'
2065 # 'x != null' != 'x isa T'
2066 else if self isa AIsaExpr then
2067 v.warning(self, "Warning: Prefer '!= null'.")
2068 else
2069 v.warning(self, "Warning: Prefer '.as(not null)'.")
2070 end
2071 end
2072 end
2073 end
2074
2075 redef class AIsaExpr
2076 super ATypeCheckExpr
2077 redef fun after_typing(v)
2078 do
2079 check_expr_cast(v, n_expr, n_type)
2080 if not n_type.is_typed then return
2081 var variable = n_expr.its_variable
2082 if variable != null then
2083 _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, n_type.stype)
2084 end
2085 _stype = v.type_bool
2086 _is_typed = true
2087 end
2088 end
2089
2090 redef class AAsCastExpr
2091 super ATypeCheckExpr
2092 redef fun after_typing(v)
2093 do
2094 check_expr_cast(v, n_expr, n_type)
2095 if not n_type.is_typed then return
2096 _stype = n_type.stype
2097 _is_typed = _stype != null
2098 end
2099 end
2100
2101 redef class AAsNotnullExpr
2102 redef fun after_typing(v)
2103 do
2104 if not v.check_expr(n_expr) then return
2105 var t = n_expr.stype
2106 if t isa MMTypeNone then
2107 v.error(n_expr, "Type error: 'as(not null)' on 'null' value.")
2108 return
2109 else if not t.is_nullable then
2110 v.warning(n_expr, "Warning: 'as(not null)' on non nullable type.")
2111 end
2112 _stype = n_expr.stype.as_notnull
2113 _is_typed = true
2114 end
2115 end
2116
2117 redef class AProxyExpr
2118 redef fun after_typing(v)
2119 do
2120 if not n_expr.is_typed then return
2121 _is_typed = true
2122 if n_expr.is_statement then return
2123 _stype = n_expr.stype
2124 _if_true_flow_ctx = n_expr._if_true_flow_ctx
2125 _if_false_flow_ctx = n_expr._if_false_flow_ctx
2126 end
2127
2128 redef fun is_self do return n_expr.is_self
2129
2130 redef fun its_variable do return n_expr.its_variable
2131 end
2132
2133 redef class AOnceExpr
2134 redef fun accept_typing(v)
2135 do
2136 if v.once_count > 0 then
2137 v.warning(self, "Useless once in a once expression.")
2138 end
2139 v.once_count = v.once_count + 1
2140
2141 super
2142
2143 v.once_count = v.once_count - 1
2144 end
2145 end
2146
2147 redef class ADebugTypeExpr
2148 redef fun after_typing(v)
2149 do
2150 if not v.check_expr(n_expr) then return
2151 if not n_type.is_typed then return
2152 var etype = n_expr.stype
2153 var ttype = n_type.stype
2154 if etype != ttype then
2155 v.warning(self, "Warning: Expression is a {etype}, expected {ttype}.")
2156 end
2157 end
2158 end