typing: Add a way to disable warnings
[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 import literal
24
25 redef class ToolContext
26 var typing_phase: Phase = new TypingPhase(self, [flow_phase, modelize_property_phase, local_var_init_phase])
27 end
28
29 private class TypingPhase
30 super Phase
31 redef fun process_npropdef(npropdef) do npropdef.do_typing(toolcontext.modelbuilder)
32 end
33
34 private class TypeVisitor
35 var modelbuilder: ModelBuilder
36
37 # The module of the analysis
38 # Used to correctly query the model
39 var mmodule: MModule is noinit
40
41 # The static type of the receiver
42 # Mainly used for type tests and type resolutions
43 var anchor: MClassType is noinit
44
45 # The analyzed mclassdef
46 var mclassdef: MClassDef is noinit
47
48 # The analyzed property
49 var mpropdef: MPropDef
50
51 var selfvariable = new Variable("self")
52
53 # Is `self` use restricted?
54 # * no explicit `self`
55 # * method called on the implicit self must be top-level
56 # Currently only used for `new` factory since there is no valid receiver inside
57 var is_toplevel_context = false
58
59 init
60 do
61 var mpropdef = self.mpropdef
62 var mclassdef = mpropdef.mclassdef
63 mmodule = mclassdef.mmodule
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_new then
75 is_toplevel_context = true
76 end
77 end
78
79 # Display a warning on `node` if `not mpropdef.is_fictive`
80 fun display_warning(node: ANode, tag: String, message: String)
81 do
82 if not mpropdef.is_fictive then self.modelbuilder.warning(node, tag, message)
83 end
84
85 fun anchor_to(mtype: MType): MType
86 do
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` and return `null`.
104 # If `sub` is a safe subtype of `sup`, then return `sub`.
105 # If `sub` is an unsafe subtype (i.e., 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 when `autocast` is true:
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, autocast: Bool): nullable MType
111 do
112 if self.is_subtype(sub, sup) then return sub
113 if autocast and 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 if sup isa MErrorType then return null # Skip error
119 if sub.need_anchor then
120 var u = anchor_to(sub)
121 self.modelbuilder.error(node, "Type Error: expected `{sup}`, got `{sub}: {u}`.")
122 else
123 self.modelbuilder.error(node, "Type Error: expected `{sup}`, got `{sub}`.")
124 end
125 return null
126 end
127
128 # Visit an expression and do not care about the return value
129 fun visit_stmt(nexpr: nullable AExpr)
130 do
131 if nexpr == null then return
132 nexpr.accept_typing(self)
133 end
134
135 # Visit an expression and expects that it is not a statement
136 # Return the type of the expression
137 # Display an error and return null if:
138 # * the type cannot be determined or
139 # * `nexpr` is a statement
140 fun visit_expr(nexpr: AExpr): nullable MType
141 do
142 nexpr.accept_typing(self)
143 var mtype = nexpr.mtype
144 if mtype != null then return mtype
145 if not nexpr.is_typed then
146 if not self.modelbuilder.toolcontext.error_count > 0 then # check that there is really an error
147 if self.modelbuilder.toolcontext.verbose_level > 1 then
148 nexpr.debug("No return type but no error.")
149 end
150 end
151 return null # forward error
152 end
153 var more_message = null
154 var p = nexpr.parent
155 if p != null then more_message = p.bad_expr_message(nexpr)
156 if more_message == null then more_message = "" else more_message = " " + more_message
157 self.error(nexpr, "Error: expected an expression{more_message}.")
158 return null
159 end
160
161 # Visit an expression and expect its static type is a least a `sup`
162 # Return the type of the expression or null if
163 # * the type cannot be determined or
164 # * `nexpr` is a statement or
165 # * `nexpr` is not a `sup`
166 fun visit_expr_subtype(nexpr: AExpr, sup: nullable MType): nullable MType
167 do
168 var sub = visit_expr(nexpr)
169 if sub == null then return null # Forward error
170
171 if sup == null then return null # Forward error
172
173 var res = check_subtype(nexpr, sub, sup, true)
174 if res != sub then
175 nexpr.implicit_cast_to = res
176 end
177 return res
178 end
179
180 # Visit an expression and expect its static type is a `Bool`
181 # Return the type of the expression or null if
182 # * the type cannot be determined or
183 # * `nexpr` is a statement or
184 # * `nexpr` is not a `Bool`
185 fun visit_expr_bool(nexpr: AExpr): nullable MType
186 do
187 return self.visit_expr_subtype(nexpr, self.type_bool(nexpr))
188 end
189
190 fun check_expr_cast(node: ANode, nexpr: AExpr, ntype: AType): nullable MType
191 do
192 var sub = nexpr.mtype
193 if sub == null then return null # Forward error
194
195 var sup = ntype.mtype
196 if sup == null then return null # Forward error
197
198 if sup == sub then
199 display_warning(node, "useless-type-test", "Warning: expression is already a `{sup}`.")
200 else if self.is_subtype(sub, sup) then
201 display_warning(node, "useless-type-test", "Warning: expression is already a `{sup}` since it is a `{sub}`.")
202 end
203 return sup
204 end
205
206 # Can `mtype` be null (up to the current knowledge)?
207 fun can_be_null(mtype: MType): Bool
208 do
209 if mtype isa MNullableType or mtype isa MNullType then return true
210 if mtype isa MFormalType then
211 var x = anchor_to(mtype)
212 if x isa MNullableType or x isa MNullType then return true
213 end
214 return false
215 end
216
217 # Check that `mtype` can be null (up to the current knowledge).
218 #
219 # If not then display a `useless-null-test` warning on node and return false.
220 # Else return true.
221 fun check_can_be_null(anode: ANode, mtype: MType): Bool
222 do
223 if mtype isa MNullType then
224 display_warning(anode, "useless-null-test", "Warning: expression is always `null`.")
225 return true
226 end
227 if can_be_null(mtype) then return true
228
229 if mtype isa MFormalType then
230 var res = anchor_to(mtype)
231 display_warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}: {res}`.")
232 else
233 display_warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}`.")
234 end
235 return false
236 end
237
238 # Special verification on != and == for null
239 # Return true
240 fun null_test(anode: ABinopExpr)
241 do
242 var mtype = anode.n_expr.mtype
243 var mtype2 = anode.n_expr2.mtype
244
245 if mtype == null or mtype2 == null then return
246
247 if not mtype2 isa MNullType then return
248
249 # Check of useless null
250 if not can_be_null(mtype) then return
251
252 if mtype isa MNullType then
253 # Because of type adaptation, we cannot just stop here
254 # so return use `null` as a bottom type that will be merged easily (cf) `merge_types`
255 mtype = null
256 else
257 mtype = mtype.as_notnull
258 end
259
260 # Check for type adaptation
261 var variable = anode.n_expr.its_variable
262 if variable == null then return
263
264 # One is null (mtype2 see above) the other is not null
265 if anode isa AEqExpr then
266 anode.after_flow_context.when_true.set_var(self, variable, mtype2)
267 anode.after_flow_context.when_false.set_var(self, variable, mtype)
268 else if anode isa ANeExpr then
269 anode.after_flow_context.when_false.set_var(self, variable, mtype2)
270 anode.after_flow_context.when_true.set_var(self, variable, mtype)
271 else
272 abort
273 end
274 end
275
276 fun try_get_mproperty_by_name2(anode: ANode, mtype: MType, name: String): nullable MProperty
277 do
278 return self.modelbuilder.try_get_mproperty_by_name2(anode, mmodule, mtype, name)
279 end
280
281 fun resolve_mtype(node: AType): nullable MType
282 do
283 return self.modelbuilder.resolve_mtype(mclassdef, node)
284 end
285
286 fun try_get_mclass(node: ANode, name: String): nullable MClass
287 do
288 var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
289 return mclass
290 end
291
292 fun get_mclass(node: ANode, name: String): nullable MClass
293 do
294 var mclass = modelbuilder.get_mclass_by_name(node, mmodule, name)
295 return mclass
296 end
297
298 fun type_bool(node: ANode): nullable MType
299 do
300 var mclass = self.get_mclass(node, "Bool")
301 if mclass == null then return null
302 return mclass.mclass_type
303 end
304
305 # Construction of a specific callsite according to the current context.
306 # Three entry points exist to create a callsite based on knowledge.
307 # The `build_callsite_by_name` is a top entry point, the method find the mpropdefs to call by the name of this.
308 # see `build_callsite_by_property` and `build_callsite_by_propdef` for more detail.
309 # If you already know the mpropdef to call use directly the `get_method_by_propdef` method
310 # If you just know the mproperty use the `build_callsite_by_property` method to display error if no `mpropdef` is found in the context
311 fun build_callsite_by_name(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable CallSite
312 do
313 var unsafe_type = self.anchor_to(recvtype)
314
315 #debug("recv: {recvtype} (aka {unsafe_type})")
316 if recvtype isa MNullType then
317 var objclass = get_mclass(node, "Object")
318 if objclass == null then return null # Forward error
319 unsafe_type = objclass.mclass_type
320 end
321
322 var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
323 if name == "new" and mproperty == null then
324 name = "defaultinit"
325 mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
326 if mproperty == null then
327 name = "init"
328 mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
329 end
330 end
331
332 if mproperty == null then
333 if recv_is_self then
334 # FIXME This test was added to display a more explicit error when a potential duplication of root object class.
335 if name == "init" then
336 self.modelbuilder.error(node, "Possible duplication of the root class `Object`")
337 else
338 self.modelbuilder.error(node, "Error: method or variable `{name}` unknown in `{recvtype}`.")
339 end
340 else if recvtype.need_anchor then
341 self.modelbuilder.error(node, "Error: method `{name}` does not exists in `{recvtype}: {unsafe_type}`.")
342 else
343 self.modelbuilder.error(node, "Error: method `{name}` does not exists in `{recvtype}`.")
344 end
345 return null
346 end
347
348 assert mproperty isa MMethod
349
350 return build_callsite_by_property(node, recvtype, mproperty, recv_is_self)
351 end
352
353 # The `build_callsite_by_property` finds the mpropdefs to call by the `MMethod`.
354 # If the mpropdef is found in the context it builds a new `Callsite`.
355 fun build_callsite_by_property(node: ANode, recvtype: MType, mproperty: MMethod, recv_is_self: Bool): nullable CallSite
356 do
357 var unsafe_type = self.anchor_to(recvtype)
358
359 if recvtype isa MNullType then
360 var objclass = get_mclass(node, "Object")
361 if objclass == null then return null # Forward error
362 unsafe_type = objclass.mclass_type
363 end
364 # `null` only accepts some methods of object.
365 if recvtype isa MNullType and not mproperty.is_null_safe then
366 self.error(node, "Error: method `{mproperty.name}` called on `null`.")
367 return null
368 else if unsafe_type isa MNullableType and not mproperty.is_null_safe then
369 modelbuilder.advice(node, "call-on-nullable", "Warning: method call on a nullable receiver `{recvtype}`.")
370 end
371
372 if is_toplevel_context and recv_is_self and not mproperty.is_toplevel then
373 error(node, "Error: `{mproperty.name}` is not a top-level method, thus need a receiver.")
374 end
375 if not recv_is_self and mproperty.is_toplevel then
376 error(node, "Error: cannot call `{mproperty.name}`, a top-level method, with a receiver.")
377 end
378
379 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
380 self.modelbuilder.error(node, "Error: method `{mproperty.name}` is protected and can only accessed by `self`.")
381 return null
382 end
383
384 var info = mproperty.deprecation
385 if info != null and self.mpropdef.mproperty.deprecation == null then
386 var mdoc = info.mdoc
387 if mdoc != null then
388 display_warning(node, "deprecated-method", "Deprecation Warning: method `{mproperty.name}` is deprecated: {mdoc.content.first}")
389 else
390 display_warning(node, "deprecated-method", "Deprecation Warning: method `{mproperty.name}` is deprecated.")
391 end
392 end
393
394 var propdefs = mproperty.lookup_definitions(self.mmodule, unsafe_type)
395 var mpropdef
396 if propdefs.length == 0 then
397 self.modelbuilder.error(node, "Type Error: no definition found for property `{mproperty.name}` in `{unsafe_type}`.")
398 abort
399 #return null
400 else if propdefs.length == 1 then
401 mpropdef = propdefs.first
402 else
403 display_warning(node, "property-conflict", "Warning: conflicting property definitions for property `{mproperty.name}` in `{unsafe_type}`: {propdefs.join(" ")}")
404 mpropdef = mproperty.intro
405 end
406
407 return build_callsite_by_propdef(node, recvtype, mpropdef, recv_is_self)
408 end
409
410 # The `build_callsite_by_propdef` builds the callsite directly with the `mprodef` passed in argument.
411 fun build_callsite_by_propdef(node: ANode, recvtype: MType, mpropdef: MMethodDef, recv_is_self: Bool): nullable CallSite
412 do
413 var msignature = mpropdef.msignature
414 if msignature == null then return null # skip error
415 msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
416
417 var erasure_cast = false
418 var rettype = mpropdef.msignature.return_mtype
419 if not recv_is_self and rettype != null then
420 rettype = rettype.undecorate
421 if rettype isa MParameterType then
422 var erased_rettype = msignature.return_mtype
423 assert erased_rettype != null
424 #node.debug("Erasure cast: Really a {rettype} but unsafely a {erased_rettype}")
425 erasure_cast = true
426 end
427 end
428
429 var callsite = new CallSite(node.hot_location, recvtype, mmodule, anchor, recv_is_self, mpropdef.mproperty, mpropdef, msignature, erasure_cast)
430 return callsite
431 end
432
433 fun try_build_callsite_by_name(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable CallSite
434 do
435 var unsafe_type = self.anchor_to(recvtype)
436 var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
437 if mproperty == null then return null
438 return build_callsite_by_name(node, recvtype, name, recv_is_self)
439 end
440
441 # Visit the expressions of args and check their conformity with the corresponding type in signature
442 # The point of this method is to handle varargs correctly
443 # Note: The signature must be correctly adapted
444 fun check_signature(node: ANode, args: Array[AExpr], mproperty: MProperty, msignature: MSignature): nullable SignatureMap
445 do
446 var vararg_rank = msignature.vararg_rank
447 if vararg_rank >= 0 then
448 if args.length < msignature.arity then
449 modelbuilder.error(node, "Error: expected at least {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
450 return null
451 end
452 else if args.length != msignature.arity then
453 # Too much argument
454 if args.length > msignature.arity then
455 modelbuilder.error(node, "Error: expected {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
456 return null
457 end
458 # Other cases are managed later
459 end
460
461 #debug("CALL {unsafe_type}.{msignature}")
462
463 # Associate each parameter to a position in the arguments
464 var map = new SignatureMap
465
466 # Special case for the isolated last argument
467 # TODO: reify this method characteristics (where? the param, the signature, the method?)
468 var last_is_padded = mproperty.name.chars.last == '='
469 var nbargs = args.length
470 if last_is_padded then
471 nbargs -= 1
472 assert not args.last isa ANamedargExpr
473 map.map[msignature.arity - 1] = args.length - 1
474 self.visit_expr_subtype(args.last, msignature.mparameters.last.mtype)
475 end
476
477 # First, handle named arguments
478 for i in [0..args.length[ do
479 var e = args[i]
480 if not e isa ANamedargExpr then continue
481 var name = e.n_id.text
482 var param = msignature.mparameter_by_name(name)
483 if param == null then
484 modelbuilder.error(e.n_id, "Error: no parameter `{name}` for `{mproperty}{msignature}`.")
485 return null
486 end
487 var idx = msignature.mparameters.index_of(param)
488 var prev = map.map.get_or_null(idx)
489 if prev != null then
490 modelbuilder.error(e, "Error: parameter `{name}` already associated with argument #{prev} for `{mproperty}{msignature}`.")
491 return null
492 end
493 map.map[idx] = i
494 e.mtype = self.visit_expr_subtype(e.n_expr, param.mtype)
495 end
496
497 # Number of minimum mandatory remaining parameters
498 var min_arity = 0
499
500 # Second, associate remaining parameters
501 var vararg_decl = args.length - msignature.arity
502 var j = 0
503 for i in [0..msignature.arity[ do
504 # Skip parameters associated by name
505 if map.map.has_key(i) then continue
506
507 var param = msignature.mparameters[i]
508
509 # Search the next free argument: skip named arguments since they are already associated
510 while j < nbargs and args[j] isa ANamedargExpr do j += 1
511 if j >= nbargs then
512 if not param.mtype isa MNullableType then
513 min_arity = j + 1
514 end
515 j += 1
516 continue
517 end
518 var arg = args[j]
519 map.map[i] = j
520 j += 1
521
522 if i == vararg_rank then
523 j += vararg_decl
524 continue # skip the vararg
525 end
526
527 if not param.is_vararg then
528 var paramtype = param.mtype
529 self.visit_expr_subtype(arg, paramtype)
530 else
531 check_one_vararg(arg, param)
532 end
533 end
534
535 if min_arity > 0 then
536 if last_is_padded then min_arity += 1
537 if min_arity < msignature.arity then
538 modelbuilder.error(node, "Error: expected at least {min_arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
539 else
540 modelbuilder.error(node, "Error: expected {min_arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
541 end
542 return null
543 end
544
545 # Third, check varargs
546 if vararg_rank >= 0 then
547 var paramtype = msignature.mparameters[vararg_rank].mtype
548 var first = args[vararg_rank]
549 if vararg_decl == 0 then
550 if not check_one_vararg(first, msignature.mparameters[vararg_rank]) then return null
551 else
552 first.vararg_decl = vararg_decl + 1
553 for i in [vararg_rank..vararg_rank+vararg_decl] do
554 self.visit_expr_subtype(args[i], paramtype)
555 end
556 end
557 end
558
559 return map
560 end
561
562 # Check an expression as a single vararg.
563 # The main point of the method if to handle the case of reversed vararg (see `AVarargExpr`)
564 fun check_one_vararg(arg: AExpr, param: MParameter): Bool
565 do
566 var paramtype = param.mtype
567 var mclass = get_mclass(arg, "Array")
568 if mclass == null then return false # Forward error
569 var array_mtype = mclass.get_mtype([paramtype])
570 if arg isa AVarargExpr then
571 self.visit_expr_subtype(arg.n_expr, array_mtype)
572 arg.mtype = arg.n_expr.mtype
573 else
574 # only one vararg, maybe `...` was forgot, so be gentle!
575 var t = visit_expr(arg)
576 if t == null then return false # Forward error
577 if not is_subtype(t, paramtype) and is_subtype(t, array_mtype) then
578 # Not acceptable but could be a `...`
579 error(arg, "Type Error: expected `{paramtype}`, got `{t}`. Is an ellipsis `...` missing on the argument?")
580 return false
581 end
582 # Standard valid vararg, finish the job
583 arg.vararg_decl = 1
584 self.visit_expr_subtype(arg, paramtype)
585 end
586 return true
587 end
588
589 fun error(node: ANode, message: String)
590 do
591 self.modelbuilder.error(node, message)
592 end
593
594 fun get_variable(node: AExpr, variable: Variable): nullable MType
595 do
596 if not variable.is_adapted then return variable.declared_type
597
598 var flow = node.after_flow_context
599 if flow == null then return null # skip error
600
601 if flow.vars.has_key(variable) then
602 return flow.vars[variable]
603 else
604 #node.debug("*** START Collected for {variable}")
605 var mtypes = flow.collect_types(variable)
606 #node.debug("**** END Collected for {variable}")
607 if mtypes.length == 0 then
608 return variable.declared_type
609 else if mtypes.length == 1 then
610 return mtypes.first
611 else
612 var res = merge_types(node,mtypes)
613 if res == null then
614 res = variable.declared_type
615 # Try to fallback to a non-null version
616 if res != null and can_be_null(res) then do
617 for t in mtypes do
618 if t != null and can_be_null(t) then break label
619 end
620 res = res.as_notnull
621 end label
622 end
623 return res
624 end
625 end
626 end
627
628 # Some variables where type-adapted during the visit
629 var dirty = false
630
631 # Some loops had been visited during the visit
632 var has_loop = false
633
634 fun set_variable(node: AExpr, variable: Variable, mtype: nullable MType)
635 do
636 var flow = node.after_flow_context
637 assert flow != null
638
639 flow.set_var(self, variable, mtype)
640 end
641
642 # Find the exact representable most specific common super-type in `col`.
643 #
644 # Try to find the most specific common type that is a super-type of each types
645 # in `col`.
646 # In most cases, the result is simply the most general type in `col`.
647 # If nullables types are involved, then the nullable information is correctly preserved.
648 # If incomparable super-types exists in `col`, them no solution is given and the `null`
649 # value is returned (since union types are non representable in Nit)
650 #
651 # The `null` values in `col` are ignored, nulltypes (MNullType) are considered.
652 #
653 # Returns the `null` value if:
654 #
655 # * `col` is empty
656 # * `col` only have null values
657 # * there is a conflict
658 #
659 # Example (with a diamond A,B,C,D):
660 #
661 # * merge(A,B,C) -> A, because A is the most general type in {A,B,C}
662 # * merge(C,B) -> null, there is conflict, because `B or C` cannot be represented
663 # * merge(A,nullable B) -> nullable A, because A is the most general type and
664 # the nullable information is preserved
665 fun merge_types(node: ANode, col: Array[nullable MType]): nullable MType
666 do
667 if col.length == 1 then return col.first
668 for t1 in col do
669 if t1 == null then continue # return null
670 var found = true
671 for t2 in col do
672 if t2 == null then continue # return null
673 if can_be_null(t2) and not can_be_null(t1) then
674 t1 = t1.as_nullable
675 end
676 if not is_subtype(t2, t1) then found = false
677 end
678 if found then
679 #print "merge {col.join(" ")} -> {t1}"
680 return t1
681 end
682 end
683 #self.modelbuilder.warning(node, "Type Error: {col.length} conflicting types: <{col.join(", ")}>")
684 return null
685 end
686
687 # Find a most general common subtype between `type1` and `type2`.
688 #
689 # Find the most general type that is a subtype of `type2` and, if possible, a subtype of `type1`.
690 # Basically, this return the most specific type between `type1` and `type2`.
691 # If nullable types are involved, the information is correctly preserved.
692 # If `type1` and `type2` are incomparable then `type2` is preferred (since intersection types
693 # are not representable in Nit).
694 #
695 # The `null` value is returned if both `type1` and `type2` are null.
696 #
697 # Examples (with diamond A,B,C,D):
698 #
699 # * intersect_types(A,B) -> B, because B is a subtype of A
700 # * intersect_types(B,A) -> B, because B is a subtype of A
701 # * intersect_types(B,C) -> C, B and C are incomparable,
702 # `type2` is then preferred (`B and C` cannot be represented)
703 # * intersect_types(nullable B,A) -> B, because B<:A and the non-null information is preserved
704 # * intersect_types(B,nullable C) -> C, `type2` is preferred and the non-null information is preserved
705 fun intersect_types(node: ANode, type1, type2: nullable MType): nullable MType
706 do
707 if type1 == null then return type2
708 if type2 == null then return type1
709
710 if not can_be_null(type2) or not can_be_null(type1) then
711 type1 = type1.as_notnull
712 type2 = type2.as_notnull
713 end
714
715 var res
716 if is_subtype(type1, type2) then
717 res = type1
718 else
719 res = type2
720 end
721 return res
722 end
723
724 # Find a most general type that is a subtype of `type1` but not one of `type2`.
725 #
726 # Basically, this returns `type1`-`type2` but since there is no substraction type
727 # in Nit this just returns `type1` most of the case.
728 #
729 # The few other cases are if `type2` is a super-type and if some nullable information
730 # is present.
731 #
732 # The `null` value is returned if `type1` is null.
733 #
734 # Examples (with diamond A,B,C,D):
735 #
736 # * diff_types(A,B) -> A, because the notB cannot be represented
737 # * diff_types(B,A) -> None (absurd type), because B<:A
738 # * diff_types(nullable A, nullable B) -> A, because null is removed
739 # * diff_types(nullable B, A) -> Null, because anything but null is removed
740 fun diff_types(node: ANode, type1, type2: nullable MType): nullable MType
741 do
742 if type1 == null then return null
743 if type2 == null then return type1
744
745 # if t1 <: t2 then t1-t2 = bottom
746 if is_subtype(type1, type2) then
747 return modelbuilder.model.null_type.as_notnull
748 end
749
750 # else if t1 <: nullable t2 then t1-t2 = nulltype
751 if is_subtype(type1, type2.as_nullable) then
752 return modelbuilder.model.null_type
753 end
754
755 # else t2 can be null and type2 must accept null then null is excluded in t1
756 if can_be_null(type1) and (type2 isa MNullableType or type2 isa MNullType) then
757 return type1.as_notnull
758 end
759
760 return type1
761 end
762 end
763
764 # Mapping between parameters and arguments in a call.
765 #
766 # Parameters and arguments are not stored in the class but referenced by their position (starting from 0)
767 #
768 # The point of this class is to help engine and other things to map arguments in the AST to parameters of the model.
769 class SignatureMap
770 # Associate a parameter to an argument
771 var map = new ArrayMap[Int, Int]
772 end
773
774 # A specific method call site with its associated informations.
775 class CallSite
776 super MEntity
777
778 redef var location
779
780 # The static type of the receiver (possibly unresolved)
781 var recv: MType
782
783 # The module where the callsite is present
784 var mmodule: MModule
785
786 # The anchor to use with `recv` or `msignature`
787 var anchor: nullable MClassType
788
789 # Is the receiver self?
790 # If "for_self", virtual types of the signature are kept
791 # If "not_for_self", virtual type are erased
792 var recv_is_self: Bool
793
794 # The designated method
795 var mproperty: MMethod
796
797 # The statically designated method definition
798 # The most specif one, it is.
799 var mpropdef: MMethodDef
800
801 # The resolved signature for the receiver
802 var msignature: MSignature
803
804 # Is a implicit cast required on erasure typing policy?
805 var erasure_cast: Bool
806
807 # The mapping used on the call to associate arguments to parameters
808 # If null then no specific association is required.
809 var signaturemap: nullable SignatureMap = null
810
811 private fun check_signature(v: TypeVisitor, node: ANode, args: Array[AExpr]): Bool
812 do
813 var map = v.check_signature(node, args, self.mproperty, self.msignature)
814 signaturemap = map
815 if map == null then is_broken = true
816 return map == null
817 end
818
819 # Information about the callsite to display on a node
820 fun dump_info(v: ASTDump): String do
821 return "{recv}.{mpropdef}{msignature}"
822 end
823
824 redef fun mdoc_or_fallback do return mproperty.intro.mdoc
825 end
826
827 redef class Variable
828 # The declared type of the variable
829 var declared_type: nullable MType = null is writable
830
831 # Was the variable type-adapted?
832 # This is used to speedup type retrieval while it remains `false`
833 private var is_adapted = false
834 end
835
836 redef class FlowContext
837 # Store changes of types because of type evolution
838 private var vars = new HashMap[Variable, nullable MType]
839
840 # Adapt the variable to a static type
841 # Warning1: do not modify vars directly.
842 # Warning2: sub-flow may have cached a unadapted variable
843 private fun set_var(v: TypeVisitor, variable: Variable, mtype: nullable MType)
844 do
845 if variable.declared_type == mtype and not variable.is_adapted then return
846 if vars.has_key(variable) and vars[variable] == mtype then return
847 self.vars[variable] = mtype
848 v.dirty = true
849 variable.is_adapted = true
850 #node.debug "set {variable} to {mtype or else "X"}"
851 end
852
853 # Look in the flow and previous flow and collect all first reachable type adaptation of a local variable
854 private fun collect_types(variable: Variable): Array[nullable MType]
855 do
856 #node.debug "flow for {variable}"
857 var res = new Array[nullable MType]
858
859 var todo = [self]
860 var seen = new HashSet[FlowContext]
861 while not todo.is_empty do
862 var f = todo.pop
863 if f.is_unreachable then continue
864 if seen.has(f) then continue
865 seen.add f
866
867 if f.vars.has_key(variable) then
868 # Found something. Collect it and do not process further on this path
869 res.add f.vars[variable]
870 #f.node.debug "process {variable}: got {f.vars[variable] or else "X"}"
871 else
872 todo.add_all f.previous
873 todo.add_all f.loops
874 if f.previous.is_empty then
875 # Root flowcontext mean a parameter or something related
876 res.add variable.declared_type
877 #f.node.debug "root process {variable}: got {variable.declared_type or else "X"}"
878 end
879 end
880 end
881 #self.node.debug "##### end flow for {variable}: {res.join(" ")}"
882 return res
883 end
884 end
885
886 redef class APropdef
887 # The entry point of the whole typing analysis
888 fun do_typing(modelbuilder: ModelBuilder)
889 do
890 end
891
892 # The variable associated to the receiver (if any)
893 var selfvariable: nullable Variable
894 end
895
896 redef class AMethPropdef
897 redef fun do_typing(modelbuilder: ModelBuilder)
898 do
899 var mpropdef = self.mpropdef
900 if mpropdef == null then return # skip error
901
902 var v = new TypeVisitor(modelbuilder, mpropdef)
903 self.selfvariable = v.selfvariable
904
905 var mmethoddef = self.mpropdef.as(not null)
906 var msignature = mmethoddef.msignature
907 if msignature == null then return # skip error
908 for i in [0..msignature.arity[ do
909 var mtype = msignature.mparameters[i].mtype
910 if msignature.vararg_rank == i then
911 var arrayclass = v.get_mclass(self.n_signature.n_params[i], "Array")
912 if arrayclass == null then return # Skip error
913 mtype = arrayclass.get_mtype([mtype])
914 end
915 var variable = self.n_signature.n_params[i].variable
916 assert variable != null
917 variable.declared_type = mtype
918 end
919
920 var nblock = self.n_block
921 if nblock == null then return
922
923 loop
924 v.dirty = false
925 v.visit_stmt(nblock)
926 if not v.has_loop or not v.dirty then break
927 end
928
929 var post_visitor = new PostTypingVisitor(v)
930 post_visitor.enter_visit(self)
931
932 if not nblock.after_flow_context.is_unreachable and msignature.return_mtype != null then
933 # We reach the end of the function without having a return, it is bad
934 v.error(self, "Error: reached end of function; expected `return` with a value.")
935 end
936 end
937 end
938
939 private class PostTypingVisitor
940 super Visitor
941 var type_visitor: TypeVisitor
942 redef fun visit(n) do
943 n.visit_all(self)
944 n.accept_post_typing(type_visitor)
945 if n isa AExpr and n.mtype == null and not n.is_typed then
946 n.is_broken = true
947 end
948 end
949 end
950
951 redef class ANode
952 private fun accept_post_typing(v: TypeVisitor) do end
953
954 # An additional information message to explain the role of a child expression.
955 #
956 # The point of the method is to allow some kind of double dispatch so the parent
957 # choose how to describe its children.
958 private fun bad_expr_message(child: AExpr): nullable String do return null
959 end
960
961 redef class AAttrPropdef
962 redef fun do_typing(modelbuilder: ModelBuilder)
963 do
964 if not has_value then return
965
966 var mpropdef = self.mreadpropdef
967 if mpropdef == null or mpropdef.msignature == null then return # skip error
968
969 var v = new TypeVisitor(modelbuilder, mpropdef)
970 self.selfvariable = v.selfvariable
971
972 var nexpr = self.n_expr
973 if nexpr != null then
974 var mtype = self.mtype
975 v.visit_expr_subtype(nexpr, mtype)
976 end
977 var nblock = self.n_block
978 if nblock != null then
979 v.visit_stmt(nblock)
980 if not nblock.after_flow_context.is_unreachable then
981 # We reach the end of the init without having a return, it is bad
982 v.error(self, "Error: reached end of block; expected `return`.")
983 end
984 end
985 end
986 end
987
988 ###
989
990 redef class AExpr
991 # The static type of the expression.
992 # null if self is a statement or in case of error
993 var mtype: nullable MType = null
994
995 # Is the statement correctly typed?
996 # Used to distinguish errors and statements when `mtype == null`
997 var is_typed: Bool = false
998
999 # If required, the following implicit cast `.as(XXX)`
1000 # Such a cast may by required after evaluating the expression when
1001 # a unsafe operation is detected (silently accepted by the Nit language).
1002 # The attribute is computed by `check_subtype`
1003 var implicit_cast_to: nullable MType = null
1004
1005 # Return the variable read (if any)
1006 # Used to perform adaptive typing
1007 fun its_variable: nullable Variable do return null
1008
1009 private fun accept_typing(v: TypeVisitor)
1010 do
1011 v.error(self, "no implemented accept_typing for {self.class_name}")
1012 end
1013
1014 # Is non-null if `self` is a leaf of a comprehension array construction.
1015 # In this case, the enclosing literal array node is designated.
1016 # The result of the evaluation of `self` must be
1017 # stored inside the designated array (there is an implicit `push`)
1018 var comprehension: nullable AArrayExpr = null
1019
1020 # It indicates the number of arguments collected as a vararg.
1021 #
1022 # When 0, the argument is used as is, without transformation.
1023 # When 1, the argument is transformed into an singleton array.
1024 # Above 1, the arguments and the next ones are transformed into a common array.
1025 #
1026 # This attribute is meaning less on expressions not used as attributes.
1027 var vararg_decl: Int = 0
1028
1029 redef fun dump_info(v) do
1030 var res = super
1031 var mtype = self.mtype
1032 if mtype != null then
1033 res += v.yellow(":{mtype}")
1034 end
1035 var ict = self.implicit_cast_to
1036 if ict != null then
1037 res += v.yellow("(.as({ict}))")
1038 end
1039 return res
1040 end
1041 end
1042
1043 redef class ABlockExpr
1044 redef fun accept_typing(v)
1045 do
1046 for e in self.n_expr do v.visit_stmt(e)
1047 self.is_typed = true
1048 end
1049
1050 # The type of a blockexpr is the one of the last expression (or null if empty)
1051 redef fun mtype
1052 do
1053 if self.n_expr.is_empty then return null
1054 return self.n_expr.last.mtype
1055 end
1056 end
1057
1058 redef class AVardeclExpr
1059 redef fun accept_typing(v)
1060 do
1061 var variable = self.variable
1062 if variable == null then return # Skip error
1063
1064 var ntype = self.n_type
1065 var mtype: nullable MType
1066 if ntype == null then
1067 mtype = null
1068 else
1069 mtype = v.resolve_mtype(ntype)
1070 if mtype == null then return # Skip error
1071 end
1072
1073 var nexpr = self.n_expr
1074 if nexpr != null then
1075 if mtype != null then
1076 var etype = v.visit_expr_subtype(nexpr, mtype)
1077 if etype == mtype then
1078 assert ntype != null
1079 v.modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition for variable `{variable.name}`")
1080 end
1081 else
1082 mtype = v.visit_expr(nexpr)
1083 if mtype == null then return # Skip error
1084 end
1085 end
1086
1087 var decltype = mtype
1088 if mtype == null or mtype isa MNullType then
1089 var objclass = v.get_mclass(self, "Object")
1090 if objclass == null then return # skip error
1091 decltype = objclass.mclass_type.as_nullable
1092 if mtype == null then mtype = decltype
1093 end
1094
1095 variable.declared_type = decltype
1096 v.set_variable(self, variable, mtype)
1097
1098 #debug("var {variable}: {mtype}")
1099
1100 self.mtype = mtype
1101 self.is_typed = true
1102 end
1103 end
1104
1105 redef class AVarExpr
1106 redef fun its_variable do return self.variable
1107 redef fun accept_typing(v)
1108 do
1109 var variable = self.variable
1110 if variable == null then return # Skip error
1111
1112 var mtype = v.get_variable(self, variable)
1113 if mtype != null then
1114 #debug("{variable} is {mtype}")
1115 else
1116 #debug("{variable} is untyped")
1117 end
1118
1119 self.mtype = mtype
1120 end
1121 end
1122
1123 redef class AVarAssignExpr
1124 redef fun accept_typing(v)
1125 do
1126 var variable = self.variable
1127 assert variable != null
1128
1129 var mtype = v.visit_expr_subtype(n_value, variable.declared_type)
1130
1131 v.set_variable(self, variable, mtype)
1132
1133 self.is_typed = true
1134 end
1135 end
1136
1137 redef class AReassignFormExpr
1138 # The method designed by the reassign operator.
1139 var reassign_callsite: nullable CallSite
1140
1141 var read_type: nullable MType = null
1142
1143 # Determine the `reassign_property`
1144 # `readtype` is the type of the reading of the left value.
1145 # `writetype` is the type of the writing of the left value.
1146 # (Because of `ACallReassignExpr`, both can be different.
1147 # Return the static type of the value to store.
1148 private fun resolve_reassignment(v: TypeVisitor, readtype, writetype: MType): nullable MType
1149 do
1150 var reassign_name = self.n_assign_op.operator
1151
1152 self.read_type = readtype
1153
1154 var callsite = v.build_callsite_by_name(self.n_assign_op, readtype, reassign_name, false)
1155 if callsite == null then return null # Skip error
1156 self.reassign_callsite = callsite
1157
1158 var msignature = callsite.msignature
1159 var rettype = msignature.return_mtype
1160 assert msignature.arity == 1 and rettype != null
1161
1162 var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype)
1163 if value_type == null then return null # Skip error
1164
1165 v.check_subtype(self, rettype, writetype, false)
1166 return rettype
1167 end
1168 end
1169
1170 redef class AVarReassignExpr
1171 redef fun accept_typing(v)
1172 do
1173 var variable = self.variable
1174 assert variable != null
1175
1176 var readtype = v.get_variable(self, variable)
1177 if readtype == null then return
1178
1179 read_type = readtype
1180
1181 var writetype = variable.declared_type
1182 if writetype == null then return
1183
1184 var rettype = self.resolve_reassignment(v, readtype, writetype)
1185
1186 v.set_variable(self, variable, rettype)
1187
1188 self.is_typed = rettype != null
1189 end
1190 end
1191
1192 redef class AContinueExpr
1193 redef fun accept_typing(v)
1194 do
1195 var nexpr = self.n_expr
1196 if nexpr != null then
1197 v.visit_expr(nexpr)
1198 end
1199 self.is_typed = true
1200 end
1201 end
1202
1203 redef class ABreakExpr
1204 redef fun accept_typing(v)
1205 do
1206 var nexpr = self.n_expr
1207 if nexpr != null then
1208 v.visit_expr(nexpr)
1209 end
1210 self.is_typed = true
1211 end
1212 end
1213
1214 redef class AReturnExpr
1215 redef fun accept_typing(v)
1216 do
1217 var nexpr = self.n_expr
1218 var ret_type
1219 var mpropdef = v.mpropdef
1220 if mpropdef isa MMethodDef then
1221 ret_type = mpropdef.msignature.return_mtype
1222 else if mpropdef isa MAttributeDef then
1223 ret_type = mpropdef.static_mtype
1224 else
1225 abort
1226 end
1227 if nexpr != null then
1228 if ret_type != null then
1229 v.visit_expr_subtype(nexpr, ret_type)
1230 else
1231 v.visit_expr(nexpr)
1232 v.error(nexpr, "Error: `return` with value in a procedure.")
1233 return
1234 end
1235 else if ret_type != null then
1236 v.error(self, "Error: `return` without value in a function.")
1237 return
1238 end
1239 self.is_typed = true
1240 end
1241 end
1242
1243 redef class AAbortExpr
1244 redef fun accept_typing(v)
1245 do
1246 self.is_typed = true
1247 end
1248 end
1249
1250 redef class AIfExpr
1251 redef fun accept_typing(v)
1252 do
1253 v.visit_expr_bool(n_expr)
1254
1255 v.visit_stmt(n_then)
1256 v.visit_stmt(n_else)
1257
1258 self.is_typed = true
1259
1260 if n_then != null and n_else == null then
1261 self.mtype = n_then.mtype
1262 end
1263 end
1264 end
1265
1266 redef class AIfexprExpr
1267 redef fun accept_typing(v)
1268 do
1269 v.visit_expr_bool(n_expr)
1270
1271 var t1 = v.visit_expr(n_then)
1272 var t2 = v.visit_expr(n_else)
1273
1274 if t1 == null or t2 == null then
1275 return # Skip error
1276 end
1277
1278 var t = v.merge_types(self, [t1, t2])
1279 if t == null then
1280 v.error(self, "Type Error: ambiguous type `{t1}` vs `{t2}`.")
1281 end
1282 self.mtype = t
1283 end
1284 end
1285
1286 redef class ADoExpr
1287 redef fun accept_typing(v)
1288 do
1289 v.visit_stmt(n_block)
1290 v.visit_stmt(n_catch)
1291 self.is_typed = true
1292 end
1293 end
1294
1295 redef class AWhileExpr
1296 redef fun accept_typing(v)
1297 do
1298 v.has_loop = true
1299 v.visit_expr_bool(n_expr)
1300 v.visit_stmt(n_block)
1301 self.is_typed = true
1302 end
1303 end
1304
1305 redef class ALoopExpr
1306 redef fun accept_typing(v)
1307 do
1308 v.has_loop = true
1309 v.visit_stmt(n_block)
1310 self.is_typed = true
1311 end
1312 end
1313
1314 redef class AForExpr
1315 redef fun accept_typing(v)
1316 do
1317 v.has_loop = true
1318
1319 for g in n_groups do
1320 var mtype = v.visit_expr(g.n_expr)
1321 if mtype == null then return
1322 g.do_type_iterator(v, mtype)
1323 if g.is_broken then is_broken = true
1324 end
1325
1326 v.visit_stmt(n_block)
1327
1328 self.mtype = n_block.mtype
1329 self.is_typed = true
1330 end
1331 end
1332
1333 redef class AForGroup
1334 var coltype: nullable MClassType
1335
1336 var method_iterator: nullable CallSite
1337 var method_is_ok: nullable CallSite
1338 var method_item: nullable CallSite
1339 var method_next: nullable CallSite
1340 var method_key: nullable CallSite
1341 var method_finish: nullable CallSite
1342
1343 var method_lt: nullable CallSite
1344 var method_successor: nullable CallSite
1345
1346 private fun do_type_iterator(v: TypeVisitor, mtype: MType)
1347 do
1348 if mtype isa MNullType then
1349 v.error(self, "Type Error: `for` cannot iterate over `null`.")
1350 return
1351 end
1352
1353 # get obj class
1354 var objcla = v.get_mclass(self, "Object")
1355 if objcla == null then return
1356
1357 # check iterator method
1358 var itdef = v.build_callsite_by_name(self, mtype, "iterator", n_expr isa ASelfExpr)
1359 if itdef == null then
1360 v.error(self, "Type Error: `for` expects a type providing an `iterator` method, got `{mtype}`.")
1361 return
1362 end
1363 self.method_iterator = itdef
1364
1365 # check that iterator return something
1366 var ittype = itdef.msignature.return_mtype
1367 if ittype == null then
1368 v.error(self, "Type Error: `for` expects the method `iterator` to return an `Iterator` or `MapIterator` type.")
1369 return
1370 end
1371
1372 # get iterator type
1373 var colit_cla = v.try_get_mclass(self, "Iterator")
1374 var mapit_cla = v.try_get_mclass(self, "MapIterator")
1375 var is_col = false
1376 var is_map = false
1377
1378 if colit_cla != null and v.is_subtype(ittype, colit_cla.get_mtype([objcla.mclass_type.as_nullable])) then
1379 # Iterator
1380 var coltype = ittype.supertype_to(v.mmodule, v.anchor, colit_cla)
1381 var variables = self.variables
1382 if variables.length != 1 then
1383 v.error(self, "Type Error: `for` expects only one variable when using `Iterator`.")
1384 else
1385 variables.first.declared_type = coltype.arguments.first
1386 end
1387 is_col = true
1388 end
1389
1390 if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type.as_nullable, objcla.mclass_type.as_nullable])) then
1391 # Map Iterator
1392 var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
1393 var variables = self.variables
1394 if variables.length != 2 then
1395 v.error(self, "Type Error: `for` expects two variables when using `MapIterator`.")
1396 else
1397 variables[0].declared_type = coltype.arguments[0]
1398 variables[1].declared_type = coltype.arguments[1]
1399 end
1400 is_map = true
1401 end
1402
1403 if not is_col and not is_map then
1404 v.error(self, "Type Error: `for` expects the method `iterator` to return an `Iterator` or `MapIterator` type.")
1405 return
1406 end
1407
1408 # anchor formal and virtual types
1409 if mtype.need_anchor then mtype = v.anchor_to(mtype)
1410
1411 mtype = mtype.undecorate
1412 self.coltype = mtype.as(MClassType)
1413
1414 # get methods is_ok, next, item
1415 var ikdef = v.build_callsite_by_name(self, ittype, "is_ok", false)
1416 if ikdef == null then
1417 v.error(self, "Type Error: `for` expects a method `is_ok` in type `{ittype}`.")
1418 return
1419 end
1420 self.method_is_ok = ikdef
1421
1422 var itemdef = v.build_callsite_by_name(self, ittype, "item", false)
1423 if itemdef == null then
1424 v.error(self, "Type Error: `for` expects a method `item` in type `{ittype}`.")
1425 return
1426 end
1427 self.method_item = itemdef
1428
1429 var nextdef = v.build_callsite_by_name(self, ittype, "next", false)
1430 if nextdef == null then
1431 v.error(self, "Type Error: `for` expects a method `next` in type {ittype}.")
1432 return
1433 end
1434 self.method_next = nextdef
1435
1436 self.method_finish = v.try_build_callsite_by_name(self, ittype, "finish", false)
1437
1438 if is_map then
1439 var keydef = v.build_callsite_by_name(self, ittype, "key", false)
1440 if keydef == null then
1441 v.error(self, "Type Error: `for` expects a method `key` in type `{ittype}`.")
1442 return
1443 end
1444 self.method_key = keydef
1445 end
1446
1447 if self.variables.length == 1 and n_expr isa ARangeExpr then
1448 var variable = variables.first
1449 var vtype = variable.declared_type.as(not null)
1450
1451 if n_expr isa AOrangeExpr then
1452 self.method_lt = v.build_callsite_by_name(self, vtype, "<", false)
1453 else
1454 self.method_lt = v.build_callsite_by_name(self, vtype, "<=", false)
1455 end
1456
1457 self.method_successor = v.build_callsite_by_name(self, vtype, "successor", false)
1458 end
1459 end
1460 end
1461
1462 redef class AWithExpr
1463 var method_start: nullable CallSite
1464 var method_finish: nullable CallSite
1465
1466 redef fun accept_typing(v: TypeVisitor)
1467 do
1468 var mtype = v.visit_expr(n_expr)
1469 if mtype == null then return
1470
1471 method_start = v.build_callsite_by_name(self, mtype, "start", n_expr isa ASelfExpr)
1472 method_finish = v.build_callsite_by_name(self, mtype, "finish", n_expr isa ASelfExpr)
1473
1474 v.visit_stmt(n_block)
1475 self.mtype = n_block.mtype
1476 self.is_typed = true
1477 end
1478 end
1479
1480 redef class AAssertExpr
1481 redef fun accept_typing(v)
1482 do
1483 v.visit_expr_bool(n_expr)
1484
1485 v.visit_stmt(n_else)
1486 self.is_typed = true
1487 end
1488 end
1489
1490 redef class AOrExpr
1491 redef fun accept_typing(v)
1492 do
1493 v.visit_expr_bool(n_expr)
1494 v.visit_expr_bool(n_expr2)
1495 self.mtype = v.type_bool(self)
1496 end
1497 end
1498
1499 redef class AImpliesExpr
1500 redef fun accept_typing(v)
1501 do
1502 v.visit_expr_bool(n_expr)
1503 v.visit_expr_bool(n_expr2)
1504 self.mtype = v.type_bool(self)
1505 end
1506 end
1507
1508 redef class AAndExpr
1509 redef fun accept_typing(v)
1510 do
1511 v.visit_expr_bool(n_expr)
1512 v.visit_expr_bool(n_expr2)
1513 self.mtype = v.type_bool(self)
1514 end
1515 end
1516
1517 redef class ANotExpr
1518 redef fun accept_typing(v)
1519 do
1520 v.visit_expr_bool(n_expr)
1521 self.mtype = v.type_bool(self)
1522 end
1523 end
1524
1525 redef class AOrElseExpr
1526 redef fun accept_typing(v)
1527 do
1528 var t1 = v.visit_expr(n_expr)
1529 var t2 = v.visit_expr(n_expr2)
1530
1531 if t1 == null or t2 == null then
1532 return # Skip error
1533 end
1534
1535 if t1 isa MNullType then
1536 self.mtype = t2
1537 return
1538 else if v.can_be_null(t1) then
1539 t1 = t1.as_notnull
1540 end
1541
1542 var t = v.merge_types(self, [t1, t2])
1543 if t == null then
1544 var c = v.get_mclass(self, "Object")
1545 if c == null then return # forward error
1546 t = c.mclass_type
1547 if v.can_be_null(t2) then
1548 t = t.as_nullable
1549 end
1550 #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
1551 end
1552 self.mtype = t
1553 end
1554
1555 redef fun accept_post_typing(v)
1556 do
1557 var t1 = n_expr.mtype
1558 if t1 == null then
1559 return
1560 else
1561 v.check_can_be_null(n_expr, t1)
1562 end
1563 end
1564 end
1565
1566 redef class ATrueExpr
1567 redef fun accept_typing(v)
1568 do
1569 self.mtype = v.type_bool(self)
1570 end
1571 end
1572
1573 redef class AFalseExpr
1574 redef fun accept_typing(v)
1575 do
1576 self.mtype = v.type_bool(self)
1577 end
1578 end
1579
1580 redef class AIntegerExpr
1581 redef fun accept_typing(v)
1582 do
1583 var mclass: nullable MClass = null
1584 if value isa Byte then
1585 mclass = v.get_mclass(self, "Byte")
1586 else if value isa Int then
1587 mclass = v.get_mclass(self, "Int")
1588 else if value isa Int8 then
1589 mclass = v.get_mclass(self, "Int8")
1590 else if value isa Int16 then
1591 mclass = v.get_mclass(self, "Int16")
1592 else if value isa UInt16 then
1593 mclass = v.get_mclass(self, "UInt16")
1594 else if value isa Int32 then
1595 mclass = v.get_mclass(self, "Int32")
1596 else if value isa UInt32 then
1597 mclass = v.get_mclass(self, "UInt32")
1598 end
1599 if mclass == null then return # Forward error
1600 self.mtype = mclass.mclass_type
1601 end
1602 end
1603
1604 redef class AFloatExpr
1605 redef fun accept_typing(v)
1606 do
1607 var mclass = v.get_mclass(self, "Float")
1608 if mclass == null then return # Forward error
1609 self.mtype = mclass.mclass_type
1610 end
1611 end
1612
1613 redef class ACharExpr
1614 redef fun accept_typing(v) do
1615 var mclass: nullable MClass = null
1616 if is_code_point then
1617 mclass = v.get_mclass(self, "Int")
1618 else
1619 mclass = v.get_mclass(self, "Char")
1620 end
1621 if mclass == null then return # Forward error
1622 self.mtype = mclass.mclass_type
1623 end
1624 end
1625
1626 redef class AugmentedStringFormExpr
1627 super AExpr
1628
1629 # Text::to_re, used for prefix `re`
1630 var to_re: nullable CallSite = null
1631 # Regex::ignore_case, used for suffix `i` on `re`
1632 var ignore_case: nullable CallSite = null
1633 # Regex::newline, used for suffix `m` on `re`
1634 var newline: nullable CallSite = null
1635 # Regex::extended, used for suffix `b` on `re`
1636 var extended: nullable CallSite = null
1637 # CString::to_bytes_with_copy, used for prefix `b`
1638 var to_bytes_with_copy: nullable CallSite = null
1639
1640 redef fun accept_typing(v) do
1641 var mclass = v.get_mclass(self, "String")
1642 if mclass == null then return # Forward error
1643 if is_bytestring then
1644 to_bytes_with_copy = v.build_callsite_by_name(self, v.mmodule.c_string_type, "to_bytes_with_copy", false)
1645 mclass = v.get_mclass(self, "Bytes")
1646 else if is_re then
1647 to_re = v.build_callsite_by_name(self, mclass.mclass_type, "to_re", false)
1648 for i in suffix.chars do
1649 mclass = v.get_mclass(self, "Regex")
1650 if mclass == null then
1651 v.error(self, "Error: `Regex` class unknown")
1652 return
1653 end
1654 var service = ""
1655 if i == 'i' then
1656 service = "ignore_case="
1657 ignore_case = v.build_callsite_by_name(self, mclass.mclass_type, service, false)
1658 else if i == 'm' then
1659 service = "newline="
1660 newline = v.build_callsite_by_name(self, mclass.mclass_type, service, false)
1661 else if i == 'b' then
1662 service = "extended="
1663 extended = v.build_callsite_by_name(self, mclass.mclass_type, service, false)
1664 else
1665 v.error(self, "Type Error: Unrecognized suffix {i} in prefixed Regex")
1666 abort
1667 end
1668 end
1669 end
1670 if mclass == null then return # Forward error
1671 mtype = mclass.mclass_type
1672 end
1673 end
1674
1675 redef class ASuperstringExpr
1676 redef fun accept_typing(v)
1677 do
1678 super
1679 var objclass = v.get_mclass(self, "Object")
1680 if objclass == null then return # Forward error
1681 var objtype = objclass.mclass_type
1682 for nexpr in self.n_exprs do
1683 v.visit_expr_subtype(nexpr, objtype)
1684 end
1685 end
1686 end
1687
1688 redef class AArrayExpr
1689 # The `with_capacity` method on Array
1690 var with_capacity_callsite: nullable CallSite
1691
1692 # The `push` method on arrays
1693 var push_callsite: nullable CallSite
1694
1695 # The element of each type
1696 var element_mtype: nullable MType
1697
1698 # Set that `self` is a part of comprehension array `na`
1699 # If `self` is a `for`, or a `if`, then `set_comprehension` is recursively applied.
1700 private fun set_comprehension(n: nullable AExpr)
1701 do
1702 if n == null then
1703 return
1704 else if n isa AForExpr then
1705 set_comprehension(n.n_block)
1706 else if n isa AIfExpr then
1707 set_comprehension(n.n_then)
1708 set_comprehension(n.n_else)
1709 else
1710 # is a leave
1711 n.comprehension = self
1712 end
1713 end
1714 redef fun accept_typing(v)
1715 do
1716 var mtype: nullable MType = null
1717 var ntype = self.n_type
1718 if ntype != null then
1719 mtype = v.resolve_mtype(ntype)
1720 if mtype == null then return # Skip error
1721 end
1722 var mtypes = new Array[nullable MType]
1723 var useless = false
1724 for e in self.n_exprs do
1725 var t = v.visit_expr(e)
1726 if t == null then
1727 return # Skip error
1728 end
1729 set_comprehension(e)
1730 if mtype != null then
1731 if v.check_subtype(e, t, mtype, false) == null then return # Forward error
1732 if t == mtype then useless = true
1733 else
1734 mtypes.add(t)
1735 end
1736 end
1737 if mtype == null then
1738 # Ensure monotony for type adaptation on loops
1739 if self.element_mtype != null then mtypes.add self.element_mtype
1740 mtype = v.merge_types(self, mtypes)
1741 end
1742 if mtype == null or mtype isa MNullType then
1743 v.error(self, "Type Error: ambiguous array type {mtypes.join(" ")}")
1744 return
1745 end
1746 if useless then
1747 assert ntype != null
1748 v.display_warning(ntype, "useless-type", "Warning: useless type declaration `{mtype}` in literal Array since it can be inferred from the elements type.")
1749 end
1750
1751 self.element_mtype = mtype
1752
1753 var mclass = v.get_mclass(self, "Array")
1754 if mclass == null then return # Forward error
1755 var array_mtype = mclass.get_mtype([mtype])
1756
1757 with_capacity_callsite = v.build_callsite_by_name(self, array_mtype, "with_capacity", false)
1758 push_callsite = v.build_callsite_by_name(self, array_mtype, "push", false)
1759
1760 self.mtype = array_mtype
1761 end
1762 end
1763
1764 redef class ARangeExpr
1765 var init_callsite: nullable CallSite
1766
1767 redef fun accept_typing(v)
1768 do
1769 var discrete_class = v.get_mclass(self, "Discrete")
1770 if discrete_class == null then return # Forward error
1771 var discrete_type = discrete_class.intro.bound_mtype
1772 var t1 = v.visit_expr_subtype(self.n_expr, discrete_type)
1773 var t2 = v.visit_expr_subtype(self.n_expr2, discrete_type)
1774 if t1 == null or t2 == null then return
1775 var mclass = v.get_mclass(self, "Range")
1776 if mclass == null then return # Forward error
1777 var mtype
1778 if v.is_subtype(t1, t2) then
1779 mtype = mclass.get_mtype([t2])
1780 else if v.is_subtype(t2, t1) then
1781 mtype = mclass.get_mtype([t1])
1782 else
1783 v.error(self, "Type Error: cannot create range: `{t1}` vs `{t2}`.")
1784 return
1785 end
1786
1787 self.mtype = mtype
1788
1789 # get the constructor
1790 var callsite
1791 if self isa ACrangeExpr then
1792 callsite = v.build_callsite_by_name(self, mtype, "defaultinit", false)
1793 else if self isa AOrangeExpr then
1794 callsite = v.build_callsite_by_name(self, mtype, "without_last", false)
1795 else
1796 abort
1797 end
1798 init_callsite = callsite
1799 end
1800 end
1801
1802 redef class ANullExpr
1803 redef fun accept_typing(v)
1804 do
1805 self.mtype = v.mmodule.model.null_type
1806 end
1807 end
1808
1809 redef class AIsaExpr
1810 # The static type to cast to.
1811 # (different from the static type of the expression that is `Bool`).
1812 var cast_type: nullable MType
1813 redef fun accept_typing(v)
1814 do
1815 v.visit_expr(n_expr)
1816
1817 var mtype = v.resolve_mtype(n_type)
1818
1819 self.cast_type = mtype
1820
1821 var variable = self.n_expr.its_variable
1822 if variable != null then
1823 var orig = self.n_expr.mtype
1824 #var from = if orig != null then orig.to_s else "invalid"
1825 #var to = if mtype != null then mtype.to_s else "invalid"
1826 #debug("adapt {variable}: {from} -> {to}")
1827
1828 var thentype = v.intersect_types(self, orig, mtype)
1829 if thentype != orig then
1830 self.after_flow_context.when_true.set_var(v, variable, thentype)
1831 #debug "{variable}:{orig or else "?"} isa {mtype or else "?"} -> then {thentype or else "?"}"
1832 end
1833
1834 var elsetype = v.diff_types(self, orig, mtype)
1835 if elsetype != orig then
1836 self.after_flow_context.when_false.set_var(v, variable, elsetype)
1837 #debug "{variable}:{orig or else "?"} isa {mtype or else "?"} -> else {elsetype or else "?"}"
1838 end
1839 end
1840
1841 self.mtype = v.type_bool(self)
1842 end
1843
1844 redef fun accept_post_typing(v)
1845 do
1846 v.check_expr_cast(self, self.n_expr, self.n_type)
1847 end
1848
1849 redef fun dump_info(v) do
1850 var res = super
1851 var mtype = self.cast_type
1852 if mtype != null then
1853 res += v.yellow(".as({mtype})")
1854 end
1855 return res
1856 end
1857
1858 end
1859
1860 redef class AAsCastExpr
1861 redef fun accept_typing(v)
1862 do
1863 v.visit_expr(n_expr)
1864
1865 self.mtype = v.resolve_mtype(n_type)
1866 end
1867
1868 redef fun accept_post_typing(v)
1869 do
1870 v.check_expr_cast(self, self.n_expr, self.n_type)
1871 end
1872 end
1873
1874 redef class AAsNotnullExpr
1875 redef fun accept_typing(v)
1876 do
1877 var mtype = v.visit_expr(self.n_expr)
1878 if mtype == null then return # Forward error
1879
1880 if mtype isa MNullType then
1881 v.error(self, "Type Error: `as(not null)` on `null`.")
1882 return
1883 end
1884
1885 if v.can_be_null(mtype) then
1886 mtype = mtype.as_notnull
1887 end
1888
1889 self.mtype = mtype
1890 end
1891
1892 redef fun accept_post_typing(v)
1893 do
1894 var mtype = n_expr.mtype
1895 if mtype == null then return
1896 v.check_can_be_null(n_expr, mtype)
1897 end
1898 end
1899
1900 redef class AParExpr
1901 redef fun accept_typing(v)
1902 do
1903 self.mtype = v.visit_expr(self.n_expr)
1904 end
1905 end
1906
1907 redef class AOnceExpr
1908 redef fun accept_typing(v)
1909 do
1910 self.mtype = v.visit_expr(self.n_expr)
1911 end
1912 end
1913
1914 redef class ASelfExpr
1915 redef var its_variable: nullable Variable
1916 redef fun accept_typing(v)
1917 do
1918 if v.is_toplevel_context and not self isa AImplicitSelfExpr then
1919 v.error(self, "Error: `self` cannot be used in top-level method.")
1920 end
1921 var variable = v.selfvariable
1922 self.its_variable = variable
1923 self.mtype = v.get_variable(self, variable)
1924 end
1925 end
1926
1927 redef class AImplicitSelfExpr
1928 # Is the implicit receiver `sys`?
1929 #
1930 # By default, the implicit receiver is `self`.
1931 # But when there is not method for `self`, `sys` is used as a fall-back.
1932 # Is this case this flag is set to `true`.
1933 var is_sys = false
1934 end
1935
1936 ## MESSAGE SENDING AND PROPERTY
1937
1938 redef class ASendExpr
1939 # The property invoked by the send.
1940 var callsite: nullable CallSite
1941
1942 # Is self a safe call (with `x?.foo`)?
1943 # If so and the receiver is null, then the arguments won't be evaluated
1944 # and the call skipped (replaced with null).
1945 var is_safe: Bool = false
1946
1947 redef fun bad_expr_message(child)
1948 do
1949 if child == self.n_expr then
1950 return "to be the receiver of `{self.property_name}`"
1951 end
1952 return null
1953 end
1954
1955 redef fun accept_typing(v)
1956 do
1957 var nrecv = self.n_expr
1958 var recvtype = v.visit_expr(nrecv)
1959
1960 if nrecv isa ASafeExpr then
1961 # Has the receiver the form `x?.foo`?
1962 # For parsing "reasons" the `?` is in the receiver node, not the call node.
1963 is_safe = true
1964 end
1965
1966 var name = self.property_name
1967 var node = self.property_node
1968
1969 if recvtype == null then return # Forward error
1970
1971 var callsite = null
1972 var unsafe_type = v.anchor_to(recvtype)
1973 var mproperty = v.try_get_mproperty_by_name2(node, unsafe_type, name)
1974 if mproperty == null and nrecv isa AImplicitSelfExpr then
1975 # Special fall-back search in `sys` when noting found in the implicit receiver.
1976 var sysclass = v.try_get_mclass(node, "Sys")
1977 if sysclass != null then
1978 var systype = sysclass.mclass_type
1979 mproperty = v.try_get_mproperty_by_name2(node, systype, name)
1980 if mproperty != null then
1981 callsite = v.build_callsite_by_name(node, systype, name, false)
1982 if callsite == null then return # Forward error
1983 # Update information, we are looking at `sys` now, not `self`
1984 nrecv.is_sys = true
1985 nrecv.its_variable = null
1986 nrecv.mtype = systype
1987 recvtype = systype
1988 end
1989 end
1990 end
1991 if callsite == null then
1992 # If still nothing, just exit
1993 callsite = v.build_callsite_by_name(node, recvtype, name, nrecv isa ASelfExpr)
1994 if callsite == null then return
1995 end
1996
1997 self.callsite = callsite
1998 var msignature = callsite.msignature
1999
2000 var args = compute_raw_arguments
2001
2002 if not self isa ACallrefExpr then
2003 callsite.check_signature(v, node, args)
2004 end
2005
2006 if callsite.mproperty.is_init then
2007 var vmpropdef = v.mpropdef
2008 if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
2009 v.error(node, "Error: an `init` can only be called from another `init`.")
2010 end
2011 if vmpropdef isa MMethodDef and vmpropdef.mproperty.is_root_init and not callsite.mproperty.is_root_init then
2012 v.error(node, "Error: `{vmpropdef}` cannot call a factory `{callsite.mproperty}`.")
2013 end
2014 end
2015
2016 var ret = msignature.return_mtype
2017 if ret != null then
2018 if is_safe then
2019 # A safe receiver makes that the call is not executed and returns null
2020 ret = ret.as_nullable
2021 end
2022 self.mtype = ret
2023 else
2024 self.is_typed = true
2025 end
2026 end
2027
2028 # The name of the property
2029 # Each subclass simply provide the correct name.
2030 private fun property_name: String is abstract
2031
2032 # The node identifying the name (id, operator, etc) for messages.
2033 #
2034 # Is `self` by default
2035 private fun property_node: ANode do return self
2036
2037 # An array of all arguments (excluding self)
2038 fun raw_arguments: Array[AExpr] do return compute_raw_arguments
2039
2040 private fun compute_raw_arguments: Array[AExpr] is abstract
2041
2042 redef fun dump_info(v) do
2043 var res = super
2044 var callsite = self.callsite
2045 if callsite != null then
2046 res += v.yellow(" call="+callsite.dump_info(v))
2047 end
2048 return res
2049 end
2050 end
2051
2052 redef class ABinopExpr
2053 redef fun compute_raw_arguments do return [n_expr2]
2054 redef fun property_name do return operator
2055 redef fun property_node do return n_op
2056 end
2057
2058 redef class AEqFormExpr
2059 redef fun accept_typing(v)
2060 do
2061 super
2062 v.null_test(self)
2063 end
2064
2065 redef fun accept_post_typing(v)
2066 do
2067 var mtype = n_expr.mtype
2068 var mtype2 = n_expr2.mtype
2069
2070 if mtype == null or mtype2 == null then return
2071
2072 if mtype == v.type_bool(self) and (n_expr2 isa AFalseExpr or n_expr2 isa ATrueExpr) then
2073 v.display_warning(self, "useless-truism", "Warning: useless comparison to a Bool literal.")
2074 end
2075
2076 if not mtype2 isa MNullType then return
2077
2078 v.check_can_be_null(n_expr, mtype)
2079 end
2080 end
2081
2082 redef class AUnaryopExpr
2083 redef fun property_name do return "unary {operator}"
2084 redef fun compute_raw_arguments do return new Array[AExpr]
2085 end
2086
2087 redef class ACallExpr
2088 redef fun property_name do return n_qid.n_id.text
2089 redef fun property_node do return n_qid
2090 redef fun compute_raw_arguments do return n_args.to_a
2091 end
2092
2093 redef class ACallAssignExpr
2094 redef fun property_name do return n_qid.n_id.text + "="
2095 redef fun property_node do return n_qid
2096 redef fun compute_raw_arguments
2097 do
2098 var res = n_args.to_a
2099 res.add(n_value)
2100 return res
2101 end
2102 end
2103
2104 redef class ABraExpr
2105 redef fun property_name do return "[]"
2106 redef fun compute_raw_arguments do return n_args.to_a
2107 end
2108
2109 redef class ABraAssignExpr
2110 redef fun property_name do return "[]="
2111 redef fun compute_raw_arguments
2112 do
2113 var res = n_args.to_a
2114 res.add(n_value)
2115 return res
2116 end
2117 end
2118
2119 redef class ASendReassignFormExpr
2120 # The property invoked for the writing
2121 var write_callsite: nullable CallSite
2122
2123 redef fun accept_typing(v)
2124 do
2125 var recvtype = v.visit_expr(self.n_expr)
2126 var name = self.property_name
2127 var node = self.property_node
2128
2129 if recvtype == null then return # Forward error
2130
2131 var for_self = self.n_expr isa ASelfExpr
2132 var callsite = v.build_callsite_by_name(node, recvtype, name, for_self)
2133
2134 if callsite == null then return
2135 self.callsite = callsite
2136
2137 var args = compute_raw_arguments
2138
2139 callsite.check_signature(v, node, args)
2140
2141 var readtype = callsite.msignature.return_mtype
2142 if readtype == null then
2143 v.error(node, "Error: `{name}` is not a function.")
2144 return
2145 end
2146
2147 var wcallsite = v.build_callsite_by_name(node, recvtype, name + "=", self.n_expr isa ASelfExpr)
2148 if wcallsite == null then return
2149 self.write_callsite = wcallsite
2150
2151 var wtype = self.resolve_reassignment(v, readtype, wcallsite.msignature.mparameters.last.mtype)
2152 if wtype == null then return
2153
2154 args = args.to_a # duplicate so raw_arguments keeps only the getter args
2155 args.add(self.n_value)
2156 wcallsite.check_signature(v, node, args)
2157
2158 self.is_typed = true
2159 end
2160 end
2161
2162 redef class ACallReassignExpr
2163 redef fun property_name do return n_qid.n_id.text
2164 redef fun property_node do return n_qid.n_id
2165 redef fun compute_raw_arguments do return n_args.to_a
2166 end
2167
2168 redef class ABraReassignExpr
2169 redef fun property_name do return "[]"
2170 redef fun compute_raw_arguments do return n_args.to_a
2171 end
2172
2173 redef class AInitExpr
2174 redef fun property_name do if n_args.n_exprs.is_empty then return "init" else return "defaultinit"
2175 redef fun property_node do return n_kwinit
2176 redef fun compute_raw_arguments do return n_args.to_a
2177 end
2178
2179 redef class ACallrefExpr
2180 redef fun property_name do return n_qid.n_id.text
2181 redef fun property_node do return n_qid
2182 redef fun compute_raw_arguments do return n_args.to_a
2183
2184 redef fun accept_typing(v)
2185 do
2186 super # do the job as if it was a real call
2187 var res = callsite.mproperty
2188
2189 var msignature = callsite.mpropdef.msignature
2190 var recv = callsite.recv
2191 assert msignature != null
2192 var arity = msignature.mparameters.length
2193
2194 var routine_type_name = "ProcRef"
2195 if msignature.return_mtype != null then
2196 routine_type_name = "FunRef"
2197 end
2198
2199 var target_routine_class = "{routine_type_name}{arity}"
2200 var routine_mclass = v.get_mclass(self, target_routine_class)
2201
2202 if routine_mclass == null then
2203 v.error(self, "Error: missing functional types, try `import functional`")
2204 return
2205 end
2206
2207 var types_list = new Array[MType]
2208 for param in msignature.mparameters do
2209 if param.is_vararg then
2210 types_list.push(v.mmodule.array_type(param.mtype))
2211 else
2212 types_list.push(param.mtype)
2213 end
2214 end
2215 if msignature.return_mtype != null then
2216 types_list.push(msignature.return_mtype.as(not null))
2217 end
2218
2219 # Why we need an anchor :
2220 #
2221 # ~~~~nitish
2222 # class A[E]
2223 # def toto(x: E) do print "{x}"
2224 # end
2225 #
2226 # var a = new A[Int]
2227 # var f = &a.toto # without anchor : ProcRef1[E]
2228 # # with anchor : ProcRef[Int]
2229 # ~~~~
2230 # However, we can only anchor if we can resolve every formal
2231 # parameter, here's an example where we can't.
2232 # ~~~~nitish
2233 # class A[E]
2234 # fun bar: A[E] do return self
2235 # fun foo: Fun0[A[E]] do return &bar # here we can't anchor
2236 # end
2237 # var f1 = a1.foo # when this expression will be evaluated,
2238 # # `a1` will anchor `&bar` returned by `foo`.
2239 # print f1.call
2240 # ~~~~
2241 var routine_type = routine_mclass.get_mtype(types_list)
2242 if not recv.need_anchor then
2243 routine_type = routine_type.anchor_to(v.mmodule, recv.as(MClassType))
2244 end
2245 is_typed = true
2246 self.mtype = routine_type
2247 end
2248 end
2249
2250 redef class AExprs
2251 fun to_a: Array[AExpr] do return self.n_exprs.to_a
2252 end
2253
2254 ###
2255
2256 redef class ASuperExpr
2257 # The method to call if the super is in fact a 'super init call'
2258 # Note: if the super is a normal call-next-method, then this attribute is null
2259 var callsite: nullable CallSite
2260
2261 # The method to call is the super is a standard `call-next-method` super-call
2262 # Note: if the super is a special super-init-call, then this attribute is null
2263 var mpropdef: nullable MMethodDef
2264
2265 redef fun accept_typing(v)
2266 do
2267 var anchor = v.anchor
2268 var recvtype = v.get_variable(self, v.selfvariable)
2269 assert recvtype != null
2270 var mproperty = v.mpropdef.mproperty
2271 if not mproperty isa MMethod then
2272 v.error(self, "Error: `super` only usable in a `method`.")
2273 return
2274 end
2275 var superprops = mproperty.lookup_super_definitions(v.mmodule, anchor)
2276 if superprops.length == 0 then
2277 if mproperty.is_init and v.mpropdef.is_intro then
2278 process_superinit(v)
2279 return
2280 end
2281 v.error(self, "Error: no super method to call for `{mproperty}`.")
2282 return
2283 end
2284 # FIXME: covariance of return type in linear extension?
2285 var superprop = superprops.first
2286
2287 var msignature = superprop.msignature.as(not null)
2288 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
2289 var args = self.n_args.to_a
2290 if args.length > 0 then
2291 signaturemap = v.check_signature(self, args, mproperty, msignature)
2292 end
2293 self.mtype = msignature.return_mtype
2294 self.is_typed = true
2295 v.mpropdef.has_supercall = true
2296 mpropdef = v.mpropdef.as(MMethodDef)
2297 end
2298
2299 # The mapping used on the call to associate arguments to parameters.
2300 # If null then no specific association is required.
2301 var signaturemap: nullable SignatureMap
2302
2303 private fun process_superinit(v: TypeVisitor)
2304 do
2305 var anchor = v.anchor
2306 var recvtype = v.get_variable(self, v.selfvariable)
2307 assert recvtype != null
2308 var mpropdef = v.mpropdef
2309 assert mpropdef isa MMethodDef
2310 var mproperty = mpropdef.mproperty
2311 var superprop: nullable MMethodDef = null
2312 for msupertype in mpropdef.mclassdef.supertypes do
2313 msupertype = msupertype.anchor_to(v.mmodule, anchor)
2314 var errcount = v.modelbuilder.toolcontext.error_count
2315 var candidate = v.try_get_mproperty_by_name2(self, msupertype, mproperty.name).as(nullable MMethod)
2316 if candidate == null then
2317 if v.modelbuilder.toolcontext.error_count > errcount then return # Forward error
2318 continue # Try next super-class
2319 end
2320 if superprop != null and candidate.is_root_init then
2321 continue
2322 end
2323 if superprop != null and superprop.mproperty != candidate and not superprop.mproperty.is_root_init then
2324 v.error(self, "Error: conflicting super constructor to call for `{mproperty}`: `{candidate.full_name}`, `{superprop.mproperty.full_name}`")
2325 return
2326 end
2327 var candidatedefs = candidate.lookup_definitions(v.mmodule, anchor)
2328 if superprop != null and superprop.mproperty == candidate then
2329 if superprop == candidatedefs.first then continue
2330 candidatedefs.add(superprop)
2331 end
2332 if candidatedefs.length > 1 then
2333 v.error(self, "Error: conflicting property definitions for property `{mproperty}` in `{recvtype}`: {candidatedefs.join(", ")}")
2334 return
2335 end
2336 superprop = candidatedefs.first
2337 end
2338 if superprop == null then
2339 v.error(self, "Error: no super method to call for `{mproperty}`.")
2340 return
2341 end
2342
2343 var msignature = superprop.msignature.as(not null)
2344 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
2345
2346 var callsite = new CallSite(hot_location, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
2347 self.callsite = callsite
2348
2349 var args = self.n_args.to_a
2350 if args.length > 0 then
2351 callsite.check_signature(v, self, args)
2352 else
2353 # Check there is at least enough parameters
2354 if mpropdef.msignature.arity < msignature.arity then
2355 v.error(self, "Error: not enough implicit arguments to pass. Got `{mpropdef.msignature.arity}`, expected at least `{msignature.arity}`. Signature is `{msignature}`.")
2356 return
2357 end
2358 # Check that each needed parameter is conform
2359 var i = 0
2360 for sp in msignature.mparameters do
2361 var p = mpropdef.msignature.mparameters[i]
2362 if not v.is_subtype(p.mtype, sp.mtype) then
2363 v.error(self, "Type Error: expected argument #{i} of type `{sp.mtype}`, got implicit argument `{p.name}` of type `{p.mtype}`. Signature is {msignature}")
2364 return
2365 end
2366 i += 1
2367 end
2368 end
2369
2370 self.is_typed = true
2371 end
2372
2373 redef fun dump_info(v) do
2374 var res = super
2375 var callsite = self.callsite
2376 if callsite != null then
2377 res += v.yellow(" super-init="+callsite.dump_info(v))
2378 end
2379 var mpropdef = self.mpropdef
2380 if mpropdef != null then
2381 res += v.yellow(" call-next-method="+mpropdef.to_s)
2382 end
2383 return res
2384 end
2385 end
2386
2387 ####
2388
2389 redef class ANewExpr
2390 # The constructor invoked by the new.
2391 var callsite: nullable CallSite
2392
2393 # The designated type
2394 var recvtype: nullable MClassType
2395
2396 redef fun accept_typing(v)
2397 do
2398 var recvtype = v.resolve_mtype(self.n_type)
2399 if recvtype == null then return
2400
2401 if not recvtype isa MClassType then
2402 if recvtype isa MNullableType then
2403 v.error(self, "Type Error: cannot instantiate the nullable type `{recvtype}`.")
2404 return
2405 else if recvtype isa MFormalType then
2406 v.error(self, "Type Error: cannot instantiate the formal type `{recvtype}`.")
2407 return
2408 else
2409 v.error(self, "Type Error: cannot instantiate the type `{recvtype}`.")
2410 return
2411 end
2412 end
2413
2414 self.recvtype = recvtype
2415 var kind = recvtype.mclass.kind
2416
2417 var name: String
2418 var nqid = self.n_qid
2419 var node: ANode
2420 if nqid != null then
2421 name = nqid.n_id.text
2422 node = nqid
2423 else
2424 name = "new"
2425 node = self.n_kwnew
2426 end
2427 if name == "intern" then
2428 if kind != concrete_kind then
2429 v.error(self, "Type Error: cannot instantiate {kind} {recvtype}.")
2430 return
2431 end
2432 if n_args.n_exprs.not_empty then
2433 v.error(n_args, "Type Error: the intern constructor expects no arguments.")
2434 return
2435 end
2436 # Our job is done
2437 self.mtype = recvtype
2438 return
2439 end
2440
2441 var callsite = v.build_callsite_by_name(node, recvtype, name, false)
2442 if callsite == null then return
2443
2444 if not callsite.mproperty.is_new then
2445 if kind != concrete_kind then
2446 v.error(self, "Type Error: cannot instantiate {kind} `{recvtype}`.")
2447 return
2448 end
2449 self.mtype = recvtype
2450 else
2451 self.mtype = callsite.msignature.return_mtype
2452 assert self.mtype != null
2453 end
2454
2455 self.callsite = callsite
2456
2457 if not callsite.mproperty.is_init_for(recvtype.mclass) then
2458 v.error(self, "Error: `{name}` is not a constructor.")
2459 return
2460 end
2461
2462 var args = n_args.to_a
2463 callsite.check_signature(v, node, args)
2464 end
2465
2466 redef fun dump_info(v) do
2467 var res = super
2468 var callsite = self.callsite
2469 if callsite != null then
2470 res += v.yellow(" call="+callsite.dump_info(v))
2471 end
2472 return res
2473 end
2474 end
2475
2476 ####
2477
2478 redef class AAttrFormExpr
2479 # The attribute accessed.
2480 var mproperty: nullable MAttribute
2481
2482 # The static type of the attribute.
2483 var attr_type: nullable MType
2484
2485 # Resolve the attribute accessed.
2486 private fun resolve_property(v: TypeVisitor)
2487 do
2488 var recvtype = v.visit_expr(self.n_expr)
2489 if recvtype == null then return # Skip error
2490 var node = self.n_id
2491 var name = node.text
2492 if recvtype isa MNullType then
2493 v.error(node, "Error: attribute `{name}` access on `null`.")
2494 return
2495 end
2496
2497 var unsafe_type = v.anchor_to(recvtype)
2498 var mproperty = v.try_get_mproperty_by_name2(node, unsafe_type, name)
2499 if mproperty == null then
2500 v.modelbuilder.error(node, "Error: attribute `{name}` does not exist in `{recvtype}`.")
2501 return
2502 end
2503 assert mproperty isa MAttribute
2504 self.mproperty = mproperty
2505
2506 var mpropdefs = mproperty.lookup_definitions(v.mmodule, unsafe_type)
2507 assert mpropdefs.length == 1
2508 var mpropdef = mpropdefs.first
2509 var attr_type = mpropdef.static_mtype
2510 if attr_type == null then return # skip error
2511 attr_type = v.resolve_for(attr_type, recvtype, self.n_expr isa ASelfExpr)
2512 self.attr_type = attr_type
2513 end
2514
2515 redef fun dump_info(v) do
2516 var res = super
2517 var mproperty = self.mproperty
2518 var attr_type = self.attr_type
2519 if mproperty != null then
2520 res += v.yellow(" attr={mproperty}:{attr_type or else "BROKEN"}")
2521 end
2522 return res
2523 end
2524 end
2525
2526 redef class AAttrExpr
2527 redef fun accept_typing(v)
2528 do
2529 self.resolve_property(v)
2530 self.mtype = self.attr_type
2531 end
2532 end
2533
2534 redef class AAttrAssignExpr
2535 redef fun accept_typing(v)
2536 do
2537 self.resolve_property(v)
2538 var mtype = self.attr_type
2539
2540 v.visit_expr_subtype(self.n_value, mtype)
2541 self.is_typed = mtype != null
2542 end
2543 end
2544
2545 redef class AAttrReassignExpr
2546 redef fun accept_typing(v)
2547 do
2548 self.resolve_property(v)
2549 var mtype = self.attr_type
2550 if mtype == null then return # Skip error
2551
2552 var rettype = self.resolve_reassignment(v, mtype, mtype)
2553
2554 self.is_typed = rettype != null
2555 end
2556 end
2557
2558 redef class AIssetAttrExpr
2559 redef fun accept_typing(v)
2560 do
2561 self.resolve_property(v)
2562 var mtype = self.attr_type
2563 if mtype == null then return # Skip error
2564
2565 var recvtype = self.n_expr.mtype.as(not null)
2566 var bound = v.resolve_for(mtype, recvtype, false)
2567 if bound isa MNullableType then
2568 v.error(n_id, "Type Error: `isset` on a nullable attribute.")
2569 end
2570 self.mtype = v.type_bool(self)
2571 end
2572 end
2573
2574 redef class ASafeExpr
2575 redef fun accept_typing(v)
2576 do
2577 var mtype = v.visit_expr(n_expr)
2578 if mtype == null then return # Skip error
2579
2580 if mtype isa MNullType then
2581 # While `null?.foo` is semantically well defined and should not execute `foo` and just return `null`,
2582 # currently `null.foo` is forbidden so it seems coherent to also forbid `null?.foo`
2583 v.modelbuilder.error(self, "Error: safe operator `?` on `null`.")
2584 return
2585 end
2586
2587 self.mtype = mtype.as_notnull
2588
2589 if not v.can_be_null(mtype) then
2590 v.display_warning(self, "useless-safe", "Warning: useless safe operator `?` on non-nullable value.")
2591 return
2592 end
2593 end
2594 end
2595
2596 redef class AVarargExpr
2597 redef fun accept_typing(v)
2598 do
2599 # This kind of pseudo-expression can be only processed trough a signature
2600 # See `check_signature`
2601 # Other cases are a syntax error.
2602 v.error(self, "Syntax Error: unexpected `...`.")
2603 end
2604 end
2605
2606 ###
2607
2608 redef class ADebugTypeExpr
2609 redef fun accept_typing(v)
2610 do
2611 var expr = v.visit_expr(self.n_expr)
2612 if expr == null then return
2613 var unsafe = v.anchor_to(expr)
2614 var ntype = self.n_type
2615 var mtype = v.resolve_mtype(ntype)
2616 if mtype != null and mtype != expr then
2617 var umtype = v.anchor_to(mtype)
2618 v.display_warning(self, "debug", "Found type {expr} (-> {unsafe}), expected {mtype} (-> {umtype})")
2619 end
2620 self.is_typed = true
2621 end
2622 end