# * 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)
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
# An abstract control structure with feature escapable block
class AAbsControl
-special AExpr
+ super AExpr
# The corresponding escapable block
readable var _escapable: nullable EscapableBlock
end
redef class ADoExpr
-special AAbsControl
+ super AAbsControl
redef fun accept_typing(v)
do
process_control(v, new BreakOnlyEscapableBlock(self), n_label, false)
end
redef class AWhileExpr
-special AAbsControl
+ super AAbsControl
redef fun accept_typing(v)
do
process_control(v, new EscapableBlock(self), n_label, true)
end
redef class ALoopExpr
-special AAbsControl
+ super AAbsControl
redef fun accept_typing(v)
do
process_control(v, new EscapableBlock(self), n_label, true)
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
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.scope_ctx.add_variable(va)
-
- # Process collection
- v.enter_visit(n_expr)
-
- if not v.check_conform_expr(n_expr, v.type_collection) 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
+ do_typing(v)
# Process inside
v.enter_visit_block(n_block)
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
+
+ # Process reciever
+ v.enter_visit(n_expr)
+ if not v.check_expr(n_expr) then return
+ var expr_type = n_expr.stype
+
+ if expr_type.is_nullable then
+ v.error(n_expr, "Type error: 'for' on a nullable expression.")
+ return
+ end
+
+ # 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
+
+ # Type the automatic variables
+ for i in [0..vas.length[ do
+ vas[i].stype = psig[i]
+ end
+ end
end
redef class AAssertExpr
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
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
end
redef class AIsaExpr
-special ATypeCheckExpr
+ super ATypeCheckExpr
redef fun after_typing(v)
do
check_expr_cast(v, n_expr, n_type)
end
redef class AAsCastExpr
-special ATypeCheckExpr
+ super ATypeCheckExpr
redef fun after_typing(v)
do
check_expr_cast(v, n_expr, n_type)