# By OO-services we mean message sending, attribute access, instantiation, etc.
module typing
-import flow
-import modelize_property
-import phase
+import modelize
import local_var_init
redef class ToolContext
private class TypeVisitor
var modelbuilder: ModelBuilder
- var nclassdef: AClassdef
# The module of the analysis
# Used to correctly query the model
# 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
- var mclassdef = mpropdef.mclassdef
+ self.mmodule = mmodule
+
+ if mpropdef != null then
+ self.mpropdef = mpropdef
+ var mclassdef = mpropdef.mclassdef
+ self.mclassdef = mclassdef
+ self.anchor = mclassdef.bound_mtype
- self.mmodule = mclassdef.mmodule
- self.anchor = mclassdef.bound_mtype
+ var mclass = mclassdef.mclass
- var mclass = mclassdef.mclass
+ var selfvariable = new Variable("self")
+ self.selfvariable = selfvariable
+ selfvariable.declared_type = mclass.mclass_type
- var selfvariable = new Variable("self")
- self.selfvariable = selfvariable
- selfvariable.declared_type = mclass.mclass_type
+ 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
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
+ else if self.is_subtype(sub, sup) then
self.modelbuilder.warning(node, "Warning: Expression is already a {sup} since it is a {sub}.")
end
return sup
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
end
assert mproperty isa MMethod
+
+ if is_toplevel_context and recv_is_self and not mproperty.is_toplevel then
+ 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
- var msignature = mpropdef.msignature.as(not null)
+ var msignature = mpropdef.new_msignature or else 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
+ rettype = rettype.as_notnullable
if rettype isa MParameterType then
var erased_rettype = msignature.return_mtype
assert erased_rettype != null
var nblock = self.n_block
if nblock == null then return
- var nclassdef = self.parent.as(AClassdef)
var mpropdef = self.mpropdef.as(not null)
- var v = new TypeVisitor(modelbuilder, nclassdef, mpropdef)
+ var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
self.selfvariable = v.selfvariable
var mmethoddef = self.mpropdef.as(not null)
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
# anchor formal and virtual types
if mtype.need_anchor then mtype = v.anchor_to(mtype)
- if mtype isa MNullableType then mtype = mtype.mtype
+ mtype = mtype.as_notnullable
self.coltype = mtype.as(MClassType)
# get methods is_ok, next, item
return # Skip error
end
- if t1 isa MNullableType then
- t1 = t1.mtype
- end
+ t1 = t1.as_notnullable
var t = v.merge_types(self, [t1, t2])
if t == null then
if mclass == null then return # Forward error
self.mtype = mclass.mclass_type
for nexpr in self.n_exprs do
- var t = v.visit_expr(nexpr)
+ v.visit_expr_subtype(nexpr, v.mmodule.object_type)
end
end
end
redef fun accept_typing(v)
do
var mtype = v.visit_expr(self.n_expr)
+ if mtype == null then return # Forward error
+
if mtype isa MNullType then
v.error(self, "Type error: as(not null) on null")
return
self.mtype = mtype.mtype
return
end
- # TODO: warn on useless as not null
self.mtype = mtype
+
+ if mtype isa MClassType then
+ v.modelbuilder.warning(self, "Warning: expression is already not null, since it is a `{mtype}`.")
+ return
+ end
+ assert mtype.need_anchor
+ var u = v.anchor_to(mtype)
+ if not u isa MNullableType then
+ v.modelbuilder.warning(self, "Warning: expression is already not null, since it is a `{mtype}: {u}`.")
+ return
+ end
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)
if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
v.error(self, "Can call a init only in another init")
end
+ if vmpropdef isa MMethodDef and vmpropdef.mproperty.is_root_init and not callsite.mproperty.is_root_init then
+ v.error(self, "Error: {vmpropdef} cannot call a factory {callsite.mproperty}")
+ end
end
var ret = msignature.return_mtype
if v.modelbuilder.toolcontext.error_count > errcount then return # Forard error
continue # Try next super-class
end
- if superprop != null and superprop.mproperty != candidate then
+ if superprop != null and candidate.is_root_init then
+ continue
+ end
+ if superprop != null and superprop.mproperty != candidate and not superprop.mproperty.is_root_init then
v.error(self, "Error: conflicting super constructor to call for {mproperty}: {candidate.full_name}, {superprop.mproperty.full_name}")
return
end
var candidatedefs = candidate.lookup_definitions(v.mmodule, recvtype)
- if superprop != null then
+ if superprop != null and superprop.mproperty == candidate then
if superprop == candidatedefs.first then continue
candidatedefs.add(superprop)
end
return
end
- var msignature = superprop.msignature.as(not null)
+ var msignature = superprop.new_msignature or else 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)