From: Jean Privat Date: Mon, 8 Jun 2015 10:05:14 +0000 (-0400) Subject: Merge: More keep going X-Git-Tag: v0.7.6~61 X-Git-Url: http://nitlanguage.org?hp=8a1e5b72b98280425bdfaa0c4eb64d8b52411502 Merge: More keep going This improve the robustness of tools when given --keep-going. Tools like nitpick, that have --keep-going by default, are more robust and collect more errors. Moreover, the compiler can now compile simple programs with instructions that fail during the typing phase (most errors like unknown method or bad type). These instructions are compiled with a run time error instead so the program is still expected to behave in an reliable way. ~~~nit print 1 fail now print 2 ~~~ ~~~sh $ nitc kg.nit --keep-going kg.nit:2,1--4: Error: method or variable `fail` unknown in `Sys`. $ ./kg 1 Runtime error: FATAL: bad statement executed. (kg.nit:1) ~~~ One usage would be to force `c_src` to compile things even if it lags behind. Pull-Request: #1440 Reviewed-by: Lucas Bajolet Reviewed-by: Alexis Laferrière Reviewed-by: Romain Chanoir --- diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index a095201..9d3b0f3 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -1672,8 +1672,9 @@ abstract class AbstractCompilerVisitor if nexpr == null then return if nexpr.mtype == null and not nexpr.is_typed then # Untyped expression. - # Might mean dead code - # So just return + # Might mean dead code or invalid code + # so aborts + add_abort("FATAL: bad statement executed.") return end @@ -1697,8 +1698,10 @@ abstract class AbstractCompilerVisitor do if nexpr.mtype == null then # Untyped expression. - # Might mean dead code - # so return a placebo result + # Might mean dead code or invalid code. + # so aborts + add_abort("FATAL: bad expression executed.") + # and return a placebo result to please the C compiler if mtype == null then mtype = compiler.mainmodule.object_type return new_var(mtype) end diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index f50a2a7..e07f125 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -625,6 +625,7 @@ class SeparateCompiler for cd in mmodule.mclassdefs do for pd in cd.mpropdefs do if not pd isa MMethodDef then continue + if pd.msignature == null then continue # Skip broken method var rta = runtime_type_analysis if modelbuilder.toolcontext.opt_skip_dead_methods.value and rta != null and not rta.live_methoddefs.has(pd) then continue #print "compile {pd} @ {cd} @ {mmodule}" diff --git a/src/phase.nit b/src/phase.nit index 5f0faf1..682d23e 100644 --- a/src/phase.nit +++ b/src/phase.nit @@ -115,7 +115,6 @@ redef class ToolContext phase.process_nmodule(nmodule) if errcount != self.error_count then self.check_errors - break end errcount = self.error_count for nclassdef in nmodule.n_classdefs do @@ -128,7 +127,6 @@ redef class ToolContext end if errcount != self.error_count then self.check_errors - break end for na in vannot.annotations do var p = na.parent @@ -138,7 +136,6 @@ redef class ToolContext end if errcount != self.error_count then self.check_errors - break end end self.check_errors diff --git a/src/rapid_type_analysis.nit b/src/rapid_type_analysis.nit index e27a98e..d81d1c7 100644 --- a/src/rapid_type_analysis.nit +++ b/src/rapid_type_analysis.nit @@ -218,13 +218,16 @@ class RapidTypeAnalysis while not todo.is_empty do var mmethoddef = todo.shift var mmeth = mmethoddef.mproperty + var msignature = mmethoddef.msignature + if msignature == null then continue # Skip broken method + #print "# visit {mmethoddef}" var v = new RapidTypeVisitor(self, mmethoddef.mclassdef.bound_mtype, mmethoddef) - var vararg_rank = mmethoddef.msignature.vararg_rank + var vararg_rank = msignature.vararg_rank if vararg_rank > -1 then var node = self.modelbuilder.mpropdef2node(mmethoddef) - var elttype = mmethoddef.msignature.mparameters[vararg_rank].mtype + var elttype = msignature.mparameters[vararg_rank].mtype #elttype = elttype.anchor_to(self.mainmodule, v.receiver) var vararg = self.mainmodule.array_type(elttype) v.add_type(vararg) @@ -234,7 +237,7 @@ class RapidTypeAnalysis end # TODO? new_msignature - var sig = mmethoddef.msignature.as(not null) + var sig = msignature var osig = mmeth.intro.msignature.as(not null) for i in [0..sig.arity[ do var origtype = osig.mparameters[i].mtype @@ -255,7 +258,7 @@ class RapidTypeAnalysis continue else if mmethoddef.constant_value != null then # Make the return type live - v.add_type(mmethoddef.msignature.return_mtype.as(MClassType)) + v.add_type(msignature.return_mtype.as(MClassType)) continue else if npropdef == null then abort @@ -275,7 +278,7 @@ class RapidTypeAnalysis if mmethoddef.is_intern or mmethoddef.is_extern then # UGLY: We force the "instantation" of the concrete return type if any - var ret = mmethoddef.msignature.return_mtype + var ret = msignature.return_mtype if ret != null and ret isa MClassType and ret.mclass.kind != abstract_kind and ret.mclass.kind != interface_kind then v.add_type(ret) end @@ -297,10 +300,10 @@ class RapidTypeAnalysis if not ot.can_resolve_for(t, t, mainmodule) then continue var rt = ot.anchor_to(mainmodule, t) if live_types.has(rt) then continue + if not check_depth(rt) then continue #print "{ot}/{t} -> {rt}" live_types.add(rt) todo_types.add(rt) - check_depth(rt) end end #print "MType {live_types.length}: {live_types.join(", ")}" @@ -318,12 +321,14 @@ class RapidTypeAnalysis #print "cast MType {live_cast_types.length}: {live_cast_types.join(", ")}" end - private fun check_depth(mtype: MClassType) + private fun check_depth(mtype: MClassType): Bool do var d = mtype.length if d > 255 then self.modelbuilder.toolcontext.fatal_error(null, "Fatal Error: limitation in the rapidtype analysis engine: a type depth of {d} is too important, the problematic type is `{mtype}`.") + return false end + return true end fun add_new(recv: MClassType, mtype: MClassType) @@ -450,10 +455,14 @@ class RapidTypeVisitor redef fun visit(n) do - n.accept_rapid_type_visitor(self) if n isa AExpr then - var implicit_cast_to = n.implicit_cast_to - if implicit_cast_to != null then self.add_cast_type(implicit_cast_to) + if n.mtype != null or n.is_typed then + n.accept_rapid_type_visitor(self) + var implicit_cast_to = n.implicit_cast_to + if implicit_cast_to != null then self.add_cast_type(implicit_cast_to) + end + else + n.accept_rapid_type_visitor(self) end # RTA does not enter in AAnnotations diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index 44ed320..4aad2d2 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -960,7 +960,7 @@ redef class AVarReassignExpr v.set_variable(self, variable, rettype) - self.is_typed = true + self.is_typed = rettype != null end end @@ -1006,9 +1006,11 @@ redef class AReturnExpr else v.visit_expr(nexpr) v.error(nexpr, "Error: `return` with value in a procedure.") + return end else if ret_type != null then v.error(self, "Error: `return` without value in a function.") + return end self.is_typed = true end @@ -2061,7 +2063,7 @@ redef class AAttrAssignExpr var mtype = self.attr_type v.visit_expr_subtype(self.n_value, mtype) - self.is_typed = true + self.is_typed = mtype != null end end @@ -2072,9 +2074,9 @@ redef class AAttrReassignExpr var mtype = self.attr_type if mtype == null then return # Skip error - self.resolve_reassignment(v, mtype, mtype) + var rettype = self.resolve_reassignment(v, mtype, mtype) - self.is_typed = true + self.is_typed = rettype != null end end diff --git a/src/transform.nit b/src/transform.nit index ebe2c73..838b9bc 100644 --- a/src/transform.nit +++ b/src/transform.nit @@ -104,7 +104,12 @@ redef class AExpr var nadd = v.builder.make_call(recv, na.push_callsite.as(not null), [self]) place.replace_with(nadd) end - super + + visit_all(v) + + if mtype == null and not is_typed then return # Skip broken + + accept_transform_visitor(v) end redef fun replace_with(other) diff --git a/tests/base_adaptive_loop3.nit b/tests/base_adaptive_loop3.nit index 33f4c8d..42e331a 100644 --- a/tests/base_adaptive_loop3.nit +++ b/tests/base_adaptive_loop3.nit @@ -27,4 +27,5 @@ while t2 != null do t2 = t2.next #alt2# t2 = null end #alt3#t2 = t2.next + #alt3#exit(0) end diff --git a/tests/base_adaptive_loop_null.nit b/tests/base_adaptive_loop_null.nit index cfbb80f..e342e07 100644 --- a/tests/base_adaptive_loop_null.nit +++ b/tests/base_adaptive_loop_null.nit @@ -48,6 +48,6 @@ loop if i != null then bar(i) else - break #alt4# + break #alt4# exit(0) end end diff --git a/tests/sav/test_keep_going.res b/tests/sav/test_keep_going.res new file mode 100644 index 0000000..346b309 --- /dev/null +++ b/tests/sav/test_keep_going.res @@ -0,0 +1 @@ +test_keep_going.nit:15,11--14: Error: class `Fail` not found in module `test_keep_going`. diff --git a/tests/test_keep_going.nit b/tests/test_keep_going.nit new file mode 100755 index 0000000..b3bedaa --- /dev/null +++ b/tests/test_keep_going.nit @@ -0,0 +1,47 @@ +# 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. + +fun plop: Fail +do + print 1 +end + +1.output +if false then + plop +end +2.output +if false then + fail +end +3.output +if false then + var x = new Fail + x.output +end +4.output +if false then + if 1 then abort +end +5.output +if false then + abort + 999.output +end +6.output +if false then + var a = new Sys.fail + a.output +end +7.output