X-Git-Url: http://nitlanguage.org diff --git a/src/syntax/typing.nit b/src/syntax/typing.nit index 27e469c..5e75e57 100644 --- a/src/syntax/typing.nit +++ b/src/syntax/typing.nit @@ -271,7 +271,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 +284,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,20 +356,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 ne != null then + if not v.check_expr(ne) then return + va.stype = ne.stype else - if not v.check_expr(n_expr.as(not null)) then return - va.stype = n_expr.stype + va.stype = v.type_object.as_nullable end _is_typed = true end @@ -529,6 +538,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 +558,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 +602,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 +632,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 +672,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 @@ -643,6 +695,10 @@ redef class AReassignFormExpr return null end var name = n_assign_op.method_name + if type_lvalue isa MMTypeNone then + v.error(self, "Error: Method '{name}' call on 'null'.") + return null + end var lc = type_lvalue.local_class if not lc.has_global_property_by_name(name) then v.error(self, "Error: Method '{name}' doesn't exists in {type_lvalue}.") @@ -671,7 +727,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 @@ -723,15 +780,24 @@ redef class AIfexprExpr v.use_if_true_variable_ctx(n_expr) # Process 'then' + v.variable_ctx = v.variable_ctx.sub(n_then) v.enter_visit(n_then) + # Remember what appened in the 'then' + var then_var_ctx = v.variable_ctx + # Prepare 'else' context v.variable_ctx = old_var_ctx v.use_if_false_variable_ctx(n_expr) # Process 'else' + v.variable_ctx = v.variable_ctx.sub(n_else) v.enter_visit(n_else) + # Merge 'then' and 'else' contexts + old_var_ctx.merge2(then_var_ctx, v.variable_ctx, v.base_variable_ctx) + v.variable_ctx = old_var_ctx + var stype = v.check_conform_multiexpr(null, [n_then, n_else]) if stype == null then return @@ -980,6 +1046,10 @@ redef class AAttrFormExpr if not v.check_expr(n_expr) then return var type_recv = n_expr.stype var name = n_id.to_symbol + if type_recv isa MMTypeNone then + v.error(self, "Error: Attribute '{name}' access on 'null'.") + return + end var lc = type_recv.local_class if not lc.has_global_property_by_name(name) then v.error(self, "Error: Attribute {name} doesn't exists in {type_recv}.") @@ -1076,7 +1146,7 @@ redef class AAbsAbsSendExpr 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.") + v.error(self, "Error: arity missmatch; prototype is '{name}{psig}'.") return false end var arg_idx = 0 @@ -1124,12 +1194,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 @@ -1161,16 +1242,20 @@ redef class AAbsSendExpr private fun get_property(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, name: Symbol): nullable MMMethod do + if type_recv isa MMTypeNone then + v.error(self, "Error: Method '{name}' call on 'null'.") + return null + end var lc = type_recv.local_class var prop: nullable MMMethod = null if lc.has_global_property_by_name(name) then prop = lc.select_method(name) if prop == null and v.local_property.global.is_init then - var props = type_recv.local_class.super_methods_named(name) + var props = lc.super_methods_named(name) if props.length > 1 then v.error(self, "Error: Ambigous method name '{name}' for {props.join(", ")}. Use explicit designation.") return null else if props.length == 1 then - var p = type_recv.local_class[props.first.global] + var p = lc[props.first.global] assert p isa MMMethod prop = p end @@ -1363,7 +1448,11 @@ redef class AEqExpr end if n_expr.stype isa MMTypeNone then - try_to_isa(v, n_expr2) + if n_expr2.stype isa MMTypeNone then + v.warning(self, "Warning: comparaison between 2 null values.") + else + try_to_isa(v, n_expr2) + end else if n_expr2.stype isa MMTypeNone then try_to_isa(v, n_expr) end @@ -1389,7 +1478,11 @@ redef class ANeExpr end if n_expr.stype isa MMTypeNone then - try_to_isa(v, n_expr2) + if n_expr2.stype isa MMTypeNone then + v.warning(self, "Warning: comparaison between 2 null values.") + else + try_to_isa(v, n_expr2) + end else if n_expr2.stype isa MMTypeNone then try_to_isa(v, n_expr) end @@ -1517,6 +1610,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 +1660,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) @@ -1578,8 +1689,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 @@ -1590,8 +1701,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) @@ -1603,8 +1714,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 @@ -1624,6 +1735,9 @@ special AExpr v.warning(self, "Warning: Expression is already a {ttype}.") else if etype < ttype then v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.") + else if etype isa MMTypeNone then + # ttype is not nullable because of prevous test + v.warning(self, "Warning: Expression is null therefore cannot be a {ttype}.") else if etype.is_nullable and etype.as_notnull == ttype then if ttype isa MMTypeFormal and ttype.bound.is_nullable then # No warning in this case since with