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