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
fun resolve_mtype(node: AType): nullable MType
do
- return self.modelbuilder.resolve_mtype(mmodule, mpropdef.mclassdef, 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 and name != "sys" and name != "exit" 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
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)