- # 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
-
- # Body evaluation
- if n_block != null then v.enter_visit(n_block)
-
- # pop context
- v.variable_ctx = old_var_ctx
- v.base_variable_ctx = old_base_var_ctx
- v.escapable_ctx.pop
- _is_typed = true
+ 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