X-Git-Url: http://nitlanguage.org diff --git a/src/modelize_class.nit b/src/modelize_class.nit index 14952d1..09b7081 100644 --- a/src/modelize_class.nit +++ b/src/modelize_class.nit @@ -76,6 +76,10 @@ redef class ModelBuilder 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 @@ -93,7 +97,12 @@ redef class ModelBuilder 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 @@ -103,7 +112,14 @@ redef class ModelBuilder 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] @@ -116,7 +132,12 @@ redef class ModelBuilder 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 @@ -124,20 +145,25 @@ redef class ModelBuilder 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 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 @@ -147,6 +173,15 @@ redef class ModelBuilder 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 @@ -159,27 +194,45 @@ redef class ModelBuilder 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) @@ -212,6 +265,7 @@ redef class ModelBuilder 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 @@ -239,8 +293,7 @@ redef class ModelBuilder 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 @@ -256,11 +309,12 @@ redef class ModelBuilder # 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 @@ -268,7 +322,7 @@ redef class ModelBuilder 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 @@ -341,15 +395,12 @@ redef class ModelBuilder 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 @@ -404,7 +455,7 @@ redef class ModelBuilder 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 @@ -421,27 +472,26 @@ redef class ModelBuilder 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 @@ -466,6 +516,8 @@ redef class AClassdef 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 @@ -488,6 +540,14 @@ redef class AExternClasskind 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