Repository: dotnet/roslyn
Pull request #77675: Extensions: definite assignment and region analysis
Author: login: jcouv
Labels: name: Area-Compilers
name: Feature - Extension Everything
description: The extension everything feature
name: untriaged
description: Issues and PRs which have not yet been triaged by a lead
Created: 2025-03-19T07:24:56Z | Merged: 2025-03-21T21:35:20Z

I chose to keep `TryGetThisParameter`/`MethodThisParameter` returning a proper `this` symbol for instance methods (rather than `null`). But it's disallowed to use it (via `HasThis`).

Relates to test plan https://github.com/dotnet/roslyn/issues/76130


Diff:
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
index 2fd89abcf810f..a16cb0ef9c6ba 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
@@ -48,6 +48,11 @@ internal bool HasThis(bool isExplicit, out bool inStaticContext)
                 return false;
             }
 
+            if (memberOpt?.GetIsNewExtensionMember() == true)
+            {
+                return false;
+            }
+
             var containingType = memberOpt?.ContainingType;
             bool inTopLevelScriptMember = (object)containingType != null && containingType.IsScriptClass;
 
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractRegionDataFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractRegionDataFlowPass.cs
index 153aa9b03f482..237b2ab5ad9e2 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractRegionDataFlowPass.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractRegionDataFlowPass.cs
@@ -33,6 +33,10 @@ protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
         {
             MakeSlots(MethodParameters);
             if ((object)MethodThisParameter != null) GetOrCreateSlot(MethodThisParameter);
+
+            if (TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter))
+                GetOrCreateSlot(extensionParameter);
+
             var result = base.Scan(ref badRegion);
             return result;
         }
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs
index b7a4bc7d33d4b..9a777aef96b1a 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs
@@ -368,6 +368,12 @@ protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
                 }
             }
 
+            ParameterSymbol extensionParameter = null;
+            if (TryGetInstanceExtensionParameter(out extensionParameter))
+            {
+                EnterParameter(extensionParameter);
+            }
+
             ImmutableArray<PendingBranch> pendingReturns = base.Scan(ref badRegion);
 
             // check that each out parameter is definitely assigned at the end of the method.  If
@@ -378,6 +384,7 @@ protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
             {
                 LeaveParameters(methodParameters, null, location);
                 if ((object)methodThisParameter != null) LeaveParameter(methodThisParameter, null, location);
+                if ((object)extensionParameter != null) LeaveParameter(extensionParameter, null, location);
 
                 var savedState = this.State;
                 foreach (PendingBranch returnBranch in pendingReturns)
@@ -385,6 +392,7 @@ protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
                     this.State = returnBranch.State;
                     LeaveParameters(methodParameters, returnBranch.Branch.Syntax, null);
                     if ((object)methodThisParameter != null) LeaveParameter(methodThisParameter, returnBranch.Branch.Syntax, null);
+                    if ((object)extensionParameter != null) LeaveParameter(extensionParameter, returnBranch.Branch.Syntax, null);
                     Join(ref savedState, ref this.State);
                 }
 
@@ -394,6 +402,21 @@ protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
             return pendingReturns;
         }
 
+        protected bool TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter)
+        {
+            if (_symbol is not null
+                && _symbol.GetIsNewExtensionMember()
+                && !_symbol.IsStatic
+                && _symbol.ContainingType.ExtensionParameter is { } foundExtensionParameter)
+            {
+                extensionParameter = foundExtensionParameter;
+                return true;
+            }
+
+            extensionParameter = null;
+            return false;
+        }
+
         protected override ImmutableArray<PendingBranch> RemoveReturns()
         {
             var result = base.RemoveReturns();
@@ -1832,6 +1855,18 @@ protected override LocalState TopState()
                             }
                         }
                     }
+
+                    if (TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter))
+                    {
+                        if (extensionParameter.RefKind != RefKind.Out)
+                        {
+                            int slot = GetOrCreateSlot(extensionParameter);
+                            if (slot > 0)
+                            {
+                                SetSlotAssigned(slot, ref topState);
+                            }
+                        }
+                    }
                 }
 
                 Symbol containing = current.ContainingSymbol;
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
index fef182b6f8b34..6d52dc0e1d95d 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
@@ -592,6 +592,7 @@ protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
                 {
                     EnterParameter(methodThisParameter, methodThisParameter.TypeWithAnnotations);
                 }
+                // PROTOTYPE should register the extension parameter
 
                 makeNotNullMembersMaybeNull();
                 // We need to create a snapshot even of the first node, because we want to have the state of the initial parameters.
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs
index 427d6080634fa..f8ab64f419aa5 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs
@@ -87,6 +87,11 @@ protected override void EnterRegion()
                         if (p.RefKind != RefKind.None) _readOutside.Add(p);
                     }
 
+                    if (TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter) && extensionParameter.RefKind != RefKind.None)
+                    {
+                        _readOutside.Add(extensionParameter);
+                    }
+
                     Debug.Assert(!ignoreThisParameter || m is SynthesizedPrimaryConstructor);
 
                     if (!ignoreThisParameter)
diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs
index d8ce97fa4088f..26b8010c98131 100644
--- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs
@@ -284,6 +284,8 @@ public override BoundNode VisitParameter(BoundParameter node)
 
         private void TryHoistTopLevelParameter(BoundParameter node)
         {
+            Debug.Assert(!topLevelMethod.GetIsNewExtensionMember()); // extension methods were replaced with implementation methods earlier in the pipeline
+
             if (node.ParameterSymbol.ContainingSymbol == topLevelMethod)
             {
                 CaptureVariable(node.ParameterSymbol, node.Syntax);
diff --git a/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs
index 7d0f900cf6a3f..5991c132e2d90 100644
--- a/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs
@@ -86,7 +86,7 @@ internal static bool GetIsNewExtensionMember(this Symbol member)
                 case SymbolKind.Property:
                     return member.ContainingSymbol is TypeSymbol { IsExtension: true };
                 default:
-                    throw ExceptionUtilities.UnexpectedValue(member.Kind);
+                    return false;
             }
         }
 
diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs
index db548eb136c2a..1b843d8c13d89 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs
@@ -9,7 +9,6 @@
 using System.Collections.Immutable;
 using System.Diagnostics;
 using System.Globalization;
-using System.Reflection.Metadata;
 using System.Runtime.InteropServices;
 using System.Text;
 using System.Threading;
