v.check_conform_expr(x, t)
end
- old_var_ctx.merge(v.variable_ctx)
v.variable_ctx = old_var_ctx
v.base_variable_ctx = old_base_var_ctx
v.escapable_ctx.pop
redef class ABlockExpr
redef fun accept_typing(v)
do
- var old_var_ctx = v.variable_ctx
- v.variable_ctx = v.variable_ctx.sub(self)
-
for e in n_expr do
- if v.variable_ctx.unreash and not v.variable_ctx.already_unreash then
+ if not v.variable_ctx.unreash then
+ v.enter_visit(e)
+ else if not v.variable_ctx.already_unreash then
v.variable_ctx.already_unreash = true
- v.warning(e, "Warning: unreachable statement.")
+ v.error(e, "Error: unreachable statement.")
end
- v.enter_visit(e)
end
- old_var_ctx.merge(v.variable_ctx)
- v.variable_ctx = old_var_ctx
_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.")
var escapable = new BreakOnlyEscapableBlock(self)
_escapable = escapable
v.escapable_ctx.push(escapable, n_label)
+ var old_var_ctx = v.variable_ctx
+ v.variable_ctx = old_var_ctx.sub(self)
super
+ # Add the end of the block as an exit context
+ if not v.variable_ctx.unreash then
+ escapable.break_variable_contexts.add(v.variable_ctx)
+ end
+
+ # Merge all exit contexts
+ if not escapable.break_variable_contexts.is_empty then
+ v.variable_ctx = old_var_ctx.merge(self, escapable.break_variable_contexts, v.base_variable_ctx)
+ end
+
v.escapable_ctx.pop
_is_typed = true
end
end
# 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
+ v.variable_ctx = old_var_ctx.merge_reash(self, then_var_ctx, v.variable_ctx, v.base_variable_ctx)
_is_typed = true
end
end
var old_var_ctx = v.variable_ctx
var old_base_var_ctx = v.base_variable_ctx
v.base_variable_ctx = v.variable_ctx
- v.variable_ctx = v.variable_ctx.sub(self)
# Process condition
v.enter_visit(n_expr)
v.enter_visit(n_block)
end
+ # Compute outside context (assert !cond + all breaks)
v.variable_ctx = old_var_ctx
+ v.use_if_false_variable_ctx(n_expr)
+ escapable.break_variable_contexts.add(v.variable_ctx)
+ v.variable_ctx = old_var_ctx.merge(self, escapable.break_variable_contexts, v.base_variable_ctx)
+
v.base_variable_ctx = old_base_var_ctx
v.escapable_ctx.pop
_is_typed = true
var old_var_ctx = v.variable_ctx
var old_base_var_ctx = v.base_variable_ctx
v.base_variable_ctx = v.variable_ctx
- v.variable_ctx = v.variable_ctx.sub(self)
# Process inside
if n_block != null then
v.enter_visit(n_block)
end
- v.variable_ctx = old_var_ctx
+ # Compute outside context (assert all breaks)
+ if escapable.break_variable_contexts.is_empty then
+ old_var_ctx.unreash = true
+ v.variable_ctx = old_var_ctx
+ else
+ v.variable_ctx = old_var_ctx.merge(self, escapable.break_variable_contexts, v.base_variable_ctx)
+ end
+
v.base_variable_ctx = old_base_var_ctx
v.escapable_ctx.pop
_is_typed = true
# Process collection
v.enter_visit(n_expr)
- if not v.check_conform_expr(n_expr, v.type_collection) then return
+ if not v.check_conform_expr(n_expr, v.type_collection) then
+ v.variable_ctx = old_var_ctx
+ v.base_variable_ctx = old_base_var_ctx
+ v.escapable_ctx.pop
+ return
+ end
var expr_type = n_expr.stype
# Get iterator
if btype != null and not v.check_conform_expr(n_value, btype) then return
# Always cast
- v.variable_ctx.stype(variable) = n_value.stype
+ v.variable_ctx = v.variable_ctx.sub_with(self, variable, n_value.stype)
_is_typed = true
end
if btype != null and not v.check_conform(n_value, t2, btype) then return
# Always cast
- v.variable_ctx.stype(variable) = t2
+ v.variable_ctx = v.variable_ctx.sub_with(self, variable, t2)
_is_typed = true
end
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
+ v.variable_ctx = old_var_ctx.merge_reash(self, then_var_ctx, v.variable_ctx, v.base_variable_ctx)
var stype = v.check_conform_multiexpr(null, [n_then, n_else])
if stype == null then return
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
+ if name == (once "==".to_symbol) or name == (once "!=".to_symbol) then
+ # Special case on != and == that are allowed for 'null'
+ type_recv = v.type_object.as_nullable
+ else
+ v.error(self, "Error: Method '{name}' call on 'null'.")
+ return null
+ end
end
var lc = type_recv.local_class
var prop: nullable MMMethod = null
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
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