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

Add span type inference #74646

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,13 @@ private void ExactInference(TypeWithAnnotations source, TypeWithAnnotations targ
return;
}

// SPEC: * V is a Span<V1> and U is an array type U1[] or a Span<U1>
// SPEC: * V is a ReadOnlySpan<V1> and U is an array type U1[] or a Span<U1> or ReadOnlySpan<U1>
if (ExactSpanInference(source.Type, target.Type, ref useSiteInfo))
{
return;
}

// SPEC: * Otherwise, if V is a constructed type C<V1...Vk> and U is a constructed
// SPEC: type C<U1...Uk> then an exact inference is made
// SPEC: from each Ui to the corresponding Vi.
Expand Down Expand Up @@ -1690,6 +1697,55 @@ private bool ExactArrayInference(TypeWithAnnotations source, TypeWithAnnotations
return true;
}

private readonly bool IsFeatureFirstClassSpanEnabled
{
get
{
// Note: when Compilation is null, we assume latest LangVersion.
return _compilation?.IsFeatureEnabled(MessageID.IDS_FeatureFirstClassSpan) != false;
}
}

private bool ExactSpanInference(TypeSymbol source, TypeSymbol target, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
Debug.Assert(source is not null);
Debug.Assert(target is not null);

if (IsFeatureFirstClassSpanEnabled && (
// SPEC: * V is a Span<V1> and U is an array type U1[] or a Span<U1>
(
target.IsSpan() &&
(source.IsSZArray() || source.IsSpan())
) ||
// SPEC: * V is a ReadOnlySpan<V1> and U is an array type U1[] or a Span<U1> or ReadOnlySpan<U1>
(
target.IsReadOnlySpan() &&
(source.IsSZArray() || source.IsSpan() || source.IsReadOnlySpan())
)
))
{
var sourceElementType = GetSpanOrSZArrayElementType(source);
var targetElementType = GetSpanElementType(target);
ExactInference(sourceElementType, targetElementType, ref useSiteInfo);
return true;
}

return false;
}

private static TypeWithAnnotations GetSpanElementType(TypeSymbol type)
{
Debug.Assert(type.IsSpan() || type.IsReadOnlySpan());
return ((NamedTypeSymbol)type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0];
Copy link
Member

@333fred 333fred Aug 8, 2024

Choose a reason for hiding this comment

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

Consider assert that type is Span or ROS. #Resolved

}

private static TypeWithAnnotations GetSpanOrSZArrayElementType(TypeSymbol type)
{
return type is ArrayTypeSymbol arraySource
? arraySource.ElementTypeWithAnnotations
: GetSpanElementType(type);
}

private enum ExactOrBoundsKind
{
Exact,
Expand Down Expand Up @@ -1922,6 +1978,13 @@ private void LowerBoundInference(TypeWithAnnotations source, TypeWithAnnotations
return;
}

// SPEC: * V is a Span<V1> and U is an array type U1[] or a Span<U1>
// SPEC: * V is a ReadOnlySpan<V1> and U is an array type U1[] or a Span<U1> or ReadOnlySpan<U1>
if (LowerBoundSpanInference(source.Type, target.Type, ref useSiteInfo))
{
return;
}

// UNDONE: At this point we could also do an inference from non-nullable U
// UNDONE: to nullable V.
// UNDONE:
Expand Down Expand Up @@ -2055,6 +2118,44 @@ private bool LowerBoundArrayInference(TypeSymbol source, TypeSymbol target, ref
return true;
}

private bool LowerBoundSpanInference(TypeSymbol source, TypeSymbol target, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
Debug.Assert(source is not null);
Debug.Assert(target is not null);

if (IsFeatureFirstClassSpanEnabled && (
// SPEC: * V is a Span<V1> and U is an array type U1[] or a Span<U1>
(
target.IsSpan() &&
(source.IsSZArray() || source.IsSpan())
) ||
// SPEC: * V is a ReadOnlySpan<V1> and U is an array type U1[] or a Span<U1> or ReadOnlySpan<U1>
(
target.IsReadOnlySpan() &&
(source.IsSZArray() || source.IsSpan() || source.IsReadOnlySpan())
)
))
{
var sourceElementType = GetSpanOrSZArrayElementType(source);
var targetElementType = GetSpanElementType(target);

// SPEC: * If U1 is not known to be a reference type then an exact inference is made
// SPEC: * If V is a Span<V1>, then an exact inference is made
if (!sourceElementType.Type.IsReferenceType || target.IsSpan())
{
ExactInference(sourceElementType, targetElementType, ref useSiteInfo);
}
else
{
LowerBoundInference(sourceElementType, targetElementType, ref useSiteInfo);
}

return true;
}

return false;
}

private bool LowerBoundNullableInference(TypeWithAnnotations source, TypeWithAnnotations target, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
return ExactOrBoundsNullableInference(ExactOrBoundsKind.LowerBound, source, target, ref useSiteInfo);
Expand Down
Loading
Loading