X-Git-Url: http://nitlanguage.org diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index b173445..8258cbf 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -181,7 +181,6 @@ private class TypeVisitor return self.visit_expr_subtype(nexpr, self.type_bool(nexpr)) end - fun check_expr_cast(node: ANode, nexpr: AExpr, ntype: AType): nullable MType do var sub = nexpr.mtype @@ -316,8 +315,12 @@ private class TypeVisitor var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name) if name == "new" and mproperty == null then - name = "init" + name = "autoinit" mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name) + if mproperty == null then + name = "init" + mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name) + end end if mproperty == null then @@ -396,7 +399,7 @@ private class TypeVisitor # The `build_callsite_by_propdef` builds the callsite directly with the `mprodef` passed in argument. fun build_callsite_by_propdef(node: ANode, recvtype: MType, mpropdef: MMethodDef, recv_is_self: Bool): nullable CallSite do - var msignature = mpropdef.new_msignature or else mpropdef.msignature + var msignature = mpropdef.msignature if msignature == null then return null # skip error msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature) @@ -424,7 +427,6 @@ private class TypeVisitor return build_callsite_by_name(node, recvtype, name, recv_is_self) end - # Visit the expressions of args and check their conformity with the corresponding type in signature # The point of this method is to handle varargs correctly # Note: The signature must be correctly adapted @@ -445,7 +447,6 @@ private class TypeVisitor # Other cases are managed later end - #debug("CALL {unsafe_type}.{msignature}") # Associate each parameter to a position in the arguments @@ -1177,7 +1178,6 @@ redef class AVarReassignExpr end end - redef class AContinueExpr redef fun accept_typing(v) do @@ -1503,7 +1503,6 @@ redef class AAndExpr end end - redef class ANotExpr redef fun accept_typing(v) do @@ -1779,7 +1778,7 @@ redef class ARangeExpr # get the constructor var callsite if self isa ACrangeExpr then - callsite = v.build_callsite_by_name(self, mtype, "init", false) + callsite = v.build_callsite_by_name(self, mtype, "autoinit", false) else if self isa AOrangeExpr then callsite = v.build_callsite_by_name(self, mtype, "without_last", false) else @@ -1929,6 +1928,11 @@ redef class ASendExpr # The property invoked by the send. var callsite: nullable CallSite + # Is self a safe call (with `x?.foo`)? + # If so and the receiver is null, then the arguments won't be evaluated + # and the call skipped (replaced with null). + var is_safe: Bool = false + redef fun bad_expr_message(child) do if child == self.n_expr then @@ -1941,6 +1945,13 @@ redef class ASendExpr do var nrecv = self.n_expr var recvtype = v.visit_expr(nrecv) + + if nrecv isa ASafeExpr then + # Has the receiver the form `x?.foo`? + # For parsing "reasons" the `?` is in the receiver node, not the call node. + is_safe = true + end + var name = self.property_name var node = self.property_node @@ -1977,7 +1988,9 @@ redef class ASendExpr var args = compute_raw_arguments - callsite.check_signature(v, node, args) + if not self isa ACallrefExpr then + callsite.check_signature(v, node, args) + end if callsite.mproperty.is_init then var vmpropdef = v.mpropdef @@ -1991,6 +2004,10 @@ redef class ASendExpr var ret = msignature.return_mtype if ret != null then + if is_safe then + # A safe receiver makes that the call is not executed and returns null + ret = ret.as_nullable + end self.mtype = ret else self.is_typed = true @@ -2056,7 +2073,6 @@ redef class AUnaryopExpr redef fun compute_raw_arguments do return new Array[AExpr] end - redef class ACallExpr redef fun property_name do return n_qid.n_id.text redef fun property_node do return n_qid @@ -2144,11 +2160,82 @@ redef class ABraReassignExpr end redef class AInitExpr - redef fun property_name do return "init" + redef fun property_name do if n_args.n_exprs.is_empty then return "init" else return "autoinit" redef fun property_node do return n_kwinit redef fun compute_raw_arguments do return n_args.to_a end +redef class ACallrefExpr + redef fun property_name do return n_qid.n_id.text + redef fun property_node do return n_qid + redef fun compute_raw_arguments do return n_args.to_a + + redef fun accept_typing(v) + do + super # do the job as if it was a real call + var res = callsite.mproperty + + var msignature = callsite.mpropdef.msignature + var recv = callsite.recv + assert msignature != null + var arity = msignature.mparameters.length + + var routine_type_name = "ProcRef" + if msignature.return_mtype != null then + routine_type_name = "FunRef" + end + + var target_routine_class = "{routine_type_name}{arity}" + var routine_mclass = v.get_mclass(self, target_routine_class) + + if routine_mclass == null then + v.error(self, "Error: missing functional types, try `import functional`") + return + end + + var types_list = new Array[MType] + for param in msignature.mparameters do + if param.is_vararg then + types_list.push(v.mmodule.array_type(param.mtype)) + else + types_list.push(param.mtype) + end + end + if msignature.return_mtype != null then + types_list.push(msignature.return_mtype.as(not null)) + end + + # Why we need an anchor : + # + # ~~~~nitish + # class A[E] + # def toto(x: E) do print "{x}" + # end + # + # var a = new A[Int] + # var f = &a.toto # without anchor : ProcRef1[E] + # # with anchor : ProcRef[Int] + # ~~~~ + # However, we can only anchor if we can resolve every formal + # parameter, here's an example where we can't. + # ~~~~nitish + # class A[E] + # fun bar: A[E] do return self + # fun foo: Fun0[A[E]] do return &bar # here we can't anchor + # end + # var f1 = a1.foo # when this expression will be evaluated, + # # `a1` will anchor `&bar` returned by `foo`. + # print f1.call + # ~~~~ + var routine_type = routine_mclass.get_mtype(types_list) + if not recv.need_anchor then + routine_type = routine_type.anchor_to(v.mmodule, recv.as(MClassType)) + end + is_typed = true + self.mtype = routine_type + end +end + redef class AExprs fun to_a: Array[AExpr] do return self.n_exprs.to_a end @@ -2242,7 +2329,7 @@ redef class ASuperExpr return end - var msignature = superprop.new_msignature or else superprop.msignature.as(not null) + var msignature = superprop.msignature.as(not null) msignature = v.resolve_for(msignature, recvtype, true).as(MSignature) var callsite = new CallSite(hot_location, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false) @@ -2433,7 +2520,6 @@ redef class AAttrExpr end end - redef class AAttrAssignExpr redef fun accept_typing(v) do @@ -2474,6 +2560,28 @@ redef class AIssetAttrExpr end end +redef class ASafeExpr + redef fun accept_typing(v) + do + var mtype = v.visit_expr(n_expr) + if mtype == null then return # Skip error + + if mtype isa MNullType then + # While `null?.foo` is semantically well defined and should not execute `foo` and just return `null`, + # currently `null.foo` is forbidden so it seems coherent to also forbid `null?.foo` + v.modelbuilder.error(self, "Error: safe operator `?` on `null`.") + return + end + + self.mtype = mtype.as_notnull + + if not v.can_be_null(mtype) then + v.modelbuilder.warning(self, "useless-safe", "Warning: useless safe operator `?` on non-nullable value.") + return + end + end +end + redef class AVarargExpr redef fun accept_typing(v) do