Introduce multi-iterators in `for`.
A single `for` can now iterates over more than one collection at once. An iterator is used for each collection and the iteration is finished once the shortest iterator is finished.
~~~nit
for i in [10, 20, 30], j in [1..10] do print i+j # outputs 11 22 33
~~~
As expected by POLA, multi-iterators are also naturally usable on maps and comprehension arrays
~~~nit
var m = new HashMap[Int,String]
m[1] = "one"
m[2] = "two"
for k, v in m, i in [1..10] do print "{k}:{v}:{i}"
# outputs 1:one:1 2:two:2
var a = [for i in [10, 20, 30], j in [1..10] do i + j]
print a # outputs [11, 22, 33]
~~~
Close #1735
Pull-Request: #1748
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
+ if callsite.is_broken then return null
var initializers = callsite.mpropdef.initializers
if not initializers.is_empty then
var recv = arguments.first
fun stmt(nexpr: nullable AExpr)
do
if nexpr == null then return
- if nexpr.mtype == null and not nexpr.is_typed then
+ if nexpr.is_broken then
# Untyped expression.
# Might mean dead code or invalid code
# so aborts
do
var recv = v.expr(self.n_expr, null)
var callsite = self.callsite.as(not null)
+ if callsite.is_broken then return null
var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
return v.compile_callsite(callsite, args)
end
do
var recv = v.expr(self.n_expr, null)
var callsite = self.callsite.as(not null)
+ if callsite.is_broken then return
var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
var value = v.expr(self.n_value, null)
var callsite = self.callsite
if callsite != null then
+ if callsite.is_broken then return null
var args
if self.n_args.n_exprs.is_empty then
var callsite = self.callsite
if callsite == null then return recv
+ if callsite.is_broken then return null
var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
var res2 = v.compile_callsite(callsite, args)
# Here we load an process all modules passed on the command line
var mmodules = modelbuilder.parse(arguments)
-if mmodules.is_empty then return
+if mmodules.is_empty then
+ toolcontext.check_errors
+ toolcontext.errors_info
+ if toolcontext.error_count > 0 then exit(1) else exit(0)
+end
+
modelbuilder.run_phases
for mmodule in mmodules do
redef class MClass
# Runtime name
- private fun rt_name: String do return "RTClass_{intro.mmodule.jname}_{jname}"
+ private fun rt_name: String do return "RTClass_{intro_mmodule.jname}_{jname}"
# Generate a Java RTClass for a Nit MClass
fun compile_to_java(v: JavaCompilerVisitor) do
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
+ if pd.mproperty.is_broken or pd.is_broken or 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}"
# In a true separate compiler (a with dynamic loading) you cannot do this unfortnally
fun compile_class_to_c(mclass: MClass)
do
+ if mclass.is_broken then return
+
var mtype = mclass.intro.bound_mtype
var c_name = mclass.c_name
if rta != null and not rta.live_methoddefs.has(mpropdef) then
v.add_decl("NULL, /* DEAD {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
continue
+ else if mpropdef.is_broken or mpropdef.msignature == null or mpropdef.mproperty.is_broken then
+ v.add_decl("NULL, /* DEAD (BROKEN) {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
+ continue
end
var rf = mpropdef.virtual_runtime_function
v.require_declaration(rf.c_name)
private fun mclasses_for_mmodule(mmodule: MModule): Set[MClass] do
var mclasses = new HashSet[MClass]
for mclass in self.mclasses do
- if mclass.intro.mmodule == mmodule then
+ if mclass.intro_mmodule == mmodule then
mclasses.add mclass
end
end
var ftype_b: nullable ForeignType = null # FIXME hack to circumvent bug where ftype is typed null
# look in super classes
- for s in in_hierarchy(intro.mmodule).direct_greaters do
+ for s in in_hierarchy(intro_mmodule).direct_greaters do
var super_ftype = s.compute_ftype(v)
if super_ftype != null then
if ftype_b == null then
res.new_field("class").text(mclass.name)
else
res.new_field("redef class").text(mclass.name)
- res.new_field("intro").add mclass.intro.linkto_text("in {mclass.intro.mmodule.to_s}")
+ res.new_field("intro").add mclass.intro.linkto_text("in {mclass.intro_mmodule.to_s}")
end
var mdoc = self.mdoc
if mdoc == null then mdoc = mclass.intro.mdoc
end
redef class CallSite
- super HInfoBoxable
redef fun infobox(v)
do
var res = new HInfoBox(v, "call {mpropdef}")
# Load the imported module
var suppath = seach_module_by_amodule_name(aimport.n_name, mmodule.mgroup)
if suppath == null then
+ mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
continue # Skip error
end
var sup = load_module_path(suppath)
if sup == null then
+ mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
continue # Skip error
end
imported_modules.add(sup)
var mvisibility = aimport.n_visibility.mvisibility
if mvisibility == protected_visibility then
+ mmodule.is_broken = true
error(aimport.n_visibility, "Error: only properties can be protected.")
+ mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
return
end
if sup == mmodule then
error(aimport.n_name, "Error: dependency loop in module {mmodule}.")
+ mmodule.is_broken = true
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}.")
+ mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
return
end
var mod_name = "core"
var sup = self.get_mmodule_by_name(nmodule, null, mod_name)
if sup == null then
+ mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
else # Skip error
imported_modules.add(sup)
redef var to_s: String is noinit
# Is self the definition that introduce the property?
- fun is_intro: Bool do return mproperty.intro == self
+ fun is_intro: Bool do return isset mproperty._intro and mproperty.intro == self
# Return the next definition in linearization of `mtype`.
#
# A Model Entity has a direct link to its model
fun model: Model is abstract
+
+ # The indication that the entity did not pass some semantic verifications.
+ #
+ # This simple flag is set by a given analysis to say that the entity is broken and unusable in
+ # an execution.
+ # When an entity status is set to broken, it is usually associated with a error message.
+ #
+ # If it is safe to do so, clients of the model SHOULD just skip broken entities in their processing.
+ # Clients that do not care about the executability (e.g. metrics) MAY still process the entity or
+ # perform specific checks to determinate the validity of the entity.
+ #
+ # Note that the broken status is not propagated to enclosing and enclosed entities.
+ # e.g. a broken method does not make the whole module broken.
+ var is_broken = false is writable
end
# Something that represents a concern
# Helper function to display an error on a node.
# Alias for `self.toolcontext.error(n.hot_location, text)`
+ #
+ # This automatically sets `n.is_broken` to true.
fun error(n: nullable ANode, text: String)
do
var l = null
- if n != null then l = n.hot_location
+ if n != null then
+ l = n.hot_location
+ n.is_broken = true
+ end
self.toolcontext.error(l, text)
end
end
end
+redef class ANode
+ # The indication that the node did not pass some semantic verifications.
+ #
+ # This simple flag is set by a given analysis to say that the node is broken and unusable in
+ # an execution.
+ # When a node status is set to broken, it is usually associated with a error message.
+ #
+ # If it is safe to do so, clients of the AST SHOULD just skip broken nodes in their processing.
+ # Clients that do not care about the executability (e.g. metrics) MAY still process the node or
+ # perform specific checks to determinate the validity of the node.
+ #
+ # Note that the broken status is not propagated to parent or children nodes.
+ # e.g. a broken expression used as argument does not make the whole call broken.
+ var is_broken = false is writable
+end
+
redef class AType
# The mtype associated to the node
var mtype: nullable MType = null
#print "new class {mclass}"
else if nclassdef isa AStdClassdef and nmodule.mclass2nclassdef.has_key(mclass) then
error(nclassdef, "Error: a class `{name}` is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
+ mclass.is_broken = true
return
else if nclassdef isa AStdClassdef and nclassdef.n_kwredef == null then
error(nclassdef, "Redef Error: `{name}` is an imported class. Add the `redef` keyword to refine it.")
+ mclass.is_broken = true
return
else if arity != 0 and mclass.arity != arity then
error(nclassdef, "Redef Error: expected {mclass.arity} formal parameter(s) for {mclass.signature_to_s}; got {arity}.")
+ mclass.is_broken = true
return
else if nkind != null and mkind != concrete_kind and mclass.kind != mkind then
error(nkind, "Redef Error: refinement changed the kind from `{mclass.kind}` to `{mkind}`.")
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.is_broken = true
mpropdef.bound = mclassdef.mmodule.model.null_type
end
end
mtype = mtype.undecorate
if mtype isa MClassType then
vis_type = mtype.mclass.visibility
- mmodule_type = mtype.mclass.intro.mmodule
+ mmodule_type = mtype.mclass.intro_mmodule
else if mtype isa MVirtualType then
vis_type = mtype.mproperty.visibility
mmodule_type = mtype.mproperty.intro_mclassdef.mmodule
res = false
end
end
+ if not res then is_broken = true
return res
end
end
mprop.is_new = n_kwnew != null
if mprop.is_new then mclassdef.mclass.has_new_factory = true
if name == "sys" then mprop.is_toplevel = true # special case for sys allowed in `new` factories
- self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop)
+ if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop) then
+ mprop.is_broken = true
+ return
+ end
else
+ if mprop.is_broken then
+ return
+ end
if 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)
end
if is_init then
for p, n in mclassdef.mprop2npropdef do
if p != mprop and p isa MMethod and p.name == name then
- check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, p)
+ if not check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, p) then
+ mprop.is_broken = true
+ return
+ end
break
end
end
var mclassdef = mpropdef.mclassdef
var mmodule = mclassdef.mmodule
var nsig = self.n_signature
- var mysignature = self.mpropdef.msignature
+ var mysignature = 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
+ mpropdef.msignature = null # invalidate
+ mpropdef.is_broken = true
return # Forward error
end
end
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
+ mpropdef.msignature = null
+ mpropdef.is_broken = true
return
end
var node = nsig.n_params[i]
if not modelbuilder.check_sametype(node, mmodule, mclassdef.bound_mtype, myt, prt) then
modelbuilder.error(node, "Redef Error: expected `{prt}` for parameter `{mysignature.mparameters[i].name}'; got `{myt}`.")
- self.mpropdef.msignature = null
+ mpropdef.msignature = null
+ mpropdef.is_broken = true
end
end
end
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: expected `{precursor_ret_type}` for return type; got `{ret_type}`.")
- self.mpropdef.msignature = null
+ mpropdef.msignature = null
+ mpropdef.is_broken = true
end
end
end
var msignature = candidatedef.new_msignature or else candidatedef.msignature
msignature = msignature.resolve_for(recvtype, anchor, mmodule, true)
- var callsite = new CallSite(self, recvtype, mmodule, anchor, true, candidate, candidatedef, msignature, false)
+ var callsite = new CallSite(hot_location, recvtype, mmodule, anchor, true, candidate, candidatedef, msignature, false)
auto_super_inits.add(callsite)
modelbuilder.toolcontext.info("Old-style auto-super init for {mpropdef} to {candidate.full_name}", 4)
end
var msignature = candidatedef.new_msignature or else candidatedef.msignature
msignature = msignature.resolve_for(recvtype, anchor, mmodule, true)
- var callsite = new CallSite(self, recvtype, mmodule, anchor, true, the_root_init_mmethod, candidatedef, msignature, false)
+ var callsite = new CallSite(hot_location, recvtype, mmodule, anchor, true, the_root_init_mmethod, candidatedef, msignature, false)
auto_super_inits.add(callsite)
modelbuilder.toolcontext.info("Auto-super init for {mpropdef} to {the_root_init_mmethod.full_name}", 4)
end
module scope
import phase
+import modelbuilder
redef class ToolContext
# Run `APropdef::do_scope` on each propdef.
var res = search_label("")
if res == null then
self.error(nlabel, "Syntax Error: invalid anonymous label.")
+ node.is_broken = true
return null
end
return res
var res = search_label(name)
if res == null then
self.error(nlabel, "Syntax Error: invalid label `{name}`.")
+ node.is_broken = true
return null
end
return res
fun error(node: ANode, message: String)
do
self.toolcontext.error(node.hot_location, message)
+ node.is_broken = true
end
end
end
end
- var callsite = new CallSite(node, recvtype, mmodule, anchor, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
+ var callsite = new CallSite(node.hot_location, recvtype, mmodule, anchor, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
return callsite
end
fun error(node: ANode, message: String)
do
- self.modelbuilder.toolcontext.error(node.hot_location, message)
+ self.modelbuilder.error(node, message)
end
fun get_variable(node: AExpr, variable: Variable): nullable MType
# A specific method call site with its associated informations.
class CallSite
- # The associated node for location
- var node: ANode
+ super MEntity
+
+ # The associated location of the callsite
+ var location: Location
# The static type of the receiver (possibly unresolved)
var recv: MType
# If null then no specific association is required.
var signaturemap: nullable SignatureMap = null
- private fun check_signature(v: TypeVisitor, args: Array[AExpr]): Bool
+ private fun check_signature(v: TypeVisitor, node: ANode, args: Array[AExpr]): Bool
do
- var map = v.check_signature(self.node, args, self.mproperty, self.msignature)
+ var map = v.check_signature(node, args, self.mproperty, self.msignature)
signaturemap = map
+ if map == null then is_broken = true
return map == null
end
end
redef fun visit(n) do
n.visit_all(self)
n.accept_post_typing(type_visitor)
+ if n isa AExpr and n.mtype == null and not n.is_typed then
+ n.is_broken = true
+ end
end
end
var args = compute_raw_arguments
- callsite.check_signature(v, args)
+ callsite.check_signature(v, node, args)
if callsite.mproperty.is_init then
var vmpropdef = v.mpropdef
var args = compute_raw_arguments
- callsite.check_signature(v, args)
+ callsite.check_signature(v, node, args)
var readtype = callsite.msignature.return_mtype
if readtype == null then
args = args.to_a # duplicate so raw_arguments keeps only the getter args
args.add(self.n_value)
- wcallsite.check_signature(v, args)
+ wcallsite.check_signature(v, node, args)
self.is_typed = true
end
var msignature = superprop.new_msignature or else superprop.msignature.as(not null)
msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
- var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
+ var callsite = new CallSite(hot_location, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
self.callsite = callsite
var args = self.n_args.to_a
if args.length > 0 then
- callsite.check_signature(v, args)
+ callsite.check_signature(v, self, args)
else
# Check there is at least enough parameters
if mpropdef.msignature.arity < msignature.arity then
end
var args = n_args.to_a
- callsite.check_signature(v, args)
+ callsite.check_signature(v, node, args)
end
end
visit_all(v)
- if mtype == null and not is_typed then return # Skip broken
+ if is_broken then return # Skip broken
accept_transform_visitor(v)
end
# ~~~
redef fun full_transform_visitor(v)
do
+ if is_broken then return # Skip broken
+
var nblock = v.builder.make_block
var nnew = v.builder.make_new(with_capacity_callsite.as(not null), [v.builder.make_int(n_exprs.length)])
base_attr_abstract.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
base_attr_abstract.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property.
-base_attr_abstract.nit:37,15: Error: untyped parameter `x'.
alt/base_attr_abstract_alt1.nit:22,15--22: Error: `abstract` attributes cannot have an initial value.
alt/base_attr_abstract_alt1.nit:23,15--22: Error: `abstract` attributes cannot have an initial value.
alt/base_attr_abstract_alt1.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property.
-alt/base_attr_abstract_alt1.nit:37,15: Error: untyped parameter `x'.
alt/base_attr_abstract_alt2.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
alt/base_attr_abstract_alt2.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property.
-alt/base_attr_abstract_alt2.nit:37,15: Error: untyped parameter `x'.
alt/base_attr_abstract_alt3.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
alt/base_attr_abstract_alt3.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property.
-alt/base_attr_abstract_alt3.nit:37,15: Error: untyped parameter `x'.
alt/base_attr_abstract_alt4.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
alt/base_attr_abstract_alt4.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property.
-alt/base_attr_abstract_alt4.nit:37,15: Error: untyped parameter `x'.
alt/error_redef_alt3.nit:28,12--13: Error: no property `B::f1` is inherited. Remove the `redef` keyword to define a new property.
-alt/error_redef_alt3.nit:28,15: Error: untyped parameter `i'.
alt/error_redef_alt6.nit:31,12--13: Error: no property `B::f1` is inherited. Remove the `redef` keyword to define a new property.
-alt/error_redef_alt6.nit:31,15: Error: untyped parameter `i'.
alt/error_redef_alt9.nit:34,12--13: Error: no property `B::f1` is inherited. Remove the `redef` keyword to define a new property.
-alt/error_redef_alt9.nit:34,15: Error: untyped parameter `i'.