syntax: variable with () is not a variable
[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 escape
22
23 redef class MMSrcModule
24 # Walk trough the module and type statments and expressions
25 # Require than supermodules are processed
26 meth do_typing(tc: ToolContext)
27 do
28 var tv = new TypingVisitor(tc, self)
29 tv.visit(node)
30 end
31 end
32
33 # Typing visitor
34 # * Associate local variables to nodes
35 # * Distinguish method call and local variable access
36 # * Resolve call and attribute access
37 # * Check type conformance
38 private class TypingVisitor
39 special AbsSyntaxVisitor
40 redef meth visit(n)
41 do
42 if n != null then n.accept_typing(self)
43 end
44
45 # Current knowledge about variables names and types
46 readable writable attr _variable_ctx: VariableContext
47
48 # Current knowledge about escapable blocks
49 readable writable attr _escapable_ctx: EscapableContext = new EscapableContext(self)
50
51 # The current reciever
52 readable writable attr _self_var: ParamVariable
53
54 # Block of the current method
55 readable writable attr _top_block: PExpr
56
57 # List of explicit invocation of constructors of super-classes
58 readable writable attr _explicit_super_init_calls: Array[MMMethod]
59
60 # Is a other constructor of the same class invoked
61 readable writable attr _explicit_other_init_call: Bool
62
63 # Make the if_true_variable_ctx of the expression effective
64 private meth use_if_true_variable_ctx(e: PExpr)
65 do
66 var ctx = e.if_true_variable_ctx
67 if ctx != null then
68 variable_ctx = ctx
69 end
70 end
71
72 init(tc, module) do super
73
74 private meth get_default_constructor_for(n: PNode, c: MMLocalClass, prop: MMSrcMethod): MMMethod
75 do
76 var v = self
77 #var prop = v.local_property
78 #assert prop isa MMMethod
79 var candidates = new Array[MMMethod]
80 var false_candidates = new Array[MMMethod]
81 var parity = prop.signature.arity
82 for g in c.global_properties do
83 if not g.is_init_for(c) then continue
84 var gp = c[g]
85 var gps = gp.signature_for(c.get_type)
86 assert gp isa MMSrcMethod
87 var garity = gps.arity
88 if prop != null and gp.name == prop.name then
89 if garity == 0 or (parity == garity and prop.signature < gps) then
90 return gp
91 else
92 false_candidates.add(gp)
93 end
94 else if garity == 0 and gp.name == once ("init".to_symbol) then
95 candidates.add(gp)
96 false_candidates.add(gp)
97 else
98 false_candidates.add(gp)
99 end
100 end
101 if candidates.length == 1 then
102 return candidates.first
103 else if candidates.length > 0 then
104 var a = new Array[String]
105 for p in candidates do
106 a.add("{p.full_name}{p.signature}")
107 end
108 v.error(n, "Error: Conflicting default constructor to call for {c}: {a.join(", ")}.")
109 return null
110 else if false_candidates.length > 0 then
111 var a = new Array[String]
112 for p in false_candidates do
113 a.add("{p.full_name}{p.signature}")
114 end
115 v.error(n, "Error: there is no available compatible constrctor in {c}. Discarded candidates are {a.join(", ")}.")
116 return null
117 else
118 v.error(n, "Error: there is no available compatible constrctor in {c}.")
119 return null
120 end
121 end
122 end
123
124 # Associate symbols to variable and variables to type
125 # Can be nested
126 abstract class VariableContext
127 # Look for the variable from its name
128 # Return null if nothing found
129 meth [](s: Symbol): Variable
130 do
131 if _dico.has_key(s) then
132 return _dico[s]
133 else
134 return null
135 end
136 end
137
138 # Register a new variable with its name
139 meth add(v: Variable)
140 do
141 _dico[v.name] = v
142 end
143
144 # The effective static type of a given variable
145 # May be different from the declaration static type
146 meth stype(v: Variable): MMType
147 do
148 return v.stype
149 end
150
151 # Variables by name (in the current context only)
152 attr _dico: Map[Symbol, Variable]
153
154 # Build a new VariableContext
155 meth sub(node: PNode): SubVariableContext
156 do
157 return new SubVariableContext.with_prev(self, node)
158 end
159
160 # Build a nested VariableContext with new variable information
161 meth sub_with(node: PNode, v: Variable, t: MMType): SubVariableContext
162 do
163 return new CastVariableContext.with_prev(self, node, v, t)
164 end
165
166 # The visitor of the context (used to display error)
167 attr _visitor: AbsSyntaxVisitor
168
169 # The syntax node that introduced the context
170 readable attr _node: PNode
171
172 init(visitor: AbsSyntaxVisitor, node: PNode)
173 do
174 _visitor = visitor
175 _node = node
176 _dico = new HashMap[Symbol, Variable]
177 end
178 end
179
180 class RootVariableContext
181 special VariableContext
182 init(visitor: AbsSyntaxVisitor, node: PNode)
183 do
184 super(visitor, node)
185 end
186 end
187
188 class SubVariableContext
189 special VariableContext
190 readable attr _prev: VariableContext
191
192 redef meth [](s)
193 do
194 if _dico.has_key(s) then
195 return _dico[s]
196 else
197 return prev[s]
198 end
199 end
200
201 redef meth stype(v)
202 do
203 return prev.stype(v)
204 end
205
206 init with_prev(p: VariableContext, node: PNode)
207 do
208 init(p._visitor, node)
209 _prev = p
210 end
211 end
212
213 class CastVariableContext
214 special SubVariableContext
215 attr _variable: Variable
216 attr _var_type: MMType
217
218 redef meth stype(v)
219 do
220 if _variable == v then
221 return _var_type
222 end
223 return prev.stype(v)
224 end
225
226 init with_prev(p: VariableContext, node: PNode, v: Variable, t: MMType)
227 do
228 super(p, node)
229 _variable = v
230 _var_type =t
231 end
232 end
233
234 ###############################################################################
235
236 redef class PNode
237 private meth accept_typing(v: TypingVisitor)
238 do
239 accept_abs_syntax_visitor(v)
240 after_typing(v)
241 end
242 private meth after_typing(v: TypingVisitor) do end
243 end
244
245 redef class PClassdef
246 redef meth accept_typing(v)
247 do
248 v.self_var = new ParamVariable("self".to_symbol, self)
249 v.self_var.stype = local_class.get_type
250 super
251 end
252 end
253
254 redef class AAttrPropdef
255 redef meth accept_typing(v)
256 do
257 super
258 if n_expr != null then
259 v.check_conform_expr(n_expr, prop.signature.return_type)
260 end
261 end
262 end
263
264 redef class AMethPropdef
265 redef readable attr _self_var: ParamVariable
266 redef meth accept_typing(v)
267 do
268 v.variable_ctx = new RootVariableContext(v, self)
269 _self_var = v.self_var
270 super
271 end
272 end
273
274 redef class AConcreteInitPropdef
275 readable attr _super_init_calls: Array[MMMethod] = new Array[MMMethod]
276 readable attr _explicit_super_init_calls: Array[MMMethod] = new Array[MMMethod]
277 redef meth accept_typing(v)
278 do
279 v.top_block = n_block
280 v.explicit_super_init_calls = explicit_super_init_calls
281 v.explicit_other_init_call = false
282 super
283 if v.explicit_other_init_call or method.global.intro != method then
284 # TODO: something?
285 else
286 var i = 0
287 var l = explicit_super_init_calls.length
288 var cur_m: MMMethod = null
289 var cur_c: MMLocalClass = null
290 if i < l then
291 cur_m = explicit_super_init_calls[i]
292 cur_c = cur_m.global.intro.local_class.for_module(v.module)
293 end
294 var j = 0
295 while j < v.local_class.cshe.direct_greaters.length do
296 var c = v.local_class.cshe.direct_greaters[j]
297 if c.global.is_interface or c.global.is_universal or c.global.is_mixin then
298 j += 1
299 else if cur_c != null and (c.cshe <= cur_c or cur_c.global.is_mixin) then
300 if c == cur_c then j += 1
301 super_init_calls.add(cur_m)
302 i += 1
303 if i < l then
304 cur_m = explicit_super_init_calls[i]
305 cur_c = cur_m.global.intro.local_class.for_module(v.module)
306 else
307 cur_m = null
308 cur_c = null
309 end
310 else
311 var p = v.get_default_constructor_for(self, c, method)
312 if p != null then
313 super_init_calls.add(p)
314 end
315 j += 1
316 end
317 end
318 end
319 end
320 end
321
322 redef class PParam
323 redef meth after_typing(v)
324 do
325 # TODO: why the test?
326 if v.variable_ctx != null then
327 v.variable_ctx.add(variable)
328 end
329 end
330 end
331
332 redef class AClosureDecl
333 # The corresponding escapable object
334 readable attr _escapable: EscapableBlock
335
336 redef meth accept_typing(v)
337 do
338 # Register the closure for ClosureCallExpr
339 v.variable_ctx.add(variable)
340
341 var old_var_ctx = v.variable_ctx
342 v.variable_ctx = v.variable_ctx.sub(self)
343
344 _escapable = new EscapableClosure(self, variable.closure, null)
345 v.escapable_ctx.push(_escapable)
346
347 super
348
349 v.variable_ctx = old_var_ctx
350 v.escapable_ctx.pop
351 end
352 end
353
354 redef class PType
355 readable attr _stype: MMType
356 redef meth after_typing(v)
357 do
358 _stype = get_stype(v)
359 end
360 end
361
362 redef class PExpr
363 redef readable attr _is_typed: Bool = false
364 redef meth is_statement: Bool do return _stype == null
365 redef meth stype
366 do
367 if not is_typed then
368 print "{locate}: not is_typed"
369 abort
370 end
371 if is_statement then
372 print "{locate}: is_statement"
373 abort
374 end
375 return _stype
376 end
377 attr _stype: MMType
378
379 # Is the expression the implicit receiver
380 meth is_implicit_self: Bool do return false
381
382 # Is the expression the current receiver (implicit or explicit)
383 meth is_self: Bool do return false
384
385 # The variable accessed is any
386 meth its_variable: Variable do return null
387
388 # The variable type information if current boolean expression is true
389 readable private attr _if_true_variable_ctx: VariableContext
390 end
391
392 redef class AVardeclExpr
393 redef meth after_typing(v)
394 do
395 var va = new VarVariable(n_id.to_symbol, self)
396 variable = va
397 v.variable_ctx.add(va)
398
399 if n_type != null then
400 va.stype = n_type.stype
401 if n_expr != null then
402 v.check_conform_expr(n_expr, va.stype)
403 end
404 else
405 if not v.check_expr(n_expr) then return
406 va.stype = n_expr.stype
407 end
408 _is_typed = true
409 end
410 end
411
412 redef class ABlockExpr
413 redef meth accept_typing(v)
414 do
415 var old_var_ctx = v.variable_ctx
416 v.variable_ctx = v.variable_ctx.sub(self)
417
418 super
419
420 v.variable_ctx = old_var_ctx
421 _is_typed = true
422 end
423 end
424
425 redef class AReturnExpr
426 redef meth after_typing(v)
427 do
428 var t = v.local_property.signature.return_type
429 if n_expr == null and t != null then
430 v.error(self, "Error: Return without value in a function.")
431 else if n_expr != null and t == null then
432 v.error(self, "Error: Return with value in a procedure.")
433 else if n_expr != null and t != null then
434 v.check_conform_expr(n_expr, t)
435 end
436 _is_typed = true
437 end
438 end
439
440 redef class AContinueExpr
441 redef meth after_typing(v)
442 do
443 var esc = compute_escapable_block(v.escapable_ctx)
444 if esc == null then return
445
446 if esc.is_break_block then
447 v.error(self, "Error: 'continue' forbiden in break blocks.")
448 return
449 end
450
451 var t = esc.continue_stype
452 if n_expr == null and t != null then
453 v.error(self, "Error: continue with a value required in this block.")
454 else if n_expr != null and t == null then
455 v.error(self, "Error: continue without value required in this block.")
456 else if n_expr != null and t != null then
457 v.check_conform_expr(n_expr, t)
458 end
459 _is_typed = true
460 end
461 end
462
463 redef class ABreakExpr
464 redef meth after_typing(v)
465 do
466 var esc = compute_escapable_block(v.escapable_ctx)
467 if esc == null then return
468
469 var bl = esc.break_list
470 if n_expr == null and bl != null then
471 v.error(self, "Error: break with a value required in this block.")
472 else if n_expr != null and bl == null then
473 v.error(self, "Error: break without value required in this block.")
474 else if n_expr != null and bl != null then
475 # Typing check can only be done later
476 bl.add(n_expr)
477 end
478 _is_typed = true
479 end
480 end
481
482 redef class AIfExpr
483 redef meth accept_typing(v)
484 do
485 var old_var_ctx = v.variable_ctx
486 v.visit(n_expr)
487 v.check_conform_expr(n_expr, v.type_bool)
488
489 v.use_if_true_variable_ctx(n_expr)
490
491 v.visit(n_then)
492 # Restore variable ctx
493 v.variable_ctx = old_var_ctx
494
495 if n_else != null then
496 v.visit(n_else)
497 v.variable_ctx = old_var_ctx
498 end
499 _is_typed = true
500 end
501 end
502
503 redef class AWhileExpr
504 # The corresponding escapable block
505 readable attr _escapable: EscapableBlock
506
507 redef meth accept_typing(v)
508 do
509 _escapable = new EscapableBlock(self)
510 v.escapable_ctx.push(_escapable)
511 var old_var_ctx = v.variable_ctx
512 v.variable_ctx = v.variable_ctx.sub(self)
513
514 super
515
516 v.check_conform_expr(n_expr, v.type_bool)
517 v.variable_ctx = old_var_ctx
518 v.escapable_ctx.pop
519 _is_typed = true
520 end
521 end
522
523 redef class AForExpr
524 # The corresponding escapable block
525 readable attr _escapable: EscapableBlock
526
527 readable attr _meth_iterator: MMMethod
528 readable attr _meth_is_ok: MMMethod
529 readable attr _meth_item: MMMethod
530 readable attr _meth_next: MMMethod
531 redef meth accept_typing(v)
532 do
533 _escapable = new EscapableBlock(self)
534 v.escapable_ctx.push(_escapable)
535
536 var old_var_ctx = v.variable_ctx
537 v.variable_ctx = v.variable_ctx.sub(self)
538 var va = new AutoVariable(n_id.to_symbol, self)
539 variable = va
540 v.variable_ctx.add(va)
541
542 v.visit(n_expr)
543
544 if not v.check_conform_expr(n_expr, v.type_collection) then return
545 var expr_type = n_expr.stype
546 _meth_iterator = expr_type.local_class.select_method(once ("iterator".to_symbol))
547 if _meth_iterator == null then
548 v.error(self, "Error: Collection MUST have an iterate method")
549 return
550 end
551 var iter_type = _meth_iterator.signature_for(expr_type).return_type
552 _meth_is_ok = iter_type.local_class.select_method(once ("is_ok".to_symbol))
553 if _meth_is_ok == null then
554 v.error(self, "Error: {iter_type} MUST have an is_ok method")
555 return
556 end
557 _meth_item = iter_type.local_class.select_method(once ("item".to_symbol))
558 if _meth_item == null then
559 v.error(self, "Error: {iter_type} MUST have an item method")
560 return
561 end
562 _meth_next = iter_type.local_class.select_method(once ("next".to_symbol))
563 if _meth_next == null then
564 v.error(self, "Error: {iter_type} MUST have a next method")
565 return
566 end
567 var t = _meth_item.signature_for(iter_type).return_type
568 if not n_expr.is_self then t = t.not_for_self
569 va.stype = t
570
571 if n_block != null then v.visit(n_block)
572
573 # pop context
574 v.variable_ctx = old_var_ctx
575 v.escapable_ctx.pop
576 _is_typed = true
577 end
578 end
579
580 redef class AAssertExpr
581 redef meth after_typing(v)
582 do
583 v.check_conform_expr(n_expr, v.type_bool)
584 v.use_if_true_variable_ctx(n_expr)
585 _is_typed = true
586 end
587 end
588
589 redef class AVarExpr
590 redef meth its_variable do return variable
591
592 redef meth after_typing(v)
593 do
594 _stype = v.variable_ctx.stype(variable)
595 _is_typed = _stype != null
596 end
597 end
598
599 redef class AVarAssignExpr
600 redef meth after_typing(v)
601 do
602 var t = v.variable_ctx.stype(variable)
603 v.check_conform_expr(n_value, t)
604 _is_typed = true
605 end
606 end
607
608 redef class AReassignFormExpr
609 # Compute and check method used through the reassigment operator
610 private meth do_lvalue_typing(v: TypingVisitor, type_lvalue: MMType)
611 do
612 if type_lvalue == null then
613 return
614 end
615 var name = n_assign_op.method_name
616 var lc = type_lvalue.local_class
617 if not lc.has_global_property_by_name(name) then
618 v.error(self, "Error: Method '{name}' doesn't exists in {type_lvalue}.")
619 return
620 end
621 var prop = lc.select_method(name)
622 prop.global.check_visibility(v, self, v.module, false)
623 var psig = prop.signature_for(type_lvalue)
624 _assign_method = prop
625 if not v.check_conform_expr(n_value, psig[0].not_for_self) then return
626 if not v.check_conform(self, psig.return_type.not_for_self, n_value.stype) then return
627 end
628
629 # Method used through the reassigment operator (once computed)
630 readable attr _assign_method: MMMethod
631 end
632
633 redef class AVarReassignExpr
634 redef meth after_typing(v)
635 do
636 var t = v.variable_ctx.stype(variable)
637 do_lvalue_typing(v, t)
638 _is_typed = true
639 end
640 end
641
642 redef class PAssignOp
643 meth method_name: Symbol is abstract
644 end
645 redef class APlusAssignOp
646 redef meth method_name do return once "+".to_symbol
647 end
648 redef class AMinusAssignOp
649 redef meth method_name do return once "-".to_symbol
650 end
651
652 redef class ASelfExpr
653 redef meth its_variable do return variable
654
655 redef meth after_typing(v)
656 do
657 variable = v.self_var
658 _stype = v.variable_ctx.stype(variable)
659 _is_typed = true
660 end
661
662 redef meth is_self do return true
663 end
664
665 redef class AImplicitSelfExpr
666 redef meth is_implicit_self do return true
667 end
668
669 redef class AIfexprExpr
670 redef meth accept_typing(v)
671 do
672 var old_var_ctx = v.variable_ctx
673
674 v.visit(n_expr)
675 v.use_if_true_variable_ctx(n_expr)
676 v.visit(n_then)
677 v.variable_ctx = old_var_ctx
678 v.visit(n_else)
679
680 v.check_conform_expr(n_expr, v.type_bool)
681
682 _stype = v.check_conform_multiexpr(null, [n_then, n_else])
683 _is_typed = _stype != null
684 end
685 end
686
687 redef class ABoolExpr
688 redef meth after_typing(v)
689 do
690 _stype = v.type_bool
691 _is_typed = true
692 end
693 end
694
695 redef class AOrExpr
696 redef meth after_typing(v)
697 do
698 v.check_conform_expr(n_expr, v.type_bool)
699 v.check_conform_expr(n_expr2, v.type_bool)
700 _stype = v.type_bool
701 _is_typed = true
702 end
703 end
704
705 redef class AAndExpr
706 redef meth accept_typing(v)
707 do
708 var old_var_ctx = v.variable_ctx
709
710 v.visit(n_expr)
711 v.use_if_true_variable_ctx(n_expr)
712
713 v.visit(n_expr2)
714 if n_expr2.if_true_variable_ctx != null then
715 _if_true_variable_ctx = n_expr2.if_true_variable_ctx
716 else
717 _if_true_variable_ctx = v.variable_ctx
718 end
719
720 v.variable_ctx = old_var_ctx
721
722 v.check_conform_expr(n_expr, v.type_bool)
723 v.check_conform_expr(n_expr2, v.type_bool)
724 _stype = v.type_bool
725 _is_typed = true
726 end
727 end
728
729 redef class ANotExpr
730 redef meth after_typing(v)
731 do
732 v.check_conform_expr(n_expr, v.type_bool)
733 _stype = v.type_bool
734 _is_typed = true
735 end
736 end
737
738 redef class AIntExpr
739 redef meth after_typing(v)
740 do
741 _stype = v.type_int
742 _is_typed = true
743 end
744 end
745
746 redef class AFloatExpr
747 redef meth after_typing(v)
748 do
749 _stype = v.type_float
750 _is_typed = true
751 end
752 end
753
754 redef class ACharExpr
755 redef meth after_typing(v)
756 do
757 _stype = v.type_char
758 _is_typed = true
759 end
760 end
761
762 redef class AStringFormExpr
763 readable attr _meth_with_native: MMMethod
764 redef meth after_typing(v)
765 do
766 _stype = v.type_string
767 _is_typed = true
768 _meth_with_native = _stype.local_class.select_method(once "with_native".to_symbol)
769 if _meth_with_native == null then v.error(self, "{_stype} MUST have a with_native method.")
770 end
771 end
772
773 redef class ASuperstringExpr
774 readable attr _meth_with_capacity: MMMethod
775 readable attr _meth_add: MMMethod
776 readable attr _meth_to_s: MMMethod
777 readable attr _atype: MMType
778 redef meth after_typing(v)
779 do
780 _stype = v.type_string
781 _atype = v.type_array(_stype)
782 _meth_with_capacity = _atype.local_class.select_method(once "with_capacity".to_symbol)
783 if _meth_with_capacity == null then v.error(self, "{_atype} MUST have a with_capacity method.")
784 _meth_add = _atype.local_class.select_method(once "add".to_symbol)
785 if _meth_add == null then v.error(self, "{_atype} MUST have an add method.")
786 _meth_to_s = v.type_object.local_class.select_method(once "to_s".to_symbol)
787 if _meth_to_s == null then v.error(self, "Object MUST have a to_s method.")
788 _is_typed = true
789 end
790 end
791
792 redef class ANullExpr
793 redef meth after_typing(v)
794 do
795 _stype = v.type_none
796 _is_typed = true
797 end
798 end
799
800 redef class AArrayExpr
801 readable attr _meth_with_capacity: MMMethod
802 readable attr _meth_add: MMMethod
803
804 redef meth after_typing(v)
805 do
806 var stype = v.check_conform_multiexpr(null, n_exprs)
807 if stype == null then return
808 do_typing(v, stype)
809 end
810
811 private meth do_typing(v: TypingVisitor, element_type: MMType)
812 do
813 _stype = v.type_array(element_type)
814
815 _meth_with_capacity = _stype.local_class.select_method(once "with_capacity".to_symbol)
816 if _meth_with_capacity == null then v.error(self, "{_stype} MUST have a with_capacity method.")
817 _meth_add = _stype.local_class.select_method(once "add".to_symbol)
818 if _meth_add == null then v.error(self, "{_stype} MUST have an add method.")
819
820 _is_typed = true
821 end
822 end
823
824 redef class ARangeExpr
825 readable attr _meth_init: MMMethod
826 redef meth after_typing(v)
827 do
828 if not v.check_expr(n_expr) or not v.check_expr(n_expr2) then return
829 var ntype = n_expr.stype
830 var ntype2 = n_expr2.stype
831 if ntype < ntype2 then
832 ntype = ntype2
833 else if not ntype2 < ntype then
834 v.error(self, "Type error: {ntype} incompatible with {ntype2}.")
835 return
836 end
837 var dtype = v.type_discrete
838 if not v.check_conform_expr(n_expr, dtype) or not v.check_conform_expr(n_expr2, dtype) then return
839 _stype = v.type_range(ntype)
840 _is_typed = true
841 end
842 end
843
844 redef class ACrangeExpr
845 redef meth after_typing(v)
846 do
847 super
848 _meth_init = stype.local_class.select_method(once "init".to_symbol)
849 end
850 end
851 redef class AOrangeExpr
852 redef meth after_typing(v)
853 do
854 super
855 _meth_init = stype.local_class.select_method(once "without_last".to_symbol)
856 end
857 end
858
859
860 redef class ASuperExpr
861 special ASuperInitCall
862 # readable attr _prop: MMSrcMethod
863 readable attr _init_in_superclass: MMMethod
864 redef meth after_typing(v)
865 do
866 var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters
867 if not precs.is_empty then
868 v.local_property.need_super = true
869 else if v.local_property.global.is_init then
870 var base_precs = v.local_class.super_methods_named(v.local_property.name)
871 for p in base_precs do
872 if not p.global.is_init then
873 v.error(self, "Error: {p.local_class}::{p} is not a constructor.")
874 else
875 precs.add(v.local_class[p.global])
876 end
877 end
878 if precs.is_empty then
879 v.error(self, "Error: No contructor named {v.local_property.name} in superclasses.")
880 return
881 else if precs.length > 1 then
882 v.error(self, "Error: Conflicting contructors named {v.local_property.name} in superclasses: {precs.join(", ")}.")
883 return
884 end
885 var p = base_precs.first
886 assert p isa MMMethod
887 _init_in_superclass = p
888 register_super_init_call(v, p)
889 if n_args.length > 0 then
890 var signature = get_signature(v, v.self_var.stype, p, true)
891 _arguments = process_signature(v, signature, p.name, n_args.to_a)
892 end
893 else
894 v.error(self, "Error: No super method to call for {v.local_property}.")
895 return
896 end
897
898 if precs.first.signature_for(v.self_var.stype).return_type != null then
899 var stypes = new Array[MMType]
900 var stype: MMType = null
901 for prop in precs do
902 assert prop isa MMMethod
903 var t = prop.signature_for(v.self_var.stype).return_type.for_module(v.module).adapt_to(v.local_property.signature.recv)
904 stypes.add(t)
905 if stype == null or stype < t then
906 stype = t
907 end
908 end
909 for t in stypes do
910 v.check_conform(self, t, stype)
911 end
912 _stype = stype
913 end
914 var p = v.local_property
915 assert p isa MMSrcMethod
916 _prop = p
917 _is_typed = true
918 end
919 end
920
921 redef class AAttrFormExpr
922 # Attribute accessed
923 readable attr _prop: MMAttribute
924
925 # Attribute type of the acceded attribute
926 readable attr _attr_type: MMType
927
928 # Compute the attribute accessed
929 private meth do_typing(v: TypingVisitor)
930 do
931 if not v.check_expr(n_expr) then return
932 var type_recv = n_expr.stype
933 var name = n_id.to_symbol
934 var lc = type_recv.local_class
935 if not lc.has_global_property_by_name(name) then
936 v.error(self, "Error: Attribute {name} doesn't exists in {type_recv}.")
937 return
938 end
939 var prop = lc.select_attribute(name)
940 if v.module.visibility_for(prop.global.local_class.module) < 3 then
941 v.error(self, "Error: Attribute {name} from {prop.global.local_class.module} is invisible in {v.module}")
942 end
943 _prop = prop
944 var at = prop.signature_for(type_recv).return_type
945 if not n_expr.is_self then at = at.not_for_self
946 _attr_type = at
947 end
948 end
949
950 redef class AAttrExpr
951 redef meth after_typing(v)
952 do
953 do_typing(v)
954 if prop == null then return
955 _stype = attr_type
956 _is_typed = true
957 end
958 end
959
960 redef class AAttrAssignExpr
961 redef meth after_typing(v)
962 do
963 do_typing(v)
964 if prop == null then return
965 if not v.check_conform_expr(n_value, attr_type) then return
966 _is_typed = true
967 end
968 end
969
970 redef class AAttrReassignExpr
971 redef meth after_typing(v)
972 do
973 do_typing(v)
974 if prop == null then return
975 do_lvalue_typing(v, attr_type)
976 _is_typed = true
977 end
978 end
979
980 class AAbsAbsSendExpr
981 special PExpr
982 # The signature of the called property
983 readable attr _prop_signature: MMSignature
984
985 # The real arguments used (after star transformation) (once computed)
986 readable attr _arguments: Array[PExpr]
987
988 # Check the conformity of a set of arguments `raw_args' to a signature.
989 private meth process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: Array[PExpr]): Array[PExpr]
990 do
991 var par_vararg = psig.vararg_rank
992 var par_arity = psig.arity
993 var raw_arity: Int
994 if raw_args == null then raw_arity = 0 else raw_arity = raw_args.length
995 if par_arity > raw_arity or (par_arity != raw_arity and par_vararg == -1) then
996 v.error(self, "Error: '{name}' arity missmatch.")
997 return null
998 end
999 var arg_idx = 0
1000 var args = new Array[PExpr]
1001 for par_idx in [0..par_arity[ do
1002 var a: PExpr
1003 var par_type = psig[par_idx]
1004 if par_idx == par_vararg then
1005 var star = new Array[PExpr]
1006 for i in [0..(raw_arity-par_arity)] do
1007 a = raw_args[arg_idx]
1008 v.check_conform_expr(a, par_type)
1009 star.add(a)
1010 arg_idx = arg_idx + 1
1011 end
1012 var aa = new AArrayExpr.init_aarrayexpr(star)
1013 aa.do_typing(v, par_type)
1014 a = aa
1015 else
1016 a = raw_args[arg_idx]
1017 v.check_conform_expr(a, par_type)
1018 arg_idx = arg_idx + 1
1019 end
1020 args.add(a)
1021 end
1022 return args
1023 end
1024
1025 # Check the conformity of a set of defined closures
1026 private meth process_closures(v: TypingVisitor, psig: MMSignature, name: Symbol, cd: Array[PClosureDef]): MMType
1027 do
1028 var t = psig.return_type
1029 var cs = psig.closures # Declared closures
1030 var min_arity = 0
1031 for c in cs do
1032 if not c.is_optional then min_arity += 1
1033 end
1034 if cd != null then
1035 if cs.length == 0 then
1036 v.error(self, "Error: {name} does not require blocks.")
1037 else if cd.length > cs.length or cd.length < min_arity then
1038 v.error(self, "Error: {name} requires {cs.length} blocks, {cd.length} found.")
1039 else
1040 # Initialize the break list if a value is required for breaks (ie. if the method is a function)
1041 var break_list: Array[ABreakExpr] = null
1042 if t != null then break_list = new Array[ABreakExpr]
1043
1044 # Process each closure definition
1045 for i in [0..cd.length[ do
1046 var csi = cs[i]
1047 var cdi = cd[i]
1048 var esc = new EscapableClosure(cdi, csi, break_list)
1049 v.escapable_ctx.push(esc)
1050 cdi.accept_typing2(v, esc)
1051 v.escapable_ctx.pop
1052 end
1053
1054 # Check break type conformity
1055 if break_list != null then
1056 t = v.check_conform_multiexpr(t, break_list)
1057 end
1058 end
1059 else if min_arity != 0 then
1060 v.error(self, "Error: {name} requires {cs.length} blocks.")
1061 end
1062 return t
1063 end
1064 end
1065
1066 class AAbsSendExpr
1067 special AAbsAbsSendExpr
1068 # Compute the called global property
1069 private meth do_typing(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, recv_is_self: Bool, name: Symbol, raw_args: Array[PExpr], closure_defs: Array[PClosureDef])
1070 do
1071 var prop = get_property(v, type_recv, is_implicit_self, name)
1072 if prop == null then return
1073 var sig = get_signature(v, type_recv, prop, recv_is_self)
1074 if sig == null then return
1075 var args = process_signature(v, sig, prop.name, raw_args)
1076 if args == null then return
1077 var rtype = process_closures(v, sig, prop.name, closure_defs)
1078 if rtype == null and sig.return_type != null then return
1079 _prop = prop
1080 _prop_signature = sig
1081 _arguments = args
1082 _return_type = rtype
1083 end
1084
1085 private meth get_property(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, name: Symbol): MMMethod
1086 do
1087 if type_recv == null then return null
1088 var lc = type_recv.local_class
1089 var prop: MMMethod = null
1090 if lc.has_global_property_by_name(name) then prop = lc.select_method(name)
1091 if prop == null and v.local_property.global.is_init then
1092 var props = type_recv.local_class.super_methods_named(name)
1093 if props.length > 1 then
1094 v.error(self, "Error: Ambigous method name '{name}' for {props.join(", ")}. Use explicit designation.")
1095 return null
1096 else if props.length == 1 then
1097 var p = type_recv.local_class[props.first.global]
1098 assert p isa MMMethod
1099 prop = p
1100 end
1101
1102 end
1103 if prop == null then
1104 if is_implicit_self then
1105 v.error(self, "Error: Method or variable '{name}' unknown in {type_recv}.")
1106 else
1107 v.error(self, "Error: Method '{name}' doesn't exists in {type_recv}.")
1108 end
1109 return null
1110 end
1111 return prop
1112 end
1113
1114 # Get the signature for a local property and a receiver
1115 private meth get_signature(v: TypingVisitor, type_recv: MMType, prop: MMMethod, recv_is_self: Bool): MMSignature
1116 do
1117 prop.global.check_visibility(v, self, v.module, recv_is_self)
1118 var psig = prop.signature_for(type_recv)
1119 if not recv_is_self then psig = psig.not_for_self
1120 return psig
1121 end
1122
1123 # The invoked method (once computed)
1124 readable attr _prop: MMMethod
1125
1126 # The return type (if any) (once computed)
1127 readable attr _return_type: MMType
1128 end
1129
1130 # A possible call of constructor in a super class
1131 # Could be an explicit call or with the 'super' keyword
1132 class ASuperInitCall
1133 special AAbsSendExpr
1134 private meth register_super_init_call(v: TypingVisitor, property: MMMethod)
1135 do
1136 if parent != v.top_block and self != v.top_block then
1137 v.error(self, "Error: Constructor invocation {property} must not be in nested block.")
1138 end
1139 var cla = v.module[property.global.intro.local_class.global]
1140 var prev_class: MMLocalClass = null
1141 if not v.explicit_super_init_calls.is_empty then
1142 prev_class = v.explicit_super_init_calls.last.global.intro.local_class
1143 end
1144 var order = v.local_class.cshe.reverse_linear_extension
1145 if cla == v.local_class then
1146 v.explicit_other_init_call = true
1147 else if not order.has(cla) then
1148 v.error(self, "Error: Constructor of class {cla} must be one in {order.join(", ")}.")
1149 else if cla == prev_class then
1150 v.error(self, "Error: Only one super constructor invocation of class {cla} is allowed.")
1151 else
1152 var last_is_found = prev_class == null
1153 for c in order do
1154 if c == prev_class then
1155 last_is_found = true
1156 else if c == cla then
1157 if not last_is_found then
1158 v.error(self, "Error: Constructor of {c} must be invoked before constructor of {prev_class}")
1159 end
1160 v.explicit_super_init_calls.add(property)
1161 break
1162 end
1163 end
1164 end
1165 end
1166
1167 end
1168
1169 redef class ANewExpr
1170 special AAbsSendExpr
1171 redef meth after_typing(v)
1172 do
1173 var t = n_type.stype
1174 if t == null then return
1175 if t.local_class.global.is_abstract then
1176 v.error(self, "Error: try to instantiate abstract class {t.local_class}.")
1177 return
1178 end
1179 var name: Symbol
1180 if n_id == null then
1181 name = once "init".to_symbol
1182 else
1183 name = n_id.to_symbol
1184 end
1185
1186 do_typing(v, t, false, false, name, n_args.to_a, null)
1187 if prop == null then return
1188
1189 if not prop.global.is_init then
1190 v.error(self, "Error: {prop} is not a constructor.")
1191 return
1192 end
1193 _stype = t
1194 _is_typed = true
1195 end
1196 end
1197
1198
1199 redef class ASendExpr
1200 special ASuperInitCall
1201 # Name of the invoked property
1202 meth name: Symbol is abstract
1203
1204 # Raw arguments used (withour star transformation)
1205 meth raw_arguments: Array[PExpr] is abstract
1206
1207 # Closure definitions
1208 meth closure_defs: Array[PClosureDef] do return null
1209
1210 redef meth after_typing(v)
1211 do
1212 do_all_typing(v)
1213 end
1214
1215 private meth do_all_typing(v: TypingVisitor)
1216 do
1217 if not v.check_expr(n_expr) then return
1218 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_arguments, closure_defs)
1219 if prop == null then return
1220
1221 if prop.global.is_init then
1222 if not v.local_property.global.is_init then
1223 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1224 else if not n_expr.is_self then
1225 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1226 else
1227 register_super_init_call(v, prop)
1228 end
1229 end
1230
1231 _stype = return_type
1232 _is_typed = true
1233 end
1234 end
1235
1236 class ASendReassignExpr
1237 special ASendExpr
1238 special AReassignFormExpr
1239 readable attr _read_prop: MMMethod
1240 redef meth do_all_typing(v)
1241 do
1242 if not v.check_expr(n_expr) then return
1243 var raw_args = raw_arguments
1244 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_args, null)
1245 if prop == null then return
1246 if prop.global.is_init then
1247 if not v.local_property.global.is_init then
1248 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1249 else if not n_expr.is_self then
1250 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1251 end
1252 end
1253 var t = prop.signature_for(n_expr.stype).return_type
1254 if not n_expr.is_self then t = t.not_for_self
1255
1256 do_lvalue_typing(v, t)
1257
1258 _read_prop = prop
1259 var old_args = arguments
1260 raw_args.add(n_value)
1261
1262 do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, "{name}=".to_symbol, raw_args, null)
1263 if prop == null then return
1264 if prop.global.is_init then
1265 if not v.local_property.global.is_init then
1266 v.error(self, "Error: try to invoke constructor {prop} in a method.")
1267 else if not n_expr.is_self then
1268 v.error(self, "Error: constructor {prop} is not invoken on 'self'.")
1269 end
1270 end
1271
1272 _arguments = old_args # FIXME: What if star parameters do not match betwen the two methods?
1273 _is_typed = true
1274 end
1275 end
1276
1277 redef class ABinopExpr
1278 redef meth raw_arguments do return [n_expr2]
1279 end
1280 redef class AEqExpr
1281 redef meth name do return once "==".to_symbol
1282 end
1283 redef class ANeExpr
1284 redef meth name do return once "!=".to_symbol
1285 end
1286 redef class ALtExpr
1287 redef meth name do return once "<".to_symbol
1288 end
1289 redef class ALeExpr
1290 redef meth name do return once "<=".to_symbol
1291 end
1292 redef class AGtExpr
1293 redef meth name do return once ">".to_symbol
1294 end
1295 redef class AGeExpr
1296 redef meth name do return once ">=".to_symbol
1297 end
1298 redef class APlusExpr
1299 redef meth name do return once "+".to_symbol
1300 end
1301 redef class AMinusExpr
1302 redef meth name do return once "-".to_symbol
1303 end
1304 redef class AStarshipExpr
1305 redef meth name do return once "<=>".to_symbol
1306 end
1307 redef class AStarExpr
1308 redef meth name do return once "*".to_symbol
1309 end
1310 redef class ASlashExpr
1311 redef meth name do return once "/".to_symbol
1312 end
1313 redef class APercentExpr
1314 redef meth name do return once "%".to_symbol
1315 end
1316
1317 redef class AUminusExpr
1318 redef meth name do return once "unary -".to_symbol
1319 redef meth raw_arguments do return null
1320 end
1321
1322 redef class ACallFormExpr
1323 redef meth after_typing(v)
1324 do
1325 if n_expr != null and n_expr.is_implicit_self then
1326 var name = n_id.to_symbol
1327 var variable = v.variable_ctx[name]
1328 if variable != null then
1329 if variable isa ClosureVariable then
1330 var n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs)
1331 replace_with(n)
1332 n.variable = variable
1333 n.after_typing(v)
1334 return
1335 else
1336 if not n_args.is_empty then
1337 v.error(self, "Error: {name} is variable, not a function.")
1338 return
1339 end
1340 var vform = variable_create(variable)
1341 vform.variable = variable
1342 replace_with(vform)
1343 vform.after_typing(v)
1344 return
1345 end
1346 end
1347 end
1348
1349 super
1350 end
1351
1352 redef meth closure_defs
1353 do
1354 if n_closure_defs == null or n_closure_defs.is_empty then
1355 return null
1356 else
1357 return n_closure_defs.to_a
1358 end
1359 end
1360
1361 # Create a variable acces corresponding to the call form
1362 meth variable_create(variable: Variable): AVarFormExpr is abstract
1363 end
1364
1365 redef class ACallExpr
1366 redef meth variable_create(variable)
1367 do
1368 return new AVarExpr.init_avarexpr(n_id)
1369 end
1370
1371 redef meth name do return n_id.to_symbol
1372 redef meth raw_arguments do return n_args.to_a
1373 end
1374
1375 redef class ACallAssignExpr
1376 redef meth variable_create(variable)
1377 do
1378 return new AVarAssignExpr.init_avarassignexpr(n_id, n_assign, n_value)
1379 end
1380
1381 redef meth name do return (n_id.text + "=").to_symbol
1382 redef meth raw_arguments do
1383 var res = n_args.to_a
1384 res.add(n_value)
1385 return res
1386 end
1387 end
1388
1389 redef class ACallReassignExpr
1390 special ASendReassignExpr
1391 redef meth variable_create(variable)
1392 do
1393 return new AVarReassignExpr.init_avarreassignexpr(n_id, n_assign_op, n_value)
1394 end
1395
1396 redef meth name do return n_id.to_symbol
1397 redef meth raw_arguments do return n_args.to_a
1398 end
1399
1400 redef class ABraExpr
1401 redef meth name do return once "[]".to_symbol
1402 redef meth raw_arguments do return n_args.to_a
1403 end
1404
1405 redef class ABraAssignExpr
1406 redef meth name do return once "[]=".to_symbol
1407 redef meth raw_arguments do
1408 var res = n_args.to_a
1409 res.add(n_value)
1410 return res
1411 end
1412 end
1413
1414 redef class ABraReassignExpr
1415 special ASendReassignExpr
1416 redef meth name do return once "[]".to_symbol
1417 redef meth raw_arguments do return n_args.to_a
1418 end
1419
1420 redef class AInitExpr
1421 redef meth name do return once "init".to_symbol
1422 redef meth raw_arguments do return n_args.to_a
1423 end
1424
1425 redef class AClosureCallExpr
1426 special AAbsAbsSendExpr
1427 redef meth after_typing(v)
1428 do
1429 var va = variable
1430 var sig = va.closure.signature
1431 var args = process_signature(v, sig, n_id.to_symbol, n_args.to_a)
1432 if not n_closure_defs.is_empty then
1433 process_closures(v, sig, n_id.to_symbol, n_closure_defs.to_a)
1434 end
1435 if args == null then return
1436 _prop_signature = sig
1437 _arguments = args
1438 _stype = sig.return_type
1439 _is_typed = true
1440 end
1441 end
1442
1443 redef class PClosureDef
1444 # The corresponding escapable object
1445 readable attr _escapable: EscapableBlock
1446
1447 attr _accept_typing2: Bool
1448 redef meth accept_typing(v)
1449 do
1450 # Typing is deferred, wait accept_typing2(v)
1451 if _accept_typing2 then super
1452 end
1453
1454 private meth accept_typing2(v: TypingVisitor, esc: EscapableClosure) is abstract
1455 end
1456
1457 redef class AClosureDef
1458 redef meth accept_typing2(v, esc)
1459 do
1460 _escapable = esc
1461
1462 var sig = esc.closure.signature
1463 if sig.arity != n_id.length then
1464 v.error(self, "Error: {sig.arity} automatic variable names expected, {n_id.length} found.")
1465 return
1466 end
1467
1468 closure = esc.closure
1469
1470 var old_var_ctx = v.variable_ctx
1471 v.variable_ctx = v.variable_ctx.sub(self)
1472 variables = new Array[AutoVariable]
1473 for i in [0..n_id.length[ do
1474 var va = new AutoVariable(n_id[i].to_symbol, self)
1475 variables.add(va)
1476 va.stype = sig[i]
1477 v.variable_ctx.add(va)
1478 end
1479
1480 _accept_typing2 = true
1481 accept_typing(v)
1482 v.variable_ctx = old_var_ctx
1483 end
1484 end
1485
1486 class ATypeCheckExpr
1487 special PExpr
1488 private meth check_expr_cast(v: TypingVisitor, n_expr: PExpr, n_type: PType)
1489 do
1490 if not v.check_expr(n_expr) then return
1491 var etype = n_expr.stype
1492 var ttype = n_type.stype
1493 if etype == ttype then
1494 v.warning(self, "Warning: Expression is already a {ttype}.")
1495 else if etype < ttype then
1496 v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.")
1497 end
1498 end
1499 end
1500
1501 redef class AIsaExpr
1502 special ATypeCheckExpr
1503 redef meth after_typing(v)
1504 do
1505 check_expr_cast(v, n_expr, n_type)
1506 var variable = n_expr.its_variable
1507 if variable != null then
1508 _if_true_variable_ctx = v.variable_ctx.sub_with(self, variable, n_type.stype)
1509 end
1510 _stype = v.type_bool
1511 _is_typed = true
1512 end
1513 end
1514
1515 redef class AAsCastExpr
1516 special ATypeCheckExpr
1517 redef meth after_typing(v)
1518 do
1519 check_expr_cast(v, n_expr, n_type)
1520 _stype = n_type.stype
1521 _is_typed = _stype != null
1522 end
1523 end
1524
1525 redef class AProxyExpr
1526 redef meth after_typing(v)
1527 do
1528 if not n_expr.is_typed then return
1529 _is_typed = true
1530 if n_expr.is_statement then return
1531 _stype = n_expr.stype
1532 end
1533 end