var mclass = try_get_mclass_by_name(nclassdef, mmodule, name)
if mclass == null then
+ if nclassdef isa AStdClassdef and nclassdef.n_kwredef != null then
+ error(nclassdef, "Redef error: No imported class {name} to refine.")
+ return
+ end
mclass = new MClass(mmodule, name, arity, mkind, mvisibility)
#print "new class {mclass}"
else if nclassdef isa AStdClassdef and nmodule.mclass2nclassdef.has_key(mclass) then
error(nvisibility, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
end
nclassdef.mclass = mclass
- nmodule.mclass2nclassdef[mclass] = nclassdef
+ if not nmodule.mclass2nclassdef.has_key(mclass) then
+ nmodule.mclass2nclassdef[mclass] = nclassdef
+ nclassdef.all_defs = [nclassdef]
+ else
+ nmodule.mclass2nclassdef[mclass].all_defs.add(nclassdef)
+ end
end
# Visit the AST and create the `MClassDef` objects
var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
var mclass = nclassdef.mclass
if mclass == null then return # Skip error
- #var mclassdef = nclassdef.mclassdef.as(not null)
+
+ # In case of non-standard AClassdef, try to attach to an already existing mclassdef
+ var other_nclassdef = nmodule.mclass2nclassdef[mclass]
+ if other_nclassdef != nclassdef then
+ assert not nclassdef isa AStdClassdef
+ nclassdef.mclassdef = other_nclassdef.mclassdef
+ return
+ end
var names = new Array[String]
var bounds = new Array[MType]
error(nfd, "Error: A formal parameter type `{ptname}' already exists")
return
end
+ for c in ptname.chars do if c >= 'a' and c<= 'z' then
+ warning(nfd, "Warning: lowercase in the formal parameter type {ptname}")
+ break
+ end
names.add(ptname)
+ nfd.mtype = mclass.mclass_type.arguments[i].as(MParameterType)
end
# Revolve bound for formal parameter names
var nfd = nclassdef.n_formaldefs[i]
var nfdt = nfd.n_type
if nfdt != null then
- var bound = resolve_mtype_unchecked(nclassdef, nfdt, false)
+ var bound = resolve_mtype_unchecked(mmodule, null, nfdt, false)
if bound == null then return # Forward error
if bound.need_anchor then
# No F-bounds!
error(nfd, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
else
bounds.add(bound)
+ nfd.bound = bound
+ end
+ if bound isa MClassType and bound.mclass.kind == enum_kind then
+ warning(nfdt, "Warning: Useless formal parameter type since `{bound}` cannnot have subclasses.")
end
else if mclass.mclassdefs.is_empty then
# No bound, then implicitely bound by nullable Object
- bounds.add(objectclass.mclass_type.as_nullable)
+ var bound = objectclass.mclass_type.as_nullable
+ bounds.add(bound)
+ nfd.bound = bound
else
# Inherit the bound
- bounds.add(mclass.intro.bound_mtype.arguments[i])
+ var bound = mclass.intro.bound_mtype.arguments[i]
+ bounds.add(bound)
+ nfd.bound = bound
end
end
end
nclassdef.mclassdef = mclassdef
self.mclassdef2nclassdef[mclassdef] = nclassdef
+ if nclassdef isa AStdClassdef then
+ var ndoc = nclassdef.n_doc
+ if ndoc != null then
+ var mdoc = ndoc.to_mdoc
+ mclassdef.mdoc = mdoc
+ mdoc.original_mentity = mclassdef
+ end
+ end
+
if mclassdef.is_intro then
self.toolcontext.info("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
else
do
var mmodule = nmodule.mmodule.as(not null)
var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
+ var pointerclass = try_get_mclass_by_name(nmodule, mmodule, "Pointer")
var mclass = nclassdef.mclass.as(not null)
var mclassdef = nclassdef.mclassdef.as(not null)
+ # Do we need to specify Object as a super class?
var specobject = true
+
+ # Do we need to specify Pointer as a super class? (is only valid
+ # if `nclassdef` is an extern class)
+ var specpointer = true
+
var supertypes = new Array[MClassType]
if nclassdef isa AStdClassdef then
for nsc in nclassdef.n_superclasses do
specobject = false
var ntype = nsc.n_type
- var mtype = resolve_mtype_unchecked(nclassdef, ntype, false)
+ var mtype = resolve_mtype_unchecked(mmodule, mclassdef, ntype, false)
if mtype == null then continue # Skip because of error
if not mtype isa MClassType then
error(ntype, "Error: supertypes cannot be a formal type")
return
end
+ if not mclass.kind.can_specialize(mtype.mclass.kind) then
+ error(ntype, "Error: {mclass.kind} {mclass} cannot specialize {mtype.mclass.kind} {mtype.mclass}")
+ end
supertypes.add mtype
#print "new super : {mclass} < {mtype}"
+ if mtype.mclass.kind == extern_kind then specpointer = false
end
end
- if specobject and mclass.name != "Object" and objectclass != null and mclassdef.is_intro then
- supertypes.add objectclass.mclass_type
+
+ if mclassdef.is_intro and objectclass != null then
+ if mclass.kind == extern_kind and mclass.name != "Pointer" then
+ # it is an extern class, but not a Pointer
+ if specpointer then supertypes.add pointerclass.mclass_type
+ else if specobject and mclass.name != "Object" then
+ # it is a standard class without super class (but is not Object)
+ supertypes.add objectclass.mclass_type
+ end
end
mclassdef.set_supertypes(supertypes)
var mmodule = nmodule.mmodule.as(not null)
for imp in mmodule.in_importation.direct_greaters do
+ if not mmodule2nmodule.has_key(imp) then continue
build_classes(mmodule2nmodule[imp])
end
if errcount != toolcontext.error_count then return
# Create the mclassdef hierarchy
- for nclassdef in nmodule.n_classdefs do
- var mclassdef = nclassdef.mclassdef.as(not null)
+ for mclassdef in mmodule.mclassdefs do
mclassdef.add_in_hierarchy
end
# Check unchecked ntypes
for nclassdef in nmodule.n_classdefs do
if nclassdef isa AStdClassdef then
+ var mclassdef = nclassdef.mclassdef
# 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)
+ var bound = resolve_mtype(mmodule, mclassdef, nfdt)
if bound == null then return # Forward error
end
end
for nsc in nclassdef.n_superclasses do
var ntype = nsc.n_type
if ntype.mtype != null then
- var mtype = resolve_mtype(nclassdef, ntype)
+ var mtype = resolve_mtype(mmodule, mclassdef, ntype)
if mtype == null then return # Forward error
end
end
assert mtype isa MClassType
var sc = mtype.mclass
if not parents.has(sc) or sc == objectclass then
- warning(ntype, "Warning: superfluous super-class {mtype} in class {mclassdef.mclass}.")
+ # Skip the warning on generated code
+ if ntype.location.file != null and not ntype.location.file.filename.is_empty then
+ warning(ntype, "Warning: superfluous super-class {mtype} in class {mclassdef.mclass}.")
+ end
else if not seen_parents.has_key(sc) then
seen_parents[sc] = ntype
else
var mclassdef2nclassdef: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
# Return the static type associated to the node `ntype`.
- # `nclassdef` is the context where the call is made (used to understand formal types)
- # The mmodule used as context is `nclassdef.mmodule`
+ # `mmodule` and `mclassdef` is the context where the call is made (used to understand formal types)
# In case of problem, an error is displayed on `ntype` and null is returned.
# FIXME: the name "resolve_mtype" is awful
- fun resolve_mtype_unchecked(nclassdef: AClassdef, ntype: AType, with_virtual: Bool): nullable MType
+ fun resolve_mtype_unchecked(mmodule: MModule, mclassdef: nullable MClassDef, ntype: AType, with_virtual: Bool): nullable MType
do
var name = ntype.n_id.text
- var mclassdef = nclassdef.mclassdef
- var mmodule = nclassdef.parent.as(AModule).mmodule.as(not null)
var res: MType
# Check virtual type
else
var mtypes = new Array[MType]
for nt in ntype.n_types do
- var mt = resolve_mtype_unchecked(nclassdef, nt, with_virtual)
+ var mt = resolve_mtype_unchecked(mmodule, mclassdef, nt, with_virtual)
if mt == null then return null # Forward error
mtypes.add(mt)
end
end
# Return the static type associated to the node `ntype`.
- # `nclassdef` is the context where the call is made (used to understand formal types)
- # The mmodule used as context is `nclassdef.mmodule`
+ # `mmodule` and `mclassdef` is the context where the call is made (used to understand formal types)
# 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(mmodule: MModule, mclassdef: nullable MClassDef, ntype: AType): nullable MType
do
var mtype = ntype.mtype
- if mtype == null then mtype = resolve_mtype_unchecked(nclassdef, ntype, true)
+ if mtype == null then mtype = resolve_mtype_unchecked(mmodule, mclassdef, ntype, true)
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)
+ var mt = resolve_mtype(mmodule, mclassdef, nt)
if mt == null then return null # forward error
- if not mt.is_subtype(mmodule, mclassdef.bound_mtype, bound) then
+ var anchor
+ if mclassdef != null then anchor = mclassdef.bound_mtype else anchor = null
+ if not mt.is_subtype(mmodule, anchor, bound) then
error(nt, "Type error: expected {bound}, got {mt}")
return null
end
var mclass: nullable MClass
# The associated MClassDef once build by a `ModelBuilder`
var mclassdef: nullable MClassDef
+ # All (self and other) definitions for the same mclassdef
+ var all_defs: nullable Array[AClassdef]
end
redef class AClasskind
redef fun mkind do return extern_kind
end
+redef class AFormaldef
+ # The associated parameter type
+ var mtype: nullable MParameterType = null
+
+ # The associated bound
+ var bound: nullable MType = null
+end
+
redef class AType
# The mtype associated to the node
var mtype: nullable MType = null