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