src: remove some warnings and do some cleaning
[nit.git] / src / semantize / typing.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 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 # Intraprocedural resolution of static types and OO-services
18 # By OO-services we mean message sending, attribute access, instantiation, etc.
19 module typing
20
21 import modelize
22 import local_var_init
23
24 redef class ToolContext
25 var typing_phase: Phase = new TypingPhase(self, [flow_phase, modelize_property_phase, local_var_init_phase])
26 end
27
28 private class TypingPhase
29 super Phase
30 redef fun process_npropdef(npropdef) do npropdef.do_typing(toolcontext.modelbuilder)
31 end
32
33 private class TypeVisitor
34 var modelbuilder: ModelBuilder
35
36 # The module of the analysis
37 # Used to correctly query the model
38 var mmodule: MModule
39
40 # The static type of the receiver
41 # Mainly used for type tests and type resolutions
42 var anchor: nullable MClassType
43
44 # The analyzed mclassdef
45 var mclassdef: nullable MClassDef
46
47 # The analyzed property
48 var mpropdef: nullable MPropDef
49
50 var selfvariable = new Variable("self")
51
52 # Is `self` use restricted?
53 # * no explicit `self`
54 # * method called on the implicit self must be top-level
55 var is_toplevel_context = false
56
57 init(modelbuilder: ModelBuilder, mmodule: MModule, mpropdef: nullable MPropDef)
58 do
59 self.modelbuilder = modelbuilder
60 self.mmodule = mmodule
61
62 if mpropdef != null then
63 self.mpropdef = mpropdef
64 var mclassdef = mpropdef.mclassdef
65 self.mclassdef = mclassdef
66 self.anchor = mclassdef.bound_mtype
67
68 var mclass = mclassdef.mclass
69
70 var selfvariable = new Variable("self")
71 self.selfvariable = selfvariable
72 selfvariable.declared_type = mclass.mclass_type
73
74 var mprop = mpropdef.mproperty
75 if mprop isa MMethod and mprop.is_toplevel then
76 is_toplevel_context = true
77 end
78 end
79 end
80
81 fun anchor_to(mtype: MType): MType
82 do
83 var anchor = anchor
84 if anchor == null then
85 assert not mtype.need_anchor
86 return mtype
87 end
88 return mtype.anchor_to(mmodule, anchor)
89 end
90
91 fun is_subtype(sub, sup: MType): Bool
92 do
93 return sub.is_subtype(mmodule, anchor, sup)
94 end
95
96 fun resolve_for(mtype, subtype: MType, for_self: Bool): MType
97 do
98 #print "resolve_for {mtype} sub={subtype} forself={for_self} mmodule={mmodule} anchor={anchor}"
99 var res = mtype.resolve_for(subtype, anchor, mmodule, not for_self)
100 return res
101 end
102
103 # Check that `sub` is a subtype of `sup`.
104 # If `sub` is not a valid suptype, then display an error on `node` an return null.
105 # If `sub` is a safe subtype of `sup` then return `sub`.
106 # If `sub` is an unsafe subtype (ie an implicit cast is required), then return `sup`.
107 #
108 # The point of the return type is to determinate the usable type on an expression:
109 # If the suptype is safe, then the return type is the one on the expression typed by `sub`.
110 # Is the subtype is unsafe, then the return type is the one of an implicit cast on `sup`.
111 fun check_subtype(node: ANode, sub, sup: MType): nullable MType
112 do
113 if self.is_subtype(sub, sup) then return sub
114 if self.is_subtype(sub, self.anchor_to(sup)) then
115 # FIXME workaround to the current unsafe typing policy. To remove once fixed virtual types exists.
116 #node.debug("Unsafe typing: expected {sup}, got {sub}")
117 return sup
118 end
119 self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}")
120 return null
121 end
122
123 # Visit an expression and do not care about the return value
124 fun visit_stmt(nexpr: nullable AExpr)
125 do
126 if nexpr == null then return
127 nexpr.accept_typing(self)
128 end
129
130 # Visit an expression and expects that it is not a statement
131 # Return the type of the expression
132 # Display an error and return null if:
133 # * the type cannot be determined or
134 # * `nexpr` is a statement
135 fun visit_expr(nexpr: AExpr): nullable MType
136 do
137 nexpr.accept_typing(self)
138 var mtype = nexpr.mtype
139 if mtype != null then return mtype
140 if not nexpr.is_typed then
141 if not self.modelbuilder.toolcontext.error_count > 0 then # check that there is really an error
142 if self.modelbuilder.toolcontext.verbose_level > 1 then
143 nexpr.debug("No return type but no error.")
144 end
145 end
146 return null # forward error
147 end
148 self.error(nexpr, "Type error: expected expression.")
149 return null
150 end
151
152 # Visit an expression and expect its static type is a least a `sup`
153 # Return the type of the expression or null if
154 # * the type cannot be determined or
155 # * `nexpr` is a statement or
156 # * `nexpr` is not a `sup`
157 fun visit_expr_subtype(nexpr: AExpr, sup: nullable MType): nullable MType
158 do
159 var sub = visit_expr(nexpr)
160 if sub == null then return null # Forward error
161
162 if sup == null then return null # Forward error
163
164 var res = check_subtype(nexpr, sub, sup)
165 if res != sub then
166 nexpr.implicit_cast_to = res
167 end
168 return res
169 end
170
171 # Visit an expression and expect its static type is a `Bool`
172 # Return the type of the expression or null if
173 # * the type cannot be determined or
174 # * `nexpr` is a statement or
175 # * `nexpr` is not a `Bool`
176 fun visit_expr_bool(nexpr: AExpr): nullable MType
177 do
178 return self.visit_expr_subtype(nexpr, self.type_bool(nexpr))
179 end
180
181
182 private fun visit_expr_cast(node: ANode, nexpr: AExpr, ntype: AType): nullable MType
183 do
184 var sub = visit_expr(nexpr)
185 if sub == null then return null # Forward error
186
187 var sup = self.resolve_mtype(ntype)
188 if sup == null then return null # Forward error
189
190 if sup == sub then
191 self.modelbuilder.warning(node, "useless-type-test", "Warning: Expression is already a {sup}.")
192 else if self.is_subtype(sub, sup) then
193 self.modelbuilder.warning(node, "useless-type-test", "Warning: Expression is already a {sup} since it is a {sub}.")
194 end
195 return sup
196 end
197
198 fun try_get_mproperty_by_name2(anode: ANode, mtype: MType, name: String): nullable MProperty
199 do
200 return self.modelbuilder.try_get_mproperty_by_name2(anode, mmodule, mtype, name)
201 end
202
203 fun resolve_mtype(node: AType): nullable MType
204 do
205 return self.modelbuilder.resolve_mtype(mmodule, mclassdef, node)
206 end
207
208 fun try_get_mclass(node: ANode, name: String): nullable MClass
209 do
210 var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
211 return mclass
212 end
213
214 fun get_mclass(node: ANode, name: String): nullable MClass
215 do
216 var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
217 if mclass == null then
218 self.modelbuilder.error(node, "Type Error: missing primitive class `{name}'.")
219 end
220 return mclass
221 end
222
223 fun type_bool(node: ANode): nullable MType
224 do
225 var mclass = self.get_mclass(node, "Bool")
226 if mclass == null then return null
227 return mclass.mclass_type
228 end
229
230 fun get_method(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable CallSite
231 do
232 var unsafe_type = self.anchor_to(recvtype)
233
234 #debug("recv: {recvtype} (aka {unsafe_type})")
235 if recvtype isa MNullType then
236 self.error(node, "Error: Method '{name}' call on 'null'.")
237 return null
238 end
239
240 var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
241 if mproperty == null then
242 #self.modelbuilder.error(node, "Type error: property {name} not found in {unsafe_type} (ie {recvtype})")
243 if recv_is_self then
244 self.modelbuilder.error(node, "Error: Method or variable '{name}' unknown in {recvtype}.")
245 else
246 self.modelbuilder.error(node, "Error: Method '{name}' doesn't exists in {recvtype}.")
247 end
248 return null
249 end
250
251 assert mproperty isa MMethod
252
253 if is_toplevel_context and recv_is_self and not mproperty.is_toplevel then
254 error(node, "Error: '{name}' is not a top-level method, thus need a receiver.")
255 end
256 if not recv_is_self and mproperty.is_toplevel then
257 error(node, "Error: cannot call '{name}', a top-level method, with a receiver.")
258 end
259
260 if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility and not modelbuilder.toolcontext.opt_ignore_visibility.value then
261 self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self.")
262 return null
263 end
264
265 var info = mproperty.deprecation
266 if info != null and self.mpropdef.mproperty.deprecation == null then
267 var mdoc = info.mdoc
268 if mdoc != null then
269 self.modelbuilder.warning(node, "deprecated-method", "Deprecation Warning: Method '{name}' is deprecated: {mdoc.content.first}")
270 else
271 self.modelbuilder.warning(node, "deprecated-method", "Deprecation Warning: Method '{name}' is deprecated.")
272 end
273 end
274
275 var propdefs = mproperty.lookup_definitions(self.mmodule, unsafe_type)
276 var mpropdef
277 if propdefs.length == 0 then
278 self.modelbuilder.error(node, "Type error: no definition found for property {name} in {unsafe_type}")
279 return null
280 else if propdefs.length == 1 then
281 mpropdef = propdefs.first
282 else
283 self.modelbuilder.warning(node, "property-conflict", "Warning: conflicting property definitions for property {name} in {unsafe_type}: {propdefs.join(" ")}")
284 mpropdef = mproperty.intro
285 end
286
287
288 var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
289 msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
290
291 var erasure_cast = false
292 var rettype = mpropdef.msignature.return_mtype
293 if not recv_is_self and rettype != null then
294 rettype = rettype.as_notnullable
295 if rettype isa MParameterType then
296 var erased_rettype = msignature.return_mtype
297 assert erased_rettype != null
298 #node.debug("Erasure cast: Really a {rettype} but unsafely a {erased_rettype}")
299 erasure_cast = true
300 end
301 end
302
303 var callsite = new CallSite(node, recvtype, mmodule, anchor, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
304 return callsite
305 end
306
307 fun try_get_method(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable CallSite
308 do
309 var unsafe_type = self.anchor_to(recvtype)
310 var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
311 if mproperty == null then return null
312 return get_method(node, recvtype, name, recv_is_self)
313 end
314
315
316 # Visit the expressions of args and check their conformity with the corresponding type in signature
317 # The point of this method is to handle varargs correctly
318 # Note: The signature must be correctly adapted
319 fun check_signature(node: ANode, args: Array[AExpr], name: String, msignature: MSignature): Bool
320 do
321 var vararg_rank = msignature.vararg_rank
322 if vararg_rank >= 0 then
323 if args.length < msignature.arity then
324 #self.modelbuilder.error(node, "Error: Incorrect number of parameters. Got {args.length}, expected at least {msignature.arity}. Signature is {msignature}")
325 self.modelbuilder.error(node, "Error: arity mismatch; prototype is '{name}{msignature}'")
326 return false
327 end
328 else if args.length != msignature.arity then
329 self.modelbuilder.error(node, "Error: Incorrect number of parameters. Got {args.length}, expected {msignature.arity}. Signature is {msignature}")
330 return false
331 end
332
333 #debug("CALL {unsafe_type}.{msignature}")
334
335 var vararg_decl = args.length - msignature.arity
336 for i in [0..msignature.arity[ do
337 var j = i
338 if i == vararg_rank then continue # skip the vararg
339 if i > vararg_rank then
340 j = i + vararg_decl
341 end
342 var paramtype = msignature.mparameters[i].mtype
343 self.visit_expr_subtype(args[j], paramtype)
344 end
345 if vararg_rank >= 0 then
346 var varargs = new Array[AExpr]
347 var paramtype = msignature.mparameters[vararg_rank].mtype
348 for j in [vararg_rank..vararg_rank+vararg_decl] do
349 varargs.add(args[j])
350 self.visit_expr_subtype(args[j], paramtype)
351 end
352 end
353 return true
354 end
355
356 fun error(node: ANode, message: String)
357 do
358 self.modelbuilder.toolcontext.error(node.hot_location, message)
359 end
360
361 fun get_variable(node: AExpr, variable: Variable): nullable MType
362 do
363 var flow = node.after_flow_context
364 if flow == null then
365 self.error(node, "No context!")
366 return null
367 end
368
369 if flow.vars.has_key(variable) then
370 return flow.vars[variable]
371 else
372 #node.debug("*** START Collected for {variable}")
373 var mtypes = flow.collect_types(variable)
374 #node.debug("**** END Collected for {variable}")
375 if mtypes == null or mtypes.length == 0 then
376 return variable.declared_type
377 else if mtypes.length == 1 then
378 return mtypes.first
379 else
380 var res = merge_types(node,mtypes)
381 if res == null then res = variable.declared_type
382 return res
383 end
384 end
385 end
386
387 fun set_variable(node: AExpr, variable: Variable, mtype: nullable MType)
388 do
389 var flow = node.after_flow_context
390 assert flow != null
391
392 flow.set_var(variable, mtype)
393 end
394
395 fun merge_types(node: ANode, col: Array[nullable MType]): nullable MType
396 do
397 if col.length == 1 then return col.first
398 for t1 in col do
399 if t1 == null then continue # return null
400 var found = true
401 for t2 in col do
402 if t2 == null then continue # return null
403 if t2 isa MNullableType or t2 isa MNullType then
404 t1 = t1.as_nullable
405 end
406 if not is_subtype(t2, t1) then found = false
407 end
408 if found then
409 #print "merge {col.join(" ")} -> {t1}"
410 return t1
411 end
412 end
413 #self.modelbuilder.warning(node, "Type Error: {col.length} conflicting types: <{col.join(", ")}>")
414 return null
415 end
416 end
417
418 # A specific method call site with its associated informations.
419 class CallSite
420 # The associated node for location
421 var node: ANode
422
423 # The static type of the receiver (possibly unresolved)
424 var recv: MType
425
426 # The module where the callsite is present
427 var mmodule: MModule
428
429 # The anchor to use with `recv` or `msignature`
430 var anchor: nullable MClassType
431
432 # Is the receiver self?
433 # If "for_self", virtual types of the signature are kept
434 # If "not_for_self", virtual type are erased
435 var recv_is_self: Bool
436
437 # The designated method
438 var mproperty: MMethod
439
440 # The statically designated method definition
441 # The most specif one, it is.
442 var mpropdef: MMethodDef
443
444 # The resolved signature for the receiver
445 var msignature: MSignature
446
447 # Is a implicit cast required on erasure typing policy?
448 var erasure_cast: Bool
449
450 private fun check_signature(v: TypeVisitor, args: Array[AExpr]): Bool
451 do
452 return v.check_signature(self.node, args, self.mproperty.name, self.msignature)
453 end
454 end
455
456 redef class Variable
457 # The declared type of the variable
458 var declared_type: nullable MType
459 end
460
461 redef class FlowContext
462 # Store changes of types because of type evolution
463 private var vars = new HashMap[Variable, nullable MType]
464 private var cache = new HashMap[Variable, nullable Array[nullable MType]]
465
466 # Adapt the variable to a static type
467 # Warning1: do not modify vars directly.
468 # Warning2: sub-flow may have cached a unadapted variable
469 private fun set_var(variable: Variable, mtype: nullable MType)
470 do
471 self.vars[variable] = mtype
472 self.cache.keys.remove(variable)
473 end
474
475 private fun collect_types(variable: Variable): nullable Array[nullable MType]
476 do
477 if cache.has_key(variable) then
478 return cache[variable]
479 end
480 var res: nullable Array[nullable MType] = null
481 if vars.has_key(variable) then
482 var mtype = vars[variable]
483 res = [mtype]
484 else if self.previous.is_empty then
485 # Root flow
486 res = [variable.declared_type]
487 else
488 for flow in self.previous do
489 if flow.is_unreachable then continue
490 var r2 = flow.collect_types(variable)
491 if r2 == null then continue
492 if res == null then
493 res = r2.to_a
494 else
495 for t in r2 do
496 if not res.has(t) then res.add(t)
497 end
498 end
499 end
500 end
501 cache[variable] = res
502 return res
503 end
504 end
505
506 redef class APropdef
507 # The entry point of the whole typing analysis
508 fun do_typing(modelbuilder: ModelBuilder)
509 do
510 end
511
512 # The variable associated to the receiver (if any)
513 var selfvariable: nullable Variable
514 end
515
516 redef class AMethPropdef
517 redef fun do_typing(modelbuilder: ModelBuilder)
518 do
519 var nblock = self.n_block
520 if nblock == null then return
521
522 var mpropdef = self.mpropdef.as(not null)
523 var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
524 self.selfvariable = v.selfvariable
525
526 var mmethoddef = self.mpropdef.as(not null)
527 for i in [0..mmethoddef.msignature.arity[ do
528 var mtype = mmethoddef.msignature.mparameters[i].mtype
529 if mmethoddef.msignature.vararg_rank == i then
530 var arrayclass = v.get_mclass(self.n_signature.n_params[i], "Array")
531 if arrayclass == null then return # Skip error
532 mtype = arrayclass.get_mtype([mtype])
533 end
534 var variable = self.n_signature.n_params[i].variable
535 assert variable != null
536 variable.declared_type = mtype
537 end
538 v.visit_stmt(nblock)
539
540 if not nblock.after_flow_context.is_unreachable and mmethoddef.msignature.return_mtype != null then
541 # We reach the end of the function without having a return, it is bad
542 v.error(self, "Control error: Reached end of function (a 'return' with a value was expected).")
543 end
544 end
545 end
546
547 redef class AAttrPropdef
548 redef fun do_typing(modelbuilder: ModelBuilder)
549 do
550 var mpropdef = self.mpropdef.as(not null)
551 var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
552 self.selfvariable = v.selfvariable
553
554 var nexpr = self.n_expr
555 if nexpr != null then
556 var mtype = self.mpropdef.static_mtype
557 v.visit_expr_subtype(nexpr, mtype)
558 end
559 end
560 end
561
562 ###
563
564 redef class AExpr
565 # The static type of the expression.
566 # null if self is a statement or in case of error
567 var mtype: nullable MType = null
568
569 # Is the statement correctly typed?
570 # Used to distinguish errors and statements when `mtype == null`
571 var is_typed: Bool = false
572
573 # If required, the following implicit cast `.as(XXX)`
574 # Such a cast may by required after evaluating the expression when
575 # a unsafe operation is detected (silently accepted by the Nit language).
576 # The attribute is computed by `check_subtype`
577 var implicit_cast_to: nullable MType = null
578
579 # Return the variable read (if any)
580 # Used to perform adaptive typing
581 fun its_variable: nullable Variable do return null
582
583 private fun accept_typing(v: TypeVisitor)
584 do
585 v.error(self, "no implemented accept_typing for {self.class_name}")
586 end
587 end
588
589 redef class ABlockExpr
590 redef fun accept_typing(v)
591 do
592 for e in self.n_expr do v.visit_stmt(e)
593 self.is_typed = true
594 end
595
596 # The type of a blockexpr is the one of the last expression (or null if empty)
597 redef fun mtype
598 do
599 if self.n_expr.is_empty then return null
600 return self.n_expr.last.mtype
601 end
602 end
603
604 redef class AVardeclExpr
605 redef fun accept_typing(v)
606 do
607 var variable = self.variable
608 if variable == null then return # Skip error
609
610 var ntype = self.n_type
611 var mtype: nullable MType
612 if ntype == null then
613 mtype = null
614 else
615 mtype = v.resolve_mtype(ntype)
616 if mtype == null then return # Skip error
617 end
618
619 var nexpr = self.n_expr
620 if nexpr != null then
621 if mtype != null then
622 v.visit_expr_subtype(nexpr, mtype)
623 else
624 mtype = v.visit_expr(nexpr)
625 if mtype == null then return # Skip error
626 end
627 end
628
629 var decltype = mtype
630 if mtype == null or mtype isa MNullType then
631 decltype = v.get_mclass(self, "Object").mclass_type.as_nullable
632 if mtype == null then mtype = decltype
633 end
634
635 variable.declared_type = decltype
636 v.set_variable(self, variable, mtype)
637
638 #debug("var {variable}: {mtype}")
639
640 self.is_typed = true
641 end
642 end
643
644 redef class AVarExpr
645 redef fun its_variable do return self.variable
646 redef fun accept_typing(v)
647 do
648 var variable = self.variable
649 if variable == null then return # Skip error
650
651 var mtype = v.get_variable(self, variable)
652 if mtype != null then
653 #debug("{variable} is {mtype}")
654 else
655 #debug("{variable} is untyped")
656 end
657
658 self.mtype = mtype
659 end
660 end
661
662 redef class AVarAssignExpr
663 redef fun accept_typing(v)
664 do
665 var variable = self.variable
666 assert variable != null
667
668 var mtype = v.visit_expr_subtype(n_value, variable.declared_type)
669
670 v.set_variable(self, variable, mtype)
671
672 self.is_typed = true
673 end
674 end
675
676 redef class AReassignFormExpr
677 # The method designed by the reassign operator.
678 var reassign_callsite: nullable CallSite
679
680 var read_type: nullable MType = null
681
682 # Determine the `reassign_property`
683 # `readtype` is the type of the reading of the left value.
684 # `writetype` is the type of the writing of the left value.
685 # (Because of `ACallReassignExpr`, both can be different.
686 # Return the static type of the value to store.
687 private fun resolve_reassignment(v: TypeVisitor, readtype, writetype: MType): nullable MType
688 do
689 var reassign_name: String
690 if self.n_assign_op isa APlusAssignOp then
691 reassign_name = "+"
692 else if self.n_assign_op isa AMinusAssignOp then
693 reassign_name = "-"
694 else
695 abort
696 end
697
698 self.read_type = readtype
699
700 if readtype isa MNullType then
701 v.error(self, "Error: Method '{reassign_name}' call on 'null'.")
702 return null
703 end
704
705 var callsite = v.get_method(self, readtype, reassign_name, false)
706 if callsite == null then return null # Skip error
707 self.reassign_callsite = callsite
708
709 var msignature = callsite.msignature
710 var rettype = msignature.return_mtype
711 assert msignature.arity == 1 and rettype != null
712
713 var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype)
714 if value_type == null then return null # Skip error
715
716 v.check_subtype(self, rettype, writetype)
717 return rettype
718 end
719 end
720
721 redef class AVarReassignExpr
722 redef fun accept_typing(v)
723 do
724 var variable = self.variable
725 assert variable != null
726
727 var readtype = v.get_variable(self, variable)
728 if readtype == null then return
729
730 read_type = readtype
731
732 var writetype = variable.declared_type
733 if writetype == null then return
734
735 var rettype = self.resolve_reassignment(v, readtype, writetype)
736
737 v.set_variable(self, variable, rettype)
738
739 self.is_typed = true
740 end
741 end
742
743
744 redef class AContinueExpr
745 redef fun accept_typing(v)
746 do
747 var nexpr = self.n_expr
748 if nexpr != null then
749 v.visit_expr(nexpr)
750 end
751 self.is_typed = true
752 end
753 end
754
755 redef class ABreakExpr
756 redef fun accept_typing(v)
757 do
758 var nexpr = self.n_expr
759 if nexpr != null then
760 v.visit_expr(nexpr)
761 end
762 self.is_typed = true
763 end
764 end
765
766 redef class AReturnExpr
767 redef fun accept_typing(v)
768 do
769 var nexpr = self.n_expr
770 var ret_type = v.mpropdef.as(MMethodDef).msignature.return_mtype
771 if nexpr != null then
772 if ret_type != null then
773 v.visit_expr_subtype(nexpr, ret_type)
774 else
775 v.visit_expr(nexpr)
776 v.error(self, "Error: Return with value in a procedure.")
777 end
778 else if ret_type != null then
779 v.error(self, "Error: Return without value in a function.")
780 end
781 self.is_typed = true
782 end
783 end
784
785 redef class AAbortExpr
786 redef fun accept_typing(v)
787 do
788 self.is_typed = true
789 end
790 end
791
792 redef class AIfExpr
793 redef fun accept_typing(v)
794 do
795 v.visit_expr_bool(n_expr)
796
797 v.visit_stmt(n_then)
798 v.visit_stmt(n_else)
799 self.is_typed = true
800 end
801 end
802
803 redef class AIfexprExpr
804 redef fun accept_typing(v)
805 do
806 v.visit_expr_bool(n_expr)
807
808 var t1 = v.visit_expr(n_then)
809 var t2 = v.visit_expr(n_else)
810
811 if t1 == null or t2 == null then
812 return # Skip error
813 end
814
815 var t = v.merge_types(self, [t1, t2])
816 if t == null then
817 v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
818 end
819 self.mtype = t
820 end
821 end
822
823 redef class ADoExpr
824 redef fun accept_typing(v)
825 do
826 v.visit_stmt(n_block)
827 self.is_typed = true
828 end
829 end
830
831 redef class AWhileExpr
832 redef fun accept_typing(v)
833 do
834 v.visit_expr_bool(n_expr)
835
836 v.visit_stmt(n_block)
837 self.is_typed = true
838 end
839 end
840
841 redef class ALoopExpr
842 redef fun accept_typing(v)
843 do
844 v.visit_stmt(n_block)
845 self.is_typed = true
846 end
847 end
848
849 redef class AForExpr
850 var coltype: nullable MClassType
851
852 var method_iterator: nullable CallSite
853 var method_is_ok: nullable CallSite
854 var method_item: nullable CallSite
855 var method_next: nullable CallSite
856 var method_key: nullable CallSite
857 var method_finish: nullable CallSite
858
859 private fun do_type_iterator(v: TypeVisitor, mtype: MType)
860 do
861 if mtype isa MNullType then
862 v.error(self, "Type error: 'for' cannot iterate over 'null'")
863 return
864 end
865
866 # get obj class
867 var objcla = v.get_mclass(self, "Object")
868 if objcla == null then return
869
870 # check iterator method
871 var itdef = v.get_method(self, mtype, "iterator", n_expr isa ASelfExpr)
872 if itdef == null then
873 v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
874 return
875 end
876 self.method_iterator = itdef
877
878 # check that iterator return something
879 var ittype = itdef.msignature.return_mtype
880 if ittype == null then
881 v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
882 return
883 end
884
885 # get iterator type
886 var colit_cla = v.try_get_mclass(self, "Iterator")
887 var mapit_cla = v.try_get_mclass(self, "MapIterator")
888 var is_col = false
889 var is_map = false
890
891 if colit_cla != null and v.is_subtype(ittype, colit_cla.get_mtype([objcla.mclass_type.as_nullable])) then
892 # Iterator
893 var coltype = ittype.supertype_to(v.mmodule, v.anchor, colit_cla)
894 var variables = self.variables
895 if variables.length != 1 then
896 v.error(self, "Type Error: 'for' expects only one variable when using 'Iterator'.")
897 else
898 variables.first.declared_type = coltype.arguments.first
899 end
900 is_col = true
901 end
902
903 if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type, objcla.mclass_type.as_nullable])) then
904 # Map Iterator
905 var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
906 var variables = self.variables
907 if variables.length != 2 then
908 v.error(self, "Type Error: 'for' expects two variables when using 'MapIterator'.")
909 else
910 variables[0].declared_type = coltype.arguments[0]
911 variables[1].declared_type = coltype.arguments[1]
912 end
913 is_map = true
914 end
915
916 if not is_col and not is_map then
917 v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
918 return
919 end
920
921 # anchor formal and virtual types
922 if mtype.need_anchor then mtype = v.anchor_to(mtype)
923
924 mtype = mtype.as_notnullable
925 self.coltype = mtype.as(MClassType)
926
927 # get methods is_ok, next, item
928 var ikdef = v.get_method(self, ittype, "is_ok", false)
929 if ikdef == null then
930 v.error(self, "Type Error: 'for' expects a method 'is_ok' in 'Iterator' type {ittype}.")
931 return
932 end
933 self.method_is_ok = ikdef
934
935 var itemdef = v.get_method(self, ittype, "item", false)
936 if itemdef == null then
937 v.error(self, "Type Error: 'for' expects a method 'item' in 'Iterator' type {ittype}.")
938 return
939 end
940 self.method_item = itemdef
941
942 var nextdef = v.get_method(self, ittype, "next", false)
943 if nextdef == null then
944 v.error(self, "Type Error: 'for' expects a method 'next' in 'Iterator' type {ittype}.")
945 return
946 end
947 self.method_next = nextdef
948
949 self.method_finish = v.try_get_method(self, ittype, "finish", false)
950
951 if is_map then
952 var keydef = v.get_method(self, ittype, "key", false)
953 if keydef == null then
954 v.error(self, "Type Error: 'for' expects a method 'key' in 'Iterator' type {ittype}.")
955 return
956 end
957 self.method_key = keydef
958 end
959 end
960
961 redef fun accept_typing(v)
962 do
963 var mtype = v.visit_expr(n_expr)
964 if mtype == null then return
965
966 self.do_type_iterator(v, mtype)
967
968 v.visit_stmt(n_block)
969 self.is_typed = true
970 end
971 end
972
973 redef class AAssertExpr
974 redef fun accept_typing(v)
975 do
976 v.visit_expr_bool(n_expr)
977
978 v.visit_stmt(n_else)
979 self.is_typed = true
980 end
981 end
982
983 redef class AOrExpr
984 redef fun accept_typing(v)
985 do
986 v.visit_expr_bool(n_expr)
987 v.visit_expr_bool(n_expr2)
988 self.mtype = v.type_bool(self)
989 end
990 end
991
992 redef class AImpliesExpr
993 redef fun accept_typing(v)
994 do
995 v.visit_expr_bool(n_expr)
996 v.visit_expr_bool(n_expr2)
997 self.mtype = v.type_bool(self)
998 end
999 end
1000
1001 redef class AAndExpr
1002 redef fun accept_typing(v)
1003 do
1004 v.visit_expr_bool(n_expr)
1005 v.visit_expr_bool(n_expr2)
1006 self.mtype = v.type_bool(self)
1007 end
1008 end
1009
1010
1011 redef class ANotExpr
1012 redef fun accept_typing(v)
1013 do
1014 v.visit_expr_bool(n_expr)
1015 self.mtype = v.type_bool(self)
1016 end
1017 end
1018
1019 redef class AOrElseExpr
1020 redef fun accept_typing(v)
1021 do
1022 var t1 = v.visit_expr(n_expr)
1023 var t2 = v.visit_expr(n_expr2)
1024
1025 if t1 == null or t2 == null then
1026 return # Skip error
1027 end
1028
1029 t1 = t1.as_notnullable
1030
1031 var t = v.merge_types(self, [t1, t2])
1032 if t == null then
1033 t = v.mmodule.object_type
1034 if t2 isa MNullableType then
1035 t = t.as_nullable
1036 end
1037 #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
1038 end
1039 self.mtype = t
1040 end
1041 end
1042
1043 redef class ATrueExpr
1044 redef fun accept_typing(v)
1045 do
1046 self.mtype = v.type_bool(self)
1047 end
1048 end
1049
1050 redef class AFalseExpr
1051 redef fun accept_typing(v)
1052 do
1053 self.mtype = v.type_bool(self)
1054 end
1055 end
1056
1057 redef class AIntExpr
1058 redef fun accept_typing(v)
1059 do
1060 var mclass = v.get_mclass(self, "Int")
1061 if mclass == null then return # Forward error
1062 self.mtype = mclass.mclass_type
1063 end
1064 end
1065
1066 redef class AFloatExpr
1067 redef fun accept_typing(v)
1068 do
1069 var mclass = v.get_mclass(self, "Float")
1070 if mclass == null then return # Forward error
1071 self.mtype = mclass.mclass_type
1072 end
1073 end
1074
1075 redef class ACharExpr
1076 redef fun accept_typing(v)
1077 do
1078 var mclass = v.get_mclass(self, "Char")
1079 if mclass == null then return # Forward error
1080 self.mtype = mclass.mclass_type
1081 end
1082 end
1083
1084 redef class AStringFormExpr
1085 redef fun accept_typing(v)
1086 do
1087 var mclass = v.get_mclass(self, "String")
1088 if mclass == null then return # Forward error
1089 self.mtype = mclass.mclass_type
1090 end
1091 end
1092
1093 redef class ASuperstringExpr
1094 redef fun accept_typing(v)
1095 do
1096 var mclass = v.get_mclass(self, "String")
1097 if mclass == null then return # Forward error
1098 self.mtype = mclass.mclass_type
1099 for nexpr in self.n_exprs do
1100 v.visit_expr_subtype(nexpr, v.mmodule.object_type)
1101 end
1102 end
1103 end
1104
1105 redef class AArrayExpr
1106 var with_capacity_callsite: nullable CallSite
1107 var push_callsite: nullable CallSite
1108
1109 redef fun accept_typing(v)
1110 do
1111 var mtype: nullable MType = null
1112 var ntype = self.n_type
1113 if ntype != null then
1114 mtype = v.resolve_mtype(ntype)
1115 if mtype == null then return # Skip error
1116 end
1117 var mtypes = new Array[nullable MType]
1118 var useless = false
1119 for e in self.n_exprs.n_exprs do
1120 var t = v.visit_expr(e)
1121 if t == null then
1122 return # Skip error
1123 end
1124 if mtype != null then
1125 if v.check_subtype(e, t, mtype) == null then return # Skip error
1126 if t == mtype then useless = true
1127 else
1128 mtypes.add(t)
1129 end
1130 end
1131 if mtype == null then
1132 mtype = v.merge_types(self, mtypes)
1133 end
1134 if mtype == null then
1135 v.error(self, "Type Error: ambiguous array type {mtypes.join(" ")}")
1136 return
1137 end
1138 if useless then
1139 assert ntype != null
1140 v.modelbuilder.warning(ntype, "useless-type", "Warning: useless type declaration `{mtype}` in literal Array since it can be inferred from the elements type.")
1141 end
1142 var mclass = v.get_mclass(self, "Array")
1143 if mclass == null then return # Forward error
1144 var array_mtype = mclass.get_mtype([mtype])
1145
1146 with_capacity_callsite = v.get_method(self, array_mtype, "with_capacity", false)
1147 push_callsite = v.get_method(self, array_mtype, "push", false)
1148
1149 self.mtype = array_mtype
1150 end
1151 end
1152
1153 redef class ARangeExpr
1154 var init_callsite: nullable CallSite
1155
1156 redef fun accept_typing(v)
1157 do
1158 var discrete_class = v.get_mclass(self, "Discrete")
1159 if discrete_class == null then return # Forward error
1160 var discrete_type = discrete_class.intro.bound_mtype
1161 var t1 = v.visit_expr_subtype(self.n_expr, discrete_type)
1162 var t2 = v.visit_expr_subtype(self.n_expr2, discrete_type)
1163 if t1 == null or t2 == null then return
1164 var mclass = v.get_mclass(self, "Range")
1165 if mclass == null then return # Forward error
1166 var mtype
1167 if v.is_subtype(t1, t2) then
1168 mtype = mclass.get_mtype([t2])
1169 else if v.is_subtype(t2, t1) then
1170 mtype = mclass.get_mtype([t1])
1171 else
1172 v.error(self, "Type Error: Cannot create range: {t1} vs {t2}")
1173 return
1174 end
1175
1176 self.mtype = mtype
1177
1178 # get the constructor
1179 var callsite
1180 if self isa ACrangeExpr then
1181 callsite = v.get_method(self, mtype, "init", false)
1182 else if self isa AOrangeExpr then
1183 callsite = v.get_method(self, mtype, "without_last", false)
1184 else
1185 abort
1186 end
1187 init_callsite = callsite
1188 end
1189 end
1190
1191 redef class ANullExpr
1192 redef fun accept_typing(v)
1193 do
1194 self.mtype = v.mmodule.model.null_type
1195 end
1196 end
1197
1198 redef class AIsaExpr
1199 # The static type to cast to.
1200 # (different from the static type of the expression that is `Bool`).
1201 var cast_type: nullable MType
1202 redef fun accept_typing(v)
1203 do
1204 var mtype = v.visit_expr_cast(self, self.n_expr, self.n_type)
1205 self.cast_type = mtype
1206
1207 var variable = self.n_expr.its_variable
1208 if variable != null then
1209 #var orig = self.n_expr.mtype
1210 #var from = if orig != null then orig.to_s else "invalid"
1211 #var to = if mtype != null then mtype.to_s else "invalid"
1212 #debug("adapt {variable}: {from} -> {to}")
1213 self.after_flow_context.when_true.set_var(variable, mtype)
1214 end
1215
1216 self.mtype = v.type_bool(self)
1217 end
1218 end
1219
1220 redef class AAsCastExpr
1221 redef fun accept_typing(v)
1222 do
1223 self.mtype = v.visit_expr_cast(self, self.n_expr, self.n_type)
1224 end
1225 end
1226
1227 redef class AAsNotnullExpr
1228 redef fun accept_typing(v)
1229 do
1230 var mtype = v.visit_expr(self.n_expr)
1231 if mtype == null then return # Forward error
1232
1233 if mtype isa MNullType then
1234 v.error(self, "Type error: as(not null) on null")
1235 return
1236 end
1237 if mtype isa MNullableType then
1238 self.mtype = mtype.mtype
1239 return
1240 end
1241 self.mtype = mtype
1242
1243 if mtype isa MClassType then
1244 v.modelbuilder.warning(self, "useless-type-test", "Warning: expression is already not null, since it is a `{mtype}`.")
1245 return
1246 end
1247 assert mtype.need_anchor
1248 var u = v.anchor_to(mtype)
1249 if not u isa MNullableType then
1250 v.modelbuilder.warning(self, "useless-type-test", "Warning: expression is already not null, since it is a `{mtype}: {u}`.")
1251 return
1252 end
1253 end
1254 end
1255
1256 redef class AProxyExpr
1257 redef fun accept_typing(v)
1258 do
1259 self.mtype = v.visit_expr(self.n_expr)
1260 end
1261 end
1262
1263 redef class ASelfExpr
1264 redef var its_variable: nullable Variable
1265 redef fun accept_typing(v)
1266 do
1267 if v.is_toplevel_context and not self isa AImplicitSelfExpr then
1268 v.error(self, "Error: self cannot be used in top-level method.")
1269 end
1270 var variable = v.selfvariable
1271 self.its_variable = variable
1272 self.mtype = v.get_variable(self, variable)
1273 end
1274 end
1275
1276 ## MESSAGE SENDING AND PROPERTY
1277
1278 redef class ASendExpr
1279 # The property invoked by the send.
1280 var callsite: nullable CallSite
1281
1282 redef fun accept_typing(v)
1283 do
1284 var recvtype = v.visit_expr(self.n_expr)
1285 var name = self.property_name
1286
1287 if recvtype == null then return # Forward error
1288 if recvtype isa MNullType then
1289 v.error(self, "Error: Method '{name}' call on 'null'.")
1290 return
1291 end
1292
1293 var callsite = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
1294 if callsite == null then return
1295 self.callsite = callsite
1296 var msignature = callsite.msignature
1297
1298 var args = compute_raw_arguments
1299
1300 callsite.check_signature(v, args)
1301
1302 if callsite.mproperty.is_init then
1303 var vmpropdef = v.mpropdef
1304 if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
1305 v.error(self, "Can call a init only in another init")
1306 end
1307 if vmpropdef isa MMethodDef and vmpropdef.mproperty.is_root_init and not callsite.mproperty.is_root_init then
1308 v.error(self, "Error: {vmpropdef} cannot call a factory {callsite.mproperty}")
1309 end
1310 end
1311
1312 var ret = msignature.return_mtype
1313 if ret != null then
1314 self.mtype = ret
1315 else
1316 self.is_typed = true
1317 end
1318 end
1319
1320 # The name of the property
1321 # Each subclass simply provide the correct name.
1322 private fun property_name: String is abstract
1323
1324 # An array of all arguments (excluding self)
1325 fun raw_arguments: Array[AExpr] do return compute_raw_arguments
1326
1327 private fun compute_raw_arguments: Array[AExpr] is abstract
1328 end
1329
1330 redef class ABinopExpr
1331 redef fun compute_raw_arguments do return [n_expr2]
1332 end
1333 redef class AEqExpr
1334 redef fun property_name do return "=="
1335 redef fun accept_typing(v)
1336 do
1337 super
1338
1339 var variable = self.n_expr.its_variable
1340 if variable == null then return
1341 var mtype = self.n_expr2.mtype
1342 if not mtype isa MNullType then return
1343 var vartype = v.get_variable(self, variable)
1344 if not vartype isa MNullableType then return
1345 self.after_flow_context.when_true.set_var(variable, mtype)
1346 self.after_flow_context.when_false.set_var(variable, vartype.mtype)
1347 #debug("adapt {variable}:{vartype} ; true->{mtype} false->{vartype.mtype}")
1348 end
1349 end
1350 redef class ANeExpr
1351 redef fun property_name do return "!="
1352 redef fun accept_typing(v)
1353 do
1354 super
1355
1356 var variable = self.n_expr.its_variable
1357 if variable == null then return
1358 var mtype = self.n_expr2.mtype
1359 if not mtype isa MNullType then return
1360 var vartype = v.get_variable(self, variable)
1361 if not vartype isa MNullableType then return
1362 self.after_flow_context.when_false.set_var(variable, mtype)
1363 self.after_flow_context.when_true.set_var(variable, vartype.mtype)
1364 #debug("adapt {variable}:{vartype} ; true->{vartype.mtype} false->{mtype}")
1365 end
1366 end
1367 redef class ALtExpr
1368 redef fun property_name do return "<"
1369 end
1370 redef class ALeExpr
1371 redef fun property_name do return "<="
1372 end
1373 redef class ALlExpr
1374 redef fun property_name do return "<<"
1375 end
1376 redef class AGtExpr
1377 redef fun property_name do return ">"
1378 end
1379 redef class AGeExpr
1380 redef fun property_name do return ">="
1381 end
1382 redef class AGgExpr
1383 redef fun property_name do return ">>"
1384 end
1385 redef class APlusExpr
1386 redef fun property_name do return "+"
1387 end
1388 redef class AMinusExpr
1389 redef fun property_name do return "-"
1390 end
1391 redef class AStarshipExpr
1392 redef fun property_name do return "<=>"
1393 end
1394 redef class AStarExpr
1395 redef fun property_name do return "*"
1396 end
1397 redef class AStarstarExpr
1398 redef fun property_name do return "**"
1399 end
1400 redef class ASlashExpr
1401 redef fun property_name do return "/"
1402 end
1403 redef class APercentExpr
1404 redef fun property_name do return "%"
1405 end
1406
1407 redef class AUminusExpr
1408 redef fun property_name do return "unary -"
1409 redef fun compute_raw_arguments do return new Array[AExpr]
1410 end
1411
1412
1413 redef class ACallExpr
1414 redef fun property_name do return n_id.text
1415 redef fun compute_raw_arguments do return n_args.to_a
1416 end
1417
1418 redef class ACallAssignExpr
1419 redef fun property_name do return n_id.text + "="
1420 redef fun compute_raw_arguments
1421 do
1422 var res = n_args.to_a
1423 res.add(n_value)
1424 return res
1425 end
1426 end
1427
1428 redef class ABraExpr
1429 redef fun property_name do return "[]"
1430 redef fun compute_raw_arguments do return n_args.to_a
1431 end
1432
1433 redef class ABraAssignExpr
1434 redef fun property_name do return "[]="
1435 redef fun compute_raw_arguments
1436 do
1437 var res = n_args.to_a
1438 res.add(n_value)
1439 return res
1440 end
1441 end
1442
1443 redef class ASendReassignFormExpr
1444 # The property invoked for the writing
1445 var write_callsite: nullable CallSite
1446
1447 redef fun accept_typing(v)
1448 do
1449 var recvtype = v.visit_expr(self.n_expr)
1450 var name = self.property_name
1451
1452 if recvtype == null then return # Forward error
1453 if recvtype isa MNullType then
1454 v.error(self, "Error: Method '{name}' call on 'null'.")
1455 return
1456 end
1457
1458 var for_self = self.n_expr isa ASelfExpr
1459 var callsite = v.get_method(self, recvtype, name, for_self)
1460
1461 if callsite == null then return
1462 self.callsite = callsite
1463
1464 var args = compute_raw_arguments
1465
1466 callsite.check_signature(v, args)
1467
1468 var readtype = callsite.msignature.return_mtype
1469 if readtype == null then
1470 v.error(self, "Error: {name} is not a function")
1471 return
1472 end
1473
1474 var wcallsite = v.get_method(self, recvtype, name + "=", self.n_expr isa ASelfExpr)
1475 if wcallsite == null then return
1476 self.write_callsite = wcallsite
1477
1478 var wtype = self.resolve_reassignment(v, readtype, wcallsite.msignature.mparameters.last.mtype)
1479 if wtype == null then return
1480
1481 args = args.to_a # duplicate so raw_arguments keeps only the getter args
1482 args.add(self.n_value)
1483 wcallsite.check_signature(v, args)
1484
1485 self.is_typed = true
1486 end
1487 end
1488
1489 redef class ACallReassignExpr
1490 redef fun property_name do return n_id.text
1491 redef fun compute_raw_arguments do return n_args.to_a
1492 end
1493
1494 redef class ABraReassignExpr
1495 redef fun property_name do return "[]"
1496 redef fun compute_raw_arguments do return n_args.to_a
1497 end
1498
1499 redef class AInitExpr
1500 redef fun property_name do return "init"
1501 redef fun compute_raw_arguments do return n_args.to_a
1502 end
1503
1504 redef class AExprs
1505 fun to_a: Array[AExpr] do return self.n_exprs.to_a
1506 end
1507
1508 ###
1509
1510 redef class ASuperExpr
1511 # The method to call if the super is in fact a 'super init call'
1512 # Note: if the super is a normal call-next-method, then this attribute is null
1513 var callsite: nullable CallSite
1514
1515 # The method to call is the super is a standard `call-next-method` super-call
1516 # Note: if the super is a special super-init-call, then this attribute is null
1517 var mpropdef: nullable MMethodDef
1518
1519 redef fun accept_typing(v)
1520 do
1521 var anchor = v.anchor
1522 assert anchor != null
1523 var recvtype = v.get_variable(self, v.selfvariable)
1524 assert recvtype != null
1525 var mproperty = v.mpropdef.mproperty
1526 if not mproperty isa MMethod then
1527 v.error(self, "Error: super only usable in a method")
1528 return
1529 end
1530 var superprops = mproperty.lookup_super_definitions(v.mmodule, anchor)
1531 if superprops.length == 0 then
1532 if mproperty.is_init and v.mpropdef.is_intro then
1533 process_superinit(v)
1534 return
1535 end
1536 v.error(self, "Error: No super method to call for {mproperty}.")
1537 return
1538 end
1539 # FIXME: covariance of return type in linear extension?
1540 var superprop = superprops.first
1541
1542 var msignature = superprop.msignature.as(not null)
1543 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
1544 var args = self.n_args.to_a
1545 if args.length > 0 then
1546 v.check_signature(self, args, mproperty.name, msignature)
1547 end
1548 self.mtype = msignature.return_mtype
1549 self.is_typed = true
1550 v.mpropdef.has_supercall = true
1551 mpropdef = v.mpropdef.as(MMethodDef)
1552 end
1553
1554 private fun process_superinit(v: TypeVisitor)
1555 do
1556 var anchor = v.anchor
1557 assert anchor != null
1558 var recvtype = v.get_variable(self, v.selfvariable)
1559 assert recvtype != null
1560 var mpropdef = v.mpropdef
1561 assert mpropdef isa MMethodDef
1562 var mproperty = mpropdef.mproperty
1563 var superprop: nullable MMethodDef = null
1564 for msupertype in mpropdef.mclassdef.supertypes do
1565 msupertype = msupertype.anchor_to(v.mmodule, anchor)
1566 var errcount = v.modelbuilder.toolcontext.error_count
1567 var candidate = v.try_get_mproperty_by_name2(self, msupertype, mproperty.name).as(nullable MMethod)
1568 if candidate == null then
1569 if v.modelbuilder.toolcontext.error_count > errcount then return # Forward error
1570 continue # Try next super-class
1571 end
1572 if superprop != null and candidate.is_root_init then
1573 continue
1574 end
1575 if superprop != null and superprop.mproperty != candidate and not superprop.mproperty.is_root_init then
1576 v.error(self, "Error: conflicting super constructor to call for {mproperty}: {candidate.full_name}, {superprop.mproperty.full_name}")
1577 return
1578 end
1579 var candidatedefs = candidate.lookup_definitions(v.mmodule, anchor)
1580 if superprop != null and superprop.mproperty == candidate then
1581 if superprop == candidatedefs.first then continue
1582 candidatedefs.add(superprop)
1583 end
1584 if candidatedefs.length > 1 then
1585 v.error(self, "Error: conflicting property definitions for property {mproperty} in {recvtype}: {candidatedefs.join(", ")}")
1586 return
1587 end
1588 superprop = candidatedefs.first
1589 end
1590 if superprop == null then
1591 v.error(self, "Error: No super method to call for {mproperty}.")
1592 return
1593 end
1594
1595 var msignature = superprop.new_msignature or else superprop.msignature.as(not null)
1596 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
1597
1598 var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
1599 self.callsite = callsite
1600
1601 var args = self.n_args.to_a
1602 if args.length > 0 then
1603 callsite.check_signature(v, args)
1604 else
1605 # Check there is at least enough parameters
1606 if mpropdef.msignature.arity < msignature.arity then
1607 v.error(self, "Error: Not enough implicit arguments to pass. Got {mpropdef.msignature.arity}, expected at least {msignature.arity}. Signature is {msignature}")
1608 return
1609 end
1610 # Check that each needed parameter is conform
1611 var i = 0
1612 for sp in msignature.mparameters do
1613 var p = mpropdef.msignature.mparameters[i]
1614 if not v.is_subtype(p.mtype, sp.mtype) then
1615 v.error(self, "Type error: expected argument #{i} of type {sp.mtype}, got implicit argument {p.name} of type {p.mtype}. Signature is {msignature}")
1616 return
1617 end
1618 i += 1
1619 end
1620 end
1621
1622 self.is_typed = true
1623 end
1624 end
1625
1626 ####
1627
1628 redef class ANewExpr
1629 # The constructor invoked by the new.
1630 var callsite: nullable CallSite
1631
1632 redef fun accept_typing(v)
1633 do
1634 var recvtype = v.resolve_mtype(self.n_type)
1635 if recvtype == null then return
1636 self.mtype = recvtype
1637
1638 if not recvtype isa MClassType then
1639 if recvtype isa MNullableType then
1640 v.error(self, "Type error: cannot instantiate the nullable type {recvtype}.")
1641 return
1642 else
1643 v.error(self, "Type error: cannot instantiate the formal type {recvtype}.")
1644 return
1645 end
1646 else
1647 if recvtype.mclass.kind == abstract_kind then
1648 v.error(self, "Cannot instantiate abstract class {recvtype}.")
1649 return
1650 else if recvtype.mclass.kind == interface_kind then
1651 v.error(self, "Cannot instantiate interface {recvtype}.")
1652 return
1653 end
1654 end
1655
1656 var name: String
1657 var nid = self.n_id
1658 if nid != null then
1659 name = nid.text
1660 else
1661 name = "init"
1662 end
1663 var callsite = v.get_method(self, recvtype, name, false)
1664 if callsite == null then return
1665
1666 self.callsite = callsite
1667
1668 if not callsite.mproperty.is_init_for(recvtype.mclass) then
1669 v.error(self, "Error: {name} is not a constructor.")
1670 return
1671 end
1672
1673 var args = n_args.to_a
1674 callsite.check_signature(v, args)
1675 end
1676 end
1677
1678 ####
1679
1680 redef class AAttrFormExpr
1681 # The attribute acceded.
1682 var mproperty: nullable MAttribute
1683
1684 # The static type of the attribute.
1685 var attr_type: nullable MType
1686
1687 # Resolve the attribute acceded.
1688 private fun resolve_property(v: TypeVisitor)
1689 do
1690 var recvtype = v.visit_expr(self.n_expr)
1691 if recvtype == null then return # Skip error
1692 var name = self.n_id.text
1693 if recvtype isa MNullType then
1694 v.error(self, "Error: Attribute '{name}' access on 'null'.")
1695 return
1696 end
1697
1698 var unsafe_type = v.anchor_to(recvtype)
1699 var mproperty = v.try_get_mproperty_by_name2(self, unsafe_type, name)
1700 if mproperty == null then
1701 v.modelbuilder.error(self, "Error: Attribute {name} doesn't exists in {recvtype}.")
1702 return
1703 end
1704 assert mproperty isa MAttribute
1705 self.mproperty = mproperty
1706
1707 var mpropdefs = mproperty.lookup_definitions(v.mmodule, unsafe_type)
1708 assert mpropdefs.length == 1
1709 var mpropdef = mpropdefs.first
1710 var attr_type = mpropdef.static_mtype.as(not null)
1711 attr_type = v.resolve_for(attr_type, recvtype, self.n_expr isa ASelfExpr)
1712 self.attr_type = attr_type
1713 end
1714 end
1715
1716 redef class AAttrExpr
1717 redef fun accept_typing(v)
1718 do
1719 self.resolve_property(v)
1720 self.mtype = self.attr_type
1721 end
1722 end
1723
1724
1725 redef class AAttrAssignExpr
1726 redef fun accept_typing(v)
1727 do
1728 self.resolve_property(v)
1729 var mtype = self.attr_type
1730
1731 v.visit_expr_subtype(self.n_value, mtype)
1732 self.is_typed = true
1733 end
1734 end
1735
1736 redef class AAttrReassignExpr
1737 redef fun accept_typing(v)
1738 do
1739 self.resolve_property(v)
1740 var mtype = self.attr_type
1741 if mtype == null then return # Skip error
1742
1743 self.resolve_reassignment(v, mtype, mtype)
1744
1745 self.is_typed = true
1746 end
1747 end
1748
1749 redef class AIssetAttrExpr
1750 redef fun accept_typing(v)
1751 do
1752 self.resolve_property(v)
1753 var mtype = self.attr_type
1754 if mtype == null then return # Skip error
1755
1756 var recvtype = self.n_expr.mtype.as(not null)
1757 var bound = v.resolve_for(mtype, recvtype, false)
1758 if bound isa MNullableType then
1759 v.error(self, "Error: isset on a nullable attribute.")
1760 end
1761 self.mtype = v.type_bool(self)
1762 end
1763 end
1764
1765 ###
1766
1767 redef class ADebugTypeExpr
1768 redef fun accept_typing(v)
1769 do
1770 var expr = v.visit_expr(self.n_expr)
1771 if expr == null then return
1772 var unsafe = v.anchor_to(expr)
1773 var ntype = self.n_type
1774 var mtype = v.resolve_mtype(ntype)
1775 if mtype != null and mtype != expr then
1776 var umtype = v.anchor_to(mtype)
1777 v.modelbuilder.warning(self, "debug", "Found type {expr} (-> {unsafe}), expected {mtype} (-> {umtype})")
1778 end
1779 self.is_typed = true
1780 end
1781 end