Merge: Keep going toolcontext
authorJean Privat <jean@pryen.org>
Thu, 4 Dec 2014 03:29:33 +0000 (22:29 -0500)
committerJean Privat <jean@pryen.org>
Thu, 4 Dec 2014 03:29:33 +0000 (22:29 -0500)
For a compiler, exiting when the source-code is incoherent make sense. However for some tools, like nitlight, it could be useful to be able to process broken code (or just to ignore it and continue).

So, this PR introduce the flag `ToolContext::keep_going` to prevent `check_errors` to terminate the program. It is then the responsibility of the tool to manage the incomplete and possibly incoherent model that was produced.

Close #863

Pull-Request: #959
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>

1  2 
src/model/model.nit
src/modelize/modelize_property.nit

diff --combined src/model/model.nit
@@@ -263,7 -263,7 +263,7 @@@ redef class MModul
                        var msg = "Fatal Error: more than one primitive class {name}:"
                        for c in cla do msg += " {c.full_name}"
                        print msg
-                       exit(1)
+                       #exit(1)
                end
                return cla.first
        end
@@@ -388,7 -388,7 +388,7 @@@ class MClas
                        self.mparameters = mparametertypes
                        var mclass_type = new MGenericType(self, mparametertypes)
                        self.mclass_type = mclass_type
 -                      self.get_mtype_cache.add(mclass_type)
 +                      self.get_mtype_cache[mparametertypes] = mclass_type
                else
                        self.mclass_type = new MClassType(self)
                end
        do
                assert mtype_arguments.length == self.arity
                if self.arity == 0 then return self.mclass_type
 -              for t in self.get_mtype_cache do
 -                      if t.arguments == mtype_arguments then
 -                              return t
 -                      end
 -              end
 -              var res = new MGenericType(self, mtype_arguments)
 -              self.get_mtype_cache.add res
 +              var res = get_mtype_cache.get_or_null(mtype_arguments)
 +              if res != null then return res
 +              res = new MGenericType(self, mtype_arguments)
 +              self.get_mtype_cache[mtype_arguments.to_a] = res
                return res
        end
  
 -      private var get_mtype_cache = new Array[MGenericType]
 +      private var get_mtype_cache = new HashMap[Array[MType], MGenericType]
  end
  
  
@@@ -729,7 -732,6 +729,7 @@@ abstract class MTyp
        # types to their bounds.
        #
        # Example
 +      #
        #     class A end
        #     class B super A end
        #     class X end
        #       super G[B]
        #       redef type U: Y
        #     end
 +      #
        # Map[T,U]  anchor_to  H  #->  Map[B,Y]
        #
        # Explanation of the example:
        # In Nit, for each super-class of a type, there is a equivalent super-type.
        #
        # Example:
 +      #
 +      # ~~~nitish
        #     class G[T, U] end
        #     class H[V] super G[V, Bool] end
 +      #
        # H[Int]  supertype_to  G  #->  G[Int, Bool]
 +      # ~~~
        #
        # REQUIRE: `super_mclass` is a super-class of `self`
        # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
        #
        # ## Example 1
        #
 -      #     class G[E] end
 -      #     class H[F] super G[F] end
 -      #     class X[Z] end
 +      # ~~~
 +      # class G[E] end
 +      # class H[F] super G[F] end
 +      # class X[Z] end
 +      # ~~~
        #
        #  * Array[E].resolve_for(H[Int])  #->  Array[Int]
        #  * Array[E].resolve_for(G[Z], X[Int]) #->  Array[Z]
        #
        # ## Example 2
        #
 -      #     class A[E]
 -      #         fun foo(e:E):E is abstract
 -      #     end
 -      #     class B super A[Int] end
 +      # ~~~
 +      # class A[E]
 +      #     fun foo(e:E):E is abstract
 +      # end
 +      # class B super A[Int] end
 +      # ~~~
        #
        # The signature on foo is (e: E): E
        # If we resolve the signature for B, we get (e:Int):Int
        #
        # ## Example 3
        #
 -      #     class A[E]
 -      #         fun foo(e:E) is abstract
 -      #     end
 -      #     class B[F]
 -      #         var a: A[Array[F]]
 -      #         fun bar do a.foo(x) # <- x is here
 -      #     end
 +      # ~~~nitish
 +      # class A[E]
 +      #     fun foo(e:E):E is abstract
 +      # end
 +      # class C[F]
 +      #     var a: A[Array[F]]
 +      #     fun bar do a.foo(x) # <- x is here
 +      # end
 +      # ~~~
        #
        # The first question is: is foo available on `a`?
        #
        # The static type of a is `A[Array[F]]`, that is an open type.
        # in order to find a method `foo`, whe must look at a resolved type.
        #
 -      #   A[Array[F]].anchor_to(B[nullable Object])  #->  A[Array[nullable Object]]
 +      #   A[Array[F]].anchor_to(C[nullable Object])  #->  A[Array[nullable Object]]
        #
        # the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
        #
        #
        # the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
        #
 -      #   E.resolve_for(A[Array[F]],B[nullable Object])  #->  Array[F]
 +      #   E.resolve_for(A[Array[F]],C[nullable Object])  #->  Array[F]
        #
        # The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
        #
        #     class B[F]
        #     end
        #
 -      #  * E.can_resolve_for(A[Int])  #->  true, E make sense in A
 -      #  * E.can_resolve_for(B[Int])  #->  false, E does not make sense in B
 -      #  * B[E].can_resolve_for(A[F], B[Object])  #->  true,
 -      #    B[E] is a red hearing only the E is important,
 -      #    E make sense in A
 +      # ~~~nitish
 +      # E.can_resolve_for(A[Int])  #->  true, E make sense in A
 +      #
 +      # E.can_resolve_for(B[Int])  #->  false, E does not make sense in B
 +      #
 +      # B[E].can_resolve_for(A[F], B[Object])  #->  true,
 +      # # B[E] is a red hearing only the E is important,
 +      # # E make sense in A
 +      # ~~~
        #
        # REQUIRE: `anchor != null implies not anchor.need_anchor`
        # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
