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