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

Switch implicit span to conversion from type #74232

Conversation

jjonescz
Copy link
Member

@jjonescz jjonescz commented Jul 2, 2024

Test plan: #73445
Corresponding speclet update: dotnet/csharplang#8241

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Jul 2, 2024
@jjonescz jjonescz marked this pull request as ready for review July 2, 2024 10:22
@jjonescz jjonescz requested review from a team as code owners July 2, 2024 10:22
@jjonescz jjonescz requested review from 333fred and cston July 2, 2024 10:23
// PROTOTYPE: Is it fine that this conversion does not exists when Compilation is null?
if (Compilation?.IsFeatureEnabled(MessageID.IDS_FeatureFirstClassSpan) != true)
// Note: when Compilation is null, we assume latest LangVersion.
if (Compilation?.IsFeatureEnabled(MessageID.IDS_FeatureFirstClassSpan) == false)
Copy link
Member

@333fred 333fred Jul 2, 2024

Choose a reason for hiding this comment

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

A little worried about this. Do we have an understanding of when Compilation is null, such that we can test those scenarios with lower language versions? Will they get different behavior, or new language version errors? #Resolved

Copy link
Member Author

@jjonescz jjonescz Jul 3, 2024

Choose a reason for hiding this comment

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

So far I've been able to hit only one scenario with Compilation being null - from IMethodSymbol.ReduceExtensionMethod public API - see e.g., test Conversion_Array_Span_ExtensionMethodReceiver_Implicit_Reduced_01. And the documentation says we should consider the latest language version in that case (it talks about constraints but it seems consistent to do for other features as well):

/// <param name="compilation">The compilation in which constraints should be checked.
/// Should not be null, but if it is null we treat constraints as we would in the latest
/// language version.</param>

Maybe other scenarios (not just reduced extension methods) should behave similarly? But there might be no more scenarios, I have investigated callsites for a while and haven't found any that I could hit.

Will they get different behavior, or new language version errors?

If they end up in the binder, they will get a language version error. Otherwise, they will get different behavior - like the ReduceExtensionMethod example mentioned above - the call will consider the implicit span conversion even in older lang version.

// PROTOTYPE: Check runtime APIs used for other span conversions once they are implemented.
if (destination.OriginalDefinition.Equals(Compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.AllIgnoreOptions))
// NOTE: Span conversions do not use well-known types because they are "conversions from type" and hence don't have access to Compilation.
Copy link
Member

@333fred 333fred Jul 2, 2024

Choose a reason for hiding this comment

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

Not quite how I'd word this comment; the lack of a Compilation in ConversionsBase is just an implementation detail. The reason is that we explicitly specified that we match (ReadOnly)Span by type name, so we need to use that same (ReadOnly)Span to look up APIs in. #Resolved

}
}
}
}

internal static MethodSymbol? TryFindImplicitOperatorFromArray(TypeSymbol type)
Copy link
Member

@333fred 333fred Jul 2, 2024

Choose a reason for hiding this comment

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

It may be worth extracting this as a TryFindSingleMember method that takes a filter delegate, since I assume we'll need the same logic for looking up the ReadOnlySpan->ReadOnlySpan converter method. Up to you though. #Resolved

comp.VerifyDiagnostics(
// (2,15): error CS0656: Missing compiler required member 'System.Span`1.op_Implicit'
[Fact]
public void Conversion_Array_Span_Implicit_DifferentOperator()
Copy link
Member

@333fred 333fred Jul 2, 2024

Choose a reason for hiding this comment

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

Perhaps a version where the operator is explicit? #Resolved

}

[Fact]
public void Conversion_Array_Span_Implicit_UnrecognizedModreq()
Copy link
Member

@333fred 333fred Jul 2, 2024

Choose a reason for hiding this comment

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

Let's add a test with an unrecognized modopt as well. #Resolved

@jjonescz jjonescz requested a review from 333fred July 3, 2024 08:48
@jjonescz
Copy link
Member Author

jjonescz commented Jul 3, 2024

@cston for the second review, thanks

@jjonescz
Copy link
Member Author

jjonescz commented Jul 8, 2024

@cston @333fred for reviews, thanks

}

internal static MethodSymbol? TryFindImplicitOperatorFromArray(TypeSymbol type)
{
Copy link
Member

@cston cston Jul 8, 2024

Choose a reason for hiding this comment

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

{

Consider adding Debug.Assert(type.IsSpan() || type.IsReadOnlySpan()); #Closed

} method ? method : null);
}

private static T? TryFindSingleMember<T>(TypeSymbol type, string name, Func<Symbol, T?> predicate) where T : class
Copy link
Member

@cston cston Jul 8, 2024

Choose a reason for hiding this comment

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

Is the type parameter necessary, or could this be simplified to TryFindSingleMethod with MethodSymbol directly? #Closed

(ignoreUserDefinedSpanConversionsInOneDirection(Compilation, source, target) ||
ignoreUserDefinedSpanConversionsInOneDirection(Compilation, target, source));
// Note: when Compilation is null, we assume latest LangVersion.
return Compilation?.IsFeatureEnabled(MessageID.IDS_FeatureFirstClassSpan) != false &&
Copy link
Member

@cston cston Jul 8, 2024

Choose a reason for hiding this comment

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

This check is repeated several times, with the same comment. Consider creating a private IsFirstClassSpansEnabled property so this is captured in one location. #Closed


rewrittenOperand = _factory.Convert(method.ParameterTypesWithAnnotations[0].Type, rewrittenOperand);

if (member == WellKnownMember.System_ReadOnlySpan_T__op_Implicit_Array)
if (_compilation.IsReadOnlySpanType(spanType))
Copy link
Member

@cston cston Jul 8, 2024

Choose a reason for hiding this comment

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

_compilation.IsReadOnlySpanType(spanType)

This uses WellKnownMember.System_ReadOnlySpan_T rather than checking by fully-qualified type name. Is that correct? #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.

That was my intent - I even have a test for it: Conversion_Array_Span_Implicit_ConstantData_NotWellKnownSpan. The emit of constant data for ReadOnlySpan (i.e., emit of BoundReadOnlySpanFromArray) expects the well-known span type and I don't think changing that is worth the effort.

@cston
Copy link
Member

cston commented Jul 8, 2024

    CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(

[This comment is not specific to this PR, so it can be addressed separately.]

CreateCompilationWithSpan() is always using the local type definitions for Span<T> and ReadOnlySpan<T>. On .NET core, we should compile against the BCL implementation instead, to ensure we're testing against shipping APIs. Consider using CreateCompilationWithSpanAndMemoryExtensions() which covers both cases. #Pending


Refers to: src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs:58 in 4161bd1. [](commit_id = 4161bd1, deletion_comment = False)

@jjonescz
Copy link
Member Author

jjonescz commented Jul 9, 2024

    CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(

Sounds good, thanks! Let me do that after I merge main into the feature branch so I get #74281 in.


In reply to: 2215489010


Refers to: src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs:58 in 4161bd1. [](commit_id = 4161bd1, deletion_comment = False)

@jjonescz jjonescz requested a review from cston July 9, 2024 12:01
@jjonescz
Copy link
Member Author

@333fred for another look, thanks

@jjonescz jjonescz merged commit 7997421 into dotnet:features/FirstClassSpan Jul 11, 2024
28 checks passed
@jjonescz jjonescz deleted the FirstClassSpan-08-ConversionFromType branch July 11, 2024 08:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers Feature - First-class Span Types untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants