var nfd = nclassdef.n_formaldefs[i]
var nfdt = nfd.n_type
if nfdt != null then
- var bound = resolve_mtype(nclassdef, nfdt)
+ var bound = resolve_mtype_unchecked(nclassdef, nfdt)
if bound == null then return # Forward error
if bound.need_anchor then
# No F-bounds!
bounds.add(objectclass.mclass_type.as_nullable)
else
# Inherit the bound
- bounds.add(mclass.mclassdefs.first.bound_mtype.arguments[i])
+ bounds.add(mclass.intro.bound_mtype.arguments[i])
end
end
end
for nsc in nclassdef.n_superclasses do
specobject = false
var ntype = nsc.n_type
- var mtype = resolve_mtype(nclassdef, ntype)
+ var mtype = resolve_mtype_unchecked(nclassdef, ntype)
if mtype == null then continue # Skip because of error
if not mtype isa MClassType then
error(ntype, "Error: supertypes cannot be a formal type")
end
# Check the validity of the specialization heirarchy
- # FIXME Stub implementation
private fun check_supertypes(nmodule: AModule, nclassdef: AClassdef)
do
var mmodule = nmodule.mmodule.as(not null)
var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
var mclass = nclassdef.mclass.as(not null)
var mclassdef = nclassdef.mclassdef.as(not null)
+
+ for s in mclassdef.supertypes do
+ if s.is_subtype(mmodule, mclassdef.bound_mtype, mclassdef.bound_mtype) then
+ error(nclassdef, "Error: Inheritance loop for class {mclass} with type {s}")
+ end
+ end
end
# Build the classes of the module `nmodule'.
mclassdef.add_in_hierarchy
end
+ # Check inheritance
+ for nclassdef in nmodule.n_classdefs do
+ self.check_supertypes(nmodule, nclassdef)
+ end
+
+ # Check unchecked ntypes
+ for nclassdef in nmodule.n_classdefs do
+ if nclassdef isa AStdClassdef then
+ # check bound of formal parameter
+ for nfd in nclassdef.n_formaldefs do
+ var nfdt = nfd.n_type
+ if nfdt != null and nfdt.mtype != null then
+ var bound = resolve_mtype(nclassdef, nfdt)
+ if bound == null then return # Forward error
+ end
+ end
+ # check declared super types
+ for nsc in nclassdef.n_superclasses do
+ var ntype = nsc.n_type
+ if ntype.mtype != null then
+ var mtype = resolve_mtype(nclassdef, ntype)
+ if mtype == null then return # Forward error
+ end
+ end
+ end
+
+ end
+
# TODO: Check that the super-class is not intrusive
# TODO: Check that the super-class is not already known (by transitivity)
# The mmodule used as context is `nclassdef.mmodule'
# In case of problem, an error is displayed on `ntype' and null is returned.
# FIXME: the name "resolve_mtype" is awful
- fun resolve_mtype(nclassdef: AClassdef, ntype: AType): nullable MType
+ fun resolve_mtype_unchecked(nclassdef: AClassdef, ntype: AType): nullable MType
do
var name = ntype.n_id.text
var mclassdef = nclassdef.mclassdef
end
res = prop.mvirtualtype
if ntype.n_kwnullable != null then res = res.as_nullable
+ ntype.mtype = res
return res
end
end
if mclassdef.parameter_names[i] == name then
res = mclassdef.mclass.mclass_type.arguments[i]
if ntype.n_kwnullable != null then res = res.as_nullable
+ ntype.mtype = res
return res
end
end
if arity == 0 then
res = mclass.mclass_type
if ntype.n_kwnullable != null then res = res.as_nullable
+ ntype.mtype = res
return res
else
var mtypes = new Array[MType]
for nt in ntype.n_types do
- var mt = resolve_mtype(nclassdef, nt)
+ var mt = resolve_mtype_unchecked(nclassdef, nt)
if mt == null then return null # Forward error
mtypes.add(mt)
end
res = mclass.get_mtype(mtypes)
if ntype.n_kwnullable != null then res = res.as_nullable
+ ntype.mtype = res
return res
end
end
return null
end
+ # Return the static type associated to the node `ntype'.
+ # `classdef' is the context where the call is made (used to understand formal types)
+ # The mmodule used as context is `nclassdef.mmodule'
+ # In case of problem, an error is displayed on `ntype' and null is returned.
+ # FIXME: the name "resolve_mtype" is awful
+ fun resolve_mtype(nclassdef: AClassdef, ntype: AType): nullable MType
+ do
+ var mtype = ntype.mtype
+ if mtype == null then mtype = resolve_mtype_unchecked(nclassdef, ntype)
+ if mtype == null then return null # Forward error
+
+ if ntype.checked_mtype then return mtype
+ if mtype isa MGenericType then
+ var mmodule = nclassdef.parent.as(AModule).mmodule.as(not null)
+ var mclassdef = nclassdef.mclassdef
+ var mclass = mtype.mclass
+ for i in [0..mclass.arity[ do
+ var bound = mclass.intro.bound_mtype.arguments[i]
+ var nt = ntype.n_types[i]
+ var mt = resolve_mtype(nclassdef, nt)
+ if mt == null then return null # forward error
+ if not mt.is_subtype(mmodule, mclassdef.bound_mtype, bound) then
+ error(nt, "Type error: expected {bound}, got {mt}")
+ return null
+ end
+ end
+ end
+ ntype.checked_mtype = true
+ return mtype
+ end
+
# Helper function to display an error on a node.
# Alias for `self.toolcontext.error(n.hot_location, text)'
fun error(n: ANode, text: String)
# The free init (implicitely constructed by the class if required)
var mfree_init: nullable MMethodDef = null
+
+ # What is the APropdef associated to a MProperty?
+ # Used to check multiple definition of a property.
+ var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
end
redef class AClasskind
redef fun mvisibility do return private_visibility
end
+redef class AType
+ # The mtype associated to the node
+ var mtype: nullable MType = null
+
+ # Is the mtype a valid one?
+ var checked_mtype: Bool = false
+end
#
private fun check_redef_keyword(modelbuilder: ModelBuilder, nclassdef: AClassdef, kwredef: nullable Token, need_redef: Bool, mprop: MProperty): Bool
do
+ if nclassdef.mprop2npropdef.has_key(mprop) then
+ modelbuilder.error(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
+ return false
+ end
if kwredef == null then
if need_redef then
modelbuilder.error(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
name = "init"
name_node = self.n_kwinit
else if self isa AExternInitPropdef then
- name = "new"
+ name = "init"
name_node = self.n_kwnew
else
abort
end
check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
end
+ nclassdef.mprop2npropdef[mprop] = self
var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
modelbuilder.error(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
else if mclass.kind == enum_kind then
modelbuilder.error(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
+ else if mclass.kind == extern_kind then
+ modelbuilder.error(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
end
var nid = self.n_id
check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return
end
+ nclassdef.mprop2npropdef[mprop] = self
+
var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
self.mpropdef = mpropdef
modelbuilder.mpropdef2npropdef[mpropdef] = self
if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, true, mreadprop) then return
check_redef_property_visibility(modelbuilder, nclassdef, nreadable.n_visibility, mreadprop)
end
+ nclassdef.mprop2npropdef[mreadprop] = self
+
var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
self.mreadpropdef = mreadpropdef
modelbuilder.mpropdef2npropdef[mreadpropdef] = self
if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, true, mwriteprop) then return
check_redef_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility, mwriteprop)
end
+ nclassdef.mprop2npropdef[mwriteprop] = self
+
var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
self.mwritepropdef = mwritepropdef
modelbuilder.mpropdef2npropdef[mwritepropdef] = self
if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mreadprop) then return
check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mreadprop)
end
+ nclassdef.mprop2npropdef[mreadprop] = self
+
var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
self.mreadpropdef = mreadpropdef
modelbuilder.mpropdef2npropdef[mreadpropdef] = self
check_redef_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility, mwriteprop)
end
end
+ nclassdef.mprop2npropdef[mwriteprop] = self
+
var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
self.mwritepropdef = mwritepropdef
modelbuilder.mpropdef2npropdef[mwritepropdef] = self
assert mprop isa MVirtualTypeProp
check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
end
+ nclassdef.mprop2npropdef[mprop] = self
+
var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
self.mpropdef = mpropdef
end