metamodel: rename 'universal' to 'enum'
[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 special 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 constrctor in {c}. Discarded candidates are {a.join(", ")}.")
156 return null
157 else
158 v.error(n, "Error: there is no available compatible constrctor 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 special 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 special 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 special 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 special 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 special AAbsControl
640 var _variable: nullable AutoVariable
641 redef fun variable do return _variable.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 # Create the automatic variable
654 var va = new AutoVariable(n_id.to_symbol, n_id)
655 _variable = va
656 v.scope_ctx.add_variable(va)
657
658 # Process collection
659 v.enter_visit(n_expr)
660
661 if not v.check_conform_expr(n_expr, v.type_collection) then return
662 var expr_type = n_expr.stype
663
664 # Get iterator
665 var meth_iterator = v.get_method(expr_type, once "iterator".to_symbol)
666 var iter_type = meth_iterator.signature_for(expr_type).return_type.as(not null)
667 var meth_item = v.get_method(iter_type, once ("item".to_symbol))
668 var va_stype = meth_item.signature_for(iter_type).return_type.as(not null)
669 if not n_expr.is_self then va_stype = va_stype.not_for_self
670 va.stype = va_stype
671
672 # Process inside
673 v.enter_visit_block(n_block)
674
675 # end == begin of the loop
676 v.flow_ctx = old_flow_ctx
677 v.scope_ctx.pop
678 end
679 end
680
681 redef class AAssertExpr
682 redef fun accept_typing(v)
683 do
684 # Process condition
685 v.enter_visit(n_expr)
686 v.check_conform_expr(n_expr, v.type_bool)
687
688 # Process optional 'else' part
689 if n_else != null then
690 var old_flow_ctx = v.flow_ctx
691 v.use_if_false_flow_ctx(n_expr)
692 v.enter_visit(n_else)
693 v.flow_ctx = old_flow_ctx
694 end
695
696 # Prepare outside
697 v.use_if_true_flow_ctx(n_expr)
698 _is_typed = true
699 end
700 end
701
702 redef class AVarFormExpr
703 var _variable: nullable Variable
704 redef fun variable do return _variable.as(not null)
705 end
706
707 redef class AVarExpr
708 redef fun its_variable do return variable
709
710 redef fun after_typing(v)
711 do
712 v.flow_ctx.check_is_set(self, variable)
713 _stype = v.flow_ctx.stype(variable)
714 _is_typed = _stype != null
715 end
716 end
717
718 redef class AVarAssignExpr
719 redef fun after_typing(v)
720 do
721 v.mark_is_set(variable)
722
723 # Check the base type
724 var btype = v.base_flow_ctx.stype(variable)
725 if not v.check_expr(n_value) then return
726 if btype != null and not v.check_conform_expr(n_value, btype) then return
727
728 # Always cast
729 v.flow_ctx = v.flow_ctx.sub_with(self, variable, n_value.stype)
730
731 _is_typed = true
732 end
733 end
734
735 redef class AReassignFormExpr
736 # Compute and check method used through the reassigment operator
737 # On success return the static type of the result of the reassigment operator
738 # Else display an error and return null
739 private fun do_rvalue_typing(v: TypingVisitor, type_lvalue: nullable MMType): nullable MMType
740 do
741 if type_lvalue == null then
742 return null
743 end
744 var name = n_assign_op.method_name
745 if type_lvalue isa MMTypeNone then
746 v.error(self, "Error: Method '{name}' call on 'null'.")
747 return null
748 end
749 var lc = type_lvalue.local_class
750 if not lc.has_global_property_by_name(name) then
751 v.error(self, "Error: Method '{name}' doesn't exists in {type_lvalue}.")
752 return null
753 end
754 var prop = lc.select_method(name)
755 prop.global.check_visibility(v, self, v.mmmodule, false)
756 var psig = prop.signature_for(type_lvalue)
757 _assign_method = prop
758 if not v.check_conform_expr(n_value, psig[0].not_for_self) then return null
759 return psig.return_type.not_for_self
760 end
761
762 redef fun assign_method do return _assign_method.as(not null)
763 var _assign_method: nullable MMMethod
764 end
765
766 redef class AVarReassignExpr
767 redef fun after_typing(v)
768 do
769 v.flow_ctx.check_is_set(self, variable)
770 v.mark_is_set(variable)
771 var t = v.flow_ctx.stype(variable)
772 var t2 = do_rvalue_typing(v, t)
773 if t2 == null then return
774
775 # Check the base type
776 var btype = v.base_flow_ctx.stype(variable)
777 if not v.check_expr(n_value) then return
778 if btype != null and not v.check_conform(n_value, t2, btype) then return
779
780 # Always cast
781 v.flow_ctx = v.flow_ctx.sub_with(self, variable, t2)
782
783 _is_typed = true
784 end
785 end
786
787 redef class AAssignOp
788 fun method_name: Symbol is abstract
789 end
790 redef class APlusAssignOp
791 redef fun method_name do return once "+".to_symbol
792 end
793 redef class AMinusAssignOp
794 redef fun method_name do return once "-".to_symbol
795 end
796
797 redef class ASelfExpr
798 var _variable: nullable ParamVariable
799 redef fun variable do return _variable.as(not null)
800
801 redef fun its_variable do return variable
802
803 redef fun after_typing(v)
804 do
805 _variable = v.self_var
806 _stype = v.flow_ctx.stype(variable)
807 _is_typed = true
808 end
809
810 redef fun is_self do return true
811 end
812
813 redef class AImplicitSelfExpr
814 redef fun is_implicit_self do return true
815 end
816
817 redef class AIfexprExpr
818 redef fun accept_typing(v)
819 do
820 var old_flow_ctx = v.flow_ctx
821
822 # Process condition
823 v.enter_visit(n_expr)
824 v.check_conform_expr(n_expr, v.type_bool)
825
826 # Prepare 'then' context
827 v.use_if_true_flow_ctx(n_expr)
828
829 # Process 'then'
830 v.enter_visit_block(n_then)
831
832 # Remember what appened in the 'then'
833 var then_flow_ctx = v.flow_ctx
834
835 # Prepare 'else' context
836 v.flow_ctx = old_flow_ctx
837 v.use_if_false_flow_ctx(n_expr)
838
839 # Process 'else'
840 v.enter_visit_block(n_else)
841
842 # Merge 'then' and 'else' contexts
843 v.flow_ctx = v.base_flow_ctx.merge_reash(self, then_flow_ctx, v.flow_ctx)
844
845 var stype = v.check_conform_multiexpr(null, [n_then, n_else])
846 if stype == null then return
847
848 _stype = stype
849 _is_typed = true
850 end
851 end
852
853 redef class ABoolExpr
854 redef fun after_typing(v)
855 do
856 _stype = v.type_bool
857 _is_typed = true
858 end
859 end
860
861 redef class AOrExpr
862 redef fun accept_typing(v)
863 do
864 var old_flow_ctx = v.flow_ctx
865 var stype = v.type_bool
866 _stype = stype
867
868 # Process left operand
869 v.enter_visit(n_expr)
870
871 # Prepare right operand context
872 v.use_if_false_flow_ctx(n_expr)
873
874 # Process right operand
875 v.enter_visit(n_expr2)
876 if n_expr2.if_false_flow_ctx != null then
877 _if_false_flow_ctx = n_expr2.if_false_flow_ctx
878 else
879 _if_false_flow_ctx = v.flow_ctx
880 end
881
882 v.flow_ctx = old_flow_ctx
883
884 v.check_conform_expr(n_expr, stype)
885 v.check_conform_expr(n_expr2, stype)
886 _stype = stype
887 _is_typed = true
888 end
889 end
890
891 redef class AAndExpr
892 redef fun accept_typing(v)
893 do
894 var old_flow_ctx = v.flow_ctx
895 var stype = v.type_bool
896
897 # Process left operand
898 v.enter_visit(n_expr)
899
900 # Prepare right operand context
901 v.use_if_true_flow_ctx(n_expr)
902
903 # Process right operand
904 v.enter_visit(n_expr2)
905 if n_expr2.if_true_flow_ctx != null then
906 _if_true_flow_ctx = n_expr2.if_true_flow_ctx
907 else
908 _if_true_flow_ctx = v.flow_ctx
909 end
910
911 v.flow_ctx = old_flow_ctx
912
913 v.check_conform_expr(n_expr, stype)
914 v.check_conform_expr(n_expr2, stype)
915 _stype = stype
916 _is_typed = true
917 end
918 end
919
920 redef class ANotExpr
921 redef fun after_typing(v)
922 do
923 v.check_conform_expr(n_expr, v.type_bool)
924
925 # Invert if_true/if_false information
926 _if_false_flow_ctx = n_expr._if_true_flow_ctx
927 _if_true_flow_ctx = n_expr._if_false_flow_ctx
928
929 _stype = v.type_bool
930 _is_typed = true
931 end
932 end
933
934 redef class AOrElseExpr
935 redef fun after_typing(v)
936 do
937 var old_flow_ctx = v.flow_ctx
938
939 # Process left operand
940 v.enter_visit(n_expr)
941 v.check_expr(n_expr)
942
943 # Consider the type of the left operand
944 var t = n_expr.stype
945 if not t.is_nullable then
946 v.warning(n_expr, "Warning: left operant of a 'or else' is not a nullable type.")
947 else
948 t = t.as_notnull
949 end
950
951 # Prepare the else context : ie the first expression is null
952 var variable = n_expr.its_variable
953 if variable != null then
954 v.flow_ctx.sub_with(self, variable, v.type_none)
955 end
956
957 # Process right operand
958 v.enter_visit(n_expr2)
959 v.check_expr(n_expr)
960
961 # Restore the context
962 v.flow_ctx = old_flow_ctx
963
964 # Merge the types
965 var stype = v.check_conform_multiexpr(t, [n_expr2])
966 if stype == null then return
967
968 _stype = stype
969 _is_typed = true
970 end
971 end
972
973 redef class AIntExpr
974 redef fun after_typing(v)
975 do
976 _stype = v.type_int
977 _is_typed = true
978 end
979 end
980
981 redef class AFloatExpr
982 redef fun after_typing(v)
983 do
984 _stype = v.type_float
985 _is_typed = true
986 end
987 end
988
989 redef class ACharExpr
990 redef fun after_typing(v)
991 do
992 _stype = v.type_char
993 _is_typed = true
994 end
995 end
996
997 redef class AStringFormExpr
998 redef fun after_typing(v)
999 do
1000 _stype = v.type_string
1001 _is_typed = true
1002 end
1003 end
1004
1005 redef class ASuperstringExpr
1006 redef fun atype do return _atype.as(not null)
1007 var _atype: nullable MMType
1008 redef fun after_typing(v)
1009 do
1010 var otype = v.type_object
1011 var stype = v.type_string
1012 _stype = stype
1013 for e in n_exprs do v.check_conform_expr(e, otype)
1014 var atype = v.type_array(stype)
1015 _atype = atype
1016 _is_typed = true
1017 end
1018 end
1019
1020 redef class ANullExpr
1021 redef fun after_typing(v)
1022 do
1023 _stype = v.type_none
1024 _is_typed = true
1025 end
1026 end
1027
1028 redef class AArrayExpr
1029 redef fun after_typing(v)
1030 do
1031 var stype = v.check_conform_multiexpr(null, n_exprs)
1032 if stype != null then do_typing(v, stype)
1033 end
1034
1035 private fun do_typing(v: TypingVisitor, element_type: MMType)
1036 do
1037 _stype = v.type_array(element_type)
1038 _is_typed = true
1039 end
1040 end
1041
1042 redef class ARangeExpr
1043 redef fun after_typing(v)
1044 do
1045 if not v.check_expr(n_expr) or not v.check_expr(n_expr2) then return
1046 var ntype = n_expr.stype
1047 var ntype2 = n_expr2.stype
1048 if ntype < ntype2 then
1049 ntype = ntype2
1050 else if not ntype2 < ntype then
1051 v.error(self, "Type error: {ntype} incompatible with {ntype2}.")
1052 return
1053 end
1054 var dtype = v.type_discrete
1055 if not v.check_conform_expr(n_expr, dtype) or not v.check_conform_expr(n_expr2, dtype) then return
1056 _stype = v.type_range(ntype)
1057 _is_typed = true
1058 end
1059 end
1060
1061 redef class ASuperExpr
1062 redef readable var _init_in_superclass: nullable MMMethod
1063 redef fun compute_raw_arguments do return n_args.to_a
1064 redef fun after_typing(v)
1065 do
1066 var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters
1067 if not precs.is_empty then
1068 v.local_property.need_super = true
1069 else if v.local_property.global.is_init then
1070 var base_precs = v.local_class.super_methods_named(v.local_property.name)
1071 for p in base_precs do
1072 if not p.global.is_init then
1073 v.error(self, "Error: {p.local_class}::{p} is not a constructor.")
1074 else
1075 precs.add(v.local_class[p.global])
1076 end
1077 end
1078 if precs.is_empty then
1079 v.error(self, "Error: No contructor named {v.local_property.name} in superclasses.")
1080 return
1081 else if precs.length > 1 then
1082 v.error(self, "Error: Conflicting contructors named {v.local_property.name} in superclasses: {precs.join(", ")}.")
1083 return
1084 end
1085 var p = base_precs.first
1086 assert p isa MMMethod
1087 _init_in_superclass = p
1088 register_super_init_call(v, p)
1089 if n_args.length > 0 then
1090 var signature = get_signature(v, v.self_var.stype.as(not null), p, true)
1091 process_signature(v, signature, p.name, compute_raw_arguments)
1092 end
1093 else
1094 v.error(self, "Error: No super method to call for {v.local_property}.")
1095 return
1096 end
1097
1098 if precs.first.signature_for(v.self_var.stype.as(not null)).return_type != null then
1099 var stypes = new Array[MMType]
1100 var stype: nullable MMType = null
1101 for prop in precs do
1102 assert prop isa MMMethod
1103 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)
1104 stypes.add(t)
1105 if stype == null or stype < t then
1106 stype = t
1107 end
1108 end
1109 for t in stypes do
1110 v.check_conform(self, t, stype.as(not null))
1111 end
1112 _stype = stype
1113 end
1114 var p = v.local_property
1115 assert p isa MMSrcMethod
1116 _prop = p
1117 _is_typed = true
1118 end
1119 end
1120
1121 redef class AAttrFormExpr
1122 redef fun prop do return _prop.as(not null)
1123 var _prop: nullable MMAttribute
1124
1125 redef fun attr_type do return _attr_type.as(not null)
1126 var _attr_type: nullable MMType
1127
1128 # Compute the attribute accessed
1129 private fun do_typing(v: TypingVisitor)
1130 do
1131 if not v.check_expr(n_expr) then return
1132 var type_recv = n_expr.stype
1133 var name = n_id.to_symbol
1134 if type_recv isa MMTypeNone then
1135 v.error(self, "Error: Attribute '{name}' access on 'null'.")
1136 return
1137 end
1138 var lc = type_recv.local_class
1139 if not lc.has_global_property_by_name(name) then
1140 v.error(self, "Error: Attribute {name} doesn't exists in {type_recv}.")
1141 return
1142 end
1143 var prop = lc.select_attribute(name)
1144 if v.mmmodule.visibility_for(prop.global.local_class.mmmodule) < 3 then
1145 v.error(self, "Error: Attribute {name} from {prop.global.local_class.mmmodule} is invisible in {v.mmmodule}")
1146 end
1147 _prop = prop
1148 var at = prop.signature_for(type_recv).return_type
1149 if not n_expr.is_self then at = at.not_for_self
1150 _attr_type = at
1151 end
1152 end
1153
1154 redef class AAttrExpr
1155 redef fun after_typing(v)
1156 do
1157 do_typing(v)
1158 if _prop == null then return
1159 _stype = attr_type
1160 _is_typed = true
1161 end
1162 end
1163
1164 redef class AAttrAssignExpr
1165 redef fun after_typing(v)
1166 do
1167 do_typing(v)
1168 if _prop == null then return
1169 if not v.check_conform_expr(n_value, attr_type) then return
1170 _is_typed = true
1171 end
1172 end
1173
1174 redef class AAttrReassignExpr
1175 redef fun after_typing(v)
1176 do
1177 do_typing(v)
1178 if _prop == null then return
1179 var t = do_rvalue_typing(v, attr_type)
1180 if t == null then return
1181 v.check_conform(self, t, n_value.stype)
1182 _is_typed = true
1183 end
1184 end
1185
1186 redef class AIssetAttrExpr
1187 redef fun after_typing(v)
1188 do
1189 do_typing(v)
1190 if _prop == null then return
1191 if attr_type.is_nullable then
1192 v.error(self, "Error: isset on a nullable attribute.")
1193 end
1194 _stype = v.type_bool
1195 _is_typed = true
1196 end
1197 end
1198
1199 redef class AAbsAbsSendExpr
1200 # The signature of the called property
1201 redef fun prop_signature do return _prop_signature.as(not null)
1202 var _prop_signature: nullable MMSignature
1203
1204 # Raw arguments used (without vararg transformation)
1205 redef fun raw_arguments: Array[AExpr]
1206 do
1207 var res = _raw_arguments_cache
1208 if res != null then
1209 return res
1210 else
1211 res = compute_raw_arguments
1212 if res == null then res = new Array[AExpr]
1213 _raw_arguments_cache = res
1214 return res
1215 end
1216 end
1217
1218 var _raw_arguments_cache: nullable Array[AExpr] = null
1219
1220 fun compute_raw_arguments: nullable Array[AExpr]
1221 do
1222 print "{location} no compute_raw_arguments"
1223 return null
1224 end
1225
1226 # Check the conformity of a set of arguments `raw_args' to a signature.
1227 private fun process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: nullable Array[AExpr]): Bool
1228 do
1229 var par_vararg = psig.vararg_rank
1230 var par_arity = psig.arity
1231 var raw_arity: Int
1232 if raw_args == null then raw_arity = 0 else raw_arity = raw_args.length
1233 if par_arity > raw_arity or (par_arity != raw_arity and par_vararg == -1) then
1234 v.error(self, "Error: arity missmatch; prototype is '{name}{psig}'.")
1235 return false
1236 end
1237 var arg_idx = 0
1238 for par_idx in [0..par_arity[ do
1239 var a: AExpr
1240 var par_type = psig[par_idx]
1241 if par_idx == par_vararg then
1242 for i in [0..(raw_arity-par_arity)] do
1243 a = raw_args[arg_idx]
1244 v.check_conform_expr(a, par_type)
1245 arg_idx = arg_idx + 1
1246 end
1247 else
1248 a = raw_args[arg_idx]
1249 v.check_conform_expr(a, par_type)
1250 arg_idx = arg_idx + 1
1251 end
1252 end
1253 return true
1254 end
1255
1256 # Check the conformity of a set of defined closures
1257 private fun process_closures(v: TypingVisitor, psig: MMSignature, name: Symbol, cd: nullable Array[AClosureDef]): nullable MMType
1258 do
1259 var t = psig.return_type
1260 var cs = psig.closures # Declared closures
1261 var min_arity = 0
1262 for c in cs do
1263 if not c.is_optional then min_arity += 1
1264 end
1265 var arity = 0
1266 if cd != null then arity = cd.length
1267 if cs.length > 0 then
1268 if arity == 0 and min_arity > 0 then
1269 v.error(self, "Error: {name} requires {cs.length} blocks.")
1270 else if arity > cs.length or arity < min_arity then
1271 v.error(self, "Error: {name} requires {cs.length} blocks, {cd.length} found.")
1272 else
1273 # Initialize the break list if a value is required for breaks (ie. if the method is a function)
1274 var break_list: nullable Array[ABreakExpr] = null
1275 if t != null then break_list = new Array[ABreakExpr]
1276
1277 # The n_label, is any in only set on the last decl
1278 var n_label = if arity > 0 then cd[arity-1].n_label else null
1279
1280 # Process each closure definition
1281 for i in [0..arity[ do
1282 var cdi = cd[i]
1283 var cni = cdi.n_id.to_symbol
1284 var csi = psig.closure_named(cni)
1285 if csi != null then
1286 var esc = new EscapableClosure(cdi, csi, break_list)
1287 v.scope_ctx.push_escapable(esc, n_label)
1288 cdi.accept_typing2(v, esc)
1289 v.scope_ctx.pop
1290 else if cs.length == 1 then
1291 v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closure is !{cs.first.name}.")
1292 else
1293 var a = new Array[String]
1294 for c in cs do
1295 a.add("!{c.name}")
1296 end
1297 v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closures are {a.join(",")}.")
1298 end
1299 end
1300
1301 # Check break type conformity
1302 if break_list != null then
1303 t = v.check_conform_multiexpr(t, break_list)
1304 end
1305 end
1306 else if arity != 0 then
1307 v.error(self, "Error: {name} does not require blocks.")
1308 end
1309 return t
1310 end
1311 end
1312
1313 redef class AAbsSendExpr
1314 # Compute the called global property
1315 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])
1316 do
1317 var prop = get_property(v, type_recv, is_implicit_self, name)
1318 if prop == null then return
1319 var sig = get_signature(v, type_recv, prop, recv_is_self)
1320 if not process_signature(v, sig, prop.name, raw_args) then return
1321 var rtype = process_closures(v, sig, prop.name, closure_defs)
1322 if rtype == null and sig.return_type != null then return
1323 _prop = prop
1324 _prop_signature = sig
1325 _return_type = rtype
1326 end
1327
1328 private fun get_property(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, name: Symbol): nullable MMMethod
1329 do
1330 if type_recv isa MMTypeNone then
1331 if name == (once "==".to_symbol) or name == (once "!=".to_symbol) then
1332 # Special case on != and == that are allowed for 'null'
1333 type_recv = v.type_object.as_nullable
1334 else
1335 v.error(self, "Error: Method '{name}' call on 'null'.")
1336 return null
1337 end
1338 end
1339 var lc = type_recv.local_class
1340 var prop: nullable MMMethod = null
1341 if lc.has_global_property_by_name(name) then prop = lc.select_method(name)
1342 if prop == null and v.local_property.global.is_init then
1343 var props = lc.super_methods_named(name)
1344 if props.length > 1 then
1345 v.error(self, "Error: Ambigous method name '{name}' for {props.join(", ")}. Use explicit designation.")
1346 return null
1347 else if props.length == 1 then
1348 var p = lc[props.first.global]
1349 assert p isa MMMethod
1350 prop = p
1351 end
1352
1353 end
1354 if prop == null then
1355 if is_implicit_self then
1356 v.error(self, "Error: Method or variable '{name}' unknown in {type_recv}.")
1357 else
1358 v.error(self, "Error: Method '{name}' doesn't exists in {type_recv}.")
1359 end
1360 return null
1361 end
1362 return prop
1363 end
1364
1365 # Get the signature for a local property and a receiver
1366 private fun get_signature(v: TypingVisitor, type_recv: MMType, prop: MMMethod, recv_is_self: Bool): MMSignature
1367 do
1368 prop.global.check_visibility(v, self, v.mmmodule, recv_is_self)
1369 var psig = prop.signature_for(type_recv)
1370 if not recv_is_self then psig = psig.not_for_self
1371 return psig
1372 end
1373
1374 # The invoked method (once computed)
1375 redef fun prop do return _prop.as(not null)
1376 var _prop: nullable MMMethod
1377
1378 # The return type (if any) (once computed)
1379 redef readable var _return_type: nullable MMType
1380 end
1381
1382 # A possible call of constructor in a super class
1383 # Could be an explicit call or with the 'super' keyword
1384 redef class ASuperInitCall
1385 private fun register_super_init_call(v: TypingVisitor, property: MMMethod)
1386 do
1387 if parent != v.top_block and self != v.top_block then
1388 v.error(self, "Error: Constructor invocation {property} must not be in nested block.")
1389 end
1390 var cla = v.mmmodule[property.global.intro.local_class.global]
1391 var prev_class: nullable MMLocalClass = null
1392 var esic = v.explicit_super_init_calls.as(not null)
1393 if not esic.is_empty then
1394 prev_class = esic.last.global.intro.local_class
1395 end
1396 var order = v.local_class.cshe.reverse_linear_extension
1397 if cla == v.local_class then
1398 v.explicit_other_init_call = true
1399 else if not order.has(cla) then
1400 v.error(self, "Error: Constructor of class {cla} must be one in {order.join(", ")}.")
1401 else if cla == prev_class then
1402 v.error(self, "Error: Only one super constructor invocation of class {cla} is allowed.")
1403 else
1404 for c in order do
1405 if c == prev_class then
1406 prev_class = null
1407 else if c == cla then
1408 if prev_class != null then
1409 v.error(self, "Error: Constructor of {c} must be invoked before constructor of {prev_class}")
1410 end
1411 esic.add(property)
1412 break
1413 end
1414 end
1415 end
1416 end
1417
1418 end
1419
1420 redef class ANewExpr
1421 redef fun compute_raw_arguments do return n_args.to_a
1422 redef fun after_typing(v)
1423 do
1424 if not n_type.is_typed then return
1425 var t = n_type.stype
1426 if t.local_class.global.is_abstract then
1427 v.error(self, "Error: try to instantiate abstract class {t.local_class}.")
1428 return
1429 end
1430 var name: Symbol
1431 if n_id == null then
1432 name = once "init".to_symbol
1433 else
1434 name = n_id.to_symbol
1435 end
1436
1437 do_typing(v, t, false, false, name, raw_arguments, null)
1438 if _prop == null then return
1439
1440 if not prop.global.is_init then
1441 v.error(self, "Error: {prop} is not a constructor.")
1442 return
1443 end
1444 _stype = t
1445 _is_typed = true
1446 end
1447 end
1448
1449
1450 redef class ASendExpr
1451 # Name of the invoked property
1452 fun name: Symbol is abstract
1453
1454 # Closure definitions
1455 redef fun closure_defs: nullable Array[AClosureDef] do return null
1456
1457 redef fun after_typing(v)
1458 do
1459 do_all_typing(v)
1460 end
1461
1462 private fun do_all_typing(v: TypingVisitor)
1463 do
1464 if not v.check_expr(n_expr) then return
1465 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_arguments, closure_defs)
1466 if _prop == null then return
1467 var prop = _prop.as(not null)
1468
1469 if prop.global.is_init then
1470 if not v.local_property.global.is_init then
1471 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1472 else if not n_expr.is_self then
1473 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1474 else
1475 register_super_init_call(v, prop)
1476 end
1477 end
1478
1479 _stype = return_type
1480 _is_typed = true
1481 end
1482 end
1483
1484 redef class ASendReassignExpr
1485 redef fun read_prop do return _read_prop.as(not null)
1486 var _read_prop: nullable MMMethod
1487 redef fun do_all_typing(v)
1488 do
1489 if not v.check_expr(n_expr) then return
1490 var raw_args = raw_arguments
1491 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_args, null)
1492 var prop = _prop
1493 if prop == null then return
1494 if prop.global.is_init then
1495 if not v.local_property.global.is_init then
1496 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1497 else if not n_expr.is_self then
1498 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1499 end
1500 end
1501 var t = prop.signature_for(n_expr.stype).return_type.as(not null)
1502 if not n_expr.is_self then t = t.not_for_self
1503
1504 var t2 = do_rvalue_typing(v, t)
1505 if t2 == null then return
1506 v.check_conform(self, t2, n_value.stype)
1507
1508 _read_prop = prop
1509 raw_args = raw_args.to_a
1510 raw_args.add(n_value)
1511
1512 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, "{name}=".to_symbol, raw_args, null)
1513 if prop.global.is_init then
1514 if not v.local_property.global.is_init then
1515 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1516 else if not n_expr.is_self then
1517 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1518 end
1519 end
1520
1521 _is_typed = true
1522 end
1523 end
1524
1525 redef class ABinopExpr
1526 redef fun compute_raw_arguments do return [n_expr2]
1527 end
1528 redef class AEqExpr
1529 redef fun name do return once "==".to_symbol
1530 redef fun after_typing(v)
1531 do
1532 super
1533 if not n_expr.is_typed or not n_expr2.is_typed then return
1534 if n_expr.stype isa MMTypeNone and not n_expr2.stype.is_nullable or
1535 n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
1536 v.warning(self, "Warning: comparaison between null and a non nullable value.")
1537 end
1538
1539 if n_expr.stype isa MMTypeNone then
1540 if n_expr2.stype isa MMTypeNone then
1541 v.warning(self, "Warning: comparaison between 2 null values.")
1542 else
1543 try_to_isa(v, n_expr2)
1544 end
1545 else if n_expr2.stype isa MMTypeNone then
1546 try_to_isa(v, n_expr)
1547 end
1548 end
1549
1550 private fun try_to_isa(v: TypingVisitor, n: AExpr)
1551 do
1552 var variable = n.its_variable
1553 if variable != null and n.stype isa MMNullableType then
1554 _if_false_flow_ctx = v.flow_ctx.sub_with(self, variable, n.stype.as_notnull)
1555 _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, v.type_none)
1556 end
1557 end
1558 end
1559 redef class ANeExpr
1560 redef fun name do return once "!=".to_symbol
1561 redef fun after_typing(v)
1562 do
1563 super
1564 if not n_expr.is_typed or not n_expr2.is_typed then return
1565 if n_expr.stype isa MMTypeNone and not n_expr2.stype.is_nullable or
1566 n_expr2.stype isa MMTypeNone and not n_expr.stype.is_nullable then
1567 v.warning(self, "Warning: comparaison between null and a non nullable value.")
1568 end
1569
1570 if n_expr.stype isa MMTypeNone then
1571 if n_expr2.stype isa MMTypeNone then
1572 v.warning(self, "Warning: comparaison between 2 null values.")
1573 else
1574 try_to_isa(v, n_expr2)
1575 end
1576 else if n_expr2.stype isa MMTypeNone then
1577 try_to_isa(v, n_expr)
1578 end
1579 end
1580
1581 private fun try_to_isa(v: TypingVisitor, n: AExpr)
1582 do
1583 var variable = n.its_variable
1584 if variable != null and n.stype isa MMNullableType then
1585 _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, n.stype.as_notnull)
1586 _if_false_flow_ctx = v.flow_ctx.sub_with(self, variable, v.type_none)
1587 end
1588 end
1589 end
1590 redef class ALtExpr
1591 redef fun name do return once "<".to_symbol
1592 end
1593 redef class ALeExpr
1594 redef fun name do return once "<=".to_symbol
1595 end
1596 redef class ALlExpr
1597 redef fun name do return once "<<".to_symbol
1598 end
1599 redef class AGtExpr
1600 redef fun name do return once ">".to_symbol
1601 end
1602 redef class AGeExpr
1603 redef fun name do return once ">=".to_symbol
1604 end
1605 redef class AGgExpr
1606 redef fun name do return once ">>".to_symbol
1607 end
1608 redef class APlusExpr
1609 redef fun name do return once "+".to_symbol
1610 end
1611 redef class AMinusExpr
1612 redef fun name do return once "-".to_symbol
1613 end
1614 redef class AStarshipExpr
1615 redef fun name do return once "<=>".to_symbol
1616 end
1617 redef class AStarExpr
1618 redef fun name do return once "*".to_symbol
1619 end
1620 redef class ASlashExpr
1621 redef fun name do return once "/".to_symbol
1622 end
1623 redef class APercentExpr
1624 redef fun name do return once "%".to_symbol
1625 end
1626
1627 redef class AUminusExpr
1628 redef fun name do return once "unary -".to_symbol
1629 redef fun compute_raw_arguments do return null
1630 end
1631
1632 redef class ACallFormExpr
1633 redef fun after_typing(v)
1634 do
1635 if n_expr.is_implicit_self then
1636 var name = n_id.to_symbol
1637 var variable = v.scope_ctx[name]
1638 if variable != null then
1639 var n: AExpr
1640 if variable isa ClosureVariable then
1641 n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs)
1642 n._variable = variable
1643 else
1644 if not n_args.is_empty then
1645 v.error(self, "Error: {name} is variable, not a function.")
1646 return
1647 end
1648 n = variable_create(variable)
1649 n._variable = variable
1650 end
1651 replace_with(n)
1652 n.after_typing(v)
1653 return
1654 end
1655 end
1656
1657 super
1658 end
1659
1660 redef fun closure_defs
1661 do
1662 if n_closure_defs.is_empty then
1663 return null
1664 else
1665 return n_closure_defs.to_a
1666 end
1667 end
1668
1669 # Create a variable acces corresponding to the call form
1670 fun variable_create(variable: Variable): AVarFormExpr is abstract
1671 end
1672
1673 redef class ACallExpr
1674 redef fun variable_create(variable)
1675 do
1676 return new AVarExpr.init_avarexpr(n_id)
1677 end
1678
1679 redef fun name do return n_id.to_symbol
1680 redef fun compute_raw_arguments do return n_args.to_a
1681 end
1682
1683 redef class ACallAssignExpr
1684 redef fun variable_create(variable)
1685 do
1686 return new AVarAssignExpr.init_avarassignexpr(n_id, n_assign, n_value)
1687 end
1688
1689 redef fun name do return (n_id.text + "=").to_symbol
1690 redef fun compute_raw_arguments do
1691 var res = n_args.to_a
1692 res.add(n_value)
1693 return res
1694 end
1695 end
1696
1697 redef class ACallReassignExpr
1698 redef fun variable_create(variable)
1699 do
1700 return new AVarReassignExpr.init_avarreassignexpr(n_id, n_assign_op, n_value)
1701 end
1702
1703 redef fun name do return n_id.to_symbol
1704 redef fun compute_raw_arguments do return n_args.to_a
1705 end
1706
1707 redef class ABraExpr
1708 redef fun name do return once "[]".to_symbol
1709 redef fun compute_raw_arguments do return n_args.to_a
1710 redef fun closure_defs
1711 do
1712 if n_closure_defs.is_empty then
1713 return null
1714 else
1715 return n_closure_defs.to_a
1716 end
1717 end
1718 end
1719
1720 redef class ABraAssignExpr
1721 redef fun name do return once "[]=".to_symbol
1722 redef fun compute_raw_arguments do
1723 var res = n_args.to_a
1724 res.add(n_value)
1725 return res
1726 end
1727 end
1728
1729 redef class ABraReassignExpr
1730 redef fun name do return once "[]".to_symbol
1731 redef fun compute_raw_arguments do return n_args.to_a
1732 end
1733
1734 redef class AInitExpr
1735 redef fun name do return once "init".to_symbol
1736 redef fun compute_raw_arguments do return n_args.to_a
1737 end
1738
1739 redef class AClosureCallExpr
1740 var _variable: nullable ClosureVariable
1741 redef fun variable do return _variable.as(not null)
1742 redef fun compute_raw_arguments do return n_args.to_a
1743
1744 redef fun after_typing(v)
1745 do
1746 var va = variable
1747 if va.closure.is_break then v.mark_unreash(self)
1748 var sig = va.closure.signature
1749 var s = process_signature(v, sig, n_id.to_symbol, compute_raw_arguments)
1750 if not n_closure_defs.is_empty then
1751 process_closures(v, sig, n_id.to_symbol, n_closure_defs.to_a)
1752 end
1753 if not s then return
1754 _prop_signature = sig
1755 _stype = sig.return_type
1756 _is_typed = true
1757 end
1758 end
1759
1760 redef class AClosureId
1761 fun to_symbol: Symbol is abstract
1762 end
1763 redef class ASimpleClosureId
1764 redef fun to_symbol: Symbol do return n_id.to_symbol
1765 end
1766 redef class ABreakClosureId
1767 redef fun to_symbol: Symbol do return n_kwbreak.to_symbol
1768 end
1769
1770 redef class AClosureDef
1771 var _closure: nullable MMClosure
1772 redef fun closure do return _closure.as(not null)
1773
1774 # The corresponding escapable object
1775 readable var _escapable: nullable EscapableBlock
1776
1777 var _accept_typing2: Bool = false
1778 redef fun accept_typing(v)
1779 do
1780 # Typing is deferred, wait accept_typing2(v)
1781 if _accept_typing2 then super
1782 end
1783
1784 private fun accept_typing2(v: TypingVisitor, esc: EscapableClosure)
1785 do
1786 _escapable = esc
1787
1788 var sig = esc.closure.signature
1789 if sig.arity != n_ids.length then
1790 v.error(self, "Error: {sig.arity} automatic variable names expected, {n_ids.length} found.")
1791 return
1792 end
1793
1794 _closure = esc.closure
1795
1796 v.scope_ctx.push(self)
1797 var old_flow_ctx = v.flow_ctx
1798 var old_base_flow_ctx = v.base_flow_ctx
1799 v.base_flow_ctx = v.flow_ctx
1800 variables = new Array[AutoVariable]
1801 for i in [0..n_ids.length[ do
1802 var va = new AutoVariable(n_ids[i].to_symbol, n_ids[i])
1803 variables.add(va)
1804 va.stype = sig[i]
1805 v.scope_ctx.add_variable(va)
1806 end
1807
1808 _accept_typing2 = true
1809 accept_typing(v)
1810
1811 if v.flow_ctx.unreash == false then
1812 if closure.signature.return_type != null then
1813 v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
1814 else if closure.is_break and esc.break_list != null then
1815 v.error(self, "Control error: Reached end of break block (a 'break' with a value was expected).")
1816 end
1817 end
1818 v.flow_ctx = old_flow_ctx
1819 v.base_flow_ctx = old_base_flow_ctx
1820 v.scope_ctx.pop
1821 end
1822 end
1823
1824 class ATypeCheckExpr
1825 special AExpr
1826 private fun check_expr_cast(v: TypingVisitor, n_expr: AExpr, n_type: AType)
1827 do
1828 if not v.check_expr(n_expr) then return
1829 if not n_type.is_typed then return
1830 var etype = n_expr.stype
1831 var ttype = n_type.stype
1832 if etype == ttype then
1833 v.warning(self, "Warning: Expression is already a {ttype}.")
1834 else if etype < ttype then
1835 v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.")
1836 else if etype isa MMTypeNone then
1837 # ttype is not nullable because of prevous test
1838 v.warning(self, "Warning: Expression is null therefore cannot be a {ttype}.")
1839 else if etype.is_nullable and etype.as_notnull == ttype then
1840 if ttype isa MMTypeFormal and ttype.bound.is_nullable then
1841 # No warning in this case since with
1842 # type T: nullable A
1843 # var x: nullable T
1844 # 'x.as(not null)' != 'x.as(T)'
1845 # 'x != null' != 'x isa T'
1846 else if self isa AIsaExpr then
1847 v.warning(self, "Warning: Prefer '!= null'.")
1848 else
1849 v.warning(self, "Warning: Prefer '.as(not null)'.")
1850 end
1851 end
1852 end
1853 end
1854
1855 redef class AIsaExpr
1856 special ATypeCheckExpr
1857 redef fun after_typing(v)
1858 do
1859 check_expr_cast(v, n_expr, n_type)
1860 if not n_type.is_typed then return
1861 var variable = n_expr.its_variable
1862 if variable != null then
1863 _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, n_type.stype)
1864 end
1865 _stype = v.type_bool
1866 _is_typed = true
1867 end
1868 end
1869
1870 redef class AAsCastExpr
1871 special ATypeCheckExpr
1872 redef fun after_typing(v)
1873 do
1874 check_expr_cast(v, n_expr, n_type)
1875 if not n_type.is_typed then return
1876 _stype = n_type.stype
1877 _is_typed = _stype != null
1878 end
1879 end
1880
1881 redef class AAsNotnullExpr
1882 redef fun after_typing(v)
1883 do
1884 if not v.check_expr(n_expr) then return
1885 var t = n_expr.stype
1886 if t isa MMTypeNone then
1887 v.error(n_expr, "Type error: 'as(not null)' on 'null' value.")
1888 return
1889 else if not t.is_nullable then
1890 v.warning(n_expr, "Warning: 'as(not null)' on non nullable type.")
1891 end
1892 _stype = n_expr.stype.as_notnull
1893 _is_typed = true
1894 end
1895 end
1896
1897 redef class AProxyExpr
1898 redef fun after_typing(v)
1899 do
1900 if not n_expr.is_typed then return
1901 _is_typed = true
1902 if n_expr.is_statement then return
1903 _stype = n_expr.stype
1904 end
1905 end
1906
1907 redef class AOnceExpr
1908 redef fun accept_typing(v)
1909 do
1910 if v.once_count > 0 then
1911 v.warning(self, "Useless once in a once expression.")
1912 end
1913 v.once_count = v.once_count + 1
1914
1915 super
1916
1917 v.once_count = v.once_count - 1
1918 end
1919 end
1920