提交 698b9e0e 编写于 作者: V Vladimir Sadov 提交者: GitHub

Merge pull request #22203 from VSadov/relaxedEscape

Relaxed escape rules for spans
...@@ -3629,20 +3629,20 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node ...@@ -3629,20 +3629,20 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
{ {
var currentScope = this.LocalScopeDepth; var currentScope = this.LocalScopeDepth;
// ref-escape must agree on both branches. // val-escape must agree on both branches.
uint whenTrueEscape = GetRefEscape(trueExpr, currentScope); uint whenTrueEscape = GetValEscape(trueExpr, currentScope);
uint whenFalseEscape = GetRefEscape(falseExpr, currentScope); uint whenFalseEscape = GetValEscape(falseExpr, currentScope);
if (whenTrueEscape != whenFalseEscape) if (whenTrueEscape != whenFalseEscape)
{ {
// ask the one with narrower escape, for the wider - hopefully the errors will make the violation easier to fix. // ask the one with narrower escape, for the wider - hopefully the errors will make the violation easier to fix.
if (whenTrueEscape < whenFalseEscape) if (whenTrueEscape < whenFalseEscape)
{ {
CheckRefEscape(falseExpr.Syntax, falseExpr, currentScope, whenTrueEscape, checkingReceiver: false, diagnostics: diagnostics); CheckValEscape(falseExpr.Syntax, falseExpr, currentScope, whenTrueEscape, checkingReceiver: false, diagnostics: diagnostics);
} }
else else
{ {
CheckRefEscape(trueExpr.Syntax, trueExpr, currentScope, whenFalseEscape, checkingReceiver: false, diagnostics: diagnostics); CheckValEscape(trueExpr.Syntax, trueExpr, currentScope, whenFalseEscape, checkingReceiver: false, diagnostics: diagnostics);
} }
diagnostics.Add(ErrorCode.ERR_MismatchedRefEscapeInTernary, node.Location); diagnostics.Add(ErrorCode.ERR_MismatchedRefEscapeInTernary, node.Location);
......
...@@ -49,11 +49,21 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node ...@@ -49,11 +49,21 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
ConstantValue conditionConstantValue = rewrittenCondition.ConstantValue; ConstantValue conditionConstantValue = rewrittenCondition.ConstantValue;
if (conditionConstantValue == ConstantValue.True) if (conditionConstantValue == ConstantValue.True)
{ {
return EnsureNotAssignableIfUsedAsMethodReceiver(rewrittenConsequence); if (!isRef)
{
rewrittenConsequence = EnsureNotAssignableIfUsedAsMethodReceiver(rewrittenConsequence);
}
return rewrittenConsequence;
} }
else if (conditionConstantValue == ConstantValue.False) else if (conditionConstantValue == ConstantValue.False)
{ {
return EnsureNotAssignableIfUsedAsMethodReceiver(rewrittenAlternative); if (!isRef)
{
rewrittenAlternative = EnsureNotAssignableIfUsedAsMethodReceiver(rewrittenAlternative);
}
return rewrittenAlternative;
} }
else else
{ {
......
...@@ -662,10 +662,7 @@ static void Main() ...@@ -662,10 +662,7 @@ static void Main()
comp.VerifyEmitDiagnostics( comp.VerifyEmitDiagnostics(
// (15,27): error CS8168: Cannot return local 'local1' by reference because it is not a ref local // (15,27): error CS8168: Cannot return local 'local1' by reference because it is not a ref local
// return ref b? ref local1: ref local2; // return ref b? ref local1: ref local2;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local1").WithArguments("local1").WithLocation(15, 27), Diagnostic(ErrorCode.ERR_RefReturnLocal, "local1").WithArguments("local1").WithLocation(15, 27)
// (15,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref b? ref local1: ref local2;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "b? ref local1: ref local2").WithLocation(15, 20)
); );
} }
...@@ -696,10 +693,7 @@ static void Main() ...@@ -696,10 +693,7 @@ static void Main()
comp.VerifyEmitDiagnostics( comp.VerifyEmitDiagnostics(
// (14,37): error CS8168: Cannot return local 'local2' by reference because it is not a ref local // (14,37): error CS8168: Cannot return local 'local2' by reference because it is not a ref local
// return ref b? ref val1: ref local2; // return ref b? ref val1: ref local2;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local2").WithArguments("local2").WithLocation(14, 37), Diagnostic(ErrorCode.ERR_RefReturnLocal, "local2").WithArguments("local2").WithLocation(14, 37)
// (14,20): error CS8351: Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
// return ref b? ref val1: ref local2;
Diagnostic(ErrorCode.ERR_MismatchedRefEscapeInTernary, "b? ref val1: ref local2").WithLocation(14, 20)
); );
} }
...@@ -735,10 +729,7 @@ struct S1 ...@@ -735,10 +729,7 @@ struct S1
comp.VerifyEmitDiagnostics( comp.VerifyEmitDiagnostics(
// (14,38): error CS8168: Cannot return local 'local2' by reference because it is not a ref local // (14,38): error CS8168: Cannot return local 'local2' by reference because it is not a ref local
// return ref (b? ref val1: ref local2).x; // return ref (b? ref val1: ref local2).x;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local2").WithArguments("local2").WithLocation(14, 38), Diagnostic(ErrorCode.ERR_RefReturnLocal, "local2").WithArguments("local2").WithLocation(14, 38)
// (14,21): error CS8351: Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
// return ref (b? ref val1: ref local2).x;
Diagnostic(ErrorCode.ERR_MismatchedRefEscapeInTernary, "b? ref val1: ref local2").WithLocation(14, 21)
); );
} }
...@@ -773,12 +764,9 @@ struct S1 ...@@ -773,12 +764,9 @@ struct S1
var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe);
comp.VerifyEmitDiagnostics( comp.VerifyEmitDiagnostics(
// (14,46): error CS8168: Cannot return local 'local2' by reference because it is not a ref local // (15,20): error CS8157: Cannot return 'temp' by reference because it was initialized to a value that cannot be returned by reference
// ref var temp = ref (b? ref val1: ref local2).x; // return ref temp;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local2").WithArguments("local2").WithLocation(14, 46), Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "temp").WithArguments("temp").WithLocation(15, 20)
// (14,29): error CS8351: Branches of a ref ternary operator cannot refer to variables with incompatible declaration scopes.
// ref var temp = ref (b? ref val1: ref local2).x;
Diagnostic(ErrorCode.ERR_MismatchedRefEscapeInTernary, "b? ref val1: ref local2").WithLocation(14, 29)
); );
} }
...@@ -828,6 +816,81 @@ .maxstack 1 ...@@ -828,6 +816,81 @@ .maxstack 1
"); ");
} }
[Fact]
public void TestRefConditionalSafeToReturn2()
{
var source = @"
class C
{
static void Main()
{
Test() ++;
System.Console.WriteLine(val1.x);
}
static ref int Test()
{
return ref (true? ref val1: ref val2).x;
}
static S1 val1;
static S1 val2;
struct S1
{
public int x;
}
}
";
var comp = CompileAndVerify(source, expectedOutput: "1", verify: false);
comp.VerifyDiagnostics();
comp.VerifyIL("C.Test", @"
{
// Code size 11 (0xb)
.maxstack 1
IL_0000: ldsflda ""C.S1 C.val1""
IL_0005: ldflda ""int C.S1.x""
IL_000a: ret
}
");
}
[Fact]
public void TestRefConditionalSafeToReturn3()
{
var source = @"
class C
{
static void Main()
{
(false? ref val1: ref val2) = (true? 1: val2);
(true? ref val1: ref val2) = (false? ref val1: ref val2);
System.Console.WriteLine(val1);
}
static int val1;
static int val2;
}
";
var comp = CompileAndVerify(source, expectedOutput: "1", verify: false);
comp.VerifyDiagnostics();
comp.VerifyIL("C.Main()", @"
{
// Code size 27 (0x1b)
.maxstack 1
IL_0000: ldc.i4.1
IL_0001: stsfld ""int C.val2""
IL_0006: ldsfld ""int C.val2""
IL_000b: stsfld ""int C.val1""
IL_0010: ldsfld ""int C.val1""
IL_0015: call ""void System.Console.WriteLine(int)""
IL_001a: ret
}
");
}
[Fact] [Fact]
public void TestRefConditionalDifferentTypes1() public void TestRefConditionalDifferentTypes1()
{ {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册