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