X-Git-Url: http://nitlanguage.org diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index 13b36b6..1d694e6 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -39,10 +39,10 @@ private class TypeVisitor # The static type of the receiver # Mainly used for type tests and type resolutions - var anchor: nullable MClassType + var anchor: nullable MClassType = null # The analyzed mclassdef - var mclassdef: nullable MClassDef + var mclassdef: nullable MClassDef = null # The analyzed property var mpropdef: nullable MPropDef @@ -54,10 +54,9 @@ private class TypeVisitor # * method called on the implicit self must be top-level var is_toplevel_context = false - init(modelbuilder: ModelBuilder, mmodule: MModule, mpropdef: nullable MPropDef) + init do - self.modelbuilder = modelbuilder - self.mmodule = mmodule + var mpropdef = self.mpropdef if mpropdef != null then self.mpropdef = mpropdef @@ -179,7 +178,7 @@ private class TypeVisitor end - private fun visit_expr_cast(node: ANode, nexpr: AExpr, ntype: AType): nullable MType + fun visit_expr_cast(node: ANode, nexpr: AExpr, ntype: AType): nullable MType do var sub = visit_expr(nexpr) if sub == null then return null # Forward error @@ -267,8 +266,13 @@ private class TypeVisitor #debug("recv: {recvtype} (aka {unsafe_type})") if recvtype isa MNullType then - self.error(node, "Error: Method '{name}' call on 'null'.") - return null + # `null` only accepts some methods of object. + if name == "==" or name == "!=" or name == "is_same_instance" then + unsafe_type = mmodule.object_type.as_nullable + else + self.error(node, "Error: Method '{name}' call on 'null'.") + return null + end end var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name) @@ -602,6 +606,10 @@ redef class AAttrPropdef var mtype = self.mpropdef.static_mtype v.visit_expr_subtype(nexpr, mtype) end + var nblock = self.n_block + if nblock != null then + v.visit_stmt(nblock) + end end end @@ -630,6 +638,12 @@ redef class AExpr do v.error(self, "no implemented accept_typing for {self.class_name}") end + + # Is non-null if `self` is a leaf of a comprehension array construction. + # In this case, the enclosing literal array node is designated. + # The result of the evaluation of `self` must be + # stored inside the designated array (there is an implicit `push`) + var comprehension: nullable AArrayExpr = null end redef class ABlockExpr @@ -665,7 +679,11 @@ redef class AVardeclExpr var nexpr = self.n_expr if nexpr != null then if mtype != null then - v.visit_expr_subtype(nexpr, mtype) + var etype = v.visit_expr_subtype(nexpr, mtype) + if etype == mtype then + assert ntype != null + v.modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition for variable `{variable.name}`") + end else mtype = v.visit_expr(nexpr) if mtype == null then return # Skip error @@ -743,11 +761,6 @@ redef class AReassignFormExpr self.read_type = readtype - if readtype isa MNullType then - v.error(self, "Error: Method '{reassign_name}' call on 'null'.") - return null - end - var callsite = v.get_method(self, readtype, reassign_name, false) if callsite == null then return null # Skip error self.reassign_callsite = callsite @@ -813,7 +826,15 @@ redef class AReturnExpr redef fun accept_typing(v) do var nexpr = self.n_expr - var ret_type = v.mpropdef.as(MMethodDef).msignature.return_mtype + var ret_type + var mpropdef = v.mpropdef + if mpropdef isa MMethodDef then + ret_type = mpropdef.msignature.return_mtype + else if mpropdef isa MAttributeDef then + ret_type = mpropdef.static_mtype + else + abort + end if nexpr != null then if ret_type != null then v.visit_expr_subtype(nexpr, ret_type) @@ -842,7 +863,12 @@ redef class AIfExpr v.visit_stmt(n_then) v.visit_stmt(n_else) + self.is_typed = true + + if n_then != null and n_else == null then + self.mtype = n_then.mtype + end end end @@ -1028,6 +1054,7 @@ redef class AForExpr self.do_type_iterator(v, mtype) v.visit_stmt(n_block) + self.mtype = n_block.mtype self.is_typed = true end end @@ -1165,9 +1192,31 @@ redef class ASuperstringExpr end redef class AArrayExpr + # The `with_capacity` method on Array var with_capacity_callsite: nullable CallSite + + # The `push` method on arrays var push_callsite: nullable CallSite + # The element of each type + var element_mtype: nullable MType + + # Set that `self` is a part of comprehension array `na` + # If `self` is a `for`, or a `if`, then `set_comprehension` is recursively applied. + private fun set_comprehension(n: nullable AExpr) + do + if n == null then + return + else if n isa AForExpr then + set_comprehension(n.n_block) + else if n isa AIfExpr then + set_comprehension(n.n_then) + set_comprehension(n.n_else) + else + # is a leave + n.comprehension = self + end + end redef fun accept_typing(v) do var mtype: nullable MType = null @@ -1178,11 +1227,12 @@ redef class AArrayExpr end var mtypes = new Array[nullable MType] var useless = false - for e in self.n_exprs.n_exprs do + for e in self.n_exprs do var t = v.visit_expr(e) if t == null then return # Skip error end + set_comprehension(e) if mtype != null then if v.check_subtype(e, t, mtype) == null then return # Skip error if t == mtype then useless = true @@ -1201,6 +1251,9 @@ redef class AArrayExpr assert ntype != null v.modelbuilder.warning(ntype, "useless-type", "Warning: useless type declaration `{mtype}` in literal Array since it can be inferred from the elements type.") end + + self.element_mtype = mtype + var mclass = v.get_mclass(self, "Array") if mclass == null then return # Forward error var array_mtype = mclass.get_mtype([mtype]) @@ -1354,10 +1407,6 @@ redef class ASendExpr var name = self.property_name if recvtype == null then return # Forward error - if recvtype isa MNullType then - v.error(self, "Error: Method '{name}' call on 'null'.") - return - end var callsite = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr) if callsite == null then return @@ -1501,10 +1550,6 @@ redef class ASendReassignFormExpr var name = self.property_name if recvtype == null then return # Forward error - if recvtype isa MNullType then - v.error(self, "Error: Method '{name}' call on 'null'.") - return - end var for_self = self.n_expr isa ASelfExpr var callsite = v.get_method(self, recvtype, name, for_self) @@ -1711,11 +1756,9 @@ redef class ANewExpr 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}.") + var kind = recvtype.mclass.kind + if kind != concrete_kind then + v.error(self, "Type Error: Cannot instantiate {kind} {recvtype}.") return end self.mtype = recvtype