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

Disallow ref structs in expression trees #30871

Merged
Merged
Show file tree
Hide file tree
Changes from 6 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 @@ -211,6 +211,18 @@ private void VisitCall(
}
}

public override BoundNode Visit(BoundNode node)
{
if (_inExpressionLambda &&
node is BoundExpression expr &&
expr.Type is TypeSymbol type &&
type.IsByRefLikeType)
{
Error(ErrorCode.ERR_FeatureNotValidInExpressionTree, node, "ref struct");
}
return base.Visit(node);
}

public override BoundNode VisitRefTypeOperator(BoundRefTypeOperator node)
{
if (_inExpressionLambda)
Expand Down Expand Up @@ -342,6 +354,21 @@ public override BoundNode VisitLambda(BoundLambda node)
{
if (_inExpressionLambda)
{
var lambda = node.ExpressionSymbol as MethodSymbol;
if ((object)lambda != null)
{
foreach (var p in lambda.Parameters)
{
if (p.RefKind != RefKind.None && p.Locations.Length != 0)
{
_diagnostics.Add(ErrorCode.ERR_ByRefParameterInExpressionTree, p.Locations[0]);
}
if (p.Type.TypeSymbol?.IsByRefLikeType == true)
{
_diagnostics.Add(ErrorCode.ERR_FeatureNotValidInExpressionTree, p.Locations[0], "ref struct");
}
}
}
switch (node.Syntax.Kind())
{
case SyntaxKind.ParenthesizedLambdaExpression:
Expand All @@ -359,18 +386,6 @@ public override BoundNode VisitLambda(BoundLambda node)
{
Error(ErrorCode.ERR_BadRefReturnExpressionTree, node);
}

var lambda = node.ExpressionSymbol as MethodSymbol;
if ((object)lambda != null)
{
foreach (var p in lambda.Parameters)
{
if (p.RefKind != RefKind.None && p.Locations.Length != 0)
{
_diagnostics.Add(ErrorCode.ERR_ByRefParameterInExpressionTree, p.Locations[0]);
}
}
}
}
break;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ public static NamedTypeSymbol GetDelegateType(this TypeSymbol type)
/// </summary>
public static bool IsExpressionTree(this TypeSymbol _type)
{
// TODO: add Compilation/Binder parameter to get WellKnownType and compare
// TODO: there must be a better way!
var type = _type.OriginalDefinition as NamedTypeSymbol;
return
Expand Down
101 changes: 101 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1533,6 +1533,107 @@ static void Main()
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "y = y").WithLocation(9, 45));
}

[Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")]
public void RefStructExpressionTree()
{
var text = @"
using System;
using System.Linq.Expressions;
public class Class1
{
public void Method1()
{
Method((Class1 c) => c.Method2(default(Struct1)));
}

public void Method2(Struct1 s1) { }

public static void Method<T>(Expression<Action<T>> expression) { }
}

public ref struct Struct1 { }
";
var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics(
// (8,40): error CS7053: An expression tree may not contain 'ref struct'
// Method((Class1 c) => c.Method2(default(Struct1)));
Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "default(Struct1)").WithArguments("ref struct").WithLocation(8, 40));
}

[Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")]
public void RefStructNewExpressionTree()
{
var text = @"
using System;
using System.Linq.Expressions;
public class Class1
{
public void Method1()
{
Method((Class1 c) => c.Method2(new Struct1()));
}

public void Method2(Struct1 s1) { }

public static void Method<T>(Expression<Action<T>> expression) { }
}

public ref struct Struct1 { }
";
var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics(
// (8,40): error CS7053: An expression tree may not contain 'ref struct'
// Method((Class1 c) => c.Method2(new Struct1()));
Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "new Struct1()").WithArguments("ref struct").WithLocation(8, 40));
}

[Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")]
public void RefStructParamExpressionTree()
{
var text = @"
using System.Linq.Expressions;

public delegate void Delegate1(Struct1 s);
public class Class1
{
public void Method1()
{
Method((Struct1 s) => Method2());
}

public void Method2() { }

public static void Method(Expression<Delegate1> expression) { }
}

public ref struct Struct1 { }
";
var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics(
// (9,25): error CS7053: An expression tree may not contain 'ref struct'
// Method((Struct1 s) => Method2());
Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "s").WithArguments("ref struct").WithLocation(9, 25));
}

[Fact, WorkItem(30776, "https://github.com/dotnet/roslyn/issues/30776")]
public void RefStructParamLambda()
{
var text = @"
public delegate void Delegate1(Struct1 s);
public class Class1
{
public void Method1()
{
Method((Struct1 s) => Method2());
}

public void Method2() { }

public static void Method(Delegate1 expression) { }
}

public ref struct Struct1 { }
";
var compilation = CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics();
}

[Fact, WorkItem(5363, "https://github.com/dotnet/roslyn/issues/5363")]
public void ReturnInferenceCache_Dynamic_vs_Object_01()
{
Expand Down