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)
redef class AAttrPropdef
redef fun do_typing(modelbuilder: ModelBuilder)
do
+ if not has_value then return
+
var mpropdef = self.mpropdef.as(not null)
var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
self.selfvariable = v.selfvariable
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
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)