module typing
import flow
-import modelbuilder
+import modelize_property
+import phase
+import local_var_init
+
+redef class ToolContext
+ var typing_phase: Phase = new TypingPhase(self, [flow_phase, modelize_property_phase, local_var_init_phase])
+end
+
+private class TypingPhase
+ super Phase
+ redef fun process_npropdef(npropdef) do npropdef.do_typing(toolcontext.modelbuilder)
+end
private class TypeVisitor
var modelbuilder: ModelBuilder
- var nclassdef: AClassdef
- var mpropdef: MPropDef
+
+ # The module of the analysis
+ # Used to correctly query the model
+ var mmodule: MModule
+
+ # The static type of the receiver
+ # Mainly used for type tests and type resolutions
+ var anchor: nullable MClassType
+
+ # The analyzed mclassdef
+ var mclassdef: nullable MClassDef
+
+ # The analyzed property
+ var mpropdef: nullable MPropDef
var selfvariable: Variable = new Variable("self")
- init(modelbuilder: ModelBuilder, nclassdef: AClassdef, mpropdef: MPropDef)
+ init(modelbuilder: ModelBuilder, mmodule: MModule, mpropdef: nullable MPropDef)
do
self.modelbuilder = modelbuilder
- self.nclassdef = nclassdef
- self.mpropdef = mpropdef
+ self.mmodule = mmodule
- var mclass = nclassdef.mclassdef.mclass
+ if mpropdef != null then
+ self.mpropdef = mpropdef
+ var mclassdef = mpropdef.mclassdef
+ self.mclassdef = mclassdef
+ self.anchor = mclassdef.bound_mtype
- var selfvariable = new Variable("self")
- self.selfvariable = selfvariable
- selfvariable.declared_type = mclass.mclass_type
- end
+ var mclass = mclassdef.mclass
- fun mmodule: MModule do return self.nclassdef.mclassdef.mmodule
-
- fun anchor: MClassType do return self.nclassdef.mclassdef.bound_mtype
+ var selfvariable = new Variable("self")
+ self.selfvariable = selfvariable
+ selfvariable.declared_type = mclass.mclass_type
+ end
+ end
fun anchor_to(mtype: MType): MType
do
- var mmodule = self.nclassdef.mclassdef.mmodule
- var anchor = self.nclassdef.mclassdef.bound_mtype
+ var anchor = anchor
+ if anchor == null then
+ assert not mtype.need_anchor
+ return mtype
+ end
return mtype.anchor_to(mmodule, anchor)
end
fun is_subtype(sub, sup: MType): Bool
do
- var mmodule = self.nclassdef.mclassdef.mmodule
- var anchor = self.nclassdef.mclassdef.bound_mtype
return sub.is_subtype(mmodule, anchor, sup)
end
fun resolve_for(mtype, subtype: MType, for_self: Bool): MType
do
- var mmodule = self.nclassdef.mclassdef.mmodule
- var anchor = self.nclassdef.mclassdef.bound_mtype
#print "resolve_for {mtype} sub={subtype} forself={for_self} mmodule={mmodule} anchor={anchor}"
var res = mtype.resolve_for(subtype, anchor, mmodule, not for_self)
return res
end
- # Retrieve the signature of a MMethodDef resolved for a specific call.
- # This method is an helper to symplify the query on the model.
- #
- # Note: `for_self` indicates if the reciever is self or not.
- # If yes, virtual types are not resolved.
- fun resolve_signature_for(mmethoddef: MMethodDef, recv: MType, for_self: Bool): MSignature
- do
- return self.resolve_for(mmethoddef.msignature.as(not null), recv, for_self).as(MSignature)
- end
-
# Check that `sub` is a subtype of `sup`.
# If `sub` is not a valud suptype, then display an error on `node` an return null.
# If `sub` is a safe subtype of `sup` then return `sub`.
- # If `sun` is an insafe subtype (ie an imlicit cast is required), then return `sup`.
+ # If `sub` is an insafe subtype (ie an imlicit cast is required), then return `sup`.
#
# The point of the return type is to determinate the usable type on an expression:
# If the suptype is safe, then the return type is the one on the expression typed by `sub`.
# Return the type of the expression
# Display an error and return null if:
# * the type cannot be determined or
- # * `nexpr' is a statement
+ # * `nexpr` is a statement
fun visit_expr(nexpr: AExpr): nullable MType
do
nexpr.accept_typing(self)
return null
end
- # Visit an expression and expect its static type is a least a `sup'
- # Return the type of the expression
+ # Visit an expression and expect its static type is a least a `sup`
+ # Return the type of the expression or null if
# * the type cannot be determined or
- # * `nexpr' is a statement
- # * `nexpt' is not a `sup'
+ # * `nexpr` is a statement or
+ # * `nexpr` is not a `sup`
fun visit_expr_subtype(nexpr: AExpr, sup: nullable MType): nullable MType
do
var sub = visit_expr(nexpr)
if sup == null then return null # Forward error
var res = check_subtype(nexpr, sub, sup)
+ if res != sub then
+ nexpr.implicit_cast_to = res
+ end
return res
end
- # Visit an expression and expect its static type is a bool
- # Return the type of the expression
+ # Visit an expression and expect its static type is a `Bool`
+ # Return the type of the expression or null if
# * the type cannot be determined or
- # * `nexpr' is a statement
- # * `nexpt' is not a `sup'
+ # * `nexpr` is a statement or
+ # * `nexpr` is not a `Bool`
fun visit_expr_bool(nexpr: AExpr): nullable MType
do
return self.visit_expr_subtype(nexpr, self.type_bool(nexpr))
var sup = self.resolve_mtype(ntype)
if sup == null then return null # Forward error
- var mmodule = self.nclassdef.mclassdef.mmodule
- var anchor = self.nclassdef.mclassdef.bound_mtype
if sup == sub then
self.modelbuilder.warning(node, "Warning: Expression is already a {sup}.")
else if self.is_subtype(sub, sup) and not sup.need_anchor then
fun try_get_mproperty_by_name2(anode: ANode, mtype: MType, name: String): nullable MProperty
do
- return self.modelbuilder.try_get_mproperty_by_name2(anode, self.nclassdef.mclassdef.mmodule, mtype, name)
+ return self.modelbuilder.try_get_mproperty_by_name2(anode, mmodule, mtype, name)
end
fun resolve_mtype(node: AType): nullable MType
do
- return self.modelbuilder.resolve_mtype(self.nclassdef, node)
+ return self.modelbuilder.resolve_mtype(mmodule, mclassdef, node)
end
fun try_get_mclass(node: ANode, name: String): nullable MClass
do
- var mmodule = self.nclassdef.mclassdef.mmodule
var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
return mclass
end
fun get_mclass(node: ANode, name: String): nullable MClass
do
- var mmodule = self.nclassdef.mclassdef.mmodule
var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
if mclass == null then
self.modelbuilder.error(node, "Type Error: missing primitive class `{name}'.")
return mclass.mclass_type
end
- fun get_method(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable MMethodDef
+ fun get_method(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable CallSite
do
var unsafe_type = self.anchor_to(recvtype)
#debug("recv: {recvtype} (aka {unsafe_type})")
+ if recvtype isa MNullType then
+ self.error(node, "Error: Method '{name}' call on 'null'.")
+ return null
+ end
var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
if mproperty == null then
return null
end
- if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility then
- self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self. {mproperty.intro_mclassdef.mmodule.visibility_for(self.mmodule)}")
+ assert mproperty isa MMethod
+ 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
+ self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self.")
return null
end
var propdefs = mproperty.lookup_definitions(self.mmodule, unsafe_type)
+ var mpropdef
if propdefs.length == 0 then
self.modelbuilder.error(node, "Type error: no definition found for property {name} in {unsafe_type}")
return null
- else if propdefs.length > 1 then
- self.modelbuilder.error(node, "Error: confliting property definitions for property {name} in {unsafe_type}: {propdefs.join(" ")}")
- return null
+ else if propdefs.length == 1 then
+ mpropdef = propdefs.first
+ else
+ self.modelbuilder.warning(node, "Warning: confliting property definitions for property {name} in {unsafe_type}: {propdefs.join(" ")}")
+ mpropdef = mproperty.intro
end
- var propdef = propdefs.first
- assert propdef isa MMethodDef
- return propdef
+
+ var msignature = mpropdef.msignature.as(not null)
+ msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
+
+ var erasure_cast = false
+ var rettype = mpropdef.msignature.return_mtype
+ if not recv_is_self and rettype != null then
+ if rettype isa MNullableType then rettype = rettype.mtype
+ if rettype isa MParameterType then
+ var erased_rettype = msignature.return_mtype
+ assert erased_rettype != null
+ #node.debug("Erasure cast: Really a {rettype} but unsafely a {erased_rettype}")
+ erasure_cast = true
+ end
+ end
+
+ var callsite = new CallSite(node, recvtype, mmodule, anchor, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
+ return callsite
end
# Visit the expressions of args and cheik their conformity with the corresponding typi in signature
end
end
+# A specific method call site with its associated informations.
+class CallSite
+ # The assiciated node for location
+ var node: ANode
+
+ # The static type of the receiver (possibly unresolved)
+ var recv: MType
+
+ # The module where the callsite is present
+ var mmodule: MModule
+
+ # The anchor to use with `recv` or `msignature`
+ var anchor: nullable MClassType
+
+ # Is the receiver self?
+ # If "for_self", virtual types of the signature are keeped
+ # If "not_for_self", virtual type are erased
+ var recv_is_self: Bool
+
+ # The designated method
+ var mproperty: MMethod
+
+ # The statically designated method definition
+ # The most specif one, it is.
+ var mpropdef: MMethodDef
+
+ # The resolved signature for the receiver
+ var msignature: MSignature
+
+ # Is a implicit cast required on erasure typing policy?
+ var erasure_cast: Bool
+
+ private fun check_signature(v: TypeVisitor, args: Array[AExpr]): Bool
+ do
+ return v.check_signature(self.node, args, self.mproperty.name, self.msignature)
+ end
+end
+
redef class Variable
# The declared type of the variable
var declared_type: nullable MType
var selfvariable: nullable Variable
end
-redef class AConcreteMethPropdef
+redef class AMethPropdef
redef fun do_typing(modelbuilder: ModelBuilder)
do
- var nclassdef = self.parent.as(AClassdef)
- var mpropdef = self.mpropdef.as(not null)
- var v = new TypeVisitor(modelbuilder, nclassdef, mpropdef)
- self.selfvariable = v.selfvariable
-
var nblock = self.n_block
if nblock == null then return
+ var mpropdef = self.mpropdef.as(not null)
+ var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
+ self.selfvariable = v.selfvariable
+
var mmethoddef = self.mpropdef.as(not null)
for i in [0..mmethoddef.msignature.arity[ do
var mtype = mmethoddef.msignature.mparameters[i].mtype
assert variable != null
variable.declared_type = mtype
end
- for i in [0..mmethoddef.msignature.mclosures.length[ do
- var mclosure = mmethoddef.msignature.mclosures[i]
- var variable = self.n_signature.n_closure_decls[i].variable
- assert variable != null
- variable.declared_type = mclosure.mtype
- end
v.visit_stmt(nblock)
if not nblock.after_flow_context.is_unreachable and mmethoddef.msignature.return_mtype != null then
redef class AAttrPropdef
redef fun do_typing(modelbuilder: ModelBuilder)
do
- var nclassdef = self.parent.as(AClassdef)
- var v = new TypeVisitor(modelbuilder, nclassdef, self.mpropdef.as(not null))
+ var mpropdef = self.mpropdef.as(not null)
+ var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
self.selfvariable = v.selfvariable
var nexpr = self.n_expr
redef class AExpr
# The static type of the expression.
- # null if self is a statement of in case of error
+ # null if self is a statement or in case of error
var mtype: nullable MType = null
# Is the statement correctly typed?
- # Used to distinguish errors and statements when `mtype' == null
+ # Used to distinguish errors and statements when `mtype == null`
var is_typed: Bool = false
+ # If required, the following implicit cast `.as(XXX)`
+ # Such a cast may by required after evaluating the expression when
+ # a unsafe operation is detected (silently accepted by the Nit language).
+ # The attribute is computed by `check_subtype`
+ var implicit_cast_to: nullable MType = null
+
# Return the variable read (if any)
# Used to perform adaptive typing
fun its_variable: nullable Variable do return null
for e in self.n_expr do v.visit_stmt(e)
self.is_typed = true
end
+
+ # The type of a blockexpr is the one of the last expression (or null if empty)
+ redef fun mtype
+ do
+ if self.n_expr.is_empty then return null
+ return self.n_expr.last.mtype
+ end
end
redef class AVardeclExpr
end
end
- if mtype == null then
- mtype = v.get_mclass(self, "Object").mclass_type.as_nullable
+ var decltype = mtype
+ if mtype == null or mtype isa MNullType then
+ decltype = v.get_mclass(self, "Object").mclass_type.as_nullable
+ if mtype == null then mtype = decltype
end
- variable.declared_type = mtype
+ variable.declared_type = decltype
v.set_variable(self, variable, mtype)
#debug("var {variable}: {mtype}")
redef class AReassignFormExpr
# The method designed by the reassign operator.
- var reassign_property: nullable MMethodDef = null
+ var reassign_callsite: nullable CallSite
var read_type: nullable MType = null
- # Determine the `reassign_property'
- # `readtype' is the type of the reading of the left value.
- # `writetype' is the type of the writing of the left value.
- # (Because of ACallReassignExpr, both can be different.
+ # Determine the `reassign_property`
+ # `readtype` is the type of the reading of the left value.
+ # `writetype` is the type of the writing of the left value.
+ # (Because of `ACallReassignExpr`, both can be different.
# Return the static type of the value to store.
private fun resolve_reassignment(v: TypeVisitor, readtype, writetype: MType): nullable MType
do
return null
end
- var mpropdef = v.get_method(self, readtype, reassign_name, false)
- if mpropdef == null then return null # Skip error
-
- self.reassign_property = mpropdef
-
- var msignature = v.resolve_signature_for(mpropdef, readtype, false)
+ var callsite = v.get_method(self, readtype, reassign_name, false)
+ if callsite == null then return null # Skip error
+ self.reassign_callsite = callsite
+ var msignature = callsite.msignature
var rettype = msignature.return_mtype
assert msignature.arity == 1 and rettype != null
var readtype = v.get_variable(self, variable)
if readtype == null then return
+ read_type = readtype
+
var writetype = variable.declared_type
if writetype == null then return
redef class AForExpr
var coltype: nullable MClassType
- var method_iterator: nullable MMethod
- var method_is_ok: nullable MMethod
- var method_item: nullable MMethod
- var method_next: nullable MMethod
- var method_key: nullable MMethod
+ var method_iterator: nullable CallSite
+ var method_is_ok: nullable CallSite
+ var method_item: nullable CallSite
+ var method_next: nullable CallSite
+ var method_key: nullable CallSite
private fun do_type_iterator(v: TypeVisitor, mtype: MType)
do
+ if mtype isa MNullType then
+ v.error(self, "Type error: 'for' cannot iterate over 'null'")
+ return
+ end
+
+ # get obj class
var objcla = v.get_mclass(self, "Object")
if objcla == null then return
+ # check iterator method
+ var itdef = v.get_method(self, mtype, "iterator", true)
+ if itdef == null then
+ v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
+ return
+ end
+ self.method_iterator = itdef
+
+ # check that iterator return something
+ var ittype = itdef.msignature.return_mtype
+ if ittype == null then
+ v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
+ return
+ end
+
+ # get iterator type
+ var colit_cla = v.try_get_mclass(self, "Iterator")
+ var mapit_cla = v.try_get_mclass(self, "MapIterator")
var is_col = false
var is_map = false
- var colcla = v.try_get_mclass(self, "Collection")
- if colcla != null and v.is_subtype(mtype, colcla.get_mtype([objcla.mclass_type.as_nullable])) then
- var coltype = mtype.supertype_to(v.mmodule, v.anchor, colcla)
- self.coltype = coltype
+ if colit_cla != null and v.is_subtype(ittype, colit_cla.get_mtype([objcla.mclass_type.as_nullable])) then
+ # Iterator
+ var coltype = ittype.supertype_to(v.mmodule, v.anchor, colit_cla)
var variables = self.variables
if variables.length != 1 then
- v.error(self, "Type Error: Expected one variable")
+ v.error(self, "Type Error: 'for' expects only one variable when using 'Iterator'.")
else
variables.first.declared_type = coltype.arguments.first
end
is_col = true
end
- var mapcla = v.try_get_mclass(self, "Map")
- if mapcla != null and v.is_subtype(mtype, mapcla.get_mtype([objcla.mclass_type.as_nullable, objcla.mclass_type.as_nullable])) then
- var coltype = mtype.supertype_to(v.mmodule, v.anchor, mapcla)
- self.coltype = coltype
+ if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type, objcla.mclass_type.as_nullable])) then
+ # Map Iterator
+ var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
var variables = self.variables
if variables.length != 2 then
- v.error(self, "Type Error: Expected two variables")
+ v.error(self, "Type Error: 'for' expects two variables when using 'MapIterator'.")
else
variables[0].declared_type = coltype.arguments[0]
variables[1].declared_type = coltype.arguments[1]
is_map = true
end
- if is_col or is_map then
- # get iterator method
- var coltype = self.coltype.as(not null)
- var itdef = v.get_method(self, coltype, "iterator", true)
- if itdef == null then
- v.error(self, "Type Error: Expected method 'iterator' in type {coltype}")
- return
- end
- self.method_iterator = itdef.mproperty
+ if not is_col and not is_map then
+ v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
+ return
+ end
- # get iterator type
- var ittype = v.resolve_signature_for(itdef, mtype, false).return_mtype
- if ittype == null then
- v.error(self, "Type Error: Expected method 'iterator' to return an Iterator type")
- return
- end
+ # anchor formal and virtual types
+ if mtype.need_anchor then mtype = v.anchor_to(mtype)
- # get methods is_ok, next, item
- var ikdef = v.get_method(self, ittype, "is_ok", false)
- if ikdef == null then
- v.error(self, "Type Error: Expected method 'is_ok' in Iterator type {ittype}")
- return
- end
- self.method_is_ok = ikdef.mproperty
+ if mtype isa MNullableType then mtype = mtype.mtype
+ self.coltype = mtype.as(MClassType)
- var itemdef = v.get_method(self, ittype, "item", false)
- if itemdef == null then
- v.error(self, "Type Error: Expected method 'item' in Iterator type {ittype}")
- return
- end
- self.method_item = itemdef.mproperty
+ # get methods is_ok, next, item
+ var ikdef = v.get_method(self, ittype, "is_ok", false)
+ if ikdef == null then
+ v.error(self, "Type Error: 'for' expects a method 'is_ok' in 'Iterator' type {ittype}.")
+ return
+ end
+ self.method_is_ok = ikdef
- var nextdef = v.get_method(self, ittype, "next", false)
- if nextdef == null then
- v.error(self, "Type Error: Expected method 'next' in Iterator type {ittype}")
- return
- end
- self.method_next = nextdef.mproperty
+ var itemdef = v.get_method(self, ittype, "item", false)
+ if itemdef == null then
+ v.error(self, "Type Error: 'for' expects a method 'item' in 'Iterator' type {ittype}.")
+ return
+ end
+ self.method_item = itemdef
- if is_map then
- var keydef = v.get_method(self, ittype, "key", false)
- if keydef == null then
- v.error(self, "Type Error: Expected method 'key' in Iterator type {ittype}")
- return
- end
- self.method_key = keydef.mproperty
- end
+ var nextdef = v.get_method(self, ittype, "next", false)
+ if nextdef == null then
+ v.error(self, "Type Error: 'for' expects a method 'next' in 'Iterator' type {ittype}.")
return
end
+ self.method_next = nextdef
- v.modelbuilder.error(self, "NOT YET IMPLEMENTED: Do 'for' on {mtype}")
+ if is_map then
+ var keydef = v.get_method(self, ittype, "key", false)
+ if keydef == null then
+ v.error(self, "Type Error: 'for' expects a method 'key' in 'Iterator' type {ittype}.")
+ return
+ end
+ self.method_key = keydef
+ end
end
redef fun accept_typing(v)
end
end
+redef class AImpliesExpr
+ redef fun accept_typing(v)
+ do
+ v.visit_expr_bool(n_expr)
+ v.visit_expr_bool(n_expr2)
+ self.mtype = v.type_bool(self)
+ end
+end
+
redef class AAndExpr
redef fun accept_typing(v)
do
var t = v.merge_types(self, [t1, t2])
if t == null then
- v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
+ t = v.mmodule.object_type
+ if t2 isa MNullableType then
+ t = t.as_nullable
+ end
+ #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
end
self.mtype = t
end
end
-redef class AEeExpr
- redef fun accept_typing(v)
- do
- v.visit_expr(n_expr)
- v.visit_expr(n_expr2)
- self.mtype = v.type_bool(self)
- end
-end
-
redef class ATrueExpr
redef fun accept_typing(v)
do
end
redef class AArrayExpr
+ var with_capacity_callsite: nullable CallSite
+ var push_callsite: nullable CallSite
+
redef fun accept_typing(v)
do
var mtypes = new Array[nullable MType]
end
var mclass = v.get_mclass(self, "Array")
if mclass == null then return # Forward error
- self.mtype = mclass.get_mtype([mtype])
+ var array_mtype = mclass.get_mtype([mtype])
+
+ with_capacity_callsite = v.get_method(self, array_mtype, "with_capacity", false)
+ push_callsite = v.get_method(self, array_mtype, "push", false)
+
+ self.mtype = array_mtype
end
end
redef class ARangeExpr
+ var init_callsite: nullable CallSite
+
redef fun accept_typing(v)
do
var discrete_class = v.get_mclass(self, "Discrete")
if t1 == null or t2 == null then return
var mclass = v.get_mclass(self, "Range")
if mclass == null then return # Forward error
+ var mtype
if v.is_subtype(t1, t2) then
- self.mtype = mclass.get_mtype([t2])
+ mtype = mclass.get_mtype([t2])
else if v.is_subtype(t2, t1) then
- self.mtype = mclass.get_mtype([t1])
+ mtype = mclass.get_mtype([t1])
else
v.error(self, "Type Error: Cannot create range: {t1} vs {t2}")
+ return
end
+
+ self.mtype = mtype
+
+ # get the constructor
+ var callsite
+ if self isa ACrangeExpr then
+ callsite = v.get_method(self, mtype, "init", false)
+ else if self isa AOrangeExpr then
+ callsite = v.get_method(self, mtype, "without_last", false)
+ else
+ abort
+ end
+ init_callsite = callsite
end
end
redef class AIsaExpr
# The static type to cast to.
- # (different from the static type of the expression that is Bool).
+ # (different from the static type of the expression that is `Bool`).
var cast_type: nullable MType
redef fun accept_typing(v)
do
redef class ASendExpr
# The property invoked by the send.
- var mproperty: nullable MMethod
+ var callsite: nullable CallSite
redef fun accept_typing(v)
do
return
end
- var mpropdef = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
- if mpropdef == null then return
- var mproperty = mpropdef.mproperty
- self.mproperty = mproperty
- var msignature = v.resolve_signature_for(mpropdef, recvtype, self.n_expr isa ASelfExpr)
+ var callsite = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
+ if callsite == null then return
+ self.callsite = callsite
+ var msignature = callsite.msignature
var args = compute_raw_arguments
- self.raw_arguments = args
- v.check_signature(self, args, name, msignature)
+ callsite.check_signature(v, args)
- if mproperty.is_init then
+ if callsite.mproperty.is_init then
var vmpropdef = v.mpropdef
if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
v.error(self, "Can call a init only in another init")
else
self.is_typed = true
end
-
- if self.n_closure_defs.length == msignature.mclosures.length then
- for i in [0..self.n_closure_defs.length[ do
- self.n_closure_defs[i].accept_typing(v, msignature.mclosures[i])
- end
- else
- debug("closure: got {self.n_closure_defs.length}, want {msignature.mclosures.length}")
- end
end
# The name of the property
private fun property_name: String is abstract
# An array of all arguments (excluding self)
- var raw_arguments: nullable Array[AExpr]
+ fun raw_arguments: Array[AExpr] do return compute_raw_arguments
private fun compute_raw_arguments: Array[AExpr] is abstract
end
redef class ASendReassignFormExpr
# The property invoked for the writing
- var write_mproperty: nullable MMethod = null
+ var write_callsite: nullable CallSite
redef fun accept_typing(v)
do
end
var for_self = self.n_expr isa ASelfExpr
- var mpropdef = v.get_method(self, recvtype, name, for_self)
+ var callsite = v.get_method(self, recvtype, name, for_self)
- if mpropdef == null then return
- var mproperty = mpropdef.mproperty
- self.mproperty = mproperty
- var msignature = v.resolve_signature_for(mpropdef, recvtype, for_self)
+ if callsite == null then return
+ self.callsite = callsite
var args = compute_raw_arguments
- self.raw_arguments = args
- v.check_signature(self, args, name, msignature)
+ callsite.check_signature(v, args)
- var readtype = msignature.return_mtype
+ var readtype = callsite.msignature.return_mtype
if readtype == null then
v.error(self, "Error: {name} is not a function")
return
end
- var wpropdef = v.get_method(self, recvtype, name + "=", self.n_expr isa ASelfExpr)
- if wpropdef == null then return
- var wmproperty = wpropdef.mproperty
- self.write_mproperty = wmproperty
- var wmsignature = v.resolve_signature_for(wpropdef, recvtype, for_self)
+ var wcallsite = v.get_method(self, recvtype, name + "=", self.n_expr isa ASelfExpr)
+ if wcallsite == null then return
+ self.write_callsite = wcallsite
- var wtype = self.resolve_reassignment(v, readtype, wmsignature.mparameters.last.mtype)
+ var wtype = self.resolve_reassignment(v, readtype, wcallsite.msignature.mparameters.last.mtype)
if wtype == null then return
args = args.to_a # duplicate so raw_arguments keeps only the getter args
args.add(self.n_value)
- v.check_signature(self, args, name + "=", wmsignature)
+ wcallsite.check_signature(v, args)
self.is_typed = true
end
redef class ASuperExpr
# The method to call if the super is in fact a 'super init call'
# Note: if the super is a normal call-next-method, then this attribute is null
- var mproperty: nullable MMethod
+ var callsite: nullable CallSite
+
+ # The method to call is the super is a standard `call-next-method` super-call
+ # Note: if the super is a special super-init-call, then this attribute is null
+ var mpropdef: nullable MMethodDef
redef fun accept_typing(v)
do
- var recvtype = v.nclassdef.mclassdef.bound_mtype
+ var recvtype = v.anchor
+ assert recvtype != null
var mproperty = v.mpropdef.mproperty
if not mproperty isa MMethod then
v.error(self, "Error: super only usable in a method")
end
v.error(self, "Error: No super method to call for {mproperty}.")
return
- else if superprops.length > 1 then
- v.modelbuilder.warning(self, "Warning: NOT YET IMPLEMENTED: Conflicting super method to call for {mproperty}: {superprops.join(", ")}.")
- return
end
+ # FIXME: covariance of return type in linear extension?
var superprop = superprops.first
- assert superprop isa MMethodDef
- var msignature = v.resolve_signature_for(superprop, recvtype, true)
+ var msignature = superprop.msignature.as(not null)
+ msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
var args = self.n_args.to_a
if args.length > 0 then
v.check_signature(self, args, mproperty.name, msignature)
end
self.mtype = msignature.return_mtype
+ self.is_typed = true
+ v.mpropdef.has_supercall = true
+ mpropdef = v.mpropdef.as(MMethodDef)
end
private fun process_superinit(v: TypeVisitor)
do
- var recvtype = v.nclassdef.mclassdef.bound_mtype
- var mproperty = v.mpropdef.mproperty
+ var recvtype = v.anchor
+ assert recvtype != null
+ var mpropdef = v.mpropdef
+ assert mpropdef isa MMethodDef
+ var mproperty = mpropdef.mproperty
var superprop: nullable MMethodDef = null
- for msupertype in v.nclassdef.mclassdef.supertypes do
+ for msupertype in mpropdef.mclassdef.supertypes do
msupertype = msupertype.anchor_to(v.mmodule, recvtype)
var errcount = v.modelbuilder.toolcontext.error_count
var candidate = v.try_get_mproperty_by_name2(self, msupertype, mproperty.name).as(nullable MMethod)
v.error(self, "Error: No super method to call for {mproperty}.")
return
end
- self.mproperty = superprop.mproperty
+
+ var msignature = superprop.msignature.as(not null)
+ msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
+
+ var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
+ self.callsite = callsite
var args = self.n_args.to_a
- var msignature = v.resolve_signature_for(superprop, recvtype, true)
if args.length > 0 then
- v.check_signature(self, args, mproperty.name, msignature)
+ callsite.check_signature(v, args)
else
- # TODO: Check signature
+ # Check there is at least enough parameters
+ if mpropdef.msignature.arity < msignature.arity then
+ v.error(self, "Error: Not enough implicit arguments to pass. Got {mpropdef.msignature.arity}, expected at least {msignature.arity}. Signature is {msignature}")
+ return
+ end
+ # Check that each needed parameter is conform
+ var i = 0
+ for sp in msignature.mparameters do
+ var p = mpropdef.msignature.mparameters[i]
+ if not v.is_subtype(p.mtype, sp.mtype) then
+ v.error(self, "Type error: expected argument #{i} of type {sp.mtype}, got implicit argument {p.name} of type {p.mtype}. Signature is {msignature}")
+ return
+ end
+ i += 1
+ end
end
self.is_typed = true
redef class ANewExpr
# The constructor invoked by the new.
- var mproperty: nullable MMethod
+ var callsite: nullable CallSite
redef fun accept_typing(v)
do
v.error(self, "Type error: cannot instantiate the formal type {recvtype}.")
return
end
+ else
+ if recvtype.mclass.kind == abstract_kind then
+ v.error(self, "Cannot instantiate abstract class {recvtype}.")
+ return
+ else if recvtype.mclass.kind == interface_kind then
+ v.error(self, "Cannot instantiate interface {recvtype}.")
+ return
+ end
end
var name: String
else
name = "init"
end
- var propdef = v.get_method(self, recvtype, name, false)
- if propdef == null then return
+ var callsite = v.get_method(self, recvtype, name, false)
+ if callsite == null then return
- self.mproperty = propdef.mproperty
+ self.callsite = callsite
- if not propdef.mproperty.is_init_for(recvtype.mclass) then
+ if not callsite.mproperty.is_init_for(recvtype.mclass) then
v.error(self, "Error: {name} is not a constructor.")
return
end
- var msignature = v.resolve_signature_for(propdef, recvtype, false)
-
var args = n_args.to_a
- v.check_signature(self, args, name, msignature)
+ callsite.check_signature(v, args)
end
end
###
-redef class AClosureCallExpr
- redef fun accept_typing(v)
- do
- var variable = self.variable
- if variable == null then return # Skip error
-
- var recvtype = v.nclassdef.mclassdef.bound_mtype
- var msignature = variable.declared_type.as(not null)
- msignature = v.resolve_for(msignature, recvtype, false).as(MSignature)
-
- var args = n_args.to_a
- v.check_signature(self, args, variable.name, msignature)
-
- self.is_typed = true
- self.mtype = msignature.return_mtype
- end
-end
-
-redef class AClosureDef
- var mclosure: nullable MParameter
-
- private fun accept_typing(v: TypeVisitor, mparameter: MParameter)
- do
- var variables = self.variables
- if variables == null then return
-
- self.mclosure = mparameter
- var msignature = mparameter.mtype.as(MSignature)
-
- if msignature.arity != variables.length then
- v.error(self, "Type error: closure {mparameter.name} expects {msignature.arity} parameters, {variables.length} given")
- return
- end
-
- for i in [0..variables.length[ do
- variables[i].declared_type = msignature.mparameters[i].mtype
- end
-
- v.visit_stmt(self.n_expr)
- end
-end
-
-###
-
redef class ADebugTypeExpr
redef fun accept_typing(v)
do
var umtype = v.anchor_to(mtype)
v.modelbuilder.warning(self, "Found type {expr} (-> {unsafe}), expected {mtype} (-> {umtype})")
end
+ self.is_typed = true
end
end