From a4c5b66d995ac63978a04a9658d3469f49b7679e Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Fri, 8 Aug 2003 05:49:37 +0000 Subject: [PATCH] Import changes from mainline svn path=/trunk/mcs/; revision=17186 --- mcs/gmcs/ChangeLog | 182 ++++ mcs/gmcs/Makefile | 4 + mcs/gmcs/assign.cs | 20 +- mcs/gmcs/attribute.cs | 51 +- mcs/gmcs/class.cs | 6 +- mcs/gmcs/codegen.cs | 174 +++- mcs/gmcs/convert.cs | 10 +- mcs/gmcs/cs-parser.jay | 65 +- mcs/gmcs/cs-tokenizer.cs | 76 +- mcs/gmcs/driver.cs | 4 +- mcs/gmcs/ecore.cs | 61 +- mcs/gmcs/expression.cs | 501 ++++++---- mcs/gmcs/iterators.cs | 12 +- mcs/gmcs/namespace.cs | 17 +- mcs/gmcs/statement.cs | 1996 +++----------------------------------- mcs/gmcs/support.cs | 73 ++ mcs/gmcs/typemanager.cs | 17 +- 17 files changed, 1078 insertions(+), 2191 deletions(-) diff --git a/mcs/gmcs/ChangeLog b/mcs/gmcs/ChangeLog index 790707e69d0..88ab7258240 100755 --- a/mcs/gmcs/ChangeLog +++ b/mcs/gmcs/ChangeLog @@ -1,3 +1,185 @@ +2003-08-08 Martin Baulig + + * flowanalysis.cs (FlowReturns): This is now nested in the + `FlowBranching' class. + (MyBitVector): Moved this here from statement.cs. + (FlowBranching.SiblingType): New enum type. + (FlowBranching.CreateSibling): Added `SiblingType' argument. + +2003-08-07 Martin Baulig + + * flowanalysis.cs (FlowBranchingType): This is now nested in the + `FlowBranching' class and called `BranchingType'. + +2003-08-07 Martin Baulig + + * flowanalysis.cs: Moved all the control flow analysis code into + its own file. + +2003-08-07 Martin Baulig + + * assign.cs (Assign.DoResolve): `target' must either be an + IAssignMethod or an EventAccess; report a CS0131 otherwise. Fixes + #37319. + +2003-08-07 Miguel de Icaza + + * expression.cs (BinaryMethod): This kind of expression is created by the + Binary class if it determines that the operator has to be handled + by a method. + + (BinaryDelegate): This kind of expression is created if we are + dealing with a + or - operator on delegates. + + (Binary): remove method, argumetns, and DelegateOperator: when + dealing with methods, + + * ecore.cs (EventExpr.EmitAddOrRemove): Update to new layout. + + * statement.cs (Block): use bitfields for the three extra booleans + we had in use. Remove unused topblock parameter. + + * codegen.cs: Remove unecessary argument to Block.EmitTopBlock + + * assign.cs: Drop extra unneeded tests. + +2003-08-06 Miguel de Icaza + + * iterators.cs (Mapvariable): provide a mechanism to use prefixes. + + * statement.cs (Foreach): Use VariableStorage instead of + LocalBuilders. + + * codegen.cs (VariableStorage): New class used by clients that + require a variable stored: locals or fields for variables that + need to live across yield. + + Maybe provide a convenience api for EmitThis+EmitLoad? + + (GetTemporaryLocal, FreeTemporaryLocal): Recycle + these bad boys. + +2003-08-05 Miguel de Icaza + + * codegen.cs (RemapLocal, RemapLocalLValue, RemapParameter, + RemapParameterLValue): New methods that are used to turn a + precomputed FieldInfo into an expression like this: + + instance.FieldInfo + + The idea is to use this instead of making LocalVariableReference + have more than one meaning. + + * cs-parser.jay: Add error production to BASE. + + * ecore.cs: Deal with TypeManager.GetField returning null, which + is now a valid return value. + + (FieldExprNoAddress): New expression for Fields whose address can + not be taken. + + * expression.cs (LocalVariableReference): During the resolve + phases, create new expressions if we are in a remapping context. + Remove code that dealt with remapping here. + + (ParameterReference): same. + + (ProxyInstance): New expression, like the `This' expression, but + it is born fully resolved. We know what we are doing, so remove + the errors that are targeted to user-provided uses of `this'. + + * statement.cs (Foreach): our variable is now stored as an + Expression; During resolution, follow the protocol, dont just + assume it will return this. + +2003-08-06 Martin Baulig + + * support.cs (SeekableStreamReader.cs): New public class. + + * cs-tokenizer.cs, cs-parser.jay, driver.cs: Use the new + SeekableStreamReader instead of the normal StreamReader. + +2003-08-04 Martin Baulig + + * cs-parser.jay (CLOSE_PARENS_CAST, CLOSE_PARENS_NO_CAST, + CLOSE_PARENS_OPEN_PARENS, CLOSE_PARENS_MINUS): New tokens to + deambiguate casts and delegate invocations. + (parenthesized_expression): Use the new tokens to ensure this is + not a cast of method invocation. + + * cs-tokenizer.cs (is_punct): Return one of the new special tokens + when reading a `)' and Deambiguate_CloseParens () was previously + called. + + * expression.cs (ParenthesizedExpression): New class. This is + just used for the CS0075 test. + (Binary.DoResolve): Check for CS0075. + +2003-07-29 Ravi Pratap + + * expression.cs (Invocation.MakeUnionSet): Patch from Lluis + Sanchez : use TypeManager.ArrayContainsMethod instead of a direct + reference comparison. + + (TypeManager.ArrayContainsMethod): When we have a MethodInfo, also + examine the ReturnType for equality - this is necessary in the + cases of implicit and explicit operators whose signature also + includes the return type. + +2003-07-26 Miguel de Icaza + + * namespace.cs: Cache the result of the namespace computation, + instead of computing it every time. + +2003-07-24 Miguel de Icaza + + * decl.cs: Use a global arraylist that we reuse over invocations + to avoid excesive memory consumption. Reduces memory usage on an + mcs compile by one meg (45 average). + + * typemanager.cs (LookupTypeReflection): In .NET pointers are + private, work around that. + +2003-07-23 Miguel de Icaza + + * literal.cs (IntLiteral): Define Zero and One static literals. + + * cs-parser.jay (integer_literal): use static literals to reduce + memory usage for the most used literals (0, 1 and -1). 211kb + reduced in memory usage. + + Replace all calls to `new ArrayList' with `new + ArrayList(4)' which is a good average number for most allocations, + and also requires only 16 bytes of memory for its buffer by + default. + + This reduced MCS memory usage in seven megabytes for the RSS after + bootstrapping. + +2003-07-28 Ravi Pratap + + * expression.cs (Invocation.OverloadResolve): Fix the algorithm to + handle params methods the correct way by forming only one + applicable set with params and normal methods in them. Earlier we + were looking at params methods only if we found no normal methods + which was not the correct thing to do. + + (Invocation.BetterFunction): Take separate arguments indicating + when candidate and the best method are params methods in their + expanded form. + + This fixes bugs #43367 and #46199. + + * attribute.cs: Documentation updates. + + (CheckAttribute): Rename to CheckAttributeTarget. + (GetValidPlaces): Rename to GetValidTargets. + + * expression.cs (Invocation.IsParamsMethodApplicable): Fix trivial + bug - use Convert.ImplicitConversion, not ImplicitUserConversion! + + Fixes bug #44468. + 2003-07-28 Miguel de Icaza * codegen.cs: Compute IsGeneric correctly. diff --git a/mcs/gmcs/Makefile b/mcs/gmcs/Makefile index 0374b1e90cd..d16d330b492 100644 --- a/mcs/gmcs/Makefile +++ b/mcs/gmcs/Makefile @@ -20,6 +20,7 @@ COMPILER_SOURCES = \ enum.cs \ ecore.cs \ expression.cs \ + flowanalysis.cs \ generic.cs \ interface.cs \ iterators.cs \ @@ -84,3 +85,6 @@ mcs2.exe: gmcs.exe mcs3.exe: mcs2.exe $(TIME) $(RUNTIME) ./mcs2.exe $(USE_MCS_FLAGS) /target:exe /out:$@ $(all_sources) + +response: + echo $(all_sources) > res diff --git a/mcs/gmcs/assign.cs b/mcs/gmcs/assign.cs index 9153f63d59d..b489fc60d27 100755 --- a/mcs/gmcs/assign.cs +++ b/mcs/gmcs/assign.cs @@ -64,12 +64,12 @@ namespace Mono.CSharp { type = t; eclass = ExprClass.Value; loc = Location.Null; - builder = ec.GetTemporaryStorage (t); + builder = ec.GetTemporaryLocal (t); } public void Release (EmitContext ec) { - ec.FreeTemporaryStorage (builder); + ec.FreeTemporaryLocal (builder, type); builder = null; } @@ -235,17 +235,10 @@ namespace Mono.CSharp { // it will appear as a FieldExpr in that case. // - if (!(source is Binary)) { + if (!(source is BinaryDelegate)) { error70 (ei, loc); return null; - } else { - Binary tmp = ((Binary) source); - if (tmp.Oper != Binary.Operator.Addition && - tmp.Oper != Binary.Operator.Subtraction) { - error70 (ei, loc); - return null; - } - } + } } } @@ -259,8 +252,7 @@ namespace Mono.CSharp { return null; } - if (target.eclass != ExprClass.Variable && target.eclass != ExprClass.EventAccess && - target.eclass != ExprClass.IndexerAccess && target.eclass != ExprClass.PropertyAccess){ + if (!(target is IAssignMethod) && (target.eclass != ExprClass.EventAccess)) { Report.Error (131, loc, "Left hand of an assignment must be a variable, " + "a property or an indexer"); @@ -288,7 +280,7 @@ namespace Mono.CSharp { CompoundAssign a = (CompoundAssign) this; Binary b = source as Binary; - if (b != null && b.IsBuiltinOperator){ + if (b != null){ // // 1. if the source is explicitly convertible to the // target_type diff --git a/mcs/gmcs/attribute.cs b/mcs/gmcs/attribute.cs index 9f9c3c144ef..9a2c1124323 100644 --- a/mcs/gmcs/attribute.cs +++ b/mcs/gmcs/attribute.cs @@ -30,7 +30,7 @@ namespace Mono.CSharp { // // The following are only meaningful when the attribute - // being emitted is one of the builtin ones + // being emitted is an AttributeUsage attribute // AttributeTargets Targets; bool AllowMultiple; @@ -42,7 +42,7 @@ namespace Mono.CSharp { UnmanagedType UnmanagedType; CustomAttributeBuilder cb; - /* non-null if named args present after Resolve () is called */ + // non-null if named args present after Resolve () is called PropertyInfo [] prop_info_arr; FieldInfo [] field_info_arr; object [] field_values_arr; @@ -81,7 +81,10 @@ namespace Mono.CSharp { Report.Error ( -202, loc, "Can not use a type parameter in an attribute"); } - + + /// + /// Tries to resolve the type of the attribute. Flags an error if it can't. + /// private Type CheckAttributeType (EmitContext ec) { Type t; bool isattributeclass = true; @@ -167,6 +170,12 @@ namespace Mono.CSharp { UsageAttr = false; bool DoCompares = true; + + // + // If we are a certain special attribute, we + // set the information accordingly + // + if (Type == TypeManager.attribute_usage_type) UsageAttr = true; else if (Type == TypeManager.methodimpl_attr_type) @@ -425,7 +434,8 @@ namespace Mono.CSharp { // Don't know what to do here // Report.Warning ( - -100, Location, "NullReferenceException while trying to create attribute. Something's wrong!"); + -100, Location, "NullReferenceException while trying to create attribute." + + "Something's wrong!"); } catch (Exception e) { // // Sample: @@ -442,7 +452,10 @@ namespace Mono.CSharp { return cb; } - static string GetValidPlaces (Attribute attr) + /// + /// Get a string containing a list of valid targets for the attribute 'attr' + /// + static string GetValidTargets (Attribute attr) { StringBuilder sb = new StringBuilder (); AttributeTargets targets = 0; @@ -523,10 +536,13 @@ namespace Mono.CSharp { Report.Error ( 592, loc, "Attribute '" + a.Name + "' is not valid on this declaration type. " + - "It is valid on " + GetValidPlaces (a) + "declarations only."); + "It is valid on " + GetValidTargets (a) + "declarations only."); } - public static bool CheckAttribute (Attribute a, object element) + /// + /// Ensure that Attribute 'a' is being applied to the right target + /// + public static bool CheckAttributeTarget (Attribute a, object element) { TypeContainer attr = TypeManager.LookupAttr (a.Type); AttributeTargets targets = 0; @@ -742,7 +758,8 @@ namespace Mono.CSharp { return ((StringConstant) arg.Expr).Value; } - static object GetFieldValue (Attribute a, string name) { + static object GetFieldValue (Attribute a, string name) + { int i; if (a.field_info_arr == null) return null; @@ -755,11 +772,13 @@ namespace Mono.CSharp { return null; } - static UnmanagedMarshal GetMarshal (Attribute a) { + static UnmanagedMarshal GetMarshal (Attribute a) + { UnmanagedMarshal marshal; if (a.UnmanagedType == UnmanagedType.CustomMarshaler) { - MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom", BindingFlags.Static | BindingFlags.Public); + MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom", + BindingFlags.Static | BindingFlags.Public); if (define_custom == null) { return null; } @@ -778,9 +797,9 @@ namespace Mono.CSharp { return marshal; } - // - // Applies the attributes to the `builder'. - // + /// + /// Applies the attributes specified on target 'kind' to the `builder'. + /// public static void ApplyAttributes (EmitContext ec, object builder, object kind, Attributes opt_attrs) { @@ -815,7 +834,7 @@ namespace Mono.CSharp { continue; if (!(kind is TypeContainer)) - if (!CheckAttribute (a, kind)) { + if (!CheckAttributeTarget (a, kind)) { Error_AttributeNotValidForElement (a, loc); return; } @@ -898,7 +917,7 @@ namespace Mono.CSharp { } } else { - if (!CheckAttribute (a, kind)) { + if (!CheckAttributeTarget (a, kind)) { Error_AttributeNotValidForElement (a, loc); return; } @@ -928,7 +947,7 @@ namespace Mono.CSharp { return; } - if (!CheckAttribute (a, kind)) { + if (!CheckAttributeTarget (a, kind)) { Error_AttributeNotValidForElement (a, loc); return; } diff --git a/mcs/gmcs/class.cs b/mcs/gmcs/class.cs index 90634591501..c80cb78877c 100755 --- a/mcs/gmcs/class.cs +++ b/mcs/gmcs/class.cs @@ -2304,7 +2304,8 @@ namespace Mono.CSharp { if (par_attr == ParameterAttributes.Out){ if (attr.Contains (TypeManager.in_attribute_type)) - Report.Error (36, Location, "Can not use [In] attribute on out parameter"); + Report.Error (36, Location, + "Can not use [In] attribute on out parameter"); } } } @@ -2356,7 +2357,8 @@ namespace Mono.CSharp { } catch (ArgumentOutOfRangeException) { Report.Warning ( -24, Location, - ".NET SDK 1.0 does not permit to set custom attributes to the return type of a method"); + ".NET SDK 1.0 does not permit setting custom attributes" + + " on the return type of a method"); } } } diff --git a/mcs/gmcs/codegen.cs b/mcs/gmcs/codegen.cs index 96d58cbb763..7293f99df5a 100755 --- a/mcs/gmcs/codegen.cs +++ b/mcs/gmcs/codegen.cs @@ -119,6 +119,52 @@ namespace Mono.CSharp { } } + // + // Provides "local" store across code that can yield: locals + // or fields, notice that this should not be used by anonymous + // methods to create local storage, those only require + // variable mapping. + // + public class VariableStorage { + ILGenerator ig; + FieldBuilder fb; + LocalBuilder local; + + static int count; + + public VariableStorage (EmitContext ec, Type t) + { + count++; + if (ec.InIterator) + fb = IteratorHandler.Current.MapVariable ("s_", count.ToString (), t); + else + local = ec.ig.DeclareLocal (t); + ig = ec.ig; + } + + public void EmitThis () + { + if (fb != null) + ig.Emit (OpCodes.Ldarg_0); + } + + public void EmitStore () + { + if (fb == null) + ig.Emit (OpCodes.Stloc, local); + else + ig.Emit (OpCodes.Stfld, fb); + } + + public void EmitLoad () + { + if (fb == null) + ig.Emit (OpCodes.Ldloc, local); + else + ig.Emit (OpCodes.Ldfld, fb); + } + } + /// /// An Emit Context is created for each body of code (from methods, /// properties bodies, indexer bodies or constructor bodies) @@ -344,7 +390,7 @@ namespace Mono.CSharp { // Starts a new code branching. This inherits the state of all local // variables and parameters from the current branching. // - public FlowBranching StartFlowBranching (FlowBranchingType type, Location loc) + public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc) { FlowBranching cfb = new FlowBranching (CurrentBranching, type, null, loc); @@ -359,12 +405,12 @@ namespace Mono.CSharp { public FlowBranching StartFlowBranching (Block block) { FlowBranching cfb; - FlowBranchingType type; + FlowBranching.BranchingType type; - if (CurrentBranching.Type == FlowBranchingType.SWITCH) - type = FlowBranchingType.SWITCH_SECTION; + if (CurrentBranching.Type == FlowBranching.BranchingType.Switch) + type = FlowBranching.BranchingType.SwitchSection; else - type = FlowBranchingType.BLOCK; + type = FlowBranching.BranchingType.Block; cfb = new FlowBranching (CurrentBranching, type, block, block.StartLocation); @@ -377,7 +423,7 @@ namespace Mono.CSharp { // Ends a code branching. Merges the state of locals and parameters // from all the children of the ending branching. // - public FlowReturns EndFlowBranching () + public FlowBranching.FlowReturns EndFlowBranching () { FlowBranching cfb = (FlowBranching) FlowStack.Pop (); @@ -404,7 +450,7 @@ namespace Mono.CSharp { try { int errors = Report.Errors; - block.EmitMeta (this, ip, block); + block.EmitMeta (this, ip); if (Report.Errors == errors){ bool old_do_flow_analysis = DoFlowAnalysis; @@ -420,15 +466,15 @@ namespace Mono.CSharp { } cfb = (FlowBranching) FlowStack.Pop (); - FlowReturns returns = cfb.MergeTopBlock (); + FlowBranching.FlowReturns returns = cfb.MergeTopBlock (); DoFlowAnalysis = old_do_flow_analysis; has_ret = block.Emit (this); - if ((returns == FlowReturns.ALWAYS) || - (returns == FlowReturns.EXCEPTION) || - (returns == FlowReturns.UNREACHABLE)) + if ((returns == FlowBranching.FlowReturns.Always) || + (returns == FlowBranching.FlowReturns.Exception) || + (returns == FlowBranching.FlowReturns.Unreachable)) has_ret = true; if (Report.Errors == errors){ @@ -508,24 +554,60 @@ namespace Mono.CSharp { /// Returns a temporary storage for a variable of type t as /// a local variable in the current body. /// - public LocalBuilder GetTemporaryStorage (Type t) + public LocalBuilder GetTemporaryLocal (Type t) { - LocalBuilder location; + LocalBuilder location = null; if (temporary_storage != null){ - location = (LocalBuilder) temporary_storage [t]; - if (location != null) - return location; + object o = temporary_storage [t]; + if (o != null){ + if (o is ArrayList){ + ArrayList al = (ArrayList) o; + + for (int i = 0; i < al.Count; i++){ + if (al [i] != null){ + location = (LocalBuilder) al [i]; + al [i] = null; + break; + } + } + } else + location = (LocalBuilder) o; + if (location != null) + return location; + } } - location = ig.DeclareLocal (t); - - return location; + return ig.DeclareLocal (t); } - public void FreeTemporaryStorage (LocalBuilder b) + public void FreeTemporaryLocal (LocalBuilder b, Type t) { - // Empty for now. + if (temporary_storage == null){ + temporary_storage = new Hashtable (); + temporary_storage [t] = b; + return; + } + object o = temporary_storage [t]; + if (o == null){ + temporary_storage [t] = b; + return; + } + if (o is ArrayList){ + ArrayList al = (ArrayList) o; + for (int i = 0; i < al.Count; i++){ + if (al [i] == null){ + al [i] = b; + return; + } + } + al.Add (b); + return; + } + ArrayList replacement = new ArrayList (); + replacement.Add (o); + temporary_storage.Remove (t); + temporary_storage [t] = replacement; } /// @@ -583,12 +665,44 @@ namespace Mono.CSharp { public FieldBuilder MapVariable (string name, Type t) { if (InIterator){ - return IteratorHandler.Current.MapVariable (name, t); + return IteratorHandler.Current.MapVariable ("v_", name, t); } throw new Exception ("MapVariable for an unknown state"); } + // + // Invoke this routine to remap a VariableInfo into the + // proper MemberAccess expression + // + public Expression RemapLocal (LocalInfo local_info) + { + FieldExpr fe = new FieldExpr (local_info.FieldBuilder, loc); + fe.InstanceExpression = new ProxyInstance (); + return fe.DoResolve (this); + } + + public Expression RemapLocalLValue (LocalInfo local_info, Expression right_side) + { + FieldExpr fe = new FieldExpr (local_info.FieldBuilder, loc); + fe.InstanceExpression = new ProxyInstance (); + return fe.DoResolveLValue (this, right_side); + } + + public Expression RemapParameter (int idx) + { + FieldExpr fe = new FieldExprNoAddress (IteratorHandler.Current.parameter_fields [idx], loc); + fe.InstanceExpression = new ProxyInstance (); + return fe.DoResolve (this); + } + + public Expression RemapParameterLValue (int idx, Expression right_side) + { + FieldExpr fe = new FieldExprNoAddress (IteratorHandler.Current.parameter_fields [idx], loc); + fe.InstanceExpression = new ProxyInstance (); + return fe.DoResolveLValue (this, right_side); + } + // // Emits the proper object to address fields on a remapped // variable/parameter to field in anonymous-method/iterator proxy classes. @@ -605,22 +719,6 @@ namespace Mono.CSharp { } } - public void EmitArgument (int idx) - { - if (InIterator) - ig.Emit (OpCodes.Ldfld, IteratorHandler.Current.parameter_fields [idx]); - else - throw new Exception ("EmitStoreArgument for an unknown state"); - } - - public void EmitStoreArgument (int idx) - { - if (InIterator) - ig.Emit (OpCodes.Stfld, IteratorHandler.Current.parameter_fields [idx]); - else - throw new Exception ("EmitStoreArgument for an unknown state"); - } - public Expression GetThis (Location loc) { This my_this; diff --git a/mcs/gmcs/convert.cs b/mcs/gmcs/convert.cs index ad577caa190..b6dfab95c44 100644 --- a/mcs/gmcs/convert.cs +++ b/mcs/gmcs/convert.cs @@ -431,8 +431,6 @@ namespace Mono.CSharp { if (expr_type == target_type) return true; - //Console.WriteLine ("No !!"); - // First numeric conversions if (expr_type == TypeManager.sbyte_type){ @@ -928,13 +926,7 @@ namespace Mono.CSharp { return null; Type most_specific_source, most_specific_target; -#if BLAH - foreach (MethodBase m in union.Methods){ - Console.WriteLine ("Name: " + m.Name); - Console.WriteLine (" : " + ((MethodInfo)m).ReturnType); - } -#endif - + most_specific_source = FindMostSpecificSource (union, source, look_for_explicit, loc); if (most_specific_source == null) return null; diff --git a/mcs/gmcs/cs-parser.jay b/mcs/gmcs/cs-parser.jay index 450cd28f2a2..b6d36d0b5a2 100755 --- a/mcs/gmcs/cs-parser.jay +++ b/mcs/gmcs/cs-parser.jay @@ -247,6 +247,10 @@ namespace Mono.CSharp %token LITERAL_STRING "string literal" %token IDENTIFIER +%token CLOSE_PARENS_CAST +%token CLOSE_PARENS_NO_CAST +%token CLOSE_PARENS_OPEN_PARENS +%token CLOSE_PARENS_MINUS /* Add precedence rules to solve dangling else s/r conflict */ %nonassoc LOWPREC @@ -429,9 +433,10 @@ type_declaration // // Enable this when we have handled all errors, because this acts as a generic fallback // -// | error { -// Report.Error (1518, lexer.Location, "Expected class, struct, interface, enum or delegate"); -// } + | error { + Console.WriteLine ("Token=" + yyToken); + Report.Error (1518, lexer.Location, "Expected class, struct, interface, enum or delegate"); + } ; // @@ -2064,11 +2069,31 @@ boolean_literal | FALSE { $$ = new BoolLiteral (false); } ; -parenthesized_expression +parenthesized_expression_0 : OPEN_PARENS expression CLOSE_PARENS - { $$ = $2; } + { + $$ = $2; + lexer.Deambiguate_CloseParens (); + // After this, the next token returned is one of + // CLOSE_PARENS_CAST, CLOSE_PARENS_NO_CAST, CLOSE_PARENS_OPEN_PARENS + // or CLOSE_PARENS_MINUS. + } ; +parenthesized_expression + : parenthesized_expression_0 CLOSE_PARENS_NO_CAST + { + $$ = $1; + } + | parenthesized_expression_0 CLOSE_PARENS_MINUS + { + // If a parenthesized expression is followed by a minus, we need to wrap + // the expression inside a ParenthesizedExpression for the CS0075 check + // in Binary.DoResolve(). + $$ = new ParenthesizedExpression ((Expression) $1, lexer.Location); + } + ;; + member_access : primary_expression DOT IDENTIFIER { @@ -2093,9 +2118,13 @@ invocation_expression } $$ = new Invocation ((Expression) $1, (ArrayList) $3, lexer.Location); } - | OPEN_PARENS expression CLOSE_PARENS unary_expression + | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS OPEN_PARENS CLOSE_PARENS + { + $$ = new Invocation ((Expression) $1, new ArrayList (), lexer.Location); + } + | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS primary_expression { - $$ = new InvocationOrCast ((Expression) $2, (Expression) $4, lexer.Location); + $$ = new InvocationOrCast ((Expression) $1, (Expression) $3, lexer.Location); } ; @@ -2199,6 +2228,10 @@ base_access { $$ = new BaseIndexerAccess ((ArrayList) $3, lexer.Location); } + | BASE error { + Report.Error (175, "Use of keyword `base' is not valid in this context"); + $$ = null; + } ; post_increment_expression @@ -2444,10 +2477,22 @@ unary_expression | cast_expression ; +cast_list + : parenthesized_expression_0 CLOSE_PARENS_CAST unary_expression + { + $$ = new Cast ((Expression) $1, (Expression) $3, lexer.Location); + } + | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS cast_expression + { + $$ = new Cast ((Expression) $1, (Expression) $3, lexer.Location); + } + ; + cast_expression - : OPEN_PARENS non_expression_type CLOSE_PARENS prefixed_unary_expression + : cast_list + | OPEN_PARENS non_expression_type CLOSE_PARENS prefixed_unary_expression { - $$ = new Cast ((Expression) $2, (Expression) $4, lexer.Location); + $$ = new Cast ((Expression) $2, (Expression) $4, lexer.Location); } ; @@ -4181,7 +4226,7 @@ public Tokenizer Lexer { } } -public CSharpParser (StreamReader reader, SourceFile file, ArrayList defines) +public CSharpParser (SeekableStreamReader reader, SourceFile file, ArrayList defines) { current_namespace = new NamespaceEntry (null, file, null); this.name = file.Name; diff --git a/mcs/gmcs/cs-tokenizer.cs b/mcs/gmcs/cs-tokenizer.cs index b3676fe5c77..e759a1a1780 100755 --- a/mcs/gmcs/cs-tokenizer.cs +++ b/mcs/gmcs/cs-tokenizer.cs @@ -30,7 +30,7 @@ namespace Mono.CSharp public class Tokenizer : yyParser.yyInput { - StreamReader reader; + SeekableStreamReader reader; public SourceFile ref_name; public SourceFile file_name; public int ref_line = 1; @@ -335,7 +335,7 @@ namespace Mono.CSharp defines [def] = true; } - public Tokenizer (StreamReader input, SourceFile file, ArrayList defs) + public Tokenizer (SeekableStreamReader input, SourceFile file, ArrayList defs) { this.ref_name = file; this.file_name = file; @@ -384,8 +384,28 @@ namespace Mono.CSharp return Token.CLOSE_BRACKET; case '(': return Token.OPEN_PARENS; - case ')': - return Token.CLOSE_PARENS; + case ')': { + if (deambiguate_close_parens == 0) + return Token.CLOSE_PARENS; + + --deambiguate_close_parens; + + // Save current position and parse next token. + int old = reader.Position; + int new_token = token (); + reader.Position = old; + putback_char = -1; + + if (new_token == Token.OPEN_PARENS) + return Token.CLOSE_PARENS_OPEN_PARENS; + else if (new_token == Token.MINUS) + return Token.CLOSE_PARENS_MINUS; + else if (IsCastToken (new_token)) + return Token.CLOSE_PARENS_CAST; + else + return Token.CLOSE_PARENS_NO_CAST; + } + case ',': return Token.COMMA; case ':': @@ -529,6 +549,14 @@ namespace Mono.CSharp return Token.ERROR; } + int deambiguate_close_parens = 0; + + public void Deambiguate_CloseParens () + { + putback (')'); + deambiguate_close_parens++; + } + void Error_NumericConstantTooLong () { Report.Error (1021, Location, "Numeric constant too long"); @@ -999,13 +1027,45 @@ namespace Mono.CSharp { return val; } - - public int token () + + bool IsCastToken (int token) { - current_token = xtoken (); - return current_token; + switch (token) { + case Token.BANG: + case Token.TILDE: + case Token.IDENTIFIER: + case Token.LITERAL_INTEGER: + case Token.LITERAL_FLOAT: + case Token.LITERAL_DOUBLE: + case Token.LITERAL_DECIMAL: + case Token.LITERAL_CHARACTER: + case Token.LITERAL_STRING: + case Token.BASE: + case Token.CHECKED: + case Token.FALSE: + case Token.FIXED: + case Token.NEW: + case Token.NULL: + case Token.SIZEOF: + case Token.THIS: + case Token.THROW: + case Token.TRUE: + case Token.TYPEOF: + case Token.UNCHECKED: + case Token.UNSAFE: + return true; + + default: + return false; + } } + public int token () + { + current_token = xtoken (); + return current_token; + } + static StringBuilder static_cmd_arg = new System.Text.StringBuilder (); void get_cmd_arg (out string cmd, out string arg) diff --git a/mcs/gmcs/driver.cs b/mcs/gmcs/driver.cs index 1b8f735c690..01d12ea067c 100755 --- a/mcs/gmcs/driver.cs +++ b/mcs/gmcs/driver.cs @@ -139,7 +139,7 @@ namespace Mono.CSharp } using (input){ - StreamReader reader = new StreamReader (input, encoding, using_default_encoder); + SeekableStreamReader reader = new SeekableStreamReader (input, encoding, using_default_encoder); Tokenizer lexer = new Tokenizer (reader, file, defines); int token, tokens = 0, errors = 0; @@ -168,7 +168,7 @@ namespace Mono.CSharp return; } - StreamReader reader = new StreamReader (input, encoding, using_default_encoder); + SeekableStreamReader reader = new SeekableStreamReader (input, encoding, using_default_encoder); parser = new CSharpParser (reader, file, defines); parser.yacc_verbose_flag = yacc_verbose; diff --git a/mcs/gmcs/ecore.cs b/mcs/gmcs/ecore.cs index da16aeda8f0..3e5af299637 100755 --- a/mcs/gmcs/ecore.cs +++ b/mcs/gmcs/ecore.cs @@ -2560,11 +2560,12 @@ namespace Mono.CSharp { if (FieldInfo is FieldBuilder){ FieldBase f = TypeManager.GetField (FieldInfo); - - if ((f.ModFlags & Modifiers.VOLATILE) != 0) - is_volatile = true; - - f.status |= Field.Status.USED; + if (f != null){ + if ((f.ModFlags & Modifiers.VOLATILE) != 0) + is_volatile = true; + + f.status |= Field.Status.USED; + } } if (FieldInfo.IsStatic){ @@ -2615,7 +2616,7 @@ namespace Mono.CSharp { Report_AssignToReadonly (!is_static); return; } - + if (!is_static){ Expression instance = instance_expr; @@ -2635,11 +2636,12 @@ namespace Mono.CSharp { if (FieldInfo is FieldBuilder){ FieldBase f = TypeManager.GetField (FieldInfo); - - if ((f.ModFlags & Modifiers.VOLATILE) != 0) - ig.Emit (OpCodes.Volatile); - - f.status |= Field.Status.ASSIGNED; + if (f != null){ + if ((f.ModFlags & Modifiers.VOLATILE) != 0) + ig.Emit (OpCodes.Volatile); + + f.status |= Field.Status.ASSIGNED; + } } if (is_static) @@ -2654,15 +2656,17 @@ namespace Mono.CSharp { if (FieldInfo is FieldBuilder){ FieldBase f = TypeManager.GetField (FieldInfo); - if ((f.ModFlags & Modifiers.VOLATILE) != 0){ - Error (676, "volatile variable: can not take its address, or pass as ref/out parameter"); - return; + if (f != null){ + if ((f.ModFlags & Modifiers.VOLATILE) != 0){ + Error (676, "volatile variable: can not take its address, or pass as ref/out parameter"); + return; + } + + if ((mode & AddressOp.Store) != 0) + f.status |= Field.Status.ASSIGNED; + if ((mode & AddressOp.Load) != 0) + f.status |= Field.Status.USED; } - - if ((mode & AddressOp.Store) != 0) - f.status |= Field.Status.ASSIGNED; - if ((mode & AddressOp.Load) != 0) - f.status |= Field.Status.USED; } // @@ -2700,6 +2704,20 @@ namespace Mono.CSharp { } } + // + // A FieldExpr whose address can not be taken + // + public class FieldExprNoAddress : FieldExpr, IMemoryLocation { + public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc) + { + } + + public new void AddressOf (EmitContext ec, AddressOp mode) + { + Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported"); + } + } + /// /// Expression that evaluates to a Property. The Assign class /// might set the `Value' expression if we are in an assignment. @@ -3098,14 +3116,15 @@ namespace Mono.CSharp { public void EmitAddOrRemove (EmitContext ec, Expression source) { - Expression handler = ((Binary) source).Right; + BinaryDelegate source_del = (BinaryDelegate) source; + Expression handler = source_del.Right; Argument arg = new Argument (handler, Argument.AType.Expression); ArrayList args = new ArrayList (); args.Add (arg); - if (((Binary) source).Oper == Binary.Operator.Addition) + if (source_del.IsAddition) Invocation.EmitCall ( ec, false, IsStatic, instance_expr, add_accessor, args, loc); else diff --git a/mcs/gmcs/expression.cs b/mcs/gmcs/expression.cs index f2603a97c1b..a223248ee94 100755 --- a/mcs/gmcs/expression.cs +++ b/mcs/gmcs/expression.cs @@ -81,6 +81,28 @@ namespace Mono.CSharp { ec.ig.Emit (OpCodes.Pop); } } + + public class ParenthesizedExpression : Expression + { + public Expression Expr; + + public ParenthesizedExpression (Expression expr, Location loc) + { + this.Expr = expr; + this.loc = loc; + } + + public override Expression DoResolve (EmitContext ec) + { + Expr = Expr.Resolve (ec); + return Expr; + } + + public override void Emit (EmitContext ec) + { + throw new Exception ("Should not happen"); + } + } /// /// Unary expressions. @@ -950,9 +972,7 @@ namespace Mono.CSharp { // For now: only localvariables when not remapped // - if (method == null && - (expr is LocalVariableReference && ec.RemapToProxy == false) || - (expr is FieldExpr && ((FieldExpr) expr).FieldInfo.IsStatic)){ + if (method == null && (expr is FieldExpr && ((FieldExpr) expr).FieldInfo.IsStatic)){ if (empty_expr == null) empty_expr = new EmptyExpression (); @@ -1816,15 +1836,6 @@ namespace Mono.CSharp { Operator oper; Expression left, right; - // - // After resolution, method might contain the operator overload - // method. - // - protected MethodBase method; - ArrayList Arguments; - - bool DelegateOperation; - // This must be kept in sync with Operator!!! public static readonly string [] oper_names; @@ -2239,16 +2250,15 @@ namespace Mono.CSharp { union = (MethodGroupExpr) left_expr; if (union != null) { - Arguments = new ArrayList (); - Arguments.Add (new Argument (left, Argument.AType.Expression)); - Arguments.Add (new Argument (right, Argument.AType.Expression)); + ArrayList args = new ArrayList (2); + args.Add (new Argument (left, Argument.AType.Expression)); + args.Add (new Argument (right, Argument.AType.Expression)); - method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null); + MethodBase method = Invocation.OverloadResolve (ec, union, args, Location.Null); if (method != null) { MethodInfo mi = (MethodInfo) method; - type = mi.ReturnType; - return this; + return new BinaryMethod (mi.ReturnType, method, args); } else { overload_failed = true; } @@ -2268,6 +2278,7 @@ namespace Mono.CSharp { // if (l == TypeManager.string_type){ + MethodBase method; if (r == TypeManager.void_type) { Error_OperatorCannotBeApplied (); @@ -2283,33 +2294,29 @@ namespace Mono.CSharp { ls.Value + rs.Value); } - if (left is Binary){ - Binary b = (Binary) left; + if (left is BinaryMethod){ + BinaryMethod b = (BinaryMethod) left; // // Call String.Concat (string, string, string) or // String.Concat (string, string, string, string) // if possible. // - if (b.oper == Operator.Addition && - (b.method == TypeManager.string_concat_string_string || - b.method == TypeManager.string_concat_string_string_string)){ + if (b.method == TypeManager.string_concat_string_string || + b.method == TypeManager.string_concat_string_string_string){ ArrayList bargs = b.Arguments; int count = bargs.Count; if (count == 2){ - Arguments = bargs; - Arguments.Add (new Argument (right, Argument.AType.Expression)); - type = TypeManager.string_type; - method = TypeManager.string_concat_string_string_string; - - return this; + bargs.Add (new Argument (right, Argument.AType.Expression)); + return new BinaryMethod ( + TypeManager.string_type, + TypeManager.string_concat_string_string_string, bargs); } else if (count == 3){ - Arguments = bargs; - Arguments.Add (new Argument (right, Argument.AType.Expression)); - type = TypeManager.string_type; - method = TypeManager.string_concat_string_string_string_string; - return this; + bargs.Add (new Argument (right, Argument.AType.Expression)); + return new BinaryMethod ( + TypeManager.string_type, + TypeManager.string_concat_string_string_string_string, bargs); } } } @@ -2326,14 +2333,15 @@ namespace Mono.CSharp { return null; } } - type = TypeManager.string_type; - Arguments = new ArrayList (); - Arguments.Add (new Argument (left, Argument.AType.Expression)); - Arguments.Add (new Argument (right, Argument.AType.Expression)); + // + // Cascading concats will hold up to 4 arguments + // + ArrayList args = new ArrayList (4); + args.Add (new Argument (left, Argument.AType.Expression)); + args.Add (new Argument (right, Argument.AType.Expression)); - return this; - + return new BinaryMethod (TypeManager.string_type, method, args); } else if (r == TypeManager.string_type){ // object + string @@ -2342,19 +2350,16 @@ namespace Mono.CSharp { return null; } - method = TypeManager.string_concat_object_object; left = Convert.ImplicitConversion (ec, left, TypeManager.object_type, loc); if (left == null){ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r); return null; } - Arguments = new ArrayList (); - Arguments.Add (new Argument (left, Argument.AType.Expression)); - Arguments.Add (new Argument (right, Argument.AType.Expression)); + ArrayList args = new ArrayList (2); + args.Add (new Argument (left, Argument.AType.Expression)); + args.Add (new Argument (right, Argument.AType.Expression)); - type = TypeManager.string_type; - - return this; + return new BinaryMethod (TypeManager.string_type, TypeManager.string_concat_object_object, args); } // @@ -2438,10 +2443,12 @@ namespace Mono.CSharp { if (oper == Operator.Addition || oper == Operator.Subtraction) { if (l.IsSubclassOf (TypeManager.delegate_type) && r.IsSubclassOf (TypeManager.delegate_type)) { + MethodInfo method; + ArrayList args = new ArrayList (2); - Arguments = new ArrayList (); - Arguments.Add (new Argument (left, Argument.AType.Expression)); - Arguments.Add (new Argument (right, Argument.AType.Expression)); + args = new ArrayList (2); + args.Add (new Argument (left, Argument.AType.Expression)); + args.Add (new Argument (right, Argument.AType.Expression)); if (oper == Operator.Addition) method = TypeManager.delegate_combine_delegate_delegate; @@ -2453,9 +2460,7 @@ namespace Mono.CSharp { return null; } - DelegateOperation = true; - type = l; - return this; + return new BinaryDelegate (l, method, args); } // @@ -2669,7 +2674,18 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - left = left.Resolve (ec); + if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) { + left = ((ParenthesizedExpression) left).Expr; + left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type); + if (left == null) + return null; + + if (left.eclass == ExprClass.Type) { + Error (75, "Casting a negative value needs to have the value in parentheses."); + return null; + } + } else + left = left.Resolve (ec); right = right.Resolve (ec); if (left == null || right == null) @@ -2700,9 +2716,6 @@ namespace Mono.CSharp { /// public bool EmitBranchable (EmitContext ec, Label target, bool onTrue) { - if (method != null) - return false; - ILGenerator ig = ec.ig; // @@ -2928,24 +2941,6 @@ namespace Mono.CSharp { Type r = right.Type; OpCode opcode; - if (method != null) { - - // Note that operators are static anyway - - if (Arguments != null) - Invocation.EmitArguments (ec, method, Arguments); - - if (method is MethodInfo) - ig.Emit (OpCodes.Call, (MethodInfo) method); - else - ig.Emit (OpCodes.Call, (ConstructorInfo) method); - - if (DelegateOperation) - ig.Emit (OpCodes.Castclass, type); - - return; - } - // // Handle short-circuit operators differently // than the rest @@ -3139,14 +3134,87 @@ namespace Mono.CSharp { ig.Emit (opcode); } + } + + // + // Object created by Binary when the binary operator uses an method instead of being + // a binary operation that maps to a CIL binary operation. + // + public class BinaryMethod : Expression { + public MethodBase method; + public ArrayList Arguments; + + public BinaryMethod (Type t, MethodBase m, ArrayList args) + { + method = m; + Arguments = args; + type = t; + eclass = ExprClass.Value; + } + + public override Expression DoResolve (EmitContext ec) + { + return this; + } + + public override void Emit (EmitContext ec) + { + ILGenerator ig = ec.ig; + + if (Arguments != null) + Invocation.EmitArguments (ec, method, Arguments); + + if (method is MethodInfo) + ig.Emit (OpCodes.Call, (MethodInfo) method); + else + ig.Emit (OpCodes.Call, (ConstructorInfo) method); + } + } + + // + // Object created with +/= on delegates + // + public class BinaryDelegate : Expression { + MethodInfo method; + ArrayList args; + + public BinaryDelegate (Type t, MethodInfo mi, ArrayList args) + { + method = mi; + this.args = args; + type = t; + eclass = ExprClass.Value; + } + + public override Expression DoResolve (EmitContext ec) + { + return this; + } - public bool IsBuiltinOperator { + public override void Emit (EmitContext ec) + { + ILGenerator ig = ec.ig; + + Invocation.EmitArguments (ec, method, args); + + ig.Emit (OpCodes.Call, (MethodInfo) method); + ig.Emit (OpCodes.Castclass, type); + } + + public Expression Right { get { - return method == null; + Argument arg = (Argument) args [1]; + return arg.Expr; } } - } + public bool IsAddition { + get { + return method == TypeManager.delegate_combine_delegate_delegate; + } + } + } + // // User-defined conditional logical operator public class ConditionalLogicalOperator : Expression { @@ -3493,6 +3561,9 @@ namespace Mono.CSharp { if ((variable_info != null) && !variable_info.IsAssigned (ec, loc)) return null; + if (local_info.LocalBuilder == null) + return ec.RemapLocal (local_info); + return this; } @@ -3512,6 +3583,9 @@ namespace Mono.CSharp { Error (1604, "cannot assign to `" + Name + "' because it is readonly"); return null; } + + if (local_info.LocalBuilder == null) + return ec.RemapLocalLValue (local_info, right_side); return this; } @@ -3525,13 +3599,7 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - if (local_info.LocalBuilder == null){ - ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder); - } else - ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder); - - local_info.Used = true; + ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder); } public void EmitAssign (EmitContext ec, Expression source) @@ -3540,25 +3608,15 @@ namespace Mono.CSharp { local_info.Assigned = true; - if (local_info.LocalBuilder == null){ - ig.Emit (OpCodes.Ldarg_0); - source.Emit (ec); - ig.Emit (OpCodes.Stfld, local_info.FieldBuilder); - } else { - source.Emit (ec); - ig.Emit (OpCodes.Stloc, local_info.LocalBuilder); - } + source.Emit (ec); + ig.Emit (OpCodes.Stloc, local_info.LocalBuilder); } public void AddressOf (EmitContext ec, AddressOp mode) { ILGenerator ig = ec.ig; - if (local_info.LocalBuilder == null){ - ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder); - } else - ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder); + ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder); } public override string ToString () @@ -3663,6 +3721,9 @@ namespace Mono.CSharp { if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc)) return null; + if (ec.RemapToProxy) + return ec.RemapParameter (idx); + return this; } @@ -3672,6 +3733,9 @@ namespace Mono.CSharp { SetAssigned (ec); + if (ec.RemapToProxy) + return ec.RemapParameterLValue (idx, right_side); + return this; } @@ -3710,12 +3774,6 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - if (ec.RemapToProxy){ - ig.Emit (OpCodes.Ldarg_0); - ec.EmitArgument (idx); - return; - } - int arg_idx = idx; if (!ec.IsStatic) @@ -3737,13 +3795,6 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - if (ec.RemapToProxy){ - ig.Emit (OpCodes.Ldarg_0); - source.Emit (ec); - ec.EmitStoreArgument (idx); - return; - } - int arg_idx = idx; if (!ec.IsStatic) @@ -3766,11 +3817,6 @@ namespace Mono.CSharp { public void AddressOf (EmitContext ec, AddressOp mode) { - if (ec.RemapToProxy){ - Report.Error (-1, "Report this: Taking the address of a remapped parameter not supported"); - return; - } - int arg_idx = idx; if (!ec.IsStatic) @@ -3986,9 +4032,10 @@ namespace Mono.CSharp { } /// - /// Determines "better conversion" as specified in 7.4.2.3 - /// Returns : 1 if a->p is better - /// 0 if a->q or neither is better + /// Determines "better conversion" as specified in 7.4.2.3 + /// + /// Returns : 1 if a->p is better + /// 0 if a->q or neither is better /// static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc) { @@ -3996,15 +4043,20 @@ namespace Mono.CSharp { Expression argument_expr = a.Expr; if (argument_type == null) - throw new Exception ("Expression of type " + a.Expr + " does not resolve its type"); + throw new Exception ("Expression of type " + a.Expr + + " does not resolve its type"); // // This is a special case since csc behaves this way. I can't find // it anywhere in the spec but oh well ... // - if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type) + if (argument_expr is NullLiteral && + p == TypeManager.string_type && + q == TypeManager.object_type) return 1; - else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type) + else if (argument_expr is NullLiteral && + p == TypeManager.object_type && + q == TypeManager.string_type) return 0; if (p == q) @@ -4125,16 +4177,18 @@ namespace Mono.CSharp { } /// - /// Determines "Better function" + /// Determines "Better function" between candidate + /// and the current best match /// /// - /// and returns an integer indicating : - /// 0 if candidate ain't better - /// 1 if candidate is better than the current best match + /// Returns an integer indicating : + /// 0 if candidate ain't better + /// 1 if candidate is better than the current best match /// static int BetterFunction (EmitContext ec, ArrayList args, - MethodBase candidate, MethodBase best, - bool expanded_form, Location loc) + MethodBase candidate, bool candidate_params, + MethodBase best, bool best_params, + Location loc) { ParameterData candidate_pd = GetParameterData (candidate); ParameterData best_pd; @@ -4153,7 +4207,7 @@ namespace Mono.CSharp { if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS) if (cand_count != argument_count) return 0; - + if (best == null) { int x = 0; @@ -4161,14 +4215,13 @@ namespace Mono.CSharp { candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS) return 1; - for (int j = argument_count; j > 0;) { - j--; + for (int j = 0; j < argument_count; ++j) { Argument a = (Argument) args [j]; Type t = candidate_pd.ParameterType (j); if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS) - if (expanded_form) + if (candidate_params) t = TypeManager.GetElementType (t); x = BetterConversion (ec, a, t, null, loc); @@ -4196,13 +4249,13 @@ namespace Mono.CSharp { Type bt = best_pd.ParameterType (j); if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS) - if (expanded_form) + if (candidate_params) ct = TypeManager.GetElementType (ct); if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS) - if (expanded_form) + if (best_params) bt = TypeManager.GetElementType (bt); - + x = BetterConversion (ec, a, ct, bt, loc); y = BetterConversion (ec, a, bt, ct, loc); @@ -4213,6 +4266,16 @@ namespace Mono.CSharp { rating2 += y; } + // + // If a method (in the normal form) with the + // same signature as the expanded form of the + // current best params method already exists, + // the expanded form is not applicable so we + // force it to select the candidate + // + if (!candidate_params && best_params && cand_count == argument_count) + return 1; + if (rating1 > rating2) return 1; else @@ -4254,7 +4317,7 @@ namespace Mono.CSharp { MemberInfo [] miset; MethodGroupExpr union; - if (mg1 == null){ + if (mg1 == null) { if (mg2 == null) return null; return (MethodGroupExpr) mg2; @@ -4274,33 +4337,29 @@ namespace Mono.CSharp { ArrayList common = new ArrayList (); - foreach (MethodBase l in left_set.Methods){ - foreach (MethodBase r in right_set.Methods){ - if (l != r) - continue; + foreach (MethodBase r in right_set.Methods){ + if (TypeManager.ArrayContainsMethod (left_set.Methods, r)) common.Add (r); - break; - } } - + miset = new MemberInfo [length1 + length2 - common.Count]; left_set.Methods.CopyTo (miset, 0); int k = length1; - foreach (MemberInfo mi in right_set.Methods){ - if (!common.Contains (mi)) - miset [k++] = mi; + foreach (MethodBase r in right_set.Methods) { + if (!common.Contains (r)) + miset [k++] = r; } - + union = new MethodGroupExpr (miset, loc); return union; } /// - /// Determines is the candidate method, if a params method, is applicable - /// in its expanded form to the given set of arguments + /// Determines if the candidate method, if a params method, is applicable + /// in its expanded form to the given set of arguments /// static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate) { @@ -4328,8 +4387,9 @@ namespace Mono.CSharp { return true; // - // If we have come this far, the case which remains is when the number of parameters - // is less than or equal to the argument count. + // If we have come this far, the case which + // remains is when the number of parameters is + // less than or equal to the argument count. // for (int i = 0; i < pd_count - 1; ++i) { @@ -4343,7 +4403,9 @@ namespace Mono.CSharp { if (a_mod == p_mod) { if (a_mod == Parameter.Modifier.NONE) - if (!Convert.ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i))) + if (!Convert.ImplicitConversionExists (ec, + a.Expr, + pd.ParameterType (i))) return false; if ((a_mod & Parameter.Modifier.ISBYREF) != 0) { @@ -4365,7 +4427,7 @@ namespace Mono.CSharp { for (int i = pd_count - 1; i < arg_count; i++) { Argument a = (Argument) arguments [i]; - if (!Convert.ImplicitStandardConversionExists (a.Expr, element_type)) + if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type)) return false; } @@ -4373,8 +4435,8 @@ namespace Mono.CSharp { } /// - /// Determines if the candidate method is applicable (section 14.4.2.1) - /// to the given set of arguments + /// Determines if the candidate method is applicable (section 14.4.2.1) + /// to the given set of arguments /// static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate) { @@ -4407,8 +4469,9 @@ namespace Mono.CSharp { if (a_mod == p_mod || (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) { if (a_mod == Parameter.Modifier.NONE) { - if (!Convert.ImplicitConversionExists (ec, - a.Expr, pd.ParameterType (i))) + if (!Convert.ImplicitConversionExists (ec, + a.Expr, + pd.ParameterType (i))) return false; } @@ -4417,7 +4480,7 @@ namespace Mono.CSharp { if (!pt.IsByRef) pt = TypeManager.GetReferenceType (pt); - + if (pt != a.Type) return false; } @@ -4455,9 +4518,15 @@ namespace Mono.CSharp { ArrayList candidates = new ArrayList (); // - // First we construct the set of applicable methods + // Used to keep a map between the candidate + // and whether it is being considered in its + // normal or expanded form // + Hashtable candidate_to_form = new PtrHashtable (); + + // + // First we construct the set of applicable methods // // We start at the top of the type hierarchy and // go down to find applicable methods @@ -4469,7 +4538,6 @@ namespace Mono.CSharp { return null; } - bool found_applicable = false; foreach (MethodBase candidate in me.Methods) { Type decl_type = candidate.DeclaringType; @@ -4486,59 +4554,48 @@ namespace Mono.CSharp { // Check if candidate is applicable (section 14.4.2.1) - if (!IsApplicable (ec, Arguments, candidate)) - continue; - - - candidates.Add (candidate); - applicable_type = candidate.DeclaringType; - found_applicable = true; - + if (!IsApplicable (ec, Arguments, candidate)) { + // Candidate is applicable in normal form + candidates.Add (candidate); + applicable_type = candidate.DeclaringType; + found_applicable = true; + candidate_to_form [candidate] = false; + } else { + if (IsParamsMethodApplicable (ec, Arguments, candidate)) { + // Candidate is applicable in expanded form + candidates.Add (candidate); + applicable_type = candidate.DeclaringType; + found_applicable = true; + candidate_to_form [candidate] = true; + } + } } - // // Now we actually find the best method // foreach (MethodBase candidate in candidates) { - int x = BetterFunction (ec, Arguments, candidate, method, false, loc); + bool cand_params = (bool) candidate_to_form [candidate]; + bool method_params = false; + + if (method != null) + method_params = (bool) candidate_to_form [method]; + int x = BetterFunction (ec, Arguments, + candidate, cand_params, + method, method_params, + loc); if (x == 0) continue; method = candidate; } - if (Arguments == null) argument_count = 0; else argument_count = Arguments.Count; - // - // Now we see if we can find params functions, - // applicable in their expanded form since if - // they were applicable in their normal form, - // they would have been selected above anyways - // - bool chose_params_expanded = false; - - if (method == null) { - candidates = new ArrayList (); - foreach (MethodBase candidate in me.Methods){ - if (!IsParamsMethodApplicable (ec, Arguments, candidate)) - continue; - - candidates.Add (candidate); - - int x = BetterFunction (ec, Arguments, candidate, method, true, loc); - if (x == 0) - continue; - - method = candidate; - chose_params_expanded = true; - } - } if (method == null) { // @@ -4555,6 +4612,7 @@ namespace Mono.CSharp { VerifyArgumentsCompat (ec, Arguments, argument_count, c, false, null, loc); + break; } if (!Location.IsNull (loc)) { @@ -4572,11 +4630,13 @@ namespace Mono.CSharp { // Now check that there are no ambiguities i.e the selected method // should be better than all the others // + bool best_params = (bool) candidate_to_form [method]; foreach (MethodBase candidate in candidates){ - if (candidate == method) - continue; + if (candidate == method) + continue; + // // If a normal method is applicable in // the sense that it has the same @@ -4585,13 +4645,15 @@ namespace Mono.CSharp { // applicable so we debar the params // method. // - - if (IsParamsMethodApplicable (ec, Arguments, candidate) && - IsApplicable (ec, Arguments, method)) - continue; - - int x = BetterFunction (ec, Arguments, method, candidate, - chose_params_expanded, loc); + if ((IsParamsMethodApplicable (ec, Arguments, candidate) && + IsApplicable (ec, Arguments, method))) + continue; + + bool cand_params = (bool) candidate_to_form [candidate]; + int x = BetterFunction (ec, Arguments, + method, best_params, + candidate, cand_params, + loc); if (x != 1) { Report.Error ( @@ -4607,9 +4669,8 @@ namespace Mono.CSharp { // necessary etc. and return if everything is // all right // - - if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method, - chose_params_expanded, null, loc)) + if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method, + best_params, null, loc)) return null; return method; @@ -4723,9 +4784,6 @@ namespace Mono.CSharp { if (a_mod != p_mod && pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) { if (!Location.IsNull (loc)) { - Console.WriteLine ("A:P: " + a.GetParameterModifier ()); - Console.WriteLine ("PP:: " + pd.ParameterModifier (j)); - Console.WriteLine ("PT: " + parameter_type.IsByRef); Report.Error (1502, loc, "The best overloaded match for method '" + FullMethodDesc (method)+ "' has some invalid arguments"); @@ -6321,6 +6379,29 @@ namespace Mono.CSharp { } } + // + // This produces the value that renders an instance, used by the iterators code + // + public class ProxyInstance : Expression, IMemoryLocation { + public override Expression DoResolve (EmitContext ec) + { + eclass = ExprClass.Variable; + type = ec.ContainerType; + return this; + } + + public override void Emit (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldarg_0); + + } + + public void AddressOf (EmitContext ec, AddressOp mode) + { + ec.ig.Emit (OpCodes.Ldarg_0); + } + } + /// /// Implements the typeof operator /// diff --git a/mcs/gmcs/iterators.cs b/mcs/gmcs/iterators.cs index bed88521116..10be47f48a5 100644 --- a/mcs/gmcs/iterators.cs +++ b/mcs/gmcs/iterators.cs @@ -96,8 +96,8 @@ namespace Mono.CSharp { if (!Yield.CheckContext (ec, loc)) return false; - ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS; - ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS; + ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Always; + ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Always; return true; } @@ -255,9 +255,13 @@ namespace Mono.CSharp { // Invoked when a local variable declaration needs to be mapped to // a field in our proxy class // - public FieldBuilder MapVariable (string name, Type t) + // Prefixes registered: + // v_ for EmitContext.MapVariable + // s_ for Storage + // + public FieldBuilder MapVariable (string pfx, string name, Type t) { - return enumerator_proxy_class.DefineField ("v" + name, t, FieldAttributes.Public); + return enumerator_proxy_class.DefineField (pfx + name, t, FieldAttributes.Public); } void Create_Reset () diff --git a/mcs/gmcs/namespace.cs b/mcs/gmcs/namespace.cs index f4ff2280c32..83731a82e56 100755 --- a/mcs/gmcs/namespace.cs +++ b/mcs/gmcs/namespace.cs @@ -201,11 +201,11 @@ namespace Mono.CSharp { public class AliasEntry { public readonly string Name; - public readonly string Alias; + public readonly Expression Alias; public readonly NamespaceEntry NamespaceEntry; public readonly Location Location; - public AliasEntry (NamespaceEntry entry, string name, string alias, Location loc) + public AliasEntry (NamespaceEntry entry, string name, Expression alias, Location loc) { Name = name; Alias = alias; @@ -221,8 +221,15 @@ namespace Mono.CSharp { return resolved; NamespaceEntry curr_ns = NamespaceEntry; + + // + // GENERICS: Cope with the expression and not with the string + // this will fail with `using A = Stack' + // + + string alias = Alias.ToString (); while ((curr_ns != null) && (resolved == null)) { - resolved = curr_ns.Lookup (null, Alias, Location); + resolved = curr_ns.Lookup (null, alias, Location); if (resolved == null) curr_ns = curr_ns.Parent; @@ -313,7 +320,7 @@ namespace Mono.CSharp { using_clauses.Add (ue); } - public void UsingAlias (string alias, string namespace_or_type, Location loc) + public void UsingAlias (string alias, Expression namespace_or_type, Location loc) { if (aliases == null) aliases = new Hashtable (); @@ -542,7 +549,7 @@ namespace Mono.CSharp { if (alias.Resolve () != null) continue; - error246 (alias.Location, alias.Alias); + error246 (alias.Location, alias.Alias.ToString ()); } } } diff --git a/mcs/gmcs/statement.cs b/mcs/gmcs/statement.cs index 36ab0e9a37a..8727b71ac32 100755 --- a/mcs/gmcs/statement.cs +++ b/mcs/gmcs/statement.cs @@ -139,14 +139,14 @@ namespace Mono.CSharp { return false; } - ec.StartFlowBranching (FlowBranchingType.BLOCK, loc); + ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc); if (!TrueStatement.Resolve (ec)) { ec.KillFlowBranching (); return false; } - ec.CurrentBranching.CreateSibling (); + ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional); if ((FalseStatement != null) && !FalseStatement.Resolve (ec)) { ec.KillFlowBranching (); @@ -229,7 +229,7 @@ namespace Mono.CSharp { { bool ok = true; - ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc); + ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc); if (!EmbeddedStatement.Resolve (ec)) ok = false; @@ -245,8 +245,8 @@ namespace Mono.CSharp { } ec.CurrentBranching.Infinite = infinite; - FlowReturns returns = ec.EndFlowBranching (); - may_return = returns != FlowReturns.NEVER; + FlowBranching.FlowReturns returns = ec.EndFlowBranching (); + may_return = returns != FlowBranching.FlowReturns.Never; return ok; } @@ -314,7 +314,7 @@ namespace Mono.CSharp { if (expr == null) return false; - ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc); + ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc); // // Inform whether we are infinite or not @@ -331,7 +331,7 @@ namespace Mono.CSharp { // // We are not infinite, so the loop may or may not be executed. // - ec.CurrentBranching.CreateSibling (); + ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional); } if (!Statement.Resolve (ec)) @@ -341,8 +341,8 @@ namespace Mono.CSharp { ec.KillFlowBranching (); else { ec.CurrentBranching.Infinite = infinite; - FlowReturns returns = ec.EndFlowBranching (); - may_return = returns != FlowReturns.NEVER; + FlowBranching.FlowReturns returns = ec.EndFlowBranching (); + may_return = returns != FlowBranching.FlowReturns.Never; } return ok; @@ -451,9 +451,9 @@ namespace Mono.CSharp { } else infinite = true; - ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc); + ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc); if (!infinite) - ec.CurrentBranching.CreateSibling (); + ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional); if (!Statement.Resolve (ec)) ok = false; @@ -467,8 +467,8 @@ namespace Mono.CSharp { ec.KillFlowBranching (); else { ec.CurrentBranching.Infinite = infinite; - FlowReturns returns = ec.EndFlowBranching (); - may_return = returns != FlowReturns.NEVER; + FlowBranching.FlowReturns returns = ec.EndFlowBranching (); + may_return = returns != FlowBranching.FlowReturns.Never; } return ok; @@ -605,8 +605,8 @@ namespace Mono.CSharp { else vector.CheckOutParameters (ec.CurrentBranching); - vector.Returns = FlowReturns.ALWAYS; - vector.Breaks = FlowReturns.ALWAYS; + vector.Returns = FlowBranching.FlowReturns.Always; + vector.Breaks = FlowBranching.FlowReturns.Always; return true; } @@ -677,8 +677,8 @@ namespace Mono.CSharp { if (!label.IsDefined) label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector); - ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS; - ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS; + ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Always; + ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Always; return true; } @@ -755,8 +755,8 @@ namespace Mono.CSharp { if (vectors != null) ec.CurrentBranching.CurrentUsageVector.MergeJumpOrigins (vectors); else { - ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.NEVER; - ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.NEVER; + ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Never; + ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Never; } referenced = true; @@ -786,8 +786,8 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS; - ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS; + ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Always; + ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Always; return true; } @@ -853,8 +853,8 @@ namespace Mono.CSharp { label = sl.ILLabelCode; - ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.UNREACHABLE; - ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS; + ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Unreachable; + ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Always; return true; } @@ -901,8 +901,8 @@ namespace Mono.CSharp { } } - ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.EXCEPTION; - ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.EXCEPTION; + ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Exception; + ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Exception; return true; } @@ -938,7 +938,7 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { ec.CurrentBranching.MayLeaveLoop = true; - ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS; + ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Always; return true; } @@ -969,7 +969,7 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS; + ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Always; return true; } @@ -1003,1749 +1003,6 @@ namespace Mono.CSharp { } } - // - // This is used in the control flow analysis code to specify whether the - // current code block may return to its enclosing block before reaching - // its end. - // - public enum FlowReturns { - // It can never return. - NEVER, - - // This means that the block contains a conditional return statement - // somewhere. - SOMETIMES, - - // The code always returns, ie. there's an unconditional return / break - // statement in it. - ALWAYS, - - // The code always throws an exception. - EXCEPTION, - - // The current code block is unreachable. This happens if it's immediately - // following a FlowReturns.ALWAYS block. - UNREACHABLE - } - - // - // This is a special bit vector which can inherit from another bit vector doing a - // copy-on-write strategy. The inherited vector may have a smaller size than the - // current one. - // - public class MyBitVector { - public readonly int Count; - public readonly MyBitVector InheritsFrom; - - bool is_dirty; - BitArray vector; - - public MyBitVector (int Count) - : this (null, Count) - { } - - public MyBitVector (MyBitVector InheritsFrom, int Count) - { - this.InheritsFrom = InheritsFrom; - this.Count = Count; - } - - // - // Checks whether this bit vector has been modified. After setting this to true, - // we won't use the inherited vector anymore, but our own copy of it. - // - public bool IsDirty { - get { - return is_dirty; - } - - set { - if (!is_dirty) - initialize_vector (); - } - } - - // - // Get/set bit `index' in the bit vector. - // - public bool this [int index] - { - get { - if (index > Count) - throw new ArgumentOutOfRangeException (); - - // We're doing a "copy-on-write" strategy here; as long - // as nobody writes to the array, we can use our parent's - // copy instead of duplicating the vector. - - if (vector != null) - return vector [index]; - else if (InheritsFrom != null) { - BitArray inherited = InheritsFrom.Vector; - - if (index < inherited.Count) - return inherited [index]; - else - return false; - } else - return false; - } - - set { - if (index > Count) - throw new ArgumentOutOfRangeException (); - - // Only copy the vector if we're actually modifying it. - - if (this [index] != value) { - initialize_vector (); - - vector [index] = value; - } - } - } - - // - // If you explicitly convert the MyBitVector to a BitArray, you will get a deep - // copy of the bit vector. - // - public static explicit operator BitArray (MyBitVector vector) - { - vector.initialize_vector (); - return vector.Vector; - } - - // - // Performs an `or' operation on the bit vector. The `new_vector' may have a - // different size than the current one. - // - public void Or (MyBitVector new_vector) - { - BitArray new_array = new_vector.Vector; - - initialize_vector (); - - int upper; - if (vector.Count < new_array.Count) - upper = vector.Count; - else - upper = new_array.Count; - - for (int i = 0; i < upper; i++) - vector [i] = vector [i] | new_array [i]; - } - - // - // Perfonrms an `and' operation on the bit vector. The `new_vector' may have - // a different size than the current one. - // - public void And (MyBitVector new_vector) - { - BitArray new_array = new_vector.Vector; - - initialize_vector (); - - int lower, upper; - if (vector.Count < new_array.Count) - lower = upper = vector.Count; - else { - lower = new_array.Count; - upper = vector.Count; - } - - for (int i = 0; i < lower; i++) - vector [i] = vector [i] & new_array [i]; - - for (int i = lower; i < upper; i++) - vector [i] = false; - } - - // - // This does a deep copy of the bit vector. - // - public MyBitVector Clone () - { - MyBitVector retval = new MyBitVector (Count); - - retval.Vector = Vector; - - return retval; - } - - BitArray Vector { - get { - if (vector != null) - return vector; - else if (!is_dirty && (InheritsFrom != null)) - return InheritsFrom.Vector; - - initialize_vector (); - - return vector; - } - - set { - initialize_vector (); - - for (int i = 0; i < System.Math.Min (vector.Count, value.Count); i++) - vector [i] = value [i]; - } - } - - void initialize_vector () - { - if (vector != null) - return; - - vector = new BitArray (Count, false); - if (InheritsFrom != null) - Vector = InheritsFrom.Vector; - - is_dirty = true; - } - - public override string ToString () - { - StringBuilder sb = new StringBuilder ("MyBitVector ("); - - BitArray vector = Vector; - sb.Append (Count); - sb.Append (","); - if (!IsDirty) - sb.Append ("INHERITED - "); - for (int i = 0; i < vector.Count; i++) { - if (i > 0) - sb.Append (","); - sb.Append (vector [i]); - } - - sb.Append (")"); - return sb.ToString (); - } - } - - // - // The type of a FlowBranching. - // - public enum FlowBranchingType { - // Normal (conditional or toplevel) block. - BLOCK, - - // A loop block. - LOOP_BLOCK, - - // Try/Catch block. - EXCEPTION, - - // Switch block. - SWITCH, - - // Switch section. - SWITCH_SECTION - } - - // - // A new instance of this class is created every time a new block is resolved - // and if there's branching in the block's control flow. - // - public class FlowBranching { - // - // The type of this flow branching. - // - public readonly FlowBranchingType Type; - - // - // The block this branching is contained in. This may be null if it's not - // a top-level block and it doesn't declare any local variables. - // - public readonly Block Block; - - // - // The parent of this branching or null if this is the top-block. - // - public readonly FlowBranching Parent; - - // - // Start-Location of this flow branching. - // - public readonly Location Location; - - // - // A list of UsageVectors. A new vector is added each time control flow may - // take a different path. - // - public UsageVector[] Siblings; - - // - // If this is an infinite loop. - // - public bool Infinite; - - // - // If we may leave the current loop. - // - public bool MayLeaveLoop; - - // - // Private - // - VariableMap param_map, local_map; - ArrayList finally_vectors; - - static int next_id = 0; - int id; - - // - // Performs an `And' operation on the FlowReturns status - // (for instance, a block only returns ALWAYS if all its siblings - // always return). - // - public static FlowReturns AndFlowReturns (FlowReturns a, FlowReturns b) - { - if (b == FlowReturns.UNREACHABLE) - return a; - - switch (a) { - case FlowReturns.NEVER: - if (b == FlowReturns.NEVER) - return FlowReturns.NEVER; - else - return FlowReturns.SOMETIMES; - - case FlowReturns.SOMETIMES: - return FlowReturns.SOMETIMES; - - case FlowReturns.ALWAYS: - if ((b == FlowReturns.ALWAYS) || (b == FlowReturns.EXCEPTION)) - return FlowReturns.ALWAYS; - else - return FlowReturns.SOMETIMES; - - case FlowReturns.EXCEPTION: - if (b == FlowReturns.EXCEPTION) - return FlowReturns.EXCEPTION; - else if (b == FlowReturns.ALWAYS) - return FlowReturns.ALWAYS; - else - return FlowReturns.SOMETIMES; - } - - return b; - } - - // - // The vector contains a BitArray with information about which local variables - // and parameters are already initialized at the current code position. - // - public class UsageVector { - // - // If this is true, then the usage vector has been modified and must be - // merged when we're done with this branching. - // - public bool IsDirty; - - // - // The number of parameters in this block. - // - public readonly int CountParameters; - - // - // The number of locals in this block. - // - public readonly int CountLocals; - - // - // If not null, then we inherit our state from this vector and do a - // copy-on-write. If null, then we're the first sibling in a top-level - // block and inherit from the empty vector. - // - public readonly UsageVector InheritsFrom; - - // - // Private. - // - MyBitVector locals, parameters; - FlowReturns real_returns, real_breaks; - bool is_finally; - - static int next_id = 0; - int id; - - // - // Normally, you should not use any of these constructors. - // - public UsageVector (UsageVector parent, int num_params, int num_locals) - { - this.InheritsFrom = parent; - this.CountParameters = num_params; - this.CountLocals = num_locals; - this.real_returns = FlowReturns.NEVER; - this.real_breaks = FlowReturns.NEVER; - - if (parent != null) { - locals = new MyBitVector (parent.locals, CountLocals); - if (num_params > 0) - parameters = new MyBitVector (parent.parameters, num_params); - real_returns = parent.Returns; - real_breaks = parent.Breaks; - } else { - locals = new MyBitVector (null, CountLocals); - if (num_params > 0) - parameters = new MyBitVector (null, num_params); - } - - id = ++next_id; - } - - public UsageVector (UsageVector parent) - : this (parent, parent.CountParameters, parent.CountLocals) - { } - - // - // This does a deep copy of the usage vector. - // - public UsageVector Clone () - { - UsageVector retval = new UsageVector (null, CountParameters, CountLocals); - - retval.locals = locals.Clone (); - if (parameters != null) - retval.parameters = parameters.Clone (); - retval.real_returns = real_returns; - retval.real_breaks = real_breaks; - - return retval; - } - - public bool IsAssigned (VariableInfo var) - { - if (!var.IsParameter && AlwaysBreaks) - return true; - - return var.IsAssigned (var.IsParameter ? parameters : locals); - } - - public void SetAssigned (VariableInfo var) - { - if (!var.IsParameter && AlwaysBreaks) - return; - - var.SetAssigned (var.IsParameter ? parameters : locals); - } - - public bool IsFieldAssigned (VariableInfo var, string name) - { - if (!var.IsParameter && AlwaysBreaks) - return true; - - return var.IsFieldAssigned (var.IsParameter ? parameters : locals, name); - } - - public void SetFieldAssigned (VariableInfo var, string name) - { - if (!var.IsParameter && AlwaysBreaks) - return; - - var.SetFieldAssigned (var.IsParameter ? parameters : locals, name); - } - - // - // Specifies when the current block returns. - // If this is FlowReturns.UNREACHABLE, then control can never reach the - // end of the method (so that we don't need to emit a return statement). - // The same applies for FlowReturns.EXCEPTION, but in this case the return - // value will never be used. - // - public FlowReturns Returns { - get { - return real_returns; - } - - set { - real_returns = value; - } - } - - // - // Specifies whether control may return to our containing block - // before reaching the end of this block. This happens if there - // is a break/continue/goto/return in it. - // This can also be used to find out whether the statement immediately - // following the current block may be reached or not. - // - public FlowReturns Breaks { - get { - return real_breaks; - } - - set { - real_breaks = value; - } - } - - public bool AlwaysBreaks { - get { - return (Breaks == FlowReturns.ALWAYS) || - (Breaks == FlowReturns.EXCEPTION) || - (Breaks == FlowReturns.UNREACHABLE); - } - } - - public bool MayBreak { - get { - return Breaks != FlowReturns.NEVER; - } - } - - public bool AlwaysReturns { - get { - return (Returns == FlowReturns.ALWAYS) || - (Returns == FlowReturns.EXCEPTION); - } - } - - public bool MayReturn { - get { - return (Returns == FlowReturns.SOMETIMES) || - (Returns == FlowReturns.ALWAYS); - } - } - - // - // Merge a child branching. - // - public FlowReturns MergeChildren (FlowBranching branching, UsageVector[] children) - { - MyBitVector new_locals = null; - MyBitVector new_params = null; - - FlowReturns new_returns = FlowReturns.NEVER; - FlowReturns new_breaks = FlowReturns.NEVER; - bool new_returns_set = false, new_breaks_set = false; - - Report.Debug (2, "MERGING CHILDREN", branching, branching.Type, - this, children.Length); - - foreach (UsageVector child in children) { - Report.Debug (2, " MERGING CHILD", child, child.is_finally); - - if (!child.is_finally) { - if (child.Breaks != FlowReturns.UNREACHABLE) { - // If Returns is already set, perform an - // `And' operation on it, otherwise just set just. - if (!new_returns_set) { - new_returns = child.Returns; - new_returns_set = true; - } else - new_returns = AndFlowReturns ( - new_returns, child.Returns); - } - - // If Breaks is already set, perform an - // `And' operation on it, otherwise just set just. - if (!new_breaks_set) { - new_breaks = child.Breaks; - new_breaks_set = true; - } else - new_breaks = AndFlowReturns ( - new_breaks, child.Breaks); - } - - // Ignore unreachable children. - if (child.Returns == FlowReturns.UNREACHABLE) - continue; - - // A local variable is initialized after a flow branching if it - // has been initialized in all its branches which do neither - // always return or always throw an exception. - // - // If a branch may return, but does not always return, then we - // can treat it like a never-returning branch here: control will - // only reach the code position after the branching if we did not - // return here. - // - // It's important to distinguish between always and sometimes - // returning branches here: - // - // 1 int a; - // 2 if (something) { - // 3 return; - // 4 a = 5; - // 5 } - // 6 Console.WriteLine (a); - // - // The if block in lines 3-4 always returns, so we must not look - // at the initialization of `a' in line 4 - thus it'll still be - // uninitialized in line 6. - // - // On the other hand, the following is allowed: - // - // 1 int a; - // 2 if (something) - // 3 a = 5; - // 4 else - // 5 return; - // 6 Console.WriteLine (a); - // - // Here, `a' is initialized in line 3 and we must not look at - // line 5 since it always returns. - // - if (child.is_finally) { - if (new_locals == null) - new_locals = locals.Clone (); - new_locals.Or (child.locals); - - if (parameters != null) { - if (new_params == null) - new_params = parameters.Clone (); - new_params.Or (child.parameters); - } - } else { - if (!child.AlwaysReturns && !child.AlwaysBreaks) { - if (new_locals != null) - new_locals.And (child.locals); - else { - new_locals = locals.Clone (); - new_locals.Or (child.locals); - } - } else if (children.Length == 1) { - new_locals = locals.Clone (); - new_locals.Or (child.locals); - } - - // An `out' parameter must be assigned in all branches which do - // not always throw an exception. - if (parameters != null) { - bool and_params = child.Breaks != FlowReturns.EXCEPTION; - if (branching.Type == FlowBranchingType.EXCEPTION) - and_params &= child.Returns != FlowReturns.NEVER; - if (and_params) { - if (new_params != null) - new_params.And (child.parameters); - else { - new_params = parameters.Clone (); - new_params.Or (child.parameters); - } - } else if ((children.Length == 1) || (new_params == null)) { - new_params = parameters.Clone (); - new_params.Or (child.parameters); - } - } - } - } - - Returns = new_returns; - if ((branching.Type == FlowBranchingType.BLOCK) || - (branching.Type == FlowBranchingType.EXCEPTION) || - (new_breaks == FlowReturns.UNREACHABLE) || - (new_breaks == FlowReturns.EXCEPTION)) - Breaks = new_breaks; - else if (branching.Type == FlowBranchingType.SWITCH_SECTION) - Breaks = new_returns; - else if (branching.Type == FlowBranchingType.SWITCH){ - if (new_breaks == FlowReturns.ALWAYS) - Breaks = FlowReturns.ALWAYS; - } - - // - // We've now either reached the point after the branching or we will - // never get there since we always return or always throw an exception. - // - // If we can reach the point after the branching, mark all locals and - // parameters as initialized which have been initialized in all branches - // we need to look at (see above). - // - - if (((new_breaks != FlowReturns.ALWAYS) && - (new_breaks != FlowReturns.EXCEPTION) && - (new_breaks != FlowReturns.UNREACHABLE)) || - (children.Length == 1)) { - if (new_locals != null) - locals.Or (new_locals); - - if (new_params != null) - parameters.Or (new_params); - } - - Report.Debug (2, "MERGING CHILDREN DONE", branching.Type, - new_params, new_locals, new_returns, new_breaks, - branching.Infinite, branching.MayLeaveLoop, this); - - if (branching.Type == FlowBranchingType.SWITCH_SECTION) { - if ((new_breaks != FlowReturns.ALWAYS) && - (new_breaks != FlowReturns.EXCEPTION) && - (new_breaks != FlowReturns.UNREACHABLE)) - Report.Error (163, branching.Location, - "Control cannot fall through from one " + - "case label to another"); - } - - if (branching.Infinite && !branching.MayLeaveLoop) { - Report.Debug (1, "INFINITE", new_returns, new_breaks, - Returns, Breaks, this); - - // We're actually infinite. - if (new_returns == FlowReturns.NEVER) { - Breaks = FlowReturns.UNREACHABLE; - return FlowReturns.UNREACHABLE; - } - - // If we're an infinite loop and do not break, the code after - // the loop can never be reached. However, if we may return - // from the loop, then we do always return (or stay in the loop - // forever). - if ((new_returns == FlowReturns.SOMETIMES) || - (new_returns == FlowReturns.ALWAYS)) { - Returns = FlowReturns.ALWAYS; - return FlowReturns.ALWAYS; - } - } - - if (branching.Type == FlowBranchingType.LOOP_BLOCK) { - Report.Debug (2, "MERGING LOOP BLOCK DONE", branching, - branching.Infinite, branching.MayLeaveLoop, - new_breaks, new_returns); - - // If we may leave the loop, then we do not always return. - if (branching.MayLeaveLoop && (new_returns == FlowReturns.ALWAYS)) { - Returns = FlowReturns.SOMETIMES; - return FlowReturns.SOMETIMES; - } - - // A `break' in a loop does not "break" in the outer block. - Breaks = FlowReturns.NEVER; - } - - return new_returns; - } - - // - // Tells control flow analysis that the current code position may be reached with - // a forward jump from any of the origins listed in `origin_vectors' which is a - // list of UsageVectors. - // - // This is used when resolving forward gotos - in the following example, the - // variable `a' is uninitialized in line 8 becase this line may be reached via - // the goto in line 4: - // - // 1 int a; - // - // 3 if (something) - // 4 goto World; - // - // 6 a = 5; - // - // 7 World: - // 8 Console.WriteLine (a); - // - // - public void MergeJumpOrigins (ICollection origin_vectors) - { - Report.Debug (1, "MERGING JUMP ORIGIN", this); - - real_breaks = FlowReturns.NEVER; - real_returns = FlowReturns.NEVER; - - foreach (UsageVector vector in origin_vectors) { - Report.Debug (1, " MERGING JUMP ORIGIN", vector); - - locals.And (vector.locals); - if (parameters != null) - parameters.And (vector.parameters); - Breaks = AndFlowReturns (Breaks, vector.Breaks); - Returns = AndFlowReturns (Returns, vector.Returns); - } - - Report.Debug (1, "MERGING JUMP ORIGIN DONE", this); - } - - // - // This is used at the beginning of a finally block if there were - // any return statements in the try block or one of the catch blocks. - // - public void MergeFinallyOrigins (ICollection finally_vectors) - { - Report.Debug (1, "MERGING FINALLY ORIGIN", this); - - real_breaks = FlowReturns.NEVER; - - foreach (UsageVector vector in finally_vectors) { - Report.Debug (1, " MERGING FINALLY ORIGIN", vector); - - if (parameters != null) - parameters.And (vector.parameters); - Breaks = AndFlowReturns (Breaks, vector.Breaks); - } - - is_finally = true; - - Report.Debug (1, "MERGING FINALLY ORIGIN DONE", this); - } - - public void CheckOutParameters (FlowBranching branching) - { - if (parameters != null) - branching.CheckOutParameters (parameters, branching.Location); - } - - // - // Performs an `or' operation on the locals and the parameters. - // - public void Or (UsageVector new_vector) - { - locals.Or (new_vector.locals); - if (parameters != null) - parameters.Or (new_vector.parameters); - } - - // - // Performs an `and' operation on the locals. - // - public void AndLocals (UsageVector new_vector) - { - locals.And (new_vector.locals); - } - - // - // Returns a deep copy of the parameters. - // - public MyBitVector Parameters { - get { - if (parameters != null) - return parameters.Clone (); - else - return null; - } - } - - // - // Returns a deep copy of the locals. - // - public MyBitVector Locals { - get { - return locals.Clone (); - } - } - - // - // Debugging stuff. - // - - public override string ToString () - { - StringBuilder sb = new StringBuilder (); - - sb.Append ("Vector ("); - sb.Append (id); - sb.Append (","); - sb.Append (Returns); - sb.Append (","); - sb.Append (Breaks); - if (parameters != null) { - sb.Append (" - "); - sb.Append (parameters); - } - sb.Append (" - "); - sb.Append (locals); - sb.Append (")"); - - return sb.ToString (); - } - } - - FlowBranching (FlowBranchingType type, Location loc) - { - this.Block = null; - this.Location = loc; - this.Type = type; - id = ++next_id; - } - - // - // Creates a new flow branching for `block'. - // This is used from Block.Resolve to create the top-level branching of - // the block. - // - public FlowBranching (Block block, Location loc) - : this (FlowBranchingType.BLOCK, loc) - { - Block = block; - Parent = null; - - param_map = block.ParameterMap; - local_map = block.LocalMap; - - UsageVector vector = new UsageVector (null, param_map.Length, local_map.Length); - - AddSibling (vector); - } - - // - // Creates a new flow branching which is contained in `parent'. - // You should only pass non-null for the `block' argument if this block - // introduces any new variables - in this case, we need to create a new - // usage vector with a different size than our parent's one. - // - public FlowBranching (FlowBranching parent, FlowBranchingType type, - Block block, Location loc) - : this (type, loc) - { - Parent = parent; - Block = block; - - UsageVector vector; - if (Block != null) { - param_map = Block.ParameterMap; - local_map = Block.LocalMap; - - vector = new UsageVector (parent.CurrentUsageVector, param_map.Length, - local_map.Length); - } else { - param_map = Parent.param_map; - local_map = Parent.local_map; - vector = new UsageVector (Parent.CurrentUsageVector); - } - - AddSibling (vector); - - switch (Type) { - case FlowBranchingType.EXCEPTION: - finally_vectors = new ArrayList (); - break; - - default: - break; - } - } - - void AddSibling (UsageVector uv) - { - if (Siblings != null) { - UsageVector[] ns = new UsageVector [Siblings.Length + 1]; - for (int i = 0; i < Siblings.Length; ++i) - ns [i] = Siblings [i]; - Siblings = ns; - } else { - Siblings = new UsageVector [1]; - } - Siblings [Siblings.Length - 1] = uv; - } - - // - // Returns the branching's current usage vector. - // - public UsageVector CurrentUsageVector - { - get { - return Siblings [Siblings.Length - 1]; - } - } - - // - // Creates a sibling of the current usage vector. - // - public void CreateSibling () - { - AddSibling (new UsageVector (Parent.CurrentUsageVector)); - - Report.Debug (1, "CREATED SIBLING", CurrentUsageVector); - } - - // - // Creates a sibling for a `finally' block. - // - public void CreateSiblingForFinally () - { - if (Type != FlowBranchingType.EXCEPTION) - throw new NotSupportedException (); - - CreateSibling (); - - CurrentUsageVector.MergeFinallyOrigins (finally_vectors); - } - - // - // Check whether all `out' parameters have been assigned. - // - public void CheckOutParameters (MyBitVector parameters, Location loc) - { - if (InTryBlock ()) - return; - - for (int i = 0; i < param_map.Count; i++) { - VariableInfo var = param_map [i]; - - if (var == null) - continue; - - if (var.IsAssigned (parameters)) - continue; - - Report.Error (177, loc, "The out parameter `" + - param_map.VariableNames [i] + "' must be " + - "assigned before control leave the current method."); - } - } - - // - // Merge a child branching. - // - public FlowReturns MergeChild (FlowBranching child) - { - FlowReturns returns = CurrentUsageVector.MergeChildren (child, child.Siblings); - - if ((child.Type != FlowBranchingType.LOOP_BLOCK) && - (child.Type != FlowBranchingType.SWITCH_SECTION)) - MayLeaveLoop |= child.MayLeaveLoop; - - return returns; - } - - // - // Does the toplevel merging. - // - public FlowReturns MergeTopBlock () - { - if ((Type != FlowBranchingType.BLOCK) || (Block == null)) - throw new NotSupportedException (); - - UsageVector vector = new UsageVector (null, param_map.Length, local_map.Length); - - Report.Debug (1, "MERGING TOP BLOCK", Location, vector); - - vector.MergeChildren (this, Siblings); - - if (Siblings.Length == 1) - Siblings [0] = vector; - else { - Siblings = null; - AddSibling (vector); - } - - Report.Debug (1, "MERGING TOP BLOCK DONE", Location, vector); - - if (vector.Breaks != FlowReturns.EXCEPTION) { - if (!vector.AlwaysBreaks) - CheckOutParameters (CurrentUsageVector.Parameters, Location); - return vector.AlwaysBreaks ? FlowReturns.ALWAYS : vector.Returns; - } else - return FlowReturns.EXCEPTION; - } - - public bool InTryBlock () - { - if (finally_vectors != null) - return true; - else if (Parent != null) - return Parent.InTryBlock (); - else - return false; - } - - public void AddFinallyVector (UsageVector vector) - { - if (finally_vectors != null) { - finally_vectors.Add (vector.Clone ()); - return; - } - - if (Parent != null) - Parent.AddFinallyVector (vector); - else - throw new NotSupportedException (); - } - - public bool IsAssigned (VariableInfo vi) - { - return CurrentUsageVector.IsAssigned (vi); - } - - public bool IsFieldAssigned (VariableInfo vi, string field_name) - { - if (CurrentUsageVector.IsAssigned (vi)) - return true; - - return CurrentUsageVector.IsFieldAssigned (vi, field_name); - } - - public void SetAssigned (VariableInfo vi) - { - CurrentUsageVector.SetAssigned (vi); - } - - public void SetFieldAssigned (VariableInfo vi, string name) - { - CurrentUsageVector.SetFieldAssigned (vi, name); - } - - public bool IsReachable () - { - bool reachable; - - switch (Type) { - case FlowBranchingType.SWITCH_SECTION: - // The code following a switch block is reachable unless the switch - // block always returns. - reachable = !CurrentUsageVector.AlwaysReturns; - break; - - case FlowBranchingType.LOOP_BLOCK: - // The code following a loop is reachable unless the loop always - // returns or it's an infinite loop without any `break's in it. - reachable = !CurrentUsageVector.AlwaysReturns && - (CurrentUsageVector.Breaks != FlowReturns.UNREACHABLE); - break; - - default: - // The code following a block or exception is reachable unless the - // block either always returns or always breaks. - if (MayLeaveLoop) - reachable = true; - else - reachable = !CurrentUsageVector.AlwaysBreaks && - !CurrentUsageVector.AlwaysReturns; - break; - } - - Report.Debug (1, "REACHABLE", this, Type, CurrentUsageVector.Returns, - CurrentUsageVector.Breaks, CurrentUsageVector, MayLeaveLoop, - reachable); - - return reachable; - } - - public override string ToString () - { - StringBuilder sb = new StringBuilder ("FlowBranching ("); - - sb.Append (id); - sb.Append (","); - sb.Append (Type); - if (Block != null) { - sb.Append (" - "); - sb.Append (Block.ID); - sb.Append (" - "); - sb.Append (Block.StartLocation); - } - sb.Append (" - "); - sb.Append (Siblings.Length); - sb.Append (" - "); - sb.Append (CurrentUsageVector); - sb.Append (")"); - return sb.ToString (); - } - } - - // - // This is used by the flow analysis code to keep track of the type of local variables - // and variables. - // - // The flow code uses a BitVector to keep track of whether a variable has been assigned - // or not. This is easy for fundamental types (int, char etc.) or reference types since - // you can only assign the whole variable as such. - // - // For structs, we also need to keep track of all its fields. To do this, we allocate one - // bit for the struct itself (it's used if you assign/access the whole struct) followed by - // one bit for each of its fields. - // - // This class computes this `layout' for each type. - // - public class TypeInfo - { - public readonly Type Type; - - // - // Total number of bits a variable of this type consumes in the flow vector. - // - public readonly int TotalLength; - - // - // Number of bits the simple fields of a variable of this type consume - // in the flow vector. - // - public readonly int Length; - - // - // This is only used by sub-structs. - // - public readonly int Offset; - - // - // If this is a struct. - // - public readonly bool IsStruct; - - // - // If this is a struct, all fields which are structs theirselves. - // - public TypeInfo[] SubStructInfo; - - protected readonly StructInfo struct_info; - private static Hashtable type_hash = new Hashtable (); - - public static TypeInfo GetTypeInfo (Type type) - { - TypeInfo info = (TypeInfo) type_hash [type]; - if (info != null) - return info; - - info = new TypeInfo (type); - type_hash.Add (type, info); - return info; - } - - public static TypeInfo GetTypeInfo (TypeContainer tc) - { - TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder]; - if (info != null) - return info; - - info = new TypeInfo (tc); - type_hash.Add (tc.TypeBuilder, info); - return info; - } - - private TypeInfo (Type type) - { - this.Type = type; - - struct_info = StructInfo.GetStructInfo (type); - if (struct_info != null) { - Length = struct_info.Length; - TotalLength = struct_info.TotalLength; - SubStructInfo = struct_info.StructFields; - IsStruct = true; - } else { - Length = 0; - TotalLength = 1; - IsStruct = false; - } - } - - private TypeInfo (TypeContainer tc) - { - this.Type = tc.TypeBuilder; - - struct_info = StructInfo.GetStructInfo (tc); - if (struct_info != null) { - Length = struct_info.Length; - TotalLength = struct_info.TotalLength; - SubStructInfo = struct_info.StructFields; - IsStruct = true; - } else { - Length = 0; - TotalLength = 1; - IsStruct = false; - } - } - - protected TypeInfo (StructInfo struct_info, int offset) - { - this.struct_info = struct_info; - this.Offset = offset; - this.Length = struct_info.Length; - this.TotalLength = struct_info.TotalLength; - this.SubStructInfo = struct_info.StructFields; - this.Type = struct_info.Type; - this.IsStruct = true; - } - - public int GetFieldIndex (string name) - { - if (struct_info == null) - return 0; - - return struct_info [name]; - } - - public TypeInfo GetSubStruct (string name) - { - if (struct_info == null) - return null; - - return struct_info.GetStructField (name); - } - - // - // A struct's constructor must always assign all fields. - // This method checks whether it actually does so. - // - public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc) - { - if (struct_info == null) - return true; - - bool ok = true; - for (int i = 0; i < struct_info.Count; i++) { - FieldInfo field = struct_info.Fields [i]; - - if (!branching.IsFieldAssigned (vi, field.Name)) { - Report.Error (171, loc, - "Field `" + TypeManager.CSharpName (Type) + - "." + field.Name + "' must be fully initialized " + - "before control leaves the constructor"); - ok = false; - } - } - - return ok; - } - - public override string ToString () - { - return String.Format ("TypeInfo ({0}:{1}:{2}:{3})", - Type, Offset, Length, TotalLength); - } - - protected class StructInfo { - public readonly Type Type; - public readonly FieldInfo[] Fields; - public readonly TypeInfo[] StructFields; - public readonly int Count; - public readonly int CountPublic; - public readonly int CountNonPublic; - public readonly int Length; - public readonly int TotalLength; - public readonly bool HasStructFields; - - private static Hashtable field_type_hash = new Hashtable (); - private Hashtable struct_field_hash; - private Hashtable field_hash; - - protected bool InTransit = false; - - // Private constructor. To save memory usage, we only need to create one instance - // of this class per struct type. - private StructInfo (Type type) - { - this.Type = type; - - field_type_hash.Add (type, this); - - if (type is TypeBuilder) { - TypeContainer tc = TypeManager.LookupTypeContainer (type); - - ArrayList fields = tc.Fields; - - ArrayList public_fields = new ArrayList (); - ArrayList non_public_fields = new ArrayList (); - - if (fields != null) { - foreach (Field field in fields) { - if ((field.ModFlags & Modifiers.STATIC) != 0) - continue; - if ((field.ModFlags & Modifiers.PUBLIC) != 0) - public_fields.Add (field.FieldBuilder); - else - non_public_fields.Add (field.FieldBuilder); - } - } - - CountPublic = public_fields.Count; - CountNonPublic = non_public_fields.Count; - Count = CountPublic + CountNonPublic; - - Fields = new FieldInfo [Count]; - public_fields.CopyTo (Fields, 0); - non_public_fields.CopyTo (Fields, CountPublic); - } else { - FieldInfo[] public_fields = type.GetFields ( - BindingFlags.Instance|BindingFlags.Public); - FieldInfo[] non_public_fields = type.GetFields ( - BindingFlags.Instance|BindingFlags.NonPublic); - - CountPublic = public_fields.Length; - CountNonPublic = non_public_fields.Length; - Count = CountPublic + CountNonPublic; - - Fields = new FieldInfo [Count]; - public_fields.CopyTo (Fields, 0); - non_public_fields.CopyTo (Fields, CountPublic); - } - - struct_field_hash = new Hashtable (); - field_hash = new Hashtable (); - - Length = 0; - StructFields = new TypeInfo [Count]; - StructInfo[] sinfo = new StructInfo [Count]; - - InTransit = true; - - for (int i = 0; i < Count; i++) { - FieldInfo field = (FieldInfo) Fields [i]; - - sinfo [i] = GetStructInfo (field.FieldType); - if (sinfo [i] == null) - field_hash.Add (field.Name, ++Length); - else if (sinfo [i].InTransit) { - Report.Error (523, String.Format ( - "Struct member '{0}.{1}' of type '{2}' causes " + - "a cycle in the structure layout", - type, field.Name, sinfo [i].Type)); - sinfo [i] = null; - return; - } - } - - InTransit = false; - - TotalLength = Length + 1; - for (int i = 0; i < Count; i++) { - FieldInfo field = (FieldInfo) Fields [i]; - - if (sinfo [i] == null) - continue; - - field_hash.Add (field.Name, TotalLength); - - HasStructFields = true; - StructFields [i] = new TypeInfo (sinfo [i], TotalLength); - struct_field_hash.Add (field.Name, StructFields [i]); - TotalLength += sinfo [i].TotalLength; - } - } - - public int this [string name] { - get { - if (field_hash.Contains (name)) - return (int) field_hash [name]; - else - return 0; - } - } - - public TypeInfo GetStructField (string name) - { - return (TypeInfo) struct_field_hash [name]; - } - - public static StructInfo GetStructInfo (Type type) - { - if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) || - TypeManager.IsBuiltinType (type)) - return null; - - StructInfo info = (StructInfo) field_type_hash [type]; - if (info != null) - return info; - - return new StructInfo (type); - } - - public static StructInfo GetStructInfo (TypeContainer tc) - { - StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder]; - if (info != null) - return info; - - return new StructInfo (tc.TypeBuilder); - } - } - } - - // - // This is used by the flow analysis code to store information about a single local variable - // or parameter. Depending on the variable's type, we need to allocate one or more elements - // in the BitVector - if it's a fundamental or reference type, we just need to know whether - // it has been assigned or not, but for structs, we need this information for each of its fields. - // - public class VariableInfo { - public readonly string Name; - public readonly TypeInfo TypeInfo; - - // - // The bit offset of this variable in the flow vector. - // - public readonly int Offset; - - // - // The number of bits this variable needs in the flow vector. - // The first bit always specifies whether the variable as such has been assigned while - // the remaining bits contain this information for each of a struct's fields. - // - public readonly int Length; - - // - // If this is a parameter of local variable. - // - public readonly bool IsParameter; - - public readonly LocalInfo LocalInfo; - public readonly int ParameterIndex; - - readonly VariableInfo Parent; - VariableInfo[] sub_info; - - protected VariableInfo (string name, Type type, int offset) - { - this.Name = name; - this.Offset = offset; - this.TypeInfo = TypeInfo.GetTypeInfo (type); - - Length = TypeInfo.TotalLength; - - Initialize (); - } - - protected VariableInfo (VariableInfo parent, TypeInfo type) - { - this.Name = parent.Name; - this.TypeInfo = type; - this.Offset = parent.Offset + type.Offset; - this.Parent = parent; - this.Length = type.TotalLength; - - this.IsParameter = parent.IsParameter; - this.LocalInfo = parent.LocalInfo; - this.ParameterIndex = parent.ParameterIndex; - - Initialize (); - } - - protected void Initialize () - { - TypeInfo[] sub_fields = TypeInfo.SubStructInfo; - if (sub_fields != null) { - sub_info = new VariableInfo [sub_fields.Length]; - for (int i = 0; i < sub_fields.Length; i++) { - if (sub_fields [i] != null) - sub_info [i] = new VariableInfo (this, sub_fields [i]); - } - } else - sub_info = new VariableInfo [0]; - } - - public VariableInfo (LocalInfo local_info, int offset) - : this (local_info.Name, local_info.VariableType, offset) - { - this.LocalInfo = local_info; - this.IsParameter = false; - } - - public VariableInfo (string name, Type type, int param_idx, int offset) - : this (name, type, offset) - { - this.ParameterIndex = param_idx; - this.IsParameter = true; - } - - public bool IsAssigned (EmitContext ec) - { - return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (this); - } - - public bool IsAssigned (EmitContext ec, Location loc) - { - if (IsAssigned (ec)) - return true; - - Report.Error (165, loc, - "Use of unassigned local variable `" + Name + "'"); - ec.CurrentBranching.SetAssigned (this); - return false; - } - - public bool IsAssigned (MyBitVector vector) - { - if (vector [Offset]) - return true; - - for (VariableInfo parent = Parent; parent != null; parent = parent.Parent) - if (vector [parent.Offset]) - return true; - - // Return unless this is a struct. - if (!TypeInfo.IsStruct) - return false; - - // Ok, so each field must be assigned. - for (int i = 0; i < TypeInfo.Length; i++) { - if (!vector [Offset + i + 1]) - return false; - } - - // Ok, now check all fields which are structs. - for (int i = 0; i < sub_info.Length; i++) { - VariableInfo sinfo = sub_info [i]; - if (sinfo == null) - continue; - - if (!sinfo.IsAssigned (vector)) - return false; - } - - vector [Offset] = true; - return true; - } - - public void SetAssigned (EmitContext ec) - { - if (ec.DoFlowAnalysis) - ec.CurrentBranching.SetAssigned (this); - } - - public void SetAssigned (MyBitVector vector) - { - vector [Offset] = true; - } - - public bool IsFieldAssigned (EmitContext ec, string name, Location loc) - { - if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsFieldAssigned (this, name)) - return true; - - Report.Error (170, loc, - "Use of possibly unassigned field `" + name + "'"); - ec.CurrentBranching.SetFieldAssigned (this, name); - return false; - } - - public bool IsFieldAssigned (MyBitVector vector, string field_name) - { - int field_idx = TypeInfo.GetFieldIndex (field_name); - - if (field_idx == 0) - return true; - - return vector [Offset + field_idx]; - } - - public void SetFieldAssigned (EmitContext ec, string name) - { - if (ec.DoFlowAnalysis) - ec.CurrentBranching.SetFieldAssigned (this, name); - } - - public void SetFieldAssigned (MyBitVector vector, string field_name) - { - int field_idx = TypeInfo.GetFieldIndex (field_name); - - if (field_idx == 0) - return; - - vector [Offset + field_idx] = true; - } - - public VariableInfo GetSubStruct (string name) - { - TypeInfo type = TypeInfo.GetSubStruct (name); - - if (type == null) - return null; - - return new VariableInfo (this, type); - } - - public override string ToString () - { - return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})", - Name, TypeInfo, Offset, Length, IsParameter); - } - } - - // - // This is used by the flow code to hold the `layout' of the flow vector for - // all locals and all parameters (ie. we create one instance of this class for the - // locals and another one for the params). - // - public class VariableMap { - // - // The number of variables in the map. - // - public readonly int Count; - - // - // Total length of the flow vector for this map. - // - public readonly int Length; - - // - // Type and name of all the variables. - // Note that this is null for variables for which we do not need to compute - // assignment info. - // - public readonly Type[] VariableTypes; - public readonly string[] VariableNames; - - VariableInfo[] map; - - public VariableMap (InternalParameters ip) - { - Count = ip != null ? ip.Count : 0; - map = new VariableInfo [Count]; - VariableNames = new string [Count]; - VariableTypes = new Type [Count]; - Length = 0; - - for (int i = 0; i < Count; i++) { - Parameter.Modifier mod = ip.ParameterModifier (i); - - if ((mod & Parameter.Modifier.OUT) == 0) - continue; - - VariableNames [i] = ip.ParameterName (i); - VariableTypes [i] = TypeManager.GetElementType (ip.ParameterType (i)); - - map [i] = new VariableInfo (VariableNames [i], VariableTypes [i], i, Length); - Length += map [i].Length; - } - } - - public VariableMap (LocalInfo[] locals) - : this (null, locals) - { } - - public VariableMap (VariableMap parent, LocalInfo[] locals) - { - int offset = 0, start = 0; - if (parent != null) { - offset = parent.Length; - start = parent.Count; - } - - Count = locals.Length + start; - map = new VariableInfo [Count]; - VariableNames = new string [Count]; - VariableTypes = new Type [Count]; - Length = offset; - - if (parent != null) { - parent.map.CopyTo (map, 0); - parent.VariableNames.CopyTo (VariableNames, 0); - parent.VariableTypes.CopyTo (VariableTypes, 0); - } - - for (int i = start; i < Count; i++) { - LocalInfo li = locals [i-start]; - - if (li.VariableType == null) - continue; - - VariableNames [i] = li.Name; - VariableTypes [i] = li.VariableType; - - map [i] = li.VariableInfo = new VariableInfo (li, Length); - Length += map [i].Length; - } - } - - // - // Returns the VariableInfo for variable @index or null if we don't need to - // compute assignment info for this variable. - // - public VariableInfo this [int index] { - get { - return map [index]; - } - } - - public override string ToString () - { - return String.Format ("VariableMap ({0}:{1})", Count, Length); - } - } - public class LocalInfo { public Expression Type; @@ -2852,7 +1109,10 @@ namespace Mono.CSharp { [Flags] public enum Flags : byte { Implicit = 1, - Unchecked = 2 + Unchecked = 2, + BlockUsed = 4, + VariablesInitialized = 8, + HasRet = 16 } Flags flags; @@ -2904,8 +1164,6 @@ namespace Mono.CSharp { // Block switch_block; - bool used = false; - static int id; int this_id; @@ -3148,7 +1406,7 @@ namespace Mono.CSharp { variables.Add (name, vi); - if (variables_initialized) + if ((flags & Flags.VariablesInitialized) != 0) throw new Exception (); // Console.WriteLine ("Adding {0} to {1}", name, ID); @@ -3264,26 +1522,25 @@ namespace Mono.CSharp { public void AddStatement (Statement s) { statements.Add (s); - used = true; + flags |= Flags.BlockUsed; } public bool Used { get { - return used; + return (flags & Flags.BlockUsed) != 0; } } public void Use () { - used = true; + flags |= Flags.BlockUsed; } VariableMap param_map, local_map; - bool variables_initialized = false; public VariableMap ParameterMap { get { - if (!variables_initialized) + if ((flags & Flags.VariablesInitialized) == 0) throw new Exception (); return param_map; @@ -3292,7 +1549,7 @@ namespace Mono.CSharp { public VariableMap LocalMap { get { - if (!variables_initialized) + if ((flags & Flags.VariablesInitialized) == 0) throw new Exception (); return local_map; @@ -3305,10 +1562,8 @@ namespace Mono.CSharp { /// /// tc: is our typecontainer (to resolve type references) /// ig: is the code generator: - /// toplevel: the toplevel block. This is used for checking - /// that no two labels with the same name are used. /// - public void EmitMeta (EmitContext ec, InternalParameters ip, Block toplevel) + public void EmitMeta (EmitContext ec, InternalParameters ip) { DeclSpace ds = ec.DeclSpace; ILGenerator ig = ec.ig; @@ -3336,7 +1591,7 @@ namespace Mono.CSharp { local_map = new VariableMap (locals); param_map = new VariableMap (ip); - variables_initialized = true; + flags |= Flags.VariablesInitialized; bool old_check_state = ec.ConstantCheckState; ec.ConstantCheckState = (flags & Flags.Unchecked) == 0; @@ -3401,7 +1656,7 @@ namespace Mono.CSharp { // if (children != null){ foreach (Block b in children) - b.EmitMeta (ec, ip, toplevel); + b.EmitMeta (ec, ip); } } @@ -3436,8 +1691,6 @@ namespace Mono.CSharp { b.UsageWarning (); } - bool has_ret = false; - public override bool Resolve (EmitContext ec) { Block prev_block = ec.CurrentBlock; @@ -3478,12 +1731,12 @@ namespace Mono.CSharp { Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching); - FlowReturns returns = ec.EndFlowBranching (); + FlowBranching.FlowReturns returns = ec.EndFlowBranching (); ec.CurrentBlock = prev_block; // If we're a non-static `struct' constructor which doesn't have an // initializer, then we must initialize all of the struct's fields. - if ((this_variable != null) && (returns != FlowReturns.EXCEPTION) && + if ((this_variable != null) && (returns != FlowBranching.FlowReturns.Exception) && !this_variable.IsThisAssigned (ec, loc)) ok = false; @@ -3494,10 +1747,10 @@ namespace Mono.CSharp { "This label has not been referenced"); } - if ((returns == FlowReturns.ALWAYS) || - (returns == FlowReturns.EXCEPTION) || - (returns == FlowReturns.UNREACHABLE)) - has_ret = true; + if ((returns == FlowBranching.FlowReturns.Always) || + (returns == FlowBranching.FlowReturns.Exception) || + (returns == FlowBranching.FlowReturns.Unreachable)) + flags |= Flags.HasRet; return ok; } @@ -3507,7 +1760,7 @@ namespace Mono.CSharp { foreach (Statement s in statements) s.Emit (ec); - return has_ret; + return (flags & Flags.HasRet) != 0; } public override bool Emit (EmitContext ec) @@ -4288,12 +2541,12 @@ namespace Mono.CSharp { ec.Switch = this; ec.Switch.SwitchType = SwitchType; - ec.StartFlowBranching (FlowBranchingType.SWITCH, loc); + ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc); bool first = true; foreach (SwitchSection ss in Sections){ if (!first) - ec.CurrentBranching.CreateSibling (); + ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.SwitchSection); else first = false; @@ -4303,7 +2556,7 @@ namespace Mono.CSharp { if (!got_default) - ec.CurrentBranching.CreateSibling (); + ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.SwitchSection); ec.EndFlowBranching (); ec.Switch = old_switch; @@ -4836,7 +3089,7 @@ namespace Mono.CSharp { { bool ok = true; - ec.StartFlowBranching (FlowBranchingType.EXCEPTION, Block.StartLocation); + ec.StartFlowBranching (FlowBranching.BranchingType.Exception, Block.StartLocation); Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation); @@ -4853,7 +3106,7 @@ namespace Mono.CSharp { Report.Debug (1, "START OF CATCH BLOCKS", vector); foreach (Catch c in Specific){ - ec.CurrentBranching.CreateSibling (); + ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Catch); Report.Debug (1, "STARTED SIBLING FOR CATCH", ec.CurrentBranching); if (c.Name != null) { @@ -4883,7 +3136,7 @@ namespace Mono.CSharp { Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching); if (General != null){ - ec.CurrentBranching.CreateSibling (); + ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Catch); Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching); bool old_in_catch = ec.InCatch; @@ -4906,7 +3159,7 @@ namespace Mono.CSharp { if (Fini != null) { if (ok) - ec.CurrentBranching.CreateSiblingForFinally (); + ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Finally); Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector); bool old_in_finally = ec.InFinally; @@ -4918,13 +3171,13 @@ namespace Mono.CSharp { ec.InFinally = old_in_finally; } - FlowReturns returns = ec.EndFlowBranching (); + FlowBranching.FlowReturns returns = ec.EndFlowBranching (); FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector; Report.Debug (1, "END OF FINALLY", ec.CurrentBranching, returns, vector, f_vector); - if ((returns == FlowReturns.SOMETIMES) || (returns == FlowReturns.ALWAYS)) { + if ((returns == FlowBranching.FlowReturns.Sometimes) || (returns == FlowBranching.FlowReturns.Always)) { ec.CurrentBranching.CheckOutParameters (f_vector.Parameters, loc); } @@ -4932,7 +3185,7 @@ namespace Mono.CSharp { Report.Debug (1, "END OF TRY", ec.CurrentBranching); - if (returns != FlowReturns.ALWAYS) { + if (returns != FlowBranching.FlowReturns.Always) { // Unfortunately, System.Reflection.Emit automatically emits a leave // to the end of the finally block. This is a problem if `returns' // is true since we may jump to a point after the end of the method. @@ -5207,7 +3460,7 @@ namespace Mono.CSharp { /// public class Foreach : Statement { Expression type; - LocalVariableReference variable; + Expression variable; Expression expr; Statement statement; ForeachHelperMethods hm; @@ -5266,8 +3519,8 @@ namespace Mono.CSharp { empty = new EmptyExpression (hm.element_type); } - ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc); - ec.CurrentBranching.CreateSibling (); + ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc); + ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional); // // @@ -5281,13 +3534,14 @@ namespace Mono.CSharp { if (conv == null) return false; - if (variable.ResolveLValue (ec, empty) == null) + variable = variable.ResolveLValue (ec, empty); + if (variable == null) return false; if (!statement.Resolve (ec)) return false; - FlowReturns returns = ec.EndFlowBranching (); + FlowBranching.FlowReturns returns = ec.EndFlowBranching (); return true; } @@ -5541,14 +3795,15 @@ namespace Mono.CSharp { bool EmitCollectionForeach (EmitContext ec) { ILGenerator ig = ec.ig; - LocalBuilder enumerator, disposable; + VariableStorage enumerator, disposable; - enumerator = ig.DeclareLocal (hm.enumerator_type); + enumerator = new VariableStorage (ec, hm.enumerator_type); if (hm.is_disposable) - disposable = ig.DeclareLocal (TypeManager.idisposable_type); + disposable = new VariableStorage (ec, TypeManager.idisposable_type); else disposable = null; - + + enumerator.EmitThis (); // // Instantiate the enumerator // @@ -5565,7 +3820,7 @@ namespace Mono.CSharp { expr.Emit (ec); ig.Emit (OpCodes.Callvirt, hm.get_enumerator); } - ig.Emit (OpCodes.Stloc, enumerator); + enumerator.EmitStore (); // // Protect the code in a try/finalize block, so that @@ -5582,13 +3837,21 @@ namespace Mono.CSharp { Label end_try = ig.DefineLabel (); ig.MarkLabel (ec.LoopBegin); - ig.Emit (OpCodes.Ldloc, enumerator); + enumerator.EmitLoad (); ig.Emit (OpCodes.Callvirt, hm.move_next); ig.Emit (OpCodes.Brfalse, end_try); - ig.Emit (OpCodes.Ldloc, enumerator); + if (ec.InIterator) + ec.EmitThis (); + + enumerator.EmitLoad (); ig.Emit (OpCodes.Callvirt, hm.get_current); - variable.EmitAssign (ec, conv); + if (ec.InIterator){ + conv.Emit (ec); + ig.Emit (OpCodes.Stfld, ((FieldExpr) variable).FieldInfo); + } else + ((IAssignMethod)variable).EmitAssign (ec, conv); + statement.Emit (ec); ig.Emit (OpCodes.Br, ec.LoopBegin); ig.MarkLabel (end_try); @@ -5605,13 +3868,16 @@ namespace Mono.CSharp { bool old_in_finally = ec.InFinally; ec.InFinally = true; ig.BeginFinallyBlock (); - - ig.Emit (OpCodes.Ldloc, enumerator); + + disposable.EmitThis (); + enumerator.EmitThis (); + enumerator.EmitLoad (); ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type); - ig.Emit (OpCodes.Stloc, disposable); - ig.Emit (OpCodes.Ldloc, disposable); + disposable.EmitStore (); + disposable.EmitLoad (); ig.Emit (OpCodes.Brfalse, end_finally); - ig.Emit (OpCodes.Ldloc, disposable); + disposable.EmitThis (); + disposable.EmitLoad (); ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); ig.MarkLabel (end_finally); ec.InFinally = old_in_finally; @@ -5635,82 +3901,106 @@ namespace Mono.CSharp { int rank = array_type.GetArrayRank (); ILGenerator ig = ec.ig; - LocalBuilder copy = ig.DeclareLocal (array_type); + VariableStorage copy = new VariableStorage (ec, array_type); // // Make our copy of the array // + copy.EmitThis (); expr.Emit (ec); - ig.Emit (OpCodes.Stloc, copy); + copy.EmitStore (); if (rank == 1){ - LocalBuilder counter = ig.DeclareLocal (TypeManager.int32_type); + VariableStorage counter = new VariableStorage (ec,TypeManager.int32_type); Label loop, test; - + + counter.EmitThis (); ig.Emit (OpCodes.Ldc_I4_0); - ig.Emit (OpCodes.Stloc, counter); + counter.EmitStore (); test = ig.DefineLabel (); ig.Emit (OpCodes.Br, test); loop = ig.DefineLabel (); ig.MarkLabel (loop); - ig.Emit (OpCodes.Ldloc, copy); - ig.Emit (OpCodes.Ldloc, counter); + if (ec.InIterator) + ec.EmitThis (); + + copy.EmitThis (); + copy.EmitLoad (); + counter.EmitThis (); + counter.EmitLoad (); // // Load the value, we load the value using the underlying type, // then we use the variable.EmitAssign to load using the proper cast. // ArrayAccess.EmitLoadOpcode (ig, element_type); - variable.EmitAssign (ec, conv); + if (ec.InIterator){ + conv.Emit (ec); + ig.Emit (OpCodes.Stfld, ((FieldExpr) variable).FieldInfo); + } else + ((IAssignMethod)variable).EmitAssign (ec, conv); statement.Emit (ec); ig.MarkLabel (ec.LoopBegin); - ig.Emit (OpCodes.Ldloc, counter); + counter.EmitThis (); + counter.EmitThis (); + counter.EmitLoad (); ig.Emit (OpCodes.Ldc_I4_1); ig.Emit (OpCodes.Add); - ig.Emit (OpCodes.Stloc, counter); + counter.EmitStore (); ig.MarkLabel (test); - ig.Emit (OpCodes.Ldloc, counter); - ig.Emit (OpCodes.Ldloc, copy); + counter.EmitThis (); + counter.EmitLoad (); + copy.EmitThis (); + copy.EmitLoad (); ig.Emit (OpCodes.Ldlen); ig.Emit (OpCodes.Conv_I4); ig.Emit (OpCodes.Blt, loop); } else { - LocalBuilder [] dim_len = new LocalBuilder [rank]; - LocalBuilder [] dim_count = new LocalBuilder [rank]; + VariableStorage [] dim_len = new VariableStorage [rank]; + VariableStorage [] dim_count = new VariableStorage [rank]; Label [] loop = new Label [rank]; Label [] test = new Label [rank]; int dim; for (dim = 0; dim < rank; dim++){ - dim_len [dim] = ig.DeclareLocal (TypeManager.int32_type); - dim_count [dim] = ig.DeclareLocal (TypeManager.int32_type); + dim_len [dim] = new VariableStorage (ec, TypeManager.int32_type); + dim_count [dim] = new VariableStorage (ec, TypeManager.int32_type); test [dim] = ig.DefineLabel (); loop [dim] = ig.DefineLabel (); } for (dim = 0; dim < rank; dim++){ - ig.Emit (OpCodes.Ldloc, copy); + dim_len [dim].EmitThis (); + copy.EmitThis (); + copy.EmitLoad (); IntLiteral.EmitInt (ig, dim); ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int); - ig.Emit (OpCodes.Stloc, dim_len [dim]); + dim_len [dim].EmitStore (); + } for (dim = 0; dim < rank; dim++){ + dim_count [dim].EmitThis (); ig.Emit (OpCodes.Ldc_I4_0); - ig.Emit (OpCodes.Stloc, dim_count [dim]); + dim_count [dim].EmitStore (); ig.Emit (OpCodes.Br, test [dim]); ig.MarkLabel (loop [dim]); } - ig.Emit (OpCodes.Ldloc, copy); - for (dim = 0; dim < rank; dim++) - ig.Emit (OpCodes.Ldloc, dim_count [dim]); + if (ec.InIterator) + ec.EmitThis (); + copy.EmitThis (); + copy.EmitLoad (); + for (dim = 0; dim < rank; dim++){ + dim_count [dim].EmitThis (); + dim_count [dim].EmitLoad (); + } // // FIXME: Maybe we can cache the computation of `get'? @@ -5727,18 +4017,26 @@ namespace Mono.CSharp { CallingConventions.HasThis| CallingConventions.Standard, var_type, args); ig.Emit (OpCodes.Call, get); - variable.EmitAssign (ec, conv); + if (ec.InIterator){ + conv.Emit (ec); + ig.Emit (OpCodes.Stfld, ((FieldExpr) variable).FieldInfo); + } else + ((IAssignMethod)variable).EmitAssign (ec, conv); statement.Emit (ec); ig.MarkLabel (ec.LoopBegin); for (dim = rank - 1; dim >= 0; dim--){ - ig.Emit (OpCodes.Ldloc, dim_count [dim]); + dim_count [dim].EmitThis (); + dim_count [dim].EmitThis (); + dim_count [dim].EmitLoad (); ig.Emit (OpCodes.Ldc_I4_1); ig.Emit (OpCodes.Add); - ig.Emit (OpCodes.Stloc, dim_count [dim]); + dim_count [dim].EmitStore (); ig.MarkLabel (test [dim]); - ig.Emit (OpCodes.Ldloc, dim_count [dim]); - ig.Emit (OpCodes.Ldloc, dim_len [dim]); + dim_count [dim].EmitThis (); + dim_count [dim].EmitLoad (); + dim_len [dim].EmitThis (); + dim_len [dim].EmitLoad (); ig.Emit (OpCodes.Blt, loop [dim]); } } diff --git a/mcs/gmcs/support.cs b/mcs/gmcs/support.cs index c93be326bf6..64f87b51945 100755 --- a/mcs/gmcs/support.cs +++ b/mcs/gmcs/support.cs @@ -9,6 +9,7 @@ // using System; +using System.IO; using System.Text; using System.Reflection; using System.Collections; @@ -255,4 +256,76 @@ namespace Mono.CSharp { } } + /// + /// This is a wrapper around StreamReader which is seekable. + /// + public class SeekableStreamReader + { + public SeekableStreamReader (StreamReader reader) + { + this.reader = reader; + this.buffer = new char [DefaultCacheSize]; + } + + public SeekableStreamReader (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks) + : this (new StreamReader (stream, encoding, detect_encoding_from_bytemarks)) + { } + + StreamReader reader; + + private const int DefaultCacheSize = 1024; + + char[] buffer; + int buffer_start; + int buffer_size; + int pos; + + /// + /// The difference to the StreamReader's BaseStream.Position is that this one is reliable; ie. it + // always reports the correct position and if it's modified, it also takes care of the buffered data. + /// + public int Position { + get { + return buffer_start + pos; + } + + set { + // This one is easy: we're modifying the position within our current + // buffer. + if ((value >= buffer_start) && (value < buffer_start + buffer_size)) { + pos = value - buffer_start; + return; + } + + // Ok, now we need to seek. + reader.DiscardBufferedData (); + reader.BaseStream.Position = buffer_start = value; + buffer_size = pos = 0; + } + } + + private bool ReadBuffer () + { + pos = 0; + buffer_start += buffer_size; + buffer_size = reader.Read (buffer, 0, buffer.Length); + return buffer_size > 0; + } + + public int Peek () + { + if ((pos >= buffer_size) && !ReadBuffer ()) + return -1; + + return buffer [pos]; + } + + public int Read () + { + if ((pos >= buffer_size) && !ReadBuffer ()) + return -1; + + return buffer [pos++]; + } + } } diff --git a/mcs/gmcs/typemanager.cs b/mcs/gmcs/typemanager.cs index 801ceba84ae..e3544a31f16 100755 --- a/mcs/gmcs/typemanager.cs +++ b/mcs/gmcs/typemanager.cs @@ -1622,6 +1622,11 @@ public class TypeManager { return true; } + // + // The return value can be null; This will be the case for + // auxiliary FieldBuilders created by the compiler that have no + // real field being declared on the source code + // static public FieldBase GetField (FieldInfo fb) { return (FieldBase) fieldbuilders_to_fields [fb]; @@ -2051,14 +2056,19 @@ public class TypeManager { // // Returns whether the array of memberinfos contains the given method // - static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method) + public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method) { Type [] new_args = TypeManager.GetArgumentTypes (new_method); - foreach (MethodBase method in array){ + foreach (MethodBase method in array) { if (method.Name != new_method.Name) continue; - + + if (method is MethodInfo && new_method is MethodInfo) + if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType) + continue; + + Type [] old_args = TypeManager.GetArgumentTypes (method); int old_count = old_args.Length; int i; @@ -2075,6 +2085,7 @@ public class TypeManager { return true; } + return false; } -- 2.25.1