Better check for instance equality of generic types. Fixes #15100
[mono.git] / mcs / mcs / anonymous.cs
index 86658f897f0f170f860077a6c88ee50950c3d0d1..ce83e7674c14d88cc1b6c60145409209a83def58 100644 (file)
@@ -191,15 +191,27 @@ namespace Mono.CSharp {
                sealed class ThisInitializer : Statement
                {
                        readonly HoistedThis hoisted_this;
+                       readonly AnonymousMethodStorey parent;
 
-                       public ThisInitializer (HoistedThis hoisted_this)
+                       public ThisInitializer (HoistedThis hoisted_this, AnonymousMethodStorey parent)
                        {
                                this.hoisted_this = hoisted_this;
+                               this.parent = parent;
                        }
 
                        protected override void DoEmit (EmitContext ec)
                        {
-                               hoisted_this.EmitAssign (ec, new CompilerGeneratedThis (ec.CurrentType, loc), false, false);
+                               Expression source;
+
+                               if (parent == null)
+                                       source = new CompilerGeneratedThis (ec.CurrentType, loc);
+                               else {
+                                       source = new FieldExpr (parent.HoistedThis.Field, Location.Null) {
+                                               InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location.Null)
+                                       };
+                               }
+
+                               hoisted_this.EmitAssign (ec, source, false, false);
                        }
 
                        protected override void CloneTo (CloneContext clonectx, Statement target)
@@ -229,6 +241,7 @@ namespace Mono.CSharp {
                public Expression Instance;
 
                bool initialize_hoisted_this;
+               AnonymousMethodStorey hoisted_this_parent;
 
                public AnonymousMethodStorey (ExplicitBlock block, TypeDefinition parent, MemberBase host, TypeParameters tparams, string name, MemberKind kind)
                        : base (parent, MakeMemberName (host, name, parent.Module.CounterAnonymousContainers, tparams, block.StartLocation),
@@ -238,13 +251,14 @@ namespace Mono.CSharp {
                        ID = parent.Module.CounterAnonymousContainers++;
                }
 
-               public void AddCapturedThisField (EmitContext ec)
+               public void AddCapturedThisField (EmitContext ec, AnonymousMethodStorey parent)
                {
                        TypeExpr type_expr = new TypeExpression (ec.CurrentType, Location);
                        Field f = AddCompilerGeneratedField ("$this", type_expr);
                        hoisted_this = new HoistedThis (this, f);
 
                        initialize_hoisted_this = true;
+                       hoisted_this_parent = parent;
                }
 
                public Field AddCapturedVariable (string name, TypeSpec type)
@@ -315,8 +329,11 @@ namespace Mono.CSharp {
 
                        var hoisted = localVariable.HoistedVariant;
                        if (hoisted != null && hoisted.Storey != this && hoisted.Storey is StateMachine) {
-                               // TODO: It's too late the field is defined in HoistedLocalVariable ctor
+                               //
+                               // Variable is already hoisted but we need it in storey which can be shared
+                               //
                                hoisted.Storey.hoisted_locals.Remove (hoisted);
+                               hoisted.Storey.Members.Remove (hoisted.Field);
                                hoisted = null;
                        }
 
@@ -550,7 +567,7 @@ namespace Mono.CSharp {
                        // referenced indirectly
                        //
                        if (initialize_hoisted_this) {
-                               rc.CurrentBlock.AddScopeStatement (new ThisInitializer (hoisted_this));
+                               rc.CurrentBlock.AddScopeStatement (new ThisInitializer (hoisted_this, hoisted_this_parent));
                        }
 
                        //
@@ -728,6 +745,12 @@ namespace Mono.CSharp {
                        this.field = field;
                }
 
+               public Field Field {
+                       get {
+                               return field;
+                       }
+               }
+
                public AnonymousMethodStorey Storey {
                        get {
                                return storey;
@@ -848,12 +871,6 @@ namespace Mono.CSharp {
 
                #region Properties
 
-               public Field Field {
-                       get {
-                               return field;
-                       }
-               }
-
                public bool IsAssigned { get; set; }
 
                public ParameterReference Parameter {
@@ -893,12 +910,6 @@ namespace Mono.CSharp {
                        : base (storey, field)
                {
                }
-
-               public Field Field {
-                       get {
-                               return field;
-                       }
-               }
        }
 
        //
@@ -959,6 +970,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               public override bool IsSideEffectFree {
+                       get {
+                               return true;
+                       }
+               }
+
                public ParametersCompiled Parameters {
                        get {
                                return Block.Parameters;
@@ -1010,9 +1027,9 @@ namespace Mono.CSharp {
                        return null;
                }
 
-               protected bool VerifyExplicitParameters (ResolveContext ec, TypeSpec delegate_type, AParametersCollection parameters)
+               protected bool VerifyExplicitParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type, AParametersCollection parameters)
                {
-                       if (VerifyParameterCompatibility (ec, delegate_type, parameters, ec.IsInProbingMode))
+                       if (VerifyParameterCompatibility (ec, tic, delegate_type, parameters, ec.IsInProbingMode))
                                return true;
 
                        if (!ec.IsInProbingMode)
@@ -1023,7 +1040,7 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               protected bool VerifyParameterCompatibility (ResolveContext ec, TypeSpec delegate_type, AParametersCollection invoke_pd, bool ignore_errors)
+               protected bool VerifyParameterCompatibility (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegate_type, AParametersCollection invoke_pd, bool ignore_errors)
                {
                        if (Parameters.Count != invoke_pd.Count) {
                                if (ignore_errors)
@@ -1056,14 +1073,11 @@ namespace Mono.CSharp {
                                        continue;
 
                                TypeSpec type = invoke_pd.Types [i];
+
+                               if (tic != null)
+                                       type = tic.InflateGenericArgument (ec, type);
                                
-                               //
-                               // Assumes that generic mvar parameters are always inflated
-                               //
-                               if (ImplicitDelegateCreation.ContainsMethodTypeParameter (type))
-                                       continue;
-                               
-                               if (!TypeSpecComparer.IsEqual (invoke_pd.Types [i], Parameters.Types [i])) {
+                               if (!TypeSpecComparer.IsEqual (type, Parameters.Types [i])) {
                                        if (ignore_errors)
                                                return false;
                                        
@@ -1081,7 +1095,7 @@ namespace Mono.CSharp {
                //
                // Infers type arguments based on explicit arguments
                //
-               public bool ExplicitTypeInference (ResolveContext ec, TypeInferenceContext type_inference, TypeSpec delegate_type)
+               public bool ExplicitTypeInference (TypeInferenceContext type_inference, TypeSpec delegate_type)
                {
                        if (!HasExplicitParameters)
                                return false;
@@ -1295,7 +1309,7 @@ namespace Mono.CSharp {
                                return ParametersCompiled.CreateFullyResolved (fixedpars, delegate_parameters.Types);
                        }
 
-                       if (!VerifyExplicitParameters (ec, delegate_type, delegate_parameters)) {
+                       if (!VerifyExplicitParameters (ec, tic, delegate_type, delegate_parameters)) {
                                return null;
                        }
 
@@ -1663,7 +1677,7 @@ namespace Mono.CSharp {
                                                // enough. No hoisted variables only 'this' and don't need to
                                                // propagate this to value type state machine.
                                                //
-                                               StateMachine sm_parent = null;
+                                               StateMachine sm_parent;
                                                var pb = src_block.ParametersBlock;
                                                do {
                                                        sm_parent = pb.StateMachine;
@@ -1675,18 +1689,17 @@ namespace Mono.CSharp {
                                                } else if (sm_parent.Kind == MemberKind.Struct) {
                                                        //
                                                        // Special case where parent class is used to emit instance method
-                                                       // because currect storey is of value type (async host). We cannot
+                                                       // because currect storey is of value type (async host) and we cannot
                                                        // use ldftn on non-boxed instances either to share mutated state
                                                        //
                                                        parent = sm_parent.Parent.PartialContainer;
+                                               } else if (sm is IteratorStorey) {
+                                                       //
+                                                       // For iterators we can host everything in one class
+                                                       //
+                                                       parent = storey = sm;
                                                }
                                        }
-
-                                       //
-                                       // For iterators we can host everything in one class
-                                       //
-                                       if (sm is IteratorStorey)
-                                               parent = storey = sm;
                                }
 
                                modifiers = storey != null ? Modifiers.INTERNAL : Modifiers.PRIVATE;
@@ -1809,12 +1822,8 @@ namespace Mono.CSharp {
                                // Special case for value type storey where this is not lifted but
                                // droped off to parent class
                                //
-                               for (var b = Block.Parent; b != null; b = b.Parent) {
-                                       if (b.ParametersBlock.StateMachine != null) {
-                                               ec.Emit (OpCodes.Ldfld, b.ParametersBlock.StateMachine.HoistedThis.Field.Spec);
-                                               break;
-                                       }
-                               }
+                               if (ec.CurrentAnonymousMethod != null && ec.AsyncTaskStorey != null)
+                                       ec.Emit (OpCodes.Ldfld, ec.AsyncTaskStorey.HoistedThis.Field.Spec);
                        }
 
                        var delegate_method = method.Spec;
@@ -1993,7 +2002,7 @@ namespace Mono.CSharp {
 
                        Method tostring = new Method (this, new TypeExpression (Compiler.BuiltinTypes.String, loc),
                                Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("ToString", loc),
-                               Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null);
+                               ParametersCompiled.EmptyReadOnlyParameters, null);
 
                        ToplevelBlock equals_block = new ToplevelBlock (Compiler, equals.ParameterInfo, loc);
 
@@ -2102,7 +2111,7 @@ namespace Mono.CSharp {
                        Method hashcode = new Method (this, new TypeExpression (Compiler.BuiltinTypes.Int, loc),
                                Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN,
                                new MemberName ("GetHashCode", loc),
-                               Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null);
+                               ParametersCompiled.EmptyReadOnlyParameters, null);
 
                        //
                        // Modified FNV with good avalanche behavior and uniform