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>

40 files changed:
benchmarks/bench_engines.sh
benchmarks/markdown/.gitignore [new file with mode: 0644]
benchmarks/markdown/Makefile [new file with mode: 0644]
benchmarks/markdown/benches/Makefile
benchmarks/markdown/engines/nitmd/Makefile
benchmarks/strings/.gitignore [new file with mode: 0644]
benchmarks/strings/Makefile
lib/ai/examples/puzzle.nit
src/ffi/extern_classes.nit
src/frontend/check_annotation.nit
src/frontend/div_by_zero.nit
src/frontend/no_warning.nit
src/frontend/serialization_phase.nit
src/loader.nit
src/model/model.nit
src/modelbuilder.nit
src/modelbuilder_base.nit
src/modelize/modelize_class.nit
src/modelize/modelize_property.nit
src/phase.nit
src/semantize/auto_super_init.nit
src/semantize/typing.nit
src/toolcontext.nit
tests/error_virtual_type.nit [new file with mode: 0644]
tests/error_virtual_type2.nit [new file with mode: 0644]
tests/sav/base_virtual_type7.res
tests/sav/error_needed_method_alt4.res
tests/sav/error_needed_method_alt7.res
tests/sav/error_virtual_type2.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt1.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt2.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt3.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt4.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt5.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt6.res [new file with mode: 0644]
tests/sav/error_virtual_type_alt1.res [new file with mode: 0644]
tests/sav/error_virtual_type_alt2.res [new file with mode: 0644]
tests/sav/error_virtual_type_alt3.res [new file with mode: 0644]
tests/sav/error_virtual_type_alt4.res [new file with mode: 0644]
tests/sav/error_virtual_type_alt5.res [new file with mode: 0644]

index 62d6a9c..ae91703 100755 (executable)
@@ -62,6 +62,7 @@ function run_compiler()
                run_command "$@" ../src/nit.nit -o "nit.$title.bin"
                bench_command "nit-queens" "nit queens.nit 8" "./nit.$title.bin" ../lib/ai/examples/queens.nit -q 8
                bench_command "nit-nitcc" "nit nitcc.nit calc.sablecc" "./nit.$title.bin" ../contrib/nitcc/src/nitcc.nit ../contrib/nitcc/examples/calc.sablecc
+               rm calc* 2> /dev/null # remove generated cruft
                run_command "$@" ../src/nitdoc.nit -o "nitdoc.$title.bin"
                rm -r out 2> /dev/null
                mkdir out 2> /dev/null
diff --git a/benchmarks/markdown/.gitignore b/benchmarks/markdown/.gitignore
new file mode 100644 (file)
index 0000000..ada48ff
--- /dev/null
@@ -0,0 +1,15 @@
+benches/gen_benches
+benches/out/
+
+engines/nitmd/nitmd
+engines/nitmd/nitmd-o
+
+engines/markdown4j/Markdown4j.class
+engines/markdown4j/markdown4j-2.2.jar
+
+engines/pandoc/pandoc
+engines/pandoc/pandoc.hi
+engines/pandoc/pandoc.o
+
+engines/txtmark/Txtmark.class
+engines/txtmark/txtmark-0.11.jar
diff --git a/benchmarks/markdown/Makefile b/benchmarks/markdown/Makefile
new file mode 100644 (file)
index 0000000..802fab6
--- /dev/null
@@ -0,0 +1,21 @@
+# 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.
+
+all:
+       ./bench_markdown.sh all
+
+clean:
+       $(MAKE) clean -C benches
+       $(MAKE) clean -C engines
+       rm -rf out/
index 641c47e..4cb8c36 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+NITC=../../../bin/nitc
+
 all: out
 
 gen_benches:
-       nitc gen_benches.nit
+       $(NITC) gen_benches.nit
 
 out: gen_benches
        ./gen_benches ./plain.md -o ./out
index 6424382..256ddfe 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+NITC=../../../../bin/nitc
+
 all: nitmd nitmd-o
 
 nitmd:
-       nitc nitmd.nit
+       $(NITC) nitmd.nit
 
 nitmd-o:
-       nitc --semi-global nitmd.nit -o $@
+       $(NITC) --semi-global nitmd.nit -o $@
 
 test: all
        ./nitmd ../../benches/hello.md 5
diff --git a/benchmarks/strings/.gitignore b/benchmarks/strings/.gitignore
new file mode 100644 (file)
index 0000000..0e224dc
--- /dev/null
@@ -0,0 +1,4 @@
+arraytos/
+string_concat/
+string_iter/
+string_substr/
index 82118c9..a6d89bf 100644 (file)
@@ -11,3 +11,6 @@ iter:
 
 array:
        ./bench_strings.sh array 10 10000000 10
+
+clean:
+       rm -rf arraytos/ string_concat/ string_iter/ string_substr/ 2>/dev/null
index 83c4b4c..0583035 100644 (file)
@@ -103,7 +103,7 @@ class PuzzleProblem
                if x < width-1 then res.add(1)
                if y >= 1 then res.add(-width)
                if y < width-1 then res.add(width)
-               return res.as_random.take_all
+               return res
        end
 
        # Return the state where the tile at hole+action has moved
index bc4f0c4..4e8f45d 100644 (file)
@@ -68,10 +68,11 @@ private class ExternClassesTypingPhaseModel
                if not nclassdef isa AStdClassdef then return
 
                var mclassdef = nclassdef.mclassdef
-               var mclass = nclassdef.mclass
+               if mclassdef == null then return
+               var mclass = mclassdef.mclass
 
                # We only need to do this once per class
-               if mclass.intro != mclassdef then return
+               if not mclassdef.is_intro then return
 
                if mclass.kind != extern_kind then return
 
index 36244f6..ffba4ad 100644 (file)
@@ -40,7 +40,7 @@ private class CheckAnnotationPhase
        do
                # Get the mmodule
                var mmodule = nmodule.mmodule
