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

Scoped implicitly-typed lambda parameters #64680

Merged
merged 9 commits into from
Oct 17, 2022
Merged

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Oct 12, 2022

Fixes #62080
Corresponding spec update: dotnet/csharplang#6551

Relates to test plan #59194 (ref fields)

@jcouv jcouv marked this pull request as ready for review October 12, 2022 23:49
@jcouv jcouv requested a review from a team as a code owner October 12, 2022 23:49
@@ -611,7 +613,8 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo
}

var parameterRefKindsBuilder = ArrayBuilder<RefKind>.GetInstance(ParameterCount);
var parameterScopesBuilder = ArrayBuilder<DeclarationScope>.GetInstance(ParameterCount);
var parameterDeclarationScopesBuilder = ArrayBuilder<DeclarationScope>.GetInstance(ParameterCount);
Copy link
Member

@cston cston Oct 13, 2022

Choose a reason for hiding this comment

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

parameterDeclarationScopesBuilder

Consider calling this parameterDeclaredScopesBuilder. #Closed

@@ -304,9 +307,11 @@ internal override void AddDeclarationDiagnostics(BindingDiagnosticBag diagnostic
CSharpCompilation compilation,
UnboundLambda unboundLambda,
ImmutableArray<TypeWithAnnotations> parameterTypes,
ImmutableArray<RefKind> parameterRefKinds)
ImmutableArray<RefKind> parameterRefKinds,
ImmutableArray<DeclarationScope> parameterDeclarationScopes)
Copy link
Member

@cston cston Oct 13, 2022

Choose a reason for hiding this comment

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

parameterDeclarationScopes

Consider calling this parameterDeclaredScopes. #Closed

@@ -225,5 +225,28 @@ internal static bool IsValidUnscopedRefAttributeTarget(this MethodSymbol method)
!method.IsConstructor() &&
!method.IsInitOnly;
}

#nullable enable
internal static ImmutableArray<DeclarationScope> GetByValueParameterDeclarationScopes(this MethodSymbol? method)
Copy link
Member

@cston cston Oct 13, 2022

Choose a reason for hiding this comment

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

GetByValueParameterDeclarationScopes

I think it would be helpful if these methods are named as "...DeclaredScopes" or "...EffectiveScopes". Currently, it's not clear if "...DeclarationScopes" refers to the enum type name or the declared values. #Closed

@@ -1054,6 +1094,7 @@ public static ReturnInferenceCacheKey Create(NamedTypeSymbol? delegateType, bool

parameterTypes = typesBuilder.ToImmutableAndFree();
parameterRefKinds = refKindsBuilder.ToImmutableAndFree();
parameterDeclarationScopes = MethodSymbolExtensions.GetByValueParameterDeclarationScopes(invoke);
Copy link
Member

@cston cston Oct 13, 2022

Choose a reason for hiding this comment

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

MethodSymbolExtensions.GetByValueParameterDeclarationScopes(invoke)

invoke.GetByValueParameterDeclarationScopes()? #Closed

{
return false;
}
}
Copy link
Member

@cston cston Oct 13, 2022

Choose a reason for hiding this comment

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

return ParameterDeclarationScopes.SequenceEqual(other.ParameterDeclarationScopes); #Closed

{
M2(r => r);
M2((scoped R r) => r); // 1
}
Copy link
Member

@cston cston Oct 13, 2022

Choose a reason for hiding this comment

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

}

Consider testing M2(r => default);. Should overload resolution fail in that case, with ambiguous overloads? #Closed

{
void M()
{
D1 d1 = () => r;
Copy link
Member

@cston cston Oct 13, 2022

Choose a reason for hiding this comment

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

r

Consider changing to new R(), to avoid any impact from that error. #Closed

void M()
{
D1 d1 = (scoped R r) => r;
}
Copy link
Member

@cston cston Oct 13, 2022

Choose a reason for hiding this comment

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

}

Consider testing d1 = r => r; as well. #Closed

@jcouv jcouv requested a review from cston October 14, 2022 02:33
return this.ParameterDeclarationScopes.IsDefault == other.ParameterDeclarationScopes.IsDefault;
}

if (this.ParameterDeclarationScopes.Length != other.ParameterDeclarationScopes.Length)
Copy link
Member

@cston cston Oct 14, 2022

Choose a reason for hiding this comment

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

if (this.ParameterDeclarationScopes.Length != other.ParameterDeclarationScopes.Length)

Minor: I believe this is included in SequenceEqual() below. #Closed

@AlekseyTs
Copy link
Contributor

@jcouv Is there a spec how this is supposed to work?

{
Debug.Assert(parameterTypes.Length == parameterRefKinds.Length);
Debug.Assert(parameterDeclaredScopes.IsDefault || parameterTypes.Length == parameterDeclaredScopes.Length);
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 14, 2022

Choose a reason for hiding this comment

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

parameterDeclaredScopes.IsDefault

What is the scenario when this condition is true? #Closed

Copy link
Member Author

@jcouv jcouv Oct 14, 2022

Choose a reason for hiding this comment

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

Is there a spec how this is supposed to work?

I'll add spec change today.

Copy link
Member Author

Choose a reason for hiding this comment

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

When all parameters are unscoped, we use a default array.

Copy link
Member Author

Choose a reason for hiding this comment

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

Created corresponding spec update: dotnet/csharplang#6551


static DeclarationScope getByValueParameterDeclaredScope(ParameterSymbol parameter)
{
// For implicitly-typed lambda parameters, we only care about declaration scopes on by-value parameters.
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 14, 2022

Choose a reason for hiding this comment

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

For implicitly-typed lambda parameters, we only care about declaration scopes on by-value parameters.

It is not obvious why is that. #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

If a parameter is ref or out then the parameters must have been explicitly-typed.

Copy link
Contributor

Choose a reason for hiding this comment

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

If a parameter is ref or out then the parameters must have been explicitly-typed.

I am not sure I am following. We are looking at a method symbol. All parameters are explicitly typed for it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Still looking at other changes, I might get it at the end

@jcouv jcouv marked this pull request as draft October 15, 2022 16:56
@jcouv jcouv marked this pull request as ready for review October 15, 2022 18:54
@jaredpar
Copy link
Member

@roslyn-compiler please ignore this message. Testing out a GitHub rule change.

@@ -1502,7 +1502,7 @@ internal sealed class SourceComplexParameterSymbolWithCustomModifiersPrecedingRe
SyntaxReference syntaxRef,
bool isParams,
bool isExtensionMethodThis,
DeclarationScope scope)
DeclarationScope? scope)
Copy link
Member

@cston cston Oct 17, 2022

Choose a reason for hiding this comment

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

DeclarationScope? scope

Is this change needed? Can we get here from a LambdaParameterSymbol? #Resolved

@@ -1479,7 +1479,7 @@ internal sealed class SourceComplexParameterSymbol : SourceComplexParameterSymbo
SyntaxReference syntaxRef,
bool isParams,
bool isExtensionMethodThis,
DeclarationScope scope)
DeclarationScope? scope)
Copy link
Member

@cston cston Oct 17, 2022

Choose a reason for hiding this comment

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

DeclarationScope? scope

Is this change needed? Can we get here from a LambdaParameterSymbol? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

WithCustomModifiersAndParamsCore copies this.DeclaredSymbol (which is Nullable<DeclarationScope>) using this constructor.
It similarly calls the SourceComplexParameterSymbolWithCustomModifiersPrecedingRef constructor.

Copy link
Member

@cston cston Oct 17, 2022

Choose a reason for hiding this comment

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

WithCustomModifiersAndParamsCore() should not be used for LambdaParameterSymbol though. If it is, we'd presumably need to copy EffectiveScope as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

WithCustomModifiersAndParamsCore isn't used for lambdas. It's used for OHI scenarios.

@jcouv jcouv requested a review from AlekseyTs October 17, 2022 16:29
var declaredScope = this.DeclaredScope;
// DeclaredScope is only null in LambdaParameterSymbol where EffectiveScope can be provided rather than computed
Debug.Assert(this.DeclaredScope is not null);
var declaredScope = this.DeclaredScope.Value;
Copy link
Contributor

Choose a reason for hiding this comment

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

Value

ValueOrDefault? Or is it your intent to crash on null value here? If so, perhaps the assert is redundant.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd rather leave as-is. I thought this was nullable-enabled code.

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (commit 9)

@jcouv jcouv merged commit 5bf1a43 into dotnet:main Oct 17, 2022
@jcouv jcouv deleted the scoped-lambda branch October 17, 2022 22:24
@ghost ghost added this to the Next milestone Oct 17, 2022
@RikkiGibson RikkiGibson modified the milestones: Next, 17.5 P1 Oct 24, 2022
jcouv added a commit to jcouv/roslyn that referenced this pull request Oct 25, 2022
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.

Untyped lambda parameters should infer scoped from target delegate
5 participants