From: Jean Privat Date: Wed, 8 Apr 2015 01:01:49 +0000 (+0700) Subject: Merge: Not null types X-Git-Tag: v0.7.4~37 X-Git-Url: http://nitlanguage.org?hp=c3339b626209ac15790791afc023d0c33b57016e Merge: Not null types 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 Reviewed-by: Lucas Bajolet Reviewed-by: Romain Chanoir Reviewed-by: Alexandre Terrasa --- diff --git a/benchmarks/bench_engines.sh b/benchmarks/bench_engines.sh index 62d6a9c..ae91703 100755 --- a/benchmarks/bench_engines.sh +++ b/benchmarks/bench_engines.sh @@ -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 index 0000000..ada48ff --- /dev/null +++ b/benchmarks/markdown/.gitignore @@ -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 index 0000000..802fab6 --- /dev/null +++ b/benchmarks/markdown/Makefile @@ -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/ diff --git a/benchmarks/markdown/benches/Makefile b/benchmarks/markdown/benches/Makefile index 641c47e..4cb8c36 100644 --- a/benchmarks/markdown/benches/Makefile +++ b/benchmarks/markdown/benches/Makefile @@ -14,10 +14,12 @@ # 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 diff --git a/benchmarks/markdown/engines/nitmd/Makefile b/benchmarks/markdown/engines/nitmd/Makefile index 6424382..256ddfe 100644 --- a/benchmarks/markdown/engines/nitmd/Makefile +++ b/benchmarks/markdown/engines/nitmd/Makefile @@ -14,13 +14,15 @@ # 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 index 0000000..0e224dc --- /dev/null +++ b/benchmarks/strings/.gitignore @@ -0,0 +1,4 @@ +arraytos/ +string_concat/ +string_iter/ +string_substr/ diff --git a/benchmarks/strings/Makefile b/benchmarks/strings/Makefile index 82118c9..a6d89bf 100644 --- a/benchmarks/strings/Makefile +++ b/benchmarks/strings/Makefile @@ -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 diff --git a/lib/ai/examples/puzzle.nit b/lib/ai/examples/puzzle.nit index 83c4b4c..0583035 100644 --- a/lib/ai/examples/puzzle.nit +++ b/lib/ai/examples/puzzle.nit @@ -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 diff --git a/src/ffi/extern_classes.nit b/src/ffi/extern_classes.nit index bc4f0c4..4e8f45d 100644 --- a/src/ffi/extern_classes.nit +++ b/src/ffi/extern_classes.nit @@ -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 diff --git a/src/frontend/check_annotation.nit b/src/frontend/check_annotation.nit index 36244f6..ffba4ad 100644 --- a/src/frontend/check_annotation.nit +++ b/src/frontend/check_annotation.nit @@ -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) diff --git a/src/frontend/div_by_zero.nit b/src/frontend/div_by_zero.nit index 4a8cfb4..6001f01 100644 --- a/src/frontend/div_by_zero.nit +++ b/src/frontend/div_by_zero.nit @@ -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) diff --git a/src/frontend/no_warning.nit b/src/frontend/no_warning.nit index 931440e..bc59d8c 100644 --- a/src/frontend/no_warning.nit +++ b/src/frontend/no_warning.nit @@ -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 diff --git a/src/frontend/serialization_phase.nit b/src/frontend/serialization_phase.nit index 2b68eea..0d7e4ec 100644 --- a/src/frontend/serialization_phase.nit +++ b/src/frontend/serialization_phase.nit @@ -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 diff --git a/src/loader.nit b/src/loader.nit index 9d1297b..9876bc4 100644 --- a/src/loader.nit +++ b/src/loader.nit @@ -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 diff --git a/src/model/model.nit b/src/model/model.nit index 6dbcda1..62c3db4 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -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] diff --git a/src/modelbuilder.nit b/src/modelbuilder.nit index 30f5885..23f7d49 100644 --- a/src/modelbuilder.nit +++ b/src/modelbuilder.nit @@ -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 diff --git a/src/modelbuilder_base.nit b/src/modelbuilder_base.nit index 9995338..93423df 100644 --- a/src/modelbuilder_base.nit +++ b/src/modelbuilder_base.nit @@ -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 diff --git a/src/modelize/modelize_class.nit b/src/modelize/modelize_class.nit index c779df9..5618c11 100644 --- a/src/modelize/modelize_class.nit +++ b/src/modelize/modelize_class.nit @@ -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 diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index f5b33af..c224b29 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -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 diff --git a/src/phase.nit b/src/phase.nit index bdec532..502d817 100644 --- a/src/phase.nit +++ b/src/phase.nit @@ -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` diff --git a/src/semantize/auto_super_init.nit b/src/semantize/auto_super_init.nit index d60e2a3..07b4f46 100644 --- a/src/semantize/auto_super_init.nit +++ b/src/semantize/auto_super_init.nit @@ -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 diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index 0634ee2..38a689a 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -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 diff --git a/src/toolcontext.nit b/src/toolcontext.nit index 62c184a..92a4824 100644 --- a/src/toolcontext.nit +++ b/src/toolcontext.nit @@ -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 index 0000000..dd7243b --- /dev/null +++ b/tests/error_virtual_type.nit @@ -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 index 0000000..274bb77 --- /dev/null +++ b/tests/error_virtual_type2.nit @@ -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') diff --git a/tests/sav/base_virtual_type7.res b/tests/sav/base_virtual_type7.res index 0fc0245..01f9a2f 100644 --- a/tests/sav/base_virtual_type7.res +++ b/tests/sav/base_virtual_type7.res @@ -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 diff --git a/tests/sav/error_needed_method_alt4.res b/tests/sav/error_needed_method_alt4.res index 6f7a1f9..f80abe8 100644 --- a/tests/sav/error_needed_method_alt4.res +++ b/tests/sav/error_needed_method_alt4.res @@ -1 +1 @@ -Fatal Error: no primitive class NativeArray +Fatal Error: no primitive class NativeArray in error_needed_method_alt4 diff --git a/tests/sav/error_needed_method_alt7.res b/tests/sav/error_needed_method_alt7.res index 6f7a1f9..2a7c903 100644 --- a/tests/sav/error_needed_method_alt7.res +++ b/tests/sav/error_needed_method_alt7.res @@ -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 index 0000000..417f403 --- /dev/null +++ b/tests/sav/error_virtual_type2.res @@ -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 index 0000000..38cf3dd --- /dev/null +++ b/tests/sav/error_virtual_type2_alt1.res @@ -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 index 0000000..f155524 --- /dev/null +++ b/tests/sav/error_virtual_type2_alt2.res @@ -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 index 0000000..80c9981 --- /dev/null +++ b/tests/sav/error_virtual_type2_alt3.res @@ -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 index 0000000..158622e --- /dev/null +++ b/tests/sav/error_virtual_type2_alt4.res @@ -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 index 0000000..1efe3e7 --- /dev/null +++ b/tests/sav/error_virtual_type2_alt5.res @@ -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 index 0000000..6e05965 --- /dev/null +++ b/tests/sav/error_virtual_type2_alt6.res @@ -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 index 0000000..b87d6c0 --- /dev/null +++ b/tests/sav/error_virtual_type_alt1.res @@ -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 index 0000000..98ff344 --- /dev/null +++ b/tests/sav/error_virtual_type_alt2.res @@ -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 index 0000000..1bad756 --- /dev/null +++ b/tests/sav/error_virtual_type_alt3.res @@ -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 index 0000000..150aef7 --- /dev/null +++ b/tests/sav/error_virtual_type_alt4.res @@ -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 index 0000000..84b89c9 --- /dev/null +++ b/tests/sav/error_virtual_type_alt5.res @@ -0,0 +1 @@ +alt/error_virtual_type_alt5.nit:22,2--28,10: Error: circularity of virtual type definition: T <-> U