Skip to content

Commit

Permalink
Collection expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
jcouv committed Sep 18, 2024
1 parent 616036e commit 74566bf
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

// TODO2 review this file
#nullable disable

using System.Collections.Immutable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,6 @@ private Conversion DeriveStandardExplicitFromOppositeStandardImplicitConversion(

return impliedExplicitConversion;
}
// TODO2 resume here

#nullable enable
/// <summary>
Expand Down Expand Up @@ -1135,6 +1134,7 @@ private Conversion ClassifyImplicitBuiltInConversionFromExpression(BoundExpressi
break;
}

// TODO2
// Neither Span<T>, nor ReadOnlySpan<T> can be wrapped into a Nullable<T>, therefore, there is no point to check for an attempt to convert to Nullable types here.
if (!IsAttributeArgumentBinding && !IsParameterDefaultValueBinding && // These checks prevent cycles caused by attribute binding when HasInlineArrayAttribute check triggers that.
source?.HasInlineArrayAttribute(out _) == true &&
Expand All @@ -1150,6 +1150,7 @@ private Conversion ClassifyImplicitBuiltInConversionFromExpression(BoundExpressi
}

#nullable enable
// TODO2 resume here
private Conversion GetImplicitCollectionExpressionConversion(BoundUnconvertedCollectionExpression collectionExpression, TypeSymbol destination, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
var collectionExpressionConversion = GetCollectionExpressionConversion(collectionExpression, destination, ref useSiteInfo);
Expand Down Expand Up @@ -1654,6 +1655,8 @@ internal static CollectionExpressionTypeKind GetCollectionExpressionTypeKind(CSh
{
Debug.Assert(compilation is { });

destination = destination.ExtendedTypeOrSelf();

if (destination is ArrayTypeSymbol arrayType)
{
if (arrayType.IsSZArray)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ private BoundExpression VisitArrayOrSpanCollectionExpression(BoundCollectionExpr
var elements = node.Elements;
MethodSymbol? spanConstructor = null;

collectionType = collectionType.ExtendedTypeOrSelf();

var arrayType = collectionType as ArrayTypeSymbol;
if (arrayType is null)
{
Expand Down
74 changes: 74 additions & 0 deletions src/Compilers/CSharp/Test/Emit3/ExtensionTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52411,6 +52411,80 @@ public class C
CompileAndVerify(comp, expectedOutput: """42""").VerifyDiagnostics();
}

[Fact]
public void Conversion_ImplicitCollection_ToExtensionOfCollection()
{
var src = """
E e = [42];
e.Print();

public explicit extension E for int[] { public void Print() { System.Console.Write(((int[])this)[0]); } } // TODO2
""";

var comp = CreateCompilation([src, ExtensionErasureAttributeDefinition]);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, expectedOutput: "42");

var tree = comp.SyntaxTrees.First();
var model = comp.GetSemanticModel(tree);
var expr = GetSyntax<CollectionExpressionSyntax>(tree, "[42]");
var conversion = model.GetConversion(expr);
Assert.Equal(ConversionKind.CollectionExpression, conversion.Kind);
}

[Fact]
public void Conversion_ImplicitCollection_ToExtensionCollection()
{
var src = """
E e = [1];

public explicit extension E for object
{
// TODO2 can an extension implement required APIs to become a collection type?
}
""";

// TODO2 should pass
var comp = CreateCompilation([src, ExtensionErasureAttributeDefinition]);
comp.VerifyEmitDiagnostics(
// (2,7): error CS0266: Cannot implicitly convert type 'C' to 'E'. An explicit conversion exists (are you missing a cast?)
// E e = c;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "c").WithArguments("C", "E").WithLocation(2, 7));

var tree = comp.SyntaxTrees.First();
var model = comp.GetSemanticModel(tree);
var expr = GetSyntax<IdentifierNameSyntax>(tree, "c");
var conversion = model.GetConversion(expr);
Assert.Equal(ConversionKind.ExplicitUserDefined, conversion.Kind);
Assert.Equal(ConversionKind.Identity, conversion.UserDefinedFromConversion.Kind);
Assert.Equal(ConversionKind.ExplicitNullable, conversion.UserDefinedToConversion.Kind);
}

[Fact]
public void Conversion_ImplicitCollection_ToExtensionOfNullable()
{
var src = """
E e = [1];

public explicit extension E for Collection? { }
// TODO2
""";

var comp = CreateCompilation([src, ExtensionErasureAttributeDefinition]);
comp.VerifyEmitDiagnostics(
// (2,7): error CS0266: Cannot implicitly convert type 'C' to 'E'. An explicit conversion exists (are you missing a cast?)
// E e = c;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "c").WithArguments("C", "E").WithLocation(2, 7));

var tree = comp.SyntaxTrees.First();
var model = comp.GetSemanticModel(tree);
var expr = GetSyntax<IdentifierNameSyntax>(tree, "c");
var conversion = model.GetConversion(expr);
Assert.Equal(ConversionKind.ExplicitUserDefined, conversion.Kind);
Assert.Equal(ConversionKind.Identity, conversion.UserDefinedFromConversion.Kind);
Assert.Equal(ConversionKind.ExplicitNullable, conversion.UserDefinedToConversion.Kind);
}

[Fact]
public void Conversion_HasImplicitEnumerationConversion()
{
Expand Down

0 comments on commit 74566bf

Please sign in to comment.