@@ -1742,6 +1741,13 @@ internal static bool IsCaptured(Symbol variable, SourceMethodSymbol containingSy
                     throw ExceptionUtilities.UnexpectedValue(variable.Kind);
             }
 
+            if (containingSymbol.GetIsNewExtensionMember()
+                && variable is ParameterSymbol { ContainingSymbol: TypeSymbol { IsExtension: true } })
+            {
+                // An extension member doesn't capture the extension parameter
+                return false;
+            }
+
             // Walk up the containing symbols until we find the target function, in which
             // case the variable is not captured by the target function, or null, in which
             // case it is.
diff --git a/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTestBase.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTestBase.cs
index 928ebdceec7b5..064bbfa34fd2b 100644
--- a/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTestBase.cs
+++ b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTestBase.cs
@@ -44,6 +44,26 @@ internal ImmutableArray<Diagnostic> FlowDiagnostics(CSharpCompilation compilatio
             return flowDiagnostics.ToReadOnlyAndFree().Diagnostics;
         }
 
+        protected static void VerifyDataFlowAnalysis(string expected, DataFlowAnalysis result)
+        {
+            var actual = $$"""
+VariablesDeclared: {{GetSymbolNamesJoined(result.VariablesDeclared)}}
+AlwaysAssigned: {{GetSymbolNamesJoined(result.AlwaysAssigned)}}
+Captured: {{GetSymbolNamesJoined(result.Captured)}}
+CapturedInside: {{GetSymbolNamesJoined(result.CapturedInside)}}
+CapturedOutside: {{GetSymbolNamesJoined(result.CapturedOutside)}}
+DataFlowsIn: {{GetSymbolNamesJoined(result.DataFlowsIn)}}
+DataFlowsOut: {{GetSymbolNamesJoined(result.DataFlowsOut)}}
+DefinitelyAssignedOnEntry: {{GetSymbolNamesJoined(result.DefinitelyAssignedOnEntry)}}
+DefinitelyAssignedOnExit: {{GetSymbolNamesJoined(result.DefinitelyAssignedOnExit)}}
+ReadInside: {{GetSymbolNamesJoined(result.ReadInside)}}
+ReadOutside: {{GetSymbolNamesJoined(result.ReadOutside)}}
+WrittenInside: {{GetSymbolNamesJoined(result.WrittenInside)}}
+WrittenOutside: {{GetSymbolNamesJoined(result.WrittenOutside)}}
+""";
+            AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, actual);
+        }
+
         private IEnumerable<MethodSymbol> AllMethods(Symbol symbol)
         {
             switch (symbol.Kind)
diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
index 4a0de50e897b5..f70249ff18948 100644
--- a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
+++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
@@ -2640,21 +2640,28 @@ public void ReceiverParameter_Out_01()
         var src = """
 public static class Extensions
 {
-    extension(out int i) { }
+    extension(out int i)
+    {
+        void M2() { }
+        static void M3() { }
+    }
     static void M(this out int i) { }
 }
 """;
         var comp = CreateCompilation(src);
         comp.VerifyEmitDiagnostics(
             // (3,15): error CS8328:  The parameter modifier 'out' cannot be used with 'extension'
-            //     extension(out int i) { }
+            //     extension(out int i)
             Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15),
-            // (4,17): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
+            // (5,14): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
+            //         void M2() { }
+            Diagnostic(ErrorCode.ERR_ParamUnassigned, "M2").WithArguments("i").WithLocation(5, 14),
+            // (8,17): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
             //     static void M(this out int i) { }
-            Diagnostic(ErrorCode.ERR_ParamUnassigned, "M").WithArguments("i").WithLocation(4, 17),
-            // (4,24): error CS8328:  The parameter modifier 'out' cannot be used with 'this'
+            Diagnostic(ErrorCode.ERR_ParamUnassigned, "M").WithArguments("i").WithLocation(8, 17),
+            // (8,24): error CS8328:  The parameter modifier 'out' cannot be used with 'this'
             //     static void M(this out int i) { }
-            Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "this").WithLocation(4, 24));
+            Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "this").WithLocation(8, 24));
 
         var tree = comp.SyntaxTrees[0];
         var model = comp.GetSemanticModel(tree);
@@ -2700,6 +2707,60 @@ public static class Extensions
             Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 19));
     }
 
