X-Git-Url: http://nitlanguage.org diff --git a/src/syntax/typing.nit b/src/syntax/typing.nit index 8d69a52..70e7d5d 100644 --- a/src/syntax/typing.nit +++ b/src/syntax/typing.nit @@ -136,6 +136,9 @@ special AbsSyntaxVisitor end end +redef class VarVariable + redef readable var _is_typed: Bool = false +end ############################################################################### @@ -271,7 +274,10 @@ redef class AClosureDecl v.base_variable_ctx = v.variable_ctx v.variable_ctx = v.variable_ctx.sub(self) - var escapable = new EscapableClosure(self, variable.closure, null) + 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) @@ -281,11 +287,14 @@ redef class AClosureDecl if v.variable_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 then - v.error(self, "Control error: Reached end of break block (an 'abort' was expected).") + else if variable.closure.is_break and escapable.break_list != null then + v.error(self, "Control error: Reached end of break block (a 'break' with a value was expected).") end end end + if blist != null then for x in blist do + v.check_conform_expr(x, t) + end old_var_ctx.merge(v.variable_ctx) v.variable_ctx = old_var_ctx @@ -350,21 +359,23 @@ redef class AVardeclExpr redef fun after_typing(v) do - var va = new VarVariable(n_id.to_symbol, self) + var va = new VarVariable(n_id.to_symbol, n_id) _variable = va v.variable_ctx.add(va) - if n_expr != null then v.variable_ctx.mark_is_set(va) + var ne = n_expr + if ne != null then v.variable_ctx.mark_is_set(va) if n_type != null then if not n_type.is_typed then return va.stype = n_type.stype - if n_expr != null then - v.check_conform_expr(n_expr.as(not null), va.stype) + if ne != null then + v.check_conform_expr(ne, va.stype) end - else - if not v.check_expr(n_expr.as(not null)) then return + else if ne != null then + if not v.check_expr(ne) then return va.stype = n_expr.stype end + va._is_typed = true _is_typed = true end end @@ -545,6 +556,33 @@ redef class AWhileExpr end end +redef class ALoopExpr + # The corresponding escapable block + readable var _escapable: nullable EscapableBlock + + redef fun accept_typing(v) + do + var escapable = new EscapableBlock(self) + _escapable = escapable + v.escapable_ctx.push(escapable, n_label) + 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.variable_ctx = v.variable_ctx.sub(n_block.as(not null)) + v.enter_visit(n_block) + end + + v.variable_ctx = old_var_ctx + v.base_variable_ctx = old_base_var_ctx + v.escapable_ctx.pop + _is_typed = true + end +end + redef class AForExpr var _variable: nullable AutoVariable redef fun variable do return _variable.as(not null) @@ -562,7 +600,7 @@ redef class AForExpr 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 va = new AutoVariable(n_id.to_symbol, self) + var va = new AutoVariable(n_id.to_symbol, n_id) _variable = va v.variable_ctx.add(va) @@ -592,9 +630,21 @@ redef class AForExpr end redef class AAssertExpr - redef fun after_typing(v) + redef fun accept_typing(v) do + # Process condition + v.enter_visit(n_expr) v.check_conform_expr(n_expr, v.type_bool) + + # Process optional 'else' part + if n_else != null then + var old_var_ctx = v.variable_ctx + v.use_if_false_variable_ctx(n_expr) + v.enter_visit(n_else) + v.variable_ctx = old_var_ctx + end + + # Prepare outside v.use_if_true_variable_ctx(n_expr) _is_typed = true end @@ -620,11 +670,11 @@ redef class AVarAssignExpr redef fun after_typing(v) do v.variable_ctx.mark_is_set(variable) - var t = v.variable_ctx.stype(variable) # Check the base type var btype = v.base_variable_ctx.stype(variable) - if not v.check_conform_expr(n_value, btype) then return + 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.stype(variable) = n_value.stype @@ -671,7 +721,8 @@ redef class AVarReassignExpr # Check the base type var btype = v.base_variable_ctx.stype(variable) - if not v.check_conform(n_value, t2, btype) then return + 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.stype(variable) = t2 @@ -1124,12 +1175,23 @@ redef class AAbsAbsSendExpr # Process each closure definition for i in [0..arity[ do - var csi = cs[i] var cdi = cd[i] - var esc = new EscapableClosure(cdi, csi, break_list) - v.escapable_ctx.push(esc, n_label) - cdi.accept_typing2(v, esc) - v.escapable_ctx.pop + var cni = cdi.n_id.to_symbol + 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) + cdi.accept_typing2(v, esc) + v.escapable_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 + var a = new Array[String] + for c in cs do + a.add("!{c.name}") + end + v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closures are {a.join(",")}.") + end end # Check break type conformity @@ -1517,6 +1579,14 @@ end redef class ABraExpr redef fun name do return once "[]".to_symbol redef fun compute_raw_arguments do return n_args.to_a + redef fun closure_defs + do + if n_closure_defs.is_empty then + return null + else + return n_closure_defs.to_a + end + end end redef class ABraAssignExpr @@ -1559,6 +1629,16 @@ redef class AClosureCallExpr end end +redef class AClosureId + fun to_symbol: Symbol is abstract +end +redef class ASimpleClosureId + redef fun to_symbol: Symbol do return n_id.to_symbol +end +redef class ABreakClosureId + redef fun to_symbol: Symbol do return n_kwbreak.to_symbol +end + redef class AClosureDef var _closure: nullable MMClosure redef fun closure do return _closure.as(not null) @@ -1591,7 +1671,7 @@ redef class AClosureDef v.variable_ctx = v.variable_ctx.sub(self) variables = new Array[AutoVariable] for i in [0..n_ids.length[ do - var va = new AutoVariable(n_ids[i].to_symbol, self) + var va = new AutoVariable(n_ids[i].to_symbol, n_ids[i]) variables.add(va) va.stype = sig[i] v.variable_ctx.add(va) @@ -1603,8 +1683,8 @@ redef class AClosureDef if v.variable_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 then - v.error(self, "Control error: Reached end of break block (a 'break' 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