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