Merge: Not null types
authorJean Privat <jean@pryen.org>
Wed, 8 Apr 2015 01:01:49 +0000 (08:01 +0700)
committerJean Privat <jean@pryen.org>
Wed, 8 Apr 2015 01:01:49 +0000 (08:01 +0700)
In order to fix #86 and #1238 some preliminary work to solve remaining issues with the type system is needed. This PR is a step toward this goal.

This introduce not-null types, that is a modifier to indicate that a type cannot contain null.
Basically, this new modifier is almost useless because it is the semantic of all the types (except obviously null and nullable things). Except in one case: when one adapts a formal type whose bound is nullable.

Before the PR, the semantic was the following

~~~nit
class A[E: nullable Object]
   fun foo(e: E, o: nullable Object) do
      var o2 = o.as(not null) # the static type of o2 is `Object`
      print o2 # OK
      var e2 = e.as(not null) # the static type of e2 is still `E` because there is no `nullable` to remove
      print e2 # Error: expected Object, got E
   end
end
~~~

Obviously, the issue was not that important because people managed to program complex things in Nit and I do not remember getting some complain about that particular issue. For the rare cases of this unexpected behavior, a workaround was possible: to cast on the non-nullable bound

~~~nit
   var e2 = e.as(Object)
   print e2 # OK
~~~

Nevertheless, the behavior was still buggy since type information was lost and not POLA. Moreover, `!= null` and `or else` did not have a workaround.

So, this PR introduces a special new type-modifier for this case so that everything become sensible.

~~~nit
      var e2 = e.as(not null) # the static type of e2 is now `not null E`
      print e2 # OK
~~~

Moreover, a lot of local refactorisation was done in model.nit and typing.nit to clean and harmonize the code. So that independently of the new notnull modifier, the code is cleaner, some bugs where removed and some small features added, especially the detection of useless `or else`.

Last, but not least, the `not null` thing is only an internal modifier and is not usable as a syntactic type construction (the grammar and the AST is unchanged); `not null` can however be shown to the programmer in messages.

~~~nit
      var e2 = e.as(not null) # the static type of e2 is now `not null E`
      var e3 = e2.as(not null) # << Warning: expression is not null, since it is a `not null E` >>
~~~

I could easily add `not null` as a specific syntactic construction since everything internally is ready. but 1. does this worth it?. 2. I do not want to conflict with #1243 that also change the grammar.
As an example, is it useful to write the following? (currently refused but very easy to add after this PR)

~~~nit
class A[E: nullable Object]
   fun foo(e: not null E): not null E do
      var x = e.to_s # no null pointer exception
      # ...
      return e
   end
end

var a = new A[nullable Int]
var i = a.foo(5)
~~~

Pull-Request: #1244
Reviewed-by: Etienne M. Gagnon <egagnon@j-meg.com>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

73 files changed:
contrib/benitlux/src/benitlux_daily.nit
contrib/pep8analysis/src/flow_analysis/framework.nit
lib/ai/search.nit
lib/github/github_curl.nit
lib/standard/collection/array.nit
src/compiler/abstract_compiler.nit
src/compiler/separate_compiler.nit
src/highlight.nit
src/metrics/detect_covariance.nit
src/metrics/detect_variance_constraints.nit
src/metrics/rta_metrics.nit
src/model/model.nit
src/modelize/modelize_property.nit
src/nitdbg_client.nit
src/nitni/nitni_callbacks.nit
src/platform/app_annotations.nit
src/rapid_type_analysis.nit
src/semantize/typing.nit
src/vm/virtual_machine.nit
tests/base_notnull.nit [new file with mode: 0644]
tests/base_notnull_lit.nit [new file with mode: 0644]
tests/sav/base_as_notnull.res
tests/sav/base_as_notnull2.res
tests/sav/base_as_notnull2_alt1.res
tests/sav/base_as_notnull2_alt2.res
tests/sav/base_as_notnull2_alt3.res
tests/sav/base_as_notnull_alt1.res
tests/sav/base_as_notnull_alt2.res
tests/sav/base_as_notnull_alt3.res
tests/sav/base_as_notnull_alt4.res
tests/sav/base_as_notnull_alt5.res
tests/sav/base_as_notnull_alt6.res
tests/sav/base_as_notnull_alt7.res
tests/sav/base_as_notnull_int.res
tests/sav/base_eq_null_notnull.res
tests/sav/base_notnull.res [new file with mode: 0644]
tests/sav/base_notnull_1alt1.res [new file with mode: 0644]
tests/sav/base_notnull_1alt1_alt1.res [new file with mode: 0644]
tests/sav/base_notnull_1alt1_alt2.res [new file with mode: 0644]
tests/sav/base_notnull_1alt1_alt3.res [new file with mode: 0644]
tests/sav/base_notnull_1alt1_alt4.res [new file with mode: 0644]
tests/sav/base_notnull_alt1.res [new file with mode: 0644]
tests/sav/base_notnull_alt2.res [new file with mode: 0644]
tests/sav/base_notnull_alt3.res [new file with mode: 0644]
tests/sav/base_notnull_alt4.res [new file with mode: 0644]
tests/sav/base_notnull_lit.res [new file with mode: 0644]
tests/sav/base_notnull_lit_alt1.res [new file with mode: 0644]
tests/sav/base_notnull_lit_alt2.res [new file with mode: 0644]
tests/sav/base_null.res
tests/sav/base_upcast2_1alt1_alt10.res
tests/sav/base_upcast2_1alt1_alt7.res
tests/sav/base_upcast2_1alt1_alt8.res
tests/sav/base_upcast2_1alt1_alt9.res
tests/sav/base_upcast2_1alt2_alt10.res
tests/sav/base_upcast2_1alt2_alt6.res
tests/sav/base_upcast2_1alt2_alt8.res
tests/sav/base_upcast2_1alt2_alt9.res
tests/sav/base_upcast2_1alt3_alt10.res
tests/sav/base_upcast2_1alt3_alt7.res
tests/sav/base_upcast2_1alt3_alt9.res
tests/sav/base_upcast2_1alt4_alt10.res
tests/sav/base_upcast2_1alt4_alt7.res
tests/sav/base_upcast2_1alt4_alt8.res
tests/sav/base_upcast2_1alt5_alt7.res
tests/sav/base_upcast2_1alt5_alt8.res
tests/sav/base_var_type_evolution_null3.res
tests/sav/base_var_type_evolution_null3_alt1.res
tests/sav/base_virtual_type_self_alt5.res
tests/sav/error_expr_not_ok_alt4.res
tests/sav/error_expr_not_ok_alt5.res
tests/sav/error_expr_not_ok_alt6.res
tests/sav/nitg-e/base_notnull_lit.res [new file with mode: 0644]
tests/sav/test_new_native_alt1.res

index 35aa64c..bb6d1fa 100644 (file)
@@ -230,11 +230,11 @@ if not opts.errors.is_empty or opts.help.value == true then
 end
 
 var ben = new Benitlux("sherbrooke")
-ben.run(opts.send_emails.value or else false)
+ben.run(opts.send_emails.value)
 
 # The parsing logic for the wellington locaiton is active (to gather data)
 # but the web interface do not allow to subscribe to its mailing list.
 #
 # TODO revamp mailing list Web interface
 ben = new Benitlux("wellington")
-ben.run(opts.send_emails.value or else false)
+ben.run(opts.send_emails.value)
index e32246c..338836b 100644 (file)
@@ -52,7 +52,7 @@ class FlowAnalysis[S]
                        end
 
                        if current_in != null then
