863d41e6d9e4818b0552a778486d678a3bd003cc
[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 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 AAndExpr
998 redef fun accept_typing(v)
999 do
1000 var old_flow_ctx = v.flow_ctx
1001 var stype = v.type_bool
1002
1003 # Process left operand
1004 v.enter_visit(n_expr)
1005
1006 # Prepare right operand context
1007 v.use_if_true_flow_ctx(n_expr)
1008
1009 # Process right operand
1010 v.enter_visit(n_expr2)
1011 if n_expr2.if_true_flow_ctx != null then
1012 _if_true_flow_ctx = n_expr2.if_true_flow_ctx
1013 else
1014 _if_true_flow_ctx = v.flow_ctx
1015 end
1016
1017 v.flow_ctx = old_flow_ctx
1018
1019 v.check_conform_expr(n_expr, stype)
1020 v.check_conform_expr(n_expr2, stype)
1021 _stype = stype
1022 _is_typed = true
1023 end
1024 end
1025
1026 redef class ANotExpr
1027 redef fun after_typing(v)
1028 do
1029 v.check_conform_expr(n_expr, v.type_bool)
1030
1031 # Invert if_true/if_false information
1032 _if_false_flow_ctx = n_expr._if_true_flow_ctx
1033 _if_true_flow_ctx = n_expr._if_false_flow_ctx
1034
1035 _stype = v.type_bool
1036 _is_typed = true
1037 end
1038 end
1039
1040 redef class AOrElseExpr
1041 redef fun after_typing(v)
1042 do
1043 var old_flow_ctx = v.flow_ctx
1044
1045 # Process left operand
1046 v.enter_visit(n_expr)
1047 v.check_expr(n_expr)
1048
1049 # Consider the type of the left operand
1050 var t = n_expr.stype
1051 if not t.is_nullable then
1052 v.warning(n_expr, "Warning: left operand of a 'or else' is not a nullable type.")
1053 else
1054 t = t.as_notnull
1055 end
1056
1057 # Prepare the else context : ie the first expression is null
1058 var variable = n_expr.its_variable
1059 if variable != null then
1060 v.flow_ctx.sub_with(self, variable, v.type_none)
1061 end
1062
1063 # Process right operand
1064 v.enter_visit(n_expr2)
1065 v.check_expr(n_expr)
1066
1067 # Restore the context
1068 v.flow_ctx = old_flow_ctx
1069
1070 # Merge the types
1071 var stype = v.check_conform_multiexpr(t, [n_expr2])
1072 if stype == null then return
1073
1074 _stype = stype
1075 _is_typed = true
1076 end
1077 end
1078
1079 redef class AIntExpr
1080 redef fun after_typing(v)
1081 do
1082 _stype = v.type_int
1083 _is_typed = true
1084 end
1085 end
1086
1087 redef class AFloatExpr
1088 redef fun after_typing(v)
1089 do
1090 _stype = v.type_float
1091 _is_typed = true
1092 end
1093 end
1094
1095 redef class ACharExpr
1096 redef fun after_typing(v)
1097 do
1098 _stype = v.type_char
1099 _is_typed = true
1100 end
1101 end
1102
1103 redef class AStringFormExpr
1104 redef fun after_typing(v)
1105 do
1106 _stype = v.type_string
1107 _is_typed = true
1108 end
1109 end
1110
1111 redef class ASuperstringExpr
1112 redef fun atype do return _atype.as(not null)
1113 var _atype: nullable MMType
1114 redef fun after_typing(v)
1115 do
1116 var otype = v.type_object
1117 var stype = v.type_string
1118 _stype = stype
1119 for e in n_exprs do v.check_conform_expr(e, otype)
1120 var atype = v.type_array(stype)
1121 _atype = atype
1122 _is_typed = true
1123 end
1124 end
1125
1126 redef class ANullExpr
1127 redef fun after_typing(v)
1128 do
1129 _stype = v.type_none
1130 _is_typed = true
1131 end
1132 end
1133
1134 redef class AArrayExpr
1135 redef fun after_typing(v)
1136 do
1137 var stype = v.check_conform_multiexpr(null, n_exprs.n_exprs)
1138 if stype != null then do_typing(v, stype)
1139 end
1140
1141 private fun do_typing(v: TypingVisitor, element_type: MMType)
1142 do
1143 _stype = v.type_array(element_type)
1144 _is_typed = true
1145 end
1146 end
1147
1148 redef class ARangeExpr
1149 redef fun after_typing(v)
1150 do
1151 if not v.check_expr(n_expr) or not v.check_expr(n_expr2) then return
1152 var ntype = n_expr.stype
1153 var ntype2 = n_expr2.stype
1154 if ntype < ntype2 then
1155 ntype = ntype2
1156 else if not ntype2 < ntype then
1157 v.error(self, "Type error: {ntype} incompatible with {ntype2}.")
1158 return
1159 end
1160 var dtype = v.type_discrete
1161 if not v.check_conform_expr(n_expr, dtype) or not v.check_conform_expr(n_expr2, dtype) then return
1162 _stype = v.type_range(ntype)
1163 _is_typed = true
1164 end
1165 end
1166
1167 redef class ASuperExpr
1168 redef readable var _init_in_superclass: nullable MMMethod
1169 redef fun compute_raw_arguments do return n_args.to_a
1170 redef fun after_typing(v)
1171 do
1172 var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters
1173 if not precs.is_empty then
1174 v.local_property.need_super = true
1175 else if v.local_property.global.is_init then
1176 var base_precs = v.local_class.super_methods_named(v.local_property.name)
1177 for p in base_precs do
1178 if not p.global.is_init then
1179 v.error(self, "Error: {p.local_class}::{p} is not a constructor.")
1180 else
1181 precs.add(v.local_class[p.global])
1182 end
1183 end
1184 if precs.is_empty then
1185 v.error(self, "Error: No contructor named {v.local_property.name} in superclasses.")
1186 return
1187 else if precs.length > 1 then
1188 v.error(self, "Error: Conflicting contructors named {v.local_property.name} in superclasses: {precs.join(", ")}.")
1189 return
1190 end
1191 var p = base_precs.first
1192 assert p isa MMMethod
1193 _init_in_superclass = p
1194 register_super_init_call(v, p)
1195 if n_args.n_exprs.length > 0 then
1196 var signature = get_signature(v, v.self_var.stype.as(not null), p, true)
1197 process_signature(v, signature, p.name, compute_raw_arguments)
1198 end
1199 else
1200 v.error(self, "Error: No super method to call for {v.local_property}.")
1201 return
1202 end
1203
1204 if precs.first.signature_for(v.self_var.stype.as(not null)).return_type != null then
1205 var stypes = new Array[MMType]
1206 var stype: nullable MMType = null
1207 for prop in precs do
1208 assert prop isa MMMethod
1209 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)
1210 stypes.add(t)
1211 if stype == null or stype < t then
1212 stype = t
1213 end
1214 end
1215 for t in stypes do
1216 v.check_conform(self, t, stype.as(not null))
1217 end
1218 _stype = stype
1219 end
1220 var p = v.local_property
1221 assert p isa MMSrcMethod
1222 _prop = p
1223 _is_typed = true
1224 end
1225 end
1226
1227 redef class AExternCall
1228 fun target_class_name : nullable Symbol do return null
1229 fun target_method_name : Symbol is abstract
1230
1231 redef fun after_typing(v)
1232 do
1233 var target_class_name = self.target_class_name
1234 var target_method_name = self.target_method_name
1235
1236 var target_class : MMLocalClass
1237 var target_method : MMMethod
1238
1239 # find class
1240 # self.target_class_name can be redef'd by sub-classes
1241 if target_class_name == null then
1242 target_class = v.local_property.local_class
1243 else
1244 if v.local_property.mmmodule.has_global_class_named( target_class_name ) then
1245 var global_class = v.local_property.mmmodule.global_class_named( target_class_name )
1246 target_class = v.local_property.mmmodule[ global_class ]
1247 else
1248 v.error( self, "Error: class {target_class_name.to_s}, not found." )
1249 return
1250 end
1251 end
1252
1253 if target_class.has_global_property_by_name( target_method_name ) then
1254 var global_property = target_class.get_property_by_name( target_method_name )
1255
1256 var target_property = target_class[global_property]
1257
1258 if target_property isa MMMethod then
1259 target_method = target_property
1260 else
1261 v.error( self, "Error: property {target_method_name.to_s} is not a method." )
1262 return
1263 end
1264 else
1265 v.error( self, "Error: property {target_method_name.to_s} not found in target class." )
1266 return
1267 end
1268
1269 var explicit_import = new MMExplicitImport( target_class, target_method )
1270 v.local_property.as(MMSrcMethod).explicit_imports.add( explicit_import )
1271 end
1272 end
1273
1274 redef class ALocalPropExternCall
1275 redef fun target_class_name do return null
1276 redef fun target_method_name do return n_methid.name.as(not null)
1277 end
1278
1279 redef class ASuperExternCall
1280 redef fun after_typing(v)
1281 do
1282 var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters
1283 if not precs.is_empty then
1284 v.local_property.need_super = true
1285 else
1286 v.error(self, "Error: No super method to call for {v.local_property}.")
1287 return
1288 end
1289 end
1290 end
1291
1292 redef class AFullPropExternCall
1293 redef fun target_class_name do return n_classid.to_symbol
1294 redef fun target_method_name do return n_methid.name.as(not null)
1295 end
1296
1297 redef class AInitPropExternCall
1298 redef fun target_class_name do return n_classid.to_symbol
1299 redef fun target_method_name do return "init".to_symbol
1300 end
1301
1302 redef class ACastExternCall
1303 fun from_type : MMType is abstract
1304 fun to_type : MMType is abstract
1305
1306 redef fun after_typing(v)
1307 do
1308 if from_type == to_type
1309 then
1310 v.error( self, "Attepting to cast from and to the same type." )
1311 end
1312
1313 var cast = new MMImportedCast( from_type, to_type )
1314 var m = v.local_property
1315 assert m isa MMMethod
1316 m.explicit_casts.add( cast )
1317 end
1318 end
1319
1320 redef class ACastAsExternCall
1321 redef fun from_type do return n_from_type.stype
1322 redef fun to_type do return n_to_type.stype
1323 end
1324
1325 redef class AAsNullableExternCall
1326 redef fun from_type do return n_type.stype
1327 redef fun to_type do return n_type.stype.as_nullable
1328 end
1329
1330 redef class AAsNotNullableExternCall
1331 redef fun from_type
1332 do
1333 var t = n_type.stype
1334 if t.is_nullable
1335 then
1336 return t
1337 else
1338 return t.as_nullable
1339 end
1340 end
1341 redef fun to_type do return n_type.stype.as_notnull
1342 end
1343
1344 redef class AAttrFormExpr
1345 redef fun prop do return _prop.as(not null)
1346 var _prop: nullable MMAttribute
1347
1348 redef fun attr_type do return _attr_type.as(not null)
1349 var _attr_type: nullable MMType
1350
1351 # Compute the attribute accessed
1352 private fun do_typing(v: TypingVisitor)
1353 do
1354 if not v.check_expr(n_expr) then return
1355 var type_recv = n_expr.stype
1356 var name = n_id.to_symbol
1357 if type_recv isa MMTypeNone then
1358 v.error(self, "Error: Attribute '{name}' access on 'null'.")
1359 return
1360 end
1361 var lc = type_recv.local_class
1362 if not lc.has_global_property_by_name(name) then
1363 v.error(self, "Error: Attribute {name} doesn't exists in {type_recv}.")
1364 return
1365 end
1366 var prop = lc.select_attribute(name)
1367 if v.mmmodule.visibility_for(prop.global.local_class.mmmodule) < 3 then
1368 v.error(self, "Error: Attribute {name} from {prop.global.local_class.mmmodule} is invisible in {v.mmmodule}")
1369 end
1370 _prop = prop
1371 var at = prop.signature_for(type_recv).return_type
1372 if not n_expr.is_self then at = at.not_for_self
1373 _attr_type = at
1374 end
1375 end
1376
1377 redef class AAttrExpr
1378 redef fun after_typing(v)
1379 do
1380 do_typing(v)
1381 if _prop == null then return
1382 _stype = attr_type
1383 _is_typed = true
1384 end
1385 end
1386
1387 redef class AAttrAssignExpr
1388 redef fun after_typing(v)
1389 do
1390 do_typing(v)
1391 if _prop == null then return
1392 if not v.check_conform_expr(n_value, attr_type) then return
1393 _is_typed = true
1394 end
1395 end
1396
1397 redef class AAttrReassignExpr
1398 redef fun after_typing(v)
1399 do
1400 do_typing(v)
1401 if _prop == null then return
1402 var t = do_rvalue_typing(v, attr_type)
1403 if t == null then return
1404 v.check_conform(self, t, n_value.stype)
1405 _is_typed = true
1406 end
1407 end
1408
1409 redef class AIssetAttrExpr
1410 redef fun after_typing(v)
1411 do
1412 do_typing(v)
1413 if _prop == null then return
1414 if attr_type.is_nullable then
1415 v.error(self, "Error: isset on a nullable attribute.")
1416 end
1417 _stype = v.type_bool
1418 _is_typed = true
1419 end
1420 end
1421
1422 redef class AAbsAbsSendExpr
1423 # The signature of the called property
1424 redef fun prop_signature do return _prop_signature.as(not null)
1425 var _prop_signature: nullable MMSignature
1426
1427 # Raw arguments used (without vararg transformation)
1428 redef fun raw_arguments: Array[AExpr]
1429 do
1430 var res = _raw_arguments_cache
1431 if res != null then
1432 return res
1433 else
1434 res = compute_raw_arguments
1435 if res == null then res = new Array[AExpr]
1436 _raw_arguments_cache = res
1437 return res
1438 end
1439 end
1440
1441 var _raw_arguments_cache: nullable Array[AExpr] = null
1442
1443 fun compute_raw_arguments: nullable Array[AExpr]
1444 do
1445 print "{location} no compute_raw_arguments"
1446 return null
1447 end
1448
1449 # Check the conformity of a set of arguments `raw_args' to a signature.
1450 private fun process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: nullable Array[AExpr]): Bool
1451 do
1452 var par_vararg = psig.vararg_rank
1453 var par_arity = psig.arity
1454 var raw_arity: Int
1455 if raw_args == null then raw_arity = 0 else raw_arity = raw_args.length
1456 if par_arity > raw_arity or (par_arity != raw_arity and par_vararg == -1) then
1457 v.error(self, "Error: arity mismatch; prototype is '{name}{psig}'.")
1458 return false
1459 end
1460 var arg_idx = 0
1461 for par_idx in [0..par_arity[ do
1462 var a: AExpr
1463 var par_type = psig[par_idx]
1464 if par_idx == par_vararg then
1465 for i in [0..(raw_arity-par_arity)] do
1466 a = raw_args[arg_idx]
1467 v.check_conform_expr(a, par_type)
1468 arg_idx = arg_idx + 1
1469 end
1470 else
1471 a = raw_args[arg_idx]
1472 v.check_conform_expr(a, par_type)
1473 arg_idx = arg_idx + 1
1474 end
1475 end
1476 return true
1477 end
1478
1479 # Check the conformity of a set of defined closures
1480 private fun process_closures(v: TypingVisitor, psig: MMSignature, name: Symbol, cd: nullable Array[AClosureDef]): nullable MMType
1481 do
1482 var t = psig.return_type
1483 var cs = psig.closures # Declared closures
1484 var min_arity = 0
1485 for c in cs do
1486 if not c.is_optional then min_arity += 1
1487 end
1488 var arity = 0
1489 if cd != null then arity = cd.length
1490 if cs.length > 0 then
1491 if arity == 0 and min_arity > 0 then
1492 v.error(self, "Error: {name} requires {cs.length} blocks.")
1493 else if arity > cs.length or arity < min_arity then
1494 v.error(self, "Error: {name} requires {cs.length} blocks, {cd.length} found.")
1495 else
1496 # Initialize the break list if a value is required for breaks (ie. if the method is a function)
1497 var break_list: nullable Array[ABreakExpr] = null
1498 if t != null then break_list = new Array[ABreakExpr]
1499
1500 # The n_label, is any in only set on the last decl
1501 var n_label = if arity > 0 then cd[arity-1].n_label else null
1502
1503 # Process each closure definition
1504 for i in [0..arity[ do
1505 var cdi = cd[i]
1506 var cni = cdi.n_id.to_symbol
1507 var csi = psig.closure_named(cni)
1508 if csi != null then
1509 var esc = new EscapableClosure(cdi, csi, break_list)
1510 v.scope_ctx.push_escapable(esc, n_label)
1511 cdi.accept_typing2(v, esc)
1512 v.scope_ctx.pop
1513 else if cs.length == 1 then
1514 v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closure is !{cs.first.name}.")
1515 else
1516 var a = new Array[String]
1517 for c in cs do
1518 a.add("!{c.name}")
1519 end
1520 v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closures are {a.join(",")}.")
1521 end
1522 end
1523
1524 # Check break type conformity
1525 if break_list != null then
1526 t = v.check_conform_multiexpr(t, break_list)
1527 end
1528 end
1529 else if arity != 0 then
1530 v.error(self, "Error: {name} does not require blocks.")
1531 end
1532 return t
1533 end
1534 end
1535
1536 redef class AAbsSendExpr
1537 # Compute the called global property
1538 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])
1539 do
1540 var prop = get_property(v, type_recv, is_implicit_self, name)
1541 if prop == null then return
1542 var sig = get_signature(v, type_recv, prop, recv_is_self)
1543 if not process_signature(v, sig, prop.name, raw_args) then return
1544 var rtype = process_closures(v, sig, prop.name, closure_defs)
1545 if rtype == null and sig.return_type != null then return
1546 _prop = prop
1547 _prop_signature = sig
1548 _return_type = rtype
1549 end
1550
1551 private fun get_property(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, name: Symbol): nullable MMMethod
1552 do
1553 if type_recv isa MMTypeNone then
1554 if name == (once "==".to_symbol) or name == (once "!=".to_symbol) then
1555 # Special case on != and == that are allowed for 'null'
1556 type_recv = v.type_object.as_nullable
1557 else
1558 v.error(self, "Error: Method '{name}' call on 'null'.")
1559 return null
1560 end
1561 end
1562 var lc = type_recv.local_class
1563 var prop: nullable MMMethod = null
1564 if lc.has_global_property_by_name(name) then prop = lc.select_method(name)
1565 if prop == null then
1566 var props = lc.super_methods_named(name)
1567 if props.length > 1 then
1568 v.error(self, "Error: Ambigous method name '{name}' for {props.join(", ")}. Use explicit designation.")
1569 return null
1570 else if props.length == 1 then
1571 var p = lc[props.first.global]
1572 assert p isa MMMethod
1573 prop = p
1574 end
1575
1576 end
1577 if prop == null then
1578 if is_implicit_self then
1579 v.error(self, "Error: Method or variable '{name}' unknown in {type_recv}.")
1580 else
1581 v.error(self, "Error: Method '{name}' doesn't exists in {type_recv}.")
1582 end
1583 return null
1584 end
1585 return prop
1586 end
1587
1588 # Get the signature for a local property and a receiver
1589 private fun get_signature(v: TypingVisitor, type_recv: MMType, prop: MMMethod, recv_is_self: Bool): MMSignature
1590 do
1591 prop.global.check_visibility(v, self, v.mmmodule, recv_is_self)
1592 var psig = prop.signature_for(type_recv)
1593 if not recv_is_self then psig = psig.not_for_self
1594 return psig
1595 end
1596
1597 # The invoked method (once computed)
1598 redef fun prop do return _prop.as(not null)
1599 var _prop: nullable MMMethod
1600
1601 # The return type (if any) (once computed)
1602 redef readable var _return_type: nullable MMType
1603 end
1604
1605 # A possible call of constructor in a super class
1606 # Could be an explicit call or with the 'super' keyword
1607 redef class ASuperInitCall
1608 private fun register_super_init_call(v: TypingVisitor, property: MMMethod)
1609 do
1610 if parent != v.top_block and self != v.top_block then
1611 v.error(self, "Error: Constructor invocation {property} must not be in nested block.")
1612 end
1613 var cla = v.mmmodule[property.global.intro.local_class.global]
1614 var prev_class: nullable MMLocalClass = null
1615 var esic = v.explicit_super_init_calls.as(not null)
1616 if not esic.is_empty then
1617 prev_class = esic.last.global.intro.local_class
1618 end
1619 var order = v.local_class.cshe.reverse_linear_extension
1620 if cla == v.local_class then
1621 v.explicit_other_init_call = true
1622 else if not order.has(cla) then
1623 v.error(self, "Error: Constructor of class {cla} must be one in {order.join(", ")}.")
1624 else if cla == prev_class then
1625 v.error(self, "Error: Only one super constructor invocation of class {cla} is allowed.")
1626 else
1627 for c in order do
1628 if c == prev_class then
1629 prev_class = null
1630 else if c == cla then
1631 esic.add(property)
1632 break
1633 end
1634 end
1635 end
1636 end
1637
1638 end
1639
1640 redef class ANewExpr
1641 redef fun compute_raw_arguments do return n_args.to_a
1642 redef fun after_typing(v)
1643 do
1644 if not n_type.is_typed then return
1645 var t = n_type.stype
1646 if t.local_class.global.is_abstract then
1647 v.error(self, "Error: try to instantiate abstract class {t.local_class}.")
1648 return
1649 end
1650 if t.is_nullable then
1651 v.error(self, "Type error: cannot instantiate the nullable type {t}.")
1652 end
1653 var name: Symbol
1654 if n_id == null then
1655 name = once "init".to_symbol
1656 else
1657 name = n_id.to_symbol
1658 end
1659
1660 do_typing(v, t, false, false, name, raw_arguments, null)
1661 if _prop == null then return
1662
1663 if not prop.global.is_init then
1664 v.error(self, "Error: {prop} is not a constructor.")
1665 return
1666 end
1667 if not prop.global.is_init_for(t.local_class) then
1668 v.error(self, "Error: {prop} is not a constructor in {t.local_class}.")
1669 return
1670 end
1671 _stype = t
1672 _is_typed = true
1673 end
1674 end
1675
1676
1677 redef class ASendExpr
1678 # Name of the invoked property
1679 fun name: Symbol is abstract
1680
1681 # Closure definitions
1682 redef fun closure_defs: nullable Array[AClosureDef] do return null
1683
1684 redef fun after_typing(v)
1685 do
1686 do_all_typing(v)
1687 end
1688
1689 private fun do_all_typing(v: TypingVisitor)
1690 do
1691 if not v.check_expr(n_expr) then return
1692 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_arguments, closure_defs)
1693 if _prop == null then return
1694 var prop = _prop.as(not null)
1695
1696 if prop.global.is_init then
1697 if not v.local_property.global.is_init then
1698 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1699 else if not n_expr.is_self then
1700 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1701 else
1702 register_super_init_call(v, prop)
1703 end
1704 end
1705
1706 _stype = return_type
1707 _is_typed = true
1708 end
1709 end
1710
1711 redef class ASendReassignExpr
1712 redef fun read_prop do return _read_prop.as(not null)
1713 var _read_prop: nullable MMMethod
1714 redef fun do_all_typing(v)
1715 do
1716 if not v.check_expr(n_expr) then return
1717 var raw_args = raw_arguments
1718 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_args, null)
1719 var prop = _prop
1720 if prop == null then return
1721 if prop.global.is_init then
1722 if not v.local_property.global.is_init then
1723 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1724 else if not n_expr.is_self then
1725 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1726 end
1727 end
1728 var t = prop.signature_for(n_expr.stype).return_type.as(not null)
1729 if not n_expr.is_self then t = t.not_for_self
1730
1731 var t2 = do_rvalue_typing(v, t)
1732 if t2 == null then return
1733 v.check_conform(self, t2, n_value.stype)
1734
1735 _read_prop = prop
1736 raw_args = raw_args.to_a
1737 raw_args.add(n_value)
1738
1739 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, "{name}=".to_symbol, raw_args, null)
1740 if prop.global.is_init then
1741 if not v.local_property.global.is_init then
1742 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1743 else if not n_expr.is_self then
1744 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1745 end
1746 end
1747
1748 _is_typed = true
1749 end
1750 end
1751
1752 redef class ABinopExpr
1753 redef fun compute_raw_arguments do return [n_expr2]
1754 end
1755 redef class AEqExpr
1756 redef fun name do return once "==".to_symbol
1757 redef fun after_typing(v)
1758 do
1759 super
1760 if not n_expr.is_typed or not n_expr2.is_typed then return
1761 if n_expr.stype isa MMTypeNone and not n_expr2.stype.is_nullable or
1762 n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
1763 v.warning(self, "Warning: comparaison between null and a non nullable value.")
1764 end
1765
1766 if n_expr.stype isa MMTypeNone then
1767 if n_expr2.stype isa MMTypeNone then
1768 v.warning(self, "Warning: comparaison between two null values.")
1769 else
1770 try_to_isa(v, n_expr2)
1771 end
1772 else if n_expr2.stype isa MMTypeNone then
1773 try_to_isa(v, n_expr)
1774 end
1775 end
1776
1777 private fun try_to_isa(v: TypingVisitor, n: AExpr)
1778 do
1779 var variable = n.its_variable
1780 if variable != null and n.stype isa MMNullableType then
1781 _if_false_flow_ctx = v.flow_ctx.sub_with(self, variable, n.stype.as_notnull)
1782 _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, v.type_none)
1783 end
1784 end
1785 end
1786 redef class ANeExpr
1787 redef fun name do return once "!=".to_symbol
1788 redef fun after_typing(v)
1789 do
1790 super
1791 if not n_expr.is_typed or not n_expr2.is_typed then return
1792 if n_expr.stype isa MMTypeNone and not n_expr2.stype.is_nullable or
1793 n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
1794 v.warning(self, "Warning: comparaison between null and a non nullable value.")
1795 end
1796
1797 if n_expr.stype isa MMTypeNone then
1798 if n_expr2.stype isa MMTypeNone then
1799 v.warning(self, "Warning: comparaison between two null values.")
1800 else
1801 try_to_isa(v, n_expr2)
1802 end
1803 else if n_expr2.stype isa MMTypeNone then
1804 try_to_isa(v, n_expr)
1805 end
1806 end
1807
1808 private fun try_to_isa(v: TypingVisitor, n: AExpr)
1809 do
1810 var variable = n.its_variable
1811 if variable != null and n.stype isa MMNullableType then
1812 _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, n.stype.as_notnull)
1813 _if_false_flow_ctx = v.flow_ctx.sub_with(self, variable, v.type_none)
1814 end
1815 end
1816 end
1817 redef class ALtExpr
1818 redef fun name do return once "<".to_symbol
1819 end
1820 redef class ALeExpr
1821 redef fun name do return once "<=".to_symbol
1822 end
1823 redef class ALlExpr
1824 redef fun name do return once "<<".to_symbol
1825 end
1826 redef class AGtExpr
1827 redef fun name do return once ">".to_symbol
1828 end
1829 redef class AGeExpr
1830 redef fun name do return once ">=".to_symbol
1831 end
1832 redef class AGgExpr
1833 redef fun name do return once ">>".to_symbol
1834 end
1835 redef class APlusExpr
1836 redef fun name do return once "+".to_symbol
1837 end
1838 redef class AMinusExpr
1839 redef fun name do return once "-".to_symbol
1840 end
1841 redef class AStarshipExpr
1842 redef fun name do return once "<=>".to_symbol
1843 end
1844 redef class AStarExpr
1845 redef fun name do return once "*".to_symbol
1846 end
1847 redef class ASlashExpr
1848 redef fun name do return once "/".to_symbol
1849 end
1850 redef class APercentExpr
1851 redef fun name do return once "%".to_symbol
1852 end
1853
1854 redef class AUminusExpr
1855 redef fun name do return once "unary -".to_symbol
1856 redef fun compute_raw_arguments do return null
1857 end
1858
1859 redef class ACallFormExpr
1860 redef fun after_typing(v)
1861 do
1862 if n_expr.is_implicit_self then
1863 var name = n_id.to_symbol
1864 var variable = v.scope_ctx[name]
1865 if variable != null then
1866 var n: AExpr
1867 if variable isa ClosureVariable then
1868 n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs)
1869 n._variable = variable
1870 else
1871 if not n_args.n_exprs.is_empty or n_args isa AParExprs then
1872 v.error(self, "Error: {name} is variable, not a function.")
1873 return
1874 end
1875 n = variable_create(variable)
1876 n._variable = variable
1877 end
1878 replace_with(n)
1879 n.after_typing(v)
1880 return
1881 end
1882 end
1883
1884 super
1885 end
1886
1887 redef fun closure_defs
1888 do
1889 if n_closure_defs.is_empty then
1890 return null
1891 else
1892 return n_closure_defs.to_a
1893 end
1894 end
1895
1896 # Create a variable acces corresponding to the call form
1897 fun variable_create(variable: Variable): AVarFormExpr is abstract
1898 end
1899
1900 redef class ACallExpr
1901 redef fun variable_create(variable)
1902 do
1903 return new AVarExpr.init_avarexpr(n_id)
1904 end
1905
1906 redef fun name do return n_id.to_symbol
1907 redef fun compute_raw_arguments do return n_args.to_a
1908 end
1909
1910 redef class ACallAssignExpr
1911 redef fun variable_create(variable)
1912 do
1913 return new AVarAssignExpr.init_avarassignexpr(n_id, n_assign, n_value)
1914 end
1915
1916 redef fun name do return (n_id.text + "=").to_symbol
1917 redef fun compute_raw_arguments do
1918 var res = n_args.to_a
1919 res.add(n_value)
1920 return res
1921 end
1922 end
1923
1924 redef class ACallReassignExpr
1925 redef fun variable_create(variable)
1926 do
1927 return new AVarReassignExpr.init_avarreassignexpr(n_id, n_assign_op, n_value)
1928 end
1929
1930 redef fun name do return n_id.to_symbol
1931 redef fun compute_raw_arguments do return n_args.to_a
1932 end
1933
1934 redef class ABraExpr
1935 redef fun name do return once "[]".to_symbol
1936 redef fun compute_raw_arguments do return n_args.to_a
1937 redef fun closure_defs
1938 do
1939 if n_closure_defs.is_empty then
1940 return null
1941 else
1942 return n_closure_defs.to_a
1943 end
1944 end
1945 end
1946
1947 redef class ABraAssignExpr
1948 redef fun name do return once "[]=".to_symbol
1949 redef fun compute_raw_arguments do
1950 var res = n_args.to_a
1951 res.add(n_value)
1952 return res
1953 end
1954 end
1955
1956 redef class ABraReassignExpr
1957 redef fun name do return once "[]".to_symbol
1958 redef fun compute_raw_arguments do return n_args.to_a
1959 end
1960
1961 redef class AInitExpr
1962 redef fun name do return once "init".to_symbol
1963 redef fun compute_raw_arguments do return n_args.to_a
1964 end
1965
1966 redef class AClosureCallExpr
1967 var _variable: nullable ClosureVariable
1968 redef fun variable do return _variable.as(not null)
1969 redef fun compute_raw_arguments do return n_args.to_a
1970
1971 redef fun after_typing(v)
1972 do
1973 var va = variable
1974 if va.closure.is_break then v.mark_unreash(self)
1975 var sig = va.closure.signature
1976 var s = process_signature(v, sig, n_id.to_symbol, compute_raw_arguments)
1977 if not n_closure_defs.is_empty then
1978 process_closures(v, sig, n_id.to_symbol, n_closure_defs.to_a)
1979 end
1980 if not s then return
1981 _prop_signature = sig
1982 _stype = sig.return_type
1983 _is_typed = true
1984 end
1985 end
1986
1987 redef class AClosureId
1988 fun to_symbol: Symbol is abstract
1989 end
1990 redef class ASimpleClosureId
1991 redef fun to_symbol: Symbol do return n_id.to_symbol
1992 end
1993 redef class ABreakClosureId
1994 redef fun to_symbol: Symbol do return n_kwbreak.to_symbol
1995 end
1996
1997 redef class AClosureDef
1998 var _closure: nullable MMClosure
1999 redef fun closure do return _closure.as(not null)
2000
2001 # The corresponding escapable object
2002 readable var _escapable: nullable EscapableBlock
2003
2004 var _accept_typing2: Bool = false
2005 redef fun accept_typing(v)
2006 do
2007 # Typing is deferred, wait accept_typing2(v)
2008 if _accept_typing2 then super
2009 end
2010
2011 private fun accept_typing2(v: TypingVisitor, esc: EscapableClosure)
2012 do
2013 _escapable = esc
2014
2015 var sig = esc.closure.signature
2016 if sig.arity != n_ids.length then
2017 v.error(self, "Error: {sig.arity} automatic variable names expected, {n_ids.length} found.")
2018 return
2019 end
2020
2021 _closure = esc.closure
2022
2023 v.scope_ctx.push(self)
2024 var old_flow_ctx = v.flow_ctx
2025 var old_base_flow_ctx = v.base_flow_ctx
2026 v.base_flow_ctx = v.flow_ctx
2027 variables = new Array[AutoVariable]
2028 for i in [0..n_ids.length[ do
2029 var va = new AutoVariable(n_ids[i].to_symbol, n_ids[i])
2030 variables.add(va)
2031 va.stype = sig[i]
2032 v.scope_ctx.add_variable(va)
2033 end
2034
2035 _accept_typing2 = true
2036 accept_typing(v)
2037
2038 if v.flow_ctx.unreash == false then
2039 if closure.signature.return_type != null then
2040 v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
2041 else if closure.is_break and esc.break_list != null then
2042 v.error(self, "Control error: Reached end of break block (a 'break' with a value was expected).")
2043 end
2044 end
2045 v.flow_ctx = old_flow_ctx
2046 v.base_flow_ctx = old_base_flow_ctx
2047 v.scope_ctx.pop
2048 end
2049 end
2050
2051 abstract class ATypeCheckExpr
2052 super AExpr
2053 private fun check_expr_cast(v: TypingVisitor, n_expr: AExpr, n_type: AType)
2054 do
2055 if not v.check_expr(n_expr) then return
2056 if not n_type.is_typed then return
2057 var etype = n_expr.stype
2058 var ttype = n_type.stype
2059 if etype == ttype then
2060 v.warning(self, "Warning: Expression is already a {ttype}.")
2061 else if etype < ttype then
2062 if not ttype.has_formal and not etype.has_formal then
2063 # the old metamodel is not that great with formal types
2064 v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.")
2065 end
2066 else if etype isa MMTypeNone then
2067 # ttype is not nullable because of prevous test
2068 v.warning(self, "Warning: Expression is null therefore cannot be a {ttype}.")
2069 else if etype.is_nullable and etype.as_notnull == ttype then
2070 if ttype isa MMTypeFormal and ttype.bound.is_nullable then
2071 # No warning in this case since with
2072 # type T: nullable A
2073 # var x: nullable T
2074 # 'x.as(not null)' != 'x.as(T)'
2075 # 'x != null' != 'x isa T'
2076 else if self isa AIsaExpr then
2077 v.warning(self, "Warning: Prefer '!= null'.")
2078 else
2079 v.warning(self, "Warning: Prefer '.as(not null)'.")
2080 end
2081 end
2082 end
2083 end
2084
2085 redef class AIsaExpr
2086 super ATypeCheckExpr
2087 redef fun after_typing(v)
2088 do
2089 check_expr_cast(v, n_expr, n_type)
2090 if not n_type.is_typed then return
2091 var variable = n_expr.its_variable
2092 if variable != null then
2093 _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, n_type.stype)
2094 end
2095 _stype = v.type_bool
2096 _is_typed = true
2097 end
2098 end
2099
2100 redef class AAsCastExpr
2101 super ATypeCheckExpr
2102 redef fun after_typing(v)
2103 do
2104 check_expr_cast(v, n_expr, n_type)
2105 if not n_type.is_typed then return
2106 _stype = n_type.stype
2107 _is_typed = _stype != null
2108 end
2109 end
2110
2111 redef class AAsNotnullExpr
2112 redef fun after_typing(v)
2113 do
2114 if not v.check_expr(n_expr) then return
2115 var t = n_expr.stype
2116 if t isa MMTypeNone then
2117 v.error(n_expr, "Type error: 'as(not null)' on 'null' value.")
2118 return
2119 else if not t.is_nullable then
2120 v.warning(n_expr, "Warning: 'as(not null)' on non nullable type.")
2121 end
2122 _stype = n_expr.stype.as_notnull
2123 _is_typed = true
2124 end
2125 end
2126
2127 redef class AProxyExpr
2128 redef fun after_typing(v)
2129 do
2130 if not n_expr.is_typed then return
2131 _is_typed = true
2132 if n_expr.is_statement then return
2133 _stype = n_expr.stype
2134 _if_true_flow_ctx = n_expr._if_true_flow_ctx
2135 _if_false_flow_ctx = n_expr._if_false_flow_ctx
2136 end
2137
2138 redef fun is_self do return n_expr.is_self
2139
2140 redef fun its_variable do return n_expr.its_variable
2141 end
2142
2143 redef class AOnceExpr
2144 redef fun accept_typing(v)
2145 do
2146 if v.once_count > 0 then
2147 v.warning(self, "Useless once in a once expression.")
2148 end
2149 v.once_count = v.once_count + 1
2150
2151 super
2152
2153 v.once_count = v.once_count - 1
2154 end
2155 end
2156
2157 redef class ADebugTypeExpr
2158 redef fun after_typing(v)
2159 do
2160 if not v.check_expr(n_expr) then return
2161 if not n_type.is_typed then return
2162 var etype = n_expr.stype
2163 var ttype = n_type.stype
2164 if etype != ttype then
2165 v.warning(self, "Warning: Expression is a {etype}, expected {ttype}.")
2166 end
2167 end
2168 end