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 redef var location: Location
645
646 # The static type of the receiver (possibly unresolved)
647 var recv: MType
648
649 # The module where the callsite is present
650 var mmodule: MModule
651
652 # The anchor to use with `recv` or `msignature`
653 var anchor: nullable MClassType
654
655 # Is the receiver self?
656 # If "for_self", virtual types of the signature are kept
657 # If "not_for_self", virtual type are erased
658 var recv_is_self: Bool
659
660 # The designated method
661 var mproperty: MMethod
662
663 # The statically designated method definition
664 # The most specif one, it is.
665 var mpropdef: MMethodDef
666
667 # The resolved signature for the receiver
668 var msignature: MSignature
669
670 # Is a implicit cast required on erasure typing policy?
671 var erasure_cast: Bool
672
673 # The mapping used on the call to associate arguments to parameters
674 # If null then no specific association is required.
675 var signaturemap: nullable SignatureMap = null
676
677 private fun check_signature(v: TypeVisitor, node: ANode, args: Array[AExpr]): Bool
678 do
679 var map = v.check_signature(node, args, self.mproperty, self.msignature)
680 signaturemap = map
681 if map == null then is_broken = true
682 return map == null
683 end
684 end
685
686 redef class Variable
687 # The declared type of the variable
688 var declared_type: nullable MType is writable
689
690 # Was the variable type-adapted?
691 # This is used to speedup type retrieval while it remains `false`
692 private var is_adapted = false
693 end
694
695 redef class FlowContext
696 # Store changes of types because of type evolution
697 private var vars = new HashMap[Variable, nullable MType]
698
699 # Adapt the variable to a static type
700 # Warning1: do not modify vars directly.
701 # Warning2: sub-flow may have cached a unadapted variable
702 private fun set_var(v: TypeVisitor, variable: Variable, mtype: nullable MType)
703 do
704 if variable.declared_type == mtype and not variable.is_adapted then return
705 if vars.has_key(variable) and vars[variable] == mtype then return
706 self.vars[variable] = mtype
707 v.dirty = true
708 variable.is_adapted = true
709 #node.debug "set {variable} to {mtype or else "X"}"
710 end
711
712 # Look in the flow and previous flow and collect all first reachable type adaptation of a local variable
713 private fun collect_types(variable: Variable): Array[nullable MType]
714 do
715 #node.debug "flow for {variable}"
716 var res = new Array[nullable MType]
717
718 var todo = [self]
719 var seen = new HashSet[FlowContext]
720 while not todo.is_empty do
721 var f = todo.pop
722 if f.is_unreachable then continue
723 if seen.has(f) then continue
724 seen.add f
725
726 if f.vars.has_key(variable) then
727 # Found something. Collect it and do not process further on this path
728 res.add f.vars[variable]
729 #f.node.debug "process {variable}: got {f.vars[variable] or else "X"}"
730 else
731 todo.add_all f.previous
732 todo.add_all f.loops
733 if f.previous.is_empty then
734 # Root flowcontext mean a parameter or something related
735 res.add variable.declared_type
736 #f.node.debug "root process {variable}: got {variable.declared_type or else "X"}"
737 end
738 end
739 end
740 #self.node.debug "##### end flow for {variable}: {res.join(" ")}"
741 return res
742 end
743 end
744
745 redef class APropdef
746 # The entry point of the whole typing analysis
747 fun do_typing(modelbuilder: ModelBuilder)
748 do
749 end
750
751 # The variable associated to the receiver (if any)
752 var selfvariable: nullable Variable
753 end
754
755 redef class AMethPropdef
756 redef fun do_typing(modelbuilder: ModelBuilder)
757 do
758 var mpropdef = self.mpropdef
759 if mpropdef == null then return # skip error
760
761 var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
762 self.selfvariable = v.selfvariable
763
764 var mmethoddef = self.mpropdef.as(not null)
765 var msignature = mmethoddef.msignature
766 if msignature == null then return # skip error
767 for i in [0..msignature.arity[ do
768 var mtype = msignature.mparameters[i].mtype
769 if msignature.vararg_rank == i then
770 var arrayclass = v.get_mclass(self.n_signature.n_params[i], "Array")
771 if arrayclass == null then return # Skip error
772 mtype = arrayclass.get_mtype([mtype])
773 end
774 var variable = self.n_signature.n_params[i].variable
775 assert variable != null
776 variable.declared_type = mtype
777 end
778
779 var nblock = self.n_block
780 if nblock == null then return
781
782 loop
783 v.dirty = false
784 v.visit_stmt(nblock)
785 if not v.has_loop or not v.dirty then break
786 end
787
788 var post_visitor = new PostTypingVisitor(v)
789 post_visitor.enter_visit(self)
790
791 if not nblock.after_flow_context.is_unreachable and msignature.return_mtype != null then
792 # We reach the end of the function without having a return, it is bad
793 v.error(self, "Error: reached end of function; expected `return` with a value.")
794 end
795 end
796 end
797
798 private class PostTypingVisitor
799 super Visitor
800 var type_visitor: TypeVisitor
801 redef fun visit(n) do
802 n.visit_all(self)
803 n.accept_post_typing(type_visitor)
804 if n isa AExpr and n.mtype == null and not n.is_typed then
805 n.is_broken = true
806 end
807 end
808 end
809
810 redef class ANode
811 private fun accept_post_typing(v: TypeVisitor) do end
812
813 # An additional information message to explain the role of a child expression.
814 #
815 # The point of the method is to allow some kind of double dispatch so the parent
816 # choose how to describe its children.
817 private fun bad_expr_message(child: AExpr): nullable String do return null
818 end
819
820 redef class AAttrPropdef
821 redef fun do_typing(modelbuilder: ModelBuilder)
822 do
823 if not has_value then return
824
825 var mpropdef = self.mreadpropdef
826 if mpropdef == null or mpropdef.msignature == null then return # skip error
827
828 var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
829 self.selfvariable = v.selfvariable
830
831 var nexpr = self.n_expr
832 if nexpr != null then
833 var mtype = self.mtype
834 v.visit_expr_subtype(nexpr, mtype)
835 end
836 var nblock = self.n_block
837 if nblock != null then
838 v.visit_stmt(nblock)
839 if not nblock.after_flow_context.is_unreachable then
840 # We reach the end of the init without having a return, it is bad
841 v.error(self, "Error: reached end of block; expected `return`.")
842 end
843 end
844 end
845 end
846
847 ###
848
849 redef class AExpr
850 # The static type of the expression.
851 # null if self is a statement or in case of error
852 var mtype: nullable MType = null
853
854 # Is the statement correctly typed?
855 # Used to distinguish errors and statements when `mtype == null`
856 var is_typed: Bool = false
857
858 # If required, the following implicit cast `.as(XXX)`
859 # Such a cast may by required after evaluating the expression when
860 # a unsafe operation is detected (silently accepted by the Nit language).
861 # The attribute is computed by `check_subtype`
862 var implicit_cast_to: nullable MType = null
863
864 # Return the variable read (if any)
865 # Used to perform adaptive typing
866 fun its_variable: nullable Variable do return null
867
868 private fun accept_typing(v: TypeVisitor)
869 do
870 v.error(self, "no implemented accept_typing for {self.class_name}")
871 end
872
873 # Is non-null if `self` is a leaf of a comprehension array construction.
874 # In this case, the enclosing literal array node is designated.
875 # The result of the evaluation of `self` must be
876 # stored inside the designated array (there is an implicit `push`)
877 var comprehension: nullable AArrayExpr = null
878
879 # It indicates the number of arguments collected as a vararg.
880 #
881 # When 0, the argument is used as is, without transformation.
882 # When 1, the argument is transformed into an singleton array.
883 # Above 1, the arguments and the next ones are transformed into a common array.
884 #
885 # This attribute is meaning less on expressions not used as attributes.
886 var vararg_decl: Int = 0
887 end
888
889 redef class ABlockExpr
890 redef fun accept_typing(v)
891 do
892 for e in self.n_expr do v.visit_stmt(e)
893 self.is_typed = true
894 end
895
896 # The type of a blockexpr is the one of the last expression (or null if empty)
897 redef fun mtype
898 do
899 if self.n_expr.is_empty then return null
900 return self.n_expr.last.mtype
901 end
902 end
903
904 redef class AVardeclExpr
905 redef fun accept_typing(v)
906 do
907 var variable = self.variable
908 if variable == null then return # Skip error
909
910 var ntype = self.n_type
911 var mtype: nullable MType
912 if ntype == null then
913 mtype = null
914 else
915 mtype = v.resolve_mtype(ntype)
916 if mtype == null then return # Skip error
917 end
918
919 var nexpr = self.n_expr
920 if nexpr != null then
921 if mtype != null then
922 var etype = v.visit_expr_subtype(nexpr, mtype)
923 if etype == mtype then
924 assert ntype != null
925 v.modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition for variable `{variable.name}`")
926 end
927 else
928 mtype = v.visit_expr(nexpr)
929 if mtype == null then return # Skip error
930 end
931 end
932
933 var decltype = mtype
934 if mtype == null or mtype isa MNullType then
935 var objclass = v.get_mclass(self, "Object")
936 if objclass == null then return # skip error
937 decltype = objclass.mclass_type.as_nullable
938 if mtype == null then mtype = decltype
939 end
940
941 variable.declared_type = decltype
942 v.set_variable(self, variable, mtype)
943
944 #debug("var {variable}: {mtype}")
945
946 self.mtype = mtype
947 self.is_typed = true
948 end
949 end
950
951 redef class AVarExpr
952 redef fun its_variable do return self.variable
953 redef fun accept_typing(v)
954 do
955 var variable = self.variable
956 if variable == null then return # Skip error
957
958 var mtype = v.get_variable(self, variable)
959 if mtype != null then
960 #debug("{variable} is {mtype}")
961 else
962 #debug("{variable} is untyped")
963 end
964
965 self.mtype = mtype
966 end
967 end
968
969 redef class AVarAssignExpr
970 redef fun accept_typing(v)
971 do
972 var variable = self.variable
973 assert variable != null
974
975 var mtype = v.visit_expr_subtype(n_value, variable.declared_type)
976
977 v.set_variable(self, variable, mtype)
978
979 self.is_typed = true
980 end
981 end
982
983 redef class AReassignFormExpr
984 # The method designed by the reassign operator.
985 var reassign_callsite: nullable CallSite
986
987 var read_type: nullable MType = null
988
989 # Determine the `reassign_property`
990 # `readtype` is the type of the reading of the left value.
991 # `writetype` is the type of the writing of the left value.
992 # (Because of `ACallReassignExpr`, both can be different.
993 # Return the static type of the value to store.
994 private fun resolve_reassignment(v: TypeVisitor, readtype, writetype: MType): nullable MType
995 do
996 var reassign_name = self.n_assign_op.operator
997
998 self.read_type = readtype
999
1000 var callsite = v.get_method(self.n_assign_op, readtype, reassign_name, false)
1001 if callsite == null then return null # Skip error
1002 self.reassign_callsite = callsite
1003
1004 var msignature = callsite.msignature
1005 var rettype = msignature.return_mtype
1006 assert msignature.arity == 1 and rettype != null
1007
1008 var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype)
1009 if value_type == null then return null # Skip error
1010
1011 v.check_subtype(self, rettype, writetype, false)
1012 return rettype
1013 end
1014 end
1015
1016 redef class AVarReassignExpr
1017 redef fun accept_typing(v)
1018 do
1019 var variable = self.variable
1020 assert variable != null
1021
1022 var readtype = v.get_variable(self, variable)
1023 if readtype == null then return
1024
1025 read_type = readtype
1026
1027 var writetype = variable.declared_type
1028 if writetype == null then return
1029
1030 var rettype = self.resolve_reassignment(v, readtype, writetype)
1031
1032 v.set_variable(self, variable, rettype)
1033
1034 self.is_typed = rettype != null
1035 end
1036 end
1037
1038
1039 redef class AContinueExpr
1040 redef fun accept_typing(v)
1041 do
1042 var nexpr = self.n_expr
1043 if nexpr != null then
1044 v.visit_expr(nexpr)
1045 end
1046 self.is_typed = true
1047 end
1048 end
1049
1050 redef class ABreakExpr
1051 redef fun accept_typing(v)
1052 do
1053 var nexpr = self.n_expr
1054 if nexpr != null then
1055 v.visit_expr(nexpr)
1056 end
1057 self.is_typed = true
1058 end
1059 end
1060
1061 redef class AReturnExpr
1062 redef fun accept_typing(v)
1063 do
1064 var nexpr = self.n_expr
1065 var ret_type
1066 var mpropdef = v.mpropdef
1067 if mpropdef isa MMethodDef then
1068 ret_type = mpropdef.msignature.return_mtype
1069 else if mpropdef isa MAttributeDef then
1070 ret_type = mpropdef.static_mtype
1071 else
1072 abort
1073 end
1074 if nexpr != null then
1075 if ret_type != null then
1076 v.visit_expr_subtype(nexpr, ret_type)
1077 else
1078 v.visit_expr(nexpr)
1079 v.error(nexpr, "Error: `return` with value in a procedure.")
1080 return
1081 end
1082 else if ret_type != null then
1083 v.error(self, "Error: `return` without value in a function.")
1084 return
1085 end
1086 self.is_typed = true
1087 end
1088 end
1089
1090 redef class AAbortExpr
1091 redef fun accept_typing(v)
1092 do
1093 self.is_typed = true
1094 end
1095 end
1096
1097 redef class AIfExpr
1098 redef fun accept_typing(v)
1099 do
1100 v.visit_expr_bool(n_expr)
1101
1102 v.visit_stmt(n_then)
1103 v.visit_stmt(n_else)
1104
1105 self.is_typed = true
1106
1107 if n_then != null and n_else == null then
1108 self.mtype = n_then.mtype
1109 end
1110 end
1111 end
1112
1113 redef class AIfexprExpr
1114 redef fun accept_typing(v)
1115 do
1116 v.visit_expr_bool(n_expr)
1117
1118 var t1 = v.visit_expr(n_then)
1119 var t2 = v.visit_expr(n_else)
1120
1121 if t1 == null or t2 == null then
1122 return # Skip error
1123 end
1124
1125 var t = v.merge_types(self, [t1, t2])
1126 if t == null then
1127 v.error(self, "Type Error: ambiguous type `{t1}` vs `{t2}`.")
1128 end
1129 self.mtype = t
1130 end
1131 end
1132
1133 redef class ADoExpr
1134 redef fun accept_typing(v)
1135 do
1136 v.visit_stmt(n_block)
1137 v.visit_stmt(n_catch)
1138 self.is_typed = true
1139 end
1140 end
1141
1142 redef class AWhileExpr
1143 redef fun accept_typing(v)
1144 do
1145 v.has_loop = true
1146 v.visit_expr_bool(n_expr)
1147 v.visit_stmt(n_block)
1148 self.is_typed = true
1149 end
1150 end
1151
1152 redef class ALoopExpr
1153 redef fun accept_typing(v)
1154 do
1155 v.has_loop = true
1156 v.visit_stmt(n_block)
1157 self.is_typed = true
1158 end
1159 end
1160
1161 redef class AForExpr
1162 redef fun accept_typing(v)
1163 do
1164 v.has_loop = true
1165
1166 for g in n_groups do
1167 var mtype = v.visit_expr(g.n_expr)
1168 if mtype == null then return
1169 g.do_type_iterator(v, mtype)
1170 if g.is_broken then is_broken = true
1171 end
1172
1173 v.visit_stmt(n_block)
1174
1175 self.mtype = n_block.mtype
1176 self.is_typed = true
1177 end
1178 end
1179
1180 redef class AForGroup
1181 var coltype: nullable MClassType
1182
1183 var method_iterator: nullable CallSite
1184 var method_is_ok: nullable CallSite
1185 var method_item: nullable CallSite
1186 var method_next: nullable CallSite
1187 var method_key: nullable CallSite
1188 var method_finish: nullable CallSite
1189
1190 var method_lt: nullable CallSite
1191 var method_successor: nullable CallSite
1192
1193 private fun do_type_iterator(v: TypeVisitor, mtype: MType)
1194 do
1195 if mtype isa MNullType then
1196 v.error(self, "Type Error: `for` cannot iterate over `null`.")
1197 return
1198 end
1199
1200 # get obj class
1201 var objcla = v.get_mclass(self, "Object")
1202 if objcla == null then return
1203
1204 # check iterator method
1205 var itdef = v.get_method(self, mtype, "iterator", n_expr isa ASelfExpr)
1206 if itdef == null then
1207 v.error(self, "Type Error: `for` expects a type providing an `iterator` method, got `{mtype}`.")
1208 return
1209 end
1210 self.method_iterator = itdef
1211
1212 # check that iterator return something
1213 var ittype = itdef.msignature.return_mtype
1214 if ittype == null then
1215 v.error(self, "Type Error: `for` expects the method `iterator` to return an `Iterator` or `MapIterator` type.")
1216 return
1217 end
1218
1219 # get iterator type
1220 var colit_cla = v.try_get_mclass(self, "Iterator")
1221 var mapit_cla = v.try_get_mclass(self, "MapIterator")
1222 var is_col = false
1223 var is_map = false
1224
1225 if colit_cla != null and v.is_subtype(ittype, colit_cla.get_mtype([objcla.mclass_type.as_nullable])) then
1226 # Iterator
1227 var coltype = ittype.supertype_to(v.mmodule, v.anchor, colit_cla)
1228 var variables = self.variables
1229 if variables.length != 1 then
1230 v.error(self, "Type Error: `for` expects only one variable when using `Iterator`.")
1231 else
1232 variables.first.declared_type = coltype.arguments.first
1233 end
1234 is_col = true
1235 end
1236
1237 if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type.as_nullable, objcla.mclass_type.as_nullable])) then
1238 # Map Iterator
1239 var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
1240 var variables = self.variables
1241 if variables.length != 2 then
1242 v.error(self, "Type Error: `for` expects two variables when using `MapIterator`.")
1243 else
1244 variables[0].declared_type = coltype.arguments[0]
1245 variables[1].declared_type = coltype.arguments[1]
1246 end
1247 is_map = true
1248 end
1249
1250 if not is_col and not is_map then
1251 v.error(self, "Type Error: `for` expects the method `iterator` to return an `Iterator` or `MapIterator` type.")
1252 return
1253 end
1254
1255 # anchor formal and virtual types
1256 if mtype.need_anchor then mtype = v.anchor_to(mtype)
1257
1258 mtype = mtype.undecorate
1259 self.coltype = mtype.as(MClassType)
1260
1261 # get methods is_ok, next, item
1262 var ikdef = v.get_method(self, ittype, "is_ok", false)
1263 if ikdef == null then
1264 v.error(self, "Type Error: `for` expects a method `is_ok` in type `{ittype}`.")
1265 return
1266 end
1267 self.method_is_ok = ikdef
1268
1269 var itemdef = v.get_method(self, ittype, "item", false)
1270 if itemdef == null then
1271 v.error(self, "Type Error: `for` expects a method `item` in type `{ittype}`.")
1272 return
1273 end
1274 self.method_item = itemdef
1275
1276 var nextdef = v.get_method(self, ittype, "next", false)
1277 if nextdef == null then
1278 v.error(self, "Type Error: `for` expects a method `next` in type {ittype}.")
1279 return
1280 end
1281 self.method_next = nextdef
1282
1283 self.method_finish = v.try_get_method(self, ittype, "finish", false)
1284
1285 if is_map then
1286 var keydef = v.get_method(self, ittype, "key", false)
1287 if keydef == null then
1288 v.error(self, "Type Error: `for` expects a method `key` in type `{ittype}`.")
1289 return
1290 end
1291 self.method_key = keydef
1292 end
1293
1294 if self.variables.length == 1 and n_expr isa ARangeExpr then
1295 var variable = variables.first
1296 var vtype = variable.declared_type.as(not null)
1297
1298 if n_expr isa AOrangeExpr then
1299 self.method_lt = v.get_method(self, vtype, "<", false)
1300 else
1301 self.method_lt = v.get_method(self, vtype, "<=", false)
1302 end
1303
1304 self.method_successor = v.get_method(self, vtype, "successor", false)
1305 end
1306 end
1307 end
1308
1309 redef class AWithExpr
1310 var method_start: nullable CallSite
1311 var method_finish: nullable CallSite
1312
1313 redef fun accept_typing(v: TypeVisitor)
1314 do
1315 var mtype = v.visit_expr(n_expr)
1316 if mtype == null then return
1317
1318 method_start = v.get_method(self, mtype, "start", n_expr isa ASelfExpr)
1319 method_finish = v.get_method(self, mtype, "finish", n_expr isa ASelfExpr)
1320
1321 v.visit_stmt(n_block)
1322 self.mtype = n_block.mtype
1323 self.is_typed = true
1324 end
1325 end
1326
1327 redef class AAssertExpr
1328 redef fun accept_typing(v)
1329 do
1330 v.visit_expr_bool(n_expr)
1331
1332 v.visit_stmt(n_else)
1333 self.is_typed = true
1334 end
1335 end
1336
1337 redef class AOrExpr
1338 redef fun accept_typing(v)
1339 do
1340 v.visit_expr_bool(n_expr)
1341 v.visit_expr_bool(n_expr2)
1342 self.mtype = v.type_bool(self)
1343 end
1344 end
1345
1346 redef class AImpliesExpr
1347 redef fun accept_typing(v)
1348 do
1349 v.visit_expr_bool(n_expr)
1350 v.visit_expr_bool(n_expr2)
1351 self.mtype = v.type_bool(self)
1352 end
1353 end
1354
1355 redef class AAndExpr
1356 redef fun accept_typing(v)
1357 do
1358 v.visit_expr_bool(n_expr)
1359 v.visit_expr_bool(n_expr2)
1360 self.mtype = v.type_bool(self)
1361 end
1362 end
1363
1364
1365 redef class ANotExpr
1366 redef fun accept_typing(v)
1367 do
1368 v.visit_expr_bool(n_expr)
1369 self.mtype = v.type_bool(self)
1370 end
1371 end
1372
1373 redef class AOrElseExpr
1374 redef fun accept_typing(v)
1375 do
1376 var t1 = v.visit_expr(n_expr)
1377 var t2 = v.visit_expr(n_expr2)
1378
1379 if t1 == null or t2 == null then
1380 return # Skip error
1381 end
1382
1383 if t1 isa MNullType then
1384 self.mtype = t2
1385 return
1386 else if v.can_be_null(t1) then
1387 t1 = t1.as_notnull
1388 end
1389
1390 var t = v.merge_types(self, [t1, t2])
1391 if t == null then
1392 var c = v.get_mclass(self, "Object")
1393 if c == null then return # forward error
1394 t = c.mclass_type
1395 if v.can_be_null(t2) then
1396 t = t.as_nullable
1397 end
1398 #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
1399 end
1400 self.mtype = t
1401 end
1402
1403 redef fun accept_post_typing(v)
1404 do
1405 var t1 = n_expr.mtype
1406 if t1 == null then
1407 return
1408 else
1409 v.check_can_be_null(n_expr, t1)
1410 end
1411 end
1412 end
1413
1414 redef class ATrueExpr
1415 redef fun accept_typing(v)
1416 do
1417 self.mtype = v.type_bool(self)
1418 end
1419 end
1420
1421 redef class AFalseExpr
1422 redef fun accept_typing(v)
1423 do
1424 self.mtype = v.type_bool(self)
1425 end
1426 end
1427
1428 redef class AIntegerExpr
1429 redef fun accept_typing(v)
1430 do
1431 var mclass: nullable MClass = null
1432 if value isa Byte then
1433 mclass = v.get_mclass(self, "Byte")
1434 else if value isa Int then
1435 mclass = v.get_mclass(self, "Int")
1436 else if value isa Int8 then
1437 mclass = v.get_mclass(self, "Int8")
1438 else if value isa Int16 then
1439 mclass = v.get_mclass(self, "Int16")
1440 else if value isa UInt16 then
1441 mclass = v.get_mclass(self, "UInt16")
1442 else if value isa Int32 then
1443 mclass = v.get_mclass(self, "Int32")
1444 else if value isa UInt32 then
1445 mclass = v.get_mclass(self, "UInt32")
1446 end
1447 if mclass == null then return # Forward error
1448 self.mtype = mclass.mclass_type
1449 end
1450 end
1451
1452 redef class AFloatExpr
1453 redef fun accept_typing(v)
1454 do
1455 var mclass = v.get_mclass(self, "Float")
1456 if mclass == null then return # Forward error
1457 self.mtype = mclass.mclass_type
1458 end
1459 end
1460
1461 redef class ACharExpr
1462 redef fun accept_typing(v) do
1463 var mclass: nullable MClass = null
1464 if is_ascii then
1465 mclass = v.get_mclass(self, "Byte")
1466 else if is_code_point then
1467 mclass = v.get_mclass(self, "Int")
1468 else
1469 mclass = v.get_mclass(self, "Char")
1470 end
1471 if mclass == null then return # Forward error
1472 self.mtype = mclass.mclass_type
1473 end
1474 end
1475
1476 redef class AugmentedStringFormExpr
1477 super AExpr
1478
1479 # Text::to_re, used for prefix `re`
1480 var to_re: nullable CallSite = null
1481 # Regex::ignore_case, used for suffix `i` on `re`
1482 var ignore_case: nullable CallSite = null
1483 # Regex::newline, used for suffix `m` on `re`
1484 var newline: nullable CallSite = null
1485 # Regex::extended, used for suffix `b` on `re`
1486 var extended: nullable CallSite = null
1487 # NativeString::to_bytes_with_copy, used for prefix `b`
1488 var to_bytes_with_copy: nullable CallSite = null
1489
1490 redef fun accept_typing(v) do
1491 var mclass = v.get_mclass(self, "String")
1492 if mclass == null then return # Forward error
1493 if is_bytestring then
1494 to_bytes_with_copy = v.get_method(self, v.mmodule.native_string_type, "to_bytes_with_copy", false)
1495 mclass = v.get_mclass(self, "Bytes")
1496 else if is_re then
1497 to_re = v.get_method(self, mclass.mclass_type, "to_re", false)
1498 for i in suffix.chars do
1499 mclass = v.get_mclass(self, "Regex")
1500 if mclass == null then
1501 v.error(self, "Error: `Regex` class unknown")
1502 return
1503 end
1504 var service = ""
1505 if i == 'i' then
1506 service = "ignore_case="
1507 ignore_case = v.get_method(self, mclass.mclass_type, service, false)
1508 else if i == 'm' then
1509 service = "newline="
1510 newline = v.get_method(self, mclass.mclass_type, service, false)
1511 else if i == 'b' then
1512 service = "extended="
1513 extended = v.get_method(self, mclass.mclass_type, service, false)
1514 else
1515 v.error(self, "Type Error: Unrecognized suffix {i} in prefixed Regex")
1516 abort
1517 end
1518 end
1519 end
1520 if mclass == null then return # Forward error
1521 mtype = mclass.mclass_type
1522 end
1523 end
1524
1525 redef class ASuperstringExpr
1526 redef fun accept_typing(v)
1527 do
1528 super
1529 var objclass = v.get_mclass(self, "Object")
1530 if objclass == null then return # Forward error
1531 var objtype = objclass.mclass_type
1532 for nexpr in self.n_exprs do
1533 v.visit_expr_subtype(nexpr, objtype)
1534 end
1535 end
1536 end
1537
1538 redef class AArrayExpr
1539 # The `with_capacity` method on Array
1540 var with_capacity_callsite: nullable CallSite
1541
1542 # The `push` method on arrays
1543 var push_callsite: nullable CallSite
1544
1545 # The element of each type
1546 var element_mtype: nullable MType
1547
1548 # Set that `self` is a part of comprehension array `na`
1549 # If `self` is a `for`, or a `if`, then `set_comprehension` is recursively applied.
1550 private fun set_comprehension(n: nullable AExpr)
1551 do
1552 if n == null then
1553 return
1554 else if n isa AForExpr then
1555 set_comprehension(n.n_block)
1556 else if n isa AIfExpr then
1557 set_comprehension(n.n_then)
1558 set_comprehension(n.n_else)
1559 else
1560 # is a leave
1561 n.comprehension = self
1562 end
1563 end
1564 redef fun accept_typing(v)
1565 do
1566 var mtype: nullable MType = null
1567 var ntype = self.n_type
1568 if ntype != null then
1569 mtype = v.resolve_mtype(ntype)
1570 if mtype == null then return # Skip error
1571 end
1572 var mtypes = new Array[nullable MType]
1573 var useless = false
1574 for e in self.n_exprs do
1575 var t = v.visit_expr(e)
1576 if t == null then
1577 return # Skip error
1578 end
1579 set_comprehension(e)
1580 if mtype != null then
1581 if v.check_subtype(e, t, mtype, false) == null then return # Forward error
1582 if t == mtype then useless = true
1583 else
1584 mtypes.add(t)
1585 end
1586 end
1587 if mtype == null then
1588 # Ensure monotony for type adaptation on loops
1589 if self.element_mtype != null then mtypes.add self.element_mtype
1590 mtype = v.merge_types(self, mtypes)
1591 end
1592 if mtype == null or mtype isa MNullType then
1593 v.error(self, "Type Error: ambiguous array type {mtypes.join(" ")}")
1594 return
1595 end
1596 if useless then
1597 assert ntype != null
1598 v.modelbuilder.warning(ntype, "useless-type", "Warning: useless type declaration `{mtype}` in literal Array since it can be inferred from the elements type.")
1599 end
1600
1601 self.element_mtype = mtype
1602
1603 var mclass = v.get_mclass(self, "Array")
1604 if mclass == null then return # Forward error
1605 var array_mtype = mclass.get_mtype([mtype])
1606
1607 with_capacity_callsite = v.get_method(self, array_mtype, "with_capacity", false)
1608 push_callsite = v.get_method(self, array_mtype, "push", false)
1609
1610 self.mtype = array_mtype
1611 end
1612 end
1613
1614 redef class ARangeExpr
1615 var init_callsite: nullable CallSite
1616
1617 redef fun accept_typing(v)
1618 do
1619 var discrete_class = v.get_mclass(self, "Discrete")
1620 if discrete_class == null then return # Forward error
1621 var discrete_type = discrete_class.intro.bound_mtype
1622 var t1 = v.visit_expr_subtype(self.n_expr, discrete_type)
1623 var t2 = v.visit_expr_subtype(self.n_expr2, discrete_type)
1624 if t1 == null or t2 == null then return
1625 var mclass = v.get_mclass(self, "Range")
1626 if mclass == null then return # Forward error
1627 var mtype
1628 if v.is_subtype(t1, t2) then
1629 mtype = mclass.get_mtype([t2])
1630 else if v.is_subtype(t2, t1) then
1631 mtype = mclass.get_mtype([t1])
1632 else
1633 v.error(self, "Type Error: cannot create range: `{t1}` vs `{t2}`.")
1634 return
1635 end
1636
1637 self.mtype = mtype
1638
1639 # get the constructor
1640 var callsite
1641 if self isa ACrangeExpr then
1642 callsite = v.get_method(self, mtype, "autoinit", false)
1643 else if self isa AOrangeExpr then
1644 callsite = v.get_method(self, mtype, "without_last", false)
1645 else
1646 abort
1647 end
1648 init_callsite = callsite
1649 end
1650 end
1651
1652 redef class ANullExpr
1653 redef fun accept_typing(v)
1654 do
1655 self.mtype = v.mmodule.model.null_type
1656 end
1657 end
1658
1659 redef class AIsaExpr
1660 # The static type to cast to.
1661 # (different from the static type of the expression that is `Bool`).
1662 var cast_type: nullable MType
1663 redef fun accept_typing(v)
1664 do
1665 v.visit_expr(n_expr)
1666
1667 var mtype = v.resolve_mtype(n_type)
1668
1669 self.cast_type = mtype
1670
1671 var variable = self.n_expr.its_variable
1672 if variable != null then
1673 var orig = self.n_expr.mtype
1674 #var from = if orig != null then orig.to_s else "invalid"
1675 #var to = if mtype != null then mtype.to_s else "invalid"
1676 #debug("adapt {variable}: {from} -> {to}")
1677
1678 # Do not adapt if there is no information gain (i.e. adapt to a supertype)
1679 if mtype == null or orig == null or not v.is_subtype(orig, mtype) then
1680 self.after_flow_context.when_true.set_var(v, variable, mtype)
1681 end
1682 end
1683
1684 self.mtype = v.type_bool(self)
1685 end
1686
1687 redef fun accept_post_typing(v)
1688 do
1689 v.check_expr_cast(self, self.n_expr, self.n_type)
1690 end
1691 end
1692
1693 redef class AAsCastExpr
1694 redef fun accept_typing(v)
1695 do
1696 v.visit_expr(n_expr)
1697
1698 self.mtype = v.resolve_mtype(n_type)
1699 end
1700
1701 redef fun accept_post_typing(v)
1702 do
1703 v.check_expr_cast(self, self.n_expr, self.n_type)
1704 end
1705 end
1706
1707 redef class AAsNotnullExpr
1708 redef fun accept_typing(v)
1709 do
1710 var mtype = v.visit_expr(self.n_expr)
1711 if mtype == null then return # Forward error
1712
1713 if mtype isa MNullType then
1714 v.error(self, "Type Error: `as(not null)` on `null`.")
1715 return
1716 end
1717
1718 if v.can_be_null(mtype) then
1719 mtype = mtype.as_notnull
1720 end
1721
1722 self.mtype = mtype
1723 end
1724
1725 redef fun accept_post_typing(v)
1726 do
1727 var mtype = n_expr.mtype
1728 if mtype == null then return
1729 v.check_can_be_null(n_expr, mtype)
1730 end
1731 end
1732
1733 redef class AParExpr
1734 redef fun accept_typing(v)
1735 do
1736 self.mtype = v.visit_expr(self.n_expr)
1737 end
1738 end
1739
1740 redef class AOnceExpr
1741 redef fun accept_typing(v)
1742 do
1743 self.mtype = v.visit_expr(self.n_expr)
1744 end
1745 end
1746
1747 redef class ASelfExpr
1748 redef var its_variable: nullable Variable
1749 redef fun accept_typing(v)
1750 do
1751 if v.is_toplevel_context and not self isa AImplicitSelfExpr then
1752 v.error(self, "Error: `self` cannot be used in top-level method.")
1753 end
1754 var variable = v.selfvariable
1755 self.its_variable = variable
1756 self.mtype = v.get_variable(self, variable)
1757 end
1758 end
1759
1760 redef class AImplicitSelfExpr
1761 # Is the implicit receiver `sys`?
1762 #
1763 # By default, the implicit receiver is `self`.
1764 # But when there is not method for `self`, `sys` is used as a fall-back.
1765 # Is this case this flag is set to `true`.
1766 var is_sys = false
1767 end
1768
1769 ## MESSAGE SENDING AND PROPERTY
1770
1771 redef class ASendExpr
1772 # The property invoked by the send.
1773 var callsite: nullable CallSite
1774
1775 redef fun bad_expr_message(child)
1776 do
1777 if child == self.n_expr then
1778 return "to be the receiver of `{self.property_name}`"
1779 end
1780 return null
1781 end
1782
1783 redef fun accept_typing(v)
1784 do
1785 var nrecv = self.n_expr
1786 var recvtype = v.visit_expr(nrecv)
1787 var name = self.property_name
1788 var node = self.property_node
1789
1790 if recvtype == null then return # Forward error
1791
1792 var callsite = null
1793 var unsafe_type = v.anchor_to(recvtype)
1794 var mproperty = v.try_get_mproperty_by_name2(node, unsafe_type, name)
1795 if mproperty == null and nrecv isa AImplicitSelfExpr then
1796 # Special fall-back search in `sys` when noting found in the implicit receiver.
1797 var sysclass = v.try_get_mclass(node, "Sys")
1798 if sysclass != null then
1799 var systype = sysclass.mclass_type
1800 mproperty = v.try_get_mproperty_by_name2(node, systype, name)
1801 if mproperty != null then
1802 callsite = v.get_method(node, systype, name, false)
1803 if callsite == null then return # Forward error
1804 # Update information, we are looking at `sys` now, not `self`
1805 nrecv.is_sys = true
1806 nrecv.its_variable = null
1807 nrecv.mtype = systype
1808 recvtype = systype
1809 end
1810 end
1811 end
1812 if callsite == null then
1813 # If still nothing, just exit
1814 callsite = v.get_method(node, recvtype, name, nrecv isa ASelfExpr)
1815 if callsite == null then return
1816 end
1817
1818 self.callsite = callsite
1819 var msignature = callsite.msignature
1820
1821 var args = compute_raw_arguments
1822
1823 callsite.check_signature(v, node, args)
1824
1825 if callsite.mproperty.is_init then
1826 var vmpropdef = v.mpropdef
1827 if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
1828 v.error(node, "Error: an `init` can only be called from another `init`.")
1829 end
1830 if vmpropdef isa MMethodDef and vmpropdef.mproperty.is_root_init and not callsite.mproperty.is_root_init then
1831 v.error(node, "Error: `{vmpropdef}` cannot call a factory `{callsite.mproperty}`.")
1832 end
1833 end
1834
1835 var ret = msignature.return_mtype
1836 if ret != null then
1837 self.mtype = ret
1838 else
1839 self.is_typed = true
1840 end
1841 end
1842
1843 # The name of the property
1844 # Each subclass simply provide the correct name.
1845 private fun property_name: String is abstract
1846
1847 # The node identifying the name (id, operator, etc) for messages.
1848 #
1849 # Is `self` by default
1850 private fun property_node: ANode do return self
1851
1852 # An array of all arguments (excluding self)
1853 fun raw_arguments: Array[AExpr] do return compute_raw_arguments
1854
1855 private fun compute_raw_arguments: Array[AExpr] is abstract
1856 end
1857
1858 redef class ABinopExpr
1859 redef fun compute_raw_arguments do return [n_expr2]
1860 redef fun property_name do return operator
1861 redef fun property_node do return n_op
1862 end
1863
1864 redef class AEqFormExpr
1865 redef fun accept_typing(v)
1866 do
1867 super
1868 v.null_test(self)
1869 end
1870
1871 redef fun accept_post_typing(v)
1872 do
1873 var mtype = n_expr.mtype
1874 var mtype2 = n_expr2.mtype
1875
1876 if mtype == null or mtype2 == null then return
1877
1878 if not mtype2 isa MNullType then return
1879
1880 v.check_can_be_null(n_expr, mtype)
1881 end
1882 end
1883
1884 redef class AUnaryopExpr
1885 redef fun property_name do return "unary {operator}"
1886 redef fun compute_raw_arguments do return new Array[AExpr]
1887 end
1888
1889
1890 redef class ACallExpr
1891 redef fun property_name do return n_qid.n_id.text
1892 redef fun property_node do return n_qid
1893 redef fun compute_raw_arguments do return n_args.to_a
1894 end
1895
1896 redef class ACallAssignExpr
1897 redef fun property_name do return n_qid.n_id.text + "="
1898 redef fun property_node do return n_qid
1899 redef fun compute_raw_arguments
1900 do
1901 var res = n_args.to_a
1902 res.add(n_value)
1903 return res
1904 end
1905 end
1906
1907 redef class ABraExpr
1908 redef fun property_name do return "[]"
1909 redef fun compute_raw_arguments do return n_args.to_a
1910 end
1911
1912 redef class ABraAssignExpr
1913 redef fun property_name do return "[]="
1914 redef fun compute_raw_arguments
1915 do
1916 var res = n_args.to_a
1917 res.add(n_value)
1918 return res
1919 end
1920 end
1921
1922 redef class ASendReassignFormExpr
1923 # The property invoked for the writing
1924 var write_callsite: nullable CallSite
1925
1926 redef fun accept_typing(v)
1927 do
1928 var recvtype = v.visit_expr(self.n_expr)
1929 var name = self.property_name
1930 var node = self.property_node
1931
1932 if recvtype == null then return # Forward error
1933
1934 var for_self = self.n_expr isa ASelfExpr
1935 var callsite = v.get_method(node, recvtype, name, for_self)
1936
1937 if callsite == null then return
1938 self.callsite = callsite
1939
1940 var args = compute_raw_arguments
1941
1942 callsite.check_signature(v, node, args)
1943
1944 var readtype = callsite.msignature.return_mtype
1945 if readtype == null then
1946 v.error(node, "Error: `{name}` is not a function.")
1947 return
1948 end
1949
1950 var wcallsite = v.get_method(node, recvtype, name + "=", self.n_expr isa ASelfExpr)
1951 if wcallsite == null then return
1952 self.write_callsite = wcallsite
1953
1954 var wtype = self.resolve_reassignment(v, readtype, wcallsite.msignature.mparameters.last.mtype)
1955 if wtype == null then return
1956
1957 args = args.to_a # duplicate so raw_arguments keeps only the getter args
1958 args.add(self.n_value)
1959 wcallsite.check_signature(v, node, args)
1960
1961 self.is_typed = true
1962 end
1963 end
1964
1965 redef class ACallReassignExpr
1966 redef fun property_name do return n_qid.n_id.text
1967 redef fun property_node do return n_qid.n_id
1968 redef fun compute_raw_arguments do return n_args.to_a
1969 end
1970
1971 redef class ABraReassignExpr
1972 redef fun property_name do return "[]"
1973 redef fun compute_raw_arguments do return n_args.to_a
1974 end
1975
1976 redef class AInitExpr
1977 redef fun property_name do if n_args.n_exprs.is_empty then return "init" else return "autoinit"
1978 redef fun property_node do return n_kwinit
1979 redef fun compute_raw_arguments do return n_args.to_a
1980 end
1981
1982 redef class AExprs
1983 fun to_a: Array[AExpr] do return self.n_exprs.to_a
1984 end
1985
1986 ###
1987
1988 redef class ASuperExpr
1989 # The method to call if the super is in fact a 'super init call'
1990 # Note: if the super is a normal call-next-method, then this attribute is null
1991 var callsite: nullable CallSite
1992
1993 # The method to call is the super is a standard `call-next-method` super-call
1994 # Note: if the super is a special super-init-call, then this attribute is null
1995 var mpropdef: nullable MMethodDef
1996
1997 redef fun accept_typing(v)
1998 do
1999 var anchor = v.anchor
2000 assert anchor != null
2001 var recvtype = v.get_variable(self, v.selfvariable)
2002 assert recvtype != null
2003 var mproperty = v.mpropdef.mproperty
2004 if not mproperty isa MMethod then
2005 v.error(self, "Error: `super` only usable in a `method`.")
2006 return
2007 end
2008 var superprops = mproperty.lookup_super_definitions(v.mmodule, anchor)
2009 if superprops.length == 0 then
2010 if mproperty.is_init and v.mpropdef.is_intro then
2011 process_superinit(v)
2012 return
2013 end
2014 v.error(self, "Error: no super method to call for `{mproperty}`.")
2015 return
2016 end
2017 # FIXME: covariance of return type in linear extension?
2018 var superprop = superprops.first
2019
2020 var msignature = superprop.msignature.as(not null)
2021 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
2022 var args = self.n_args.to_a
2023 if args.length > 0 then
2024 signaturemap = v.check_signature(self, args, mproperty, msignature)
2025 end
2026 self.mtype = msignature.return_mtype
2027 self.is_typed = true
2028 v.mpropdef.has_supercall = true
2029 mpropdef = v.mpropdef.as(MMethodDef)
2030 end
2031
2032 # The mapping used on the call to associate arguments to parameters.
2033 # If null then no specific association is required.
2034 var signaturemap: nullable SignatureMap
2035
2036 private fun process_superinit(v: TypeVisitor)
2037 do
2038 var anchor = v.anchor
2039 assert anchor != null
2040 var recvtype = v.get_variable(self, v.selfvariable)
2041 assert recvtype != null
2042 var mpropdef = v.mpropdef
2043 assert mpropdef isa MMethodDef
2044 var mproperty = mpropdef.mproperty
2045 var superprop: nullable MMethodDef = null
2046 for msupertype in mpropdef.mclassdef.supertypes do
2047 msupertype = msupertype.anchor_to(v.mmodule, anchor)
2048 var errcount = v.modelbuilder.toolcontext.error_count
2049 var candidate = v.try_get_mproperty_by_name2(self, msupertype, mproperty.name).as(nullable MMethod)
2050 if candidate == null then
2051 if v.modelbuilder.toolcontext.error_count > errcount then return # Forward error
2052 continue # Try next super-class
2053 end
2054 if superprop != null and candidate.is_root_init then
2055 continue
2056 end
2057 if superprop != null and superprop.mproperty != candidate and not superprop.mproperty.is_root_init then
2058 v.error(self, "Error: conflicting super constructor to call for `{mproperty}`: `{candidate.full_name}`, `{superprop.mproperty.full_name}`")
2059 return
2060 end
2061 var candidatedefs = candidate.lookup_definitions(v.mmodule, anchor)
2062 if superprop != null and superprop.mproperty == candidate then
2063 if superprop == candidatedefs.first then continue
2064 candidatedefs.add(superprop)
2065 end
2066 if candidatedefs.length > 1 then
2067 v.error(self, "Error: conflicting property definitions for property `{mproperty}` in `{recvtype}`: {candidatedefs.join(", ")}")
2068 return
2069 end
2070 superprop = candidatedefs.first
2071 end
2072 if superprop == null then
2073 v.error(self, "Error: no super method to call for `{mproperty}`.")
2074 return
2075 end
2076
2077 var msignature = superprop.msignature.as(not null)
2078 msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
2079
2080 var callsite = new CallSite(hot_location, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
2081 self.callsite = callsite
2082
2083 var args = self.n_args.to_a
2084 if args.length > 0 then
2085 callsite.check_signature(v, self, args)
2086 else
2087 # Check there is at least enough parameters
2088 if mpropdef.msignature.arity < msignature.arity then
2089 v.error(self, "Error: not enough implicit arguments to pass. Got `{mpropdef.msignature.arity}`, expected at least `{msignature.arity}`. Signature is `{msignature}`.")
2090 return
2091 end
2092 # Check that each needed parameter is conform
2093 var i = 0
2094 for sp in msignature.mparameters do
2095 var p = mpropdef.msignature.mparameters[i]
2096 if not v.is_subtype(p.mtype, sp.mtype) then
2097 v.error(self, "Type Error: expected argument #{i} of type `{sp.mtype}`, got implicit argument `{p.name}` of type `{p.mtype}`. Signature is {msignature}")
2098 return
2099 end
2100 i += 1
2101 end
2102 end
2103
2104 self.is_typed = true
2105 end
2106 end
2107
2108 ####
2109
2110 redef class ANewExpr
2111 # The constructor invoked by the new.
2112 var callsite: nullable CallSite
2113
2114 # The designated type
2115 var recvtype: nullable MClassType
2116
2117 redef fun accept_typing(v)
2118 do
2119 var recvtype = v.resolve_mtype(self.n_type)
2120 if recvtype == null then return
2121
2122 if not recvtype isa MClassType then
2123 if recvtype isa MNullableType then
2124 v.error(self, "Type Error: cannot instantiate the nullable type `{recvtype}`.")
2125 return
2126 else if recvtype isa MFormalType then
2127 v.error(self, "Type Error: cannot instantiate the formal type `{recvtype}`.")
2128 return
2129 else
2130 v.error(self, "Type Error: cannot instantiate the type `{recvtype}`.")
2131 return
2132 end
2133 end
2134
2135 self.recvtype = recvtype
2136 var kind = recvtype.mclass.kind
2137
2138 var name: String
2139 var nqid = self.n_qid
2140 var node: ANode
2141 if nqid != null then
2142 name = nqid.n_id.text
2143 node = nqid
2144 else
2145 name = "new"
2146 node = self.n_kwnew
2147 end
2148 if name == "intern" then
2149 if kind != concrete_kind then
2150 v.error(self, "Type Error: cannot instantiate {kind} {recvtype}.")
2151 return
2152 end
2153 if n_args.n_exprs.not_empty then
2154 v.error(n_args, "Type Error: the intern constructor expects no arguments.")
2155 return
2156 end
2157 # Our job is done
2158 self.mtype = recvtype
2159 return
2160 end
2161
2162 var callsite = v.get_method(node, recvtype, name, false)
2163 if callsite == null then return
2164
2165 if not callsite.mproperty.is_new then
2166 if kind != concrete_kind then
2167 v.error(self, "Type Error: cannot instantiate {kind} `{recvtype}`.")
2168 return
2169 end
2170 self.mtype = recvtype
2171 else
2172 self.mtype = callsite.msignature.return_mtype
2173 assert self.mtype != null
2174 end
2175
2176 self.callsite = callsite
2177
2178 if not callsite.mproperty.is_init_for(recvtype.mclass) then
2179 v.error(self, "Error: `{name}` is not a constructor.")
2180 return
2181 end
2182
2183 var args = n_args.to_a
2184 callsite.check_signature(v, node, args)
2185 end
2186 end
2187
2188 ####
2189
2190 redef class AAttrFormExpr
2191 # The attribute accessed.
2192 var mproperty: nullable MAttribute
2193
2194 # The static type of the attribute.
2195 var attr_type: nullable MType
2196
2197 # Resolve the attribute accessed.
2198 private fun resolve_property(v: TypeVisitor)
2199 do
2200 var recvtype = v.visit_expr(self.n_expr)
2201 if recvtype == null then return # Skip error
2202 var node = self.n_id
2203 var name = node.text
2204 if recvtype isa MNullType then
2205 v.error(node, "Error: attribute `{name}` access on `null`.")
2206 return
2207 end
2208
2209 var unsafe_type = v.anchor_to(recvtype)
2210 var mproperty = v.try_get_mproperty_by_name2(node, unsafe_type, name)
2211 if mproperty == null then
2212 v.modelbuilder.error(node, "Error: attribute `{name}` does not exist in `{recvtype}`.")
2213 return
2214 end
2215 assert mproperty isa MAttribute
2216 self.mproperty = mproperty
2217
2218 var mpropdefs = mproperty.lookup_definitions(v.mmodule, unsafe_type)
2219 assert mpropdefs.length == 1
2220 var mpropdef = mpropdefs.first
2221 var attr_type = mpropdef.static_mtype
2222 if attr_type == null then return # skip error
2223 attr_type = v.resolve_for(attr_type, recvtype, self.n_expr isa ASelfExpr)
2224 self.attr_type = attr_type
2225 end
2226 end
2227
2228 redef class AAttrExpr
2229 redef fun accept_typing(v)
2230 do
2231 self.resolve_property(v)
2232 self.mtype = self.attr_type
2233 end
2234 end
2235
2236
2237 redef class AAttrAssignExpr
2238 redef fun accept_typing(v)
2239 do
2240 self.resolve_property(v)
2241 var mtype = self.attr_type
2242
2243 v.visit_expr_subtype(self.n_value, mtype)
2244 self.is_typed = mtype != null
2245 end
2246 end
2247
2248 redef class AAttrReassignExpr
2249 redef fun accept_typing(v)
2250 do
2251 self.resolve_property(v)
2252 var mtype = self.attr_type
2253 if mtype == null then return # Skip error
2254
2255 var rettype = self.resolve_reassignment(v, mtype, mtype)
2256
2257 self.is_typed = rettype != null
2258 end
2259 end
2260
2261 redef class AIssetAttrExpr
2262 redef fun accept_typing(v)
2263 do
2264 self.resolve_property(v)
2265 var mtype = self.attr_type
2266 if mtype == null then return # Skip error
2267
2268 var recvtype = self.n_expr.mtype.as(not null)
2269 var bound = v.resolve_for(mtype, recvtype, false)
2270 if bound isa MNullableType then
2271 v.error(n_id, "Type Error: `isset` on a nullable attribute.")
2272 end
2273 self.mtype = v.type_bool(self)
2274 end
2275 end
2276
2277 redef class AVarargExpr
2278 redef fun accept_typing(v)
2279 do
2280 # This kind of pseudo-expression can be only processed trough a signature
2281 # See `check_signature`
2282 # Other cases are a syntax error.
2283 v.error(self, "Syntax Error: unexpected `...`.")
2284 end
2285 end
2286
2287 ###
2288
2289 redef class ADebugTypeExpr
2290 redef fun accept_typing(v)
2291 do
2292 var expr = v.visit_expr(self.n_expr)
2293 if expr == null then return
2294 var unsafe = v.anchor_to(expr)
2295 var ntype = self.n_type
2296 var mtype = v.resolve_mtype(ntype)
2297 if mtype != null and mtype != expr then
2298 var umtype = v.anchor_to(mtype)
2299 v.modelbuilder.warning(self, "debug", "Found type {expr} (-> {unsafe}), expected {mtype} (-> {umtype})")
2300 end
2301 self.is_typed = true
2302 end
2303 end