-                               in_set(block) = current_in.as(not null)
+                               in_set(block) = current_in
                        else
                                continue
                        end
@@ -61,7 +61,7 @@ class FlowAnalysis[S]
 
                        var old_out = out_set(block)
                        for line in block.lines do
-                               self.current_in = current_in.as(not null)
+                               self.current_in = current_in
                                self.current_out = empty_set
                                pre_line_visit(line)
                                enter_visit(line)
index 69b5c0d..f406949 100644 (file)
@@ -731,7 +731,7 @@ class SearchNode[S: Object, A]
                print "result:{state}"
                for n in path do
                        var a = n.action
-                       if a != null then print "    + {a or else ""}"
+                       if a != null then print "    + {a}"
                        print "  {n.steps}: {n.state} ({n.cost}$)"
                end
        end
index cc12923..8e70600 100644 (file)
@@ -82,7 +82,7 @@ class GithubCurl
                        if obj isa JsonObject then
                                if obj.keys.has("message") then
                                        var title = "GithubAPIError"
-                                       var msg = obj["message"].to_s or else ""
+                                       var msg = obj["message"].to_s
                                        var err = new GithubError(msg, title)
                                        err.json["requested_uri"] = uri
                                        err.json["status_code"] = response.status_code
index 233621e..3cc0b57 100644 (file)
@@ -13,7 +13,9 @@
 
 # This module introduces the standard array structure.
 # It also implements two other abstract collections : ArrayMap and ArraySet
-module array
+module array is
+       no_warning "useless-type-test" # to avoid warning with nitc while compiling with c_src
+end
 
 import abstract_collection
 
index 894a13d..3956744 100644 (file)
@@ -2370,7 +2370,7 @@ redef class AAttrPropdef
                var oldnode = v.current_node
                v.current_node = self
                var old_frame = v.frame
-               var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.as(MClassType), [recv])
+               var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
                v.frame = frame
 
                var value
index dab4a79..34e7be4 100644 (file)
@@ -458,14 +458,14 @@ class SeparateCompiler
 
                var mtypes_by_class = new MultiHashMap[MClass, MType]
                for e in mtypes do
-                       var c = e.as_notnullable.as(MClassType).mclass
+                       var c = e.undecorate.as(MClassType).mclass
                        mtypes_by_class[c].add(e)
                        poset.add_node(e)
                end
 
                var casttypes_by_class = new MultiHashMap[MClass, MType]
                for e in cast_types do
-                       var c = e.as_notnullable.as(MClassType).mclass
+                       var c = e.undecorate.as(MClassType).mclass
                        casttypes_by_class[c].add(e)
                        poset.add_node(e)
                end
@@ -510,7 +510,7 @@ class SeparateCompiler
                # Group cast_type by their classes
                var bucklets = new HashMap[MClass, Set[MType]]
                for e in cast_types do
-                       var c = e.as_notnullable.as(MClassType).mclass
+                       var c = e.undecorate.as(MClassType).mclass
                        if not bucklets.has_key(c) then
                                bucklets[c] = new HashSet[MType]
                        end
@@ -742,7 +742,7 @@ class SeparateCompiler
 
                # resolution table (for receiver)
                if is_live then
-                       var mclass_type = mtype.as_notnullable
+                       var mclass_type = mtype.undecorate
                        assert mclass_type isa MClassType
                        if resolution_tables[mclass_type].is_empty then
                                v.add_decl("NULL, /*NO RESOLUTIONS*/")
@@ -775,7 +775,7 @@ class SeparateCompiler
 
        fun compile_type_resolution_table(mtype: MType) do
 
-               var mclass_type = mtype.as_notnullable.as(MClassType)
+               var mclass_type = mtype.undecorate.as(MClassType)
 
                # extern const struct resolution_table_X resolution_table_X
                self.provide_declaration("resolution_table_{mtype.c_name}", "extern const struct types resolution_table_{mtype.c_name};")
@@ -2006,7 +2006,7 @@ class SeparateCompilerVisitor
 
        fun can_be_primitive(value: RuntimeVariable): Bool
        do
-               var t = value.mcasttype.as_notnullable
+               var t = value.mcasttype.undecorate
                if not t isa MClassType then return false
                var k = t.mclass.kind
                return k == interface_kind or t.is_c_primitive
index ecc4c7d..39a042a 100644 (file)
@@ -510,6 +510,33 @@ redef class MNullableType
        end
 end
 
+redef class MNotNullType
+       redef fun infobox(v)
+       do
+               return mtype.infobox(v)
+       end
+       redef fun linkto
+       do
+               var res = new HTMLTag("span")
+               res.append("not null ").add(mtype.linkto)
+               return res
+       end
+end
+
+redef class MNullType
+       redef fun infobox(v)
+       do
+               var res = new HInfoBox(v, to_s)
+               return res
+       end
+       redef fun linkto
+       do
+               var res = new HTMLTag("span")
+               res.append("null")
+               return res
+       end
+end
+
 redef class MSignature
        redef fun linkto
        do
@@ -870,8 +897,8 @@ redef class AType
        do
                var mt = mtype
                if mt == null then return null
-               mt = mt.as_notnullable
-               if mt isa MVirtualType or mt isa MParameterType then
+               mt = mt.undecorate
+               if mt isa MFormalType then
                        res.add_class("nc_vt")
                end
                return mt.infobox(v)
index dd7c36d..9090658 100644 (file)
@@ -130,8 +130,8 @@ private class DetectCovariancePhase
        # Returns true if the test concern real generic covariance
        fun count_types(node, elem: ANode, sub, sup: MType, mmodule: MModule, anchor: nullable MClassType): Bool
        do
-               sub = sub.as_notnullable
-               sup = sup.as_notnullable
+               sub = sub.undecorate
+               sup = sup.undecorate
 
                # Category of the target type
                if sub isa MGenericType then
@@ -254,8 +254,8 @@ private class DetectCovariancePhase
        fun count_cast(node: ANode, sub, sup: MType, mmodule: MModule, anchor: nullable MClassType)
        do
                var nsup = sup
-               sup = sup.as_notnullable
-               sub = sub.as_notnullable
+               sup = sup.undecorate
+               sub = sub.undecorate
 
                if sub == nsup then
                        cpt_cast_pattern.inc("monomorphic cast!?!")
@@ -445,7 +445,7 @@ redef class MType
                # Now the case of direct null and nullable is over.
 
                # If `sub` is a formal type, then it is accepted if its bound is accepted
-               while sub isa MParameterType or sub isa MVirtualType do
+               while sub isa MFormalType do
                        #print "3.is {sub} a {sup}?"
 
                        # A unfixed formal type can only accept itself
@@ -469,7 +469,7 @@ redef class MType
                assert sub isa MClassType # It is the only remaining type
 
                # A unfixed formal type can only accept itself
-               if sup isa MParameterType or sup isa MVirtualType then
+               if sup isa MFormalType then
                        return false
                end
 
index 3665376..1f0205e 100644 (file)
@@ -113,7 +113,7 @@ class DetectVarianceConstraints
                                        if pd isa MMethodDef then
                                                # Parameters (contravariant)
                                                for p in pd.msignature.mparameters do
-                                                       var t = p.mtype.as_notnullable
+                                                       var t = p.mtype.undecorate
                                                        if not t.need_anchor then
                                                                # OK
                                                        else if t isa MParameterType then