-               assert mmodule != null
+               if mmodule == null then return
                self.mmodule = mmodule
 
                # If no decl block then quit
@@ -112,7 +112,7 @@ platform
                if primtives_annotations.has(name) then return
 
                var mmodule = self.mmodule
-               assert mmodule != null
+               if mmodule == null then return
 
                # Lazily build the full user-list
                var annots = user_annotations.get_or_null(mmodule)
index 4a8cfb4..6001f01 100644 (file)
@@ -37,7 +37,8 @@ private class DivByZeroPhase
        redef fun process_nmodule(nmodule)
        do
                # The AST node is not enough, we need also the associated model element
-               var mmodule = nmodule.mmodule.as(not null)
+               var mmodule = nmodule.mmodule
+               if mmodule == null then return
                # For the specific job we have, the simpler it to launch a visitor on
                # all elements of the AST.
                var visitor = new DivByZeroVisitor(toolcontext, mmodule)
index 931440e..bc59d8c 100644 (file)
@@ -30,7 +30,7 @@ private class NoWarningPhase
        do
                # Get the mmodule
                var mmodule = nmodule.mmodule
-               assert mmodule != null
+               if mmodule == null then return
 
                var source = nmodule.location.file
 
index 2b68eea..0d7e4ec 100644 (file)
@@ -184,7 +184,9 @@ private class SerializationPhasePostModel
        redef fun process_nmodule(nmodule)
        do
                for npropdef in nmodule.inits_to_retype do
-                       var v = new PreciseTypeVisitor(npropdef, npropdef.mpropdef.mclassdef, toolcontext)
+                       var mpropdef = npropdef.mpropdef
+                       if mpropdef == null then continue # skip error
+                       var v = new PreciseTypeVisitor(npropdef, mpropdef.mclassdef, toolcontext)
                        npropdef.accept_precise_type_visitor v
                end
        end
index 9d1297b..9876bc4 100644 (file)
@@ -72,8 +72,9 @@ redef class ModelBuilder
                        if nmodule == null then continue # Skip error
                        # Load imported module
                        build_module_importation(nmodule)
-
-                       mmodules.add(nmodule.mmodule.as(not null))
+                       var mmodule = nmodule.mmodule
+                       if mmodule == null then continue # skip error
+                       mmodules.add mmodule
                end
                var time1 = get_time
                self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
@@ -100,8 +101,9 @@ redef class ModelBuilder
                                if nmodule == null then continue # Skip error
                                # Load imported module
                                build_module_importation(nmodule)
-
-                               res.add(nmodule.mmodule.as(not null))
+                               var mmodule = nmodule.mmodule
+                               if mmodule == null then continue # Skip error
+                               res.add mmodule
                        end
                end
                return res
@@ -154,7 +156,9 @@ redef class ModelBuilder
                                                var nmodule = self.load_module(af)
                                                if nmodule == null then continue # Skip error
                                                build_module_importation(nmodule)
-                                               mmodules.add(nmodule.mmodule.as(not null))
+                                               var mmodule = nmodule.mmodule
+                                               if mmodule == null then continue # Skip error
+                                               mmodules.add mmodule
                                        else
                                                self.toolcontext.info("ignore file {af}", 2)
                                        end
@@ -166,8 +170,9 @@ redef class ModelBuilder
                        if nmodule == null then continue # Skip error
                        # Load imported module
                        build_module_importation(nmodule)
-
-                       mmodules.add(nmodule.mmodule.as(not null))
+                       var mmodule = nmodule.mmodule
+                       if mmodule == null then continue # Skip error
+                       mmodules.add mmodule
                end
                var time1 = get_time
                self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
@@ -261,7 +266,7 @@ redef class ModelBuilder
                if res == null then return null # Forward error
                # Load imported module
                build_module_importation(res)
-               return res.mmodule.as(not null)
+               return res.mmodule
        end
 
        # Search a module `name` from path `lookpaths`.
@@ -667,24 +672,33 @@ redef class ModelBuilder
                        if aimport.n_name.n_quad != null then mgroup = null # Start from top level
                        for grp in aimport.n_name.n_path do
                                var path = search_mmodule_by_name(grp, mgroup, grp.text)
-                               if path == null then return # Skip error
+                               if path == null then
+                                       nmodule.mmodule = null # invalidate the module
+                                       return # Skip error
+                               end
                                mgroup = path.mgroup
                        end
                        var mod_name = aimport.n_name.n_id.text
                        var sup = self.get_mmodule_by_name(aimport.n_name, mgroup, mod_name)
-                       if sup == null then continue # Skip error
+                       if sup == null then
+                               nmodule.mmodule = null # invalidate the module
+                               continue # Skip error
+                       end
                        aimport.mmodule = sup
                        imported_modules.add(sup)
                        var mvisibility = aimport.n_visibility.mvisibility
                        if mvisibility == protected_visibility then
                                error(aimport.n_visibility, "Error: only properties can be protected.")
+                               nmodule.mmodule = null # invalidate the module
                                return
                        end
                        if sup == mmodule then
                                error(aimport.n_name, "Error: Dependency loop in module {mmodule}.")
+                               nmodule.mmodule = null # invalidate the module
                        end
                        if sup.in_importation < mmodule then
                                error(aimport.n_name, "Error: Dependency loop between modules {mmodule} and {sup}.")
+                               nmodule.mmodule = null # invalidate the module
                                return
                        end
                        mmodule.set_visibility_for(sup, mvisibility)
@@ -692,7 +706,9 @@ redef class ModelBuilder
                if stdimport then
                        var mod_name = "standard"
                        var sup = self.get_mmodule_by_name(nmodule, null, mod_name)
-                       if sup != null then # Skip error
+                       if sup == null then
+                               nmodule.mmodule = null # invalidate the module
+                       else # Skip error
                                imported_modules.add(sup)
                                mmodule.set_visibility_for(sup, public_visibility)
                        end
