src: use `as_notnullable` in code
[nit.git] / src / modelize_property.nit
index 96ec598..8273fb8 100644 (file)
@@ -187,7 +187,7 @@ redef class ModelBuilder
                # It is a case-by case
                var vis_type: nullable MVisibility = null # The own visibility of the type
                var mmodule_type: nullable MModule = null # The origial module of the type
-               if mtype isa MNullableType then mtype = mtype.mtype
+               mtype = mtype.as_notnullable
                if mtype isa MClassType then
                        vis_type = mtype.mclass.visibility
                        mmodule_type = mtype.mclass.intro.mmodule
@@ -645,10 +645,20 @@ redef class AAttrPropdef
        # Is the node tagged `noinit`?
        var noinit = false
 
+       # Is the node taggeg lazy?
+       var is_lazy = false
+
+       # The guard associated to a lasy attribute.
+       # Because some engines does not have a working `isset`,
+       # this additionnal attribute is used to guard the lazy initialization.
+       # TODO: to remove once isset is correctly implemented
+       var mlazypropdef: nullable MAttributeDef
+
        # The associated getter (read accessor) if any
        var mreadpropdef: nullable MMethodDef writable
        # The associated setter (write accessor) if any
        var mwritepropdef: nullable MMethodDef writable
+
        redef fun build_property(modelbuilder, mclassdef)
        do
                var mclass = mclassdef.mclass
@@ -718,6 +728,17 @@ redef class AAttrPropdef
                        modelbuilder.mpropdef2npropdef[mreadpropdef] = self
                        mreadpropdef.mdoc = mpropdef.mdoc
 
+                       var atlazy = self.get_single_annotation("lazy", modelbuilder)
+                       if atlazy != null then
+                               if n_expr == null then
+                                       modelbuilder.error(atlazy, "Error: a lazy attribute needs a value")
+                               end
+                               is_lazy = true
+                               var mlazyprop = new MAttribute(mclassdef, "lazy _" + name, none_visibility)
+                               var mlazypropdef = new MAttributeDef(mclassdef, mlazyprop, self.location)
+                               self.mlazypropdef = mlazypropdef
+                       end
+
                        var atreadonly = self.get_single_annotation("readonly", modelbuilder)
                        if atreadonly != null then
                                if n_expr == null then
@@ -840,7 +861,7 @@ redef class AAttrPropdef
                        mreadpropdef.msignature = msignature
                end
 
-               var msritepropdef = self.mwritepropdef
+               var mwritepropdef = self.mwritepropdef
                if mwritepropdef != null then
                        var name: String
                        if n_id != null then
@@ -852,6 +873,11 @@ redef class AAttrPropdef
                        var msignature = new MSignature([mparameter], null)
                        mwritepropdef.msignature = msignature
                end
+
+               var mlazypropdef = self.mlazypropdef
+               if mlazypropdef != null then
+                       mlazypropdef.static_mtype = modelbuilder.model.get_mclasses_by_name("Bool").first.mclass_type
+               end
        end
 
        redef fun check_signature(modelbuilder)
@@ -975,6 +1001,11 @@ redef class ATypePropdef
                self.mpropdef = mpropdef
                modelbuilder.mpropdef2npropdef[mpropdef] = self
                set_doc(mpropdef)
+
+               var atfixed = get_single_annotation("fixed", modelbuilder)
+               if atfixed != null then
+                       mpropdef.is_fixed = true
+               end
        end
 
        redef fun build_signature(modelbuilder)
@@ -1003,25 +1034,44 @@ redef class ATypePropdef
 
                modelbuilder.check_visibility(n_type, bound, mpropdef)
 
-               # Fast case: the bound is not a formal type
-               if not bound isa MVirtualType then return
-
                var mclassdef = mpropdef.mclassdef
                var mmodule = mclassdef.mmodule
                var anchor = mclassdef.bound_mtype
 
-               # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
-               var seen = [self.mpropdef.mproperty.mvirtualtype]
-               loop
-                       if seen.has(bound) then
+               # Check circularity
+               if bound isa MVirtualType then
+                       # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
+                       var seen = [self.mpropdef.mproperty.mvirtualtype]
+                       loop
+                               if seen.has(bound) then
+                                       seen.add(bound)
+                                       modelbuilder.error(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
+                                       return
+                               end
                                seen.add(bound)
-                               modelbuilder.error(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
-                               return
+                               var next = bound.lookup_bound(mmodule, anchor)
+                               if not next isa MVirtualType then break
+                               bound = next
+                       end
+               end
+
+               # Check redefinitions
+               bound = mpropdef.bound.as(not null)
+               for p in mpropdef.mproperty.lookup_super_definitions(mmodule, anchor) do
+                       var supbound = p.bound.as(not null)
+                       if p.is_fixed then
+                               modelbuilder.error(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
+                               break
+                       end
+                       if p.mclassdef.mclass == mclassdef.mclass then
+                               # Still a warning to pass existing bad code
+                               modelbuilder.warning(n_type, "Redef Error: a virtual type cannot be refined.")
+                               break
+                       end
+                       if not bound.is_subtype(mmodule, anchor, supbound) then
+                               modelbuilder.error(n_type, "Redef Error: Wrong bound type. Found {bound}, expected a subtype of {supbound}, as in {p}.")
+                               break
                        end
-                       seen.add(bound)
-                       var next = bound.lookup_bound(mmodule, anchor)
-                       if not next isa MVirtualType then break
-                       bound = next
                end
        end
 end