X-Git-Url: http://nitlanguage.org diff --git a/src/syntax/typing.nit b/src/syntax/typing.nit index e125491..863d41e 100644 --- a/src/syntax/typing.nit +++ b/src/syntax/typing.nit @@ -37,7 +37,7 @@ end # * 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) @@ -152,10 +152,10 @@ special AbsSyntaxVisitor for p in false_candidates do a.add("{p.full_name}{p.signature.as(not null)}") end - v.error(n, "Error: there is no available compatible constrctor in {c}. Discarded candidates are {a.join(", ")}.") + v.error(n, "Error: there is no available compatible constructor in {c}. Discarded candidates are {a.join(", ")}.") return null else - v.error(n, "Error: there is no available compatible constrctor in {c}.") + v.error(n, "Error: there is no available compatible constructor in {c}.") return null end end @@ -252,7 +252,7 @@ redef class AConcreteInitPropdef 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_extern 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 @@ -277,6 +277,27 @@ redef class AConcreteInitPropdef end end +redef class AExternInitPropdef + redef fun accept_typing(v) + do + v.explicit_other_init_call = false + super + end + redef fun after_typing(v) + do + super + end +end + +redef class ASignature + redef fun after_typing(v) + do + if self.n_opar != null and self.n_params.is_empty then + v.warning(self, "Warning: superfluous parentheses.") + end + end +end + redef class AParam redef fun after_typing(v) do @@ -377,6 +398,27 @@ redef class AExpr # The control flow information if current boolean expression is false readable private var _if_false_flow_ctx: nullable FlowContext + + # Wharn in case of superfluous parentheses + private fun warn_parentheses(v: AbsSyntaxVisitor) + do + end +end + +redef class AParExpr + redef fun warn_parentheses(v) + do + v.warning(self, "Warning: superfluous parentheses.") + end +end + +redef class AParExprs + redef fun after_typing(v) + do + if n_exprs.is_empty then + v.warning(self, "Warning: superfluous parentheses.") + end + end end redef class AVardeclExpr @@ -399,7 +441,13 @@ redef class AVardeclExpr end else if ne != null then if not v.check_expr(ne) then return - va.stype = ne.stype + var st = ne.stype + if st isa MMTypeNone then + va.stype = v.type_object.as_nullable + v.flow_ctx = v.flow_ctx.sub_with(self, va, st) + else + va.stype = st + end else va.stype = v.type_object.as_nullable end @@ -442,6 +490,9 @@ redef class AReturnExpr else if e != null and t != null then v.check_conform_expr(e, t) end + if e != null then + e.warn_parentheses(v) + end _is_typed = true end end @@ -459,12 +510,16 @@ redef class AContinueExpr end var t = esc.continue_stype - if n_expr == null and t != null then + var e = n_expr + if e == null and t != null then v.error(self, "Error: continue with a value required in this block.") - else if n_expr != null and t == null then + else if e != null and t == null then v.error(self, "Error: continue without value required in this block.") - else if n_expr != null and t != null then - v.check_conform_expr(n_expr.as(not null), t) + else if e != null and t != null then + v.check_conform_expr(e, t) + end + if e != null then + e.warn_parentheses(v) end _is_typed = true end @@ -481,13 +536,17 @@ redef class ABreakExpr esc.break_flow_contexts.add(old_flow_ctx) var bl = esc.break_list - if n_expr == null and bl != null then + var e = n_expr + if e == null and bl != null then v.error(self, "Error: break with a value required in this block.") - else if n_expr != null and bl == null then + else if e != null and bl == null then v.error(self, "Error: break without value required in this block.") - else if n_expr != null and bl != null then + else if e != null and bl != null then # Typing check can only be done later - bl.add(n_expr.as(not null)) + bl.add(e) + end + if e != null then + e.warn_parentheses(v) end _is_typed = true end @@ -502,8 +561,8 @@ redef class AAbortExpr end # An abstract control structure with feature escapable block -class AAbsControl -special AExpr +abstract class AAbsControl + super AExpr # The corresponding escapable block readable var _escapable: nullable EscapableBlock @@ -545,7 +604,7 @@ special AExpr end redef class ADoExpr -special AAbsControl + super AAbsControl redef fun accept_typing(v) do process_control(v, new BreakOnlyEscapableBlock(self), n_label, false) @@ -563,6 +622,8 @@ redef class AIfExpr v.enter_visit(n_expr) v.check_conform_expr(n_expr, v.type_bool) + n_expr.warn_parentheses(v) + # Prepare 'then' context var old_flow_ctx = v.flow_ctx v.use_if_true_flow_ctx(n_expr) @@ -587,7 +648,7 @@ redef class AIfExpr end redef class AWhileExpr -special AAbsControl + super AAbsControl redef fun accept_typing(v) do process_control(v, new EscapableBlock(self), n_label, true) @@ -603,6 +664,8 @@ special AAbsControl if n_expr isa ATrueExpr then v.warning(self, "Warning: use 'loop' instead of 'while true do'.") + else + n_expr.warn_parentheses(v) end # Prepare inside context (assert cond) @@ -619,7 +682,7 @@ special AAbsControl end redef class ALoopExpr -special AAbsControl + super AAbsControl redef fun accept_typing(v) do process_control(v, new EscapableBlock(self), n_label, true) @@ -636,9 +699,9 @@ special AAbsControl 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 @@ -650,24 +713,7 @@ special AAbsControl 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) @@ -676,6 +722,65 @@ special AAbsControl 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 + n_expr.warn_parentheses(v) + + # 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 @@ -684,6 +789,7 @@ redef class AAssertExpr # Process condition v.enter_visit(n_expr) v.check_conform_expr(n_expr, v.type_bool) + n_expr.warn_parentheses(v) # Process optional 'else' part if n_else != null then @@ -943,7 +1049,7 @@ redef class AOrElseExpr # Consider the type of the left operand var t = n_expr.stype if not t.is_nullable then - v.warning(n_expr, "Warning: left operant of a 'or else' is not a nullable type.") + v.warning(n_expr, "Warning: left operand of a 'or else' is not a nullable type.") else t = t.as_notnull end @@ -1028,7 +1134,7 @@ end redef class AArrayExpr redef fun after_typing(v) do - var stype = v.check_conform_multiexpr(null, n_exprs) + var stype = v.check_conform_multiexpr(null, n_exprs.n_exprs) if stype != null then do_typing(v, stype) end @@ -1086,7 +1192,7 @@ redef class ASuperExpr assert p isa MMMethod _init_in_superclass = p register_super_init_call(v, p) - if n_args.length > 0 then + if n_args.n_exprs.length > 0 then var signature = get_signature(v, v.self_var.stype.as(not null), p, true) process_signature(v, signature, p.name, compute_raw_arguments) end @@ -1118,6 +1224,123 @@ redef class ASuperExpr end end +redef class AExternCall + fun target_class_name : nullable Symbol do return null + fun target_method_name : Symbol is abstract + + redef fun after_typing(v) + do + var target_class_name = self.target_class_name + var target_method_name = self.target_method_name + + var target_class : MMLocalClass + var target_method : MMMethod + + # find class + # self.target_class_name can be redef'd by sub-classes + if target_class_name == null then + target_class = v.local_property.local_class + else + if v.local_property.mmmodule.has_global_class_named( target_class_name ) then + var global_class = v.local_property.mmmodule.global_class_named( target_class_name ) + target_class = v.local_property.mmmodule[ global_class ] + else + v.error( self, "Error: class {target_class_name.to_s}, not found." ) + return + end + end + + if target_class.has_global_property_by_name( target_method_name ) then + var global_property = target_class.get_property_by_name( target_method_name ) + + var target_property = target_class[global_property] + + if target_property isa MMMethod then + target_method = target_property + else + v.error( self, "Error: property {target_method_name.to_s} is not a method." ) + return + end + else + v.error( self, "Error: property {target_method_name.to_s} not found in target class." ) + return + end + + var explicit_import = new MMExplicitImport( target_class, target_method ) + v.local_property.as(MMSrcMethod).explicit_imports.add( explicit_import ) + end +end + +redef class ALocalPropExternCall + redef fun target_class_name do return null + redef fun target_method_name do return n_methid.name.as(not null) +end + +redef class ASuperExternCall + redef fun after_typing(v) + do + var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters + if not precs.is_empty then + v.local_property.need_super = true + else + v.error(self, "Error: No super method to call for {v.local_property}.") + return + end + end +end + +redef class AFullPropExternCall + redef fun target_class_name do return n_classid.to_symbol + redef fun target_method_name do return n_methid.name.as(not null) +end + +redef class AInitPropExternCall + redef fun target_class_name do return n_classid.to_symbol + redef fun target_method_name do return "init".to_symbol +end + +redef class ACastExternCall + fun from_type : MMType is abstract + fun to_type : MMType is abstract + + redef fun after_typing(v) + do + if from_type == to_type + then + v.error( self, "Attepting to cast from and to the same type." ) + end + + var cast = new MMImportedCast( from_type, to_type ) + var m = v.local_property + assert m isa MMMethod + m.explicit_casts.add( cast ) + end +end + +redef class ACastAsExternCall + redef fun from_type do return n_from_type.stype + redef fun to_type do return n_to_type.stype +end + +redef class AAsNullableExternCall + redef fun from_type do return n_type.stype + redef fun to_type do return n_type.stype.as_nullable +end + +redef class AAsNotNullableExternCall + redef fun from_type + do + var t = n_type.stype + if t.is_nullable + then + return t + else + return t.as_nullable + end + end + redef fun to_type do return n_type.stype.as_notnull +end + redef class AAttrFormExpr redef fun prop do return _prop.as(not null) var _prop: nullable MMAttribute @@ -1231,7 +1454,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: arity missmatch; prototype is '{name}{psig}'.") + v.error(self, "Error: arity mismatch; prototype is '{name}{psig}'.") return false end var arg_idx = 0 @@ -1339,7 +1562,7 @@ redef class AAbsSendExpr 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 + if prop == null then 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.") @@ -1405,9 +1628,6 @@ redef class ASuperInitCall if c == prev_class then prev_class = null else if c == cla then - if prev_class != null then - v.error(self, "Error: Constructor of {c} must be invoked before constructor of {prev_class}") - end esic.add(property) break end @@ -1427,6 +1647,9 @@ redef class ANewExpr v.error(self, "Error: try to instantiate abstract class {t.local_class}.") return end + if t.is_nullable then + v.error(self, "Type error: cannot instantiate the nullable type {t}.") + end var name: Symbol if n_id == null then name = once "init".to_symbol @@ -1441,6 +1664,10 @@ redef class ANewExpr v.error(self, "Error: {prop} is not a constructor.") return end + if not prop.global.is_init_for(t.local_class) then + v.error(self, "Error: {prop} is not a constructor in {t.local_class}.") + return + end _stype = t _is_typed = true end @@ -1538,7 +1765,7 @@ redef class AEqExpr if n_expr.stype isa MMTypeNone then if n_expr2.stype isa MMTypeNone then - v.warning(self, "Warning: comparaison between 2 null values.") + v.warning(self, "Warning: comparaison between two null values.") else try_to_isa(v, n_expr2) end @@ -1569,7 +1796,7 @@ redef class ANeExpr if n_expr.stype isa MMTypeNone then if n_expr2.stype isa MMTypeNone then - v.warning(self, "Warning: comparaison between 2 null values.") + v.warning(self, "Warning: comparaison between two null values.") else try_to_isa(v, n_expr2) end @@ -1593,12 +1820,18 @@ end 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 @@ -1635,7 +1868,7 @@ redef class ACallFormExpr n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs) n._variable = variable else - if not n_args.is_empty then + if not n_args.n_exprs.is_empty or n_args isa AParExprs then v.error(self, "Error: {name} is variable, not a function.") return end @@ -1815,8 +2048,8 @@ redef class AClosureDef end end -class ATypeCheckExpr -special AExpr +abstract class ATypeCheckExpr + 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 @@ -1826,7 +2059,10 @@ special AExpr if etype == ttype then 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}.") + if not ttype.has_formal and not etype.has_formal then + # the old metamodel is not that great with formal types + v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.") + end 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}.") @@ -1847,7 +2083,7 @@ special AExpr end redef class AIsaExpr -special ATypeCheckExpr + super ATypeCheckExpr redef fun after_typing(v) do check_expr_cast(v, n_expr, n_type) @@ -1862,7 +2098,7 @@ special ATypeCheckExpr end redef class AAsCastExpr -special ATypeCheckExpr + super ATypeCheckExpr redef fun after_typing(v) do check_expr_cast(v, n_expr, n_type) @@ -1895,7 +2131,13 @@ redef class AProxyExpr _is_typed = true if n_expr.is_statement then return _stype = n_expr.stype + _if_true_flow_ctx = n_expr._if_true_flow_ctx + _if_false_flow_ctx = n_expr._if_false_flow_ctx end + + redef fun is_self do return n_expr.is_self + + redef fun its_variable do return n_expr.its_variable end redef class AOnceExpr @@ -1912,3 +2154,15 @@ redef class AOnceExpr end end +redef class ADebugTypeExpr + redef fun after_typing(v) + do + if not v.check_expr(n_expr) then return + if not n_type.is_typed then return + var etype = n_expr.stype + var ttype = n_type.stype + if etype != ttype then + v.warning(self, "Warning: Expression is a {etype}, expected {ttype}.") + end + end +end