index 6dbcda1..62c3db4 100644 (file)
@@ -251,7 +251,9 @@ redef class MModule
        fun get_primitive_class(name: String): MClass
        do
                var cla = self.model.get_mclasses_by_name(name)
-               if cla == null then
+               # Filter classes by introducing module
+               if cla != null then cla = [for c in cla do if self.in_importation <= c.intro_mmodule then c]
+               if cla == null or cla.is_empty then
                        if name == "Bool" and self.model.get_mclasses_by_name("Object") != null then
                                # Bool is injected because it is needed by engine to code the result
                                # of the implicit casts.
@@ -261,11 +263,11 @@ redef class MModule
                                cladef.add_in_hierarchy
                                return c
                        end
-                       print("Fatal Error: no primitive class {name}")
+                       print("Fatal Error: no primitive class {name} in {self}")
                        exit(1)
                end
                if cla.length != 1 then
-                       var msg = "Fatal Error: more than one primitive class {name}:"
+                       var msg = "Fatal Error: more than one primitive class {name} in {self}:"
                        for c in cla do msg += " {c.full_name}"
                        print msg
                        #exit(1)
@@ -433,8 +435,17 @@ class MClass
        #
        # Warning: such a definition may not exist in the early life of the object.
        # In this case, the method will abort.
+       #
+       # Use `try_intro` instead
        var intro: MClassDef is noinit
 
+       # The definition that introduces the class or null if not yet known.
+       #
+       # See `intro`
+       fun try_intro: nullable MClassDef do
+               if isset _intro then return _intro else return null
+       end
+
        # Return the class `self` in the class hierarchy of the module `mmodule`.
        #
        # SEE: `MModule::flatten_mclass_hierarchy`
@@ -627,7 +638,7 @@ class MClassDef
        var in_hierarchy: nullable POSetElement[MClassDef] = null
 
        # Is the definition the one that introduced `mclass`?
-       fun is_intro: Bool do return mclass.intro == self
+       fun is_intro: Bool do return isset mclass._intro and mclass.intro == self
 
        # All properties introduced by the classdef
        var intro_mproperties = new Array[MProperty]
index 30f5885..23f7d49 100644 (file)
@@ -52,11 +52,16 @@ redef class ToolContext
        # Run `process_mainmodule` on all phases
        fun run_global_phases(mmodules: Array[MModule])
        do
-               var mainmodule = make_main_module(mmodules)
-               for phase in phases_list do
-                       if phase.disabled then continue
-                       phase.process_mainmodule(mainmodule, mmodules)
+               if not mmodules.is_empty then
+                       var mainmodule = make_main_module(mmodules)
+                       for phase in phases_list do
+                               if phase.disabled then continue
+                               phase.process_mainmodule(mainmodule, mmodules)
+                       end
                end
+
+               check_errors
+               errors_info
        end
 end
 
index 9995338..93423df 100644 (file)
@@ -81,6 +81,16 @@ class ModelBuilder
                return res
        end
 
+       # Like `try_get_mclass_by_name` but display an error message when the class is not found
+       fun get_mclass_by_name(node: ANode, mmodule: MModule, name: String): nullable MClass
+       do
+               var mclass = try_get_mclass_by_name(node, mmodule, name)
+               if mclass == null then
+                       error(node, "Type Error: missing primitive class `{name}'.")
+               end
+               return mclass
+       end
+
        # Return a property named `name` on the type `mtype` visible in the module `mmodule`.
        # Visibility in modules is correctly handled.
        # Protected properties are returned (it is up to the caller to check and reject protected properties).
@@ -305,7 +315,9 @@ class ModelBuilder
                if mtype isa MGenericType then
                        var mclass = mtype.mclass
                        for i in [0..mclass.arity[ do
-                               var bound = mclass.intro.bound_mtype.arguments[i]
+                               var intro = mclass.try_intro
+                               if intro == null then return null # skip error
+                               var bound = intro.bound_mtype.arguments[i]
                                var nt = ntype.n_types[i]
                                var mt = resolve_mtype(mmodule, mclassdef, nt)
                                if mt == null then return null # forward error
index c779df9..5618c11 100644 (file)
@@ -103,7 +103,9 @@ redef class ModelBuilder
                                var mclasses = model.get_mclasses_by_name(name)
                                if mclasses != null then for other in mclasses do
                                        if other.intro_mmodule.mgroup != null and other.intro_mmodule.mgroup.mproject == mmodule.mgroup.mproject then
-                                               error(nclassdef, "Error: A class named `{other.full_name}` is already defined in module `{other.intro_mmodule}` at {other.intro.location}.")
+                                               # Skip classes that are buggy
+                                               if other.try_intro == null then continue
+                                               warning(nclassdef, "full-name-conflict", "Error: A class named `{other.full_name}` is already defined in module `{other.intro_mmodule}` at {other.intro.location}.")
                                                break
                                        end
                                end
@@ -224,11 +226,14 @@ redef class ModelBuilder
        # Visit the AST and set the super-types of the `MClassDef` objects
        private fun collect_a_mclassdef_inheritance(nmodule: AModule, nclassdef: AClassdef)
        do
-               var mmodule = nmodule.mmodule.as(not null)
+               var mmodule = nmodule.mmodule
+               if mmodule == null then return
                var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
                var pointerclass = try_get_mclass_by_name(nmodule, mmodule, "Pointer")
-               var mclass = nclassdef.mclass.as(not null)
-               var mclassdef = nclassdef.mclassdef.as(not null)
+               var mclass = nclassdef.mclass
+               if mclass == null then return
+               var mclassdef = nclassdef.mclassdef
+               if mclassdef == null then return
 
                # Do we need to specify Object as a super class?
                var specobject = true
@@ -274,9 +279,12 @@ redef class ModelBuilder
        # Check the validity of the specialization heirarchy
        private fun check_supertypes(nmodule: AModule, nclassdef: AClassdef)
        do
-               var mmodule = nmodule.mmodule.as(not null)
-               var mclass = nclassdef.mclass.as(not null)
-               var mclassdef = nclassdef.mclassdef.as(not null)
+               var mmodule = nmodule.mmodule
+               if mmodule == null then return
+               var mclass = nclassdef.mclass
+               if mclass == null then return
+               var mclassdef = nclassdef.mclassdef
+               if mclassdef == null then return
 
                for s in mclassdef.supertypes do
                        if s.is_subtype(mmodule, mclassdef.bound_mtype, mclassdef.bound_mtype) then
@@ -293,7 +301,8 @@ redef class ModelBuilder
                # Force building recursively
                if nmodule.build_classes_is_done then return
                nmodule.build_classes_is_done = true
-               var mmodule = nmodule.mmodule.as(not null)
+               var mmodule = nmodule.mmodule
+               if mmodule == null then return
                for imp in mmodule.in_importation.direct_greaters do
                        var nimp = mmodule2node(imp)
                        if nimp != null then build_classes(nimp)
@@ -363,7 +372,8 @@ redef class ModelBuilder
 
                # Check clash of ancestors
                for nclassdef in nmodule.n_classdefs do
-                       var mclassdef = nclassdef.mclassdef.as(not null)
+                       var mclassdef = nclassdef.mclassdef
+                       if mclassdef == null then continue
                        var superclasses = new HashMap[MClass, MClassType]
                        for scd in mclassdef.in_hierarchy.greaters do
                                for st in scd.supertypes do
@@ -387,7 +397,8 @@ redef class ModelBuilder
                # Check that the superclasses are not already known (by transitivity)
                for nclassdef in nmodule.n_classdefs do
                        if not nclassdef isa AStdClassdef then continue
-                       var mclassdef = nclassdef.mclassdef.as(not null)
+                       var mclassdef = nclassdef.mclassdef
+                       if mclassdef == null then continue
 
                        # Get the direct superclasses
                        # Since we are a mclassdef, just look at the mclassdef hierarchy
index f5b33af..c224b29 100644 (file)
@@ -86,7 +86,8 @@ redef class ModelBuilder
                # Force building recursively
                if nclassdef.build_properties_is_done then return
                nclassdef.build_properties_is_done = true
-               var mclassdef = nclassdef.mclassdef.as(not null)
+               var mclassdef = nclassdef.mclassdef
+               if mclassdef == null then return # skip error
                if mclassdef.in_hierarchy == null then return # Skip error
                for superclassdef in mclassdef.in_hierarchy.direct_greaters do
                        if not mclassdef2nclassdef.has_key(superclassdef) then continue
@@ -102,6 +103,24 @@ redef class ModelBuilder
                                npropdef.build_signature(self)
                        end
                        for npropdef in nclassdef2.n_propdefs do
+                               if not npropdef isa ATypePropdef then continue
+                               # Check circularity
+                               var mpropdef = npropdef.mpropdef
+                               if mpropdef == null then continue
+                               if mpropdef.bound == null then continue
+                               if not check_virtual_types_circularity(npropdef, mpropdef.mproperty, mclassdef.bound_mtype, mclassdef.mmodule) then
+                                       # Invalidate the bound
+                                       mpropdef.bound = mclassdef.mmodule.model.null_type
+                               end
+                       end
+                       for npropdef in nclassdef2.n_propdefs do
+                               # Check ATypePropdef first since they may be required for the other properties
+                               if not npropdef isa ATypePropdef then continue
+                               npropdef.check_signature(self)
+                       end
+
+                       for npropdef in nclassdef2.n_propdefs do
+                               if npropdef isa ATypePropdef then continue
                                npropdef.check_signature(self)
                        end
                end
@@ -296,6 +315,7 @@ redef class ModelBuilder
                                        for p in spd.initializers do
                                                if p != longest.initializers[i] then
                                                        self.error(nclassdef, "Error: conflict for inherited inits {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")})")
+                                                       # TODO: invalidate the initializer to avoid more errors
                                                        return
                                                end
                                                i += 1
@@ -359,6 +379,8 @@ redef class ModelBuilder
                        mmodule_type = mtype.mproperty.intro_mclassdef.mmodule
                else if mtype isa MParameterType then
                        # nothing, always visible
+               else if mtype isa MNullType then
+                       # nothing to do.
                else
                        node.debug "Unexpected type {mtype}"
                        abort
@@ -387,6 +409,72 @@ redef class ModelBuilder
                        for t in mtype.arguments do check_visibility(node, t, mpropdef)
                end
        end
+
+       # Detect circularity errors for virtual types.
+       fun check_virtual_types_circularity(node: ANode, mproperty: MVirtualTypeProp, recv: MType, mmodule: MModule): Bool
+       do
+               # Check circularity
+               # Slow case: progress on each resolution until we visit all without getting a loop
+
+               # The graph used to detect loops
+               var mtype = mproperty.mvirtualtype
+               var poset = new POSet[MType]
+
+               # The work-list of types to resolve
+               var todo = new List[MType]
+               todo.add mtype
+
+               while not todo.is_empty do
+                       # The visited type
+                       var t = todo.pop
+
+                       if not t.need_anchor then continue
+
+                       # Get the types derived of `t` (subtypes and bounds)
+                       var nexts
+                       if t isa MNullableType then
+                               nexts = [t.mtype]
+                       else if t isa MGenericType then
+                               nexts = t.arguments
+                       else if t isa MVirtualType then
+                               var vt = t.mproperty
+                               # Because `vt` is possibly unchecked, we have to do the bound-lookup manually
+                               var defs = vt.lookup_definitions(mmodule, recv)
+                               # TODO something to manage correctly bound conflicts
+                               assert not defs.is_empty
+                               nexts = new Array[MType]
+                               for d in defs do
+                                       var next = defs.first.bound
+                                       if next == null then return false
+                                       nexts.add next
+                               end
+                       else if t isa MClassType then
+                               # Basic type, nothing to to
+                               continue
+                       else if t isa MParameterType then
+                               # Parameter types cannot depend on virtual types, so nothing to do
+                               continue
+                       else
+                               abort
+                       end
+
+                       # For each one
+                       for next in nexts do
+                               if poset.has_edge(next, t) then
+                                       if mtype == next then
+                                               error(node, "Error: circularity of virtual type definition: {next} <-> {t}")
+                                       else
+                                               error(node, "Error: circularity of virtual type definition: {mtype} -> {next} <-> {t}")
+                                       end
+                                       return false
+                               else
+                                       poset.add_edge(t, next)
+                                       todo.add next
+                               end
+                       end
+               end
+               return true
+       end
 end
 
 redef class MPropDef
@@ -597,7 +685,7 @@ redef class ASignature
                        param_names.add(np.n_id.text)
                        var ntype = np.n_type
                        if ntype != null then
-                               var mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
+                               var mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true)
                                if mtype == null then return false # Skip error
                                for i in [0..param_names.length-param_types.length[ do
                                        param_types.add(mtype)
@@ -614,7 +702,7 @@ redef class ASignature
                end
                var ntype = self.n_type
                if ntype != null then
-                       self.ret_type = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
+                       self.ret_type = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true)
                        if self.ret_type == null then return false # Skip error
                end
 
@@ -622,24 +710,24 @@ redef class ASignature
                return true
        end
 
-       # Build a visited signature
-       fun build_signature(modelbuilder: ModelBuilder): nullable MSignature
+       private fun check_signature(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
        do
-               if param_names.length != param_types.length then
-                       # Some parameters are typed, other parameters are not typed.
-                       modelbuilder.error(self.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
-                       return null
+               var res = true
+               for np in self.n_params do
+                       var ntype = np.n_type
+                       if ntype != null then
+                               if modelbuilder.resolve_mtype(mclassdef.mmodule, mclassdef, ntype) == null then
+                                       res = false
+                               end
+                       end
                end
-
-               var mparameters = new Array[MParameter]
-               for i in [0..param_names.length[ do
-                       var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
-                       self.n_params[i].mparameter = mparameter
-                       mparameters.add(mparameter)
+               var ntype = self.n_type
+               if ntype != null then
+                       if modelbuilder.resolve_mtype(mclassdef.mmodule, mclassdef, ntype) == null then
+                               res = false
+                       end
                end
-
-               var msignature = new MSignature(mparameters, ret_type)
-               return msignature
+               return res
        end
 end
 
@@ -880,6 +968,14 @@ redef class AMethPropdef
                var mysignature = self.mpropdef.msignature
                if mysignature == null then return # Error thus skiped
 
+               # Check
+               if nsig != null then
+                       if not nsig.check_signature(modelbuilder, mclassdef) then
+                               self.mpropdef.msignature = null # invalidate
+                               return # Forward error
+                       end
+               end
+
                # Lookup for signature in the precursor
                # FIXME all precursors should be considered
                if not mpropdef.is_intro then
@@ -890,6 +986,7 @@ redef class AMethPropdef
                        var ret_type = mysignature.return_mtype
                        if ret_type != null and precursor_ret_type == null then
                                modelbuilder.error(nsig.n_type.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
+                               self.mpropdef.msignature = null
                                return
                        end
 
@@ -901,6 +998,7 @@ redef class AMethPropdef
                                        var node = nsig.n_params[i]
                                        if not modelbuilder.check_sametype(node, mmodule, mclassdef.bound_mtype, myt, prt) then
                                                modelbuilder.error(node, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt} as in {mpropdef.mproperty.intro}.")
+                                               self.mpropdef.msignature = null
                                        end
                                end
                        end
@@ -913,6 +1011,7 @@ redef class AMethPropdef
                                        ret_type = precursor_ret_type
                                else if not modelbuilder.check_subtype(node, mmodule, mclassdef.bound_mtype, ret_type, precursor_ret_type) then
                                        modelbuilder.error(node, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type} as in {mpropdef.mproperty.intro}.")
+                                       self.mpropdef.msignature = null
                                end
                        end
                end
@@ -1028,6 +1127,7 @@ redef class AAttrPropdef
                                else if atautoinit != null then
                                        modelbuilder.error(atautoinit, "Error: a autoinit attribute needs a value")
                                end
+                               has_value = true
                                return
                        end
                        is_lazy = true
@@ -1092,7 +1192,7 @@ redef class AAttrPropdef
 
                var ntype = self.n_type
                if ntype != null then
-                       mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
+                       mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true)
                        if mtype == null then return
                end
 
@@ -1113,7 +1213,7 @@ redef class AAttrPropdef
                if mtype == null then
                        if nexpr != null then
                                if nexpr isa ANewExpr then
-                                       mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
+                                       mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, nexpr.n_type, true)
                                else if nexpr isa AIntExpr then
                                        var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
                                        if cla != null then mtype = cla.mclass_type
@@ -1140,7 +1240,7 @@ redef class AAttrPropdef
                        end
                else if ntype != null and inherited_type == mtype then
                        if nexpr isa ANewExpr then
-                               var xmtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
+                               var xmtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, nexpr.n_type, true)
                                if xmtype == mtype then
                                        modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition")
                                end
@@ -1184,6 +1284,18 @@ redef class AAttrPropdef
                var mtype = self.mpropdef.static_mtype
                if mtype == null then return # Error thus skipped
 
+               var mclassdef = mpropdef.mclassdef
+               var mmodule = mclassdef.mmodule
+
+               # Check types
+               if ntype != null then
+                       if modelbuilder.resolve_mtype(mmodule, mclassdef, ntype) == null then return
+               end
+               var nexpr = n_expr
+               if nexpr isa ANewExpr then
+                       if modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type) == null then return
+               end
+
                # Lookup for signature in the precursor
                # FIXME all precursors should be considered
                if not mpropdef.is_intro then
@@ -1315,7 +1427,7 @@ redef class ATypePropdef
                var mtype: nullable MType = null
 
                var ntype = self.n_type
-               mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
+               mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true)
                if mtype == null then return
 
                mpropdef.bound = mtype
@@ -1327,7 +1439,7 @@ redef class ATypePropdef
                var mpropdef = self.mpropdef
                if mpropdef == null then return # Error thus skipped
 
-               var bound = self.mpropdef.bound
+               var bound = mpropdef.bound
                if bound == null then return # Error thus skipped
 
                modelbuilder.check_visibility(n_type, bound, mpropdef)
@@ -1336,25 +1448,13 @@ redef class ATypePropdef
                var mmodule = mclassdef.mmodule
                var anchor = mclassdef.bound_mtype
 
-               # 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)
-                               var next = bound.lookup_bound(mmodule, anchor)
-                               if not next isa MVirtualType then break
-                               bound = next
-                       end
+               var ntype = self.n_type
+               if modelbuilder.resolve_mtype(mmodule, mclassdef, ntype) == null then
+                       mpropdef.bound = null
+                       return
                end
 
                # Check redefinitions
-               bound = mpropdef.bound.as(not null)
                for p in mpropdef.mproperty.lookup_super_definitions(mmodule, anchor) do
                        var supbound = p.bound
                        if supbound == null then break # broken super bound, skip error
index bdec532..502d817 100644 (file)
@@ -147,7 +147,7 @@ redef class ToolContext
                var time1 = get_time
                self.info("*** END SEMANTIC ANALYSIS: {time1-time0} ***", 2)
 
-               errors_info
+               self.check_errors
        end
 
        # Process the given `phase` on the `npropdef`
index d60e2a3..07b4f46 100644 (file)
@@ -56,8 +56,10 @@ redef class AMethPropdef
        # Collect initializers and build the auto-init
        fun do_auto_super_init(modelbuilder: ModelBuilder)
        do
-               var mclassdef = self.parent.as(AClassdef).mclassdef.as(not null)
-               var mpropdef = self.mpropdef.as(not null)
+               var mclassdef = self.parent.as(AClassdef).mclassdef
+               if mclassdef == null then return # skip error
+               var mpropdef = self.mpropdef
+               if mpropdef == null then return # skip error
                var mmodule = mpropdef.mclassdef.mmodule
                var anchor = mclassdef.bound_mtype
                var recvtype = mclassdef.mclass.mclass_type
index 0634ee2..38a689a 100644 (file)
@@ -279,10 +279,7 @@ private class TypeVisitor
 
        fun get_mclass(node: ANode, name: String): nullable MClass
        do
-               var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
-               if mclass == null then
-                       self.modelbuilder.error(node, "Type Error: missing primitive class `{name}'.")
-               end
+               var mclass = modelbuilder.get_mclass_by_name(node, mmodule, name)
                return mclass
        end
 
@@ -301,7 +298,9 @@ private class TypeVisitor
                if recvtype isa MNullType then
                        # `null` only accepts some methods of object.
                        if name == "==" or name == "!=" or name == "is_same_instance" then
-                               unsafe_type = mmodule.object_type.as_nullable
+                               var objclass = get_mclass(node, "Object")
+                               if objclass == null then return null # Forward error
+                               unsafe_type = objclass.mclass_type
                        else
                                self.error(node, "Error: Method '{name}' call on 'null'.")
                                return null
@@ -361,7 +360,8 @@ private class TypeVisitor
                end
 
 
-               var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+               var msignature = mpropdef.new_msignature or else mpropdef.msignature
+               if msignature == null then return null # skip error
                msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
 
                var erasure_cast = false
@@ -602,14 +602,18 @@ redef class AMethPropdef
                var nblock = self.n_block
                if nblock == null then return
 
-               var mpropdef = self.mpropdef.as(not null)
+               var mpropdef = self.mpropdef
+               if mpropdef == null then return # skip error
+
                var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
                self.selfvariable = v.selfvariable
 
                var mmethoddef = self.mpropdef.as(not null)
-               for i in [0..mmethoddef.msignature.arity[ do
-                       var mtype = mmethoddef.msignature.mparameters[i].mtype
-                       if mmethoddef.msignature.vararg_rank == i then
+               var msignature = mmethoddef.msignature
+               if msignature == null then return # skip error
+               for i in [0..msignature.arity[ do
+                       var mtype = msignature.mparameters[i].mtype
+                       if msignature.vararg_rank == i then
                                var arrayclass = v.get_mclass(self.n_signature.n_params[i], "Array")
                                if arrayclass == null then return # Skip error
                                mtype = arrayclass.get_mtype([mtype])
@@ -620,7 +624,7 @@ redef class AMethPropdef
                end
                v.visit_stmt(nblock)
 
-               if not nblock.after_flow_context.is_unreachable and mmethoddef.msignature.return_mtype != null then
+               if not nblock.after_flow_context.is_unreachable and msignature.return_mtype != null then
                        # We reach the end of the function without having a return, it is bad
                        v.error(self, "Control error: Reached end of function (a 'return' with a value was expected).")
                end
@@ -632,7 +636,9 @@ redef class AAttrPropdef
        do
                if not has_value then return
 
-               var mpropdef = self.mpropdef.as(not null)
+               var mpropdef = self.mpropdef
+               if mpropdef == null then return # skip error
+
                var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
                self.selfvariable = v.selfvariable
 
@@ -731,7 +737,9 @@ redef class AVardeclExpr
 
                var decltype = mtype
                if mtype == null or mtype isa MNullType then
-                       decltype = v.get_mclass(self, "Object").mclass_type.as_nullable
+                       var objclass = v.get_mclass(self, "Object")
+                       if objclass == null then return # skip error
+                       decltype = objclass.mclass_type.as_nullable
                        if mtype == null then mtype = decltype
                end
 
@@ -1162,7 +1170,9 @@ redef class AOrElseExpr
 
                var t = v.merge_types(self, [t1, t2])
                if t == null then
-                       t = v.mmodule.object_type
+                       var c = v.get_mclass(self, "Object")
+                       if c == null then return # forward error
+                       t = c.mclass_type
                        if v.can_be_null(t2) then
                                t = t.as_nullable
                        end
@@ -1228,8 +1238,11 @@ redef class ASuperstringExpr
                var mclass = v.get_mclass(self, "String")
                if mclass == null then return # Forward error
                self.mtype = mclass.mclass_type
+               var objclass = v.get_mclass(self, "Object")
+               if objclass == null then return # Forward error
+               var objtype = objclass.mclass_type
                for nexpr in self.n_exprs do
-                       v.visit_expr_subtype(nexpr, v.mmodule.object_type)
+                       v.visit_expr_subtype(nexpr, objtype)
                end
        end
 end
@@ -1844,7 +1857,8 @@ redef class AAttrFormExpr
                var mpropdefs = mproperty.lookup_definitions(v.mmodule, unsafe_type)
                assert mpropdefs.length == 1
                var mpropdef = mpropdefs.first
-               var attr_type = mpropdef.static_mtype.as(not null)
+               var attr_type = mpropdef.static_mtype
+               if attr_type == null then return # skip error
                attr_type = v.resolve_for(attr_type, recvtype, self.n_expr isa ASelfExpr)
                self.attr_type = attr_type
        end
index 62c184a..92a4824 100644 (file)
@@ -134,13 +134,13 @@ class ToolContext
                return tags.has("all") or tags.has(tag)
        end
 
-       # Output all current stacked messages and display total error informations
+       # Output all current stacked messages
        #
        # Return true if no errors occurred.
        #
        # If some errors occurred, the behavior depends on the value of `keep_going`.
-       # If `keep_going` is false, then the program exits.
-       # Else, the error count and the warning count are reset and false is returned.
+       # If `keep_going` is false, then the total error informations is displayed and the program exits.
+       # Else, false is returned.
        fun check_errors: Bool
        do
                if messages.length > 0 then
@@ -158,21 +158,21 @@ class ToolContext
                end
 
                if error_count > 0 then
-                       errors_info
-                       if not keep_going then exit(1)
+                       if not keep_going then
+                               errors_info
+                               exit(1)
+                       end
                        return false
                end
                return true
        end
 
-       # Display (and reset) total error informations
+       # Display total error informations
        fun errors_info
        do
                if error_count == 0 and warning_count == 0 then return
                if opt_no_color.value then return
                sys.stderr.write "Errors: {error_count}. Warnings: {warning_count}.\n"
-               error_count = 0
-               warning_count = 0
        end
 
        # Display an error
diff --git a/tests/error_virtual_type.nit b/tests/error_virtual_type.nit
new file mode 100644 (file)
index 0000000..dd7243b
--- /dev/null
@@ -0,0 +1,35 @@
+# 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 G[E: Object]
+end
+
+class A
+       fun foo(t: T): Comparable do return t
+       type T: Comparable #alt1-5#
+       #alt1#type T: T
+       #alt2#type T: nullable T
+       #alt3#type T: G[T]
+       #alt4#type T: U
+       #alt4#type U: FAIL
+       #alt5#type T: U
+       #alt5#type U: T
+       fun bar(t: T): Comparable do return t
+end
+
+var a = new A
+a.foo(1)
+a.bar('1')
diff --git a/tests/error_virtual_type2.nit b/tests/error_virtual_type2.nit
new file mode 100644 (file)
index 0000000..274bb77
--- /dev/null
@@ -0,0 +1,52 @@
+# 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 G[E]
+end
+
+class A
+       fun foo(t: T): Comparable do return t
+       #fun foog: nullable G[T] do return barg
+       type T: Comparable #alt1-5#
+       type GT: G[T]
+       #alt1#type T: T
+       #alt2#type T: nullable T
+       #alt3#type T: G[T]
+       #alt4#type T: U
+       #alt4#type U: FAIL
+       #alt5#type T: U
+       #alt5#type U: T
+       fun bar(t: T): Comparable do return t
+       #fun barg: nullable G[T] do return foog
+end
+
+class B
+       super A
+       redef fun foo(t: T): T do return t
+       #redef fun foog: GT do return barg
+       redef type GT: G[Discrete]
+       #alt6#redef type GT: G[Bool]
+       redef fun bar(t: T): T do return t
+       #redef fun barg: GT do return foog
+end
+
+var a = new A
+a.foo(1)
+a.bar('1')
+
+var b = new B
+b.foo(2)
+b.bar('3')
index 0fc0245..01f9a2f 100644 (file)
@@ -1,2 +1 @@
-base_virtual_type7.nit:20,2--10: Error: circularity of virtual type definition: E -> F -> E
-base_virtual_type7.nit:21,2--10: Error: circularity of virtual type definition: F -> E -> F
+base_virtual_type7.nit:20,2--10: Error: circularity of virtual type definition: E <-> F
index 6f7a1f9..f80abe8 100644 (file)
@@ -1 +1 @@
-Fatal Error: no primitive class NativeArray
+Fatal Error: no primitive class NativeArray in error_needed_method_alt4
index 6f7a1f9..2a7c903 100644 (file)
@@ -1 +1 @@
-Fatal Error: no primitive class NativeArray
+Fatal Error: no primitive class NativeArray in error_needed_method_alt7
diff --git a/tests/sav/error_virtual_type2.res b/tests/sav/error_virtual_type2.res
new file mode 100644 (file)
index 0000000..417f403
--- /dev/null
@@ -0,0 +1 @@
+error_virtual_type2.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of G[T], as in error_virtual_type2#A#GT.
diff --git a/tests/sav/error_virtual_type2_alt1.res b/tests/sav/error_virtual_type2_alt1.res
new file mode 100644 (file)
index 0000000..38cf3dd
--- /dev/null
@@ -0,0 +1,5 @@
+alt/error_virtual_type2_alt1.nit:22,2--24,13: Error: circularity of virtual type definition: GT -> T <-> T
+alt/error_virtual_type2_alt1.nit:25,2--10: Error: circularity of virtual type definition: T <-> T
+alt/error_virtual_type2_alt1.nit:38,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt1#A#foo.
+alt/error_virtual_type2_alt1.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of null, as in error_virtual_type2_alt1#A#GT.
+alt/error_virtual_type2_alt1.nit:42,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt1#A#bar.
diff --git a/tests/sav/error_virtual_type2_alt2.res b/tests/sav/error_virtual_type2_alt2.res
new file mode 100644 (file)
index 0000000..f155524
--- /dev/null
@@ -0,0 +1,5 @@
+alt/error_virtual_type2_alt2.nit:22,2--24,13: Error: circularity of virtual type definition: GT -> T <-> nullable T
+alt/error_virtual_type2_alt2.nit:25,2--26,19: Error: circularity of virtual type definition: T <-> nullable T
+alt/error_virtual_type2_alt2.nit:38,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt2#A#foo.
+alt/error_virtual_type2_alt2.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of null, as in error_virtual_type2_alt2#A#GT.
+alt/error_virtual_type2_alt2.nit:42,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt2#A#bar.
diff --git a/tests/sav/error_virtual_type2_alt3.res b/tests/sav/error_virtual_type2_alt3.res
new file mode 100644 (file)
index 0000000..80c9981
--- /dev/null
@@ -0,0 +1,5 @@
+alt/error_virtual_type2_alt3.nit:22,2--24,13: Error: circularity of virtual type definition: GT -> G[T] <-> T
+alt/error_virtual_type2_alt3.nit:25,2--27,12: Error: circularity of virtual type definition: T <-> G[T]
+alt/error_virtual_type2_alt3.nit:38,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt3#A#foo.
+alt/error_virtual_type2_alt3.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of null, as in error_virtual_type2_alt3#A#GT.
+alt/error_virtual_type2_alt3.nit:42,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt3#A#bar.
diff --git a/tests/sav/error_virtual_type2_alt4.res b/tests/sav/error_virtual_type2_alt4.res
new file mode 100644 (file)
index 0000000..158622e
--- /dev/null
@@ -0,0 +1,4 @@
+alt/error_virtual_type2_alt4.nit:29,10--13: Type error: class FAIL not found in module error_virtual_type2_alt4.
+alt/error_virtual_type2_alt4.nit:38,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt4#A#foo.
+alt/error_virtual_type2_alt4.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of null, as in error_virtual_type2_alt4#A#GT.
+alt/error_virtual_type2_alt4.nit:42,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt4#A#bar.
diff --git a/tests/sav/error_virtual_type2_alt5.res b/tests/sav/error_virtual_type2_alt5.res
new file mode 100644 (file)
index 0000000..1efe3e7
--- /dev/null
@@ -0,0 +1,5 @@
+alt/error_virtual_type2_alt5.nit:22,2--24,13: Error: circularity of virtual type definition: GT -> T <-> U
+alt/error_virtual_type2_alt5.nit:25,2--30,10: Error: circularity of virtual type definition: T <-> U
+alt/error_virtual_type2_alt5.nit:38,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt5#A#foo.
+alt/error_virtual_type2_alt5.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of null, as in error_virtual_type2_alt5#A#GT.
+alt/error_virtual_type2_alt5.nit:42,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt5#A#bar.
diff --git a/tests/sav/error_virtual_type2_alt6.res b/tests/sav/error_virtual_type2_alt6.res
new file mode 100644 (file)
index 0000000..6e05965
--- /dev/null
@@ -0,0 +1,2 @@
+alt/error_virtual_type2_alt6.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of G[T], as in error_virtual_type2_alt6#A#GT.
+alt/error_virtual_type2_alt6.nit:41,2--22: Error: A property GT is already defined in class B at line 39.
diff --git a/tests/sav/error_virtual_type_alt1.res b/tests/sav/error_virtual_type_alt1.res
new file mode 100644 (file)
index 0000000..b87d6c0
--- /dev/null
@@ -0,0 +1 @@
+alt/error_virtual_type_alt1.nit:22,2--23,10: Error: circularity of virtual type definition: T <-> T
diff --git a/tests/sav/error_virtual_type_alt2.res b/tests/sav/error_virtual_type_alt2.res
new file mode 100644 (file)
index 0000000..98ff344
--- /dev/null
@@ -0,0 +1 @@
+alt/error_virtual_type_alt2.nit:22,2--24,19: Error: circularity of virtual type definition: T <-> nullable T
diff --git a/tests/sav/error_virtual_type_alt3.res b/tests/sav/error_virtual_type_alt3.res
new file mode 100644 (file)
index 0000000..1bad756
--- /dev/null
@@ -0,0 +1,2 @@
+alt/error_virtual_type_alt3.nit:25,12: Type error: expected Object, got T
+alt/error_virtual_type_alt3.nit:22,2--25,12: Error: circularity of virtual type definition: T <-> G[T]
diff --git a/tests/sav/error_virtual_type_alt4.res b/tests/sav/error_virtual_type_alt4.res
new file mode 100644 (file)
index 0000000..150aef7
--- /dev/null
@@ -0,0 +1 @@
+alt/error_virtual_type_alt4.nit:27,10--13: Type error: class FAIL not found in module error_virtual_type_alt4.
diff --git a/tests/sav/error_virtual_type_alt5.res b/tests/sav/error_virtual_type_alt5.res
new file mode 100644 (file)
index 0000000..84b89c9
--- /dev/null
@@ -0,0 +1 @@
+alt/error_virtual_type_alt5.nit:22,2--28,10: Error: circularity of virtual type definition: T <-> U