@@@ -1030,21 -1017,14 +1030,21 @@@ class MClassTyp
  
        redef fun collect_mclasses(mmodule)
        do
 +              if collect_mclasses_last_module == mmodule then return collect_mclasses_last_module_cache
                assert not self.need_anchor
                var cache = self.collect_mclasses_cache
                if not cache.has_key(mmodule) then
                        self.collect_things(mmodule)
                end
 -              return cache[mmodule]
 +              var res = cache[mmodule]
 +              collect_mclasses_last_module = mmodule
 +              collect_mclasses_last_module_cache = res
 +              return res
        end
  
 +      private var collect_mclasses_last_module: nullable MModule = null
 +      private var collect_mclasses_last_module_cache: Set[MClass] is noinit
 +
        redef fun collect_mtypes(mmodule)
        do
                assert not self.need_anchor
  # directly to the parameter types of the super-classes.
  #
  # Example:
 +#
  #     class A[E]
  #         fun e: E is abstract
  #     end
  #     class B[F]
  #         super A[Array[F]]
  #     end
 +#
  # In the class definition B[F], `F` is a valid type but `E` is not.
  # However, `self.e` is a valid method call, and the signature of `e` is
  # declared `e: E`.
@@@ -175,7 -175,8 +175,8 @@@ redef class ModelBuilde
                # Look for most-specific new-stype init definitions
                var spropdefs = the_root_init_mmethod.lookup_super_definitions(mclassdef.mmodule, mclassdef.bound_mtype)
                if spropdefs.is_empty then
-                       toolcontext.fatal_error(nclassdef.location, "Fatal error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
+                       toolcontext.error(nclassdef.location, "Error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
+                       return
                end
  
                # Search the longest-one and checks for conflict
@@@ -618,7 -619,7 +619,7 @@@ redef class AMethPropde
                        mprop.is_init = is_init
                        mprop.is_new = n_kwnew != null
                        if parent isa ATopClassdef then mprop.is_toplevel = true
-                       if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop) then return
+                       self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop)
                else
                        if not mprop.is_root_init and not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, not self isa AMainMethPropdef, mprop) then return
                        check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
@@@ -945,13 -946,11 +946,13 @@@ redef class AAttrPropde
                        if mtype == null then return
                end
  
 +              var inherited_type: nullable MType = null
                # Inherit the type from the getter (usually an abstract getter)
 -              if mtype == null and mreadpropdef != null and not mreadpropdef.is_intro then
 +              if mreadpropdef != null and not mreadpropdef.is_intro then
                        var msignature = mreadpropdef.mproperty.intro.msignature
                        if msignature == null then return # Error, thus skipped
 -                      mtype = msignature.return_mtype
 +                      inherited_type = msignature.return_mtype
 +                      if mtype == null then mtype = inherited_type
                end
  
                var nexpr = self.n_expr
  
                                if mtype == null then return
                        end
 -              else if ntype != null then
 +              else if ntype != null and inherited_type == mtype then
                        if nexpr isa ANewExpr then
                                var xmtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
                                if xmtype == mtype then
@@@ -1195,7 -1194,8 +1196,8 @@@ redef class ATypePropde
                # Check redefinitions
                bound = mpropdef.bound.as(not null)
                for p in mpropdef.mproperty.lookup_super_definitions(mmodule, anchor) do
-                       var supbound = p.bound.as(not null)
+                       var supbound = p.bound
+                       if supbound == null then break # broken super bound, skip error
                        if p.is_fixed then
                                modelbuilder.error(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
                                break