+    [Fact]
+    public void ReceiverParameter_Out_04()
+    {
+        var src = """
+public static class Extensions
+{
+    extension(out int i)
+    {
+        void M2(bool b) { if (b) return; else return; }
+    }
+    static void M(this out int i, bool b) { if (b) return; else return; }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (3,15): error CS8328:  The parameter modifier 'out' cannot be used with 'extension'
+            //     extension(out int i)
+            Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15),
+            // (5,34): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
+            //         void M2(bool b) { if (b) return; else return; }
+            Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(5, 34),
+            // (5,47): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
+            //         void M2(bool b) { if (b) return; else return; }
+            Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(5, 47),
+            // (7,24): error CS8328:  The parameter modifier 'out' cannot be used with 'this'
+            //     static void M(this out int i, bool b) { if (b) return; else return; }
+            Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "this").WithLocation(7, 24),
+            // (7,52): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
+            //     static void M(this out int i, bool b) { if (b) return; else return; }
+            Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(7, 52),
+            // (7,65): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
+            //     static void M(this out int i, bool b) { if (b) return; else return; }
+            Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("i").WithLocation(7, 65));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Out_05()
+    {
+        var src = """
+public static class Extensions
+{
+    extension(out int i)
+    {
+        void M2(bool b) { i = 0; }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (3,15): error CS8328:  The parameter modifier 'out' cannot be used with 'extension'
+            //     extension(out int i)
+            Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15));
+    }
+
     [Fact]
     public void ReceiverParameter_In_01()
     {
@@ -15948,12 +16009,9 @@ static class E
     public static ref string M(this ref string s) => ref s;
 }
 """;
-        // PROTOTYPE unexpected definite assignment error and missing error on extension parameter
+        // PROTOTYPE missing error on extension parameter
         var comp = CreateCompilation(src);
         comp.VerifyEmitDiagnostics(
-            // (12,36): error CS0165: Use of unassigned local variable 's'
-            //         public ref string f => ref s;
-            Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(12, 36),
             // (15,30): error CS8337: The first parameter of a 'ref' extension method 'M' must be a value type or a generic type constrained to struct.
             //     public static ref string M(this ref string s) => ref s;
             Diagnostic(ErrorCode.ERR_RefExtensionMustBeValueTypeOrConstrainedToOne, "M").WithArguments("M").WithLocation(15, 30));
@@ -28402,4 +28460,593 @@ static void verifySymbolInfo(CSharpCompilation comp, bool newLangVer)
             }
         }
     }
+
+    [Fact]
+    public void This_01()
+    {
+        var src = """
+static class E
+{
+    extension(object)
+    {
+        public void M()
+        {
+            var x = this;
+            this.ToString();
+            local();
+
+            void local()
+            {
+                var y = this;
+            }
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,21): error CS0027: Keyword 'this' is not available in the current context
+            //             var x = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(7, 21),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.ToString();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13),
+            // (13,25): error CS0027: Keyword 'this' is not available in the current context
+            //                 var y = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 25));
+    }
+
+    [Fact]
+    public void This_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+            this.M2();
+            M2(new object());
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.M2();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13));
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Null(model.GetSymbolInfo(invocation).Symbol);
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "this.M2()");
+        Assert.Equal("void E.<>E__0.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2(new object())");
+        Assert.Equal("void E.M2(this System.Object o)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void This_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void This_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Equal("void E.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_01()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0176: Member 'E.extension(object).M2()' cannot be accessed with an instance reference; qualify it with a type name instead
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_ObjectProhibited, "o.M2").WithArguments("E.extension(object).M2()").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS9512: Cannot use extension parameter 'object o' in this context.
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "o").WithArguments("object o").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            local();
+            void local()
+            {
+                o.M2();
+            }
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_05()
+    {
+        var src = """
+static class E
+{
+    extension(object o, object o2)
+    {
+        public void M()
+        {
+            o2.ToString();
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (3,25): error CS9504: An extension container can have only one receiver parameter
+            //     extension(object o, object o2)
+            Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "object o2").WithLocation(3, 25),
+            // (7,13): error CS0103: The name 'o2' does not exist in the current context
+            //             o2.ToString();
+            Diagnostic(ErrorCode.ERR_NameNotInContext, "o2").WithArguments("o2").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_06()
+    {
+        var src = """
+static class E
+{
+    extension(System.Span<int> s)
+    {
+        public async void M()
+        {
+            s.ToString();
+            await System.Threading.Tasks.Task.Yield();
+            s.ToString();
+        }
+    }
+}
+""";
+        // PROTOTYPE we should produce this error instead:
+        // error CS4012: Parameters of type 'Span<int>' cannot be declared in async methods or async lambda expressions.
+        var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
+            //             s.ToString();
+            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span<int>").WithLocation(7, 13),
+            // (9,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
+            //             s.ToString();
+            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span<int>").WithLocation(9, 13));
+    }
+
+    public partial class RegionAnalysisTests : FlowTestBase
+    {
+        // PROTOTYPE consider removing `this` from the region analysis tests
+        [Fact]
+        public void RegionAnalysis_01()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            _ = /*<bind>*/i + i2/*</bind>*/;
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: i, i2
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: i, i2
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_02()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            /*<bind>*/this.ToString()/*</bind>*/;
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: this
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: this
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_03()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            int i3 = 0;
+/*<bind>*/
+            System.Action<int> = () => i + i2 + i3;
+/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured: i, i2, i3
+CapturedInside: i, i2, i3
+CapturedOutside:
+DataFlowsIn: i, i2, i3
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2, i3
+DefinitelyAssignedOnExit: i, this, i2, i3
+ReadInside: i, i2, i3
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2, i3
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_04()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(ref int i)
+    {
+        public void M(ref int i2)
+        {
+            _ = /*<bind>*/i + i2/*</bind>*/;
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: i, i2
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: i, i2
+ReadOutside: i, i2
+WrittenInside:
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_05()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(out int i)
+    {
+        public void M(out int i2)
+        {
+            /*<bind>*/i = i2 = 0;/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i, i2
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn:
+DataFlowsOut: i, i2
+DefinitelyAssignedOnEntry: this
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside:
+ReadOutside: i, i2
+WrittenInside: i, i2
+WrittenOutside: this
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_06()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            /*<bind>*/i = i2 = 0;/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i, i2
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn:
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside:
+ReadOutside:
+WrittenInside: i, i2
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_07()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(ref int i)
+    {
+        public void M(ref int i2)
+        {
+            /*<bind>*/i = ref i2;/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: i2
+DataFlowsOut: i, i2
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: i2
+ReadOutside: i, i2
+WrittenInside: i, i2
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_08()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            void local(int i3)
+            {
+                _ = /*<bind>*/i + i2 + i3/*</bind>*/;
+            }
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured: i, i2
+CapturedInside: i, i2
+CapturedOutside:
+DataFlowsIn: i3
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2, i3
+DefinitelyAssignedOnExit: i, this, i2, i3
+ReadInside: i, i2, i3
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2, i3
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_09()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(out int i)
+    {
+        public void M(out int i2)
+        {
+            void local(out int i3)
+            {
+                /*<bind>*/i = i2 = i3 = 0;/*</bind>*/
+            }
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i, i2, i3
+Captured: i, i2
+CapturedInside: i, i2
+CapturedOutside:
+DataFlowsIn:
+DataFlowsOut: i, i2, i3
+DefinitelyAssignedOnEntry: this
+DefinitelyAssignedOnExit: i, this, i2, i3
+ReadInside:
+ReadOutside: i, i2, i3
+WrittenInside: i, i2, i3
+WrittenOutside: this
+""", analysisResults);
+        }
+    }
+
+    [Fact]
+    public void Base_01()
+    {
+        var src = """
+static class E
+{
+    extension(object)
+    {
+        public void M()
+        {
+            base.ToString();
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS1512: Keyword 'base' is not available in the current context
+            //             base.ToString();
+            Diagnostic(ErrorCode.ERR_BaseInBadContext, "base").WithLocation(7, 13));
+    }
 }


Reviews:
user: login: AlekseyTs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T17:48:34Z
user: login: AlekseyTs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T17:52:02Z
user: login: AlekseyTs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T18:00:13Z
user: login: AlekseyTs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T18:05:11Z
user: login: AlekseyTs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T18:12:23Z
user: login: AlekseyTs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T18:12:44Z
user: login: jcouv
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T04:01:17Z
user: login: AlekseyTs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T04:55:54Z
user: login: AlekseyTs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T04:57:21Z
user: login: AlekseyTs
body: LGTM (commit 3)
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T04:58:01Z
user: login: jjonescz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T10:16:37Z
user: login: jcouv
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T18:28:56Z
user: login: AlekseyTs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T19:02:41Z
user: login: jcouv
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T19:47:06Z
user: login: jjonescz
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-21T20:01:33Z

Review comments:
diff_hunk: @@ -1832,6 +1852,16 @@ protected override LocalState TopState()
                             }
                         }
                     }
+
+                    if (TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter))
+                    {
+                        Debug.Assert(thisParameter.RefKind != RefKind.Out);
path: src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs
user: login: AlekseyTs
body: >Debug.Assert(thisParameter.RefKind != RefKind.Out); [](http://example.com/codeflow?start=24&length=51)

Is this true even in an error scenario? #Closed
created_at: 2025-03-20T17:48:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -79,23 +79,6 @@ internal static bool GetIsVararg(this Symbol member)
 
 #nullable enable
         internal static bool GetIsNewExtensionMember(this Symbol member)
-        {
-            switch (member.Kind)
-            {
-                case SymbolKind.Method:
-                case SymbolKind.Property:
-                    return member.ContainingSymbol is TypeSymbol { IsExtension: true };
-                default:
-                    throw ExceptionUtilities.UnexpectedValue(member.Kind);
-            }
-        }
-
-        internal static bool GetIsNewExtensionMember(this MethodSymbol member)
path: src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs
user: login: AlekseyTs
body: >nternal static bool GetIsNewExtensionMember(this MethodSymbol member) [](http://example.com/codeflow?start=9&length=69)

I do not understand why these overloads are removed. I intentionally added them to avoid the need to check the symbol kind #Closed
created_at: 2025-03-20T17:52:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1742,6 +1741,11 @@ internal static bool IsCaptured(Symbol variable, SourceMethodSymbol containingSy
                     throw ExceptionUtilities.UnexpectedValue(variable.Kind);
             }
 
+            if (containingSymbol.GetIsNewExtensionMember() && ReferenceEquals(variable.ContainingSymbol, containingSymbol.ContainingSymbol))
path: src/Compilers/CSharp/Portable/Symbols/Symbol.cs
user: login: AlekseyTs
body: >ReferenceEquals(variable.ContainingSymbol, containingSymbol.ContainingSymbol) [](http://example.com/codeflow?start=62&length=77)

Is this an indirect/veiled way to check whether the ```variable``` is an extension parameter? Consider checking for that explicitly instead. #Closed
created_at: 2025-03-20T18:00:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24753,4 +24752,419 @@ public static void M<U>(U u) { }
             // object.M<string, long>(42);
             Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension<string>(string).M<long>(long)", "string").WithLocation(1, 1));
     }
+
+    [Fact]
+    public void This_01()
+    {
+        var src = """
+static class E
+{
+    extension(object)
+    {
+        public void M()
+        {
+            var x = this;
+            this.ToString();
+            local();
+
+            void local()
+            {
+                var y = this;
+            }
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,21): error CS0027: Keyword 'this' is not available in the current context
+            //             var x = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(7, 21),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.ToString();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13),
+            // (13,25): error CS0027: Keyword 'this' is not available in the current context
+            //                 var y = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 25));
+    }
+
+    [Fact]
+    public void This_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+            this.M2();
+            M2(new object());
+        }
+        public void M2() { }
+    }
+}
+""";
+        // PROTOTYPE confirm expectations
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.M2();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13));
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Null(model.GetSymbolInfo(invocation).Symbol);
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "this.M2()");
+        Assert.Equal("void E.<>E__0.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2(new object())");
+        Assert.Equal("void E.M2(this System.Object o)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void This_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void This_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Equal("void E.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_01()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0176: Member 'E.extension(object).M2()' cannot be accessed with an instance reference; qualify it with a type name instead
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_ObjectProhibited, "o.M2").WithArguments("E.extension(object).M2()").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0103: The name 'o' does not exist in the current context
path: src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
user: login: AlekseyTs
body: >// (7,13): error CS0103: The name 'o' does not exist in the current context [](http://example.com/codeflow?start=12&length=75)

This test is going to cause a conflict with #77704 #Closed
created_at: 2025-03-20T18:05:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24753,4 +24752,419 @@ public static void M<U>(U u) { }
             // object.M<string, long>(42);
             Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension<string>(string).M<long>(long)", "string").WithLocation(1, 1));
     }
+
+    [Fact]
+    public void This_01()
+    {
+        var src = """
+static class E
+{
+    extension(object)
+    {
+        public void M()
+        {
+            var x = this;
+            this.ToString();
+            local();
+
+            void local()
+            {
+                var y = this;
+            }
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,21): error CS0027: Keyword 'this' is not available in the current context
+            //             var x = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(7, 21),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.ToString();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13),
+            // (13,25): error CS0027: Keyword 'this' is not available in the current context
+            //                 var y = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 25));
+    }
+
+    [Fact]
+    public void This_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+            this.M2();
+            M2(new object());
+        }
+        public void M2() { }
+    }
+}
+""";
+        // PROTOTYPE confirm expectations
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.M2();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13));
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Null(model.GetSymbolInfo(invocation).Symbol);
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "this.M2()");
+        Assert.Equal("void E.<>E__0.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2(new object())");
+        Assert.Equal("void E.M2(this System.Object o)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void This_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void This_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Equal("void E.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_01()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0176: Member 'E.extension(object).M2()' cannot be accessed with an instance reference; qualify it with a type name instead
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_ObjectProhibited, "o.M2").WithArguments("E.extension(object).M2()").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0103: The name 'o' does not exist in the current context
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            local();
+            void local()
+            {
+                o.M2();
+            }
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_05()
+    {
+        var src = """
+static class E
+{
+    extension(object o, object o2)
+    {
+        public void M()
+        {
+            o2.ToString();
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (3,25): error CS9504: An extension container can have only one receiver parameter
+            //     extension(object o, object o2)
+            Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "object o2").WithLocation(3, 25),
+            // (7,13): error CS0103: The name 'o2' does not exist in the current context
+            //             o2.ToString();
+            Diagnostic(ErrorCode.ERR_NameNotInContext, "o2").WithArguments("o2").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_06()
+    {
+        var src = """
+static class E
+{
+    extension(System.Span<int> s)
+    {
+        public async void M()
+        {
+            s.ToString();
+            await System.Threading.Tasks.Task.Yield();
+            s.ToString();
+        }
+    }
+}
+""";
+        // PROTOTYPE we should produce this error instead:
+        // error CS4012: Parameters of type 'Span<int>' cannot be declared in async methods or async lambda expressions.
+        var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
+            //             s.ToString();
+            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span<int>").WithLocation(7, 13),
+            // (9,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
+            //             s.ToString();
+            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span<int>").WithLocation(9, 13));
+    }
+
+    public partial class RegionAnalysisTests : FlowTestBase
+    {
+        [Fact]
+        public void RegionAnalysis_01()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            _ = /*<bind>*/i + i2/*</bind>*/;
+        }
+    }
+}
+""");
+            Assert.Null(GetSymbolNamesJoined(analysisResults.VariablesDeclared));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.AlwaysAssigned));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.Captured));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.CapturedInside));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.CapturedOutside));
+            Assert.Equal("i, i2", GetSymbolNamesJoined(analysisResults.DataFlowsIn));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.DataFlowsOut));
+            Assert.Equal("i, this, i2", GetSymbolNamesJoined(analysisResults.DefinitelyAssignedOnEntry));
+            Assert.Equal("i, this, i2", GetSymbolNamesJoined(analysisResults.DefinitelyAssignedOnExit));
+            Assert.Equal("i, i2", GetSymbolNamesJoined(analysisResults.ReadInside));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.ReadOutside));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.WrittenInside));
+            Assert.Equal("i, this, i2", GetSymbolNamesJoined(analysisResults.WrittenOutside));
+        }
+
+        [Fact]
+        public void RegionAnalysis_02()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            /*<bind>*/this.ToString()/*</bind>*/;
+        }
+    }
+}
+""");
+            Assert.Null(GetSymbolNamesJoined(analysisResults.VariablesDeclared));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.AlwaysAssigned));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.Captured));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.CapturedInside));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.CapturedOutside));
+            Assert.Equal("this", GetSymbolNamesJoined(analysisResults.DataFlowsIn));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.DataFlowsOut));
+            Assert.Equal("i, this, i2", GetSymbolNamesJoined(analysisResults.DefinitelyAssignedOnEntry));
+            Assert.Equal("i, this, i2", GetSymbolNamesJoined(analysisResults.DefinitelyAssignedOnExit));
+            Assert.Equal("this", GetSymbolNamesJoined(analysisResults.ReadInside));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.ReadOutside));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.WrittenInside));
+            Assert.Equal("i, this, i2", GetSymbolNamesJoined(analysisResults.WrittenOutside));
+        }
+
+        [Fact]
+        public void RegionAnalysis_03()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            int i3 = 0;
+/*<bind>*/
+            System.Action<int> = () => i + i2 + i3;
+/*</bind>*/
+        }
+    }
+}
+""");
+            Assert.Null(GetSymbolNamesJoined(analysisResults.VariablesDeclared));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.AlwaysAssigned));
+            Assert.Equal("i, i2, i3", GetSymbolNamesJoined(analysisResults.Captured));
+            Assert.Equal("i, i2, i3", GetSymbolNamesJoined(analysisResults.CapturedInside));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.CapturedOutside));
+            Assert.Equal("i, i2, i3", GetSymbolNamesJoined(analysisResults.DataFlowsIn));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.DataFlowsOut));
+            Assert.Equal("i, this, i2, i3", GetSymbolNamesJoined(analysisResults.DefinitelyAssignedOnEntry));
+            Assert.Equal("i, this, i2, i3", GetSymbolNamesJoined(analysisResults.DefinitelyAssignedOnExit));
+            Assert.Equal("i, i2, i3", GetSymbolNamesJoined(analysisResults.ReadInside));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.ReadOutside));
+            Assert.Null(GetSymbolNamesJoined(analysisResults.WrittenInside));
+            Assert.Equal("i, this, i2, i3", GetSymbolNamesJoined(analysisResults.WrittenOutside));
+        }
+
+        [Fact]
+        public void RegionAnalysis_04()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(ref int i)
+    {
+        public void M(ref int i2)
+        {
+            _ = /*<bind>*/i + i2/*</bind>*/;
path: src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
user: login: AlekseyTs
body: >i [](http://example.com/codeflow?start=26&length=1)

Consider adding a flavor of the test where ```i``` is assigned within the region #Closed
created_at: 2025-03-20T18:12:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24753,4 +24752,419 @@ public static void M<U>(U u) { }
             // object.M<string, long>(42);
             Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension<string>(string).M<long>(long)", "string").WithLocation(1, 1));
     }
+
+    [Fact]
+    public void This_01()
+    {
+        var src = """
+static class E
+{
+    extension(object)
+    {
+        public void M()
+        {
+            var x = this;
+            this.ToString();
+            local();
+
+            void local()
+            {
+                var y = this;
+            }
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,21): error CS0027: Keyword 'this' is not available in the current context
+            //             var x = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(7, 21),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.ToString();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13),
+            // (13,25): error CS0027: Keyword 'this' is not available in the current context
+            //                 var y = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 25));
+    }
+
+    [Fact]
+    public void This_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+            this.M2();
+            M2(new object());
+        }
+        public void M2() { }
+    }
+}
+""";
+        // PROTOTYPE confirm expectations
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.M2();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13));
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Null(model.GetSymbolInfo(invocation).Symbol);
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "this.M2()");
+        Assert.Equal("void E.<>E__0.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2(new object())");
+        Assert.Equal("void E.M2(this System.Object o)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void This_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void This_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Equal("void E.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_01()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0176: Member 'E.extension(object).M2()' cannot be accessed with an instance reference; qualify it with a type name instead
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_ObjectProhibited, "o.M2").WithArguments("E.extension(object).M2()").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0103: The name 'o' does not exist in the current context
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            local();
+            void local()
+            {
+                o.M2();
+            }
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_05()
+    {
+        var src = """
+static class E
+{
+    extension(object o, object o2)
+    {
+        public void M()
+        {
+            o2.ToString();
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (3,25): error CS9504: An extension container can have only one receiver parameter
+            //     extension(object o, object o2)
+            Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "object o2").WithLocation(3, 25),
+            // (7,13): error CS0103: The name 'o2' does not exist in the current context
+            //             o2.ToString();
+            Diagnostic(ErrorCode.ERR_NameNotInContext, "o2").WithArguments("o2").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_06()
+    {
+        var src = """
+static class E
+{
+    extension(System.Span<int> s)
+    {
+        public async void M()
+        {
+            s.ToString();
+            await System.Threading.Tasks.Task.Yield();
+            s.ToString();
+        }
+    }
+}
+""";
+        // PROTOTYPE we should produce this error instead:
+        // error CS4012: Parameters of type 'Span<int>' cannot be declared in async methods or async lambda expressions.
+        var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
+            //             s.ToString();
+            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span<int>").WithLocation(7, 13),
+            // (9,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
+            //             s.ToString();
+            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span<int>").WithLocation(9, 13));
+    }
+
+    public partial class RegionAnalysisTests : FlowTestBase
+    {
+        [Fact]
+        public void RegionAnalysis_01()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            _ = /*<bind>*/i + i2/*</bind>*/;
path: src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
user: login: AlekseyTs
body: >i [](http://example.com/codeflow?start=26&length=1)

Consider adding a flavor of the test where ```i``` is assigned within the region #Closed
created_at: 2025-03-20T18:12:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24753,4 +24752,419 @@ public static void M<U>(U u) { }
             // object.M<string, long>(42);
             Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension<string>(string).M<long>(long)", "string").WithLocation(1, 1));
     }
+
+    [Fact]
+    public void This_01()
+    {
+        var src = """
+static class E
+{
+    extension(object)
+    {
+        public void M()
+        {
+            var x = this;
+            this.ToString();
+            local();
+
+            void local()
+            {
+                var y = this;
+            }
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,21): error CS0027: Keyword 'this' is not available in the current context
+            //             var x = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(7, 21),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.ToString();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13),
+            // (13,25): error CS0027: Keyword 'this' is not available in the current context
+            //                 var y = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 25));
+    }
+
+    [Fact]
+    public void This_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+            this.M2();
+            M2(new object());
+        }
+        public void M2() { }
+    }
+}
+""";
+        // PROTOTYPE confirm expectations
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.M2();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13));
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Null(model.GetSymbolInfo(invocation).Symbol);
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "this.M2()");
+        Assert.Equal("void E.<>E__0.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2(new object())");
+        Assert.Equal("void E.M2(this System.Object o)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void This_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void This_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Equal("void E.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_01()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0176: Member 'E.extension(object).M2()' cannot be accessed with an instance reference; qualify it with a type name instead
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_ObjectProhibited, "o.M2").WithArguments("E.extension(object).M2()").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0103: The name 'o' does not exist in the current context
path: src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
user: login: jcouv
body: Yup. I'll merge/resolve after your PR goes in
created_at: 2025-03-21T04:01:17Z
author_association: MEMBER
diff_hunk: @@ -24753,4 +24752,593 @@ public static void M<U>(U u) { }
             // object.M<string, long>(42);
             Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension<string>(string).M<long>(long)", "string").WithLocation(1, 1));
     }
+
+    [Fact]
+    public void This_01()
+    {
+        var src = """
+static class E
+{
+    extension(object)
+    {
+        public void M()
+        {
+            var x = this;
+            this.ToString();
+            local();
+
+            void local()
+            {
+                var y = this;
+            }
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,21): error CS0027: Keyword 'this' is not available in the current context
+            //             var x = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(7, 21),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.ToString();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13),
+            // (13,25): error CS0027: Keyword 'this' is not available in the current context
+            //                 var y = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 25));
+    }
+
+    [Fact]
+    public void This_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+            this.M2();
+            M2(new object());
+        }
+        public void M2() { }
+    }
+}
+""";
+        // PROTOTYPE confirm expectations
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.M2();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13));
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Null(model.GetSymbolInfo(invocation).Symbol);
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "this.M2()");
+        Assert.Equal("void E.<>E__0.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2(new object())");
+        Assert.Equal("void E.M2(this System.Object o)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void This_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void This_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Equal("void E.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_01()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0176: Member 'E.extension(object).M2()' cannot be accessed with an instance reference; qualify it with a type name instead
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_ObjectProhibited, "o.M2").WithArguments("E.extension(object).M2()").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0103: The name 'o' does not exist in the current context
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            local();
+            void local()
+            {
+                o.M2();
+            }
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_05()
+    {
+        var src = """
+static class E
+{
+    extension(object o, object o2)
+    {
+        public void M()
+        {
+            o2.ToString();
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (3,25): error CS9504: An extension container can have only one receiver parameter
+            //     extension(object o, object o2)
+            Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "object o2").WithLocation(3, 25),
+            // (7,13): error CS0103: The name 'o2' does not exist in the current context
+            //             o2.ToString();
+            Diagnostic(ErrorCode.ERR_NameNotInContext, "o2").WithArguments("o2").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_06()
+    {
+        var src = """
+static class E
+{
+    extension(System.Span<int> s)
+    {
+        public async void M()
+        {
+            s.ToString();
+            await System.Threading.Tasks.Task.Yield();
+            s.ToString();
+        }
+    }
+}
+""";
+        // PROTOTYPE we should produce this error instead:
+        // error CS4012: Parameters of type 'Span<int>' cannot be declared in async methods or async lambda expressions.
+        var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
+            //             s.ToString();
+            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span<int>").WithLocation(7, 13),
+            // (9,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
+            //             s.ToString();
+            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span<int>").WithLocation(9, 13));
+    }
+
+    public partial class RegionAnalysisTests : FlowTestBase
+    {
+        [Fact]
+        public void RegionAnalysis_01()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            _ = /*<bind>*/i + i2/*</bind>*/;
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: i, i2
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: i, i2
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_02()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            /*<bind>*/this.ToString()/*</bind>*/;
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: this
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: this
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_03()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            int i3 = 0;
+/*<bind>*/
+            System.Action<int> = () => i + i2 + i3;
+/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured: i, i2, i3
+CapturedInside: i, i2, i3
+CapturedOutside:
+DataFlowsIn: i, i2, i3
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2, i3
+DefinitelyAssignedOnExit: i, this, i2, i3
+ReadInside: i, i2, i3
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2, i3
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_04()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(ref int i)
+    {
+        public void M(ref int i2)
+        {
+            _ = /*<bind>*/i + i2/*</bind>*/;
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: i, i2
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: i, i2
+ReadOutside: i, i2
+WrittenInside:
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_05()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(out int i)
+    {
+        public void M(out int i2)
+        {
+            /*<bind>*/i = i2 = 0;/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i, i2
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn:
+DataFlowsOut: i, i2
+DefinitelyAssignedOnEntry: this
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside:
+ReadOutside: i, i2
+WrittenInside: i, i2
+WrittenOutside: this
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_06()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            /*<bind>*/i = i2 = 0;/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i, i2
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn:
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside:
+ReadOutside:
+WrittenInside: i, i2
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_07()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(ref int i)
+    {
+        public void M(ref int i2)
+        {
+            /*<bind>*/i = ref i2;/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: i2
+DataFlowsOut: i, i2
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: i2
+ReadOutside: i, i2
+WrittenInside: i, i2
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_08()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            void local(int i3)
+            {
+                _ = /*<bind>*/i + i2 + i3/*</bind>*/;
+            }
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured: i, i2
+CapturedInside: i, i2
+CapturedOutside:
+DataFlowsIn: i3
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2, i3
+DefinitelyAssignedOnExit: i, this, i2, i3
+ReadInside: i, i2, i3
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2, i3
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_09()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(out int i)
+    {
+        public void M(out int i2)
+        {
+            void local(out int i3)
+            {
+                /*<bind>*/i = i2 = i3 = 0;/*</bind>*/
+            }
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i, i2, i3
+Captured: i, i2
+CapturedInside: i, i2
+CapturedOutside:
+DataFlowsIn:
+DataFlowsOut: i, i2, i3
+DefinitelyAssignedOnEntry: this
+DefinitelyAssignedOnExit: i, this, i2, i3
+ReadInside:
+ReadOutside: i, i2, i3
+WrittenInside: i, i2, i3
+WrittenOutside: this
path: src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
user: login: AlekseyTs
body: >this [](http://example.com/codeflow?start=16&length=4)

The fact that `this` is mentioned in the result (in any symbol set) feels somewhat unexpected. #Resolved
created_at: 2025-03-21T04:55:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24753,4 +24752,593 @@ public static void M<U>(U u) { }
             // object.M<string, long>(42);
             Diagnostic(ErrorCode.ERR_BadInstanceArgType, "object").WithArguments("object", "M", "E.extension<string>(string).M<long>(long)", "string").WithLocation(1, 1));
     }
+
+    [Fact]
+    public void This_01()
+    {
+        var src = """
+static class E
+{
+    extension(object)
+    {
+        public void M()
+        {
+            var x = this;
+            this.ToString();
+            local();
+
+            void local()
+            {
+                var y = this;
+            }
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,21): error CS0027: Keyword 'this' is not available in the current context
+            //             var x = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(7, 21),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.ToString();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13),
+            // (13,25): error CS0027: Keyword 'this' is not available in the current context
+            //                 var y = this;
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(13, 25));
+    }
+
+    [Fact]
+    public void This_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+            this.M2();
+            M2(new object());
+        }
+        public void M2() { }
+    }
+}
+""";
+        // PROTOTYPE confirm expectations
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13),
+            // (8,13): error CS0027: Keyword 'this' is not available in the current context
+            //             this.M2();
+            Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(8, 13));
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Null(model.GetSymbolInfo(invocation).Symbol);
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "this.M2()");
+        Assert.Equal("void E.<>E__0.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+
+        invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2(new object())");
+        Assert.Equal("void E.M2(this System.Object o)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void This_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'o' of 'E.M2(object)'
+            //             M2();
+            Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M2").WithArguments("o", "E.M2(object)").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void This_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+
+        var tree = comp.SyntaxTrees.First();
+        var model = comp.GetSemanticModel(tree);
+        var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "M2()");
+        Assert.Equal("void E.M2()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_01()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_02()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            o.M2();
+        }
+        public static void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0176: Member 'E.extension(object).M2()' cannot be accessed with an instance reference; qualify it with a type name instead
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_ObjectProhibited, "o.M2").WithArguments("E.extension(object).M2()").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_03()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public static void M()
+        {
+            o.M2();
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS0103: The name 'o' does not exist in the current context
+            //             o.M2();
+            Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_04()
+    {
+        var src = """
+static class E
+{
+    extension(object o)
+    {
+        public void M()
+        {
+            local();
+            void local()
+            {
+                o.M2();
+            }
+        }
+        public void M2() { }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics();
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_05()
+    {
+        var src = """
+static class E
+{
+    extension(object o, object o2)
+    {
+        public void M()
+        {
+            o2.ToString();
+        }
+    }
+}
+""";
+        var comp = CreateCompilation(src);
+        comp.VerifyEmitDiagnostics(
+            // (3,25): error CS9504: An extension container can have only one receiver parameter
+            //     extension(object o, object o2)
+            Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "object o2").WithLocation(3, 25),
+            // (7,13): error CS0103: The name 'o2' does not exist in the current context
+            //             o2.ToString();
+            Diagnostic(ErrorCode.ERR_NameNotInContext, "o2").WithArguments("o2").WithLocation(7, 13));
+    }
+
+    [Fact]
+    public void ReceiverParameter_Access_06()
+    {
+        var src = """
+static class E
+{
+    extension(System.Span<int> s)
+    {
+        public async void M()
+        {
+            s.ToString();
+            await System.Threading.Tasks.Task.Yield();
+            s.ToString();
+        }
+    }
+}
+""";
+        // PROTOTYPE we should produce this error instead:
+        // error CS4012: Parameters of type 'Span<int>' cannot be declared in async methods or async lambda expressions.
+        var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
+        comp.VerifyEmitDiagnostics(
+            // (7,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
+            //             s.ToString();
+            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span<int>").WithLocation(7, 13),
+            // (9,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
+            //             s.ToString();
+            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s").WithArguments("System.Span<int>").WithLocation(9, 13));
+    }
+
+    public partial class RegionAnalysisTests : FlowTestBase
+    {
+        [Fact]
+        public void RegionAnalysis_01()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            _ = /*<bind>*/i + i2/*</bind>*/;
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: i, i2
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: i, i2
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_02()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            /*<bind>*/this.ToString()/*</bind>*/;
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: this
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: this
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_03()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            int i3 = 0;
+/*<bind>*/
+            System.Action<int> = () => i + i2 + i3;
+/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured: i, i2, i3
+CapturedInside: i, i2, i3
+CapturedOutside:
+DataFlowsIn: i, i2, i3
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2, i3
+DefinitelyAssignedOnExit: i, this, i2, i3
+ReadInside: i, i2, i3
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2, i3
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_04()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(ref int i)
+    {
+        public void M(ref int i2)
+        {
+            _ = /*<bind>*/i + i2/*</bind>*/;
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: i, i2
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: i, i2
+ReadOutside: i, i2
+WrittenInside:
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_05()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(out int i)
+    {
+        public void M(out int i2)
+        {
+            /*<bind>*/i = i2 = 0;/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i, i2
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn:
+DataFlowsOut: i, i2
+DefinitelyAssignedOnEntry: this
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside:
+ReadOutside: i, i2
+WrittenInside: i, i2
+WrittenOutside: this
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_06()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            /*<bind>*/i = i2 = 0;/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i, i2
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn:
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside:
+ReadOutside:
+WrittenInside: i, i2
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_07()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(ref int i)
+    {
+        public void M(ref int i2)
+        {
+            /*<bind>*/i = ref i2;/*</bind>*/
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i
+Captured:
+CapturedInside:
+CapturedOutside:
+DataFlowsIn: i2
+DataFlowsOut: i, i2
+DefinitelyAssignedOnEntry: i, this, i2
+DefinitelyAssignedOnExit: i, this, i2
+ReadInside: i2
+ReadOutside: i, i2
+WrittenInside: i, i2
+WrittenOutside: i, this, i2
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_08()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(int i)
+    {
+        public void M(int i2)
+        {
+            void local(int i3)
+            {
+                _ = /*<bind>*/i + i2 + i3/*</bind>*/;
+            }
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned:
+Captured: i, i2
+CapturedInside: i, i2
+CapturedOutside:
+DataFlowsIn: i3
+DataFlowsOut:
+DefinitelyAssignedOnEntry: i, this, i2, i3
+DefinitelyAssignedOnExit: i, this, i2, i3
+ReadInside: i, i2, i3
+ReadOutside:
+WrittenInside:
+WrittenOutside: i, this, i2, i3
+""", analysisResults);
+        }
+
+        [Fact]
+        public void RegionAnalysis_09()
+        {
+            var analysisResults = CompileAndAnalyzeDataFlowExpression("""
+static class E
+{
+    extension(out int i)
+    {
+        public void M(out int i2)
+        {
+            void local(out int i3)
+            {
+                /*<bind>*/i = i2 = i3 = 0;/*</bind>*/
+            }
+        }
+    }
+}
+""");
+            VerifyDataFlowAnalysis("""
+VariablesDeclared:
+AlwaysAssigned: i, i2, i3
+Captured: i, i2
+CapturedInside: i, i2
+CapturedOutside:
+DataFlowsIn:
+DataFlowsOut: i, i2, i3
+DefinitelyAssignedOnEntry: this
+DefinitelyAssignedOnExit: i, this, i2, i3
+ReadInside:
+ReadOutside: i, i2, i3
+WrittenInside: i, i2, i3
+WrittenOutside: this
path: src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
user: login: AlekseyTs
body: Consider at least adding a prototype comment
created_at: 2025-03-21T04:57:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1832,6 +1852,18 @@ protected override LocalState TopState()
                             }
                         }
                     }
+
+                    if (TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter))
+                    {
+                        if (extensionParameter.RefKind != RefKind.Out)
path: src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs
user: login: jjonescz
body: Consider collapsing these `if` conditions into one. #Resolved
created_at: 2025-03-21T10:02:50Z
author_association: MEMBER
diff_hunk: @@ -368,6 +368,11 @@ protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
                 }
             }
 
+            if (TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter))
+            {
+                EnterParameter(extensionParameter);
path: src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs
user: login: jjonescz
body: Should we also `LeaveParameter(extensionParameter);` below like we do for `methodThisParameter`? #Resolved
created_at: 2025-03-21T10:04:04Z
author_association: MEMBER
diff_hunk: @@ -87,6 +87,11 @@ protected override void EnterRegion()
                         if (p.RefKind != RefKind.None) _readOutside.Add(p);
                     }
 
+                    if (TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter))
+                    {
+                        if (extensionParameter.RefKind != RefKind.None) _readOutside.Add(extensionParameter);
path: src/Compilers/CSharp/Portable/FlowAnalysis/ReadWriteWalker.cs
user: login: jjonescz
body: Consider collapsing the `if` conditions into one.
created_at: 2025-03-21T10:06:54Z
author_association: MEMBER
diff_hunk: @@ -15466,12 +15469,8 @@ static class E
     public static ref string M(this ref string s) => ref s;
 }
 """;
-        // PROTOTYPE unexpected definite assignment error and missing error on extension parameter
path: src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
user: login: jjonescz
body: >missing error on extension parameter [](http://example.com/codeflow?start=62&length=36)

Looks like this part of the prototype comment wasn't addressed. #Resolved
created_at: 2025-03-21T10:10:19Z
author_association: MEMBER
diff_hunk: @@ -1832,6 +1852,18 @@ protected override LocalState TopState()
                             }
                         }
                     }
+
+                    if (TryGetInstanceExtensionParameter(out ParameterSymbol extensionParameter))
+                    {
+                        if (extensionParameter.RefKind != RefKind.Out)
path: src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs
user: login: jcouv
body: I'll leave this as-is to match surrounding code
created_at: 2025-03-21T18:28:56Z
author_association: MEMBER
diff_hunk: @@ -2640,21 +2640,27 @@ public void ReceiverParameter_Out_01()
         var src = """
 public static class Extensions
 {
-    extension(out int i) { }
+    extension(out int i)
+    {
+        void M2() { }
+    }
     static void M(this out int i) { }
 }
 """;
         var comp = CreateCompilation(src);
         comp.VerifyEmitDiagnostics(
             // (3,15): error CS8328:  The parameter modifier 'out' cannot be used with 'extension'
-            //     extension(out int i) { }
+            //     extension(out int i)
             Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15),
-            // (4,17): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
+            // (5,14): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
path: src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
user: login: AlekseyTs
body: >// (5,14): error CS0177: The out parameter 'i' must be assigned to before control leaves the current metho [](http://example.com/codeflow?start=12&length=106)

Is this error going to be reported for a static method? #Closed
created_at: 2025-03-21T19:02:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2640,21 +2640,27 @@ public void ReceiverParameter_Out_01()
         var src = """
 public static class Extensions
 {
-    extension(out int i) { }
+    extension(out int i)
+    {
+        void M2() { }
+    }
     static void M(this out int i) { }
 }
 """;
         var comp = CreateCompilation(src);
         comp.VerifyEmitDiagnostics(
             // (3,15): error CS8328:  The parameter modifier 'out' cannot be used with 'extension'
-            //     extension(out int i) { }
+            //     extension(out int i)
             Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "extension").WithLocation(3, 15),
-            // (4,17): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
+            // (5,14): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
path: src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
user: login: jcouv
body: It should not. We only enter/leave the extension parameter for instance methods. I'll add a test
created_at: 2025-03-21T19:47:06Z
author_association: MEMBER

PR comments:
user: login: AlekseyTs
created_at: 2025-03-20T18:14:25Z
body: Done with review pass (commit 1)
author_association: CONTRIBUTOR
user: login: jcouv
created_at: 2025-03-21T06:27:40Z
body: @jjonescz for review. Thanks
author_association: MEMBER