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)
+ # Is `self` use restricted?
+ # * no explicit `self`
+ # * method called on the implicit self must be top-level
+ var is_toplevel_context = false
+
+ 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
+ var selfvariable = new Variable("self")
+ self.selfvariable = selfvariable
+ selfvariable.declared_type = mclass.mclass_type
- fun anchor: MClassType do return self.nclassdef.mclassdef.bound_mtype
+ var mprop = mpropdef.mproperty
+ if mprop isa MMethod and mprop.is_toplevel then
+ is_toplevel_context = true
+ end
+ 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`.
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}'.")
end
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 then
- self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self. {mproperty.intro_mclassdef.mmodule.visibility_for(self.mmodule)}")
+
+ if is_toplevel_context and recv_is_self and not mproperty.is_toplevel and name != "sys" and name != "exit" and name != "args" then
+ # FIXME named methods are here as a workaround
+ error(node, "Error: '{name}' is not a top-level method, thus need a receiver.")
+ end
+ if not recv_is_self and mproperty.is_toplevel then
+ error(node, "Error: cannot call '{name}', a top-level method, with a receiver.")
+ end
+
+ 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
end
- var msignature = self.resolve_signature_for(mpropdef, recvtype, recv_is_self)
+ 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
end
end
- var callsite = new CallSite(node, recvtype, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
+ var callsite = new CallSite(node, recvtype, mmodule, anchor, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
return callsite
end
# The assiciated node for location
var node: ANode
- # The statis type of the receiver
+ # 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 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
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
if objcla == null then return
# check iterator method
- var itdef = v.get_method(self, mtype, "iterator", true)
+ var itdef = v.get_method(self, mtype, "iterator", n_expr isa ASelfExpr)
if itdef == null then
v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
return
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 var its_variable: nullable Variable
redef fun accept_typing(v)
do
+ if v.is_toplevel_context and not self isa AImplicitSelfExpr then
+ v.error(self, "Error: self cannot be used in top-level method.")
+ end
var variable = v.selfvariable
self.its_variable = variable
self.mtype = v.get_variable(self, variable)
var msignature = callsite.msignature
var args = compute_raw_arguments
- self.raw_arguments = args
callsite.check_signature(v, args)
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
self.callsite = callsite
var args = compute_raw_arguments
- self.raw_arguments = args
callsite.check_signature(v, args)
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")
# FIXME: covariance of return type in linear extension?
var superprop = superprops.first
- 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)
private fun process_superinit(v: TypeVisitor)
do
- var recvtype = v.nclassdef.mclassdef.bound_mtype
+ 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)
return
end
- var msignature = v.resolve_signature_for(superprop, recvtype, true)
- var callsite = new CallSite(self, recvtype, true, superprop.mproperty, superprop, msignature, false)
+ 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