end
end
-redef class VarVariable
- redef readable var _is_typed: Bool = false
-end
###############################################################################
end
else if ne != null then
if not v.check_expr(ne) then return
- va.stype = n_expr.stype
+ va.stype = ne.stype
+ else
+ va.stype = v.type_object.as_nullable
end
- va._is_typed = true
_is_typed = true
end
end
redef class ABreakExpr
redef fun after_typing(v)
do
+ var unreash = v.variable_ctx.unreash
v.variable_ctx.unreash = true
var esc = compute_escapable_block(v.escapable_ctx)
if esc == null then return
+ if not unreash then esc.break_variable_contexts.add(v.variable_ctx)
+
var bl = esc.break_list
if n_expr == null and bl != null then
v.error(self, "Error: break with a value required in this block.")
v.enter_visit(n_expr)
v.check_conform_expr(n_expr, v.type_bool)
+ if n_expr isa ATrueExpr then
+ v.warning(self, "Warning: use 'loop' instead of 'while true do'.")
+ end
+
# Prepare inside context (assert cond)
v.use_if_true_variable_ctx(n_expr)
end
v.variable_ctx = old_var_ctx
+
+ # Compute outside context (assert !cond + all breaks)
+ v.use_if_false_variable_ctx(n_expr)
+ escapable.break_variable_contexts.add(v.variable_ctx)
+ old_var_ctx.combine_merge(escapable.break_variable_contexts, v.base_variable_ctx)
+
v.base_variable_ctx = old_base_var_ctx
v.escapable_ctx.pop
_is_typed = true
v.enter_visit(n_block)
end
+ # Compute outside context (assert all breaks)
+ if not escapable.break_variable_contexts.is_empty then
+ old_var_ctx.combine_merge(escapable.break_variable_contexts, v.base_variable_ctx)
+ end
+
v.variable_ctx = old_var_ctx
v.base_variable_ctx = old_base_var_ctx
v.escapable_ctx.pop
return null
end
var name = n_assign_op.method_name
+ if type_lvalue isa MMTypeNone then
+ v.error(self, "Error: Method '{name}' call on 'null'.")
+ return null
+ end
var lc = type_lvalue.local_class
if not lc.has_global_property_by_name(name) then
v.error(self, "Error: Method '{name}' doesn't exists in {type_lvalue}.")
v.use_if_true_variable_ctx(n_expr)
# Process 'then'
+ v.variable_ctx = v.variable_ctx.sub(n_then)
v.enter_visit(n_then)
+ # Remember what appened in the 'then'
+ var then_var_ctx = v.variable_ctx
+
# Prepare 'else' context
v.variable_ctx = old_var_ctx
v.use_if_false_variable_ctx(n_expr)
# Process 'else'
+ v.variable_ctx = v.variable_ctx.sub(n_else)
v.enter_visit(n_else)
+ # Merge 'then' and 'else' contexts
+ old_var_ctx.merge2(then_var_ctx, v.variable_ctx, v.base_variable_ctx)
+ v.variable_ctx = old_var_ctx
+
var stype = v.check_conform_multiexpr(null, [n_then, n_else])
if stype == null then return
if not v.check_expr(n_expr) then return
var type_recv = n_expr.stype
var name = n_id.to_symbol
+ if type_recv isa MMTypeNone then
+ v.error(self, "Error: Attribute '{name}' access on 'null'.")
+ return
+ end
var lc = type_recv.local_class
if not lc.has_global_property_by_name(name) then
v.error(self, "Error: Attribute {name} doesn't exists in {type_recv}.")
private fun get_property(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, name: Symbol): nullable MMMethod
do
+ if type_recv isa MMTypeNone then
+ v.error(self, "Error: Method '{name}' call on 'null'.")
+ return null
+ end
var lc = type_recv.local_class
var prop: nullable MMMethod = null
if lc.has_global_property_by_name(name) then prop = lc.select_method(name)
if prop == null and v.local_property.global.is_init then
- var props = type_recv.local_class.super_methods_named(name)
+ var props = lc.super_methods_named(name)
if props.length > 1 then
v.error(self, "Error: Ambigous method name '{name}' for {props.join(", ")}. Use explicit designation.")
return null
else if props.length == 1 then
- var p = type_recv.local_class[props.first.global]
+ var p = lc[props.first.global]
assert p isa MMMethod
prop = p
end
end
if n_expr.stype isa MMTypeNone then
- try_to_isa(v, n_expr2)
+ if n_expr2.stype isa MMTypeNone then
+ v.warning(self, "Warning: comparaison between 2 null values.")
+ else
+ try_to_isa(v, n_expr2)
+ end
else if n_expr2.stype isa MMTypeNone then
try_to_isa(v, n_expr)
end
private fun try_to_isa(v: TypingVisitor, n: AExpr)
do
var variable = n.its_variable
- if variable != null then
+ if variable != null and n.stype isa MMNullableType then
_if_false_variable_ctx = v.variable_ctx.sub_with(self, variable, n.stype.as_notnull)
+ _if_true_variable_ctx = v.variable_ctx.sub_with(self, variable, v.type_none)
end
end
end
end
if n_expr.stype isa MMTypeNone then
- try_to_isa(v, n_expr2)
+ if n_expr2.stype isa MMTypeNone then
+ v.warning(self, "Warning: comparaison between 2 null values.")
+ else
+ try_to_isa(v, n_expr2)
+ end
else if n_expr2.stype isa MMTypeNone then
try_to_isa(v, n_expr)
end
private fun try_to_isa(v: TypingVisitor, n: AExpr)
do
var variable = n.its_variable
- if variable != null then
+ if variable != null and n.stype isa MMNullableType then
_if_true_variable_ctx = v.variable_ctx.sub_with(self, variable, n.stype.as_notnull)
+ _if_false_variable_ctx = v.variable_ctx.sub_with(self, variable, v.type_none)
end
end
end
v.warning(self, "Warning: Expression is already a {ttype}.")
else if etype < ttype then
v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.")
+ else if etype isa MMTypeNone then
+ # ttype is not nullable because of prevous test
+ v.warning(self, "Warning: Expression is null therefore cannot be a {ttype}.")
else if etype.is_nullable and etype.as_notnull == ttype then
if ttype isa MMTypeFormal and ttype.bound.is_nullable then
# No warning in this case since with