X-Git-Url: http://nitlanguage.org diff --git a/src/syntax/typing.nit b/src/syntax/typing.nit index 1ef3ab8..96c4840 100644 --- a/src/syntax/typing.nit +++ b/src/syntax/typing.nit @@ -18,8 +18,8 @@ package typing import syntax_base -import escape -import control_flow +import flow +import scope redef class MMSrcModule # Walk trough the module and type statments and expressions @@ -37,38 +37,44 @@ end # * Resolve call and attribute access # * Check type conformance private class TypingVisitor -special AbsSyntaxVisitor + super AbsSyntaxVisitor redef fun visit(n) do if n != null then n.accept_typing(self) end - # Current knowledge about variables names and types - fun variable_ctx: VariableContext do return _variable_ctx.as(not null) - writable var _variable_ctx: nullable VariableContext + # Current knowledge about scoped things (variable, labels, etc.) + readable var _scope_ctx: ScopeContext = new ScopeContext(self) + + # Current knowledge about control flow + fun flow_ctx: FlowContext do return _flow_ctx.as(not null) + writable var _flow_ctx: nullable FlowContext + + # Mark a local variable as set + fun mark_is_set(va: Variable) + do + if flow_ctx.is_set(va) then return + flow_ctx = flow_ctx.sub_setvariable(va) + end # Mark the flow context as unreashable fun mark_unreash(n: ANode) do - var ctx = variable_ctx.sub(n) - ctx.unreash = true - variable_ctx = ctx + flow_ctx = flow_ctx.sub_unreash(n) end # Enter in an expression as inside a new local variable scope fun enter_visit_block(node: nullable AExpr) do if node == null then return - variable_ctx = variable_ctx.sub(node) + scope_ctx.push(node) enter_visit(node) + scope_ctx.pop end # Non-bypassable knowledge about variables names and types - fun base_variable_ctx: VariableContext do return _base_variable_ctx.as(not null) - writable var _base_variable_ctx: nullable VariableContext - - # Current knowledge about escapable blocks - readable writable var _escapable_ctx: EscapableContext = new EscapableContext(self) + fun base_flow_ctx: FlowContext do return _base_flow_ctx.as(not null) + writable var _base_flow_ctx: nullable FlowContext # The current reciever fun self_var: ParamVariable do return _self_var.as(not null) @@ -83,18 +89,18 @@ special AbsSyntaxVisitor # Is a other constructor of the same class invoked readable writable var _explicit_other_init_call: Bool = false - # Make the if_true_variable_ctx of the expression effective - private fun use_if_true_variable_ctx(e: AExpr) + # Make the if_true_flow_ctx of the expression effective + private fun use_if_true_flow_ctx(e: AExpr) do - var ctx = e.if_true_variable_ctx - if ctx != null then variable_ctx = ctx + var ctx = e.if_true_flow_ctx + if ctx != null then flow_ctx = ctx end - # Make the if_false_variable_ctx of the expression effective - private fun use_if_false_variable_ctx(e: AExpr) + # Make the if_false_flow_ctx of the expression effective + private fun use_if_false_flow_ctx(e: AExpr) do - var ctx = e.if_false_variable_ctx - if ctx != null then variable_ctx = ctx + var ctx = e.if_false_flow_ctx + if ctx != null then flow_ctx = ctx end # Are we inside a default closure definition ? @@ -103,7 +109,7 @@ special AbsSyntaxVisitor # Number of nested once readable writable var _once_count: Int = 0 - init(tc, module) do super + init(tc, mod) do super private fun get_default_constructor_for(n: ANode, c: MMLocalClass, prop: MMSrcMethod): nullable MMMethod do @@ -170,8 +176,6 @@ end redef class AClassdef redef fun accept_typing(v) do - v.variable_ctx = new RootVariableContext(v, self) - v.base_variable_ctx = v.variable_ctx v.self_var = new ParamVariable("self".to_symbol, self) v.self_var.stype = local_class.get_type super @@ -186,25 +190,29 @@ end redef class AAttrPropdef redef fun accept_typing(v) do - var old_var_ctx = v.variable_ctx - v.variable_ctx = old_var_ctx.sub(self) + v.flow_ctx = new RootFlowContext(v, self) + v.base_flow_ctx = v.flow_ctx + + v.scope_ctx.push(self) _self_var = v.self_var super if n_expr != null then v.check_conform_expr(n_expr.as(not null), prop.signature.return_type.as(not null)) end - v.variable_ctx = old_var_ctx + v.scope_ctx.pop end end redef class AMethPropdef redef fun accept_typing(v) do - var old_var_ctx = v.variable_ctx - v.variable_ctx = old_var_ctx.sub(self) + v.flow_ctx = new RootFlowContext(v, self) + v.base_flow_ctx = v.flow_ctx + + v.scope_ctx.push(self) _self_var = v.self_var super - v.variable_ctx = old_var_ctx + v.scope_ctx.pop end end @@ -212,7 +220,7 @@ redef class AConcreteMethPropdef redef fun after_typing(v) do super - if v.variable_ctx.unreash == false and method.signature.return_type != null then + if not v.flow_ctx.unreash and method.signature.return_type != null then v.error(self, "Control error: Reached end of function (a 'return' with a value was expected).") end end @@ -239,12 +247,12 @@ redef class AConcreteInitPropdef var cur_c: nullable MMLocalClass = null if i < l then cur_m = explicit_super_init_calls[i] - cur_c = cur_m.global.intro.local_class.for_module(v.module) + cur_c = cur_m.global.intro.local_class.for_module(v.mmmodule) end var j = 0 while j < v.local_class.cshe.direct_greaters.length do var c = v.local_class.cshe.direct_greaters[j] - if c.global.is_interface or c.global.is_universal or c.global.is_mixin then + if c.global.is_interface or c.global.is_enum or c.global.is_mixin then j += 1 else if cur_c != null and (c.cshe <= cur_c or cur_c.global.is_mixin) then if c == cur_c then j += 1 @@ -252,7 +260,7 @@ redef class AConcreteInitPropdef i += 1 if i < l then cur_m = explicit_super_init_calls[i] - cur_c = cur_m.global.intro.local_class.for_module(v.module) + cur_c = cur_m.global.intro.local_class.for_module(v.mmmodule) else cur_m = null cur_c = null @@ -272,7 +280,7 @@ end redef class AParam redef fun after_typing(v) do - v.variable_ctx.add(variable) + v.scope_ctx.add_variable(variable) end end @@ -283,19 +291,18 @@ redef class AClosureDecl redef fun accept_typing(v) do # Register the closure for ClosureCallExpr - v.variable_ctx.add(variable) + v.scope_ctx.add_variable(variable) - 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) + var old_flow_ctx = v.flow_ctx + var old_base_flow_ctx = v.base_flow_ctx + v.base_flow_ctx = v.flow_ctx var blist: nullable Array[AExpr] = null var t = v.local_property.signature.return_type if t != null then blist = new Array[AExpr] var escapable = new EscapableClosure(self, variable.closure, blist) _escapable = escapable - v.escapable_ctx.push(escapable, null) + v.scope_ctx.push_escapable(escapable, null) v.is_default_closure_definition = true @@ -304,7 +311,7 @@ redef class AClosureDecl v.is_default_closure_definition = false if n_expr != null then - if v.variable_ctx.unreash == false then + if v.flow_ctx.unreash == false then if variable.closure.signature.return_type != null then v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).") else if variable.closure.is_break and escapable.break_list != null then @@ -316,9 +323,9 @@ redef class AClosureDecl v.check_conform_expr(x, t) end - v.variable_ctx = old_var_ctx - v.base_variable_ctx = old_base_var_ctx - v.escapable_ctx.pop + v.flow_ctx = old_flow_ctx + v.base_flow_ctx = old_base_flow_ctx + v.scope_ctx.pop end end @@ -365,11 +372,11 @@ redef class AExpr # The variable accessed is any fun its_variable: nullable Variable do return null - # The variable type information if current boolean expression is true - readable private var _if_true_variable_ctx: nullable VariableContext + # The control flow information if current boolean expression is true + readable private var _if_true_flow_ctx: nullable FlowContext - # The variable type information if current boolean expression is false - readable private var _if_false_variable_ctx: nullable VariableContext + # The control flow information if current boolean expression is false + readable private var _if_false_flow_ctx: nullable FlowContext end redef class AVardeclExpr @@ -380,9 +387,9 @@ redef class AVardeclExpr do var va = new VarVariable(n_id.to_symbol, n_id) _variable = va - v.variable_ctx.add(va) + v.scope_ctx.add_variable(va) var ne = n_expr - if ne != null then v.variable_ctx.mark_is_set(va) + if ne != null then v.mark_is_set(va) if n_type != null then if not n_type.is_typed then return @@ -404,10 +411,10 @@ redef class ABlockExpr redef fun accept_typing(v) do for e in n_expr do - if not v.variable_ctx.unreash then + if not v.flow_ctx.unreash then v.enter_visit(e) - else if not v.variable_ctx.already_unreash then - v.variable_ctx.already_unreash = true + else if not v.flow_ctx.already_unreash then + v.flow_ctx.already_unreash = true v.error(e, "Error: unreachable statement.") end end @@ -443,7 +450,7 @@ redef class AContinueExpr redef fun after_typing(v) do v.mark_unreash(self) - var esc = compute_escapable_block(v.escapable_ctx) + var esc = compute_escapable_block(v.scope_ctx) if esc == null then return if esc.is_break_block then @@ -466,11 +473,12 @@ end redef class ABreakExpr redef fun after_typing(v) do + var old_flow_ctx = v.flow_ctx v.mark_unreash(self) - var esc = compute_escapable_block(v.escapable_ctx) + var esc = compute_escapable_block(v.scope_ctx) if esc == null then return - esc.break_variable_contexts.add(v.variable_ctx) + esc.break_flow_contexts.add(old_flow_ctx) var bl = esc.break_list if n_expr == null and bl != null then @@ -495,7 +503,7 @@ end # An abstract control structure with feature escapable block class AAbsControl -special AExpr + super AExpr # The corresponding escapable block readable var _escapable: nullable EscapableBlock @@ -504,32 +512,31 @@ special AExpr do # Register the escapable block _escapable = escapable - v.escapable_ctx.push(escapable, n_label) + v.scope_ctx.push_escapable(escapable, n_label) - # Save an prepae the variable contextes - var old_var_ctx = v.variable_ctx - var old_base_var_ctx = v.base_variable_ctx - if is_loop then v.base_variable_ctx = v.variable_ctx - v.variable_ctx = old_var_ctx.sub(self) + # Save an prepare the contextes + var old_flow_ctx = v.flow_ctx + var old_base_flow_ctx = v.base_flow_ctx + if is_loop then v.base_flow_ctx = v.flow_ctx # Do the main processing process_control_inside(v) # 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) + if not v.flow_ctx.unreash then + escapable.break_flow_contexts.add(v.flow_ctx) end # Merge all exit contexts - if escapable.break_variable_contexts.is_empty then - v.variable_ctx = old_var_ctx + if escapable.break_flow_contexts.is_empty then + v.flow_ctx = old_flow_ctx v.mark_unreash(self) else - v.variable_ctx = old_var_ctx.merge(self, escapable.break_variable_contexts, v.base_variable_ctx) + v.flow_ctx = old_base_flow_ctx.merge(self, escapable.break_flow_contexts) end - if is_loop then v.base_variable_ctx = old_base_var_ctx - v.escapable_ctx.pop + if is_loop then v.base_flow_ctx = old_base_flow_ctx + v.scope_ctx.pop _is_typed = true end @@ -538,7 +545,7 @@ special AExpr end redef class ADoExpr -special AAbsControl + super AAbsControl redef fun accept_typing(v) do process_control(v, new BreakOnlyEscapableBlock(self), n_label, false) @@ -546,41 +553,41 @@ special AAbsControl redef fun process_control_inside(v) do - v.enter_visit(n_block) + v.enter_visit_block(n_block) end end redef class AIfExpr redef fun accept_typing(v) do - var old_var_ctx = v.variable_ctx v.enter_visit(n_expr) v.check_conform_expr(n_expr, v.type_bool) # Prepare 'then' context - v.use_if_true_variable_ctx(n_expr) + var old_flow_ctx = v.flow_ctx + v.use_if_true_flow_ctx(n_expr) # Process the 'then' v.enter_visit_block(n_then) # Remember what appened in the 'then' - var then_var_ctx = v.variable_ctx + var then_flow_ctx = v.flow_ctx # Prepare 'else' context - v.variable_ctx = old_var_ctx - v.use_if_false_variable_ctx(n_expr) + v.flow_ctx = old_flow_ctx + v.use_if_false_flow_ctx(n_expr) # Process the 'else' v.enter_visit_block(n_else) # Merge 'then' and 'else' contexts - v.variable_ctx = old_var_ctx.merge_reash(self, then_var_ctx, v.variable_ctx, v.base_variable_ctx) + v.flow_ctx = v.base_flow_ctx.merge_reash(self, then_flow_ctx, v.flow_ctx) _is_typed = true end end redef class AWhileExpr -special AAbsControl + super AAbsControl redef fun accept_typing(v) do process_control(v, new EscapableBlock(self), n_label, true) @@ -588,7 +595,7 @@ special AAbsControl redef fun process_control_inside(v) do - var old_var_ctx = v.variable_ctx + var old_flow_ctx = v.flow_ctx # Process condition v.enter_visit(n_expr) @@ -599,20 +606,20 @@ special AAbsControl end # Prepare inside context (assert cond) - v.use_if_true_variable_ctx(n_expr) + v.use_if_true_flow_ctx(n_expr) # Process inside v.enter_visit_block(n_block) # 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.flow_ctx = old_flow_ctx + v.use_if_false_flow_ctx(n_expr) + escapable.break_flow_contexts.add(v.flow_ctx) end end redef class ALoopExpr -special AAbsControl + super AAbsControl redef fun accept_typing(v) do process_control(v, new EscapableBlock(self), n_label, true) @@ -629,9 +636,9 @@ special AAbsControl end redef class AForExpr -special AAbsControl - var _variable: nullable AutoVariable - redef fun variable do return _variable.as(not null) + super AAbsControl + var _variables: nullable Array[AutoVariable] + redef fun variables do return _variables.as(not null) redef fun accept_typing(v) do @@ -640,32 +647,75 @@ special AAbsControl redef fun process_control_inside(v) do - var old_var_ctx = v.variable_ctx + v.scope_ctx.push(self) + var old_flow_ctx = v.flow_ctx - # Create the automatic variable - var va = new AutoVariable(n_id.to_symbol, n_id) - _variable = va - v.variable_ctx.add(va) + do_typing(v) - # Process collection - v.enter_visit(n_expr) + # Process inside + v.enter_visit_block(n_block) + + # end == begin of the loop + v.flow_ctx = old_flow_ctx + v.scope_ctx.pop + end + + private fun do_typing(v: TypingVisitor) + do + # Create the automatic variables + var vas = new Array[AutoVariable] + for n_id in n_ids do + var va = new AutoVariable(n_id.to_symbol, n_id) + v.scope_ctx.add_variable(va) + vas.add(va) + end + _variables = vas - if not v.check_conform_expr(n_expr, v.type_collection) then return + # Process reciever + v.enter_visit(n_expr) + if not v.check_expr(n_expr) then return var expr_type = n_expr.stype - # Get iterator - var meth_iterator = v.get_method(expr_type, once "iterator".to_symbol) - var iter_type = meth_iterator.signature_for(expr_type).return_type.as(not null) - var meth_item = v.get_method(iter_type, once ("item".to_symbol)) - var va_stype = meth_item.signature_for(iter_type).return_type.as(not null) - if not n_expr.is_self then va_stype = va_stype.not_for_self - va.stype = va_stype + if expr_type.is_nullable then + v.error(n_expr, "Type error: 'for' on a nullable expression.") + return + end - # Process inside - v.enter_visit_block(n_block) + # Get iterate + var iterate_name = once "iterate".to_symbol + if not expr_type.local_class.has_global_property_by_name(iterate_name) then + v.error(n_expr, "Type error: Expected a type with an 'iterate' method. Found {expr_type}.") + return + end + var prop = expr_type.local_class.select_method(iterate_name) + prop.global.check_visibility(v, self, v.mmmodule, n_expr.is_self) + var psig = prop.signature_for(expr_type) + if not n_expr.is_self then psig = psig.not_for_self + if psig.arity != 0 then + v.error(self, "Error: 'iterate' incompatible with 'for': require no arguments.") + return + else if psig.closures.length != 1 then + v.error(self, "Error: 'iterate' incompatible with 'for': require one closure.") + return + end + psig = psig.closures.first.signature + if psig.return_type != null then + v.error(self, "Error: 'iterate' incompatible with 'for': require one procedural closure.") + return + end + if vas.length != psig.arity then + if psig.arity == 1 then + v.error(self, "Error: Expected {psig.arity} variable {psig}, found {vas.length}.") + else + v.error(self, "Error: Expected {psig.arity} variables {psig}, found {vas.length}.") + end + return + end - # end == begin of the loop - v.variable_ctx = old_var_ctx + # Type the automatic variables + for i in [0..vas.length[ do + vas[i].stype = psig[i] + end end end @@ -678,14 +728,14 @@ redef class AAssertExpr # Process optional 'else' part if n_else != null then - var old_var_ctx = v.variable_ctx - v.use_if_false_variable_ctx(n_expr) + var old_flow_ctx = v.flow_ctx + v.use_if_false_flow_ctx(n_expr) v.enter_visit(n_else) - v.variable_ctx = old_var_ctx + v.flow_ctx = old_flow_ctx end # Prepare outside - v.use_if_true_variable_ctx(n_expr) + v.use_if_true_flow_ctx(n_expr) _is_typed = true end end @@ -700,8 +750,8 @@ redef class AVarExpr redef fun after_typing(v) do - v.variable_ctx.check_is_set(self, variable) - _stype = v.variable_ctx.stype(variable) + v.flow_ctx.check_is_set(self, variable) + _stype = v.flow_ctx.stype(variable) _is_typed = _stype != null end end @@ -709,15 +759,15 @@ end redef class AVarAssignExpr redef fun after_typing(v) do - v.variable_ctx.mark_is_set(variable) + v.mark_is_set(variable) # Check the base type - var btype = v.base_variable_ctx.stype(variable) + var btype = v.base_flow_ctx.stype(variable) if not v.check_expr(n_value) then return if btype != null and not v.check_conform_expr(n_value, btype) then return # Always cast - v.variable_ctx = v.variable_ctx.sub_with(self, variable, n_value.stype) + v.flow_ctx = v.flow_ctx.sub_with(self, variable, n_value.stype) _is_typed = true end @@ -743,7 +793,7 @@ redef class AReassignFormExpr return null end var prop = lc.select_method(name) - prop.global.check_visibility(v, self, v.module, false) + prop.global.check_visibility(v, self, v.mmmodule, false) var psig = prop.signature_for(type_lvalue) _assign_method = prop if not v.check_conform_expr(n_value, psig[0].not_for_self) then return null @@ -757,19 +807,19 @@ end redef class AVarReassignExpr redef fun after_typing(v) do - v.variable_ctx.check_is_set(self, variable) - v.variable_ctx.mark_is_set(variable) - var t = v.variable_ctx.stype(variable) + v.flow_ctx.check_is_set(self, variable) + v.mark_is_set(variable) + var t = v.flow_ctx.stype(variable) var t2 = do_rvalue_typing(v, t) if t2 == null then return # Check the base type - var btype = v.base_variable_ctx.stype(variable) + var btype = v.base_flow_ctx.stype(variable) if not v.check_expr(n_value) then return if btype != null and not v.check_conform(n_value, t2, btype) then return # Always cast - v.variable_ctx = v.variable_ctx.sub_with(self, variable, t2) + v.flow_ctx = v.flow_ctx.sub_with(self, variable, t2) _is_typed = true end @@ -794,7 +844,7 @@ redef class ASelfExpr redef fun after_typing(v) do _variable = v.self_var - _stype = v.variable_ctx.stype(variable) + _stype = v.flow_ctx.stype(variable) _is_typed = true end @@ -808,30 +858,30 @@ end redef class AIfexprExpr redef fun accept_typing(v) do - var old_var_ctx = v.variable_ctx + var old_flow_ctx = v.flow_ctx # Process condition v.enter_visit(n_expr) v.check_conform_expr(n_expr, v.type_bool) # Prepare 'then' context - v.use_if_true_variable_ctx(n_expr) + v.use_if_true_flow_ctx(n_expr) # Process 'then' v.enter_visit_block(n_then) # Remember what appened in the 'then' - var then_var_ctx = v.variable_ctx + var then_flow_ctx = v.flow_ctx # Prepare 'else' context - v.variable_ctx = old_var_ctx - v.use_if_false_variable_ctx(n_expr) + v.flow_ctx = old_flow_ctx + v.use_if_false_flow_ctx(n_expr) # Process 'else' v.enter_visit_block(n_else) # Merge 'then' and 'else' contexts - v.variable_ctx = old_var_ctx.merge_reash(self, then_var_ctx, v.variable_ctx, v.base_variable_ctx) + v.flow_ctx = v.base_flow_ctx.merge_reash(self, then_flow_ctx, v.flow_ctx) var stype = v.check_conform_multiexpr(null, [n_then, n_else]) if stype == null then return @@ -852,7 +902,7 @@ end redef class AOrExpr redef fun accept_typing(v) do - var old_var_ctx = v.variable_ctx + var old_flow_ctx = v.flow_ctx var stype = v.type_bool _stype = stype @@ -860,17 +910,17 @@ redef class AOrExpr v.enter_visit(n_expr) # Prepare right operand context - v.use_if_false_variable_ctx(n_expr) + v.use_if_false_flow_ctx(n_expr) # Process right operand v.enter_visit(n_expr2) - if n_expr2.if_false_variable_ctx != null then - _if_false_variable_ctx = n_expr2.if_false_variable_ctx + if n_expr2.if_false_flow_ctx != null then + _if_false_flow_ctx = n_expr2.if_false_flow_ctx else - _if_false_variable_ctx = v.variable_ctx + _if_false_flow_ctx = v.flow_ctx end - v.variable_ctx = old_var_ctx + v.flow_ctx = old_flow_ctx v.check_conform_expr(n_expr, stype) v.check_conform_expr(n_expr2, stype) @@ -882,24 +932,24 @@ end redef class AAndExpr redef fun accept_typing(v) do - var old_var_ctx = v.variable_ctx + var old_flow_ctx = v.flow_ctx var stype = v.type_bool # Process left operand v.enter_visit(n_expr) # Prepare right operand context - v.use_if_true_variable_ctx(n_expr) + v.use_if_true_flow_ctx(n_expr) # Process right operand v.enter_visit(n_expr2) - if n_expr2.if_true_variable_ctx != null then - _if_true_variable_ctx = n_expr2.if_true_variable_ctx + if n_expr2.if_true_flow_ctx != null then + _if_true_flow_ctx = n_expr2.if_true_flow_ctx else - _if_true_variable_ctx = v.variable_ctx + _if_true_flow_ctx = v.flow_ctx end - v.variable_ctx = old_var_ctx + v.flow_ctx = old_flow_ctx v.check_conform_expr(n_expr, stype) v.check_conform_expr(n_expr2, stype) @@ -914,8 +964,8 @@ redef class ANotExpr v.check_conform_expr(n_expr, v.type_bool) # Invert if_true/if_false information - _if_false_variable_ctx = n_expr._if_true_variable_ctx - _if_true_variable_ctx = n_expr._if_false_variable_ctx + _if_false_flow_ctx = n_expr._if_true_flow_ctx + _if_true_flow_ctx = n_expr._if_false_flow_ctx _stype = v.type_bool _is_typed = true @@ -925,7 +975,7 @@ end redef class AOrElseExpr redef fun after_typing(v) do - var old_var_ctx = v.variable_ctx + var old_flow_ctx = v.flow_ctx # Process left operand v.enter_visit(n_expr) @@ -942,7 +992,7 @@ redef class AOrElseExpr # Prepare the else context : ie the first expression is null var variable = n_expr.its_variable if variable != null then - v.variable_ctx.sub_with(self, variable, v.type_none) + v.flow_ctx.sub_with(self, variable, v.type_none) end # Process right operand @@ -950,7 +1000,7 @@ redef class AOrElseExpr v.check_expr(n_expr) # Restore the context - v.variable_ctx = old_var_ctx + v.flow_ctx = old_flow_ctx # Merge the types var stype = v.check_conform_multiexpr(t, [n_expr2]) @@ -1091,7 +1141,7 @@ redef class ASuperExpr var stype: nullable MMType = null for prop in precs do assert prop isa MMMethod - var t = prop.signature_for(v.self_var.stype.as(not null)).return_type.for_module(v.module).adapt_to(v.local_property.signature.recv) + var t = prop.signature_for(v.self_var.stype.as(not null)).return_type.for_module(v.mmmodule).adapt_to(v.local_property.signature.recv) stypes.add(t) if stype == null or stype < t then stype = t @@ -1132,8 +1182,8 @@ redef class AAttrFormExpr return end var prop = lc.select_attribute(name) - if v.module.visibility_for(prop.global.local_class.module) < 3 then - v.error(self, "Error: Attribute {name} from {prop.global.local_class.module} is invisible in {v.module}") + if v.mmmodule.visibility_for(prop.global.local_class.mmmodule) < 3 then + v.error(self, "Error: Attribute {name} from {prop.global.local_class.mmmodule} is invisible in {v.mmmodule}") end _prop = prop var at = prop.signature_for(type_recv).return_type @@ -1275,9 +1325,9 @@ redef class AAbsAbsSendExpr var csi = psig.closure_named(cni) if csi != null then var esc = new EscapableClosure(cdi, csi, break_list) - v.escapable_ctx.push(esc, n_label) + v.scope_ctx.push_escapable(esc, n_label) cdi.accept_typing2(v, esc) - v.escapable_ctx.pop + v.scope_ctx.pop else if cs.length == 1 then v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closure is !{cs.first.name}.") else @@ -1356,7 +1406,7 @@ redef class AAbsSendExpr # Get the signature for a local property and a receiver private fun get_signature(v: TypingVisitor, type_recv: MMType, prop: MMMethod, recv_is_self: Bool): MMSignature do - prop.global.check_visibility(v, self, v.module, recv_is_self) + prop.global.check_visibility(v, self, v.mmmodule, recv_is_self) var psig = prop.signature_for(type_recv) if not recv_is_self then psig = psig.not_for_self return psig @@ -1378,7 +1428,7 @@ redef class ASuperInitCall if parent != v.top_block and self != v.top_block then v.error(self, "Error: Constructor invocation {property} must not be in nested block.") end - var cla = v.module[property.global.intro.local_class.global] + var cla = v.mmmodule[property.global.intro.local_class.global] var prev_class: nullable MMLocalClass = null var esic = v.explicit_super_init_calls.as(not null) if not esic.is_empty then @@ -1542,8 +1592,8 @@ redef class AEqExpr do var variable = n.its_variable 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) + _if_false_flow_ctx = v.flow_ctx.sub_with(self, variable, n.stype.as_notnull) + _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, v.type_none) end end end @@ -1573,8 +1623,8 @@ redef class ANeExpr do var variable = n.its_variable 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) + _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, n.stype.as_notnull) + _if_false_flow_ctx = v.flow_ctx.sub_with(self, variable, v.type_none) end end end @@ -1584,12 +1634,18 @@ end redef class ALeExpr redef fun name do return once "<=".to_symbol end +redef class ALlExpr + redef fun name do return once "<<".to_symbol +end redef class AGtExpr redef fun name do return once ">".to_symbol end redef class AGeExpr redef fun name do return once ">=".to_symbol end +redef class AGgExpr + redef fun name do return once ">>".to_symbol +end redef class APlusExpr redef fun name do return once "+".to_symbol end @@ -1619,7 +1675,7 @@ redef class ACallFormExpr do if n_expr.is_implicit_self then var name = n_id.to_symbol - var variable = v.variable_ctx[name] + var variable = v.scope_ctx[name] if variable != null then var n: AExpr if variable isa ClosureVariable then @@ -1778,35 +1834,36 @@ redef class AClosureDef _closure = esc.closure - 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) + v.scope_ctx.push(self) + var old_flow_ctx = v.flow_ctx + var old_base_flow_ctx = v.base_flow_ctx + v.base_flow_ctx = v.flow_ctx variables = new Array[AutoVariable] for i in [0..n_ids.length[ do var va = new AutoVariable(n_ids[i].to_symbol, n_ids[i]) variables.add(va) va.stype = sig[i] - v.variable_ctx.add(va) + v.scope_ctx.add_variable(va) end _accept_typing2 = true accept_typing(v) - if v.variable_ctx.unreash == false then + if v.flow_ctx.unreash == false then if closure.signature.return_type != null then v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).") else if closure.is_break and esc.break_list != null then v.error(self, "Control error: Reached end of break block (a 'break' with a value was expected).") end end - v.variable_ctx = old_var_ctx - v.base_variable_ctx = old_base_var_ctx + v.flow_ctx = old_flow_ctx + v.base_flow_ctx = old_base_flow_ctx + v.scope_ctx.pop end end class ATypeCheckExpr -special AExpr + super AExpr private fun check_expr_cast(v: TypingVisitor, n_expr: AExpr, n_type: AType) do if not v.check_expr(n_expr) then return @@ -1837,14 +1894,14 @@ special AExpr end redef class AIsaExpr -special ATypeCheckExpr + super ATypeCheckExpr redef fun after_typing(v) do check_expr_cast(v, n_expr, n_type) if not n_type.is_typed then return var variable = n_expr.its_variable if variable != null then - _if_true_variable_ctx = v.variable_ctx.sub_with(self, variable, n_type.stype) + _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, n_type.stype) end _stype = v.type_bool _is_typed = true @@ -1852,7 +1909,7 @@ special ATypeCheckExpr end redef class AAsCastExpr -special ATypeCheckExpr + super ATypeCheckExpr redef fun after_typing(v) do check_expr_cast(v, n_expr, n_type)