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