@@ -129,7 +129,7 @@ class DetectVarianceConstraints
                                                # Return (covariant)
                                                var t = pd.msignature.return_mtype
                                                if t != null and t.need_anchor then
-                                                       t = t.as_notnullable
+                                                       t = t.undecorate
                                                        if t isa MParameterType then
                                                                covar_pt.add(t)
                                                        else if t isa MVirtualType then
@@ -144,7 +144,7 @@ class DetectVarianceConstraints
                                                # Attribute (invariant)
                                                var t = pd.static_mtype
                                                if t != null and t.need_anchor then
-                                                       t = t.as_notnullable
+                                                       t = t.undecorate
                                                        if t isa MParameterType then
                                                                covar_pt.add t
                                                                contravar_pt.add t
@@ -161,7 +161,7 @@ class DetectVarianceConstraints
                                                # Virtual type bound (covariant)
                                                var t = pd.bound
                                                if t != null and t.need_anchor then
-                                                       t = t.as_notnullable
+                                                       t = t.undecorate
                                                        if t isa MParameterType then
                                                                covar_pt.add t
                                                        else if t isa MVirtualType then
@@ -223,7 +223,7 @@ class DetectVarianceConstraints
                        # Process the generic types in a covariant position
                        for c in covar_classes do for i in [0..c.mclass.arity[ do
                                # The type used in the argument
-                               var ta = c.arguments[i].as_notnullable
+                               var ta = c.arguments[i].undecorate
                                # The associated formal parameter
                                var tp = c.mclass.mparameters[i]
 
@@ -259,7 +259,7 @@ class DetectVarianceConstraints
                        # Process the generic types in a contravariant position
                        for c in contravar_classes do for i in [0..c.mclass.arity[ do
                                # The type used in the argument
-                               var ta = c.arguments[i].as_notnullable
+                               var ta = c.arguments[i].undecorate
                                # The associated formal parameter
                                var tp = c.mclass.mparameters[i]
 
index 1527731..00f9d02 100644 (file)
@@ -374,7 +374,7 @@ redef class RapidTypeAnalysis
                super
                tnlc.values.inc(mtype)
 
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                if mtype isa MClassType then
                        cnlc.values.inc(mtype.mclass)
                end
@@ -385,7 +385,7 @@ end
 
 redef class MType
        private fun signature_depth: Int do
-               var mtype = self.as_notnullable
+               var mtype = self.undecorate
                if not mtype isa MGenericType then return 0
 
                var depth = 0
index 1dbedfb..62c3db4 100644 (file)
@@ -708,6 +708,8 @@ abstract class MType
                if sup isa MNullableType then
                        sup_accept_null = true
                        sup = sup.mtype
+               else if sup isa MNotNullType then
+                       sup = sup.mtype
                else if sup isa MNullType then
                        sup_accept_null = true
                end
@@ -715,16 +717,20 @@ abstract class MType
                # Can `sub` provide null or not?
                # Thus we can match with `sup_accept_null`
                # Also discard the nullable marker if it exists
+               var sub_reject_null = false
                if sub isa MNullableType then
                        if not sup_accept_null then return false
                        sub = sub.mtype
+               else if sub isa MNotNullType then
+                       sub_reject_null = true
+                       sub = sub.mtype
                else if sub isa MNullType then
                        return sup_accept_null
                end
                # Now the case of direct null and nullable is over.
 
                # If `sub` is a formal type, then it is accepted if its bound is accepted
-               while sub isa MParameterType or sub isa MVirtualType do
+               while sub isa MFormalType do
                        #print "3.is {sub} a {sup}?"
 
                        # A unfixed formal type can only accept itself
@@ -732,12 +738,16 @@ abstract class MType
 
                        assert anchor != null
                        sub = sub.lookup_bound(mmodule, anchor)
+                       if sub_reject_null then sub = sub.as_notnull
 
                        #print "3.is {sub} a {sup}?"
 
                        # Manage the second layer of null/nullable
                        if sub isa MNullableType then
-                               if not sup_accept_null then return false
+                               if not sup_accept_null and not sub_reject_null then return false
+                               sub = sub.mtype
+                       else if sub isa MNotNullType then
+                               sub_reject_null = true
                                sub = sub.mtype
                        else if sub isa MNullType then
                                return sup_accept_null
@@ -745,10 +755,10 @@ abstract class MType
                end
                #print "4.is {sub} a {sup}? <- no more resolution"
 
-               assert sub isa MClassType # It is the only remaining type
+               assert sub isa MClassType else print "{sub} <? {sub}" # It is the only remaining type
 
                # A unfixed formal type can only accept itself
-               if sup isa MParameterType or sup isa MVirtualType then
+               if sup isa MFormalType then
                        return false
                end
 
@@ -999,16 +1009,25 @@ abstract class MType
                return res
        end
 
-       # Return the not nullable version of the type
-       # Is the type is already not nullable, then self is returned.
+       # Remove the base type of a decorated (proxy) type.
+       # Is the type is not decorated, then self is returned.
        #
-       # Note: this just remove the `nullable` notation, but the result can still contains null.
+       # Most of the time it is used to return the not nullable version of a nullable type.
+       # In this case, this just remove the `nullable` notation, but the result can still contains null.
        # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
-       fun as_notnullable: MType
+       # If you really want to exclude the `null` value, then use `as_notnull`
+       fun undecorate: MType
        do
                return self
        end
 
+       # Returns the not null version of the type.
+       # That is `self` minus the `null` value.
+       #
+       # For most types, this return `self`.
+       # For formal types, this returns a special `MNotNullType`
+       fun as_notnull: MType do return self
+
        private var as_nullable_cache: nullable MType = null
 
 
@@ -1270,9 +1289,19 @@ class MGenericType
        end
 end
 
+# A formal type (either virtual of parametric).
+#
+# The main issue with formal types is that they offer very little information on their own
+# and need a context (anchor and mmodule) to be useful.
+abstract class MFormalType
+       super MType
+
+       redef var as_notnull = new MNotNullType(self) is lazy
+end
+
 # A virtual formal type.
 class MVirtualType
-       super MType
+       super MFormalType
 
        # The property associated with the type.
        # Its the definitions of this property that determine the bound or the virtual type.
@@ -1313,7 +1342,7 @@ class MVirtualType
        redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
-               resolved_receiver = resolved_receiver.as_notnullable
+               resolved_receiver = resolved_receiver.undecorate
                assert resolved_receiver isa MClassType # It is the only remaining type
 
                var prop = lookup_single_definition(mmodule, resolved_receiver)
@@ -1400,7 +1429,7 @@ end
 # Note that parameter types are shared among class refinements.
 # Therefore parameter only have an internal name (see `to_s` for details).
 class MParameterType
-       super MType
+       super MFormalType
 
        # The generic class where the parameter belong
        var mclass: MClass
@@ -1422,7 +1451,7 @@ class MParameterType
        redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
-               resolved_receiver = resolved_receiver.as_notnullable
+               resolved_receiver = resolved_receiver.undecorate
                assert resolved_receiver isa MClassType # It is the only remaining type
                var goalclass = self.mclass
                if resolved_receiver.mclass == goalclass then
@@ -1450,7 +1479,7 @@ class MParameterType
        redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
-               resolved_receiver = resolved_receiver.as_notnullable
+               resolved_receiver = resolved_receiver.undecorate
                assert resolved_receiver isa MClassType # It is the only remaining type
                var res = self.resolve_for(resolved_receiver.mclass.mclass_type, resolved_receiver, mmodule, false)
                return res
@@ -1522,33 +1551,24 @@ class MParameterType
        end
 end
 
-# A type prefixed with "nullable"
-class MNullableType
+# A type that decorates another type.
+#
+# The point of this class is to provide a common implementation of sevices that just forward to the original type.
+# Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
+abstract class MProxyType
        super MType
-
-       # The base type of the nullable type
+       # The base type
        var mtype: MType
 
        redef fun model do return self.mtype.model
-
-       init
-       do
-               self.to_s = "nullable {mtype}"
-       end
-
-       redef var to_s: String is noinit
-
-       redef var full_name is lazy do return "nullable {mtype.full_name}"
-
-       redef var c_name is lazy do return "nullable__{mtype.c_name}"
-
        redef fun need_anchor do return mtype.need_anchor
-       redef fun as_nullable do return self
-       redef fun as_notnullable do return mtype
+       redef fun as_nullable do return mtype.as_nullable
+       redef fun as_notnull do return mtype.as_notnull
+       redef fun undecorate do return mtype.undecorate
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
        do
                var res = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
-               return res.as_nullable
+               return res
        end
 
        redef fun can_resolve_for(mtype, anchor, mmodule)
@@ -1556,12 +1576,10 @@ class MNullableType
                return self.mtype.can_resolve_for(mtype, anchor, mmodule)
        end
 
-       # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
        redef fun lookup_fixed(mmodule, resolved_receiver)
        do
                var t = mtype.lookup_fixed(mmodule, resolved_receiver)
-               if t == mtype then return self
-               return t.as_nullable
+               return t
        end
 
        redef fun depth do return self.mtype.depth
@@ -1587,6 +1605,64 @@ class MNullableType
        end
 end
 
+# A type prefixed with "nullable"
+class MNullableType
+       super MProxyType
+
+       init
+       do
+               self.to_s = "nullable {mtype}"
+       end
+
+       redef var to_s: String is noinit
+
+       redef var full_name is lazy do return "nullable {mtype.full_name}"
+
+       redef var c_name is lazy do return "nullable__{mtype.c_name}"
+
+       redef fun as_nullable do return self
+       redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
+       do
+               var res = super
+               return res.as_nullable
+       end
+
+       # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
+       redef fun lookup_fixed(mmodule, resolved_receiver)
+       do
+               var t = super
+               if t == mtype then return self
+               return t.as_nullable
+       end
+end
+
+# A non-null version of a formal type.
+#
+# When a formal type in bounded to a nullable type, this is the type of the not null version of it.
+class MNotNullType
+       super MProxyType
+
+       redef fun to_s do return "not null {mtype}"
+       redef var full_name is lazy do return "not null {mtype.full_name}"
+       redef var c_name is lazy do return "notnull__{mtype.c_name}"
+
+       redef fun as_notnull do return self
+
+       redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
+       do
+               var res = super
+               return res.as_notnull
+       end
+
+       # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull`
+       redef fun lookup_fixed(mmodule, resolved_receiver)
+       do
+               var t = super
+               if t == mtype then return self
+               return t.as_notnull
+       end
+end
+
 # The type of the only value null
 #
 # The is only one null type per model, see `MModel::null_type`.
@@ -1597,6 +1673,9 @@ class MNullType
        redef fun full_name do return "null"
        redef fun c_name do return "null"
        redef fun as_nullable do return self
+
+       # Aborts on `null`
+       redef fun as_notnull do abort # sorry...
        redef fun need_anchor do return false
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self
        redef fun can_resolve_for(mtype, anchor, mmodule) do return true
@@ -1819,7 +1898,7 @@ abstract class MProperty
        fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
                assert not mtype.need_anchor
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
 
                var cache = self.lookup_definitions_cache[mmodule, mtype]
                if cache != null then return cache
@@ -1859,7 +1938,7 @@ abstract class MProperty
        fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
                assert not mtype.need_anchor
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
 
                # First, select all candidates
                var candidates = new Array[MPROPDEF]
@@ -1937,7 +2016,7 @@ abstract class MProperty
        # REQUIRE: `mtype.has_mproperty(mmodule, self)`
        fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
 
                var cache = self.lookup_all_definitions_cache[mmodule, mtype]
                if cache != null then return cache
index cd98915..c224b29 100644 (file)
@@ -370,7 +370,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 original module of the type
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                if mtype isa MClassType then
                        vis_type = mtype.mclass.visibility
                        mmodule_type = mtype.mclass.intro.mmodule
index 349f53c..b12e1e9 100644 (file)
@@ -81,7 +81,7 @@ else
 end
 
 print "[HOST ADDRESS] : {debug.address}"
-print "[HOST] : {debug.host or else "unamed"}"
+print "[HOST] : {debug.host}"
 print "[PORT] : {debug.port}"
 print "Connecting ... {debug.connected}"
 
index f53466c..210a4b5 100644 (file)
@@ -111,7 +111,7 @@ redef class AMethPropdef
                # return type
                var rmt = mpropdef.msignature.return_mtype
                if rmt != null then
-                       if rmt isa MParameterType or rmt isa MVirtualType then
+                       if rmt isa MFormalType then
                                var mclass_type = mpropdef.mclassdef.bound_mtype
                                rmt = rmt.anchor_to(mmodule, mclass_type)
                        end
@@ -122,7 +122,7 @@ redef class AMethPropdef
                # params
                for p in mpropdef.msignature.mparameters do
                        var mtype = p.mtype.resolve_for(recv_type, recv_type, mmodule, true)
-                       if mtype isa MParameterType or mtype isa MVirtualType then
+                       if mtype isa MFormalType then
                                var mclass_type = mpropdef.mclassdef.bound_mtype
                                mtype = mtype.anchor_to(mmodule, mclass_type)
                        end
@@ -308,7 +308,7 @@ redef class AFullPropExternCall
 
                if mtype == null then return
 
-               if mtype isa MParameterType or mtype isa MVirtualType then
+               if mtype isa MFormalType then
                        mtype = mtype.anchor_to(mmodule, mclass_type)
                end
 
@@ -422,7 +422,7 @@ redef class AAsNotNullableExternCall
        redef fun from_mtype do return n_type.mtype.as_nullable
        redef fun to_mtype do
                var mtype = n_type.mtype.as(not null)
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                return mtype
        end
 
index ab0b067..67af354 100644 (file)
@@ -68,9 +68,9 @@ class AppProject
        end
 
        redef fun to_s do return """
-name: {{{name or else "null"}}}
-namespace: {{{namespace or else "null"}}}
-version: {{{version or else "null"}}}"""
+name: {{{name}}}
+namespace: {{{namespace}}}
+version: {{{version}}}"""
 end
 
 redef class AAnnotation
index 69e9023..73cc176 100644 (file)
@@ -93,7 +93,7 @@ class RapidTypeAnalysis
                var mtype = callsite.recv
                var anchor = callsite.anchor
                if anchor != null then mtype = mtype.anchor_to(callsite.mmodule, anchor)
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                if mtype isa MClassType then mtype = mtype.mclass.intro.bound_mtype
                var mproperty = callsite.mproperty
                var res = live_targets_cache[mtype, mproperty]
@@ -465,7 +465,7 @@ class RapidTypeVisitor
        do
                mtype = mtype.anchor_to(self.analysis.mainmodule, self.receiver)
                if mtype isa MNullType then return null
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                assert mtype isa MClassType
                assert not mtype.need_anchor
                return mtype
index 8e9e3ac..38a689a 100644 (file)
@@ -115,7 +115,12 @@ private class TypeVisitor
                        #node.debug("Unsafe typing: expected {sup}, got {sub}")
                        return sup
                end
-               self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}")
+               if sub.need_anchor then
+                       var u = anchor_to(sub)
+                       self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}: {u}")
+               else
+                       self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}")
+               end
                return null
        end
 
@@ -194,6 +199,34 @@ private class TypeVisitor
                return sup
        end
 
+       # Can `mtype` be null (up to the current knowledge)?
+       fun can_be_null(mtype: MType): Bool
+       do
+               if mtype isa MNullableType or mtype isa MNullType then return true
+               if mtype isa MFormalType then
+                       var x = anchor_to(mtype)
+                       if x isa MNullableType or x isa MNullType then return true
+               end
+               return false
+       end
+
+       # Check that `mtype` can be null (up to the current knowledge).
+       #
+       # If not then display a `useless-null-test` warning on node and return false.
+       # Else return true.
+       fun check_can_be_null(anode: ANode, mtype: MType): Bool
+       do
+               if can_be_null(mtype) then return true
+
+               if mtype isa MFormalType then
+                       var res = anchor_to(mtype)
+                       modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}: {res}`.")
+               else
+                       modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}`.")
+               end
+               return false
+       end
+
        # Special verification on != and == for null
        # Return true
        fun null_test(anode: ABinopExpr)
@@ -205,24 +238,24 @@ private class TypeVisitor
 
                if not mtype2 isa MNullType then return
 
+               if mtype isa MNullType then return
+
                # Check of useless null
-               if not mtype isa MNullableType then
-                       if not anchor_to(mtype) isa MNullableType then
-                               modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}`.")
-                       end
-                       return
-               end
+               if not check_can_be_null(anode.n_expr, mtype) then return
+
+               mtype = mtype.as_notnull
 
                # Check for type adaptation
                var variable = anode.n_expr.its_variable
                if variable == null then return
 
+               # One is null (mtype2 see above) the other is not null
                if anode isa AEqExpr then
                        anode.after_flow_context.when_true.set_var(variable, mtype2)
-                       anode.after_flow_context.when_false.set_var(variable, mtype.mtype)
+                       anode.after_flow_context.when_false.set_var(variable, mtype)
                else if anode isa ANeExpr then
                        anode.after_flow_context.when_false.set_var(variable, mtype2)
-                       anode.after_flow_context.when_true.set_var(variable, mtype.mtype)
+                       anode.after_flow_context.when_true.set_var(variable, mtype)
                else
                        abort
                end
@@ -334,7 +367,7 @@ private class TypeVisitor
                var erasure_cast = false
                var rettype = mpropdef.msignature.return_mtype
                if not recv_is_self and rettype != null then
-                       rettype = rettype.as_notnullable
+                       rettype = rettype.undecorate
                        if rettype isa MParameterType then
                                var erased_rettype = msignature.return_mtype
                                assert erased_rettype != null
@@ -450,7 +483,7 @@ private class TypeVisitor
                        var found = true
                        for t2 in col do
                                if t2 == null then continue # return null
-                               if t2 isa MNullableType or t2 isa MNullType then
+                               if can_be_null(t2) and not can_be_null(t1) then
                                        t1 = t1.as_nullable
                                end
                                if not is_subtype(t2, t1) then found = false
@@ -1010,7 +1043,7 @@ redef class AForExpr
                # anchor formal and virtual types
                if mtype.need_anchor then mtype = v.anchor_to(mtype)
 
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                self.coltype = mtype.as(MClassType)
 
                # get methods is_ok, next, item
@@ -1129,14 +1162,18 @@ redef class AOrElseExpr
                        return # Skip error
                end
 
-               t1 = t1.as_notnullable
+               if t1 isa MNullType then
+                       v.error(n_expr, "Type error: or else on null")
+               else if v.check_can_be_null(n_expr, t1) then
+                       t1 = t1.as_notnull
+               end
 
                var t = v.merge_types(self, [t1, t2])
                if t == null then
                        var c = v.get_mclass(self, "Object")
                        if c == null then return # forward error
                        t = c.mclass_type
-                       if t2 isa MNullableType then
+                       if v.can_be_null(t2) then
                                t = t.as_nullable
                        end
                        #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
@@ -1368,22 +1405,12 @@ redef class AAsNotnullExpr
                        v.error(self, "Type error: as(not null) on null")
                        return
                end
-               if mtype isa MNullableType then
-                       self.mtype = mtype.mtype
-                       return
-               end
-               self.mtype = mtype
 
-               if mtype isa MClassType then
-                       v.modelbuilder.warning(self, "useless-type-test", "Warning: expression is already not null, since it is a `{mtype}`.")
-                       return
-               end
-               assert mtype.need_anchor
-               var u = v.anchor_to(mtype)
-               if not u isa MNullableType then
-                       v.modelbuilder.warning(self, "useless-type-test", "Warning: expression is already not null, since it is a `{mtype}: {u}`.")
-                       return
+               if v.check_can_be_null(n_expr, mtype) then
+                       mtype = mtype.as_notnull
                end
+
+               self.mtype = mtype
        end
 end
 
index b33e7f8..9c3d516 100644 (file)
@@ -61,10 +61,10 @@ class VirtualMachine super NaiveInterpreter
                var anchor = self.frame.arguments.first.mtype.as(MClassType)
 
                # `sub` or `sup` are formal or virtual types, resolve them to concrete types
-               if sub isa MParameterType or sub isa MVirtualType then
+               if sub isa MFormalType then
                        sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mainmodule, false)
                end
-               if sup isa MParameterType or sup isa MVirtualType then
+               if sup isa MFormalType then
                        sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mainmodule, false)
                end
 
@@ -87,7 +87,7 @@ class VirtualMachine super NaiveInterpreter
                end
                # Now the case of direct null and nullable is over
 
-               if sub isa MParameterType or sub isa MVirtualType then
+               if sub isa MFormalType then
                        sub = sub.anchor_to(mainmodule, anchor)
                        # Manage the second layer of null/nullable
                        if sub isa MNullableType then
diff --git a/tests/base_notnull.nit b/tests/base_notnull.nit
new file mode 100644 (file)
index 0000000..133aef1
--- /dev/null
@@ -0,0 +1,43 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import standard::kernel
+
+class A[E] #alt2# class A[E: Object]
+       type V: nullable Object #alt2# type V: Object
+
+       fun foo(e: E, v: E) do #1alt1# fun foo(e: nullable E, v: nullable E) do
+               assert e != null#alt1# #alt3# assert e == null #alt4# if false then e = null
+               assert v != null#alt1# #alt3# assert v == null #alt4# if false then e = null
+               bar(e)
+               bar(v)
+               if e != null then
+                       bar(e)
+               else bar(e)
+               if v != null then
+                       bar(v)
+               else bar(v)
+               bar(e.as(not null))
+               bar(v.as(not null))
+               bar(e or else 0)
+               bar(v or else 0)
+               bar(e or else v)
+               bar(v or else e)
+       end
+
+       fun bar(o: Object) do o.output
+end
+
+var a = new A[Object]
+a.foo (1, 2)
diff --git a/tests/base_notnull_lit.nit b/tests/base_notnull_lit.nit
new file mode 100644 (file)
index 0000000..dae4e46
--- /dev/null
@@ -0,0 +1,40 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class A[E: nullable Discrete]
+       fun array(e, f: E): Object
+       do
+               assert e != null
+               assert f != null #alt1# #alt2# assert f == null
+               return [e, f]
+       end
+
+       fun range(e, f: E): Object
+       do
+               assert e != null
+               assert f != null #alt1#
+               return [e..f]
+       end
+end
+
+var a = new A[nullable Int]
+
+var ar = a.array(1, 5)
+ar.output_class_name
+ar.as(Array[Int]).add 6
+print ar
+
+var ra = a.range(1, 5)
+ra.output_class_name
+print ra
index 2380a43..2324342 100644 (file)
@@ -1,7 +1,7 @@
-base_as_notnull.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-base_as_notnull.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-base_as_notnull.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-base_as_notnull.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+base_as_notnull.nit:41,6: Warning: expression is not null, since it is a `A`.
+base_as_notnull.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+base_as_notnull.nit:43,6: Warning: expression is not null, since it is a `B`.
+base_as_notnull.nit:52,6: Warning: expression is not null, since it is a `B`.
 1
 2
 3
index b0818df..1962743 100644 (file)
@@ -1,5 +1,5 @@
-base_as_notnull2.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
-base_as_notnull2.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
+base_as_notnull2.nit:30,12: Warning: expression is not null, since it is a `Object`.
+base_as_notnull2.nit:50,12: Warning: expression is not null, since it is a `F: Object`.
 1
 1
 2
index 01ee624..b61957e 100644 (file)
@@ -1,3 +1,3 @@
-alt/base_as_notnull2_alt1.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
-alt/base_as_notnull2_alt1.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
+alt/base_as_notnull2_alt1.nit:30,12: Warning: expression is not null, since it is a `Object`.
+alt/base_as_notnull2_alt1.nit:50,12: Warning: expression is not null, since it is a `F: Object`.
 alt/base_as_notnull2_alt1.nit:58,7--10: Type error: expected Object, got null
index e6335c5..4ac9e4e 100644 (file)
@@ -1,5 +1,5 @@
-alt/base_as_notnull2_alt2.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
-alt/base_as_notnull2_alt2.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
+alt/base_as_notnull2_alt2.nit:30,12: Warning: expression is not null, since it is a `Object`.
+alt/base_as_notnull2_alt2.nit:50,12: Warning: expression is not null, since it is a `F: Object`.
 Runtime error: Cast failed (alt/base_as_notnull2_alt2.nit:40)
 1
 1
index 4fb6e73..4a57748 100644 (file)
@@ -1,3 +1,3 @@
-alt/base_as_notnull2_alt3.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
-alt/base_as_notnull2_alt3.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
+alt/base_as_notnull2_alt3.nit:30,12: Warning: expression is not null, since it is a `Object`.
+alt/base_as_notnull2_alt3.nit:50,12: Warning: expression is not null, since it is a `F: Object`.
 alt/base_as_notnull2_alt3.nit:64,7--10: Type error: expected Int, got null
index ad6b798..cbb18f8 100644 (file)
@@ -1,6 +1,6 @@
-alt/base_as_notnull_alt1.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt1.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt1.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt1.nit:50,6--19: Warning: expression is already not null, since it is a `A`.
+alt/base_as_notnull_alt1.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt1.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt1.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt1.nit:50,6: Warning: expression is not null, since it is a `A`.
 alt/base_as_notnull_alt1.nit:50,6--19: Type error: expected B, got A
-alt/base_as_notnull_alt1.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt1.nit:52,6: Warning: expression is not null, since it is a `B`.
index 0e0e68c..c9dfed9 100644 (file)
@@ -1,6 +1,6 @@
-alt/base_as_notnull_alt2.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt2.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt2.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt2.nit:51,6--20: Warning: expression is already not null, since it is a `A`.
+alt/base_as_notnull_alt2.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt2.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt2.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt2.nit:51,6--7: Warning: expression is not null, since it is a `A`.
 alt/base_as_notnull_alt2.nit:51,6--20: Type error: expected B, got A
-alt/base_as_notnull_alt2.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt2.nit:52,6: Warning: expression is not null, since it is a `B`.
index bd83530..d66632f 100644 (file)
@@ -1,5 +1,5 @@
-alt/base_as_notnull_alt3.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt3.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt3.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt3.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt3.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt3.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt3.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt3.nit:52,6: Warning: expression is not null, since it is a `B`.
 alt/base_as_notnull_alt3.nit:53,6--20: Type error: expected B, got A
index 0050108..b25242f 100644 (file)
@@ -1,5 +1,5 @@
-alt/base_as_notnull_alt4.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt4.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt4.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt4.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt4.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt4.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt4.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt4.nit:52,6: Warning: expression is not null, since it is a `B`.
 alt/base_as_notnull_alt4.nit:54,6--21: Type error: expected B, got A
index d8136e9..b52a40b 100644 (file)
@@ -1,7 +1,7 @@
-alt/base_as_notnull_alt5.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt5.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt5.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt5.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt5.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt5.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt5.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt5.nit:52,6: Warning: expression is not null, since it is a `B`.
 Runtime error: Cast failed (alt/base_as_notnull_alt5.nit:59)
 1
 2
index 7083fa3..518f166 100644 (file)
@@ -1,7 +1,7 @@
-alt/base_as_notnull_alt6.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt6.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt6.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt6.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt6.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt6.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt6.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt6.nit:52,6: Warning: expression is not null, since it is a `B`.
 Runtime error: Cast failed (alt/base_as_notnull_alt6.nit:60)
 1
 2
index 38f0903..6ad88ec 100644 (file)
@@ -1,5 +1,5 @@
-alt/base_as_notnull_alt7.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt7.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt7.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt7.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt7.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt7.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt7.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt7.nit:52,6: Warning: expression is not null, since it is a `B`.
 alt/base_as_notnull_alt7.nit:61,1--17: Type error: as(not null) on null
index 4635340..8b381a4 100644 (file)
@@ -1,5 +1,5 @@
-base_as_notnull_int.nit:18,1--14: Warning: expression is already not null, since it is a `Int`.
-base_as_notnull_int.nit:20,1--15: Warning: expression is already not null, since it is a `Object`.
+base_as_notnull_int.nit:18,1: Warning: expression is not null, since it is a `Int`.
+base_as_notnull_int.nit:20,1--2: Warning: expression is not null, since it is a `Object`.
 1
 1
 1
index b4226bc..faf4840 100644 (file)
@@ -1,5 +1,5 @@
-base_eq_null_notnull.nit:36,6--14: Warning: expression is not null, since it is a `A`.
-base_eq_null_notnull.nit:43,2--10: Warning: expression is not null, since it is a `A`.
+base_eq_null_notnull.nit:36,6: Warning: expression is not null, since it is a `A`.
+base_eq_null_notnull.nit:43,2: Warning: expression is not null, since it is a `A`.
 true
 true
 true
diff --git a/tests/sav/base_notnull.res b/tests/sav/base_notnull.res
new file mode 100644 (file)
index 0000000..1b755df
--- /dev/null
@@ -0,0 +1,18 @@
+base_notnull.nit:25,6: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:28,6: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:31,7: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:32,7: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:33,7: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:34,7: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:35,7: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:36,7: Warning: expression is not null, since it is a `not null E`.
+1
+2
+1
+2
+1
+2
+1
+2
+1
+2
diff --git a/tests/sav/base_notnull_1alt1.res b/tests/sav/base_notnull_1alt1.res
new file mode 100644 (file)
index 0000000..925e389
--- /dev/null
@@ -0,0 +1,18 @@
+alt/base_notnull_1alt1.nit:25,6: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:28,6: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:31,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:32,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:33,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:34,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:35,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:36,7: Warning: expression is not null, since it is a `not null E`.
+1
+2
+1
+2
+1
+2
+1
+2
+1
+2
diff --git a/tests/sav/base_notnull_1alt1_alt1.res b/tests/sav/base_notnull_1alt1_alt1.res
new file mode 100644 (file)
index 0000000..8a63507
--- /dev/null
@@ -0,0 +1,6 @@
+alt/base_notnull_1alt1_alt1.nit:23,7: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt1.nit:24,7: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt1.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt1.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt1.nit:35,7--17: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt1.nit:36,7--17: Type error: expected Object, got nullable E: nullable Object
diff --git a/tests/sav/base_notnull_1alt1_alt2.res b/tests/sav/base_notnull_1alt1_alt2.res
new file mode 100644 (file)
index 0000000..a316b82
--- /dev/null
@@ -0,0 +1,18 @@
+alt/base_notnull_1alt1_alt2.nit:25,6: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:28,6: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:31,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:32,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:33,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:34,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:35,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:36,7: Warning: expression is not null, since it is a `not null E`.
+1
+2
+1
+2
+1
+2
+1
+2
+1
+2
diff --git a/tests/sav/base_notnull_1alt1_alt3.res b/tests/sav/base_notnull_1alt1_alt3.res
new file mode 100644 (file)
index 0000000..d044957
--- /dev/null
@@ -0,0 +1,16 @@
+alt/base_notnull_1alt1_alt3.nit:23,7: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:24,7: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:26,8: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:29,8: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:31,7--20: Type error: as(not null) on null
+alt/base_notnull_1alt1_alt3.nit:32,7--20: Type error: as(not null) on null
+alt/base_notnull_1alt1_alt3.nit:33,7: Type error: or else on null
+alt/base_notnull_1alt1_alt3.nit:33,7--17: Type error: expected Object, got nullable Int
+alt/base_notnull_1alt1_alt3.nit:34,7: Type error: or else on null
+alt/base_notnull_1alt1_alt3.nit:34,7--17: Type error: expected Object, got nullable Int
+alt/base_notnull_1alt1_alt3.nit:35,7: Type error: or else on null
+alt/base_notnull_1alt1_alt3.nit:35,7--17: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:36,7: Type error: or else on null
+alt/base_notnull_1alt1_alt3.nit:36,7--17: Type error: expected Object, got null
diff --git a/tests/sav/base_notnull_1alt1_alt4.res b/tests/sav/base_notnull_1alt1_alt4.res
new file mode 100644 (file)
index 0000000..b0f0ecd
--- /dev/null
@@ -0,0 +1,6 @@
+alt/base_notnull_1alt1_alt4.nit:23,7: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt4.nit:24,7: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt4.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt4.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt4.nit:35,7--17: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt4.nit:36,7--17: Type error: expected Object, got nullable E: nullable Object
diff --git a/tests/sav/base_notnull_alt1.res b/tests/sav/base_notnull_alt1.res
new file mode 100644 (file)
index 0000000..4a50aa8
--- /dev/null
@@ -0,0 +1,6 @@
+alt/base_notnull_alt1.nit:23,7: Type error: expected Object, got E: nullable Object
+alt/base_notnull_alt1.nit:24,7: Type error: expected Object, got E: nullable Object
+alt/base_notnull_alt1.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_alt1.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_alt1.nit:35,7--17: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_alt1.nit:36,7--17: Type error: expected Object, got nullable E: nullable Object
diff --git a/tests/sav/base_notnull_alt2.res b/tests/sav/base_notnull_alt2.res
new file mode 100644 (file)
index 0000000..9450e83
--- /dev/null
@@ -0,0 +1,20 @@
+alt/base_notnull_alt2.nit:21,10: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:22,10: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:25,6: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:28,6: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:31,7: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:32,7: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:33,7: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:34,7: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:35,7: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:36,7: Warning: expression is not null, since it is a `E: Object`.
+1
+2
+1
+2
+1
+2
+1
+2
+1
+2
diff --git a/tests/sav/base_notnull_alt3.res b/tests/sav/base_notnull_alt3.res
new file mode 100644 (file)
index 0000000..addd582
--- /dev/null
@@ -0,0 +1,16 @@
+alt/base_notnull_alt3.nit:23,7: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:24,7: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:26,8: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:29,8: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:31,7--20: Type error: as(not null) on null
+alt/base_notnull_alt3.nit:32,7--20: Type error: as(not null) on null
+alt/base_notnull_alt3.nit:33,7: Type error: or else on null
+alt/base_notnull_alt3.nit:33,7--17: Type error: expected Object, got nullable Int
+alt/base_notnull_alt3.nit:34,7: Type error: or else on null
+alt/base_notnull_alt3.nit:34,7--17: Type error: expected Object, got nullable Int
+alt/base_notnull_alt3.nit:35,7: Type error: or else on null
+alt/base_notnull_alt3.nit:35,7--17: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:36,7: Type error: or else on null
+alt/base_notnull_alt3.nit:36,7--17: Type error: expected Object, got null
diff --git a/tests/sav/base_notnull_alt4.res b/tests/sav/base_notnull_alt4.res
new file mode 100644 (file)
index 0000000..d0db7c3
--- /dev/null
@@ -0,0 +1,6 @@
+alt/base_notnull_alt4.nit:23,7: Type error: expected Object, got E: nullable Object
+alt/base_notnull_alt4.nit:24,7: Type error: expected Object, got E: nullable Object
+alt/base_notnull_alt4.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_alt4.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_alt4.nit:35,7--17: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_alt4.nit:36,7--17: Type error: expected Object, got nullable E: nullable Object
diff --git a/tests/sav/base_notnull_lit.res b/tests/sav/base_notnull_lit.res
new file mode 100644 (file)
index 0000000..dc19389
--- /dev/null
@@ -0,0 +1,4 @@
+Array[Int]
+156
+Range[Int]
+12345
diff --git a/tests/sav/base_notnull_lit_alt1.res b/tests/sav/base_notnull_lit_alt1.res
new file mode 100644 (file)
index 0000000..fac195d
--- /dev/null
@@ -0,0 +1 @@
+alt/base_notnull_lit_alt1.nit:27,14: Type error: expected Discrete, got E: nullable Discrete
diff --git a/tests/sav/base_notnull_lit_alt2.res b/tests/sav/base_notnull_lit_alt2.res
new file mode 100644 (file)
index 0000000..522489c
--- /dev/null
@@ -0,0 +1 @@
+Runtime error: Assert failed (alt/base_notnull_lit_alt2.nit:19)
index 80acf2a..814a7ef 100644 (file)
@@ -1,5 +1,3 @@
-base_null.nit:28,2--13: Warning: expression is not null, since it is a `null`.
-base_null.nit:42,2--13: Warning: expression is not null, since it is a `null`.
 false
 false
 true
index 99abb44..28f095a 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt1_alt10.nit:36,21: Type error: expected C, got T
+alt/base_upcast2_1alt1_alt10.nit:36,21: Type error: expected C, got T: A[Int]
index 29fe46d..15ba7c3 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt1_alt7.nit:33,22: Type error: expected A[Bool], got T
+alt/base_upcast2_1alt1_alt7.nit:33,22: Type error: expected A[Bool], got T: A[Int]
index 4f33a48..a7f751c 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt1_alt8.nit:34,22: Type error: expected B[Int], got T
+alt/base_upcast2_1alt1_alt8.nit:34,22: Type error: expected B[Int], got T: A[Int]
index 3191dca..98420d0 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt1_alt9.nit:35,22: Type error: expected B[Bool], got T
+alt/base_upcast2_1alt1_alt9.nit:35,22: Type error: expected B[Bool], got T: A[Int]
index 8d013a7..8ef15ac 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt2_alt10.nit:36,21: Type error: expected C, got T
+alt/base_upcast2_1alt2_alt10.nit:36,21: Type error: expected C, got T: A[Bool]
index afb8ffe..016d020 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt2_alt6.nit:32,22: Type error: expected A[Int], got T
+alt/base_upcast2_1alt2_alt6.nit:32,22: Type error: expected A[Int], got T: A[Bool]
index ab7c7d3..cdbac7a 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt2_alt8.nit:34,22: Type error: expected B[Int], got T
+alt/base_upcast2_1alt2_alt8.nit:34,22: Type error: expected B[Int], got T: A[Bool]
index c687866..2b3c257 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt2_alt9.nit:35,22: Type error: expected B[Bool], got T
+alt/base_upcast2_1alt2_alt9.nit:35,22: Type error: expected B[Bool], got T: A[Bool]
index b64929b..975c3fb 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt3_alt10.nit:36,21: Type error: expected C, got T
+alt/base_upcast2_1alt3_alt10.nit:36,21: Type error: expected C, got T: B[Int]
index b2aeba1..e44436b 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt3_alt7.nit:33,22: Type error: expected A[Bool], got T
+alt/base_upcast2_1alt3_alt7.nit:33,22: Type error: expected A[Bool], got T: B[Int]
index f6151ca..1f17f5f 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt3_alt9.nit:35,22: Type error: expected B[Bool], got T
+alt/base_upcast2_1alt3_alt9.nit:35,22: Type error: expected B[Bool], got T: B[Int]
index 7943796..37d0456 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt4_alt10.nit:36,21: Type error: expected C, got T
+alt/base_upcast2_1alt4_alt10.nit:36,21: Type error: expected C, got T: B[Bool]
index 1ce4304..a9f7c8b 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt4_alt7.nit:33,22: Type error: expected A[Bool], got T
+alt/base_upcast2_1alt4_alt7.nit:33,22: Type error: expected A[Bool], got T: B[Bool]
index a636739..821b826 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt4_alt8.nit:34,22: Type error: expected B[Int], got T
+alt/base_upcast2_1alt4_alt8.nit:34,22: Type error: expected B[Int], got T: B[Bool]
index a670740..9d35793 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt5_alt7.nit:33,22: Type error: expected A[Bool], got T
+alt/base_upcast2_1alt5_alt7.nit:33,22: Type error: expected A[Bool], got T: C
index ce4fd54..5ce490d 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt5_alt8.nit:34,22: Type error: expected B[Int], got T
+alt/base_upcast2_1alt5_alt8.nit:34,22: Type error: expected B[Int], got T: C
index 46069e8..0025f05 100644 (file)
@@ -1,4 +1,4 @@
-base_var_type_evolution_null3.nit:52,5--13: Warning: expression is not null, since it is a `Object`.
+base_var_type_evolution_null3.nit:52,5: Warning: expression is not null, since it is a `Object`.
 1
 1
 5
index a10a5e3..5bc9b2d 100644 (file)
@@ -1,4 +1,4 @@
-alt/base_var_type_evolution_null3_alt1.nit:52,5--13: Warning: expression is not null, since it is a `Object`.
+alt/base_var_type_evolution_null3_alt1.nit:52,5: Warning: expression is not null, since it is a `Object`.
 1
 1
 5
index 397a44a..44a485a 100644 (file)
@@ -1,3 +1,3 @@
 alt/base_virtual_type_self_alt5.nit:44,9: Type error: expected A[U], got Float
-alt/base_virtual_type_self_alt5.nit:45,7--12: Type error: expected Float, got A[U]
-alt/base_virtual_type_self_alt5.nit:47,7--12: Type error: expected Float, got A[A[U]]
+alt/base_virtual_type_self_alt5.nit:45,7--12: Type error: expected Float, got A[U]: A[Int]
+alt/base_virtual_type_self_alt5.nit:47,7--12: Type error: expected Float, got A[A[U]]: A[A[Int]]
index 01f96ed..d22055c 100644 (file)
@@ -106,7 +106,7 @@ alt/error_expr_not_ok_alt4.nit:147,7--18: Type error: expected A, got Array[Int]
 alt/error_expr_not_ok_alt4.nit:149,7--24: Type error: expected A, got String
 alt/error_expr_not_ok_alt4.nit:150,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt4.nit:150,7--18: Type error: expected A, got Int
-alt/error_expr_not_ok_alt4.nit:151,7--23: Warning: expression is already not null, since it is a `Int`.
+alt/error_expr_not_ok_alt4.nit:151,7--10: Warning: expression is not null, since it is a `Int`.
 alt/error_expr_not_ok_alt4.nit:151,7--23: Type error: expected A, got Int
 alt/error_expr_not_ok_alt4.nit:152,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt4.nit:152,7--18: Type error: expected A, got Bool
index 98e1d46..a6caca4 100644 (file)
@@ -101,7 +101,7 @@ alt/error_expr_not_ok_alt5.nit:147,7--18: Type error: expected A, got Array[Int]
 alt/error_expr_not_ok_alt5.nit:149,7--24: Type error: expected A, got String
 alt/error_expr_not_ok_alt5.nit:150,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt5.nit:150,7--18: Type error: expected A, got Int
-alt/error_expr_not_ok_alt5.nit:151,7--23: Warning: expression is already not null, since it is a `Int`.
+alt/error_expr_not_ok_alt5.nit:151,7--10: Warning: expression is not null, since it is a `Int`.
 alt/error_expr_not_ok_alt5.nit:151,7--23: Type error: expected A, got Int
 alt/error_expr_not_ok_alt5.nit:152,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt5.nit:152,7--18: Type error: expected A, got Bool
index efeddc2..c56e7b6 100644 (file)
@@ -105,7 +105,7 @@ alt/error_expr_not_ok_alt6.nit:147,7--18: Type error: expected A, got Array[Int]
 alt/error_expr_not_ok_alt6.nit:149,7--24: Type error: expected A, got String
 alt/error_expr_not_ok_alt6.nit:150,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt6.nit:150,7--18: Type error: expected A, got Int
-alt/error_expr_not_ok_alt6.nit:151,7--23: Warning: expression is already not null, since it is a `Int`.
+alt/error_expr_not_ok_alt6.nit:151,7--10: Warning: expression is not null, since it is a `Int`.
 alt/error_expr_not_ok_alt6.nit:151,7--23: Type error: expected A, got Int
 alt/error_expr_not_ok_alt6.nit:152,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt6.nit:152,7--18: Type error: expected A, got Bool
diff --git a/tests/sav/nitg-e/base_notnull_lit.res b/tests/sav/nitg-e/base_notnull_lit.res
new file mode 100644 (file)
index 0000000..59ec579
--- /dev/null
@@ -0,0 +1,4 @@
+Array
+156
+Range
+12345
index 1fb7aeb..5789941 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:909)
+Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:911)
 NativeString
 N
 Nit