From: Luca Bruno Date: Sat, 6 Aug 2011 08:38:59 +0000 (+0200) Subject: Make the semantic analyzer be stateless X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2d66c4833dad492849fad5535226677865b30c6c;p=thirdparty%2Fvala.git Make the semantic analyzer be stateless --- diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala index 0b6fbc9ad..95cbcaf97 100644 --- a/vala/valaassignment.vala +++ b/vala/valaassignment.vala @@ -117,19 +117,21 @@ public class Vala.Assignment : Expression { checked = true; + var insert_block = context.analyzer.get_insert_block (this); + if (left is Tuple && operator == AssignmentOperator.SIMPLE && parent_node is ExpressionStatement) { var tuple = (Tuple) left; var local = new LocalVariable (null, get_temp_name (), right, right.source_reference); var decl = new DeclarationStatement (local, source_reference); - insert_statement (context.analyzer.insert_block, decl); + insert_statement (insert_block, decl); decl.check (context); int i = 0; ExpressionStatement stmt = null; foreach (var expr in tuple.get_expressions ()) { if (stmt != null) { - insert_statement (context.analyzer.insert_block, stmt); + insert_statement (insert_block, stmt); stmt.check (context); } @@ -165,7 +167,7 @@ public class Vala.Assignment : Expression { } if ((!(ma.symbol_reference is DynamicProperty) && ma.value_type == null) || - (ma.inner == null && ma.member_name == "this" && context.analyzer.is_in_instance_method ())) { + (ma.inner == null && ma.member_name == "this" && context.analyzer.is_in_instance_method (this))) { error = true; Report.error (source_reference, "unsupported lvalue in assignment"); return false; @@ -272,15 +274,16 @@ public class Vala.Assignment : Expression { left.value_type = dynamic_prop.property_type.copy (); } + var current_method = context.analyzer.get_current_method (this); if (prop.set_accessor == null - || (!prop.set_accessor.writable && !(context.analyzer.find_current_method () is CreationMethod || context.analyzer.is_in_constructor ()))) { + || (!prop.set_accessor.writable && !(current_method is CreationMethod || context.analyzer.is_in_constructor (this)))) { ma.error = true; Report.error (ma.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ())); return false; } else if (!context.deprecated && !prop.set_accessor.writable - && context.analyzer.find_current_method () is CreationMethod) { - if (ma.inner.symbol_reference != context.analyzer.find_current_method ().this_parameter) { + && current_method is CreationMethod) { + if (ma.inner.symbol_reference != current_method.this_parameter) { // trying to set construct-only property in creation method for foreign instance Report.error (ma.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ())); return false; diff --git a/vala/valabaseaccess.vala b/vala/valabaseaccess.vala index 955233bdc..613990e0f 100644 --- a/vala/valabaseaccess.vala +++ b/vala/valabaseaccess.vala @@ -56,38 +56,43 @@ public class Vala.BaseAccess : Expression { checked = true; - if (!context.analyzer.is_in_instance_method ()) { + if (!context.analyzer.is_in_instance_method (this)) { error = true; Report.error (source_reference, "Base access invalid outside of instance methods"); return false; } - if (context.analyzer.current_class == null) { - if (context.analyzer.current_struct == null) { + var current_class = context.analyzer.get_current_class (this); + var current_struct = context.analyzer.get_current_struct (this); + var current_method = context.analyzer.get_current_method (this); + var current_property_accessor = context.analyzer.get_current_property_accessor (this); + + if (current_class == null) { + if (current_struct == null) { error = true; Report.error (source_reference, "Base access invalid outside of class and struct"); return false; - } else if (context.analyzer.current_struct.base_type == null) { + } else if (current_struct.base_type == null) { error = true; Report.error (source_reference, "Base access invalid without base type"); return false; } - value_type = context.analyzer.current_struct.base_type; - } else if (context.analyzer.current_class.base_class == null) { + value_type = current_struct.base_type; + } else if (current_class.base_class == null) { error = true; Report.error (source_reference, "Base access invalid without base class"); return false; - } else if (context.analyzer.current_class.is_compact && context.analyzer.current_method != null - && !(context.analyzer.current_method is CreationMethod)) { + } else if (current_class.is_compact && current_method != null + && !(current_method is CreationMethod)) { error = true; Report.error (source_reference, "Base access invalid in virtual overridden method of compact class"); return false; - } else if (context.analyzer.current_class.is_compact && context.analyzer.current_property_accessor != null) { + } else if (current_class.is_compact && current_property_accessor != null) { error = true; Report.error (source_reference, "Base access invalid in virtual overridden property of compact class"); return false; } else { - foreach (var base_type in context.analyzer.current_class.get_base_types ()) { + foreach (var base_type in current_class.get_base_types ()) { if (base_type.data_type is Class) { value_type = base_type.copy (); value_type.value_owned = false; diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala index 0dd61b6c1..84f6a7437 100644 --- a/vala/valabinaryexpression.vala +++ b/vala/valabinaryexpression.vala @@ -140,9 +140,11 @@ public class Vala.BinaryExpression : Expression { checked = true; + var insert_block = context.analyzer.get_insert_block (this); + // some expressions are not in a block, // for example, expressions in method contracts - if (context.analyzer.current_symbol is Block + if (context.analyzer.get_current_non_local_symbol (this) is Block && (operator == BinaryOperator.AND || operator == BinaryOperator.OR)) { // convert conditional expression into if statement // required for flow analysis and exception handling @@ -167,8 +169,8 @@ public class Vala.BinaryExpression : Expression { var if_stmt = new IfStatement (left, true_block, false_block, source_reference); - insert_statement (context.analyzer.insert_block, decl); - insert_statement (context.analyzer.insert_block, if_stmt); + insert_statement (insert_block, decl); + insert_statement (insert_block, if_stmt); decl.check (context); @@ -242,8 +244,8 @@ public class Vala.BinaryExpression : Expression { var if_stmt = new IfStatement (cond, true_block, null, source_reference); - insert_statement (context.analyzer.insert_block, decl); - insert_statement (context.analyzer.insert_block, if_stmt); + insert_statement (insert_block, decl); + insert_statement (insert_block, if_stmt); if (!decl.check (context)) { error = true; diff --git a/vala/valablock.vala b/vala/valablock.vala index 7419b5b9d..72e7801e2 100644 --- a/vala/valablock.vala +++ b/vala/valablock.vala @@ -97,10 +97,12 @@ public class Vala.Block : Symbol, Statement { parent_block = parent_block.parent_symbol; } local_variables.add (local); + scope.add (local.name, local); } public void remove_local_variable (LocalVariable local) { local_variables.remove (local); + scope.remove (local.name); } /** @@ -151,12 +153,7 @@ public class Vala.Block : Symbol, Statement { checked = true; - owner = context.analyzer.current_symbol.scope; - - var old_symbol = context.analyzer.current_symbol; - var old_insert_block = context.analyzer.insert_block; - context.analyzer.current_symbol = this; - context.analyzer.insert_block = this; + owner = context.analyzer.get_current_non_local_symbol (parent_node).scope; for (int i = 0; i < statement_list.size; i++) { statement_list[i].check (context); @@ -170,9 +167,6 @@ public class Vala.Block : Symbol, Statement { constant.active = false; } - context.analyzer.current_symbol = old_symbol; - context.analyzer.insert_block = old_insert_block; - return !error; } diff --git a/vala/valacatchclause.vala b/vala/valacatchclause.vala index 1ff942116..8c0b32538 100644 --- a/vala/valacatchclause.vala +++ b/vala/valacatchclause.vala @@ -131,7 +131,6 @@ public class Vala.CatchClause : CodeNode { if (variable_name != null) { error_variable = new LocalVariable (error_type.copy (), variable_name, null, source_reference); - body.scope.add (variable_name, error_variable); body.add_local_variable (error_variable); error_variable.checked = true; diff --git a/vala/valaclass.vala b/vala/valaclass.vala index 51e8fbade..31615cbbd 100644 --- a/vala/valaclass.vala +++ b/vala/valaclass.vala @@ -522,14 +522,6 @@ public class Vala.Class : ObjectTypeSymbol { checked = true; - var old_source_file = context.analyzer.current_source_file; - var old_symbol = context.analyzer.current_symbol; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - context.analyzer.current_symbol = this; - foreach (DataType base_type_reference in get_base_types ()) { if (!base_type_reference.check (context)) { error = true; @@ -819,9 +811,6 @@ public class Vala.Class : ObjectTypeSymbol { } } - context.analyzer.current_source_file = old_source_file; - context.analyzer.current_symbol = old_symbol; - return !error; } } diff --git a/vala/valaconditionalexpression.vala b/vala/valaconditionalexpression.vala index 3395dd56f..b6884f616 100644 --- a/vala/valaconditionalexpression.vala +++ b/vala/valaconditionalexpression.vala @@ -145,7 +145,7 @@ public class Vala.ConditionalExpression : Expression { checked = true; - if (!(context.analyzer.current_symbol is Block)) { + if (!(context.analyzer.get_current_non_local_symbol (this) is Block)) { Report.error (source_reference, "Conditional expressions may only be used in blocks"); error = true; return false; @@ -174,8 +174,8 @@ public class Vala.ConditionalExpression : Expression { var if_stmt = new IfStatement (condition, true_block, false_block, source_reference); - insert_statement (context.analyzer.insert_block, decl); - insert_statement (context.analyzer.insert_block, if_stmt); + insert_statement (context.analyzer.get_insert_block (this), decl); + insert_statement (context.analyzer.get_insert_block (this), if_stmt); if (!if_stmt.check (context) || true_expression.error || false_expression.error) { error = true; diff --git a/vala/valaconstant.vala b/vala/valaconstant.vala index 0a9266cf1..bf6635e18 100644 --- a/vala/valaconstant.vala +++ b/vala/valaconstant.vala @@ -102,17 +102,6 @@ public class Vala.Constant : Symbol { checked = true; - var old_source_file = context.analyzer.current_source_file; - var old_symbol = context.analyzer.current_symbol; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - if (!(parent_symbol is Block)) { - // non-local constant - context.analyzer.current_symbol = this; - } - type_reference.check (context); if (!check_const_type (type_reference, context)) { @@ -171,9 +160,6 @@ public class Vala.Constant : Symbol { Report.warning (source_reference, "%s hides inherited constant `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ())); } - context.analyzer.current_source_file = old_source_file; - context.analyzer.current_symbol = old_symbol; - active = true; return !error; diff --git a/vala/valaconstructor.vala b/vala/valaconstructor.vala index ae8f19e8d..86f24de3f 100644 --- a/vala/valaconstructor.vala +++ b/vala/valaconstructor.vala @@ -67,12 +67,9 @@ public class Vala.Constructor : Subroutine { checked = true; - this_parameter = new Parameter ("this", new ObjectType (context.analyzer.current_class)); + this_parameter = new Parameter ("this", new ObjectType (context.analyzer.get_current_class (this))); scope.add (this_parameter.name, this_parameter); - owner = context.analyzer.current_symbol.scope; - context.analyzer.current_symbol = this; - if (body != null) { body.check (context); } @@ -85,8 +82,6 @@ public class Vala.Constructor : Subroutine { } } - context.analyzer.current_symbol = context.analyzer.current_symbol.parent_symbol; - return !error; } } diff --git a/vala/valacreationmethod.vala b/vala/valacreationmethod.vala index ae8daab38..e201624a9 100644 --- a/vala/valacreationmethod.vala +++ b/vala/valacreationmethod.vala @@ -88,19 +88,11 @@ public class Vala.CreationMethod : Method { if (class_name != null && class_name != parent_symbol.name) { // class_name is null for constructors generated by GIdlParser - Report.error (source_reference, "missing return type in method `%s.%s´".printf (context.analyzer.current_symbol.get_full_name (), class_name)); + Report.error (source_reference, "missing return type in method `%s.%s´".printf (context.analyzer.get_current_symbol (parent_node).get_full_name (), class_name)); error = true; return false; } - var old_source_file = context.analyzer.current_source_file; - var old_symbol = context.analyzer.current_symbol; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - context.analyzer.current_symbol = this; - int i = 0; foreach (Parameter param in get_parameters()) { param.check (context); @@ -135,40 +127,23 @@ public class Vala.CreationMethod : Method { if (context.profile == Profile.GOBJECT && cl.base_class.default_construction_method != null && !cl.base_class.default_construction_method.has_construct_function) { - // directly chain up to Object - var old_insert_block = context.analyzer.insert_block; - context.analyzer.current_symbol = body; - context.analyzer.insert_block = body; var stmt = new ExpressionStatement (new MethodCall (new MemberAccess (new MemberAccess.simple ("GLib", source_reference), "Object", source_reference), source_reference), source_reference); body.insert_statement (0, stmt); stmt.check (context); - - context.analyzer.current_symbol = this; - context.analyzer.insert_block = old_insert_block; } else if (cl.base_class.default_construction_method == null || cl.base_class.default_construction_method.access == SymbolAccessibility.PRIVATE) { Report.error (source_reference, "unable to chain up to private base constructor"); } else if (cl.base_class.default_construction_method.get_required_arguments () > 0) { Report.error (source_reference, "unable to chain up to base constructor requiring arguments"); } else { - var old_insert_block = context.analyzer.insert_block; - context.analyzer.current_symbol = body; - context.analyzer.insert_block = body; - var stmt = new ExpressionStatement (new MethodCall (new BaseAccess (source_reference), source_reference), source_reference); body.insert_statement (0, stmt); stmt.check (context); - - context.analyzer.current_symbol = this; - context.analyzer.insert_block = old_insert_block; } } } - context.analyzer.current_source_file = old_source_file; - context.analyzer.current_symbol = old_symbol; - if (is_abstract || is_virtual || overrides) { Report.error (source_reference, "The creation method `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ())); return false; diff --git a/vala/valadelegate.vala b/vala/valadelegate.vala index 4b4e7074a..039f6a5c6 100644 --- a/vala/valadelegate.vala +++ b/vala/valadelegate.vala @@ -293,12 +293,6 @@ public class Vala.Delegate : TypeSymbol, Callable { checked = true; - var old_source_file = context.analyzer.current_source_file; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - foreach (TypeParameter p in type_parameters) { p.check (context); } @@ -315,8 +309,6 @@ public class Vala.Delegate : TypeSymbol, Callable { } } - context.analyzer.current_source_file = old_source_file; - return !error; } } diff --git a/vala/valadestructor.vala b/vala/valadestructor.vala index 7ee3843bd..ddfb0f9ea 100644 --- a/vala/valadestructor.vala +++ b/vala/valadestructor.vala @@ -67,15 +67,10 @@ public class Vala.Destructor : Subroutine { checked = true; - owner = context.analyzer.current_symbol.scope; - context.analyzer.current_symbol = this; - if (body != null) { body.check (context); } - context.analyzer.current_symbol = context.analyzer.current_symbol.parent_symbol; - return !error; } } diff --git a/vala/valaenum.vala b/vala/valaenum.vala index 508ef12ef..15cb2c830 100644 --- a/vala/valaenum.vala +++ b/vala/valaenum.vala @@ -158,14 +158,6 @@ public class Vala.Enum : TypeSymbol { checked = true; - var old_source_file = context.analyzer.current_source_file; - var old_symbol = context.analyzer.current_symbol; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - context.analyzer.current_symbol = this; - if (values.size <= 0) { Report.error (source_reference, "Enum `%s' requires at least one value".printf (get_full_name ())); error = true; @@ -184,9 +176,6 @@ public class Vala.Enum : TypeSymbol { c.check (context); } - context.analyzer.current_source_file = old_source_file; - context.analyzer.current_symbol = old_symbol; - return !error; } } diff --git a/vala/valafield.vala b/vala/valafield.vala index 6bd54ff95..fd2082d71 100644 --- a/vala/valafield.vala +++ b/vala/valafield.vala @@ -84,14 +84,6 @@ public class Vala.Field : Variable, Lockable { checked = true; - var old_source_file = context.analyzer.current_source_file; - var old_symbol = context.analyzer.current_symbol; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - context.analyzer.current_symbol = this; - if (variable_type is VoidType) { error = true; Report.error (source_reference, "'void' not supported as field type"); @@ -189,9 +181,6 @@ public class Vala.Field : Variable, Lockable { Report.warning (source_reference, "%s hides inherited field `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ())); } - context.analyzer.current_source_file = old_source_file; - context.analyzer.current_symbol = old_symbol; - return !error; } } diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala index 67063bbe1..ada291ccd 100644 --- a/vala/valaforeachstatement.vala +++ b/vala/valaforeachstatement.vala @@ -154,6 +154,8 @@ public class Vala.ForeachStatement : Block { checked = true; + owner = context.analyzer.get_current_symbol (parent_node).scope; + // analyze collection expression first, used for type inference if (!collection.check (context)) { // ignore inner error @@ -353,16 +355,10 @@ public class Vala.ForeachStatement : Block { element_variable = new LocalVariable (type_reference, variable_name, null, source_reference); - body.scope.add (variable_name, element_variable); - body.add_local_variable (element_variable); element_variable.active = true; element_variable.checked = true; - // analyze body - owner = context.analyzer.current_symbol.scope; - context.analyzer.current_symbol = this; - // call add_local_variable to check for shadowed variable add_local_variable (element_variable); remove_local_variable (element_variable); @@ -373,8 +369,6 @@ public class Vala.ForeachStatement : Block { local.active = false; } - context.analyzer.current_symbol = context.analyzer.current_symbol.parent_symbol; - collection_variable = new LocalVariable (collection_type.copy (), "%s_collection".printf (variable_name)); add_local_variable (collection_variable); diff --git a/vala/valainterface.vala b/vala/valainterface.vala index f6c503641..61d1e50ef 100644 --- a/vala/valainterface.vala +++ b/vala/valainterface.vala @@ -194,14 +194,6 @@ public class Vala.Interface : ObjectTypeSymbol { checked = true; - var old_source_file = context.analyzer.current_source_file; - var old_symbol = context.analyzer.current_symbol; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - context.analyzer.current_symbol = this; - foreach (DataType prerequisite_reference in get_prerequisites ()) { // check whether prerequisite is at least as accessible as the interface if (!context.analyzer.is_type_accessible (this, prerequisite_reference)) { @@ -364,9 +356,6 @@ public class Vala.Interface : ObjectTypeSymbol { } } - context.analyzer.current_source_file = old_source_file; - context.analyzer.current_symbol = old_symbol; - return !error; } } diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala index a22497e70..5e8fcee07 100644 --- a/vala/valalambdaexpression.vala +++ b/vala/valalambdaexpression.vala @@ -137,10 +137,10 @@ public class Vala.LambdaExpression : Expression { method.used = true; method.version.check (source_reference); - if (!cb.has_target || !context.analyzer.is_in_instance_method ()) { + if (!cb.has_target || !context.analyzer.is_in_instance_method (this)) { method.binding = MemberBinding.STATIC; } else { - var sym = context.analyzer.current_symbol; + var sym = context.analyzer.get_current_symbol (this); while (method.this_parameter == null) { if (sym is Property) { var prop = (Property) sym; @@ -159,7 +159,7 @@ public class Vala.LambdaExpression : Expression { sym = sym.parent_symbol; } } - method.owner = context.analyzer.current_symbol.scope; + method.owner = context.analyzer.get_current_non_local_symbol (this).scope; var lambda_params = get_parameters (); Iterator lambda_param_it = lambda_params.iterator (); @@ -220,7 +220,7 @@ public class Vala.LambdaExpression : Expression { method.body.owner = method.scope; // support use of generics in closures - var m = context.analyzer.find_parent_method (context.analyzer.current_symbol); + var m = context.analyzer.get_current_method (this); if (m != null) { foreach (var type_param in m.get_type_parameters ()) { method.add_type_parameter (new TypeParameter (type_param.name, type_param.source_reference)); diff --git a/vala/valalocalvariable.vala b/vala/valalocalvariable.vala index 3a2ecae01..acc6a3607 100644 --- a/vala/valalocalvariable.vala +++ b/vala/valalocalvariable.vala @@ -92,6 +92,16 @@ public class Vala.LocalVariable : Variable { } } + // current_symbol is a Method if this is the `result' + // variable used for postconditions + var block = context.analyzer.get_current_block (this); + if (block != null) { + /* so that we can use parent_symbol */ + block.add_local_variable (this); + } + + active = false; + if (variable_type != null) { if (variable_type is VoidType) { error = true; @@ -211,15 +221,6 @@ public class Vala.LocalVariable : Variable { } } - context.analyzer.current_symbol.scope.add (name, this); - - // current_symbol is a Method if this is the `result' - // variable used for postconditions - var block = context.analyzer.current_symbol as Block; - if (block != null) { - block.add_local_variable (this); - } - active = true; return !error; diff --git a/vala/valalockstatement.vala b/vala/valalockstatement.vala index e64d4a206..be942acee 100644 --- a/vala/valalockstatement.vala +++ b/vala/valalockstatement.vala @@ -114,7 +114,7 @@ public class Vala.LockStatement : CodeNode, Statement { } /* parent symbol must be the current class */ - if (resource.symbol_reference.parent_symbol != context.analyzer.current_class) { + if (resource.symbol_reference.parent_symbol != context.analyzer.get_current_class (this)) { error = true; resource.error = true; Report.error (resource.source_reference, "Only members of the current class are lockable"); @@ -122,7 +122,7 @@ public class Vala.LockStatement : CodeNode, Statement { } /* parent class must not be compact */ - if (context.analyzer.current_class.is_compact) { + if (context.analyzer.get_current_class (this).is_compact) { error = true; resource.error = true; Report.error (resource.source_reference, "Only members of the non-compact classes are lockable"); diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala index dfd68a4aa..41b336934 100644 --- a/vala/valamemberaccess.vala +++ b/vala/valamemberaccess.vala @@ -226,20 +226,20 @@ public class Vala.MemberAccess : Expression { symbol_reference = base_symbol.scope.lookup (member_name); } else if (inner == null) { if (member_name == "this") { - if (!context.analyzer.is_in_instance_method ()) { + if (!context.analyzer.is_in_instance_method (this)) { error = true; Report.error (source_reference, "This access invalid outside of instance methods"); return false; } } - base_symbol = context.analyzer.current_symbol; + base_symbol = context.analyzer.get_current_non_local_symbol (this); // track whether method has been found to make sure that access // to instance member is denied from within static lambda expressions bool method_found = false; - var sym = context.analyzer.current_symbol; + var sym = base_symbol; while (sym != null && symbol_reference == null) { if (!method_found) { if (sym is CreationMethod) { @@ -484,13 +484,15 @@ public class Vala.MemberAccess : Expression { return false; } + var current_method_or_property_accessor = context.analyzer.get_current_method_or_property_accessor (this); + if (member is LocalVariable) { var local = (LocalVariable) member; var block = local.parent_symbol as Block; - if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) { + if (block != null && context.analyzer.get_current_method_or_property_accessor (block) != current_method_or_property_accessor) { // mark all methods between current method and the captured // block as closures (to support nested closures) - Symbol sym = context.analyzer.current_method_or_property_accessor; + Symbol sym = current_method_or_property_accessor; while (sym != block) { var method = sym as Method; if (method != null) { @@ -508,10 +510,10 @@ public class Vala.MemberAccess : Expression { } else if (member is Parameter) { var param = (Parameter) member; var m = param.parent_symbol as Method; - if (m != null && m != context.analyzer.current_method_or_property_accessor && param != m.this_parameter) { + if (m != null && m != current_method_or_property_accessor && param != m.this_parameter) { // mark all methods between current method and the captured // parameter as closures (to support nested closures) - Symbol sym = context.analyzer.current_method_or_property_accessor; + Symbol sym = current_method_or_property_accessor; while (sym != m) { var method = sym as Method; if (method != null) { @@ -529,10 +531,10 @@ public class Vala.MemberAccess : Expression { } } else { var acc = param.parent_symbol.parent_symbol as PropertyAccessor; - if (acc != null && acc != context.analyzer.current_method_or_property_accessor && param != acc.prop.this_parameter) { + if (acc != null && acc != current_method_or_property_accessor && param != acc.prop.this_parameter) { // mark all methods between current method and the captured // parameter as closures (to support nested closures) - Symbol sym = context.analyzer.current_method_or_property_accessor; + Symbol sym = current_method_or_property_accessor; while (sym != m) { var method = sym as Method; if (method != null) { @@ -561,7 +563,7 @@ public class Vala.MemberAccess : Expression { access = c.access; var block = c.parent_symbol as Block; - if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) { + if (block != null && context.analyzer.get_current_method_or_property_accessor (block) != current_method_or_property_accessor) { error = true; Report.error (source_reference, "internal error: accessing local constants of outer methods is not supported yet"); return false; @@ -571,7 +573,7 @@ public class Vala.MemberAccess : Expression { if (m.is_async_callback) { // ensure to use right callback method for virtual/abstract async methods // and also for lambda expressions within async methods - var async_method = context.analyzer.current_async_method; + var async_method = context.analyzer.get_current_async_method (this); bool is_valid_access = false; if (async_method != null) { @@ -589,14 +591,11 @@ public class Vala.MemberAccess : Expression { return false; } - if (async_method != context.analyzer.current_method) { - Symbol sym = context.analyzer.current_method; - while (sym != async_method) { - var method = sym as Method; - if (method != null) { - method.closure = true; - } - sym = sym.parent_symbol; + var current_method = context.analyzer.get_current_method (this); + if (async_method != current_method) { + while (current_method != async_method) { + current_method.closure = true; + current_method = context.analyzer.get_current_method (current_method.parent_symbol); } async_method.body.captured = true; } @@ -715,7 +714,7 @@ public class Vala.MemberAccess : Expression { var target_type = (TypeSymbol) member.parent_symbol; bool in_subtype = false; - for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) { + for (Symbol this_symbol = context.analyzer.get_current_non_local_symbol (this); this_symbol != null; this_symbol = this_symbol.parent_symbol) { if (this_symbol == target_type) { // required for interfaces with non-abstract methods // accessing protected interface members @@ -739,7 +738,7 @@ public class Vala.MemberAccess : Expression { var target_type = member.parent_symbol; bool in_target_type = false; - for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) { + for (Symbol this_symbol = context.analyzer.get_current_non_local_symbol (this); this_symbol != null; this_symbol = this_symbol.parent_symbol) { if (target_type == this_symbol) { in_target_type = true; break; diff --git a/vala/valamethod.vala b/vala/valamethod.vala index 22980085f..65bc183a6 100644 --- a/vala/valamethod.vala +++ b/vala/valamethod.vala @@ -771,14 +771,6 @@ public class Vala.Method : Subroutine, Callable { return false; } - var old_source_file = context.analyzer.current_source_file; - var old_symbol = context.analyzer.current_symbol; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - context.analyzer.current_symbol = this; - return_type.floating_reference = returns_floating_reference; return_type.check (context); @@ -862,7 +854,7 @@ public class Vala.Method : Subroutine, Callable { body.check (context); } - if (context.analyzer.current_struct != null) { + if (context.analyzer.get_current_struct (this) != null) { if (is_abstract || is_virtual || overrides) { error = true; Report.error (source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ())); @@ -890,9 +882,6 @@ public class Vala.Method : Subroutine, Callable { } } - context.analyzer.current_source_file = old_source_file; - context.analyzer.current_symbol = old_symbol; - if (!external_package && !overrides && !hides && get_hidden_member () != null) { Report.warning (source_reference, "%s hides inherited method `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ())); } diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala index 80d0d772f..041d096d2 100644 --- a/vala/valamethodcall.vala +++ b/vala/valamethodcall.vala @@ -258,7 +258,7 @@ public class Vala.MethodCall : Expression { CreationMethod base_cm = null; if (is_chainup) { - var cm = context.analyzer.find_current_method () as CreationMethod; + var cm = context.analyzer.get_current_method (this) as CreationMethod; if (cm == null) { error = true; Report.error (source_reference, "invocation not supported in this context"); @@ -518,7 +518,8 @@ public class Vala.MethodCall : Expression { error = true; Report.error (source_reference, "yield expression requires async method"); } - if (context.analyzer.current_method == null || !context.analyzer.current_method.coroutine) { + var current_method = context.analyzer.get_current_method (this); + if (current_method == null || !current_method.coroutine) { error = true; Report.error (source_reference, "yield expression not available outside async method"); } @@ -645,7 +646,7 @@ public class Vala.MethodCall : Expression { if (tree_can_fail) { if (parent_node is LocalVariable || parent_node is ExpressionStatement) { // simple statements, no side effects after method call - } else if (!(context.analyzer.current_symbol is Block)) { + } else if (!(context.analyzer.get_current_non_local_symbol (this) is Block)) { // can't handle errors in field initializers Report.error (source_reference, "Field initializers must not throw errors"); } else { @@ -655,7 +656,7 @@ public class Vala.MethodCall : Expression { var local = new LocalVariable (value_type.copy (), get_temp_name (), null, source_reference); var decl = new DeclarationStatement (local, source_reference); - insert_statement (context.analyzer.insert_block, decl); + insert_statement (context.analyzer.get_insert_block (this), decl); var temp_access = SemanticAnalyzer.create_temp_access (local, target_type); @@ -666,9 +667,9 @@ public class Vala.MethodCall : Expression { // move temp variable to insert block to ensure the // variable is in the same block as the declaration // otherwise there will be scoping issues in the generated code - var block = (Block) context.analyzer.current_symbol; + var block = context.analyzer.get_current_block (this); block.remove_local_variable (local); - context.analyzer.insert_block.add_local_variable (local); + context.analyzer.get_insert_block (this).add_local_variable (local); old_parent_node.replace_expression (this, temp_access); temp_access.check (context); diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala index 0b6a29391..4f30f5b84 100644 --- a/vala/valaobjectcreationexpression.vala +++ b/vala/valaobjectcreationexpression.vala @@ -293,7 +293,7 @@ public class Vala.ObjectCreationExpression : Expression { if (symbol_reference != null && (symbol_reference.access == SymbolAccessibility.PRIVATE || symbol_reference.access == SymbolAccessibility.PROTECTED)) { bool in_target_type = false; - for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) { + for (Symbol this_symbol = context.analyzer.get_current_non_local_symbol (this); this_symbol != null; this_symbol = this_symbol.parent_symbol) { if (this_symbol == cl) { in_target_type = true; break; @@ -361,7 +361,8 @@ public class Vala.ObjectCreationExpression : Expression { error = true; Report.error (source_reference, "yield expression requires async method"); } - if (context.analyzer.current_method == null || !context.analyzer.current_method.coroutine) { + var current_method = context.analyzer.get_current_method (this); + if (current_method == null || !current_method.coroutine) { error = true; Report.error (source_reference, "yield expression not available outside async method"); } @@ -484,7 +485,7 @@ public class Vala.ObjectCreationExpression : Expression { if (tree_can_fail) { if (parent_node is LocalVariable || parent_node is ExpressionStatement) { // simple statements, no side effects after method call - } else if (!(context.analyzer.current_symbol is Block)) { + } else if (!(context.analyzer.get_current_non_local_symbol (this) is Block)) { // can't handle errors in field initializers Report.error (source_reference, "Field initializers must not throw errors"); } else { @@ -494,7 +495,7 @@ public class Vala.ObjectCreationExpression : Expression { var local = new LocalVariable (value_type.copy (), get_temp_name (), null, source_reference); var decl = new DeclarationStatement (local, source_reference); - insert_statement (context.analyzer.insert_block, decl); + insert_statement (context.analyzer.get_insert_block (this), decl); var temp_access = SemanticAnalyzer.create_temp_access (local, target_type); // don't set initializer earlier as this changes parent_node and parent_statement @@ -504,9 +505,9 @@ public class Vala.ObjectCreationExpression : Expression { // move temp variable to insert block to ensure the // variable is in the same block as the declaration // otherwise there will be scoping issues in the generated code - var block = (Block) context.analyzer.current_symbol; + var block = context.analyzer.get_current_block (this); block.remove_local_variable (local); - context.analyzer.insert_block.add_local_variable (local); + context.analyzer.get_insert_block (this).add_local_variable (local); old_parent_node.replace_expression (this, temp_access); temp_access.check (context); diff --git a/vala/valaparameter.vala b/vala/valaparameter.vala index 7c13a7c19..3c8bb0f09 100644 --- a/vala/valaparameter.vala +++ b/vala/valaparameter.vala @@ -132,14 +132,6 @@ public class Vala.Parameter : Variable { checked = true; - var old_source_file = context.analyzer.current_source_file; - var old_symbol = context.analyzer.current_symbol; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - context.analyzer.current_symbol = parent_symbol; - if (variable_type != null) { if (variable_type is VoidType) { error = true; @@ -204,9 +196,6 @@ public class Vala.Parameter : Variable { } } - context.analyzer.current_source_file = old_source_file; - context.analyzer.current_symbol = old_symbol; - return !error; } } diff --git a/vala/valaproperty.vala b/vala/valaproperty.vala index cd1bcaff5..c4ab84c44 100644 --- a/vala/valaproperty.vala +++ b/vala/valaproperty.vala @@ -450,14 +450,6 @@ public class Vala.Property : Symbol, Lockable { } } - var old_source_file = context.analyzer.current_source_file; - var old_symbol = context.analyzer.current_symbol; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - context.analyzer.current_symbol = this; - if (property_type is VoidType) { error = true; Report.error (source_reference, "'void' not supported as property type"); @@ -514,9 +506,6 @@ public class Vala.Property : Symbol, Lockable { Report.error (initializer.source_reference, "Expected initializer of type `%s' but got `%s'".printf (property_type.to_string (), initializer.value_type.to_string ())); } - context.analyzer.current_source_file = old_source_file; - context.analyzer.current_symbol = old_symbol; - return !error; } } diff --git a/vala/valapropertyaccessor.vala b/vala/valapropertyaccessor.vala index e348c2510..019e993df 100644 --- a/vala/valapropertyaccessor.vala +++ b/vala/valapropertyaccessor.vala @@ -150,10 +150,6 @@ public class Vala.PropertyAccessor : Subroutine { return false; } - var old_symbol = context.analyzer.current_symbol; - - context.analyzer.current_symbol = this; - if (writable || construction) { value_parameter = new Parameter ("value", value_type, source_reference); } @@ -206,8 +202,6 @@ public class Vala.PropertyAccessor : Subroutine { } } - context.analyzer.current_symbol = old_symbol; - return !error; } diff --git a/vala/valareturnstatement.vala b/vala/valareturnstatement.vala index f51164968..e4fa6b506 100644 --- a/vala/valareturnstatement.vala +++ b/vala/valareturnstatement.vala @@ -83,8 +83,10 @@ public class Vala.ReturnStatement : CodeNode, Statement { checked = true; + var current_return_type = context.analyzer.get_current_return_type (this); + if (return_expression != null) { - return_expression.target_type = context.analyzer.current_return_type.copy (); + return_expression.target_type = current_return_type.copy (); } if (return_expression != null && !return_expression.check (context)) { @@ -93,21 +95,21 @@ public class Vala.ReturnStatement : CodeNode, Statement { return false; } - if (context.analyzer.current_return_type == null) { + if (current_return_type == null) { error = true; Report.error (source_reference, "Return not allowed in this context"); return false; } if (return_expression == null) { - if (!(context.analyzer.current_return_type is VoidType)) { + if (!(current_return_type is VoidType)) { error = true; Report.error (source_reference, "Return without value in non-void function"); } return !error; } - if (context.analyzer.current_return_type is VoidType) { + if (current_return_type is VoidType) { Report.error (source_reference, "Return with value in void function"); return false; } @@ -118,14 +120,14 @@ public class Vala.ReturnStatement : CodeNode, Statement { return false; } - if (!return_expression.value_type.compatible (context.analyzer.current_return_type)) { + if (!return_expression.value_type.compatible (current_return_type)) { error = true; - Report.error (source_reference, "Return: Cannot convert from `%s' to `%s'".printf (return_expression.value_type.to_string (), context.analyzer.current_return_type.to_string ())); + Report.error (source_reference, "Return: Cannot convert from `%s' to `%s'".printf (return_expression.value_type.to_string (), current_return_type.to_string ())); return false; } if (return_expression.value_type.is_disposable () && - !context.analyzer.current_return_type.value_owned) { + !current_return_type.value_owned) { error = true; Report.error (source_reference, "Return value transfers ownership but method return type hasn't been declared to transfer ownership"); return false; @@ -133,15 +135,15 @@ public class Vala.ReturnStatement : CodeNode, Statement { var local = return_expression.symbol_reference as LocalVariable; if (local != null && local.variable_type.is_disposable () && - !context.analyzer.current_return_type.value_owned) { + !current_return_type.value_owned) { error = true; Report.error (source_reference, "Local variable with strong reference used as return value and method return type has not been declared to transfer ownership"); return false; } if (return_expression is NullLiteral - && !context.analyzer.current_return_type.nullable) { - Report.warning (source_reference, "`null' incompatible with return type `%s'".printf (context.analyzer.current_return_type.to_string ())); + && !current_return_type.nullable) { + Report.warning (source_reference, "`null' incompatible with return type `%s'".printf (current_return_type.to_string ())); } return !error; diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index 485ab222d..3f3388851 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -30,108 +30,6 @@ using GLib; public class Vala.SemanticAnalyzer : CodeVisitor { CodeContext context; - public Symbol current_symbol { get; set; } - public SourceFile current_source_file { get; set; } - - public TypeSymbol? current_type_symbol { - get { - var sym = current_symbol; - while (sym != null) { - if (sym is TypeSymbol) { - return (TypeSymbol) sym; - } - sym = sym.parent_symbol; - } - return null; - } - } - - public Class? current_class { - get { return current_type_symbol as Class; } - } - - - public Struct? current_struct { - get { return current_type_symbol as Struct; } - } - - public Method? current_method { - get { - unowned Symbol sym = current_symbol; - while (sym is Block) { - sym = sym.parent_symbol; - } - return sym as Method; - } - } - - public Method? current_async_method { - get { - unowned Symbol sym = current_symbol; - while (sym is Block || sym is Method) { - var m = sym as Method; - if (m != null && m.coroutine) { - break; - } - - sym = sym.parent_symbol; - } - return sym as Method; - } - } - - public PropertyAccessor? current_property_accessor { - get { - unowned Symbol sym = current_symbol; - while (sym is Block) { - sym = sym.parent_symbol; - } - return sym as PropertyAccessor; - } - } - - public Symbol? current_method_or_property_accessor { - get { - unowned Symbol sym = current_symbol; - while (sym is Block) { - sym = sym.parent_symbol; - } - if (sym is Method) { - return sym; - } else if (sym is PropertyAccessor) { - return sym; - } else { - return null; - } - } - } - - public DataType? current_return_type { - get { - var m = current_method; - if (m != null) { - return m.return_type; - } - - var acc = current_property_accessor; - if (acc != null) { - if (acc.readable) { - return acc.value_type; - } else { - return void_type; - } - } - - if (is_in_constructor () || is_in_destructor ()) { - return void_type; - } - - return null; - } - } - - public Block insert_block; - public DataType void_type = new VoidType (); public DataType bool_type; public DataType string_type; @@ -219,7 +117,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor { gsource_type = (Class) glib_ns.scope.lookup ("Source"); } - current_symbol = root_symbol; context.root.check (context); context.accept (this); @@ -227,11 +124,122 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } public override void visit_source_file (SourceFile file) { - current_source_file = file; - file.check (context); } + public unowned Symbol? get_current_symbol (CodeNode node) { + while (node != null && !(node is Symbol)) { + node = node.parent_node; + } + return (Symbol) node; + } + + public unowned Symbol? get_current_non_local_symbol (CodeNode node) { + while (node != null && (!(node is Symbol) || is_local_symbol ((Symbol) node))) { + node = node.parent_node; + } + return (Symbol) node; + } + + public bool is_local_symbol (Symbol sym) { + if (sym is LocalVariable || (sym is Constant && sym.parent_symbol is Block)) { + return true; + } + return false; + } + + public unowned TypeSymbol? get_current_type_symbol (CodeNode node) { + unowned Symbol sym = get_current_symbol (node); + while (sym != null && !(sym is TypeSymbol)) { + sym = sym.parent_symbol; + } + return (TypeSymbol) sym; + } + + public unowned Class? get_current_class (CodeNode node) { + return get_current_type_symbol (node) as Class; + } + + + public unowned Struct? get_current_struct (CodeNode node) { + return get_current_type_symbol (node) as Struct; + } + + public unowned Method? get_current_method (CodeNode node) { + unowned Symbol sym = get_current_symbol (node); + while (sym != null && !(sym is Method)) { + sym = sym.parent_symbol; + } + return sym as Method; + } + + public unowned Method? get_current_async_method (CodeNode node) { + unowned Method m = get_current_method (node); + while (m != null && !m.coroutine) { + m = get_current_method (m.parent_symbol); + } + return m; + } + + public unowned PropertyAccessor? get_current_property_accessor (CodeNode node) { + unowned Symbol sym = get_current_symbol (node); + while (sym != null && !(sym is PropertyAccessor)) { + sym = sym.parent_symbol; + } + return sym as PropertyAccessor; + } + + public unowned Symbol? get_current_method_or_property_accessor (CodeNode node) { + unowned Symbol sym = get_current_symbol (node); + while (sym != null && !(sym is Method) && !(sym is PropertyAccessor)) { + sym = sym.parent_symbol; + } + if (sym is Method) { + return sym; + } else if (sym is PropertyAccessor) { + return sym; + } else { + return null; + } + } + + public unowned DataType? get_current_return_type (CodeNode node) { + unowned Method m = get_current_method (node); + if (m != null) { + return m.return_type; + } + + unowned PropertyAccessor acc = get_current_property_accessor (node); + if (acc != null) { + if (acc.readable) { + return acc.value_type; + } else { + return void_type; + } + } + + if (is_in_constructor (node) || is_in_destructor (node)) { + return void_type; + } + + return null; + } + + public unowned Block? get_current_block (CodeNode node) { + while (node != null && !(node is Block)) { + node = node.parent_node; + } + return (Block) node; + } + + public unowned Block? get_insert_block (CodeNode node) { + unowned Block? block = get_current_block (node); + if (block is ForeachStatement) { + block = block.parent_symbol as Block; + } + return block; + } + // check whether type is at least as accessible as the specified symbol public bool is_type_accessible (Symbol sym, DataType type) { return type.is_accessible (sym); @@ -903,8 +911,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor { return actual_type; } - public bool is_in_instance_method () { - var sym = current_symbol; + public bool is_in_instance_method (CodeNode node) { + unowned Symbol sym = get_current_symbol (node); while (sym != null) { if (sym is CreationMethod) { return true; @@ -1021,39 +1029,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } } - public Method? find_current_method () { - var sym = current_symbol; - while (sym != null) { - if (sym is Method) { - return (Method) sym; - } - sym = sym.parent_symbol; - } - return null; - } - - public Method? find_parent_method (Symbol sym) { - while (sym is Block) { - sym = sym.parent_symbol; - } - return sym as Method; - } - - public Symbol? find_parent_method_or_property_accessor (Symbol sym) { - while (sym is Block) { - sym = sym.parent_symbol; - } - if (sym is Method) { - return sym; - } else if (sym is PropertyAccessor) { - return sym; - } else { - return null; - } - } - - public bool is_in_constructor () { - var sym = current_symbol; + public bool is_in_constructor (CodeNode node) { + unowned Symbol sym = get_current_symbol (node); while (sym != null) { if (sym is Constructor) { return true; @@ -1063,8 +1040,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor { return false; } - public bool is_in_destructor () { - var sym = current_symbol; + public bool is_in_destructor (CodeNode node) { + unowned Symbol sym = get_current_symbol (node); while (sym != null) { if (sym is Destructor) { return true; diff --git a/vala/valastruct.vala b/vala/valastruct.vala index c96632805..e47bc3f24 100644 --- a/vala/valastruct.vala +++ b/vala/valastruct.vala @@ -481,14 +481,6 @@ public class Vala.Struct : TypeSymbol { checked = true; - var old_source_file = context.analyzer.current_source_file; - var old_symbol = context.analyzer.current_symbol; - - if (source_reference != null) { - context.analyzer.current_source_file = source_reference.file; - } - context.analyzer.current_symbol = this; - if (base_type != null) { base_type.check (context); @@ -564,9 +556,6 @@ public class Vala.Struct : TypeSymbol { } } - context.analyzer.current_source_file = old_source_file; - context.analyzer.current_symbol = old_symbol; - return !error; } } diff --git a/vala/valasubroutine.vala b/vala/valasubroutine.vala index e9c05ac23..0ef8bf333 100644 --- a/vala/valasubroutine.vala +++ b/vala/valasubroutine.vala @@ -45,7 +45,6 @@ public abstract class Vala.Subroutine : Symbol { set { _body = value; if (_body != null) { - _body.owner = scope; _body.parent_node = this; } } diff --git a/vala/valaswitchsection.vala b/vala/valaswitchsection.vala index 2b6bc60ab..9e94edea1 100644 --- a/vala/valaswitchsection.vala +++ b/vala/valaswitchsection.vala @@ -99,17 +99,12 @@ public class Vala.SwitchSection : Block { checked = true; + owner = context.analyzer.get_current_symbol (parent_node).scope; + foreach (SwitchLabel label in get_labels ()) { label.check (context); } - owner = context.analyzer.current_symbol.scope; - - var old_symbol = context.analyzer.current_symbol; - var old_insert_block = context.analyzer.insert_block; - context.analyzer.current_symbol = this; - context.analyzer.insert_block = this; - foreach (Statement st in get_statements ()) { st.check (context); } @@ -118,9 +113,6 @@ public class Vala.SwitchSection : Block { local.active = false; } - context.analyzer.current_symbol = old_symbol; - context.analyzer.insert_block = old_insert_block; - return !error; } diff --git a/vala/valaunlockstatement.vala b/vala/valaunlockstatement.vala index d60d5706c..e97458ea8 100644 --- a/vala/valaunlockstatement.vala +++ b/vala/valaunlockstatement.vala @@ -72,7 +72,7 @@ public class Vala.UnlockStatement : CodeNode, Statement { } /* parent symbol must be the current class */ - if (resource.symbol_reference.parent_symbol != context.analyzer.current_class) { + if (resource.symbol_reference.parent_symbol != context.analyzer.get_current_class (this)) { error = true; resource.error = true; Report.error (resource.source_reference, "Only members of the current class are lockable"); @@ -80,7 +80,7 @@ public class Vala.UnlockStatement : CodeNode, Statement { } /* parent class must not be compact */ - if (context.analyzer.current_class.is_compact) { + if (context.analyzer.get_current_class (this).is_compact) { error = true; resource.error = true; Report.error (resource.source_reference, "Only members of the non-compact classes are lockable");