Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle capturing of primary constructor parameters within queries and in type-or-value scenarios #66254

Conversation

AlekseyTs
Copy link
Contributor

This PR matches the version of the spec from dotnet/csharplang#6855.

It might be easier to review commit by commit.

}

this.LookupExtensionMethodsInSingleBinder(scope, lookupResult, rightName, arity, options, ref useSiteInfo);
return useSiteInfo;
Copy link
Member

@jjonescz jjonescz Jan 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return useSiteInfo;

The return value of this method is never used? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value of this method is never used?

Yes. This is an artifact of an automatic refactoring. Will fix.

captured.Free();

return _capturedParameters;
throw ExceptionUtilities.Unreachable();
Copy link
Member

@jjonescz jjonescz Jan 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw ExceptionUtilities.Unreachable();

This doesn't seem to be needed. Consider also lifting code out of the else block above - it's not needed since the if returns. #Closed

}

[Fact]
public void ParameterCapturing_022_ColorColor_MemberAccess_Instance_Method()
Copy link
Member

@jjonescz jjonescz Jan 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ParameterCapturing_022_ColorColor_MemberAccess_Instance_Method

Consider also testing when both extension method and instance method are available. #Closed

Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "Color").WithArguments("Color").WithLocation(2, 17),
// (4,33): error CS9500: Cannot use primary constructor parameter 'Color Color' in this context.
// public static int Test() => Color.M1(new S1());
Diagnostic(ErrorCode.ERR_InvalidPrimaryConstructorParameterReference, "Color").WithArguments("Color Color").WithLocation(4, 33)
Copy link
Member

@jjonescz jjonescz Jan 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diagnostic(ErrorCode.ERR_InvalidPrimaryConstructorParameterReference, "Color").WithArguments("Color Color").WithLocation(4, 33)

This error feels unexpected. The parameter is not used here. I would expect this code to compile and call the static method. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error feels unexpected. The parameter is not used here. I would expect this code to compile and call the static method.

Language rules do not agree with these expectations
https://sharplab.io/#v2:C4LglgNgPgzsBOBXAxsABAZQIwFgBQA3vmiWgAIDM5WAbGmAHboAqApnABQDCA9hD/DS9+8AJRoAvAD4hfAQDoAslg4NWAd0wrRogNz4AvvnxkATLJH4ieUuSqN0yjtjQAPcdLQAGfTdLFSSmo6BzRlAB5mKQ5mN3F1AAtWeFY0WJA0RAYAWwBDBlyAc1YAE0kZH0N8IA===

struct S1
{
    public static int Test(Color Color) => Color.M1(new S1());
}

class Color
{
    public int M1(S1 x) => 0;
    
    public static int M1<T>(T x) where T : unmanaged => 0;
}

Observed:

    .method public hidebysig static 
        int32 Test (
            class Color Color
        ) cil managed 
    {
        .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
            01 00 01 00 00
        )
        // Method begins at RVA 0x20a0
        // Code size 16 (0x10)
        .maxstack 2
        .locals init (
            [0] valuetype S1
        )

        IL_0000: ldarg.0
        IL_0001: ldloca.s 0
        IL_0003: initobj S1
        IL_0009: ldloc.0
        IL_000a: callvirt instance int32 Color::M1(valuetype S1)
        IL_000f: ret
    } // end of method S1::Test

comp.VerifyEmitDiagnostics(
// (6,19): error CS0229: Ambiguity between 'Color.P' and 'Color.P'
// _ = Color.P;
Diagnostic(ErrorCode.ERR_AmbigMember, "P").WithArguments("Color.P", "Color.P").WithLocation(6, 19)
Copy link
Member

@jjonescz jjonescz Jan 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERR_AmbigMember

I'm curious why this also isn't ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious why this also isn't ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver?

Because lookup fails with the ERR_AmbigMember, C# doesn't support overloading of regular properties. The ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver is reported if lookup succeeds

@AlekseyTs
Copy link
Contributor Author

@cston, @dotnet/roslyn-compiler For the second review

(object)contaningMember.ContainingSymbol != primaryCtor.ContainingSymbol || // The member doesn't belong to our type, i.e. from nested type
((object)contaningMember != primaryCtor && contaningMember is MethodSymbol { MethodKind: MethodKind.Constructor })) && // We are in a non-primary instance constructor
(!IsInDeclaringTypeInstanceMember(primaryCtor) ||
(this.ContainingMember() is MethodSymbol { MethodKind: MethodKind.Constructor } contaningMember && (object)contaningMember != primaryCtor)) && // We are in a non-primary instance constructor
Copy link
Member

@cston cston Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contaning

Typo. #Closed

