# 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
# * 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
selfvariable.declared_type = mclass.mclass_type
var mprop = mpropdef.mproperty
- if mprop isa MMethod and mprop.is_toplevel then
+ if mprop isa MMethod and (mprop.is_toplevel or mprop.is_new) then
is_toplevel_context = true
end
end
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
#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)
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)
+ if not nblock.after_flow_context.is_unreachable then
+ # We reach the end of the init without having a return, it is bad
+ v.error(self, "Control error: Reached end of block (a 'return' with a value was expected).")
+ end
+ end
end
end
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
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
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
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)
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
is_col = true
end
- if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type, objcla.mclass_type.as_nullable])) then
+ if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type.as_nullable, objcla.mclass_type.as_nullable])) then
# Map Iterator
var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
var variables = self.variables
self.do_type_iterator(v, mtype)
v.visit_stmt(n_block)
+ self.mtype = n_block.mtype
self.is_typed = true
end
end
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
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
if mtype == null then
mtype = v.merge_types(self, mtypes)
end
- if mtype == null then
+ if mtype == null or mtype isa MNullType then
v.error(self, "Type Error: ambiguous array type {mtypes.join(" ")}")
return
end
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])
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
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)
# 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
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
var callsite = v.get_method(self, recvtype, name, false)
if callsite == null then return
+ if not callsite.mproperty.is_new then
+ var kind = recvtype.mclass.kind
+ if kind != concrete_kind then
+ v.error(self, "Type Error: Cannot instantiate {kind} {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