X-Git-Url: http://nitlanguage.org diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index bd63c0f..83bebc2 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -47,7 +47,7 @@ private class TypeVisitor # The analyzed property var mpropdef: nullable MPropDef - var selfvariable: Variable = new Variable("self") + var selfvariable = new Variable("self") # Is `self` use restricted? # * no explicit `self` @@ -195,6 +195,40 @@ private class TypeVisitor return sup end + # Special verification on != and == for null + # Return true + fun null_test(anode: ABinopExpr) + do + var mtype = anode.n_expr.mtype + var mtype2 = anode.n_expr2.mtype + + if mtype == null or mtype2 == null then return + + if not mtype2 isa MNullType then return + + # Check of useless null + if not mtype isa MNullableType then + if not anchor_to(mtype) isa MNullableType then + modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}`.") + end + return + end + + # Check for type adaptation + var variable = anode.n_expr.its_variable + if variable == null then return + + if anode isa AEqExpr then + anode.after_flow_context.when_true.set_var(variable, mtype2) + anode.after_flow_context.when_false.set_var(variable, mtype.mtype) + else if anode isa ANeExpr then + anode.after_flow_context.when_false.set_var(variable, mtype2) + anode.after_flow_context.when_true.set_var(variable, mtype.mtype) + else + abort + end + end + fun try_get_mproperty_by_name2(anode: ANode, mtype: MType, name: String): nullable MProperty do return self.modelbuilder.try_get_mproperty_by_name2(anode, mmodule, mtype, name) @@ -238,6 +272,11 @@ private class TypeVisitor end var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name) + if name == "new" and mproperty == null then + name = "init" + mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name) + end + if mproperty == null then #self.modelbuilder.error(node, "Type error: property {name} not found in {unsafe_type} (ie {recvtype})") if recv_is_self then @@ -343,11 +382,18 @@ private class TypeVisitor self.visit_expr_subtype(args[j], paramtype) end if vararg_rank >= 0 then - var varargs = new Array[AExpr] var paramtype = msignature.mparameters[vararg_rank].mtype - for j in [vararg_rank..vararg_rank+vararg_decl] do - varargs.add(args[j]) - self.visit_expr_subtype(args[j], paramtype) + var first = args[vararg_rank] + if vararg_decl == 0 and first isa AVarargExpr then + var mclass = get_mclass(node, "Array") + if mclass == null then return false # Forward error + var array_mtype = mclass.get_mtype([paramtype]) + self.visit_expr_subtype(first.n_expr, array_mtype) + first.mtype = first.n_expr.mtype + else + for j in [vararg_rank..vararg_rank+vararg_decl] do + self.visit_expr_subtype(args[j], paramtype) + end end end return true @@ -395,7 +441,6 @@ private class TypeVisitor fun merge_types(node: ANode, col: Array[nullable MType]): nullable MType do if col.length == 1 then return col.first - var res = new Array[nullable MType] for t1 in col do if t1 == null then continue # return null var found = true @@ -461,8 +506,8 @@ end redef class FlowContext # Store changes of types because of type evolution - private var vars: HashMap[Variable, nullable MType] = new HashMap[Variable, nullable MType] - private var cache: HashMap[Variable, nullable Array[nullable MType]] = new HashMap[Variable, nullable Array[nullable MType]] + private var vars = new HashMap[Variable, nullable MType] + private var cache = new HashMap[Variable, nullable Array[nullable MType]] # Adapt the variable to a static type # Warning1: do not modify vars directly. @@ -747,7 +792,7 @@ redef class AContinueExpr do var nexpr = self.n_expr if nexpr != null then - var mtype = v.visit_expr(nexpr) + v.visit_expr(nexpr) end self.is_typed = true end @@ -758,7 +803,7 @@ redef class ABreakExpr do var nexpr = self.n_expr if nexpr != null then - var mtype = v.visit_expr(nexpr) + v.visit_expr(nexpr) end self.is_typed = true end @@ -771,9 +816,9 @@ redef class AReturnExpr var ret_type = v.mpropdef.as(MMethodDef).msignature.return_mtype if nexpr != null then if ret_type != null then - var mtype = v.visit_expr_subtype(nexpr, ret_type) + v.visit_expr_subtype(nexpr, ret_type) else - var mtype = v.visit_expr(nexpr) + v.visit_expr(nexpr) v.error(self, "Error: Return with value in a procedure.") end else if ret_type != null then @@ -1223,9 +1268,9 @@ redef class AIsaExpr var variable = self.n_expr.its_variable if variable != null then - var orig = self.n_expr.mtype - var from = if orig != null then orig.to_s else "invalid" - var to = if mtype != null then mtype.to_s else "invalid" + #var orig = self.n_expr.mtype + #var from = if orig != null then orig.to_s else "invalid" + #var to = if mtype != null then mtype.to_s else "invalid" #debug("adapt {variable}: {from} -> {to}") self.after_flow_context.when_true.set_var(variable, mtype) end @@ -1270,7 +1315,14 @@ redef class AAsNotnullExpr end end -redef class AProxyExpr +redef class AParExpr + redef fun accept_typing(v) + do + self.mtype = v.visit_expr(self.n_expr) + end +end + +redef class AOnceExpr redef fun accept_typing(v) do self.mtype = v.visit_expr(self.n_expr) @@ -1352,16 +1404,7 @@ redef class AEqExpr redef fun accept_typing(v) do super - - var variable = self.n_expr.its_variable - if variable == null then return - var mtype = self.n_expr2.mtype - if not mtype isa MNullType then return - var vartype = v.get_variable(self, variable) - if not vartype isa MNullableType then return - self.after_flow_context.when_true.set_var(variable, mtype) - self.after_flow_context.when_false.set_var(variable, vartype.mtype) - #debug("adapt {variable}:{vartype} ; true->{mtype} false->{vartype.mtype}") + v.null_test(self) end end redef class ANeExpr @@ -1369,16 +1412,7 @@ redef class ANeExpr redef fun accept_typing(v) do super - - var variable = self.n_expr.its_variable - if variable == null then return - var mtype = self.n_expr2.mtype - if not mtype isa MNullType then return - var vartype = v.get_variable(self, variable) - if not vartype isa MNullableType then return - self.after_flow_context.when_false.set_var(variable, mtype) - self.after_flow_context.when_true.set_var(variable, vartype.mtype) - #debug("adapt {variable}:{vartype} ; true->{vartype.mtype} false->{mtype}") + v.null_test(self) end end redef class ALtExpr @@ -1646,11 +1680,13 @@ redef class ANewExpr # The constructor invoked by the new. var callsite: nullable CallSite + # The designated type + var recvtype: nullable MClassType + redef fun accept_typing(v) do var recvtype = v.resolve_mtype(self.n_type) if recvtype == null then return - self.mtype = recvtype if not recvtype isa MClassType then if recvtype isa MNullableType then @@ -1660,26 +1696,34 @@ redef class ANewExpr v.error(self, "Type error: cannot instantiate the formal type {recvtype}.") return end - else - if recvtype.mclass.kind == abstract_kind then - v.error(self, "Cannot instantiate abstract class {recvtype}.") - return - else if recvtype.mclass.kind == interface_kind then - v.error(self, "Cannot instantiate interface {recvtype}.") - return - end end + self.recvtype = recvtype + var name: String var nid = self.n_id if nid != null then name = nid.text else - name = "init" + name = "new" end var callsite = v.get_method(self, recvtype, name, false) if callsite == null then return + if not callsite.mproperty.is_new then + if recvtype.mclass.kind == abstract_kind then + v.error(self, "Cannot instantiate abstract class {recvtype}.") + return + else if recvtype.mclass.kind == interface_kind then + v.error(self, "Cannot instantiate interface {recvtype}.") + return + end + self.mtype = recvtype + else + self.mtype = callsite.msignature.return_mtype + assert self.mtype != null + end + self.callsite = callsite if not callsite.mproperty.is_init_for(recvtype.mclass) then @@ -1779,6 +1823,16 @@ redef class AIssetAttrExpr end end +redef class AVarargExpr + redef fun accept_typing(v) + do + # This kind of pseudo-expression can be only processed trough a signature + # See `check_signature` + # Other cases are a syntax error. + v.error(self, "Syntax error: unexpected `...`") + end +end + ### redef class ADebugTypeExpr