{
return !(InParameterDefaultValue ||
InAttributeArgument ||
this.ContainingMember() is not { Kind: not SymbolKind.NamedType, IsStatic: false } contaningMember || // We are not in an instance member
Copy link
Member

@cston cston Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contaning

Typo. #Closed

@@ -6390,12 +6404,17 @@ private BoundExpression BindLeftIdentifierOfPotentialColorColorMemberAccess(Iden
var boundType = BindNamespaceOrType(left, typeDiagnostics);
if (TypeSymbol.Equals(boundType.Type, leftType, TypeCompareKind.AllIgnoreOptions))
{
Debug.Assert(!leftType.IsDynamic());
Debug.Assert(IsPotentialColorColorReceiver(left, leftType));
Copy link
Member

@cston cston Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug.Assert(IsPotentialColorColorReceiver(left, leftType));

What is the assert checking? (It looks like IsPotentialColorColorReceiver() is checking the same two conditions as the two if conditions above.) #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the assert checking? (It looks like IsPotentialColorColorReceiver() is checking the same two conditions as the two if conditions above.)

It is verifying that we can rely on IsPotentialColorColorReceiver elsewhere to check for the same condition.

@@ -1564,6 +1564,27 @@ private BoundExpression ReplaceTypeOrValueReceiver(BoundExpression receiver, boo
}
}

private BoundExpression GetValueExpressionIfTypeOrValueReceiver(BoundExpression receiver)
Copy link
Member

@cston cston Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private

static #Closed

diagnostics.Add(ErrorCode.ERR_FuncPtrMethMustBeStatic, location, symbol);
}
else
if (receiverOpt?.HasErrors != true)
Copy link
Member

@cston cston Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

receiverOpt?.HasErrors != true

What is the impact of this change? Does it improve errors or does it affect non-error scenarios? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the impact of this change? Does it improve errors or does it affect non-error scenarios?

It reduces the noise in error scenarios. See the only test in QueryTests.cs, for example. However, the primary goal was to suppress cascading diagnostics on a BoundBadExpression that we create in ConstructBoundMemberGroupAndReportOmittedTypeArguments due to an ambiguity.


LookupOptions options = LookupOptions.AllMethodsOnArityZero;
if (SyntaxFacts.IsInvoked(id))
bool checkQuery(QueryExpressionSyntax query, Binder enclosingBinder)
Copy link
Member

@cston cston Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bool

Consider adding // Follows the logic of BindQuery
#Closed

@cston
Copy link
Member

cston commented Jan 9, 2023

    public void ParameterCapturing_033_ColorColor_MemberAccess_InstanceAndStatic_Method()

Is this test identical to _032?


In reply to: 1375123522


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:9677 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@cston
Copy link
Member

cston commented Jan 9, 2023

            // (6,9): error CS9501: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context.

Why is Color in Color.M1(this) ambiguous here but not in _046?


In reply to: 1375131340


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:10284 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@cston
Copy link
Member

cston commented Jan 9, 2023

            // (5,9): error CS9501: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context.

Why is Color ambiguous? Isn't the instance member M1() inapplicable because of the argument mismatch?


In reply to: 1375132933


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:10315 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@cston
Copy link
Member

cston commented Jan 9, 2023

}

Consider including capture of an unmanaged parameter:

struct S3(int p3)
{
    string Test() => p3;
}

Test(new S3());

In reply to: 1375136132


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:10728 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@cston
Copy link
Member

cston commented Jan 9, 2023

    public void ParameterCapturing_058_ColorColor_MemberAccess_InstanceAndStatic_Property()

It looks like both properties are instance members.


In reply to: 1375136996


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:10829 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@cston
Copy link
Member

cston commented Jan 9, 2023

    Color.M1(this);

Why isn't this ambiguous?


In reply to: 1375138681


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:10872 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@AlekseyTs
Copy link
Contributor Author

    public void ParameterCapturing_033_ColorColor_MemberAccess_InstanceAndStatic_Method()

Is this test identical to _032?

Looks like it is. I'll remove it.


In reply to: 1375123522


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:9677 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@AlekseyTs
Copy link
Contributor Author

            // (6,9): error CS9501: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context.

Why is Color in Color.M1(this) ambiguous here but not in _046?

Initializer value is not a capturing context, therefore the ambiguity restriction doesn't apply. Here is one of the conditions from the spec: "If E is treated as a simple name, rather than a type name, it would refer to a primary constructor parameter and would capture the parameter into the state of the enclosing type."


In reply to: 1375131340


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:10284 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@AlekseyTs
Copy link
Contributor Author

            // (5,9): error CS9501: Identifier 'Color' is ambiguous between type 'Color' and parameter 'Color Color' in this context.

Why is Color ambiguous? Isn't the instance member M1() inapplicable because of the argument mismatch?

What argument mismatch? Regardless, the ambiguity rule doesn't take arguments into consideration at all. See dotnet/csharplang#6855.


In reply to: 1375132933


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:10315 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@AlekseyTs
Copy link
Contributor Author

AlekseyTs commented Jan 9, 2023

    Color.M1(this);

Why isn't this ambiguous?

There are no static methods. Per spec: "Extension methods applicable to the receiver type are treated as instance methods for the purpose of this check."

The "Color" definetly won't be valid as a type.


In reply to: 1375138681


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:10872 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@cston
Copy link
Member

cston commented Jan 9, 2023

What argument mismatch?

The first parameter in the instance method is declared as S1 rather than Color.

In reply to: 1375132933

Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs:10315 in 808952a. [](commit_id = 808952a, deletion_comment = False)

@AlekseyTs
Copy link
Contributor Author

The first parameter in the instance method is declared as S1 rather than Color.

Thanks for pointing this out. I will adjust this in one of the next PRs


In reply to: 1376143344

@AlekseyTs AlekseyTs merged commit 2adfb12 into dotnet:features/PrimaryConstructors Jan 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants