metamodel: add nullable static types
authorJean Privat <jean@pryen.org>
Tue, 23 Jun 2009 17:54:47 +0000 (13:54 -0400)
committerJean Privat <jean@pryen.org>
Wed, 24 Jun 2009 20:01:52 +0000 (16:01 -0400)
Syntax error on nullable type only display a warning

Signed-off-by: Jean Privat <jean@pryen.org>

src/metamodel/static_type.nit
src/metamodel/type_formal.nit
src/syntax/mmbuilder.nit
src/syntax/syntax_base.nit

index e8b5704..8d36232 100644 (file)
@@ -45,11 +45,7 @@ redef class MMLocalClass
        # The ancestor type for a given superclass
        meth ancestor(c: MMLocalClass): MMType
        do
-               assert _ancestors != null
-               if _ancestors.has_key(c) then
-                       return _ancestors[c].stype
-               end
-               return null
+               return _ancestors[c].stype
        end
 end
 
@@ -352,6 +348,74 @@ abstract class MMType
        # Return a type approximation if the reveiver is not self
        # Useful for virtual types
        meth not_for_self: MMType do return self
+
+       # The nullable version of self (if needed)
+       attr _as_nullable_cache: MMType = null
+
+       # IS the type can accept null?
+       meth is_nullable: Bool do return false
+
+       # Return the nullable version of the type
+       # Noop if already nullable
+       meth as_nullable: MMType do
+               var cache = _as_nullable_cache
+               if cache != null then return cache
+               var res = new MMNullableType(self)
+               _as_nullable_cache = res
+               return res
+       end
+
+       # Return the not null version of the type
+       # Noop if already not null
+       meth as_notnull: MMType do return self
+end
+
+class MMNullableType
+special MMType
+       attr _base_type: MMType
+       redef meth is_nullable: Bool do return true
+       redef meth as_notnull do return _base_type
+       redef meth as_nullable do return self
+       init(t: MMType) do _base_type = t
+
+       redef meth module do return _base_type.module
+
+       redef meth local_class do return _base_type.local_class
+
+       redef meth <(t)
+       do
+               return t isa MMNullableType and _base_type < t.as_notnull
+       end
+
+       redef meth to_s
+       do
+               return "nullable {_base_type}"
+       end
+
+       redef meth is_supertype(t)
+       do
+               return _base_type.is_supertype(t)
+       end
+
+       redef meth for_module(mod)
+       do
+               return _base_type.for_module(mod).as_nullable
+       end
+
+       redef meth adapt_to(recv)
+       do
+               return _base_type.adapt_to(recv).as_nullable
+       end
+
+       redef meth upcast_for(c)
+       do
+               return _base_type.upcast_for(c)
+       end
+
+       redef meth not_for_self
+       do
+               return _base_type.not_for_self.as_nullable
+       end
 end
 
 class MMTypeClass 
@@ -413,11 +477,14 @@ end
 class MMTypeNone
 special MMType
        redef readable attr _module: MMModule
-       redef meth <(t) do return true
+       redef meth is_nullable: Bool do return true
+       redef meth <(t) do return t isa MMTypeNone or t isa MMNullableType
        redef meth to_s do return "null"
        redef meth is_supertype(t) do return false
        redef meth local_class do abort
        redef meth upcast_for(c) do abort
+       redef meth as_nullable do return self
+       redef meth as_notnull do abort
 
        private init(m: MMModule) do _module = m
 end
index fcbcb87..d4da2f5 100644 (file)
@@ -43,6 +43,7 @@ special MMType
 
        redef meth <(t) do return t != null and (t == self or t.is_supertype(_bound))
        redef meth is_supertype(t) do return _bound.is_supertype(t)
+       redef meth is_nullable do return _bound.is_nullable
        redef meth direct_type do return _bound.direct_type
        redef meth local_class do return _bound.local_class
 
index cdcf45e..99be10f 100644 (file)
@@ -688,7 +688,7 @@ redef class AFormaldef
                var o = c.global.intro
                if c == o then
                        if n_type == null then
-                               _formal.bound = v.module.type_any
+                               _formal.bound = v.module.type_any.as_nullable
                        else
                                _formal.bound = n_type.get_stype(v)
                        end
index 096e9b3..e5b492d 100644 (file)
@@ -362,12 +362,15 @@ special Visitor
                if subtype < stype then
                        return true
                end
-               #error(n, "Type error: expected {stype}'{stype.module}, got {subtype}'{subtype.module}")
-               #abort
+               # Do not enforce nullable subtype rules yet
+               if subtype isa MMTypeNone or subtype.as_notnull < stype.as_notnull then
+                       warning(n, "Nullable type warning: expected {stype}, got {subtype}")
+                       return true
+               end
                error(n, "Type error: expected {stype}, got {subtype}")
                return false
        end
-       
+
        # Check that an expression has a static type and that 
        # Display an error and return false if n is a statement
        # Require that the static type of n is known
@@ -554,15 +557,17 @@ redef class AType
                var name = n_id.to_symbol
                var mod = v.module
                var cla = v.local_class
+               var t: MMType
 
                if cla.formal_dict.has_key(name) then
                        if n_types.length > 0 then
                                v.error(self, "Type error: formal type {name} cannot have formal parameters.")
                                return null
                        end
-                       var formal = cla.formal_dict[name]
-                       _stype_cache = formal
-                       return formal
+                       t = cla.formal_dict[name]
+                       if n_kwnullable != null then t = t.as_nullable
+                       _stype_cache = t
+                       return t
                end
 
                if cla.global_properties != null and cla.has_global_property_by_name(name) then
@@ -570,11 +575,12 @@ redef class AType
                                v.error(self, "Type error: formal type {name} cannot have formal parameters.")
                                return null
                        end
-                       var t = cla.get_type.local_class.select_virtual_type(name).stype_for(cla.get_type)
+                       t = cla.get_type.local_class.select_virtual_type(name).stype_for(cla.get_type)
                        if t == null then
                                v.error(self, "Type error: circular definition in formal type {name}.")
                                return null
                        end
+                       if n_kwnullable != null then t = t.as_nullable
                        _stype_cache = t
                        return t
                end
@@ -593,14 +599,13 @@ redef class AType
                        for p in n_types do
                                tab.add(p.get_unchecked_stype(v))
                        end
-                       var t = local_class.get_instantiate_type(tab)
-                       _stype_cache = t
-                       return t
+                       t = local_class.get_instantiate_type(tab)
                else
-                       var t = local_class.get_type
-                       _stype_cache = t
-                       return t
+                       t = local_class.get_type
                end
+               if n_kwnullable != null then t = t.as_nullable
+               _stype_cache = t
+               return t
        end
        
        redef meth get_stype(v)