modelize_class: Link `subset_kind` with its corresponding production
[nit.git] / src / modelize / modelize_class.nit
index b3ab0bb..553263b 100644 (file)
@@ -46,8 +46,11 @@ redef class ModelBuilder
                var mvisibility: nullable MVisibility
                var arity = 0
                var names = new Array[String]
+               var mclass
                if nclassdef isa AStdClassdef then
-                       name = nclassdef.n_id.text
+                       var qid = nclassdef.n_qid
+                       assert qid != null
+                       name = qid.n_id.text
                        nkind = nclassdef.n_classkind
                        mkind = nkind.mkind
                        nvisibility = nclassdef.n_visibility
@@ -74,6 +77,12 @@ redef class ModelBuilder
                                end
                                names.add(ptname)
                        end
+                       mclass = try_get_mclass_by_qid(qid, mmodule)
+                       if mclass == null and (qid.n_qualified != null or nclassdef.n_kwredef != null) then
+                               class_not_found(qid, mmodule)
+                               nclassdef.is_broken = true
+                               return
+                       end
 
                else if nclassdef isa ATopClassdef and nclassdef.n_propdefs.first.as(AMethPropdef).n_methid.collect_text == "sys" then
                        # Special case to keep `sys` in object.
@@ -84,21 +93,17 @@ redef class ModelBuilder
                        mkind = interface_kind
                        nvisibility = null
                        mvisibility = public_visibility
+                       mclass = try_get_mclass_by_name(nclassdef, mmodule, name)
                else
                        name = "Sys"
                        nkind = null
                        mkind = concrete_kind
                        nvisibility = null
                        mvisibility = public_visibility
+                       mclass = try_get_mclass_by_name(nclassdef, mmodule, name)
                end
 
-               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
-
                        # Check for conflicting class full-names in the package
                        if mmodule.mgroup != null and mvisibility >= protected_visibility then
                                var mclasses = model.get_mclasses_by_name(name)
@@ -112,7 +117,7 @@ redef class ModelBuilder
                                end
                        end
 
