end
end
+ # Combine informations of ctx to the current flow context informations as an alternative
+ # Require that all contexts are reachable at the end
+ fun combine_merge(ctxs: Array[VariableContext], basectx: VariableContext)
+ do
+ for v in _all_variables do
+ do
+ if not is_set(v) then
+ for ctx in ctxs do
+ if not ctx.is_set(v) then break label set
+ end
+ mark_is_set(v)
+ end
+ end label set
+
+ var candidate: nullable MMType = null
+ var is_nullable = false
+ var same_candidate: nullable MMType = ctxs.first.stype(v)
+ for ctx in ctxs do
+ var t = ctx.stype(v)
+ if t == null then
+ stype(v) = null
+ continue label each_variable
+ end
+ if t != same_candidate then
+ same_candidate = null
+ end
+ if t isa MMTypeNone then
+ is_nullable = true
+ continue
+ end
+ if t isa MMNullableType then
+ is_nullable = true
+ t = t.as_notnull
+ end
+ if candidate == null or candidate < t then
+ candidate = t
+ end
+ end
+ if same_candidate != null then
+ stype(v) = same_candidate
+ end
+ if is_nullable then
+ if candidate == null then
+ candidate = _visitor.type_none
+ else
+ candidate = candidate.as_nullable
+ end
+ end
+ if candidate == null then
+ stype(v) = basectx.stype(v)
+ else
+ for ctx in ctxs do
+ var t = ctx.stype(v)
+ if not t < candidate then
+ stype(v) = basectx.stype(v)
+ continue label each_variable
+ end
+ end
+ end
+ stype(v) = candidate
+ end label each_variable
+ end
+
# Combine and get the most specific comon supertype
# return null if no comon supertype is found
private fun merge_types(t1, t2: MMType): nullable MMType
package escape
import syntax_base
+import control_flow
# Stack escapable blocks
class EscapableContext
# The static type required by the continue statement (if any)
fun continue_stype: nullable MMType do return null
+ # Alternatives variable contexts for breaks
+ readable var _break_variable_contexts: Array[VariableContext] = new Array[VariableContext]
+
init(node: ANode)
do
_node = node
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.")
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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2010 Jean Privat <jean@pryen.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+class A
+end
+
+fun rand: Bool = true
+
+fun eat_na(a: nullable A) do if a == null then 0.output else 1.output
+fun eat_a(a: A) do 2.output
+
+fun get_a: nullable A = new A
+fun get_na: nullable A = null
+
+var a = get_na
+while a == null do
+ eat_na(a)
+ #alt1#eat_a(a)
+ #alt2#if rand then break
+ a = new A
+end
+eat_na(a)
+eat_a(a)
+
+'\n'.output
+
+a = get_a
+loop
+ eat_na(a)
+ if rand and a != null then
+ eat_a(a)
+ break
+ end
+ #alt3#break
+end
+eat_na(a)
+eat_a(a)
-alt/base_isa_cast2_alt8.nit:62,1--7: Error: Method 'foo' doesn't exists in A.
+1
+2
+3
+4
+5
+6
+7
--- /dev/null
+0
+1
+2
+
+1
+2
+1
+2
--- /dev/null
+alt/base_var_type_evolution_null4_alt1.nit:33,8: Type error: expected A, got null
--- /dev/null
+0
+0
+2
+
+1
+2
+1
+2
--- /dev/null
+alt/base_var_type_evolution_null4_alt3.nit:52,7: Type error: expected A, got nullable A