#node.debug("Unsafe typing: expected {sup}, got {sub}")
return sup
end
- self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}")
+ if sub.need_anchor then
+ var u = anchor_to(sub)
+ self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}: {u}")
+ else
+ self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}")
+ end
return null
end
return sup
end
+ # Can `mtype` be null (up to the current knowledge)?
+ fun can_be_null(mtype: MType): Bool
+ do
+ if mtype isa MNullableType or mtype isa MNullType then return true
+ if mtype isa MFormalType then
+ var x = anchor_to(mtype)
+ if x isa MNullableType or x isa MNullType then return true
+ end
+ return false
+ end
+
+ # Check that `mtype` can be null (up to the current knowledge).
+ #
+ # If not then display a `useless-null-test` warning on node and return false.
+ # Else return true.
+ fun check_can_be_null(anode: ANode, mtype: MType): Bool
+ do
+ if can_be_null(mtype) then return true
+
+ if mtype isa MFormalType then
+ var res = anchor_to(mtype)
+ modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}: {res}`.")
+ else
+ modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}`.")
+ end
+ return false
+ end
+
# Special verification on != and == for null
# Return true
fun null_test(anode: ABinopExpr)
if not mtype2 isa MNullType then return
+ if mtype 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
+ if not check_can_be_null(anode.n_expr, mtype) then return
+
+ mtype = mtype.as_notnull
# Check for type adaptation
var variable = anode.n_expr.its_variable
if variable == null then return
+ # One is null (mtype2 see above) the other is not null
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)
+ anode.after_flow_context.when_false.set_var(variable, 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)
+ anode.after_flow_context.when_true.set_var(variable, mtype)
else
abort
end
fun get_mclass(node: ANode, name: String): nullable MClass
do
- var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
- if mclass == null then
- self.modelbuilder.error(node, "Type Error: missing primitive class `{name}'.")
- end
+ var mclass = modelbuilder.get_mclass_by_name(node, mmodule, name)
return mclass
end
if recvtype isa MNullType then
# `null` only accepts some methods of object.
if name == "==" or name == "!=" or name == "is_same_instance" then
- unsafe_type = mmodule.object_type.as_nullable
+ var objclass = get_mclass(node, "Object")
+ if objclass == null then return null # Forward error
+ unsafe_type = objclass.mclass_type
else
self.error(node, "Error: Method '{name}' call on 'null'.")
return null
end
- var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+ var msignature = mpropdef.new_msignature or else mpropdef.msignature
+ if msignature == null then return null # skip error
msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
var erasure_cast = false
var rettype = mpropdef.msignature.return_mtype
if not recv_is_self and rettype != null then
- rettype = rettype.as_notnullable
+ rettype = rettype.undecorate
if rettype isa MParameterType then
var erased_rettype = msignature.return_mtype
assert erased_rettype != null
var found = true
for t2 in col do
if t2 == null then continue # return null
- if t2 isa MNullableType or t2 isa MNullType then
+ if can_be_null(t2) and not can_be_null(t1) then
t1 = t1.as_nullable
end
if not is_subtype(t2, t1) then found = false
var nblock = self.n_block
if nblock == null then return
- var mpropdef = self.mpropdef.as(not null)
+ var mpropdef = self.mpropdef
+ if mpropdef == null then return # skip error
+
var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
self.selfvariable = v.selfvariable
var mmethoddef = self.mpropdef.as(not null)
- for i in [0..mmethoddef.msignature.arity[ do
- var mtype = mmethoddef.msignature.mparameters[i].mtype
- if mmethoddef.msignature.vararg_rank == i then
+ var msignature = mmethoddef.msignature
+ if msignature == null then return # skip error
+ for i in [0..msignature.arity[ do
+ var mtype = msignature.mparameters[i].mtype
+ if msignature.vararg_rank == i then
var arrayclass = v.get_mclass(self.n_signature.n_params[i], "Array")
if arrayclass == null then return # Skip error
mtype = arrayclass.get_mtype([mtype])
end
v.visit_stmt(nblock)
- if not nblock.after_flow_context.is_unreachable and mmethoddef.msignature.return_mtype != null then
+ if not nblock.after_flow_context.is_unreachable and msignature.return_mtype != null then
# We reach the end of the function without having a return, it is bad
v.error(self, "Control error: Reached end of function (a 'return' with a value was expected).")
end
redef class AAttrPropdef
redef fun do_typing(modelbuilder: ModelBuilder)
do
- var mpropdef = self.mpropdef.as(not null)
+ if not has_value then return
+
+ var mpropdef = self.mpropdef
+ if mpropdef == null then return # skip error
+
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
var decltype = mtype
if mtype == null or mtype isa MNullType then
- decltype = v.get_mclass(self, "Object").mclass_type.as_nullable
+ var objclass = v.get_mclass(self, "Object")
+ if objclass == null then return # skip error
+ decltype = objclass.mclass_type.as_nullable
if mtype == null then mtype = decltype
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
# anchor formal and virtual types
if mtype.need_anchor then mtype = v.anchor_to(mtype)
- mtype = mtype.as_notnullable
+ mtype = mtype.undecorate
self.coltype = mtype.as(MClassType)
# get methods is_ok, next, item
return # Skip error
end
- t1 = t1.as_notnullable
+ if t1 isa MNullType then
+ v.error(n_expr, "Type error: or else on null")
+ else if v.check_can_be_null(n_expr, t1) then
+ t1 = t1.as_notnull
+ end
var t = v.merge_types(self, [t1, t2])
if t == null then
- t = v.mmodule.object_type
- if t2 isa MNullableType then
+ var c = v.get_mclass(self, "Object")
+ if c == null then return # forward error
+ t = c.mclass_type
+ if v.can_be_null(t2) then
t = t.as_nullable
end
#v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
var mclass = v.get_mclass(self, "String")
if mclass == null then return # Forward error
self.mtype = mclass.mclass_type
+ var objclass = v.get_mclass(self, "Object")
+ if objclass == null then return # Forward error
+ var objtype = objclass.mclass_type
for nexpr in self.n_exprs do
- v.visit_expr_subtype(nexpr, v.mmodule.object_type)
+ v.visit_expr_subtype(nexpr, objtype)
end
end
end
v.error(self, "Type error: as(not null) on null")
return
end
- if mtype isa MNullableType then
- self.mtype = mtype.mtype
- return
- end
- self.mtype = mtype
- if mtype isa MClassType then
- v.modelbuilder.warning(self, "useless-type-test", "Warning: expression is already not null, since it is a `{mtype}`.")
- return
- end
- assert mtype.need_anchor
- var u = v.anchor_to(mtype)
- if not u isa MNullableType then
- v.modelbuilder.warning(self, "useless-type-test", "Warning: expression is already not null, since it is a `{mtype}: {u}`.")
- return
+ if v.check_can_be_null(n_expr, mtype) then
+ mtype = mtype.as_notnull
end
+
+ self.mtype = mtype
end
end
var mpropdefs = mproperty.lookup_definitions(v.mmodule, unsafe_type)
assert mpropdefs.length == 1
var mpropdef = mpropdefs.first
- var attr_type = mpropdef.static_mtype.as(not null)
+ var attr_type = mpropdef.static_mtype
+ if attr_type == null then return # skip error
attr_type = v.resolve_for(attr_type, recvtype, self.n_expr isa ASelfExpr)
self.attr_type = attr_type
end