X-Git-Url: http://nitlanguage.org diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index 8fe169d..8a4e13f 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -105,13 +105,13 @@ private class TypeVisitor # If `sub` is a safe subtype of `sup` then return `sub`. # If `sub` is an unsafe subtype (ie an implicit cast is required), then return `sup`. # - # The point of the return type is to determinate the usable type on an expression: + # The point of the return type is to determinate the usable type on an expression when `autocast` is true: # If the suptype is safe, then the return type is the one on the expression typed by `sub`. # Is the subtype is unsafe, then the return type is the one of an implicit cast on `sup`. - fun check_subtype(node: ANode, sub, sup: MType): nullable MType + fun check_subtype(node: ANode, sub, sup: MType, autocast: Bool): nullable MType do if self.is_subtype(sub, sup) then return sub - if self.is_subtype(sub, self.anchor_to(sup)) then + if autocast and self.is_subtype(sub, self.anchor_to(sup)) then # FIXME workaround to the current unsafe typing policy. To remove once fixed virtual types exists. #node.debug("Unsafe typing: expected {sup}, got {sub}") return sup @@ -166,7 +166,7 @@ private class TypeVisitor if sup == null then return null # Forward error - var res = check_subtype(nexpr, sub, sup) + var res = check_subtype(nexpr, sub, sup, true) if res != sub then nexpr.implicit_cast_to = res end @@ -407,8 +407,18 @@ private class TypeVisitor return null end else if args.length != msignature.arity then - modelbuilder.error(node, "Error: expected {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.") - return null + if msignature.arity == msignature.min_arity then + modelbuilder.error(node, "Error: expected {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.") + return null + end + if args.length > msignature.arity then + modelbuilder.error(node, "Error: expected at most {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.") + return null + end + if args.length < msignature.min_arity then + modelbuilder.error(node, "Error: expected at least {msignature.min_arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.") + return null + end end #debug("CALL {unsafe_type}.{msignature}") @@ -416,10 +426,51 @@ private class TypeVisitor # Associate each parameter to a position in the arguments var map = new SignatureMap + var setted = args.length - msignature.min_arity + + # First, handle named arguments + for i in [0..args.length[ do + var e = args[i] + if not e isa ANamedargExpr then continue + var name = e.n_id.text + var param = msignature.mparameter_by_name(name) + if param == null then + modelbuilder.error(e.n_id, "Error: no parameter `{name}` for `{mproperty}{msignature}`.") + return null + end + if not param.is_default then + modelbuilder.error(e, "Error: parameter `{name}` is not optional for `{mproperty}{msignature}`.") + return null + end + var idx = msignature.mparameters.index_of(param) + var prev = map.map.get_or_null(idx) + if prev != null then + modelbuilder.error(e, "Error: parameter `{name}` already associated with argument #{prev} for `{mproperty}{msignature}`.") + return null + end + map.map[idx] = i + setted -= 1 + e.mtype = self.visit_expr_subtype(e.n_expr, param.mtype) + end + + # Second, associate remaining parameters var vararg_decl = args.length - msignature.arity var j = 0 for i in [0..msignature.arity[ do + # Skip parameters associated by name + if map.map.has_key(i) then continue + var param = msignature.mparameters[i] + if param.is_default then + if setted > 0 then + setted -= 1 + else + continue + end + end + + # Search the next free argument: skip named arguments since they are already associated + while args[j] isa ANamedargExpr do j += 1 var arg = args[j] map.map[i] = j j += 1 @@ -432,15 +483,31 @@ private class TypeVisitor var paramtype = param.mtype self.visit_expr_subtype(arg, paramtype) end + + # Third, check varargs if vararg_rank >= 0 then var paramtype = msignature.mparameters[vararg_rank].mtype var first = args[vararg_rank] - if vararg_decl == 0 and first isa AVarargExpr then + 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]) - self.visit_expr_subtype(first.n_expr, array_mtype) - first.mtype = first.n_expr.mtype + 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 else map.vararg_decl = vararg_decl + 1 for i in [vararg_rank..vararg_rank+vararg_decl] do @@ -579,7 +646,7 @@ end redef class Variable # The declared type of the variable - var declared_type: nullable MType + var declared_type: nullable MType is writable # Was the variable type-adapted? # This is used to speedup type retrieval while it remains `false` @@ -868,7 +935,7 @@ redef class AReassignFormExpr var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype) if value_type == null then return null # Skip error - v.check_subtype(self, rettype, writetype) + v.check_subtype(self, rettype, writetype, false) return rettype end end @@ -1360,7 +1427,7 @@ redef class AArrayExpr end set_comprehension(e) if mtype != null then - if v.check_subtype(e, t, mtype) == null then return # Skip error + if v.check_subtype(e, t, mtype, false) == null then return # Forward error if t == mtype then useless = true else mtypes.add(t) @@ -1623,13 +1690,8 @@ redef class ANeExpr end end -redef class AUplusExpr - redef fun property_name do return "unary +" - redef fun compute_raw_arguments do return new Array[AExpr] -end - -redef class AUminusExpr - redef fun property_name do return "unary -" +redef class AUnaryopExpr + redef fun property_name do return "unary {operator}" redef fun compute_raw_arguments do return new Array[AExpr] end