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