Merge: doc: fixed some typos and other misc. corrections
[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
1042 # Type the expression as if located in `visited_mpropdef`
1043 # `TypeVisitor` and `PostTypingVisitor` will be used to do the typing, see them for more information.
1044 #
1045 # `visited_mpropdef`: Correspond to the evaluation context in which the expression is located.
1046 fun do_typing(modelbuilder: ModelBuilder, visited_mpropdef: MPropDef)
1047 do
1048 var type_visitor = new TypeVisitor(modelbuilder, visited_mpropdef)
1049 type_visitor.visit_stmt(self)
1050 var post_visitor = new PostTypingVisitor(type_visitor)
1051 post_visitor.enter_visit(self)
1052 end
1053 end
1054
1055 redef class ABlockExpr
1056 redef fun accept_typing(v)
1057 do
1058 for e in self.n_expr do v.visit_stmt(e)
1059 self.is_typed = true
1060 end
1061
1062 # The type of a blockexpr is the one of the last expression (or null if empty)
1063 redef fun mtype
1064 do
1065 if self.n_expr.is_empty then return null
1066 return self.n_expr.last.mtype
1067 end
1068 end
1069
1070 redef class AVardeclExpr
1071 redef fun accept_typing(v)
1072 do
1073 var variable = self.variable
1074 if variable == null then return # Skip error
1075
1076 var ntype = self.n_type
1077 var mtype: nullable MType
1078 if ntype == null then
1079 mtype = null
1080 else
1081 mtype = v.resolve_mtype(ntype)
1082 if mtype == null then return # Skip error
1083 end
1084
1085 var nexpr = self.n_expr
1086 if nexpr != null then
1087 if mtype != null then
1088 var etype = v.visit_expr_subtype(nexpr, mtype)
1089 if etype == mtype then
1090 assert ntype != null
1091 v.modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition for variable `{variable.name}`")
1092 end
1093 else
1094 mtype = v.visit_expr(nexpr)
1095 if mtype == null then return # Skip error
1096 end
1097 end
1098
1099 var decltype = mtype
1100 if mtype == null or mtype isa MNullType then
1101 var objclass = v.get_mclass(self, "Object")
1102 if objclass == null then return # skip error
1103 decltype = objclass.mclass_type.as_nullable
1104 if mtype == null then mtype = decltype
1105 end
1106
1107 variable.declared_type = decltype
1108 v.set_variable(self, variable, mtype)
1109
1110 #debug("var {variable}: {mtype}")
1111
1112 self.mtype = mtype
1113 self.is_typed = true
1114 end
1115 end
1116
1117 redef class AVarExpr
1118 redef fun its_variable do return self.variable
1119 redef fun accept_typing(v)
1120 do
1121 var variable = self.variable
1122 if variable == null then return # Skip error
1123
1124 var mtype = v.get_variable(self, variable)
1125 if mtype != null then
1126 #debug("{variable} is {mtype}")
1127 else
1128 #debug("{variable} is untyped")
1129 end
1130
1131 self.mtype = mtype
1132 end
1133 end
1134
1135 redef class AVarAssignExpr
1136 redef fun accept_typing(v)
1137 do
1138 var variable = self.variable
1139 assert variable != null
1140
1141 var mtype = v.visit_expr_subtype(n_value, variable.declared_type)
1142
1143 v.set_variable(self, variable, mtype)
1144
1145 self.is_typed = true
1146 end
1147 end
1148
1149 redef class AReassignFormExpr
1150 # The method designed by the reassign operator.
1151 var reassign_callsite: nullable CallSite
1152
1153 var read_type: nullable MType = null
1154
1155 # Determine the `reassign_property`
1156 # `readtype` is the type of the reading of the left value.
1157 # `writetype` is the type of the writing of the left value.
1158 # (Because of `ACallReassignExpr`, both can be different.
1159 # Return the static type of the value to store.
1160 private fun resolve_reassignment(v: TypeVisitor, readtype, writetype: MType): nullable MType
1161 do
1162 var reassign_name = self.n_assign_op.operator
1163
1164 self.read_type = readtype
1165
1166 var callsite = v.build_callsite_by_name(self.n_assign_op, readtype, reassign_name, false)
1167 if callsite == null then return null # Skip error
1168 self.reassign_callsite = callsite
1169
1170 var msignature = callsite.msignature
1171 var rettype = msignature.return_mtype
1172 assert msignature.arity == 1 and rettype != null
1173
1174 var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype)
1175 if value_type == null then return null # Skip error
1176
1177 v.check_subtype(self, rettype, writetype, false)
1178 return rettype
1179 end
1180 end
1181
1182 redef class AVarReassignExpr
1183 redef fun accept_typing(v)
1184 do
1185 var variable = self.variable
1186 assert variable != null
1187
1188 var readtype = v.get_variable(self, variable)
1189 if readtype == null then return
1190
1191 read_type = readtype
1192
1193 var writetype = variable.declared_type
1194 if writetype == null then return
1195
1196 var rettype = self.resolve_reassignment(v, readtype, writetype)
1197
1198 v.set_variable(self, variable, rettype)
1199
1200 self.is_typed = rettype != null
1201 end
1202 end
1203
1204 redef class AContinueExpr
1205 redef fun accept_typing(v)
1206 do
1207 var nexpr = self.n_expr
1208 if nexpr != null then
1209 v.visit_expr(nexpr)
1210 end
1211 self.is_typed = true
1212 end
1213 end
1214
1215 redef class ABreakExpr
1216 redef fun accept_typing(v)
1217 do
1218 var nexpr = self.n_expr
1219 if nexpr != null then
1220 v.visit_expr(nexpr)
1221 end
1222 self.is_typed = true
1223 end
1224 end
1225
1226 redef class AReturnExpr
1227 redef fun accept_typing(v)
1228 do
1229 var nexpr = self.n_expr
1230 var ret_type
1231 var mpropdef = v.mpropdef
1232 if mpropdef isa MMethodDef then
1233 ret_type = mpropdef.msignature.return_mtype
1234 else if mpropdef isa MAttributeDef then
1235 ret_type = mpropdef.static_mtype
1236 else
1237 abort
1238 end
1239 if nexpr != null then
1240 if ret_type != null then
1241 v.visit_expr_subtype(nexpr, ret_type)
1242 else
1243 v.visit_expr(nexpr)
1244 v.error(nexpr, "Error: `return` with value in a procedure.")
1245 return
1246 end
1247 else if ret_type != null then
1248 v.error(self, "Error: `return` without value in a function.")
1249 return
1250 end
1251 self.is_typed = true
1252 end
1253 end
1254
1255 redef class AAbortExpr
1256 redef fun accept_typing(v)
1257 do
1258 self.is_typed = true
1259 end
1260 end
1261
1262 redef class AIfExpr
1263 redef fun accept_typing(v)
1264 do
1265 v.visit_expr_bool(n_expr)
1266
1267 v.visit_stmt(n_then)
1268 v.visit_stmt(n_else)
1269
1270 self.is_typed = true
1271
1272 if n_then != null and n_else == null then
1273 self.mtype = n_then.mtype
1274 end
1275 end
1276 end
1277
1278 redef class AIfexprExpr
1279 redef fun accept_typing(v)
1280 do
1281 v.visit_expr_bool(n_expr)
1282
1283 var t1 = v.visit_expr(n_then)
1284 var t2 = v.visit_expr(n_else)
1285
1286 if t1 == null or t2 == null then
1287 return # Skip error
1288 end
1289
1290 var t = v.merge_types(self, [t1, t2])
1291 if t == null then
1292 v.error(self, "Type Error: ambiguous type `{t1}` vs `{t2}`.")
1293 end
1294 self.mtype = t
1295 end
1296 end
1297
1298 redef class ADoExpr
1299 redef fun accept_typing(v)
1300 do
1301 v.visit_stmt(n_block)
1302 v.visit_stmt(n_catch)
1303 self.is_typed = true
1304 end
1305 end
1306
1307 redef class AWhileExpr
1308 redef fun accept_typing(v)
1309 do
1310 v.has_loop = true
1311 v.visit_expr_bool(n_expr)
1312 v.visit_stmt(n_block)
1313 self.is_typed = true
1314 end
1315 end
1316
1317 redef class ALoopExpr
1318 redef fun accept_typing(v)
1319 do
1320 v.has_loop = true
1321 v.visit_stmt(n_block)
1322 self.is_typed = true
1323 end
1324 end
1325
1326 redef class AForExpr
1327 redef fun accept_typing(v)
1328 do
1329 v.has_loop = true
1330
1331 for g in n_groups do
1332 var mtype = v.visit_expr(g.n_expr)
1333 if mtype == null then return
1334 g.do_type_iterator(v, mtype)
1335 if g.is_broken then is_broken = true
1336 end
1337
1338 v.visit_stmt(n_block)
1339
1340 self.mtype = n_block.mtype
1341 self.is_typed = true
1342 end
1343 end
1344
1345 redef class AForGroup
1346 var coltype: nullable MClassType
1347
1348 var method_iterator: nullable CallSite
1349 var method_is_ok: nullable CallSite
1350 var method_item: nullable CallSite
1351 var method_next: nullable CallSite
1352 var method_key: nullable CallSite
1353 var method_finish: nullable CallSite
1354
1355 var method_lt: nullable CallSite
1356 var method_successor: nullable CallSite
1357
1358 private fun do_type_iterator(v: TypeVisitor, mtype: MType)
1359 do
1360 if mtype isa MNullType then
1361 v.error(self, "Type Error: `for` cannot iterate over `null`.")
1362 return
1363 end
1364
1365 # get obj class
1366 var objcla = v.get_mclass(self, "Object")
1367 if objcla == null then return
1368
1369 # check iterator method
1370 var itdef = v.build_callsite_by_name(self, mtype, "iterator", n_expr isa ASelfExpr)
1371 if itdef == null then
1372 v.error(self, "Type Error: `for` expects a type providing an `iterator` method, got `{mtype}`.")
1373 return
1374 end
1375 self.method_iterator = itdef
1376
1377 # check that iterator return something
1378 var ittype = itdef.msignature.return_mtype
1379 if ittype == null then
1380 v.error(self, "Type Error: `for` expects the method `iterator` to return an `Iterator` or `MapIterator` type.")
1381 return
1382 end
1383
1384 # get iterator type
1385 var colit_cla = v.try_get_mclass(self, "Iterator")
1386 var mapit_cla = v.try_get_mclass(self, "MapIterator")
1387 var is_col = false
1388 var is_map = false
1389
1390 if colit_cla != null and v.is_subtype(ittype, colit_cla.get_mtype([objcla.mclass_type.as_nullable])) then
1391 # Iterator
1392 var coltype = ittype.supertype_to(v.mmodule, v.anchor, colit_cla)
1393 var variables = self.variables
1394 if variables.length != 1 then
1395 v.error(self, "Type Error: `for` expects only one variable when using `Iterator`.")
1396 else
1397 variables.first.declared_type = coltype.arguments.first
1398 end
1399 is_col = true
1400 end
1401
1402 if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type.as_nullable, objcla.mclass_type.as_nullable])) then
1403 # Map Iterator
1404 var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
1405 var variables = self.variables
1406 if variables.length != 2 then
1407 v.error(self, "Type Error: `for` expects two variables when using `MapIterator`.")
1408 else
1409 variables[0].declared_type = coltype.arguments[0]
1410 variables[1].declared_type = coltype.arguments[1]
1411 end
1412 is_map = true
1413 end
1414
1415 if not is_col and not is_map then
1416 v.error(self, "Type Error: `for` expects the method `iterator` to return an `Iterator` or `MapIterator` type.")
1417 return
1418 end
1419
1420 # anchor formal and virtual types
1421 if mtype.need_anchor then mtype = v.anchor_to(mtype)
1422
1423 mtype = mtype.undecorate
1424 self.coltype = mtype.as(MClassType)
1425
1426 # get methods is_ok, next, item
1427 var ikdef = v.build_callsite_by_name(self, ittype, "is_ok", false)
1428 if ikdef == null then
1429 v.error(self, "Type Error: `for` expects a method `is_ok` in type `{ittype}`.")
1430 return
1431 end
1432 self.method_is_ok = ikdef
1433
1434 var itemdef = v.build_callsite_by_name(self, ittype, "item", false)
1435 if itemdef == null then
1436 v.error(self, "Type Error: `for` expects a method `item` in type `{ittype}`.")
1437 return
1438 end
1439 self.method_item = itemdef
1440
1441 var nextdef = v.build_callsite_by_name(self, ittype, "next", false)
1442 if nextdef == null then
1443 v.error(self, "Type Error: `for` expects a method `next` in type {ittype}.")
1444 return
1445 end
1446 self.method_next = nextdef
1447
1448 self.method_finish = v.try_build_callsite_by_name(self, ittype, "finish", false)
1449
1450 if is_map then
1451 var keydef = v.build_callsite_by_name(self, ittype, "key", false)
1452 if keydef == null then
1453 v.error(self, "Type Error: `for` expects a method `key` in type `{ittype}`.")
1454 return
1455 end
1456 self.method_key = keydef
1457 end
1458
1459 if self.variables.length == 1 and n_expr isa ARangeExpr then
1460 var variable = variables.first
1461 var vtype = variable.declared_type.as(not null)
1462
1463 if n_expr isa AOrangeExpr then
1464 self.method_lt = v.build_callsite_by_name(self, vtype, "<", false)
1465 else
1466 self.method_lt = v.build_callsite_by_name(self, vtype, "<=", false)
1467 end
1468
1469 self.method_successor = v.build_callsite_by_name(self, vtype, "successor", false)
1470 end
1471 end
1472 end
1473
1474 redef class AWithExpr
1475 var method_start: nullable CallSite
1476 var method_finish: nullable CallSite
1477
1478 redef fun accept_typing(v: TypeVisitor)
1479 do
1480 var mtype = v.visit_expr(n_expr)
1481 if mtype == null then return
1482
1483 method_start = v.build_callsite_by_name(self, mtype, "start", n_expr isa ASelfExpr)
1484 method_finish = v.build_callsite_by_name(self, mtype, "finish", n_expr isa ASelfExpr)
1485
1486 v.visit_stmt(n_block)
1487 self.mtype = n_block.mtype
1488 self.is_typed = true
1489 end
1490 end
1491
1492 redef class AAssertExpr
1493 redef fun accept_typing(v)
1494 do
1495 v.visit_expr_bool(n_expr)
1496
1497 v.visit_stmt(n_else)
1498 self.is_typed = true
1499 end
1500 end
1501
1502 redef class AOrExpr
1503 redef fun accept_typing(v)
1504 do
1505 v.visit_expr_bool(n_expr)
1506 v.visit_expr_bool(n_expr2)
1507 self.mtype = v.type_bool(self)
1508 end
1509 end
1510
1511 redef class AImpliesExpr
1512 redef fun accept_typing(v)
1513 do
1514 v.visit_expr_bool(n_expr)
1515 v.visit_expr_bool(n_expr2)
1516 self.mtype = v.type_bool(self)
1517 end
1518 end
1519
1520 redef class AAndExpr
1521 redef fun accept_typing(v)
1522 do
1523 v.visit_expr_bool(n_expr)
1524 v.visit_expr_bool(n_expr2)
1525 self.mtype = v.type_bool(self)
1526 end
1527 end
1528
1529 redef class ANotExpr
1530 redef fun accept_typing(v)
1531 do
1532 v.visit_expr_bool(n_expr)
1533 self.mtype = v.type_bool(self)
1534 end
1535 end
1536
1537 redef class AOrElseExpr
1538 redef fun accept_typing(v)
1539 do
1540 var t1 = v.visit_expr(n_expr)
1541 var t2 = v.visit_expr(n_expr2)
1542
1543 if t1 == null or t2 == null then
1544 return # Skip error
1545 end
1546
1547 if t1 isa MNullType then
1548 self.mtype = t2
1549 return
1550 else if v.can_be_null(t1) then
1551 t1 = t1.as_notnull
1552 end
1553
1554 var t = v.merge_types(self, [t1, t2])
1555 if t == null then
1556 var c = v.get_mclass(self, "Object")
1557 if c == null then return # forward error
1558 t = c.mclass_type
1559 if v.can_be_null(t2) then
1560 t = t.as_nullable
1561 end
1562 #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
1563 end
1564 self.mtype = t
1565 end
1566
1567 redef fun accept_post_typing(v)
1568 do
1569 var t1 = n_expr.mtype
1570 if t1 == null then
1571 return
1572 else
1573 v.check_can_be_null(n_expr, t1)
1574 end
1575 end
1576 end
1577
1578 redef class ATrueExpr
1579 redef fun accept_typing(v)
1580 do
1581 self.mtype = v.type_bool(self)
1582 end
1583 end
1584
1585 redef class AFalseExpr
1586 redef fun accept_typing(v)
1587 do
1588 self.mtype = v.type_bool(self)
1589 end
1590 end
1591
1592 redef class AIntegerExpr
1593 redef fun accept_typing(v)
1594 do
1595 var mclass: nullable MClass = null
1596 if value isa Byte then
1597 mclass = v.get_mclass(self, "Byte")
1598 else if value isa Int then
1599 mclass = v.get_mclass(self, "Int")
1600 else if value isa Int8 then
1601 mclass = v.get_mclass(self, "Int8")
1602 else if value isa Int16 then
1603 mclass = v.get_mclass(self, "Int16")
1604 else if value isa UInt16 then
1605 mclass = v.get_mclass(self, "UInt16")
1606 else if value isa Int32 then
1607 mclass = v.get_mclass(self, "Int32")
1608 else if value isa UInt32 then
1609 mclass = v.get_mclass(self, "UInt32")
1610 end
1611 if mclass == null then return # Forward error
1612 self.mtype = mclass.mclass_type
1613 end
1614 end
1615
1616 redef class AFloatExpr
1617 redef fun accept_typing(v)
1618 do
1619 var mclass = v.get_mclass(self, "Float")
1620 if mclass == null then return # Forward error
1621 self.mtype = mclass.mclass_type
1622 end
1623 end
1624
1625 redef class ACharExpr
1626 redef fun accept_typing(v) do
1627 var mclass: nullable MClass = null
1628 if is_code_point then
1629 mclass = v.get_mclass(self, "Int")
1630 else
1631 mclass = v.get_mclass(self, "Char")
1632 end
1633 if mclass == null then return # Forward error
1634 self.mtype = mclass.mclass_type
1635 end
1636 end
1637
1638 redef class AugmentedStringFormExpr
1639 super AExpr
1640
1641 # Text::to_re, used for prefix `re`
1642 var to_re: nullable CallSite = null
1643 # Regex::ignore_case, used for suffix `i` on `re`
1644 var ignore_case: nullable CallSite = null
1645 # Regex::newline, used for suffix `m` on `re`
1646 var newline: nullable CallSite = null
1647 # Regex::extended, used for suffix `b` on `re`
1648 var extended: nullable CallSite = null
1649 # CString::to_bytes_with_copy, used for prefix `b`
1650 var to_bytes_with_copy: nullable CallSite = null
1651
1652 redef fun accept_typing(v) do
1653 var mclass = v.get_mclass(self, "String")
1654 if mclass == null then return # Forward error
1655 if is_bytestring then
1656 to_bytes_with_copy = v.build_callsite_by_name(self, v.mmodule.c_string_type, "to_bytes_with_copy", false)
1657 mclass = v.get_mclass(self, "Bytes")
1658 else if is_re then
1659 to_re = v.build_callsite_by_name(self, mclass.mclass_type, "to_re", false)
1660 for i in suffix.chars do
1661 mclass = v.get_mclass(self, "Regex")
1662 if mclass == null then
1663 v.error(self, "Error: `Regex` class unknown")
1664 return
1665 end
1666 var service = ""
1667 if i == 'i' then
1668 service = "ignore_case="
1669 ignore_case = v.build_callsite_by_name(self, mclass.mclass_type, service, false)
1670 else if i == 'm' then
1671 service = "newline="
1672 newline = v.build_callsite_by_name(self, mclass.mclass_type, service, false)
1673 else if i == 'b' then
1674 service = "extended="
1675 extended = v.build_callsite_by_name(self, mclass.mclass_type, service, false)
1676 else
1677 v.error(self, "Type Error: Unrecognized suffix {i} in prefixed Regex")
1678 abort
1679 end
1680 end
1681 end
1682 if mclass == null then return # Forward error
1683 mtype = mclass.mclass_type
1684 end
1685 end
1686
1687 redef class ASuperstringExpr
1688 redef fun accept_typing(v)
1689 do
1690 super
1691 var objclass = v.get_mclass(self, "Object")
1692 if objclass == null then return # Forward error
1693 var objtype = objclass.mclass_type
1694 for nexpr in self.n_exprs do
1695 v.visit_expr_subtype(nexpr, objtype)
1696 end
1697 end
1698 end
1699
1700 redef class AArrayExpr
1701 # The `with_capacity` method on Array
1702 var with_capacity_callsite: nullable CallSite
1703
1704 # The `push` method on arrays
1705 var push_callsite: nullable CallSite
1706
1707 # The element of each type
1708 var element_mtype: nullable MType
1709
1710 # Set that `self` is a part of comprehension array `na`
1711 # If `self` is a `for`, or a `if`, then `set_comprehension` is recursively applied.
1712 private fun set_comprehension(n: nullable AExpr)
1713 do
1714 if n == null then
1715 return
1716 else if n isa AForExpr then
1717 set_comprehension(n.n_block)
1718 else if n isa AIfExpr then
1719 set_comprehension(n.n_then)
1720 set_comprehension(n.n_else)
1721 else
1722 # is a leave
1723 n.comprehension = self
1724 end
1725 end
1726 redef fun accept_typing(v)
1727 do
1728 var mtype: nullable MType = null
1729 var ntype = self.n_type
1730 if ntype != null then
1731 mtype = v.resolve_mtype(ntype)
1732 if mtype == null then return # Skip error
1733 end
1734 var mtypes = new Array[nullable MType]
1735 var useless = false
1736 for e in self.n_exprs do
1737 var t = v.visit_expr(e)
1738 if t == null then
1739 return # Skip error
1740 end
1741 set_comprehension(e)
1742 if mtype != null then
1743 if v.check_subtype(e, t, mtype, false) == null then return # Forward error
1744 if t == mtype then useless = true
1745 else
1746 mtypes.add(t)
1747 end
1748 end
1749 if mtype == null then
1750 # Ensure monotony for type adaptation on loops
1751 if self.element_mtype != null then mtypes.add self.element_mtype
1752 mtype = v.merge_types(self, mtypes)
1753 end
1754 if mtype == null or mtype isa MNullType then
1755 v.error(self, "Type Error: ambiguous array type {mtypes.join(" ")}")
1756 return
1757 end
1758 if useless then
1759 assert ntype != null
1760 v.display_warning(ntype, "useless-type", "Warning: useless type declaration `{mtype}` in literal Array since it can be inferred from the elements type.")
1761 end
1762
1763 self.element_mtype = mtype
1764
1765 var mclass = v.get_mclass(self, "Array")
1766 if mclass == null then return # Forward error
1767 var array_mtype = mclass.get_mtype([mtype])
1768
1769 with_capacity_callsite = v.build_callsite_by_name(self, array_mtype, "with_capacity", false)
1770 push_callsite = v.build_callsite_by_name(self, array_mtype, "push", false)
1771
1772 self.mtype = array_mtype
1773 end
1774 end
1775
1776 redef class ARangeExpr
1777 var init_callsite: nullable CallSite
1778
1779 redef fun accept_typing(v)
1780 do
1781 var discrete_class = v.get_mclass(self, "Discrete")
1782 if discrete_class == null then return # Forward error
1783 var discrete_type = discrete_class.intro.bound_mtype
1784 var t1 = v.visit_expr_subtype(self.n_expr, discrete_type)
1785 var t2 = v.visit_expr_subtype(self.n_expr2, discrete_type)
1786 if t1 == null or t2 == null then return
1787 var mclass = v.get_mclass(self, "Range")
1788 if mclass == null then return # Forward error
1789 var mtype
1790 if v.is_subtype(t1, t2) then
1791 mtype = mclass.get_mtype([t2])
1792 else if v.is_subtype(t2, t1) then
1793 mtype = mclass.get_mtype([t1])
1794 else
1795 v.error(self, "Type Error: cannot create range: `{t1}` vs `{t2}`.")
1796 return
1797 end
1798
1799 self.mtype = mtype
1800
1801 # get the constructor
1802 var callsite
1803 if self isa ACrangeExpr then
1804 callsite = v.build_callsite_by_name(self, mtype, "defaultinit", false)
1805 else if self isa AOrangeExpr then
1806 callsite = v.build_callsite_by_name(self, mtype, "without_last", false)
1807 else
1808 abort
1809 end
1810 init_callsite = callsite
1811 end
1812 end
1813
1814 redef class ANullExpr
1815 redef fun accept_typing(v)
1816 do
1817 self.mtype = v.mmodule.model.null_type
1818 end
1819 end
1820
1821 redef class AIsaExpr
1822 # The static type to cast to.
1823 # (different from the static type of the expression that is `Bool`).
1824 var cast_type: nullable MType
1825 redef fun accept_typing(v)
1826 do
1827 v.visit_expr(n_expr)
1828
1829 var mtype = v.resolve_mtype(n_type)
1830
1831 self.cast_type = mtype
1832
1833 var variable = self.n_expr.its_variable
1834 if variable != null then
1835 var orig = self.n_expr.mtype
1836 #var from = if orig != null then orig.to_s else "invalid"
1837 #var to = if mtype != null then mtype.to_s else "invalid"
1838 #debug("adapt {variable}: {from} -> {to}")
1839
1840 var thentype = v.intersect_types(self, orig, mtype)
1841 if thentype != orig then
1842 self.after_flow_context.when_true.set_var(v, variable, thentype)
1843 #debug "{variable}:{orig or else "?"} isa {mtype or else "?"} -> then {thentype or else "?"}"
1844 end
1845
1846 var elsetype = v.diff_types(self, orig, mtype)
1847 if elsetype != orig then
1848 self.after_flow_context.when_false.set_var(v, variable, elsetype)
1849 #debug "{variable}:{orig or else "?"} isa {mtype or else "?"} -> else {elsetype or else "?"}"
1850 end
1851 end
1852
1853 self.mtype = v.type_bool(self)
1854 end
1855
1856 redef fun accept_post_typing(v)
1857 do
1858 v.check_expr_cast(self, self.n_expr, self.n_type)
1859 end
1860
1861 redef fun dump_info(v) do
1862 var res = super
1863 var mtype = self.cast_type
1864 if mtype != null then
1865 res += v.yellow(".as({mtype})")
1866 end
1867 return res
1868 end
1869
1870 end
1871
1872 redef class AAsCastExpr
1873 redef fun accept_typing(v)
1874 do
1875 v.visit_expr(n_expr)
1876
1877 self.mtype = v.resolve_mtype(n_type)
1878 end
1879
1880 redef fun accept_post_typing(v)
1881 do
1882 v.check_expr_cast(self, self.n_expr, self.n_type)
1883 end
1884 end
1885
1886 redef class AAsNotnullExpr
1887 redef fun accept_typing(v)
1888 do
1889 var mtype = v.visit_expr(self.n_expr)
1890 if mtype == null then return # Forward error
1891
1892 if mtype isa MNullType then
1893 v.error(self, "Type Error: `as(not null)` on `null`.")
1894 return
1895 end
1896
1897 if v.can_be_null(mtype) then
1898 mtype = mtype.as_notnull
1899 end
1900
1901 self.mtype = mtype
1902 end
1903
1904 redef fun accept_post_typing(v)
1905 do
1906 var mtype = n_expr.mtype
1907 if mtype == null then return
1908 v.check_can_be_null(n_expr, mtype)
1909 end
1910 end
1911
1912 redef class AParExpr
1913 redef fun accept_typing(v)
1914 do
1915 self.mtype = v.visit_expr(self.n_expr)
1916 end
1917 end
1918
1919 redef class AOnceExpr
1920 redef fun accept_typing(v)
1921 do
1922 self.mtype = v.visit_expr(self.n_expr)
1923 end
1924 end
1925
1926 redef class ASelfExpr
1927 redef var its_variable: nullable Variable
1928 redef fun accept_typing(v)
1929 do
1930 if v.is_toplevel_context and not self isa AImplicitSelfExpr then
1931 v.error(self, "Error: `self` cannot be used in top-level method.")
1932 end
1933 var variable = v.selfvariable
1934 self.its_variable = variable
1935 self.mtype = v.get_variable(self, variable)
1936 end
1937 end
1938
1939 redef class AImplicitSelfExpr
1940 # Is the implicit receiver `sys`?
1941 #
1942 # By default, the implicit receiver is `self`.
1943 # But when there is not method for `self`, `sys` is used as a fall-back.
1944 # Is this case this flag is set to `true`.
1945 var is_sys = false
1946 end
1947
1948 ## MESSAGE SENDING AND PROPERTY
1949
1950 redef class ASendExpr
1951 # The property invoked by the send.
1952 var callsite: nullable CallSite
1953
1954 # Is self a safe call (with `x?.foo`)?
1955 # If so and the receiver is null, then the arguments won't be evaluated
1956 # and the call skipped (replaced with null).
1957 var is_safe: Bool = false
1958
1959 redef fun bad_expr_message(child)
1960 do
1961 if child == self.n_expr then
1962 return "to be the receiver of `{self.property_name}`"
1963 end
1964 return null
1965 end
1966
1967 redef fun accept_typing(v)
1968 do
1969 var nrecv = self.n_expr
1970 var recvtype = v.visit_expr(nrecv)
1971
1972 if nrecv isa ASafeExpr then
1973 # Has the receiver the form `x?.foo`?
1974 # For parsing "reasons" the `?` is in the receiver node, not the call node.
1975 is_safe = true
1976 end
1977
1978 var name = self.property_name
1979 var node = self.property_node
1980
1981 if recvtype == null then return # Forward error
1982
1983 var callsite = null
1984 var unsafe_type = v.anchor_to(recvtype)
1985 var mproperty = v.try_get_mproperty_by_name2(node, unsafe_type, name)
1986 if mproperty == null and nrecv isa AImplicitSelfExpr then
1987 # Special fall-back search in `sys` when noting found in the implicit receiver.
1988 var sysclass = v.try_get_mclass(node, "Sys")
1989 if sysclass != null then
1990 var systype = sysclass.mclass_type
1991 mproperty = v.try_get_mproperty_by_name2(node, systype, name)
1992 if mproperty != null then
1993 callsite = v.build_callsite_by_name(node, systype, name, false)
1994 if callsite == null then return # Forward error
1995 # Update information, we are looking at `sys` now, not `self`
1996 nrecv.is_sys = true
1997 nrecv.its_variable = null
1998 nrecv.mtype = systype
1999 recvtype = systype
2000 end
2001 end
2002 end
2003 if callsite == null then
2004 # If still nothing, just exit
2005 callsite = v.build_callsite_by_name(node, recvtype, name, nrecv isa ASelfExpr)
2006 if callsite == null then return
2007 end
2008
2009 self.callsite = callsite
2010 var msignature = callsite.msignature
2011
2012 var args = compute_raw_arguments
2013
2014 if not self isa ACallrefExpr then callsite.check_signature(v, node, args)
2015
2016 if callsite.mproperty.is_init then
2017 var vmpropdef = v.mpropdef
2018 if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
2019 v.error(node, "Error: an `init` can only be called from another `init`.")
2020 end
2021 if vmpropdef isa MMethodDef and vmpropdef.mproperty.is_root_init and not callsite.mproperty.is_root_init then
2022 v.error(node, "Error: `{vmpropdef}` cannot call a factory `{callsite.mproperty}`.")
2023 end
2024 end
2025
2026 var ret = msignature.return_mtype
2027 if ret != null then
2028 if is_safe then
2029 # A safe receiver makes that the call is not executed and returns null
2030 ret = ret.as_nullable
2031 end
2032 self.mtype = ret
2033 else
2034 self.is_typed = true
2035 end
2036 end
2037
2038 # The name of the property
2039 # Each subclass simply provide the correct name.
2040 private fun property_name: String is abstract
2041
2042 # The node identifying the name (id, operator, etc) for messages.
2043 #
2044 # Is `self` by default
2045 private fun property_node: ANode do return self
2046
2047 # An array of all arguments (excluding self)
2048 fun raw_arguments: Array[AExpr] do return compute_raw_arguments
2049
2050 private fun compute_raw_arguments: Array[AExpr] is abstract
2051
2052 redef fun dump_info(v) do
2053 var res = super
2054 var callsite = self.callsite
2055 if callsite != null then
2056 res += v.yellow(" call="+callsite.dump_info(v))
2057 end
2058 return res
2059 end
2060 end
2061
2062 redef class ABinopExpr
2063 redef fun compute_raw_arguments do return [n_expr2]
2064 redef fun property_name do return operator
2065 redef fun property_node do return n_op
2066 end
2067
2068 redef class AEqFormExpr
2069 redef fun accept_typing(v)
2070 do
2071 super
2072 v.null_test(self)
2073 end
2074
2075 redef fun accept_post_typing(v)
2076 do
2077 var mtype = n_expr.mtype
2078 var mtype2 = n_expr2.mtype
2079
2080 if mtype == null or mtype2 == null then return
2081
2082 if mtype == v.type_bool(self) and (n_expr2 isa AFalseExpr or n_expr2 isa ATrueExpr) then
2083 v.display_warning(self, "useless-truism", "Warning: useless comparison to a Bool literal.")
2084 end
2085
2086 if not mtype2 isa MNullType then return
2087
2088 v.check_can_be_null(n_expr, mtype)
2089 end
2090 end
2091
2092 redef class AUnaryopExpr
2093 redef fun property_name do return "unary {operator}"
2094 redef fun compute_raw_arguments do return new Array[AExpr]
2095 end
2096
2097 redef class ACallExpr
2098 redef fun property_name do return n_qid.n_id.text
2099 redef fun property_node do return n_qid
2100 redef fun compute_raw_arguments do return n_args.to_a
2101 end
2102
2103 redef class ACallAssignExpr
2104 redef fun property_name do return n_qid.n_id.text + "="
2105 redef fun property_node do return n_qid
2106 redef fun compute_raw_arguments
2107 do
2108 var res = n_args.to_a
2109 res.add(n_value)
2110 return res
2111 end
2112 end
2113
2114 redef class ABraExpr
2115 redef fun property_name do return "[]"
2116 redef fun compute_raw_arguments do return n_args.to_a
2117 end
2118
2119 redef class ABraAssignExpr
2120 redef fun property_name do return "[]="
2121 redef fun compute_raw_arguments
2122 do
2123 var res = n_args.to_a
2124 res.add(n_value)
2125 return res
2126 end
2127 end
2128
2129 redef class ASendReassignFormExpr
2130 # The property invoked for the writing
2131 var write_callsite: nullable CallSite
2132
2133 redef fun accept_typing(v)
2134 do
2135 var recvtype = v.visit_expr(self.n_expr)
2136 var name = self.property_name
2137 var node = self.property_node
2138
2139 if recvtype == null then return # Forward error
2140
2141 var for_self = self.n_expr isa ASelfExpr
2142 var callsite = v.build_callsite_by_name(node, recvtype, name, for_self)
2143
2144 if callsite == null then return
2145 self.callsite = callsite
2146
2147 var args = compute_raw_arguments
2148
2149 callsite.check_signature(v, node, args)
2150
2151 var readtype = callsite.msignature.return_mtype
2152 if readtype == null then
2153 v.error(node, "Error: `{name}` is not a function.")
2154 return
2155 end
2156
2157 var wcallsite = v.build_callsite_by_name(node, recvtype, name + "=", self.n_expr isa ASelfExpr)
2158 if wcallsite == null then return
2159 self.write_callsite = wcallsite
2160
2161 var wtype = self.resolve_reassignment(v, readtype, wcallsite.msignature.mparameters.last.mtype)
2162 if wtype == null then return
2163
2164 args = args.to_a # duplicate so raw_arguments keeps only the getter args
2165 args.add(self.n_value)
2166 wcallsite.check_signature(v, node, args)
2167
2168 self.is_typed = true
2169 end
2170 end
2171
2172 redef class ACallReassignExpr
2173 redef fun property_name do return n_qid.n_id.text
2174 redef fun property_node do return n_qid.n_id
2175 redef fun compute_raw_arguments do return n_args.to_a
2176 end
2177
2178 redef class ABraReassignExpr
2179 redef fun property_name do return "[]"
2180 redef fun compute_raw_arguments do return n_args.to_a
2181 end
2182
2183 redef class AInitExpr
2184 redef fun property_name do if n_args.n_exprs.is_empty then return "init" else return "defaultinit"
2185 redef fun property_node do return n_kwinit
2186 redef fun compute_raw_arguments do return n_args.to_a
2187 end
2188
2189 redef class ACallrefExpr
2190 redef fun property_name do return n_qid.n_id.text
2191 redef fun property_node do return n_qid
2192 redef fun compute_raw_arguments do return n_args.to_a
2193
2194 redef fun accept_typing(v)
2195 do
2196 super # do the job as if it was a real call
2197 var res = callsite.mproperty
2198
2199 var msignature = callsite.mpropdef.msignature
2200 var recv = callsite.recv
2201 assert msignature != null
2202 var arity = msignature.mparameters.length
2203
2204 var routine_type_name = "ProcRef"
2205 if msignature.return_mtype != null then
2206 routine_type_name = "FunRef"
2207 end
2208
2209 var target_routine_class = "{routine_type_name}{arity}"
2210 var routine_mclass = v.get_mclass(self, target_routine_class)
2211
2212 if routine_mclass == null then
2213 v.error(self, "Error: missing functional types, try `import functional`")
2214 return
2215 end
2216
2217 var types_list = new Array[MType]
2218 for param in msignature.mparameters do
2219 if param.is_vararg then
2220 types_list.push(v.mmodule.array_type(param.mtype))
2221 else
2222 types_list.push(param.mtype)
2223 end
2224 end
2225 if msignature.return_mtype != null then
2226 types_list.push(msignature.return_mtype.as(not null))
2227 end
2228
2229 # Why we need an anchor :
2230 #
2231 # ~~~~nitish
2232 # class A[E]
2233 # def toto(x: E) do print "{x}"
2234 # end
2235 #
2236 # var a = new A[Int]
2237 # var f = &a.toto # without anchor : ProcRef1[E]
2238 # # with anchor : ProcRef[Int]
2239 # ~~~~
2240 # However, we can only anchor if we can resolve every formal
2241 # parameter, here's an example where we can't.
2242 # ~~~~nitish
2243 # class A[E]
2244 # fun bar: A[E] do return self
2245 # fun foo: Fun0[A[E]] do return &bar # here we can't anchor
2246 # end
2247 # var f1 = a1.foo # when this expression will be evaluated,
2248 # # `a1` will anchor `&bar` returned by `foo`.
2249 # print f1.call
2250 # ~~~~
2251 var routine_type = routine_mclass.get_mtype(types_list)
2252 if not recv.need_anchor then
2253 routine_type = routine_type.anchor_to(v.mmodule, recv.as(MClassType))
2254 end
2255 is_typed = true
2256 self.mtype = routine_type
2257 end
2258 end
2259
2260 redef class AExprs
2261 fun to_a: Array[AExpr] do return self.n_exprs.to_a
2262 end
2263
2264 ###
2265
2266 redef class ASuperExpr
2267 # The method to call if the super is in fact a 'super init call'
2268 # Note: if the super is a normal call-next-method, then this attribute is null
2269 var callsite: nullable CallSite
2270
2271 # The method to call is the super is a standard `call-next-method` super-call
2272 # Note: if the super is a special super-init-call, then this attribute is null
2273 var mpropdef: nullable MMethodDef
2274
2275 redef fun accept_typing(v)
2276 do
2277 var anchor = v.anchor
2278 var recvtype = v.get_variable(self, v.selfvariable)
2279 assert recvtype != null
2280 var mproperty = v.mpropdef.mproperty
2281 if not mproperty isa MMethod then
2282 v.error(self, "Error: `super` only usable in a `method`.")
2283 return
2284 end
2285 var superprops = mproperty.lookup_super_definitions(v.mmodule, anchor)
2286 if superprops.length == 0 then
2287 if mproperty.is_init and v.mpropdef.is_intro then
2288 process_superinit(v)
2289 return
2290 end
2291 v.error(self, "Error: no super method to call for `{mproperty}`.")
2292 return
2293 end
2294 # FIXME: covariance of return type in linear extension?
2295 var superprop = superprops.first
2296
2297 var msignature = superprop.msignature.as(not null)
2298 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
2299 var args = self.n_args.to_a
2300 if args.length > 0 then
2301 signaturemap = v.check_signature(self, args, mproperty, msignature)
2302 end
2303 self.mtype = msignature.return_mtype
2304 self.is_typed = true
2305 v.mpropdef.has_supercall = true
2306 mpropdef = v.mpropdef.as(MMethodDef)
2307 end
2308
2309 # The mapping used on the call to associate arguments to parameters.
2310 # If null then no specific association is required.
2311 var signaturemap: nullable SignatureMap
2312
2313 private fun process_superinit(v: TypeVisitor)
2314 do
2315 var anchor = v.anchor
2316 var recvtype = v.get_variable(self, v.selfvariable)
2317 assert recvtype != null
2318 var mpropdef = v.mpropdef
2319 assert mpropdef isa MMethodDef
2320 var mproperty = mpropdef.mproperty
2321 var superprop: nullable MMethodDef = null
2322 for msupertype in mpropdef.mclassdef.supertypes do
2323 msupertype = msupertype.anchor_to(v.mmodule, anchor)
2324 var errcount = v.modelbuilder.toolcontext.error_count
2325 var candidate = v.try_get_mproperty_by_name2(self, msupertype, mproperty.name).as(nullable MMethod)
2326 if candidate == null then
2327 if v.modelbuilder.toolcontext.error_count > errcount then return # Forward error
2328 continue # Try next super-class
2329 end
2330 if superprop != null and candidate.is_root_init then
2331 continue
2332 end
2333 if superprop != null and superprop.mproperty != candidate and not superprop.mproperty.is_root_init then
2334 v.error(self, "Error: conflicting super constructor to call for `{mproperty}`: `{candidate.full_name}`, `{superprop.mproperty.full_name}`")
2335 return
2336 end
2337 var candidatedefs = candidate.lookup_definitions(v.mmodule, anchor)
2338 if superprop != null and superprop.mproperty == candidate then
2339 if superprop == candidatedefs.first then continue
2340 candidatedefs.add(superprop)
2341 end
2342 if candidatedefs.length > 1 then
2343 v.error(self, "Error: conflicting property definitions for property `{mproperty}` in `{recvtype}`: {candidatedefs.join(", ")}")
2344 return
2345 end
2346 superprop = candidatedefs.first
2347 end
2348 if superprop == null then
2349 v.error(self, "Error: no super method to call for `{mproperty}`.")
2350 return
2351 end
2352
2353 var msignature = superprop.msignature.as(not null)
2354 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
2355
2356 var callsite = new CallSite(hot_location, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
2357 self.callsite = callsite
2358
2359 var args = self.n_args.to_a
2360 if args.length > 0 then
2361 callsite.check_signature(v, self, args)
2362 else
2363 # Check there is at least enough parameters
2364 if mpropdef.msignature.arity < msignature.arity then
2365 v.error(self, "Error: not enough implicit arguments to pass. Got `{mpropdef.msignature.arity}`, expected at least `{msignature.arity}`. Signature is `{msignature}`.")
2366 return
2367 end
2368 # Check that each needed parameter is conform
2369 var i = 0
2370 for sp in msignature.mparameters do
2371 var p = mpropdef.msignature.mparameters[i]
2372 if not v.is_subtype(p.mtype, sp.mtype) then
2373 v.error(self, "Type Error: expected argument #{i} of type `{sp.mtype}`, got implicit argument `{p.name}` of type `{p.mtype}`. Signature is {msignature}")
2374 return
2375 end
2376 i += 1
2377 end
2378 end
2379
2380 self.is_typed = true
2381 end
2382
2383 redef fun dump_info(v) do
2384 var res = super
2385 var callsite = self.callsite
2386 if callsite != null then
2387 res += v.yellow(" super-init="+callsite.dump_info(v))
2388 end
2389 var mpropdef = self.mpropdef
2390 if mpropdef != null then
2391 res += v.yellow(" call-next-method="+mpropdef.to_s)
2392 end
2393 return res
2394 end
2395 end
2396
2397 ####
2398
2399 redef class ANewExpr
2400 # The constructor invoked by the new.
2401 var callsite: nullable CallSite
2402
2403 # The designated type
2404 var recvtype: nullable MClassType
2405
2406 redef fun accept_typing(v)
2407 do
2408 var recvtype = v.resolve_mtype(self.n_type)
2409 if recvtype == null then return
2410
2411 if not recvtype isa MClassType then
2412 if recvtype isa MNullableType then
2413 v.error(self, "Type Error: cannot instantiate the nullable type `{recvtype}`.")
2414 return
2415 else if recvtype isa MFormalType then
2416 v.error(self, "Type Error: cannot instantiate the formal type `{recvtype}`.")
2417 return
2418 else
2419 v.error(self, "Type Error: cannot instantiate the type `{recvtype}`.")
2420 return
2421 end
2422 end
2423
2424 self.recvtype = recvtype
2425 var kind = recvtype.mclass.kind
2426
2427 var name: String
2428 var nqid = self.n_qid
2429 var node: ANode
2430 if nqid != null then
2431 name = nqid.n_id.text
2432 node = nqid
2433 else
2434 name = "new"
2435 node = self.n_kwnew
2436 end
2437 if name == "intern" then
2438 if kind != concrete_kind then
2439 v.error(self, "Type Error: cannot instantiate {kind} {recvtype}.")
2440 return
2441 end
2442 if n_args.n_exprs.not_empty then
2443 v.error(n_args, "Type Error: the intern constructor expects no arguments.")
2444 return
2445 end
2446 # Our job is done
2447 self.mtype = recvtype
2448 return
2449 end
2450
2451 var callsite = v.build_callsite_by_name(node, recvtype, name, false)
2452 if callsite == null then return
2453
2454 if not callsite.mproperty.is_new then
2455 if kind != concrete_kind then
2456 v.error(self, "Type Error: cannot instantiate {kind} `{recvtype}`.")
2457 return
2458 end
2459 self.mtype = recvtype
2460 else
2461 self.mtype = callsite.msignature.return_mtype
2462 assert self.mtype != null
2463 end
2464
2465 self.callsite = callsite
2466
2467 if not callsite.mproperty.is_init_for(recvtype.mclass) then
2468 v.error(self, "Error: `{name}` is not a constructor.")
2469 return
2470 end
2471
2472 var args = n_args.to_a
2473 callsite.check_signature(v, node, args)
2474 end
2475
2476 redef fun dump_info(v) do
2477 var res = super
2478 var callsite = self.callsite
2479 if callsite != null then
2480 res += v.yellow(" call="+callsite.dump_info(v))
2481 end
2482 return res
2483 end
2484 end
2485
2486 ####
2487
2488 redef class AAttrFormExpr
2489 # The attribute accessed.
2490 var mproperty: nullable MAttribute
2491
2492 # The static type of the attribute.
2493 var attr_type: nullable MType
2494
2495 # Resolve the attribute accessed.
2496 private fun resolve_property(v: TypeVisitor)
2497 do
2498 var recvtype = v.visit_expr(self.n_expr)
2499 if recvtype == null then return # Skip error
2500 var node = self.n_id
2501 var name = node.text
2502 if recvtype isa MNullType then
2503 v.error(node, "Error: attribute `{name}` access on `null`.")
2504 return
2505 end
2506
2507 var unsafe_type = v.anchor_to(recvtype)
2508 var mproperty = v.try_get_mproperty_by_name2(node, unsafe_type, name)
2509 if mproperty == null then
2510 v.modelbuilder.error(node, "Error: attribute `{name}` does not exist in `{recvtype}`.")
2511 return
2512 end
2513 assert mproperty isa MAttribute
2514 self.mproperty = mproperty
2515
2516 var mpropdefs = mproperty.lookup_definitions(v.mmodule, unsafe_type)
2517 assert mpropdefs.length == 1
2518 var mpropdef = mpropdefs.first
2519 var attr_type = mpropdef.static_mtype
2520 if attr_type == null then return # skip error
2521 attr_type = v.resolve_for(attr_type, recvtype, self.n_expr isa ASelfExpr)
2522 self.attr_type = attr_type
2523 end
2524
2525 redef fun dump_info(v) do
2526 var res = super
2527 var mproperty = self.mproperty
2528 var attr_type = self.attr_type
2529 if mproperty != null then
2530 res += v.yellow(" attr={mproperty}:{attr_type or else "BROKEN"}")
2531 end
2532 return res
2533 end
2534 end
2535
2536 redef class AAttrExpr
2537 redef fun accept_typing(v)
2538 do
2539 self.resolve_property(v)
2540 self.mtype = self.attr_type
2541 end
2542 end
2543
2544 redef class AAttrAssignExpr
2545 redef fun accept_typing(v)
2546 do
2547 self.resolve_property(v)
2548 var mtype = self.attr_type
2549
2550 v.visit_expr_subtype(self.n_value, mtype)
2551 self.is_typed = mtype != null
2552 end
2553 end
2554
2555 redef class AAttrReassignExpr
2556 redef fun accept_typing(v)
2557 do
2558 self.resolve_property(v)
2559 var mtype = self.attr_type
2560 if mtype == null then return # Skip error
2561
2562 var rettype = self.resolve_reassignment(v, mtype, mtype)
2563
2564 self.is_typed = rettype != null
2565 end
2566 end
2567
2568 redef class AIssetAttrExpr
2569 redef fun accept_typing(v)
2570 do
2571 self.resolve_property(v)
2572 var mtype = self.attr_type
2573 if mtype == null then return # Skip error
2574
2575 var recvtype = self.n_expr.mtype.as(not null)
2576 var bound = v.resolve_for(mtype, recvtype, false)
2577 if bound isa MNullableType then
2578 v.error(n_id, "Type Error: `isset` on a nullable attribute.")
2579 end
2580 self.mtype = v.type_bool(self)
2581 end
2582 end
2583
2584 redef class ASafeExpr
2585 redef fun accept_typing(v)
2586 do
2587 var mtype = v.visit_expr(n_expr)
2588 if mtype == null then return # Skip error
2589
2590 if mtype isa MNullType then
2591 # While `null?.foo` is semantically well defined and should not execute `foo` and just return `null`,
2592 # currently `null.foo` is forbidden so it seems coherent to also forbid `null?.foo`
2593 v.modelbuilder.error(self, "Error: safe operator `?` on `null`.")
2594 return
2595 end
2596
2597 self.mtype = mtype.as_notnull
2598
2599 if not v.can_be_null(mtype) then
2600 v.display_warning(self, "useless-safe", "Warning: useless safe operator `?` on non-nullable value.")
2601 return
2602 end
2603 end
2604 end
2605
2606 redef class AVarargExpr
2607 redef fun accept_typing(v)
2608 do
2609 # This kind of pseudo-expression can be only processed trough a signature
2610 # See `check_signature`
2611 # Other cases are a syntax error.
2612 v.error(self, "Syntax Error: unexpected `...`.")
2613 end
2614 end
2615
2616 ###
2617
2618 redef class ADebugTypeExpr
2619 redef fun accept_typing(v)
2620 do
2621 var expr = v.visit_expr(self.n_expr)
2622 if expr == null then return
2623 var unsafe = v.anchor_to(expr)
2624 var ntype = self.n_type
2625 var mtype = v.resolve_mtype(ntype)
2626 if mtype != null and mtype != expr then
2627 var umtype = v.anchor_to(mtype)
2628 v.display_warning(self, "debug", "Found type {expr} (-> {unsafe}), expected {mtype} (-> {umtype})")
2629 end
2630 self.is_typed = true
2631 end
2632 end