X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=417830431dbf5bc64fe2e3fdf555152b2bd63f99;hb=95dc3521c07b15316c0087fb5f088e65162077e4;hp=63052ea98966ebb6f550dd386b8d573591f0c086;hpb=c20307a7b01c1a16642bc2dff4d53181d41b296d;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index 63052ea9896..417830431db 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -1074,6 +1074,8 @@ namespace Mono.CSharp { return false; } + ec.CurrentBranching.CurrentUsageVector.Goto (); + expr = expr.Resolve (ec); if (expr == null) return false; @@ -1085,21 +1087,18 @@ namespace Mono.CSharp { } Type type = ec.Switch.SwitchType; - if (!Convert.ImplicitStandardConversionExists (c, type)) - Report.Warning (469, 2, loc, "The `goto case' value is not implicitly " + - "convertible to type `{0}'", TypeManager.CSharpName (type)); - - bool fail = false; - object val = c.GetValue (); - if ((val != null) && (c.Type != type) && (c.Type != TypeManager.object_type)) - val = TypeManager.ChangeType (val, type, out fail); - - if (fail) { - Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'", - c.GetSignatureForError (), TypeManager.CSharpName (type)); + Constant res = c.TryReduce (ec, type, c.Location); + if (res == null) { + c.Error_ValueCannotBeConverted (ec, loc, type, true); return false; } + if (!Convert.ImplicitStandardConversionExists (c, type)) + Report.Warning (469, 2, loc, + "The `goto case' value is not implicitly convertible to type `{0}'", + TypeManager.CSharpName (type)); + + object val = res.GetValue (); if (val == null) val = SwitchLabel.NullStringCase; @@ -1111,7 +1110,6 @@ namespace Mono.CSharp { return false; } - ec.CurrentBranching.CurrentUsageVector.Goto (); return true; } @@ -1159,7 +1157,7 @@ namespace Mono.CSharp { if ((t != TypeManager.exception_type) && !TypeManager.IsSubclassOf (t, TypeManager.exception_type) && - !(expr is NullLiteral)) { + t != TypeManager.null_type) { Error (155, "The type caught or thrown must be derived from System.Exception"); return false; } @@ -1272,7 +1270,7 @@ namespace Mono.CSharp { // The information about a user-perceived local variable // public class LocalInfo : IKnownVariable, ILocalVariable { - public readonly Expression Type; + public readonly FullNamedExpression Type; public Type VariableType; public readonly string Name; @@ -1302,8 +1300,8 @@ namespace Mono.CSharp { Flags flags; ReadOnlyContext ro_context; LocalBuilder builder; - - public LocalInfo (Expression type, string name, Block block, Location l) + + public LocalInfo (FullNamedExpression type, string name, Block block, Location l) { Type = type; Name = name; @@ -1480,7 +1478,7 @@ namespace Mono.CSharp { // Variables in anonymous block are not resolved yet // if (VariableType == null) - return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location); + return new LocalInfo ((FullNamedExpression) Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location); // // Variables in method block are resolved @@ -1519,10 +1517,10 @@ namespace Mono.CSharp { BlockUsed = 2, VariablesInitialized = 4, HasRet = 8, - IsDestructor = 16, - Unsafe = 32, - IsIterator = 64, - HasStoreyAccess = 128 + Unsafe = 16, + IsIterator = 32, + HasCapturedVariable = 64, + HasCapturedThis = 128 } protected Flags flags; @@ -1559,7 +1557,6 @@ namespace Mono.CSharp { // Keeps track of (name, type) pairs // IDictionary variables; - protected IDictionary range_variables; // // Keeps track of constants @@ -1575,7 +1572,7 @@ namespace Mono.CSharp { // Block switch_block; - ArrayList scope_initializers; + protected ArrayList scope_initializers; ArrayList anonymous_children; @@ -1599,6 +1596,20 @@ namespace Mono.CSharp { : this (parent, (Flags) 0, start, end) { } + // + // Useful when TopLevel block is downgraded to normal block + // + public Block (ToplevelBlock parent, ToplevelBlock source) + : this (parent, source.flags, source.StartLocation, source.EndLocation) + { + statements = source.statements; + children = source.children; + labels = source.labels; + variables = source.variables; + constants = source.constants; + switch_block = source.switch_block; + } + public Block (Block parent, Flags flags, Location start, Location end) { if (parent != null) { @@ -1811,35 +1822,45 @@ namespace Mono.CSharp { return false; } - public LocalInfo AddVariable (Expression type, string name, Location l) + protected virtual bool CheckParentConflictName (ToplevelBlock block, string name, Location l) { LocalInfo vi = GetLocalInfo (name); if (vi != null) { Report.SymbolRelatedToPreviousError (vi.Location, name); if (Explicit == vi.Block.Explicit) { - if (type == Linq.ImplicitQueryParameter.ImplicitType.Instance && type == vi.Type) - Error_AlreadyDeclared (l, name); - else - Error_AlreadyDeclared (l, name, null); + Error_AlreadyDeclared (l, name, null); } else { - Error_AlreadyDeclared (l, name, "parent"); + Error_AlreadyDeclared (l, name, this is ToplevelBlock ? + "parent or current" : "parent"); } - return null; + return false; } - ToplevelParameterInfo pi = Toplevel.GetParameterInfo (name); - if (pi != null) { - Report.SymbolRelatedToPreviousError (pi.Location, name); - Error_AlreadyDeclared (loc, name, - pi.Block == Toplevel ? "method argument" : "parent or current"); - return null; + if (block != null) { + Expression e = block.GetParameterReference (name, Location.Null); + if (e != null) { + ParameterReference pr = e as ParameterReference; + if (this is Linq.QueryBlock && (pr != null && pr.Parameter is Linq.QueryBlock.ImplicitQueryParameter || e is MemberAccess)) + Error_AlreadyDeclared (loc, name); + else + Error_AlreadyDeclared (loc, name, "parent or current"); + return false; + } } - + + return true; + } + + public LocalInfo AddVariable (Expression type, string name, Location l) + { + if (!CheckParentConflictName (Toplevel, name, l)) + return null; + if (Toplevel.GenericMethod != null) { foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) { if (tp.Name == name) { Report.SymbolRelatedToPreviousError (tp); - Error_AlreadyDeclaredTypeParameter (loc, name); + Error_AlreadyDeclaredTypeParameter (loc, name, "local variable"); return null; } } @@ -1852,7 +1873,7 @@ namespace Mono.CSharp { return null; } - vi = new LocalInfo (type, name, this, l); + LocalInfo vi = new LocalInfo ((FullNamedExpression) type, name, this, l); AddVariable (vi); if ((flags & Flags.VariablesInitialized) != 0) @@ -1886,10 +1907,11 @@ namespace Mono.CSharp { "A local variable named `{0}' is already defined in this scope", name); } - protected virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name) + public virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name, string conflict) { - GenericMethod.Error_ParameterNameCollision (loc, name, "local variable"); - } + Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'", + name, conflict); + } public bool AddConstant (Expression type, string name, Expression value, Location l) { @@ -1933,12 +1955,6 @@ namespace Mono.CSharp { if (ret != null) return ret; } - - if (b.range_variables != null) { - ret = (LocalInfo) b.range_variables [name]; - if (ret != null) - return ret; - } } return null; @@ -1966,7 +1982,7 @@ namespace Mono.CSharp { // It should be used by expressions which require to // register a statement during resolve process. // - public void AddScopeStatement (StatementExpression s) + public void AddScopeStatement (Statement s) { if (scope_initializers == null) scope_initializers = new ArrayList (); @@ -1993,15 +2009,6 @@ namespace Mono.CSharp { get { return (flags & Flags.HasRet) != 0; } } - public bool IsDestructor { - get { return (flags & Flags.IsDestructor) != 0; } - } - - public void SetDestructor () - { - flags |= Flags.IsDestructor; - } - public int AssignableSlots { get { // TODO: Re-enable @@ -2313,16 +2320,8 @@ namespace Mono.CSharp { Block prev_block = ec.CurrentBlock; ec.CurrentBlock = this; - if (scope_initializers != null) { - SymbolWriter.OpenCompilerGeneratedBlock (ec.ig); - - using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) { - foreach (StatementExpression s in scope_initializers) - s.Emit (ec); - } - - SymbolWriter.CloseCompilerGeneratedBlock (ec.ig); - } + if (scope_initializers != null) + EmitScopeInitializers (ec); ec.Mark (StartLocation); DoEmit (ec); @@ -2333,6 +2332,18 @@ namespace Mono.CSharp { ec.CurrentBlock = prev_block; } + protected void EmitScopeInitializers (EmitContext ec) + { + SymbolWriter.OpenCompilerGeneratedBlock (ec.ig); + + using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) { + foreach (Statement s in scope_initializers) + s.Emit (ec); + } + + SymbolWriter.CloseCompilerGeneratedBlock (ec.ig); + } + protected virtual void EmitSymbolInfo (EmitContext ec) { if (variables != null) { @@ -2456,7 +2467,6 @@ namespace Mono.CSharp { // When referencing a variable in iterator storey from children anonymous method // if (Toplevel.am_storey is IteratorStorey) { - ec.CurrentAnonymousMethod.AddStoreyReference (Toplevel.am_storey); return Toplevel.am_storey; } @@ -2471,26 +2481,18 @@ namespace Mono.CSharp { GenericMethod gm = mc == null ? null : mc.GenericMethod; // - // Create anonymous method storey for this block + // Creates anonymous method storey for this block // am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey"); } - // - // Creates a link between this block and the anonymous method - // - // An anonymous method can reference variables from any outer block, but they are - // hoisted in their own ExplicitBlock. When more than one block is referenced we - // need to create another link between those variable storeys - // - ec.CurrentAnonymousMethod.AddStoreyReference (am_storey); return am_storey; } public override void Emit (EmitContext ec) { if (am_storey != null) - am_storey.EmitHoistedVariables (ec); + am_storey.EmitStoreyInstantiation (ec); bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey); if (emit_debug_info) @@ -2509,13 +2511,46 @@ namespace Mono.CSharp { // if (am_storey != null) { if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) { + // + // Creates parent storey reference when hoisted this is accessible + // + if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) { + ExplicitBlock parent = Toplevel.Parent.Explicit; + + // + // Hoisted this exists in top-level parent storey only + // + while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey) + parent = parent.Parent.Explicit; + + am_storey.AddParentStoreyReference (parent.am_storey); + } + am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey); } am_storey.DefineType (); - am_storey.ResolveType (); + am_storey.ResolveType (); am_storey.Define (); am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey); + + ArrayList ref_blocks = am_storey.ReferencesFromChildrenBlock; + if (ref_blocks != null) { + foreach (ExplicitBlock ref_block in ref_blocks) { + for (ExplicitBlock b = ref_block.Explicit; b != this; b = b.Parent.Explicit) { + if (b.am_storey != null) { + b.am_storey.AddParentStoreyReference (am_storey); + + // Stop propagation inside same top block + if (b.Toplevel == Toplevel) + break; + + b = b.Toplevel; + } + b.HasCapturedVariable = true; + } + } + } } base.EmitMeta (ec); @@ -2526,29 +2561,16 @@ namespace Mono.CSharp { return known_variables == null ? null : (IKnownVariable) known_variables [name]; } - public void PropagateStoreyReference (AnonymousMethodStorey s) + public bool HasCapturedThis { - if (Parent != null && am_storey != s) { - if (am_storey != null) - am_storey.AddParentStoreyReference (s); - - Parent.Explicit.PropagateStoreyReference (s); - } + set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; } + get { return (flags & Flags.HasCapturedThis) != 0; } } - public override bool Resolve (EmitContext ec) + public bool HasCapturedVariable { - bool ok = base.Resolve (ec); - - // - // Discard an anonymous method storey when this block has no hoisted variables - // - if (am_storey != null && !am_storey.HasHoistedVariables) { - am_storey.Undo (); - am_storey = null; - } - - return ok; + set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; } + get { return (flags & Flags.HasCapturedVariable) != 0; } } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -2594,10 +2616,60 @@ namespace Mono.CSharp { // In particular, this was introduced when the support for Anonymous // Methods was implemented. // - public class ToplevelBlock : ExplicitBlock { + public class ToplevelBlock : ExplicitBlock + { + // + // Block is converted to an expression + // + sealed class BlockScopeExpression : Expression + { + Expression child; + readonly ToplevelBlock block; + + public BlockScopeExpression (Expression child, ToplevelBlock block) + { + this.child = child; + this.block = block; + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + throw new NotSupportedException (); + } + + public override Expression DoResolve (EmitContext ec) + { + if (child == null) + return null; + + block.ResolveMeta (ec, ParametersCompiled.EmptyReadOnlyParameters); + child = child.Resolve (ec); + if (child == null) + return null; + + eclass = child.eclass; + type = child.Type; + return this; + } + + public override void Emit (EmitContext ec) + { + block.EmitMeta (ec); + block.EmitScopeInitializers (ec); + child.Emit (ec); + } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + type = storey.MutateType (type); + child.MutateHoistedGenericType (storey); + block.MutateHoistedGenericType (storey); + } + } + GenericMethod generic; FlowBranchingToplevel top_level_branching; - Parameters parameters; + protected ParametersCompiled parameters; ToplevelParameterInfo[] parameter_info; LocalInfo this_variable; @@ -2606,7 +2678,7 @@ namespace Mono.CSharp { // // The parameters for the block. // - public Parameters Parameters { + public ParametersCompiled Parameters { get { return parameters; } } @@ -2614,44 +2686,39 @@ namespace Mono.CSharp { get { return generic; } } - public bool HasStoreyAccess { - set { flags = value ? flags | Flags.HasStoreyAccess : flags & ~Flags.HasStoreyAccess; } - get { return (flags & Flags.HasStoreyAccess) != 0; } - } - public ToplevelBlock Container { get { return Parent == null ? null : Parent.Toplevel; } } - public ToplevelBlock (Block parent, Parameters parameters, Location start) : + public ToplevelBlock (Block parent, ParametersCompiled parameters, Location start) : this (parent, (Flags) 0, parameters, start) { } - public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) : + public ToplevelBlock (Block parent, ParametersCompiled parameters, GenericMethod generic, Location start) : this (parent, parameters, start) { this.generic = generic; } - public ToplevelBlock (Parameters parameters, Location start) : + public ToplevelBlock (ParametersCompiled parameters, Location start) : this (null, (Flags) 0, parameters, start) { } - ToplevelBlock (Flags flags, Parameters parameters, Location start) : + ToplevelBlock (Flags flags, ParametersCompiled parameters, Location start) : this (null, flags, parameters, start) { } // We use 'Parent' to hook up to the containing block, but don't want to register the current block as a child. // So, we use a two-stage setup -- first pass a null parent to the base constructor, and then override 'Parent'. - public ToplevelBlock (Block parent, Flags flags, Parameters parameters, Location start) : + public ToplevelBlock (Block parent, Flags flags, ParametersCompiled parameters, Location start) : base (null, flags, start, Location.Null) { this.Toplevel = this; - this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters; + this.parameters = parameters; this.Parent = parent; if (parent != null) parent.AddAnonymousChild (this); @@ -2660,7 +2727,8 @@ namespace Mono.CSharp { ProcessParameters (); } - public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc) + public ToplevelBlock (Location loc) + : this (null, (Flags) 0, ParametersCompiled.EmptyReadOnlyParameters, loc) { } @@ -2692,15 +2760,11 @@ namespace Mono.CSharp { return true; } - public virtual Expression GetTransparentIdentifier (string name) - { - return null; - } - void ProcessParameters () { int n = parameters.Count; parameter_info = new ToplevelParameterInfo [n]; + ToplevelBlock top_parent = Parent == null ? null : Parent.Toplevel; for (int i = 0; i < n; ++i) { parameter_info [i] = new ToplevelParameterInfo (this, i); @@ -2709,21 +2773,8 @@ namespace Mono.CSharp { continue; string name = p.Name; - LocalInfo vi = GetLocalInfo (name); - if (vi != null) { - Report.SymbolRelatedToPreviousError (vi.Location, name); - Error_AlreadyDeclared (loc, name, "parent or current"); - continue; - } - - ToplevelParameterInfo pi = Parent == null ? null : Parent.Toplevel.GetParameterInfo (name); - if (pi != null) { - Report.SymbolRelatedToPreviousError (pi.Location, name); - Error_AlreadyDeclared (loc, name, "parent or current"); - continue; - } - - AddKnownVariable (name, parameter_info [i]); + if (CheckParentConflictName (top_parent, name, loc)) + AddKnownVariable (name, parameter_info [i]); } // mark this block as "used" so that we create local declarations in a sub-block @@ -2745,8 +2796,13 @@ namespace Mono.CSharp { public override Expression CreateExpressionTree (EmitContext ec) { - if (statements.Count == 1) - return ((Statement) statements [0]).CreateExpressionTree (ec); + if (statements.Count == 1) { + Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec); + if (scope_initializers != null) + expr = new BlockScopeExpression (expr, this); + + return expr; + } return base.CreateExpressionTree (ec); } @@ -2756,16 +2812,10 @@ namespace Mono.CSharp { // public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source) { - // Create block with original statements - ExplicitBlock iter_block = new ExplicitBlock (this, flags, StartLocation, EndLocation); IsIterator = true; - // TODO: Change to iter_block.statements = statements; - foreach (Statement stmt in source.statements) - iter_block.AddStatement (stmt); - labels = source.labels; - - AddStatement (new IteratorStatement (iterator, iter_block)); + // Creates block with original statements + AddStatement (new IteratorStatement (iterator, new Block (this, source))); source.statements = new ArrayList (1); source.AddStatement (new Return (iterator, iterator.Location)); @@ -2781,26 +2831,27 @@ namespace Mono.CSharp { } // - // Returns a `ParameterReference' for the given name, or null if there - // is no such parameter + // Returns a parameter reference expression for the given name, + // or null if there is no such parameter // - public ParameterReference GetParameterReference (string name, Location loc) + public Expression GetParameterReference (string name, Location loc) { - ToplevelParameterInfo p = GetParameterInfo (name); - return p == null ? null : new ParameterReference (this, p, loc); - } - - public ToplevelParameterInfo GetParameterInfo (string name) - { - int idx; for (ToplevelBlock t = this; t != null; t = t.Container) { - Parameter par = t.Parameters.GetParameterByName (name, out idx); - if (par != null) - return t.parameter_info [idx]; + Expression expr = t.GetParameterReferenceExpression (name, loc); + if (expr != null) + return expr; } + return null; } + protected virtual Expression GetParameterReferenceExpression (string name, Location loc) + { + int idx = parameters.GetParameterIndexByName (name); + return idx < 0 ? + null : new ParameterReference (parameter_info [idx], loc); + } + // // Returns the "this" instance variable of this block. // See AddThisVariable() for more information. @@ -2839,7 +2890,7 @@ namespace Mono.CSharp { return this_variable == null || this_variable.IsThisAssigned (ec); } - public bool ResolveMeta (EmitContext ec, Parameters ip) + public bool ResolveMeta (EmitContext ec, ParametersCompiled ip) { int errors = Report.Errors; int orig_count = parameters.Count; @@ -3086,20 +3137,14 @@ namespace Mono.CSharp { FieldExpr switch_cache_field; static int unique_counter; -#if GMCS_SOURCE // - // Nullable Types support for GMCS. + // Nullable Types support // Nullable.Unwrap unwrap; protected bool HaveUnwrap { get { return unwrap != null; } } -#else - protected bool HaveUnwrap { - get { return false; } - } -#endif // // The types allowed to be implicitly cast from @@ -3551,6 +3596,7 @@ namespace Mono.CSharp { public static void Reset () { unique_counter = 0; + allowed_types = null; } public override bool Resolve (EmitContext ec) @@ -3561,18 +3607,18 @@ namespace Mono.CSharp { new_expr = SwitchGoverningType (ec, Expr); -#if GMCS_SOURCE if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) { - unwrap = Nullable.Unwrap.Create (Expr, ec); + unwrap = Nullable.Unwrap.Create (Expr, false); if (unwrap == null) return false; new_expr = SwitchGoverningType (ec, unwrap); } -#endif if (new_expr == null){ - Report.Error (151, loc, "A value of an integral type or string expected for switch"); + Report.Error (151, loc, + "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type", + TypeManager.CSharpName (Expr.Type)); return false; } @@ -3653,20 +3699,21 @@ namespace Mono.CSharp { void ResolveStringSwitchMap (EmitContext ec) { FullNamedExpression string_dictionary_type; -#if GMCS_SOURCE - MemberAccess system_collections_generic = new MemberAccess (new MemberAccess ( - new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc); - - string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary", - new TypeArguments (loc, - new TypeExpression (TypeManager.string_type, loc), - new TypeExpression (TypeManager.int32_type, loc)), loc); -#else - MemberAccess system_collections_generic = new MemberAccess ( - new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc); - - string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc); -#endif + if (TypeManager.generic_ienumerable_type != null) { + MemberAccess system_collections_generic = new MemberAccess (new MemberAccess ( + new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc); + + string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary", + new TypeArguments ( + new TypeExpression (TypeManager.string_type, loc), + new TypeExpression (TypeManager.int32_type, loc)), loc); + } else { + MemberAccess system_collections_generic = new MemberAccess ( + new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc); + + string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc); + } + Field field = new Field (ec.TypeContainer, string_dictionary_type, Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null); @@ -3679,11 +3726,10 @@ namespace Mono.CSharp { Elements.Clear (); string value = null; foreach (SwitchSection section in Sections) { + int last_count = init.Count; foreach (SwitchLabel sl in section.Labels) { - if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) { - value = null; + if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) continue; - } value = (string) sl.Converted; ArrayList init_args = new ArrayList (2); @@ -3692,15 +3738,18 @@ namespace Mono.CSharp { init.Add (new CollectionElementInitializer (init_args, loc)); } - if (value == null) + // + // Don't add empty sections + // + if (last_count == init.Count) continue; Elements.Add (counter, section.Labels [0]); ++counter; } - ArrayList args = new ArrayList (1); - args.Add (new Argument (new IntConstant (Sections.Count, loc))); + Arguments args = new Arguments (1); + args.Add (new Argument (new IntConstant (init.Count, loc))); Expression initializer = new NewInitialize (string_dictionary_type, args, new CollectionOrObjectInitializers (init, loc), loc); @@ -3727,36 +3776,37 @@ namespace Mono.CSharp { LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type); -#if GMCS_SOURCE - ArrayList get_value_args = new ArrayList (2); - get_value_args.Add (new Argument (value)); - get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out)); - Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec); - if (get_item == null) - return; + if (TypeManager.generic_ienumerable_type != null) { + Arguments get_value_args = new Arguments (2); + get_value_args.Add (new Argument (value)); + get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out)); + Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec); + if (get_item == null) + return; - // - // A value was not found, go to default case - // - get_item.EmitBranchable (ec, default_target, false); -#else - ArrayList get_value_args = new ArrayList (1); - get_value_args.Add (value); + // + // A value was not found, go to default case + // + get_item.EmitBranchable (ec, default_target, false); + } else { + Arguments get_value_args = new Arguments (1); + get_value_args.Add (new Argument (value)); - Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec); - if (get_item == null) - return; + Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec); + if (get_item == null) + return; - LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type); - get_item_object.EmitAssign (ec, get_item, true, false); - ec.ig.Emit (OpCodes.Brfalse, default_target); + LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type); + get_item_object.EmitAssign (ec, get_item, true, false); + ec.ig.Emit (OpCodes.Brfalse, default_target); - ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable, - new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (ec); + ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable, + new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (ec); + + get_item_int.EmitStatement (ec); + get_item_object.Release (ec); + } - get_item_int.EmitStatement (ec); - get_item_object.Release (ec); -#endif TableSwitchEmit (ec, string_switch_variable); string_switch_variable.Release (ec); } @@ -3773,12 +3823,10 @@ namespace Mono.CSharp { LocalTemporary value; if (HaveUnwrap) { value = new LocalTemporary (SwitchType); -#if GMCS_SOURCE unwrap.EmitCheck (ec); ig.Emit (OpCodes.Brfalse, null_target); new_expr.Emit (ec); value.Store (ec); -#endif } else if (!is_constant) { value = new LocalTemporary (SwitchType); new_expr.Emit (ec); @@ -4029,7 +4077,7 @@ namespace Mono.CSharp { if (expr == null) return false; - if (expr.Type.IsValueType){ + if (!TypeManager.IsReferenceType (expr.Type)){ Report.Error (185, loc, "`{0}' is not a reference type as required by the lock statement", TypeManager.CSharpName (expr.Type)); @@ -4248,81 +4296,51 @@ namespace Mono.CSharp { } } - class StringEmitter : Emitter { - class StringPtr : Expression - { - LocalBuilder b; - - public StringPtr (LocalBuilder b, Location l) - { - this.b = b; - eclass = ExprClass.Value; - type = TypeManager.char_ptr_type; - loc = l; - } - - public override Expression CreateExpressionTree (EmitContext ec) - { - throw new NotSupportedException ("ET"); - } - - public override Expression DoResolve (EmitContext ec) - { - // This should never be invoked, we are born in fully - // initialized state. - - return this; - } - - public override void Emit (EmitContext ec) - { - if (TypeManager.int_get_offset_to_string_data == null) { - // TODO: Move to resolve !! - TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod ( - TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes); - } - - ILGenerator ig = ec.ig; - - ig.Emit (OpCodes.Ldloc, b); - ig.Emit (OpCodes.Conv_I); - ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data); - ig.Emit (OpCodes.Add); - } - } - - LocalBuilder pinned_string; - Location loc; + class StringEmitter : Emitter + { + LocalInfo pinned_string; public StringEmitter (Expression expr, LocalInfo li, Location loc): base (expr, li) { - this.loc = loc; + pinned_string = new LocalInfo (new TypeExpression (TypeManager.string_type, loc), null, null, loc); + pinned_string.Pinned = true; } public override void Emit (EmitContext ec) { - ILGenerator ig = ec.ig; - pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type); - + pinned_string.Resolve (ec); + pinned_string.ResolveVariable (ec); + converted.Emit (ec); - ig.Emit (OpCodes.Stloc, pinned_string); + pinned_string.EmitAssign (ec); - Expression sptr = new StringPtr (pinned_string, loc); - converted = Convert.ImplicitConversionRequired ( - ec, sptr, vi.VariableType, loc); - - if (converted == null) - return; + PropertyInfo p = TypeManager.int_get_offset_to_string_data; + if (p == null) { + // TODO: Move to resolve + p = TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty ( + TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type); - converted.Emit (ec); + if (p == null) + return; + } + + // TODO: Should use Binary::Add + pinned_string.Emit (ec); + ec.ig.Emit (OpCodes.Conv_I); + + PropertyExpr pe = new PropertyExpr (pinned_string.VariableType, p, pinned_string.Location); + //pe.InstanceExpression = pinned_string; + pe.Resolve (ec).Emit (ec); + + ec.ig.Emit (OpCodes.Add); vi.EmitAssign (ec); } public override void EmitExit (EmitContext ec) { ec.ig.Emit (OpCodes.Ldnull); - ec.ig.Emit (OpCodes.Stloc, pinned_string); + pinned_string.EmitAssign (ec); } } @@ -4560,6 +4578,12 @@ namespace Mono.CSharp { // TODO: Move to resolve LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc); lvr.Resolve (ec); + +#if GMCS_SOURCE + // Only to make verifier happy + if (TypeManager.IsGenericParameter (lvr.Type)) + ig.Emit (OpCodes.Unbox_Any, lvr.Type); +#endif Expression source; if (lvr.IsHoisted) { @@ -4747,7 +4771,9 @@ namespace Mono.CSharp { Type resolved_type = c.CatchType; for (int ii = 0; ii < last_index; ++ii) { if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) { - Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName); + Report.Error (160, c.loc, + "A previous catch clause already catches all exceptions of this or a super type `{0}'", + TypeManager.CSharpName (prev_catches [ii])); ok = false; } } @@ -4758,7 +4784,7 @@ namespace Mono.CSharp { if (General != null) { if (CodeGen.Assembly.WrapNonExceptionThrows) { foreach (Catch c in Specific){ - if (c.CatchType == TypeManager.exception_type) { + if (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) { Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'"); } } @@ -4831,6 +4857,7 @@ namespace Mono.CSharp { } } + // FIXME: Why is it almost exact copy of Using ?? public class UsingTemporary : ExceptionStatement { TemporaryVariable local_copy; public Statement Statement; @@ -4891,7 +4918,7 @@ namespace Mono.CSharp { protected override void EmitFinallyBody (EmitContext ec) { ILGenerator ig = ec.ig; - if (!expr_type.IsValueType) { + if (!TypeManager.IsStruct (expr_type)) { Label skip = ig.DefineLabel (); local_copy.Emit (ec); ig.Emit (OpCodes.Brfalse, skip); @@ -4955,7 +4982,6 @@ namespace Mono.CSharp { Expression var; Expression init; - Expression converted_var; ExpressionStatement assign; public Using (Expression var, Expression init, Statement stmt, Location l) @@ -4966,31 +4992,6 @@ namespace Mono.CSharp { loc = l; } - bool ResolveVariable (EmitContext ec) - { - ExpressionStatement a = new SimpleAssign (var, init, loc); - a = a.ResolveStatement (ec); - if (a == null) - return false; - - assign = a; - - if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) { - converted_var = var; - return true; - } - - Expression e = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location); - if (e == null) { - Error_IsNotConvertibleToIDisposable (var); - return false; - } - - converted_var = e; - - return true; - } - static public void Error_IsNotConvertibleToIDisposable (Expression expr) { Report.SymbolRelatedToPreviousError (expr.Type); @@ -5011,42 +5012,18 @@ namespace Mono.CSharp { protected override void EmitFinallyBody (EmitContext ec) { ILGenerator ig = ec.ig; + Label skip = ig.DefineLabel (); - if (!var.Type.IsValueType) { - Label skip = ig.DefineLabel (); + bool emit_null_check = !TypeManager.IsValueType (var.Type); + if (emit_null_check) { var.Emit (ec); ig.Emit (OpCodes.Brfalse, skip); - converted_var.Emit (ec); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - ig.MarkLabel (skip); - } else { - Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null); - - if (!(ml is MethodGroupExpr)) { - var.Emit (ec); - ig.Emit (OpCodes.Box, var.Type); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - } else { - MethodInfo mi = null; - - foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) { - if (TypeManager.GetParameterData (mk).Count == 0) { - mi = mk; - break; - } - } - - if (mi == null) { - Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters."); - return; - } + } - IMemoryLocation mloc = (IMemoryLocation) var; + Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, null, loc); - mloc.AddressOf (ec, AddressOp.Load); - ig.Emit (OpCodes.Call, mi); - } - } + if (emit_null_check) + ig.MarkLabel (skip); } public override void MutateHoistedGenericType (AnonymousMethodStorey storey) @@ -5077,6 +5054,27 @@ namespace Mono.CSharp { return ok; } + bool ResolveVariable (EmitContext ec) + { + assign = new SimpleAssign (var, init, loc); + assign = assign.ResolveStatement (ec); + if (assign == null) + return false; + + if (assign.Type == TypeManager.idisposable_type || + TypeManager.ImplementsInterface (assign.Type, TypeManager.idisposable_type)) { + return true; + } + + Expression e = Convert.ImplicitConversionStandard (ec, assign, TypeManager.idisposable_type, var.Location); + if (e == null) { + Error_IsNotConvertibleToIDisposable (var); + return false; + } + + throw new NotImplementedException ("covariance?"); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { Using target = (Using) t; @@ -5154,7 +5152,7 @@ namespace Mono.CSharp { copy.Resolve (ec); int rank = length_exprs.Length; - ArrayList list = new ArrayList (rank); + Arguments list = new Arguments (rank); for (int i = 0; i < rank; i++) { counter [i] = new ArrayCounter (loc); counter [i].ResolveIncrement (ec); @@ -5165,12 +5163,12 @@ namespace Mono.CSharp { lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc); lengths [i].Resolve (ec); - ArrayList args = new ArrayList (1); + Arguments args = new Arguments (1); args.Add (new Argument (new IntConstant (i, loc))); length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec); } - list.Add (counter [i]); + list.Add (new Argument (counter [i])); } access = new ElementAccess (copy, list).Resolve (ec); @@ -5197,7 +5195,7 @@ namespace Mono.CSharp { ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc); ec.CurrentBranching.CreateSibling (); - for_each.variable = for_each.variable.ResolveLValue (ec, conv, loc); + for_each.variable = for_each.variable.ResolveLValue (ec, conv); if (for_each.variable == null) ok = false; @@ -5377,8 +5375,7 @@ namespace Mono.CSharp { // if (return_type == TypeManager.ienumerator_type || - TypeManager.ienumerator_type.IsAssignableFrom (return_type) || - (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) { + TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type)) { // // If it is not an interface, lets try to find the methods ourselves. // For example, if we have: @@ -5403,11 +5400,10 @@ namespace Mono.CSharp { TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type); } -#if GMCS_SOURCE // // Prefer a generic enumerator over a non-generic one. // - if (return_type.IsInterface && return_type.IsGenericType) { + if (return_type.IsInterface && TypeManager.IsGenericType (return_type)) { enumerator_type = return_type; if (!FetchGetCurrent (ec, return_type)) get_current = new PropertyExpr ( @@ -5416,7 +5412,6 @@ namespace Mono.CSharp { move_next = TypeManager.bool_movenext_void; return true; } -#endif if (return_type.IsInterface || !FetchMoveNext (return_type) || @@ -5450,14 +5445,10 @@ namespace Mono.CSharp { // bool FetchMoveNext (Type t) { - MemberList move_next_list; - - move_next_list = TypeContainer.FindMembers ( - t, MemberTypes.Method, + MemberInfo[] move_next_list = TypeManager.MemberLookup (null, null, t, + MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance, - Type.FilterName, "MoveNext"); - if (move_next_list.Count == 0) - return false; + "MoveNext", null); foreach (MemberInfo m in move_next_list){ MethodInfo mi = (MethodInfo) m; @@ -5487,31 +5478,6 @@ namespace Mono.CSharp { return true; } - // - // Retrieves a `public void Dispose ()' method from the Type `t' - // - static MethodInfo FetchMethodDispose (Type t) - { - MemberList dispose_list; - - dispose_list = TypeContainer.FindMembers ( - t, MemberTypes.Method, - BindingFlags.Public | BindingFlags.Instance, - Type.FilterName, "Dispose"); - if (dispose_list.Count == 0) - return null; - - foreach (MemberInfo m in dispose_list){ - MethodInfo mi = (MethodInfo) m; - - if (TypeManager.GetParameterData (mi).Count == 0){ - if (mi.ReturnType == TypeManager.void_type) - return mi; - } - } - return null; - } - void Error_Enumerator () { if (enumerator_found) { @@ -5654,9 +5620,6 @@ namespace Mono.CSharp { return false; } - bool is_disposable = !enumerator_type.IsSealed || - TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type); - VarExpr ve = var_type as VarExpr; if (ve != null) { // Infer implicitly typed local variable from foreach enumerable type @@ -5691,9 +5654,14 @@ namespace Mono.CSharp { loop = new While (move_next_expr, block, loc); - wrapper = is_disposable ? - (Statement) new DisposableWrapper (this) : - (Statement) new NonDisposableWrapper (this); + + bool implements_idisposable = TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type); + if (implements_idisposable || !enumerator_type.IsSealed) { + wrapper = new DisposableWrapper (this, implements_idisposable); + } else { + wrapper = new NonDisposableWrapper (this); + } + return wrapper.Resolve (ec); } @@ -5732,12 +5700,15 @@ namespace Mono.CSharp { } } - class DisposableWrapper : ExceptionStatement { + sealed class DisposableWrapper : ExceptionStatement + { CollectionForeach parent; + bool implements_idisposable; - internal DisposableWrapper (CollectionForeach parent) + internal DisposableWrapper (CollectionForeach parent, bool implements) { this.parent = parent; + this.implements_idisposable = implements; } protected override void CloneTo (CloneContext clonectx, Statement target) @@ -5777,7 +5748,30 @@ namespace Mono.CSharp { protected override void EmitFinallyBody (EmitContext ec) { - parent.EmitFinallyBody (ec); + Expression instance = parent.enumerator; + if (!TypeManager.IsValueType (parent.enumerator_type)) { + ILGenerator ig = ec.ig; + + parent.enumerator.Emit (ec); + + Label call_dispose = ig.DefineLabel (); + + if (!implements_idisposable) { + ec.ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type); + LocalTemporary temp = new LocalTemporary (TypeManager.idisposable_type); + temp.Store (ec); + temp.Emit (ec); + instance = temp; + } + + ig.Emit (OpCodes.Brtrue_S, call_dispose); + + // using 'endfinally' to empty the evaluation stack + ig.Emit (OpCodes.Endfinally); + ig.MarkLabel (call_dispose); + } + + Invocation.EmitCall (ec, false, instance, TypeManager.void_dispose_void, null, loc); } public override void MutateHoistedGenericType (AnonymousMethodStorey storey) @@ -5801,37 +5795,6 @@ namespace Mono.CSharp { loop.Emit (ec); } - void EmitFinallyBody (EmitContext ec) - { - ILGenerator ig = ec.ig; - - if (enumerator_type.IsValueType) { - MethodInfo mi = FetchMethodDispose (enumerator_type); - if (mi != null) { - enumerator.AddressOf (ec, AddressOp.Load); - ig.Emit (OpCodes.Call, mi); - } else { - enumerator.Emit (ec); - ig.Emit (OpCodes.Box, enumerator_type); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - } - } else { - Label call_dispose = ig.DefineLabel (); - - enumerator.Emit (ec); - ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type); - ig.Emit (OpCodes.Dup); - ig.Emit (OpCodes.Brtrue_S, call_dispose); - - // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block - // (Partition III, Section 3.35) - ig.Emit (OpCodes.Endfinally); - - ig.MarkLabel (call_dispose); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - } - } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) { enumerator_type = storey.MutateType (enumerator_type);