1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # Intraprocedural resolution of static types and OO-services
18 # By OO-services we mean message sending, attribute access, instantiation, etc.
24 private class TypeVisitor
25 var modelbuilder
: ModelBuilder
26 var nclassdef
: AClassdef
27 var mpropdef
: MPropDef
29 var selfvariable
: Variable = new Variable("self")
31 init(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MPropDef)
33 self.modelbuilder
= modelbuilder
34 self.nclassdef
= nclassdef
35 self.mpropdef
= mpropdef
37 var mclass
= nclassdef
.mclassdef
.mclass
39 var selfvariable
= new Variable("self")
40 self.selfvariable
= selfvariable
41 selfvariable
.declared_type
= mclass
.mclass_type
44 fun mmodule
: MModule do return self.nclassdef
.mclassdef
.mmodule
46 fun anchor
: MClassType do return self.nclassdef
.mclassdef
.bound_mtype
48 fun anchor_to
(mtype
: MType): MType
50 var mmodule
= self.nclassdef
.mclassdef
.mmodule
51 var anchor
= self.nclassdef
.mclassdef
.bound_mtype
52 return mtype
.anchor_to
(mmodule
, anchor
)
55 fun is_subtype
(sub
, sup
: MType): Bool
57 var mmodule
= self.nclassdef
.mclassdef
.mmodule
58 var anchor
= self.nclassdef
.mclassdef
.bound_mtype
59 return sub
.is_subtype
(mmodule
, anchor
, sup
)
62 fun resolve_for
(mtype
, subtype
: MType, for_self
: Bool): MType
64 var mmodule
= self.nclassdef
.mclassdef
.mmodule
65 var anchor
= self.nclassdef
.mclassdef
.bound_mtype
66 #print "resolve_for {mtype} sub={subtype} forself={for_self} mmodule={mmodule} anchor={anchor}"
67 var res
= mtype
.resolve_for
(subtype
, anchor
, mmodule
, not for_self
)
71 # Retrieve the signature of a MMethodDef resolved for a specific call.
72 # This method is an helper to symplify the query on the model.
74 # Note: `for_self` indicates if the reciever is self or not.
75 # If yes, virtual types are not resolved.
76 fun resolve_signature_for
(mmethoddef
: MMethodDef, recv
: MType, for_self
: Bool): MSignature
78 return self.resolve_for
(mmethoddef
.msignature
.as(not null), recv
, for_self
).as(MSignature)
81 # Check that `sub` is a subtype of `sup`.
82 # If `sub` is not a valud suptype, then display an error on `node` an return null.
83 # If `sub` is a safe subtype of `sup` then return `sub`.
84 # If `sun` is an insafe subtype (ie an imlicit cast is required), then return `sup`.
86 # The point of the return type is to determinate the usable type on an expression:
87 # If the suptype is safe, then the return type is the one on the expression typed by `sub`.
88 # Is the subtype is unsafe, then the return type is the one of an implicit cast on `sup`.
89 fun check_subtype
(node
: ANode, sub
, sup
: MType): nullable MType
91 if self.is_subtype
(sub
, sup
) then return sub
92 if self.is_subtype
(sub
, self.anchor_to
(sup
)) then
93 # FIXME workarround to the current unsafe typing policy. To remove once fixed virtual types exists.
94 #node.debug("Unsafe typing: expected {sup}, got {sub}")
97 self.modelbuilder
.error
(node
, "Type error: expected {sup}, got {sub}")
101 # Visit an expression and do not care about the return value
102 fun visit_stmt
(nexpr
: nullable AExpr)
104 if nexpr
== null then return
105 nexpr
.accept_typing
(self)
108 # Visit an expression and expects that it is not a statement
109 # Return the type of the expression
110 # Display an error and return null if:
111 # * the type cannot be determined or
112 # * `nexpr' is a statement
113 fun visit_expr
(nexpr
: AExpr): nullable MType
115 nexpr
.accept_typing
(self)
116 var mtype
= nexpr
.mtype
117 if mtype
!= null then return mtype
118 if not nexpr
.is_typed
then
119 if not self.modelbuilder
.toolcontext
.error_count
> 0 then # check that there is really an error
120 if self.modelbuilder
.toolcontext
.verbose_level
> 1 then
121 nexpr
.debug
("No return type but no error.")
124 return null # forward error
126 self.error
(nexpr
, "Type error: expected expression.")
130 # Visit an expression and expect its static type is a least a `sup'
131 # Return the type of the expression
132 # * the type cannot be determined or
133 # * `nexpr' is a statement
134 # * `nexpt' is not a `sup'
135 fun visit_expr_subtype
(nexpr
: AExpr, sup
: nullable MType): nullable MType
137 var sub
= visit_expr
(nexpr
)
138 if sub
== null then return null # Forward error
140 if sup
== null then return null # Forward error
142 var res
= check_subtype
(nexpr
, sub
, sup
)
144 nexpr
.implicit_cast_to
= res
149 # Visit an expression and expect its static type is a bool
150 # Return the type of the expression
151 # * the type cannot be determined or
152 # * `nexpr' is a statement
153 # * `nexpt' is not a `sup'
154 fun visit_expr_bool
(nexpr
: AExpr): nullable MType
156 return self.visit_expr_subtype
(nexpr
, self.type_bool
(nexpr
))
160 private fun visit_expr_cast
(node
: ANode, nexpr
: AExpr, ntype
: AType): nullable MType
162 var sub
= visit_expr
(nexpr
)
163 if sub
== null then return null # Forward error
165 var sup
= self.resolve_mtype
(ntype
)
166 if sup
== null then return null # Forward error
168 var mmodule
= self.nclassdef
.mclassdef
.mmodule
169 var anchor
= self.nclassdef
.mclassdef
.bound_mtype
171 self.modelbuilder
.warning
(node
, "Warning: Expression is already a {sup}.")
172 else if self.is_subtype
(sub
, sup
) and not sup
.need_anchor
then
173 self.modelbuilder
.warning
(node
, "Warning: Expression is already a {sup} since it is a {sub}.")
178 fun try_get_mproperty_by_name2
(anode
: ANode, mtype
: MType, name
: String): nullable MProperty
180 return self.modelbuilder
.try_get_mproperty_by_name2
(anode
, self.nclassdef
.mclassdef
.mmodule
, mtype
, name
)
183 fun resolve_mtype
(node
: AType): nullable MType
185 return self.modelbuilder
.resolve_mtype
(self.nclassdef
, node
)
188 fun try_get_mclass
(node
: ANode, name
: String): nullable MClass
190 var mmodule
= self.nclassdef
.mclassdef
.mmodule
191 var mclass
= modelbuilder
.try_get_mclass_by_name
(node
, mmodule
, name
)
195 fun get_mclass
(node
: ANode, name
: String): nullable MClass
197 var mmodule
= self.nclassdef
.mclassdef
.mmodule
198 var mclass
= modelbuilder
.try_get_mclass_by_name
(node
, mmodule
, name
)
199 if mclass
== null then
200 self.modelbuilder
.error
(node
, "Type Error: missing primitive class `{name}'.")
205 fun type_bool
(node
: ANode): nullable MType
207 var mclass
= self.get_mclass
(node
, "Bool")
208 if mclass
== null then return null
209 return mclass
.mclass_type
212 fun get_method
(node
: ANode, recvtype
: MType, name
: String, recv_is_self
: Bool): nullable MMethodDef
214 var unsafe_type
= self.anchor_to
(recvtype
)
216 #debug("recv: {recvtype} (aka {unsafe_type})")
218 var mproperty
= self.try_get_mproperty_by_name2
(node
, unsafe_type
, name
)
219 if mproperty
== null then
220 #self.modelbuilder.error(node, "Type error: property {name} not found in {unsafe_type} (ie {recvtype})")
222 self.modelbuilder
.error
(node
, "Error: Method or variable '{name}' unknown in {recvtype}.")
224 self.modelbuilder
.error
(node
, "Error: Method '{name}' doesn't exists in {recvtype}.")
229 if mproperty
.visibility
== protected_visibility
and not recv_is_self
and self.mmodule
.visibility_for
(mproperty
.intro_mclassdef
.mmodule
) < intrude_visibility
then
230 self.modelbuilder
.error
(node
, "Error: Method '{name}' is protected and can only acceded by self. {mproperty.intro_mclassdef.mmodule.visibility_for(self.mmodule)}")
234 var propdefs
= mproperty
.lookup_definitions
(self.mmodule
, unsafe_type
)
235 if propdefs
.length
== 0 then
236 self.modelbuilder
.error
(node
, "Type error: no definition found for property {name} in {unsafe_type}")
238 else if propdefs
.length
> 1 then
239 self.modelbuilder
.error
(node
, "Error: confliting property definitions for property {name} in {unsafe_type}: {propdefs.join(" ")}")
243 var propdef
= propdefs
.first
244 assert propdef
isa MMethodDef
248 # Visit the expressions of args and cheik their conformity with the corresponding typi in signature
249 # The point of this method is to handle varargs correctly
250 # Note: The signature must be correctly adapted
251 fun check_signature
(node
: ANode, args
: Array[AExpr], name
: String, msignature
: MSignature): Bool
253 var vararg_rank
= msignature
.vararg_rank
254 if vararg_rank
>= 0 then
255 if args
.length
< msignature
.arity
then
256 #self.modelbuilder.error(node, "Error: Incorrect number of parameters. Got {args.length}, expected at least {msignature.arity}. Signature is {msignature}")
257 self.modelbuilder
.error
(node
, "Error: arity mismatch; prototype is '{name}{msignature}'")
260 else if args
.length
!= msignature
.arity
then
261 self.modelbuilder
.error
(node
, "Error: Incorrect number of parameters. Got {args.length}, expected {msignature.arity}. Signature is {msignature}")
265 #debug("CALL {unsafe_type}.{msignature}")
267 var vararg_decl
= args
.length
- msignature
.arity
268 for i
in [0..msignature
.arity
[ do
270 if i
== vararg_rank
then continue # skip the vararg
271 if i
> vararg_rank
then
274 var paramtype
= msignature
.mparameters
[i
].mtype
275 self.visit_expr_subtype
(args
[j
], paramtype
)
277 if vararg_rank
>= 0 then
278 var varargs
= new Array[AExpr]
279 var paramtype
= msignature
.mparameters
[vararg_rank
].mtype
280 for j
in [vararg_rank
..vararg_rank
+vararg_decl
] do
282 self.visit_expr_subtype
(args
[j
], paramtype
)
288 fun error
(node
: ANode, message
: String)
290 self.modelbuilder
.toolcontext
.error
(node
.hot_location
, message
)
293 fun get_variable
(node
: AExpr, variable
: Variable): nullable MType
295 var flow
= node
.after_flow_context
297 self.error
(node
, "No context!")
301 if flow
.vars
.has_key
(variable
) then
302 return flow
.vars
[variable
]
304 #node.debug("*** START Collected for {variable}")
305 var mtypes
= flow
.collect_types
(variable
)
306 #node.debug("**** END Collected for {variable}")
307 if mtypes
== null or mtypes
.length
== 0 then
308 return variable
.declared_type
309 else if mtypes
.length
== 1 then
312 var res
= merge_types
(node
,mtypes
)
313 if res
== null then res
= variable
.declared_type
319 fun set_variable
(node
: AExpr, variable
: Variable, mtype
: nullable MType)
321 var flow
= node
.after_flow_context
324 flow
.set_var
(variable
, mtype
)
327 fun merge_types
(node
: ANode, col
: Array[nullable MType]): nullable MType
329 if col
.length
== 1 then return col
.first
330 var res
= new Array[nullable MType]
332 if t1
== null then continue # return null
335 if t2
== null then continue # return null
336 if t2
isa MNullableType or t2
isa MNullType then
339 if not is_subtype
(t2
, t1
) then found
= false
342 #print "merge {col.join(" ")} -> {t1}"
346 #self.modelbuilder.warning(node, "Type Error: {col.length} conflicting types: <{col.join(", ")}>")
352 # The declared type of the variable
353 var declared_type
: nullable MType
356 redef class FlowContext
357 # Store changes of types because of type evolution
358 private var vars
: HashMap[Variable, nullable MType] = new HashMap[Variable, nullable MType]
359 private var cache
: HashMap[Variable, nullable Array[nullable MType]] = new HashMap[Variable, nullable Array[nullable MType]]
361 # Adapt the variable to a static type
362 # Warning1: do not modify vars directly.
363 # Warning2: sub-flow may have cached a unadapted variabial
364 private fun set_var
(variable
: Variable, mtype
: nullable MType)
366 self.vars
[variable
] = mtype
367 self.cache
.keys
.remove
(variable
)
370 private fun collect_types
(variable
: Variable): nullable Array[nullable MType]
372 if cache
.has_key
(variable
) then
373 return cache
[variable
]
375 var res
: nullable Array[nullable MType] = null
376 if vars
.has_key
(variable
) then
377 var mtype
= vars
[variable
]
379 else if self.previous
.is_empty
then
381 res
= [variable
.declared_type
]
383 for flow
in self.previous
do
384 if flow
.is_unreachable
then continue
385 var r2
= flow
.collect_types
(variable
)
386 if r2
== null then continue
391 if not res
.has
(t
) then res
.add
(t
)
396 cache
[variable
] = res
402 # The entry point of the whole typing analysis
403 fun do_typing
(modelbuilder
: ModelBuilder)
407 # The variable associated to the reciever (if any)
408 var selfvariable
: nullable Variable
411 redef class AConcreteMethPropdef
412 redef fun do_typing
(modelbuilder
: ModelBuilder)
414 var nclassdef
= self.parent
.as(AClassdef)
415 var mpropdef
= self.mpropdef
.as(not null)
416 var v
= new TypeVisitor(modelbuilder
, nclassdef
, mpropdef
)
417 self.selfvariable
= v
.selfvariable
419 var nblock
= self.n_block
420 if nblock
== null then return
422 var mmethoddef
= self.mpropdef
.as(not null)
423 for i
in [0..mmethoddef
.msignature
.arity
[ do
424 var mtype
= mmethoddef
.msignature
.mparameters
[i
].mtype
425 if mmethoddef
.msignature
.vararg_rank
== i
then
426 var arrayclass
= v
.get_mclass
(self.n_signature
.n_params
[i
], "Array")
427 if arrayclass
== null then return # Skip error
428 mtype
= arrayclass
.get_mtype
([mtype
])
430 var variable
= self.n_signature
.n_params
[i
].variable
431 assert variable
!= null
432 variable
.declared_type
= mtype
434 for i
in [0..mmethoddef
.msignature
.mclosures
.length
[ do
435 var mclosure
= mmethoddef
.msignature
.mclosures
[i
]
436 var variable
= self.n_signature
.n_closure_decls
[i
].variable
437 assert variable
!= null
438 variable
.declared_type
= mclosure
.mtype
442 if not nblock
.after_flow_context
.is_unreachable
and mmethoddef
.msignature
.return_mtype
!= null then
443 # We reach the end of the function without having a return, it is bad
444 v
.error
(self, "Control error: Reached end of function (a 'return' with a value was expected).")
449 redef class AAttrPropdef
450 redef fun do_typing
(modelbuilder
: ModelBuilder)
452 var nclassdef
= self.parent
.as(AClassdef)
453 var v
= new TypeVisitor(modelbuilder
, nclassdef
, self.mpropdef
.as(not null))
454 self.selfvariable
= v
.selfvariable
456 var nexpr
= self.n_expr
457 if nexpr
!= null then
458 var mtype
= self.mpropdef
.static_mtype
459 v
.visit_expr_subtype
(nexpr
, mtype
)
467 # The static type of the expression.
468 # null if self is a statement of in case of error
469 var mtype
: nullable MType = null
471 # Is the statement correctly typed?
472 # Used to distinguish errors and statements when `mtype' == null
473 var is_typed
: Bool = false
475 # If required, the following implicit cast ".as(XXX)"
476 # Such a cast may by required after evaluating the expression when
477 # a unsafe operation is detected (silently accepted by the Nit language).
478 # The attribute is computed by `check_subtype`
479 var implicit_cast_to
: nullable MType = null
481 # Return the variable read (if any)
482 # Used to perform adaptive typing
483 fun its_variable
: nullable Variable do return null
485 private fun accept_typing
(v
: TypeVisitor)
487 v
.error
(self, "no implemented accept_typing for {self.class_name}")
491 redef class ABlockExpr
492 redef fun accept_typing
(v
)
494 for e
in self.n_expr
do v
.visit_stmt
(e
)
499 redef class AVardeclExpr
500 redef fun accept_typing
(v
)
502 var variable
= self.variable
503 if variable
== null then return # Skip error
505 var ntype
= self.n_type
506 var mtype
: nullable MType
507 if ntype
== null then
510 mtype
= v
.resolve_mtype
(ntype
)
511 if mtype
== null then return # Skip error
514 var nexpr
= self.n_expr
515 if nexpr
!= null then
516 if mtype
!= null then
517 v
.visit_expr_subtype
(nexpr
, mtype
)
519 mtype
= v
.visit_expr
(nexpr
)
520 if mtype
== null then return # Skip error
524 if mtype
== null then
525 mtype
= v
.get_mclass
(self, "Object").mclass_type
.as_nullable
528 variable
.declared_type
= mtype
529 v
.set_variable
(self, variable
, mtype
)
531 #debug("var {variable}: {mtype}")
538 redef fun its_variable
do return self.variable
539 redef fun accept_typing
(v
)
541 var variable
= self.variable
542 if variable
== null then return # Skip error
544 var mtype
= v
.get_variable
(self, variable
)
545 if mtype
!= null then
546 #debug("{variable} is {mtype}")
548 #debug("{variable} is untyped")
555 redef class AVarAssignExpr
556 redef fun accept_typing
(v
)
558 var variable
= self.variable
559 assert variable
!= null
561 var mtype
= v
.visit_expr_subtype
(n_value
, variable
.declared_type
)
563 v
.set_variable
(self, variable
, mtype
)
569 redef class AReassignFormExpr
570 # The method designed by the reassign operator.
571 var reassign_property
: nullable MMethodDef = null
573 var read_type
: nullable MType = null
575 # Determine the `reassign_property'
576 # `readtype' is the type of the reading of the left value.
577 # `writetype' is the type of the writing of the left value.
578 # (Because of ACallReassignExpr, both can be different.
579 # Return the static type of the value to store.
580 private fun resolve_reassignment
(v
: TypeVisitor, readtype
, writetype
: MType): nullable MType
582 var reassign_name
: String
583 if self.n_assign_op
isa APlusAssignOp then
585 else if self.n_assign_op
isa AMinusAssignOp then
591 self.read_type
= readtype
593 if readtype
isa MNullType then
594 v
.error
(self, "Error: Method '{reassign_name}' call on 'null'.")
598 var mpropdef
= v
.get_method
(self, readtype
, reassign_name
, false)
599 if mpropdef
== null then return null # Skip error
601 self.reassign_property
= mpropdef
603 var msignature
= v
.resolve_signature_for
(mpropdef
, readtype
, false)
605 var rettype
= msignature
.return_mtype
606 assert msignature
.arity
== 1 and rettype
!= null
608 var value_type
= v
.visit_expr_subtype
(self.n_value
, msignature
.mparameters
.first
.mtype
)
609 if value_type
== null then return null # Skip error
611 v
.check_subtype
(self, rettype
, writetype
)
616 redef class AVarReassignExpr
617 redef fun accept_typing
(v
)
619 var variable
= self.variable
620 assert variable
!= null
622 var readtype
= v
.get_variable
(self, variable
)
623 if readtype
== null then return
625 var writetype
= variable
.declared_type
626 if writetype
== null then return
628 var rettype
= self.resolve_reassignment
(v
, readtype
, writetype
)
630 v
.set_variable
(self, variable
, rettype
)
637 redef class AContinueExpr
638 redef fun accept_typing
(v
)
640 var nexpr
= self.n_expr
641 if nexpr
!= null then
642 var mtype
= v
.visit_expr
(nexpr
)
648 redef class ABreakExpr
649 redef fun accept_typing
(v
)
651 var nexpr
= self.n_expr
652 if nexpr
!= null then
653 var mtype
= v
.visit_expr
(nexpr
)
659 redef class AReturnExpr
660 redef fun accept_typing
(v
)
662 var nexpr
= self.n_expr
663 var ret_type
= v
.mpropdef
.as(MMethodDef).msignature
.return_mtype
664 if nexpr
!= null then
665 if ret_type
!= null then
666 var mtype
= v
.visit_expr_subtype
(nexpr
, ret_type
)
668 var mtype
= v
.visit_expr
(nexpr
)
669 v
.error
(self, "Error: Return with value in a procedure.")
671 else if ret_type
!= null then
672 v
.error
(self, "Error: Return without value in a function.")
678 redef class AAbortExpr
679 redef fun accept_typing
(v
)
686 redef fun accept_typing
(v
)
688 v
.visit_expr_bool
(n_expr
)
696 redef class AIfexprExpr
697 redef fun accept_typing
(v
)
699 v
.visit_expr_bool
(n_expr
)
701 var t1
= v
.visit_expr
(n_then
)
702 var t2
= v
.visit_expr
(n_else
)
704 if t1
== null or t2
== null then
708 var t
= v
.merge_types
(self, [t1
, t2
])
710 v
.error
(self, "Type Error: ambiguous type {t1} vs {t2}")
717 redef fun accept_typing
(v
)
719 v
.visit_stmt
(n_block
)
724 redef class AWhileExpr
725 redef fun accept_typing
(v
)
727 v
.visit_expr_bool
(n_expr
)
729 v
.visit_stmt
(n_block
)
734 redef class ALoopExpr
735 redef fun accept_typing
(v
)
737 v
.visit_stmt
(n_block
)
743 var coltype
: nullable MClassType
745 var method_iterator
: nullable MMethod
746 var method_is_ok
: nullable MMethod
747 var method_item
: nullable MMethod
748 var method_next
: nullable MMethod
749 var method_key
: nullable MMethod
751 private fun do_type_iterator
(v
: TypeVisitor, mtype
: MType)
753 var objcla
= v
.get_mclass
(self, "Object")
754 if objcla
== null then return
759 var colcla
= v
.try_get_mclass
(self, "Collection")
760 if colcla
!= null and v
.is_subtype
(mtype
, colcla
.get_mtype
([objcla
.mclass_type
.as_nullable
])) then
761 var coltype
= mtype
.supertype_to
(v
.mmodule
, v
.anchor
, colcla
)
762 self.coltype
= coltype
763 var variables
= self.variables
764 if variables
.length
!= 1 then
765 v
.error
(self, "Type Error: Expected one variable")
767 variables
.first
.declared_type
= coltype
.arguments
.first
772 var mapcla
= v
.try_get_mclass
(self, "Map")
773 if mapcla
!= null and v
.is_subtype
(mtype
, mapcla
.get_mtype
([objcla
.mclass_type
.as_nullable
, objcla
.mclass_type
.as_nullable
])) then
774 var coltype
= mtype
.supertype_to
(v
.mmodule
, v
.anchor
, mapcla
)
775 self.coltype
= coltype
776 var variables
= self.variables
777 if variables
.length
!= 2 then
778 v
.error
(self, "Type Error: Expected two variables")
780 variables
[0].declared_type
= coltype
.arguments
[0]
781 variables
[1].declared_type
= coltype
.arguments
[1]
786 if is_col
or is_map
then
787 # get iterator method
788 var coltype
= self.coltype
.as(not null)
789 var itdef
= v
.get_method
(self, coltype
, "iterator", true)
790 if itdef
== null then
791 v
.error
(self, "Type Error: Expected method 'iterator' in type {coltype}")
794 self.method_iterator
= itdef
.mproperty
797 var ittype
= v
.resolve_signature_for
(itdef
, mtype
, false).return_mtype
798 if ittype
== null then
799 v
.error
(self, "Type Error: Expected method 'iterator' to return an Iterator type")
803 # get methods is_ok, next, item
804 var ikdef
= v
.get_method
(self, ittype
, "is_ok", false)
805 if ikdef
== null then
806 v
.error
(self, "Type Error: Expected method 'is_ok' in Iterator type {ittype}")
809 self.method_is_ok
= ikdef
.mproperty
811 var itemdef
= v
.get_method
(self, ittype
, "item", false)
812 if itemdef
== null then
813 v
.error
(self, "Type Error: Expected method 'item' in Iterator type {ittype}")
816 self.method_item
= itemdef
.mproperty
818 var nextdef
= v
.get_method
(self, ittype
, "next", false)
819 if nextdef
== null then
820 v
.error
(self, "Type Error: Expected method 'next' in Iterator type {ittype}")
823 self.method_next
= nextdef
.mproperty
826 var keydef
= v
.get_method
(self, ittype
, "key", false)
827 if keydef
== null then
828 v
.error
(self, "Type Error: Expected method 'key' in Iterator type {ittype}")
831 self.method_key
= keydef
.mproperty
836 v
.modelbuilder
.error
(self, "NOT YET IMPLEMENTED: Do 'for' on {mtype}")
839 redef fun accept_typing
(v
)
841 var mtype
= v
.visit_expr
(n_expr
)
842 if mtype
== null then return
844 self.do_type_iterator
(v
, mtype
)
846 v
.visit_stmt
(n_block
)
851 redef class AAssertExpr
852 redef fun accept_typing
(v
)
854 v
.visit_expr_bool
(n_expr
)
862 redef fun accept_typing
(v
)
864 v
.visit_expr_bool
(n_expr
)
865 v
.visit_expr_bool
(n_expr2
)
866 self.mtype
= v
.type_bool
(self)
871 redef fun accept_typing
(v
)
873 v
.visit_expr_bool
(n_expr
)
874 v
.visit_expr_bool
(n_expr2
)
875 self.mtype
= v
.type_bool
(self)
881 redef fun accept_typing
(v
)
883 v
.visit_expr_bool
(n_expr
)
884 self.mtype
= v
.type_bool
(self)
888 redef class AOrElseExpr
889 redef fun accept_typing
(v
)
891 var t1
= v
.visit_expr
(n_expr
)
892 var t2
= v
.visit_expr
(n_expr2
)
894 if t1
== null or t2
== null then
898 if t1
isa MNullableType then
902 var t
= v
.merge_types
(self, [t1
, t2
])
904 v
.error
(self, "Type Error: ambiguous type {t1} vs {t2}")
911 redef fun accept_typing
(v
)
914 v
.visit_expr
(n_expr2
)
915 self.mtype
= v
.type_bool
(self)
919 redef class ATrueExpr
920 redef fun accept_typing
(v
)
922 self.mtype
= v
.type_bool
(self)
926 redef class AFalseExpr
927 redef fun accept_typing
(v
)
929 self.mtype
= v
.type_bool
(self)
934 redef fun accept_typing
(v
)
936 var mclass
= v
.get_mclass
(self, "Int")
937 if mclass
== null then return # Forward error
938 self.mtype
= mclass
.mclass_type
942 redef class AFloatExpr
943 redef fun accept_typing
(v
)
945 var mclass
= v
.get_mclass
(self, "Float")
946 if mclass
== null then return # Forward error
947 self.mtype
= mclass
.mclass_type
951 redef class ACharExpr
952 redef fun accept_typing
(v
)
954 var mclass
= v
.get_mclass
(self, "Char")
955 if mclass
== null then return # Forward error
956 self.mtype
= mclass
.mclass_type
960 redef class AStringFormExpr
961 redef fun accept_typing
(v
)
963 var mclass
= v
.get_mclass
(self, "String")
964 if mclass
== null then return # Forward error
965 self.mtype
= mclass
.mclass_type
969 redef class ASuperstringExpr
970 redef fun accept_typing
(v
)
972 var mclass
= v
.get_mclass
(self, "String")
973 if mclass
== null then return # Forward error
974 self.mtype
= mclass
.mclass_type
975 for nexpr
in self.n_exprs
do
976 var t
= v
.visit_expr
(nexpr
)
981 redef class AArrayExpr
982 redef fun accept_typing
(v
)
984 var mtypes
= new Array[nullable MType]
985 for e
in self.n_exprs
.n_exprs
do
986 var t
= v
.visit_expr
(e
)
992 var mtype
= v
.merge_types
(self, mtypes
)
993 if mtype
== null then
994 v
.error
(self, "Type Error: ambiguous array type {mtypes.join(" ")}")
997 var mclass
= v
.get_mclass
(self, "Array")
998 if mclass
== null then return # Forward error
999 self.mtype
= mclass
.get_mtype
([mtype
])
1003 redef class ARangeExpr
1004 redef fun accept_typing
(v
)
1006 var discrete_class
= v
.get_mclass
(self, "Discrete")
1007 if discrete_class
== null then return # Forward error
1008 var discrete_type
= discrete_class
.intro
.bound_mtype
1009 var t1
= v
.visit_expr_subtype
(self.n_expr
, discrete_type
)
1010 var t2
= v
.visit_expr_subtype
(self.n_expr2
, discrete_type
)
1011 if t1
== null or t2
== null then return
1012 var mclass
= v
.get_mclass
(self, "Range")
1013 if mclass
== null then return # Forward error
1014 if v
.is_subtype
(t1
, t2
) then
1015 self.mtype
= mclass
.get_mtype
([t2
])
1016 else if v
.is_subtype
(t2
, t1
) then
1017 self.mtype
= mclass
.get_mtype
([t1
])
1019 v
.error
(self, "Type Error: Cannot create range: {t1} vs {t2}")
1024 redef class ANullExpr
1025 redef fun accept_typing
(v
)
1027 self.mtype
= v
.mmodule
.model
.null_type
1031 redef class AIsaExpr
1032 # The static type to cast to.
1033 # (different from the static type of the expression that is Bool).
1034 var cast_type
: nullable MType
1035 redef fun accept_typing
(v
)
1037 var mtype
= v
.visit_expr_cast
(self, self.n_expr
, self.n_type
)
1038 self.cast_type
= mtype
1040 var variable
= self.n_expr
.its_variable
1041 if variable
!= null then
1042 var orig
= self.n_expr
.mtype
1043 var from
= if orig
!= null then orig
.to_s
else "invalid"
1044 var to
= if mtype
!= null then mtype
.to_s
else "invalid"
1045 #debug("adapt {variable}: {from} -> {to}")
1046 self.after_flow_context
.when_true
.set_var
(variable
, mtype
)
1049 self.mtype
= v
.type_bool
(self)
1053 redef class AAsCastExpr
1054 redef fun accept_typing
(v
)
1056 self.mtype
= v
.visit_expr_cast
(self, self.n_expr
, self.n_type
)
1060 redef class AAsNotnullExpr
1061 redef fun accept_typing
(v
)
1063 var mtype
= v
.visit_expr
(self.n_expr
)
1064 if mtype
isa MNullType then
1065 v
.error
(self, "Type error: as(not null) on null")
1068 if mtype
isa MNullableType then
1069 self.mtype
= mtype
.mtype
1072 # TODO: warn on useless as not null
1077 redef class AProxyExpr
1078 redef fun accept_typing
(v
)
1080 self.mtype
= v
.visit_expr
(self.n_expr
)
1084 redef class ASelfExpr
1085 redef var its_variable
: nullable Variable
1086 redef fun accept_typing
(v
)
1088 var variable
= v
.selfvariable
1089 self.its_variable
= variable
1090 self.mtype
= v
.get_variable
(self, variable
)
1094 ## MESSAGE SENDING AND PROPERTY
1096 redef class ASendExpr
1097 # The property invoked by the send.
1098 var mproperty
: nullable MMethod
1100 redef fun accept_typing
(v
)
1102 var recvtype
= v
.visit_expr
(self.n_expr
)
1103 var name
= self.property_name
1105 if recvtype
== null then return # Forward error
1106 if recvtype
isa MNullType then
1107 v
.error
(self, "Error: Method '{name}' call on 'null'.")
1111 var mpropdef
= v
.get_method
(self, recvtype
, name
, self.n_expr
isa ASelfExpr)
1112 if mpropdef
== null then return
1113 var mproperty
= mpropdef
.mproperty
1114 self.mproperty
= mproperty
1115 var msignature
= v
.resolve_signature_for
(mpropdef
, recvtype
, self.n_expr
isa ASelfExpr)
1117 var args
= compute_raw_arguments
1118 self.raw_arguments
= args
1120 v
.check_signature
(self, args
, name
, msignature
)
1122 if mproperty
.is_init
then
1123 var vmpropdef
= v
.mpropdef
1124 if not (vmpropdef
isa MMethodDef and vmpropdef
.mproperty
.is_init
) then
1125 v
.error
(self, "Can call a init only in another init")
1129 var ret
= msignature
.return_mtype
1133 self.is_typed
= true
1136 if self.n_closure_defs
.length
== msignature
.mclosures
.length
then
1137 for i
in [0..self.n_closure_defs
.length
[ do
1138 self.n_closure_defs
[i
].accept_typing
(v
, msignature
.mclosures
[i
])
1141 debug
("closure: got {self.n_closure_defs.length}, want {msignature.mclosures.length}")
1145 # The name of the property
1146 # Each subclass simply provide the correct name.
1147 private fun property_name
: String is abstract
1149 # An array of all arguments (excluding self)
1150 var raw_arguments
: nullable Array[AExpr]
1152 private fun compute_raw_arguments
: Array[AExpr] is abstract
1155 redef class ABinopExpr
1156 redef fun compute_raw_arguments
do return [n_expr2
]
1159 redef fun property_name
do return "=="
1160 redef fun accept_typing
(v
)
1164 var variable
= self.n_expr
.its_variable
1165 if variable
== null then return
1166 var mtype
= self.n_expr2
.mtype
1167 if not mtype
isa MNullType then return
1168 var vartype
= v
.get_variable
(self, variable
)
1169 if not vartype
isa MNullableType then return
1170 self.after_flow_context
.when_true
.set_var
(variable
, mtype
)
1171 self.after_flow_context
.when_false
.set_var
(variable
, vartype
.mtype
)
1172 #debug("adapt {variable}:{vartype} ; true->{mtype} false->{vartype.mtype}")
1176 redef fun property_name
do return "!="
1177 redef fun accept_typing
(v
)
1181 var variable
= self.n_expr
.its_variable
1182 if variable
== null then return
1183 var mtype
= self.n_expr2
.mtype
1184 if not mtype
isa MNullType then return
1185 var vartype
= v
.get_variable
(self, variable
)
1186 if not vartype
isa MNullableType then return
1187 self.after_flow_context
.when_false
.set_var
(variable
, mtype
)
1188 self.after_flow_context
.when_true
.set_var
(variable
, vartype
.mtype
)
1189 #debug("adapt {variable}:{vartype} ; true->{vartype.mtype} false->{mtype}")
1193 redef fun property_name
do return "<"
1196 redef fun property_name
do return "<="
1199 redef fun property_name
do return "<<"
1202 redef fun property_name
do return ">"
1205 redef fun property_name
do return ">="
1208 redef fun property_name
do return ">>"
1210 redef class APlusExpr
1211 redef fun property_name
do return "+"
1213 redef class AMinusExpr
1214 redef fun property_name
do return "-"
1216 redef class AStarshipExpr
1217 redef fun property_name
do return "<=>"
1219 redef class AStarExpr
1220 redef fun property_name
do return "*"
1222 redef class ASlashExpr
1223 redef fun property_name
do return "/"
1225 redef class APercentExpr
1226 redef fun property_name
do return "%"
1229 redef class AUminusExpr
1230 redef fun property_name
do return "unary -"
1231 redef fun compute_raw_arguments
do return new Array[AExpr]
1235 redef class ACallExpr
1236 redef fun property_name
do return n_id
.text
1237 redef fun compute_raw_arguments
do return n_args
.to_a
1240 redef class ACallAssignExpr
1241 redef fun property_name
do return n_id
.text
+ "="
1242 redef fun compute_raw_arguments
1244 var res
= n_args
.to_a
1250 redef class ABraExpr
1251 redef fun property_name
do return "[]"
1252 redef fun compute_raw_arguments
do return n_args
.to_a
1255 redef class ABraAssignExpr
1256 redef fun property_name
do return "[]="
1257 redef fun compute_raw_arguments
1259 var res
= n_args
.to_a
1265 redef class ASendReassignFormExpr
1266 # The property invoked for the writing
1267 var write_mproperty
: nullable MMethod = null
1269 redef fun accept_typing
(v
)
1271 var recvtype
= v
.visit_expr
(self.n_expr
)
1272 var name
= self.property_name
1274 if recvtype
== null then return # Forward error
1275 if recvtype
isa MNullType then
1276 v
.error
(self, "Error: Method '{name}' call on 'null'.")
1280 var for_self
= self.n_expr
isa ASelfExpr
1281 var mpropdef
= v
.get_method
(self, recvtype
, name
, for_self
)
1283 if mpropdef
== null then return
1284 var mproperty
= mpropdef
.mproperty
1285 self.mproperty
= mproperty
1286 var msignature
= v
.resolve_signature_for
(mpropdef
, recvtype
, for_self
)
1288 var args
= compute_raw_arguments
1289 self.raw_arguments
= args
1291 v
.check_signature
(self, args
, name
, msignature
)
1293 var readtype
= msignature
.return_mtype
1294 if readtype
== null then
1295 v
.error
(self, "Error: {name} is not a function")
1299 var wpropdef
= v
.get_method
(self, recvtype
, name
+ "=", self.n_expr
isa ASelfExpr)
1300 if wpropdef
== null then return
1301 var wmproperty
= wpropdef
.mproperty
1302 self.write_mproperty
= wmproperty
1303 var wmsignature
= v
.resolve_signature_for
(wpropdef
, recvtype
, for_self
)
1305 var wtype
= self.resolve_reassignment
(v
, readtype
, wmsignature
.mparameters
.last
.mtype
)
1306 if wtype
== null then return
1308 args
= args
.to_a
# duplicate so raw_arguments keeps only the getter args
1309 args
.add
(self.n_value
)
1310 v
.check_signature
(self, args
, name
+ "=", wmsignature
)
1312 self.is_typed
= true
1316 redef class ACallReassignExpr
1317 redef fun property_name
do return n_id
.text
1318 redef fun compute_raw_arguments
do return n_args
.to_a
1321 redef class ABraReassignExpr
1322 redef fun property_name
do return "[]"
1323 redef fun compute_raw_arguments
do return n_args
.to_a
1326 redef class AInitExpr
1327 redef fun property_name
do return "init"
1328 redef fun compute_raw_arguments
do return n_args
.to_a
1332 fun to_a
: Array[AExpr] do return self.n_exprs
.to_a
1337 redef class ASuperExpr
1338 # The method to call if the super is in fact a 'super init call'
1339 # Note: if the super is a normal call-next-method, then this attribute is null
1340 var mproperty
: nullable MMethod
1342 redef fun accept_typing
(v
)
1344 var recvtype
= v
.nclassdef
.mclassdef
.bound_mtype
1345 var mproperty
= v
.mpropdef
.mproperty
1346 if not mproperty
isa MMethod then
1347 v
.error
(self, "Error: super only usable in a method")
1350 var superprops
= mproperty
.lookup_super_definitions
(v
.mmodule
, recvtype
)
1351 if superprops
.length
== 0 then
1352 if mproperty
.is_init
and v
.mpropdef
.is_intro
then
1353 process_superinit
(v
)
1356 v
.error
(self, "Error: No super method to call for {mproperty}.")
1358 else if superprops
.length
> 1 then
1359 v
.modelbuilder
.warning
(self, "Warning: NOT YET IMPLEMENTED: Conflicting super method to call for {mproperty}: {superprops.join(", ")}.")
1362 var superprop
= superprops
.first
1363 assert superprop
isa MMethodDef
1365 var msignature
= v
.resolve_signature_for
(superprop
, recvtype
, true)
1366 var args
= self.n_args
.to_a
1367 if args
.length
> 0 then
1368 v
.check_signature
(self, args
, mproperty
.name
, msignature
)
1370 self.mtype
= msignature
.return_mtype
1373 private fun process_superinit
(v
: TypeVisitor)
1375 var recvtype
= v
.nclassdef
.mclassdef
.bound_mtype
1376 var mproperty
= v
.mpropdef
.mproperty
1377 var superprop
: nullable MMethodDef = null
1378 for msupertype
in v
.nclassdef
.mclassdef
.supertypes
do
1379 msupertype
= msupertype
.anchor_to
(v
.mmodule
, recvtype
)
1380 var errcount
= v
.modelbuilder
.toolcontext
.error_count
1381 var candidate
= v
.try_get_mproperty_by_name2
(self, msupertype
, mproperty
.name
).as(nullable MMethod)
1382 if candidate
== null then
1383 if v
.modelbuilder
.toolcontext
.error_count
> errcount
then return # Forard error
1384 continue # Try next super-class
1386 if superprop
!= null and superprop
.mproperty
!= candidate
then
1387 v
.error
(self, "Error: conflicting super constructor to call for {mproperty}: {candidate.full_name}, {superprop.mproperty.full_name}")
1390 var candidatedefs
= candidate
.lookup_definitions
(v
.mmodule
, recvtype
)
1391 if superprop
!= null then
1392 if superprop
== candidatedefs
.first
then continue
1393 candidatedefs
.add
(superprop
)
1395 if candidatedefs
.length
> 1 then
1396 v
.error
(self, "Error: confliting property definitions for property {mproperty} in {recvtype}: {candidatedefs.join(", ")}")
1399 superprop
= candidatedefs
.first
1401 if superprop
== null then
1402 v
.error
(self, "Error: No super method to call for {mproperty}.")
1405 self.mproperty
= superprop
.mproperty
1407 var args
= self.n_args
.to_a
1408 var msignature
= v
.resolve_signature_for
(superprop
, recvtype
, true)
1409 if args
.length
> 0 then
1410 v
.check_signature
(self, args
, mproperty
.name
, msignature
)
1412 # TODO: Check signature
1415 self.is_typed
= true
1421 redef class ANewExpr
1422 # The constructor invoked by the new.
1423 var mproperty
: nullable MMethod
1425 redef fun accept_typing
(v
)
1427 var recvtype
= v
.resolve_mtype
(self.n_type
)
1428 if recvtype
== null then return
1429 self.mtype
= recvtype
1431 if not recvtype
isa MClassType then
1432 if recvtype
isa MNullableType then
1433 v
.error
(self, "Type error: cannot instantiate the nullable type {recvtype}.")
1436 v
.error
(self, "Type error: cannot instantiate the formal type {recvtype}.")
1448 var propdef
= v
.get_method
(self, recvtype
, name
, false)
1449 if propdef
== null then return
1451 self.mproperty
= propdef
.mproperty
1453 if not propdef
.mproperty
.is_init_for
(recvtype
.mclass
) then
1454 v
.error
(self, "Error: {name} is not a constructor.")
1458 var msignature
= v
.resolve_signature_for
(propdef
, recvtype
, false)
1460 var args
= n_args
.to_a
1461 v
.check_signature
(self, args
, name
, msignature
)
1467 redef class AAttrFormExpr
1468 # The attribute acceded.
1469 var mproperty
: nullable MAttribute
1471 # The static type of the attribute.
1472 var attr_type
: nullable MType
1474 # Resolve the attribute acceded.
1475 private fun resolve_property
(v
: TypeVisitor)
1477 var recvtype
= v
.visit_expr
(self.n_expr
)
1478 if recvtype
== null then return # Skip error
1479 var name
= self.n_id
.text
1480 if recvtype
isa MNullType then
1481 v
.error
(self, "Error: Attribute '{name}' access on 'null'.")
1485 var unsafe_type
= v
.anchor_to
(recvtype
)
1486 var mproperty
= v
.try_get_mproperty_by_name2
(self, unsafe_type
, name
)
1487 if mproperty
== null then
1488 v
.modelbuilder
.error
(self, "Error: Attribute {name} doesn't exists in {recvtype}.")
1491 assert mproperty
isa MAttribute
1492 self.mproperty
= mproperty
1494 var mpropdefs
= mproperty
.lookup_definitions
(v
.mmodule
, unsafe_type
)
1495 assert mpropdefs
.length
== 1
1496 var mpropdef
= mpropdefs
.first
1497 var attr_type
= mpropdef
.static_mtype
.as(not null)
1498 attr_type
= v
.resolve_for
(attr_type
, recvtype
, self.n_expr
isa ASelfExpr)
1499 self.attr_type
= attr_type
1503 redef class AAttrExpr
1504 redef fun accept_typing
(v
)
1506 self.resolve_property
(v
)
1507 self.mtype
= self.attr_type
1512 redef class AAttrAssignExpr
1513 redef fun accept_typing
(v
)
1515 self.resolve_property
(v
)
1516 var mtype
= self.attr_type
1518 v
.visit_expr_subtype
(self.n_value
, mtype
)
1519 self.is_typed
= true
1523 redef class AAttrReassignExpr
1524 redef fun accept_typing
(v
)
1526 self.resolve_property
(v
)
1527 var mtype
= self.attr_type
1528 if mtype
== null then return # Skip error
1530 self.resolve_reassignment
(v
, mtype
, mtype
)
1532 self.is_typed
= true
1536 redef class AIssetAttrExpr
1537 redef fun accept_typing
(v
)
1539 self.resolve_property
(v
)
1540 var mtype
= self.attr_type
1541 if mtype
== null then return # Skip error
1543 var recvtype
= self.n_expr
.mtype
.as(not null)
1544 var bound
= v
.resolve_for
(mtype
, recvtype
, false)
1545 if bound
isa MNullableType then
1546 v
.error
(self, "Error: isset on a nullable attribute.")
1548 self.mtype
= v
.type_bool
(self)
1554 redef class AClosureCallExpr
1555 redef fun accept_typing
(v
)
1557 var variable
= self.variable
1558 if variable
== null then return # Skip error
1560 var recvtype
= v
.nclassdef
.mclassdef
.bound_mtype
1561 var msignature
= variable
.declared_type
.as(not null)
1562 msignature
= v
.resolve_for
(msignature
, recvtype
, false).as(MSignature)
1564 var args
= n_args
.to_a
1565 v
.check_signature
(self, args
, variable
.name
, msignature
)
1567 self.is_typed
= true
1568 self.mtype
= msignature
.return_mtype
1572 redef class AClosureDef
1573 var mclosure
: nullable MParameter
1575 private fun accept_typing
(v
: TypeVisitor, mparameter
: MParameter)
1577 var variables
= self.variables
1578 if variables
== null then return
1580 self.mclosure
= mparameter
1581 var msignature
= mparameter
.mtype
.as(MSignature)
1583 if msignature
.arity
!= variables
.length
then
1584 v
.error
(self, "Type error: closure {mparameter.name} expects {msignature.arity} parameters, {variables.length} given")
1588 for i
in [0..variables
.length
[ do
1589 variables
[i
].declared_type
= msignature
.mparameters
[i
].mtype
1592 v
.visit_stmt
(self.n_expr
)
1598 redef class ADebugTypeExpr
1599 redef fun accept_typing
(v
)
1601 var expr
= v
.visit_expr
(self.n_expr
)
1602 if expr
== null then return
1603 var unsafe
= v
.anchor_to
(expr
)
1604 var ntype
= self.n_type
1605 var mtype
= v
.resolve_mtype
(ntype
)
1606 if mtype
!= null and mtype
!= expr
then
1607 var umtype
= v
.anchor_to
(mtype
)
1608 v
.modelbuilder
.warning
(self, "Found type {expr} (-> {unsafe}), expected {mtype} (-> {umtype})")