X-Git-Url: http://nitlanguage.org diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index df3b33a..b37e4a4 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -301,15 +301,9 @@ private class TypeVisitor #debug("recv: {recvtype} (aka {unsafe_type})") if recvtype isa MNullType then - # `null` only accepts some methods of object. - if name == "==" or name == "!=" or name == "is_same_instance" then - var objclass = get_mclass(node, "Object") - if objclass == null then return null # Forward error - unsafe_type = objclass.mclass_type - else - self.error(node, "Error: method `{name}` called on `null`.") - return null - end + var objclass = get_mclass(node, "Object") + if objclass == null then return null # Forward error + unsafe_type = objclass.mclass_type end var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name) @@ -331,6 +325,14 @@ private class TypeVisitor assert mproperty isa MMethod + # `null` only accepts some methods of object. + if recvtype isa MNullType and not mproperty.is_null_safe then + self.error(node, "Error: method `{name}` called on `null`.") + return null + else if unsafe_type isa MNullableType and not mproperty.is_null_safe then + modelbuilder.advice(node, "call-on-nullable", "Warning: method call on a nullable receiver `{recvtype}`.") + end + if is_toplevel_context and recv_is_self and not mproperty.is_toplevel then error(node, "Error: `{name}` is not a top-level method, thus need a receiver.") end @@ -427,9 +429,39 @@ private class TypeVisitor 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 @@ -438,6 +470,9 @@ private class TypeVisitor 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 @@ -450,6 +485,8 @@ 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] @@ -611,7 +648,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` @@ -723,15 +760,15 @@ redef class AAttrPropdef do if not has_value then return - var mpropdef = self.mpropdef - if mpropdef == null then return # skip error + var mpropdef = self.mreadpropdef + if mpropdef == null or mpropdef.msignature == null then return # skip error var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef) self.selfvariable = v.selfvariable var nexpr = self.n_expr if nexpr != null then - var mtype = self.mpropdef.static_mtype + var mtype = self.mtype v.visit_expr_subtype(nexpr, mtype) end var nblock = self.n_block @@ -923,7 +960,7 @@ redef class AVarReassignExpr v.set_variable(self, variable, rettype) - self.is_typed = true + self.is_typed = rettype != null end end @@ -969,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 @@ -1307,6 +1346,15 @@ redef class AIntExpr end end +redef class AByteExpr + redef fun accept_typing(v) + do + var mclass = v.get_mclass(self, "Byte") + if mclass == null then return # Forward error + self.mtype = mclass.mclass_type + end +end + redef class AFloatExpr redef fun accept_typing(v) do @@ -1655,13 +1703,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 @@ -2020,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 @@ -2031,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