syntax: Update check_conform_multiexpr with nullables
[nit.git] / src / syntax / syntax_base.nit
index bbb972c..ab1ced0 100644 (file)
@@ -29,9 +29,9 @@ special MMModule
        # Concrete NIT source local classs by name
        readable attr _src_local_classes: Map[Symbol, MMSrcLocalClass]
 
-       init(c: MMContext, source: AModule, dir: MMDirectory, name: Symbol)
+       init(c: MMContext, source: AModule, dir: MMDirectory, name: Symbol, filename: String)
        do
-               super(name, dir, c)
+               super(name, dir, c, filename)
                _node = source
                _src_local_classes = new HashMap[Symbol, MMSrcLocalClass]
        end
@@ -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
@@ -398,16 +401,23 @@ special Visitor
        # Conformance is granted if among them there is a most general type
        # Return the most general type if a conformance is found
        # Display an error and return null if no conformance is found
+       # The only allowed combinaison is with the nullable marker
        # @param stype is a possible additional type (without node)
        # Examples:
        #   Int, Int, Object => return Object
        #   Int, Float => display error, return null
+       #   nullable Int, Object => return nullable Object
        meth check_conform_multiexpr(stype: MMType, nodes: Collection[PExpr]): MMType
        do
                var node: PExpr = null # candidate node
                for n in nodes do
                        if not check_expr(n) then return null
                        var ntype = n.stype
+                       if stype != null and stype.is_nullable != ntype.is_nullable then
+                               # nullable combinaison: if one of them is nulable, considers that both are
+                               stype = stype.as_nullable
+                               ntype = ntype.as_nullable
+                       end
                        if stype == null or (ntype != null and stype < ntype) then
                                stype = ntype
                                node = n
@@ -554,15 +564,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 +582,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 +606,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)