-                       mclass = new MClass(mmodule, name, names, mkind, mvisibility)
+                       mclass = new MClass(mmodule, name, nclassdef.location, names, mkind, mvisibility)
                        #print "new class {mclass}"
                else if nclassdef isa AStdClassdef and nmodule.mclass2nclassdef.has_key(mclass) then
                        error(nclassdef, "Error: a class `{name}` is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
@@ -174,7 +179,7 @@ redef class ModelBuilder
                                end
                                var nfdt = nfd.n_type
                                if nfdt != null then
-                                       var bound = resolve_mtype_unchecked(mmodule, null, nfdt, false)
+                                       var bound = resolve_mtype3_unchecked(mmodule, null, null, nfdt, false)
                                        if bound == null then return # Forward error
                                        if bound.need_anchor then
                                                # No F-bounds!
@@ -183,9 +188,6 @@ redef class ModelBuilder
                                                bounds.add(bound)
                                                nfd.bound = bound
                                        end
-                                       if bound isa MClassType and bound.mclass.kind == enum_kind then
-                                               warning(nfdt, "useless-bound", "Warning: useless formal parameter type since `{bound}` cannot have subclasses.")
-                                       end
                                else if mclass.mclassdefs.is_empty then
                                        if objectclass == null then
                                                error(nfd, "Error: formal parameter type `{pname}` unbounded but no `Object` class exists.")
@@ -223,7 +225,7 @@ redef class ModelBuilder
                if mclassdef.is_intro then
                        self.toolcontext.info("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
                else
-                       self.toolcontext.info("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
+                       self.toolcontext.info("{mclassdef} refines {mclass.kind} {mclass.full_name}", 3)
                end
        end
 
@@ -251,7 +253,7 @@ redef class ModelBuilder
                        for nsc in nclassdef.n_superclasses do
                                specobject = false
                                var ntype = nsc.n_type
-                               var mtype = resolve_mtype_unchecked(mmodule, mclassdef, ntype, false)
+                               var mtype = resolve_mtype_unchecked(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.")
@@ -269,10 +271,19 @@ redef class ModelBuilder
                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 pointerclass == null then
+                                       error(nclassdef, "Error: `Pointer` must be defined first.")
+                                       return
+                               end
                                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
+                       else if specobject then
+                               if mclass.name != "Object" then
+                                       # it is a standard class without super class (but is not Object)
+                                       supertypes.add objectclass.mclass_type
+                               else if mclass.kind != interface_kind then
+                                       error(nclassdef, "Error: `Object` must be an {interface_kind}.")
+                                       return
+                               end
                        end
                end
 
@@ -298,10 +309,8 @@ redef class ModelBuilder
        end
 
        # Build the classes of the module `nmodule`.
-       # REQUIRE: classes of imported modules are already build. (let `phase` do the job)
        private fun build_classes(nmodule: AModule)
        do
-               var errcount = toolcontext.error_count
                # Force building recursively
                if nmodule.build_classes_is_done then return
                nmodule.build_classes_is_done = true
@@ -312,8 +321,6 @@ redef class ModelBuilder
                        if nimp != null then build_classes(nimp)
                end
 
-               if errcount != toolcontext.error_count then return
-
                # Create all classes
                # process AStdClassdef before so that non-AStdClassdef classes can be attached to existing ones, if any
                for nclassdef in nmodule.n_classdefs do
@@ -325,8 +332,6 @@ redef class ModelBuilder
                        self.build_a_mclass(nmodule, nclassdef)
                end
 
-               if errcount != toolcontext.error_count then return
-
                # Create all classdefs
                for nclassdef in nmodule.n_classdefs do
                        if not nclassdef isa AStdClassdef then continue
@@ -337,38 +342,40 @@ redef class ModelBuilder
                        self.build_a_mclassdef(nmodule, nclassdef)
                end
 
-               if errcount != toolcontext.error_count then return
-
                # Create inheritance on all classdefs
                for nclassdef in nmodule.n_classdefs do
                        self.collect_a_mclassdef_inheritance(nmodule, nclassdef)
                end
 
-               if errcount != toolcontext.error_count then return
-
                # Create the mclassdef hierarchy
                for mclassdef in mmodule.mclassdefs do
                        mclassdef.add_in_hierarchy
                end
 
-               if errcount != toolcontext.error_count then return
-
                # Check inheritance
                for nclassdef in nmodule.n_classdefs do
                        self.check_supertypes(nmodule, nclassdef)
                end
 
-               if errcount != toolcontext.error_count then return
-
                # Check unchecked ntypes
                for nclassdef in nmodule.n_classdefs do
                        if nclassdef isa AStdClassdef then
                                var mclassdef = nclassdef.mclassdef
+                               var mclass
+                               var anchor
+                               if mclassdef == null then
+                                       mclass = null
+                                       anchor = null
+                               else
+                                       mclass = mclassdef.mclass
+                                       anchor = mclassdef.bound_mtype
+                               end
+
                                # check bound of formal parameter
-                               for nfd in  nclassdef.n_formaldefs do
+                               for nfd in nclassdef.n_formaldefs do
                                        var nfdt = nfd.n_type
                                        if nfdt != null and nfdt.mtype != null then
-                                               var bound = resolve_mtype(mmodule, mclassdef, nfdt)
+                                               var bound = resolve_mtype3(mmodule, mclass, anchor, nfdt)
                                                if bound == null then return # Forward error
                                        end
                                end
@@ -376,15 +383,13 @@ redef class ModelBuilder
                                for nsc in nclassdef.n_superclasses do
                                        var ntype = nsc.n_type
                                        if ntype.mtype != null then
-                                               var mtype = resolve_mtype(mmodule, mclassdef, ntype)
+                                               var mtype = resolve_mtype3(mmodule, mclass, anchor, ntype)
                                                if mtype == null then return # Forward error
                                        end
                                end
                        end
                end
 
-               if errcount != toolcontext.error_count then return
-
                # Check clash of ancestors
                for nclassdef in nmodule.n_classdefs do
                        var mclassdef = nclassdef.mclassdef
@@ -405,13 +410,11 @@ redef class ModelBuilder
                        end
                end
 
-               if errcount != toolcontext.error_count then return
-
                # TODO: Check that the super-class is not intrusive
 
                # Check that the superclasses are not already known (by transitivity)
                for nclassdef in nmodule.n_classdefs do
-                       if not nclassdef isa AStdClassdef then continue
+                       if not nclassdef isa AStdClassdef or nclassdef.is_broken then continue
                        var mclassdef = nclassdef.mclassdef
                        if mclassdef == null then continue
 
@@ -497,6 +500,9 @@ end
 redef class AExternClasskind
        redef fun mkind do return extern_kind
 end
+redef class ASubsetClasskind
+       redef fun mkind do return subset_kind
+end
 
 redef class AFormaldef
        # The associated parameter type