X-Git-Url: http://nitlanguage.org diff --git a/src/syntax/typing.nit b/src/syntax/typing.nit index 4608ccd..f9fb4a6 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 @@ -529,6 +540,10 @@ redef class AWhileExpr v.enter_visit(n_expr) v.check_conform_expr(n_expr, v.type_bool) + if n_expr isa ATrueExpr then + v.warning(self, "Warning: use 'loop' instead of 'while true do'.") + end + # Prepare inside context (assert cond) v.use_if_true_variable_ctx(n_expr) @@ -545,6 +560,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 +604,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 +634,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 +674,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 +725,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 @@ -909,6 +964,7 @@ end redef class ASuperExpr redef readable var _init_in_superclass: nullable MMMethod + redef fun compute_raw_arguments do return n_args.to_a redef fun after_typing(v) do var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters @@ -936,7 +992,7 @@ redef class ASuperExpr register_super_init_call(v, p) if n_args.length > 0 then var signature = get_signature(v, v.self_var.stype.as(not null), p, true) - _arguments = process_signature(v, signature, p.name, n_args.to_a) + process_signature(v, signature, p.name, compute_raw_arguments) end else v.error(self, "Error: No super method to call for {v.local_property}.") @@ -1045,45 +1101,56 @@ redef class AAbsAbsSendExpr redef fun prop_signature do return _prop_signature.as(not null) var _prop_signature: nullable MMSignature - # The real arguments used (after star transformation) (once computed) - redef fun arguments do return _arguments.as(not null) - var _arguments: nullable Array[AExpr] + # Raw arguments used (without vararg transformation) + redef fun raw_arguments: Array[AExpr] + do + var res = _raw_arguments_cache + if res != null then + return res + else + res = compute_raw_arguments + if res == null then res = new Array[AExpr] + _raw_arguments_cache = res + return res + end + end + + var _raw_arguments_cache: nullable Array[AExpr] = null + + fun compute_raw_arguments: nullable Array[AExpr] + do + print "{location} no compute_raw_arguments" + return null + end # Check the conformity of a set of arguments `raw_args' to a signature. - private fun process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: nullable Array[AExpr]): nullable Array[AExpr] + private fun process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: nullable Array[AExpr]): Bool do var par_vararg = psig.vararg_rank var par_arity = psig.arity var raw_arity: Int if raw_args == null then raw_arity = 0 else raw_arity = raw_args.length if par_arity > raw_arity or (par_arity != raw_arity and par_vararg == -1) then - v.error(self, "Error: '{name}' arity missmatch.") - return null + v.error(self, "Error: arity missmatch; prototype is '{name}{psig}'.") + return false end var arg_idx = 0 - var args = new Array[AExpr] for par_idx in [0..par_arity[ do var a: AExpr var par_type = psig[par_idx] if par_idx == par_vararg then - var star = new Array[AExpr] for i in [0..(raw_arity-par_arity)] do a = raw_args[arg_idx] v.check_conform_expr(a, par_type) - star.add(a) arg_idx = arg_idx + 1 end - var aa = new AArrayExpr.init_aarrayexpr(star) - aa.do_typing(v, par_type) - a = aa else a = raw_args[arg_idx] v.check_conform_expr(a, par_type) arg_idx = arg_idx + 1 end - args.add(a) end - return args + return true end # Check the conformity of a set of defined closures @@ -1112,12 +1179,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 @@ -1139,13 +1217,11 @@ redef class AAbsSendExpr var prop = get_property(v, type_recv, is_implicit_self, name) if prop == null then return var sig = get_signature(v, type_recv, prop, recv_is_self) - var args = process_signature(v, sig, prop.name, raw_args) - if args == null then return + if not process_signature(v, sig, prop.name, raw_args) then return var rtype = process_closures(v, sig, prop.name, closure_defs) if rtype == null and sig.return_type != null then return _prop = prop _prop_signature = sig - _arguments = args _return_type = rtype end @@ -1234,6 +1310,7 @@ redef class ASuperInitCall end redef class ANewExpr + redef fun compute_raw_arguments do return n_args.to_a redef fun after_typing(v) do if not n_type.is_typed then return @@ -1249,7 +1326,7 @@ redef class ANewExpr name = n_id.to_symbol end - do_typing(v, t, false, false, name, n_args.to_a, null) + do_typing(v, t, false, false, name, raw_arguments, null) if _prop == null then return if not prop.global.is_init then @@ -1266,9 +1343,6 @@ redef class ASendExpr # Name of the invoked property fun name: Symbol is abstract - # Raw arguments used (withour star transformation) - fun raw_arguments: nullable Array[AExpr] is abstract - # Closure definitions redef fun closure_defs: nullable Array[AClosureDef] do return null @@ -1324,7 +1398,7 @@ redef class ASendReassignExpr v.check_conform(self, t2, n_value.stype) _read_prop = prop - var old_args = arguments + raw_args = raw_args.to_a raw_args.add(n_value) do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, "{name}=".to_symbol, raw_args, null) @@ -1336,13 +1410,12 @@ redef class ASendReassignExpr end end - _arguments = old_args # FIXME: What if star parameters do not match betwen the two methods? _is_typed = true end end redef class ABinopExpr - redef fun raw_arguments do return [n_expr2] + redef fun compute_raw_arguments do return [n_expr2] end redef class AEqExpr redef fun name do return once "==".to_symbol @@ -1429,7 +1502,7 @@ end redef class AUminusExpr redef fun name do return once "unary -".to_symbol - redef fun raw_arguments do return null + redef fun compute_raw_arguments do return null end redef class ACallFormExpr @@ -1480,7 +1553,7 @@ redef class ACallExpr end redef fun name do return n_id.to_symbol - redef fun raw_arguments do return n_args.to_a + redef fun compute_raw_arguments do return n_args.to_a end redef class ACallAssignExpr @@ -1490,7 +1563,7 @@ redef class ACallAssignExpr end redef fun name do return (n_id.text + "=").to_symbol - redef fun raw_arguments do + redef fun compute_raw_arguments do var res = n_args.to_a res.add(n_value) return res @@ -1504,17 +1577,25 @@ redef class ACallReassignExpr end redef fun name do return n_id.to_symbol - redef fun raw_arguments do return n_args.to_a + redef fun compute_raw_arguments do return n_args.to_a end redef class ABraExpr redef fun name do return once "[]".to_symbol - redef fun raw_arguments do return n_args.to_a + 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 redef fun name do return once "[]=".to_symbol - redef fun raw_arguments do + redef fun compute_raw_arguments do var res = n_args.to_a res.add(n_value) return res @@ -1523,35 +1604,45 @@ end redef class ABraReassignExpr redef fun name do return once "[]".to_symbol - redef fun raw_arguments do return n_args.to_a + redef fun compute_raw_arguments do return n_args.to_a end redef class AInitExpr redef fun name do return once "init".to_symbol - redef fun raw_arguments do return n_args.to_a + redef fun compute_raw_arguments do return n_args.to_a end redef class AClosureCallExpr var _variable: nullable ClosureVariable redef fun variable do return _variable.as(not null) + redef fun compute_raw_arguments do return n_args.to_a redef fun after_typing(v) do var va = variable if va.closure.is_break then v.variable_ctx.unreash = true var sig = va.closure.signature - var args = process_signature(v, sig, n_id.to_symbol, n_args.to_a) + var s = process_signature(v, sig, n_id.to_symbol, compute_raw_arguments) if not n_closure_defs.is_empty then process_closures(v, sig, n_id.to_symbol, n_closure_defs.to_a) end - if args == null then return + if not s then return _prop_signature = sig - _arguments = args _stype = sig.return_type _is_typed = true 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) @@ -1571,8 +1662,8 @@ redef class AClosureDef _escapable = esc var sig = esc.closure.signature - if sig.arity != n_id.length then - v.error(self, "Error: {sig.arity} automatic variable names expected, {n_id.length} found.") + if sig.arity != n_ids.length then + v.error(self, "Error: {sig.arity} automatic variable names expected, {n_ids.length} found.") return end @@ -1583,8 +1674,8 @@ redef class AClosureDef v.base_variable_ctx = v.variable_ctx v.variable_ctx = v.variable_ctx.sub(self) variables = new Array[AutoVariable] - for i in [0..n_id.length[ do - var va = new AutoVariable(n_id[i].to_symbol, self) + 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) @@ -1596,8 +1687,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