diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 821ad3100e..1308e29ff9 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -1224,8 +1224,8 @@ abstract class AbstractCompilerVisitor res.add(null_instance) continue end - if param.is_vararg and map.vararg_decl > 0 then - var vararg = exprs.sub(j, map.vararg_decl) + if param.is_vararg and args[i].vararg_decl > 0 then + var vararg = exprs.sub(j, args[i].vararg_decl) var elttype = param.mtype var arg = self.vararg_instance(mpropdef, recv, vararg, elttype) res.add(arg) diff --git a/src/compiler/java_compiler.nit b/src/compiler/java_compiler.nit index 84b5a47088..7468d28b93 100644 --- a/src/compiler/java_compiler.nit +++ b/src/compiler/java_compiler.nit @@ -526,8 +526,8 @@ class JavaCompilerVisitor res.add(null_instance) continue end - if param.is_vararg and map.vararg_decl > 0 then - var vararg = exprs.sub(j, map.vararg_decl) + if param.is_vararg and args[i].vararg_decl > 0 then + var vararg = exprs.sub(j, args[i].vararg_decl) var elttype = param.mtype var arg = self.vararg_instance(mpropdef, recv, vararg, elttype) res.add(arg) diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index dc911fd883..299445d866 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -471,8 +471,8 @@ class NaiveInterpreter res.add(null_instance) continue end - if param.is_vararg and map.vararg_decl > 0 then - var vararg = exprs.sub(j, map.vararg_decl) + if param.is_vararg and args[i].vararg_decl > 0 then + var vararg = exprs.sub(j, args[i].vararg_decl) var elttype = param.mtype.anchor_to(self.mainmodule, recv.mtype.as(MClassType)) var arg = self.array_instance(vararg, elttype) res.add(arg) diff --git a/src/model/model.nit b/src/model/model.nit index ccb7522a3f..49ababd547 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -1818,16 +1818,26 @@ class MSignature for i in [0..mparameters.length[ do var parameter = mparameters[i] if parameter.is_vararg then - assert vararg_rank == -1 + if vararg_rank >= 0 then + # If there is more than one vararg, + # consider that additional arguments cannot be mapped. + vararg_rank = -1 + break + end vararg_rank = i end end self.vararg_rank = vararg_rank end - # The rank of the ellipsis (`...`) for vararg (starting from 0). + # The rank of the main ellipsis (`...`) for vararg (starting from 0). # value is -1 if there is no vararg. # Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1 + # + # From a model POV, a signature can contain more than one vararg parameter, + # the `vararg_rank` just indicates the one that will receive the additional arguments. + # However, currently, if there is more that one vararg parameter, no one will be the main one, + # and additional arguments will be refused. var vararg_rank: Int is noinit # The number of parameters diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index 23feb8791a..cd50d4a5db 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -186,11 +186,7 @@ redef class ModelBuilder var sig = mpropdef.msignature if sig == null then continue # Skip broken method - for param in sig.mparameters do - var ret_type = param.mtype - var mparameter = new MParameter(param.name, ret_type, false) - mparameters.add(mparameter) - end + mparameters.add_all sig.mparameters initializers.add(mpropdef.mproperty) mpropdef.mproperty.is_autoinit = true end diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index b4599d0392..aeb3b7efff 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -490,8 +490,12 @@ private class TypeVisitor continue # skip the vararg end - var paramtype = param.mtype - self.visit_expr_subtype(arg, paramtype) + if not param.is_vararg then + var paramtype = param.mtype + self.visit_expr_subtype(arg, paramtype) + else + check_one_vararg(arg, param) + end end if min_arity > 0 then @@ -509,27 +513,9 @@ private class TypeVisitor var paramtype = msignature.mparameters[vararg_rank].mtype var first = args[vararg_rank] if vararg_decl == 0 then - var mclass = get_mclass(node, "Array") - if mclass == null then return null # Forward error - var array_mtype = mclass.get_mtype([paramtype]) - if first isa AVarargExpr then - self.visit_expr_subtype(first.n_expr, array_mtype) - first.mtype = first.n_expr.mtype - else - # only one vararg, maybe `...` was forgot, so be gentle! - var t = visit_expr(first) - if t == null then return null # Forward error - if not is_subtype(t, paramtype) and is_subtype(t, array_mtype) then - # Not acceptable but could be a `...` - error(first, "Type Error: expected `{paramtype}`, got `{t}`. Is an ellipsis `...` missing on the argument?") - return null - end - # Standard valid vararg, finish the job - map.vararg_decl = 1 - self.visit_expr_subtype(first, paramtype) - end + if not check_one_vararg(first, msignature.mparameters[vararg_rank]) then return null else - map.vararg_decl = vararg_decl + 1 + first.vararg_decl = vararg_decl + 1 for i in [vararg_rank..vararg_rank+vararg_decl] do self.visit_expr_subtype(args[i], paramtype) end @@ -539,6 +525,33 @@ private class TypeVisitor return map end + # Check an expression as a single vararg. + # The main point of the method if to handle the case of reversed vararg (see `AVarargExpr`) + fun check_one_vararg(arg: AExpr, param: MParameter): Bool + do + var paramtype = param.mtype + var mclass = get_mclass(arg, "Array") + if mclass == null then return false # Forward error + var array_mtype = mclass.get_mtype([paramtype]) + if arg isa AVarargExpr then + self.visit_expr_subtype(arg.n_expr, array_mtype) + arg.mtype = arg.n_expr.mtype + else + # only one vararg, maybe `...` was forgot, so be gentle! + var t = visit_expr(arg) + if t == null then return false # Forward error + if not is_subtype(t, paramtype) and is_subtype(t, array_mtype) then + # Not acceptable but could be a `...` + error(arg, "Type Error: expected `{paramtype}`, got `{t}`. Is an ellipsis `...` missing on the argument?") + return false + end + # Standard valid vararg, finish the job + arg.vararg_decl = 1 + self.visit_expr_subtype(arg, paramtype) + end + return true + end + fun error(node: ANode, message: String) do self.modelbuilder.error(node, message) @@ -614,10 +627,6 @@ end class SignatureMap # Associate a parameter to an argument var map = new ArrayMap[Int, Int] - - # The length of the vararg sequence - # 0 if no vararg or if reverse vararg (cf `AVarargExpr`) - var vararg_decl: Int = 0 end # A specific method call site with its associated informations. @@ -853,6 +862,15 @@ redef class AExpr # The result of the evaluation of `self` must be # stored inside the designated array (there is an implicit `push`) var comprehension: nullable AArrayExpr = null + + # It indicates the number of arguments collected as a vararg. + # + # When 0, the argument is used as is, without transformation. + # When 1, the argument is transformed into an singleton array. + # Above 1, the arguments and the next ones are transformed into a common array. + # + # This attribute is meaning less on expressions not used as attributes. + var vararg_decl: Int = 0 end redef class ABlockExpr diff --git a/tests/base_vararg_mult.nit b/tests/base_vararg_mult.nit new file mode 100644 index 0000000000..9f9bd0a8bf --- /dev/null +++ b/tests/base_vararg_mult.nit @@ -0,0 +1,51 @@ +# 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 array + +class A + fun x(ints: Int...) is autoinit do + for i in ints do + 'X'.output + i.output + end + '\n'.output + end +end + +class B + super A + fun y(objs: Object...) is autoinit do + for i in objs do + 'Y'.output + i.output + end + '\n'.output + end +end + +var x + +#alt1#x = new A +x = new A(1) +x = new A(10, 20) +x = new A([100, 200, 300]...) + +#aly1#x = new B(1) +x = new B(1, 2) +#alt1#x = new B(1, 2, 3) +#alt1#x = new B([10, 20], 33) +x = new B([10, 11]..., 20) +x = new B(10, [20, 21]...) +x = new B([10, 11]..., [20, 21, 23]...) diff --git a/tests/sav/base_vararg_mult.res b/tests/sav/base_vararg_mult.res new file mode 100644 index 0000000000..2776784bf3 --- /dev/null +++ b/tests/sav/base_vararg_mult.res @@ -0,0 +1,30 @@ +X1 + +X10 +X20 + +X100 +X200 +X300 + +X1 + +Y2 + +X10 +X11 + +Y20 + +X10 + +Y20 +Y21 + +X10 +X11 + +Y20 +Y21 +Y23 + diff --git a/tests/sav/base_vararg_mult_alt1.res b/tests/sav/base_vararg_mult_alt1.res new file mode 100644 index 0000000000..8189994b93 --- /dev/null +++ b/tests/sav/base_vararg_mult_alt1.res @@ -0,0 +1,3 @@ +alt/base_vararg_mult_alt1.nit:40,5--7: Error: expected at least 1 argument(s) for `init(ints: Int...)`; got 0. See introduction at `core::Object::init`. +alt/base_vararg_mult_alt1.nit:47,5--7: Error: expected 2 argument(s) for `init(ints: Int..., objs: Object...)`; got 3. See introduction at `core::Object::init`. +alt/base_vararg_mult_alt1.nit:48,11--18: Type Error: expected `Int`, got `Array[Int]`. Is an ellipsis `...` missing on the argument?