提交 98b2c040 编写于 作者: V vsadov

Considering receivers of calls + more tests

上级 0e9dc4ca
...@@ -911,6 +911,7 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV ...@@ -911,6 +911,7 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV
private static bool CheckInvocationEscape( private static bool CheckInvocationEscape(
SyntaxNode syntax, SyntaxNode syntax,
Symbol symbol, Symbol symbol,
BoundExpression receiverOpt,
ImmutableArray<ParameterSymbol> parameters, ImmutableArray<ParameterSymbol> parameters,
ImmutableArray<BoundExpression> args, ImmutableArray<BoundExpression> args,
ImmutableArray<RefKind> argRefKinds, ImmutableArray<RefKind> argRefKinds,
...@@ -920,8 +921,6 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV ...@@ -920,8 +921,6 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV
uint escapeTo, uint escapeTo,
DiagnosticBag diagnostics) DiagnosticBag diagnostics)
{ {
//TODO: VS ref-like receiver
ArrayBuilder<bool> inParametersMatchedWithArgs = null; ArrayBuilder<bool> inParametersMatchedWithArgs = null;
// check all arguments that are not passed by value // check all arguments that are not passed by value
...@@ -981,8 +980,14 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV ...@@ -981,8 +980,14 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV
} }
} }
} }
inParametersMatchedWithArgs?.Free(); inParametersMatchedWithArgs?.Free();
// check receiver if ref-like
if (receiverOpt?.Type?.IsByRefLikeType == true)
{
return CheckValEscape(receiverOpt.Syntax, receiverOpt, escapeFrom, escapeTo, false, diagnostics);
}
return true; return true;
} }
...@@ -992,14 +997,13 @@ private static ErrorCode GetStandardCallEscapeError(bool checkingReceiver) ...@@ -992,14 +997,13 @@ private static ErrorCode GetStandardCallEscapeError(bool checkingReceiver)
} }
private static uint GetInvocationEscape( private static uint GetInvocationEscape(
BoundExpression receiverOpt,
ImmutableArray<ParameterSymbol> parameters, ImmutableArray<ParameterSymbol> parameters,
ImmutableArray<BoundExpression> args, ImmutableArray<BoundExpression> args,
ImmutableArray<RefKind> argRefKinds, ImmutableArray<RefKind> argRefKinds,
ImmutableArray<int> argToParamsOpt, ImmutableArray<int> argToParamsOpt,
uint scopeOfTheContainingExpression) uint scopeOfTheContainingExpression)
{ {
//TODO: VS ref-like receiver
ArrayBuilder<bool> inParametersMatchedWithArgs = null; ArrayBuilder<bool> inParametersMatchedWithArgs = null;
//by default it is safe to escape //by default it is safe to escape
...@@ -1059,6 +1063,13 @@ private static ErrorCode GetStandardCallEscapeError(bool checkingReceiver) ...@@ -1059,6 +1063,13 @@ private static ErrorCode GetStandardCallEscapeError(bool checkingReceiver)
} }
inParametersMatchedWithArgs?.Free(); inParametersMatchedWithArgs?.Free();
// check receiver if ref-like
if (receiverOpt?.Type?.IsByRefLikeType == true)
{
return GetValEscape(receiverOpt, scopeOfTheContainingExpression);
}
return escapeScope; return escapeScope;
} }
...@@ -1417,6 +1428,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint ...@@ -1417,6 +1428,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape( return CheckInvocationEscape(
call.Syntax, call.Syntax,
methodSymbol, methodSymbol,
call.ReceiverOpt,
methodSymbol.Parameters, methodSymbol.Parameters,
call.Arguments, call.Arguments,
call.ArgumentRefKindsOpt, call.ArgumentRefKindsOpt,
...@@ -1438,6 +1450,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint ...@@ -1438,6 +1450,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape( return CheckInvocationEscape(
indexerAccess.Syntax, indexerAccess.Syntax,
indexerSymbol, indexerSymbol,
indexerAccess.ReceiverOpt,
indexerSymbol.Parameters, indexerSymbol.Parameters,
indexerAccess.Arguments, indexerAccess.Arguments,
indexerAccess.ArgumentRefKindsOpt, indexerAccess.ArgumentRefKindsOpt,
...@@ -1460,6 +1473,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint ...@@ -1460,6 +1473,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape( return CheckInvocationEscape(
propertyAccess.Syntax, propertyAccess.Syntax,
propertySymbol, propertySymbol,
propertyAccess.ReceiverOpt,
default, default,
default, default,
default, default,
...@@ -1603,6 +1617,7 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin ...@@ -1603,6 +1617,7 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin
} }
return GetInvocationEscape( return GetInvocationEscape(
call.ReceiverOpt,
methodSymbol.Parameters, methodSymbol.Parameters,
call.Arguments, call.Arguments,
call.ArgumentRefKindsOpt, call.ArgumentRefKindsOpt,
...@@ -1614,6 +1629,7 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin ...@@ -1614,6 +1629,7 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin
var indexerSymbol = indexerAccess.Indexer; var indexerSymbol = indexerAccess.Indexer;
return GetInvocationEscape( return GetInvocationEscape(
indexerAccess.ReceiverOpt,
indexerSymbol.Parameters, indexerSymbol.Parameters,
indexerAccess.Arguments, indexerAccess.Arguments,
indexerAccess.ArgumentRefKindsOpt, indexerAccess.ArgumentRefKindsOpt,
...@@ -1626,6 +1642,7 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin ...@@ -1626,6 +1642,7 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin
// not passing any arguments/parameters // not passing any arguments/parameters
return GetInvocationEscape( return GetInvocationEscape(
propertyAccess.ReceiverOpt,
default, default,
default, default,
default, default,
...@@ -1704,6 +1721,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint ...@@ -1704,6 +1721,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape( return CheckInvocationEscape(
call.Syntax, call.Syntax,
methodSymbol, methodSymbol,
call.ReceiverOpt,
methodSymbol.Parameters, methodSymbol.Parameters,
call.Arguments, call.Arguments,
call.ArgumentRefKindsOpt, call.ArgumentRefKindsOpt,
...@@ -1720,6 +1738,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint ...@@ -1720,6 +1738,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape( return CheckInvocationEscape(
indexerAccess.Syntax, indexerAccess.Syntax,
indexerSymbol, indexerSymbol,
indexerAccess.ReceiverOpt,
indexerSymbol.Parameters, indexerSymbol.Parameters,
indexerAccess.Arguments, indexerAccess.Arguments,
indexerAccess.ArgumentRefKindsOpt, indexerAccess.ArgumentRefKindsOpt,
...@@ -1737,6 +1756,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint ...@@ -1737,6 +1756,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape( return CheckInvocationEscape(
propertyAccess.Syntax, propertyAccess.Syntax,
propertySymbol, propertySymbol,
propertyAccess.ReceiverOpt,
default, default,
default, default,
default, default,
...@@ -1753,6 +1773,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint ...@@ -1753,6 +1773,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
var escape = CheckInvocationEscape( var escape = CheckInvocationEscape(
objectCreation.Syntax, objectCreation.Syntax,
constructorSymbol, constructorSymbol,
null,
constructorSymbol.Parameters, constructorSymbol.Parameters,
objectCreation.Arguments, objectCreation.Arguments,
objectCreation.ArgumentRefKindsOpt, objectCreation.ArgumentRefKindsOpt,
...@@ -1823,6 +1844,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin ...@@ -1823,6 +1844,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
var methodSymbol = call.Method; var methodSymbol = call.Method;
return GetInvocationEscape( return GetInvocationEscape(
call.ReceiverOpt,
methodSymbol.Parameters, methodSymbol.Parameters,
call.Arguments, call.Arguments,
call.ArgumentRefKindsOpt, call.ArgumentRefKindsOpt,
...@@ -1834,6 +1856,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin ...@@ -1834,6 +1856,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
var indexerSymbol = indexerAccess.Indexer; var indexerSymbol = indexerAccess.Indexer;
return GetInvocationEscape( return GetInvocationEscape(
indexerAccess.ReceiverOpt,
indexerSymbol.Parameters, indexerSymbol.Parameters,
indexerAccess.Arguments, indexerAccess.Arguments,
indexerAccess.ArgumentRefKindsOpt, indexerAccess.ArgumentRefKindsOpt,
...@@ -1846,6 +1869,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin ...@@ -1846,6 +1869,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
// not passing any arguments/parameters // not passing any arguments/parameters
return GetInvocationEscape( return GetInvocationEscape(
propertyAccess.ReceiverOpt,
default, default,
default, default,
default, default,
...@@ -1857,6 +1881,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin ...@@ -1857,6 +1881,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
var constructorSymbol = objectCreation.Constructor; var constructorSymbol = objectCreation.Constructor;
var escape = GetInvocationEscape( var escape = GetInvocationEscape(
null,
constructorSymbol.Parameters, constructorSymbol.Parameters,
objectCreation.Arguments, objectCreation.Arguments,
objectCreation.ArgumentRefKindsOpt, objectCreation.ArgumentRefKindsOpt,
......
...@@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics ...@@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
public class RefEscapingTests : CompilingTestBase public class RefEscapingTests : CompilingTestBase
{ {
[Fact()] [Fact()]
public void SimpleRefLikeReturnEscape() public void RefLikeReturnEscape()
{ {
var text = @" var text = @"
class Program class Program
...@@ -29,7 +29,7 @@ static void Main() ...@@ -29,7 +29,7 @@ static void Main()
return ref (new int[1])[0]; return ref (new int[1])[0];
} }
static S1 Test2(ref int arg) static S1 MayWrap(ref int arg)
{ {
return default; return default;
} }
...@@ -37,7 +37,7 @@ static S1 Test2(ref int arg) ...@@ -37,7 +37,7 @@ static S1 Test2(ref int arg)
static ref int Test3() static ref int Test3()
{ {
int local = 42; int local = 42;
return ref Test1(Test2(ref local)); return ref Test1(MayWrap(ref local));
} }
ref struct S1 ref struct S1
...@@ -46,20 +46,20 @@ static S1 Test2(ref int arg) ...@@ -46,20 +46,20 @@ static S1 Test2(ref int arg)
} }
"; ";
CreateStandardCompilation(text).VerifyDiagnostics( CreateStandardCompilation(text).VerifyDiagnostics(
// (21,40): error CS8168: Cannot return local 'local' by reference because it is not a ref local // (21,42): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// return ref Test1(Test2(ref local)); // return ref Test1(MayWrap(ref local));
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(21, 40), Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(21, 42),
// (21,30): error CS8521: Cannot use a result of 'Program.Test2(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope // (21,30): error CS8521: Cannot use a result of 'Program.MayWrap(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// return ref Test1(Test2(ref local)); // return ref Test1(MayWrap(ref local));
Diagnostic(ErrorCode.ERR_EscapeCall, "Test2(ref local)").WithArguments("Program.Test2(ref int)", "arg").WithLocation(21, 30), Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref local)").WithArguments("Program.MayWrap(ref int)", "arg").WithLocation(21, 30),
// (21,24): error CS8521: Cannot use a result of 'Program.Test1(Program.S1)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope // (21,24): error CS8521: Cannot use a result of 'Program.Test1(Program.S1)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// return ref Test1(Test2(ref local)); // return ref Test1(MayWrap(ref local));
Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(Test2(ref local))").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(21, 24) Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(MayWrap(ref local))").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(21, 24)
); );
} }
[Fact()] [Fact()]
public void SimpleRefLikeReturnEscape1() public void RefLikeReturnEscape1()
{ {
var text = @" var text = @"
class Program class Program
...@@ -73,7 +73,7 @@ static void Main() ...@@ -73,7 +73,7 @@ static void Main()
return ref (new int[1])[0]; return ref (new int[1])[0];
} }
static S1 Test2(ref int arg) static S1 MayWrap(ref int arg)
{ {
return default; return default;
} }
...@@ -81,7 +81,7 @@ static S1 Test2(ref int arg) ...@@ -81,7 +81,7 @@ static S1 Test2(ref int arg)
static ref int Test3() static ref int Test3()
{ {
int local = 42; int local = 42;
var sp = Test2(ref local); var sp = MayWrap(ref local);
return ref Test1(sp); return ref Test1(sp);
} }
...@@ -98,7 +98,7 @@ static S1 Test2(ref int arg) ...@@ -98,7 +98,7 @@ static S1 Test2(ref int arg)
} }
[Fact()] [Fact()]
public void SimpleRefLikeReturnEscapeInParam() public void RefLikeReturnEscapeInParam()
{ {
var text = @" var text = @"
class Program class Program
...@@ -112,7 +112,7 @@ static void Main() ...@@ -112,7 +112,7 @@ static void Main()
return ref (new int[1])[0]; return ref (new int[1])[0];
} }
static S1 Test2(in int arg) static S1 MayWrap(in int arg)
{ {
return default; return default;
} }
...@@ -120,10 +120,10 @@ static S1 Test2(in int arg) ...@@ -120,10 +120,10 @@ static S1 Test2(in int arg)
static ref int Test3() static ref int Test3()
{ {
int local = 42; int local = 42;
var sp = Test2(local); var sp = MayWrap(local);
// not an error // not an error
sp = Test2(local); sp = MayWrap(local);
// not an error // not an error
sp = sp; sp = sp;
...@@ -148,7 +148,7 @@ static S1 Test2(in int arg) ...@@ -148,7 +148,7 @@ static S1 Test2(in int arg)
} }
[Fact()] [Fact()]
public void SimpleRefLikeReturnEscapeInParamOptional() public void RefLikeReturnEscapeInParamOptional()
{ {
var text = @" var text = @"
class Program class Program
...@@ -162,7 +162,7 @@ static void Main() ...@@ -162,7 +162,7 @@ static void Main()
return ref (new int[1])[0]; return ref (new int[1])[0];
} }
static S1 Test2(in int arg = 123) static S1 MayWrap(in int arg = 123)
{ {
return default; return default;
} }
...@@ -170,7 +170,7 @@ static S1 Test2(in int arg = 123) ...@@ -170,7 +170,7 @@ static S1 Test2(in int arg = 123)
static ref int Test3() static ref int Test3()
{ {
// error here // error here
return ref Test1(Test2()); return ref Test1(MayWrap());
} }
ref struct S1 ref struct S1
...@@ -179,62 +179,276 @@ static S1 Test2(in int arg = 123) ...@@ -179,62 +179,276 @@ static S1 Test2(in int arg = 123)
} }
"; ";
CreateStandardCompilation(text).VerifyDiagnostics( CreateStandardCompilation(text).VerifyDiagnostics(
// (21,30): error CS8521: Cannot use a result of 'Program.Test2(in int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope // (21,30): error CS8521: Cannot use a result of 'Program.MayWrap(in int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// return ref Test1(Test2()); // return ref Test1(MayWrap());
Diagnostic(ErrorCode.ERR_EscapeCall, "Test2()").WithArguments("Program.Test2(in int)", "arg").WithLocation(21, 30), Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap()").WithArguments("Program.MayWrap(in int)", "arg").WithLocation(21, 30),
// (21,24): error CS8521: Cannot use a result of 'Program.Test1(Program.S1)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope // (21,24): error CS8521: Cannot use a result of 'Program.Test1(Program.S1)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// return ref Test1(Test2()); // return ref Test1(MayWrap());
Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(Test2())").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(21, 24) Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(MayWrap())").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(21, 24)
); );
} }
[Fact()] [Fact()]
public void SimpleRefLikeScopeEscape() public void RefLikeScopeEscape()
{ {
var text = @" var text = @"
class Program class Program
{ {
static void Main() static void Main()
{ {
int outer = 1;
S1 x = MayWrap(ref outer);
{
int inner = 1;
// valid
x = MayWrap(ref outer);
// error
x = MayWrap(ref inner);
}
}
static S1 MayWrap(ref int arg)
{
return default;
}
ref struct S1
{
}
}
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (17,33): error CS8520: Cannot use local 'inner' in this context because it may expose referenced variables outside of their declaration scope
// x = MayWrap(ref inner);
Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(17, 33),
// (17,21): error CS8521: Cannot use a result of 'Program.MayWrap(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// x = MayWrap(ref inner);
Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref inner)").WithArguments("Program.MayWrap(ref int)", "arg").WithLocation(17, 21)
);
}
[Fact()]
public void RefLikeScopeEscapeReturnable()
{
var text = @"
class Program
{
static void Main()
{
int outer = 1;
// make x returnable
S1 x = default; S1 x = default;
{
int inner = 1;
// valid
x = MayWrap(ref outer);
// error
x = MayWrap(ref inner);
}
}
static S1 MayWrap(ref int arg)
{
return default;
}
ref struct S1
{
}
}
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (15,33): error CS8168: Cannot return local 'outer' by reference because it is not a ref local
// x = MayWrap(ref outer);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "outer").WithArguments("outer").WithLocation(15, 33),
// (15,21): error CS8521: Cannot use a result of 'Program.MayWrap(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// x = MayWrap(ref outer);
Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref outer)").WithArguments("Program.MayWrap(ref int)", "arg").WithLocation(15, 21),
// (18,33): error CS8168: Cannot return local 'inner' by reference because it is not a ref local
// x = MayWrap(ref inner);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "inner").WithArguments("inner").WithLocation(18, 33),
// (18,21): error CS8521: Cannot use a result of 'Program.MayWrap(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// x = MayWrap(ref inner);
Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref inner)").WithArguments("Program.MayWrap(ref int)", "arg").WithLocation(18, 21)
);
}
[Fact()]
public void RefLikeScopeEscapeThis()
{
var text = @"
class Program
{
static void Main()
{
int outer = 1; int outer = 1;
S1 x = MayWrap(ref outer);
{ {
int inner = 1; int inner = 1;
// valid // valid
x = Test1(ref outer); x = S1.NotSlice(1);
// valid
x = MayWrap(ref outer).Slice(1);
// error // error
x = Test1(ref inner); x = MayWrap(ref inner).Slice(1);
} }
} }
static S1 Test1(ref int arg) static S1 MayWrap(ref int arg)
{ {
return default; return default;
} }
ref struct S1 ref struct S1
{ {
public static S1 NotSlice(int x) => default;
public S1 Slice(int x) => this;
} }
} }
"; ";
CreateStandardCompilation(text).VerifyDiagnostics( CreateStandardCompilation(text).VerifyDiagnostics(
// (14,31): error CS8168: Cannot return local 'outer' by reference because it is not a ref local // (20,33): error CS8520: Cannot use local 'inner' in this context because it may expose referenced variables outside of their declaration scope
// x = Test1(ref outer); // x = MayWrap(ref inner).Slice(1);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "outer").WithArguments("outer").WithLocation(14, 31), Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(20, 33),
// (14,21): error CS8521: Cannot use a result of 'Program.Test1(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope // (20,21): error CS8521: Cannot use a result of 'Program.MayWrap(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// x = Test1(ref outer); // x = MayWrap(ref inner).Slice(1);
Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(ref outer)").WithArguments("Program.Test1(ref int)", "arg").WithLocation(14, 21), Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref inner)").WithArguments("Program.MayWrap(ref int)", "arg").WithLocation(20, 21)
// (17,31): error CS8168: Cannot return local 'inner' by reference because it is not a ref local );
// x = Test1(ref inner); }
Diagnostic(ErrorCode.ERR_RefReturnLocal, "inner").WithArguments("inner").WithLocation(17, 31),
// (17,21): error CS8521: Cannot use a result of 'Program.Test1(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope [Fact()]
// x = Test1(ref inner); public void RefLikeScopeEscapeThisRef()
Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(ref inner)").WithArguments("Program.Test1(ref int)", "arg").WithLocation(17, 21) {
var text = @"
class Program
{
static void Main()
{
int outer = 1;
ref S1 x = ref MayWrap(ref outer)[0];
{
int inner = 1;
// valid
x[0] = MayWrap(ref outer).Slice(1)[0];
// PROTOTYPE(span): we may relax this. The LHS indexer cannot possibly return itself byref
// ref-returning calls do not need to include receiver
// error
x[0] = MayWrap(ref inner).Slice(1)[0];
// PROTOTYPE(span): we may relax this. The LHS indexer cannot possibly return itself byref
// ref-returning calls do not need to include receiver
// error
x[x] = MayWrap(ref inner).Slice(1)[0];
// error
x.ReturnsRefArg(ref x) = MayWrap(ref inner).Slice(1)[0];
}
}
static S1 MayWrap(ref int arg)
{
return default;
}
ref struct S1
{
public ref S1 this[int i] => throw null;
public ref S1 this[S1 i] => throw null;
public ref S1 ReturnsRefArg(ref S1 arg) => ref arg;
public S1 Slice(int x) => this;
}
}
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (19,32): error CS8520: Cannot use local 'inner' in this context because it may expose referenced variables outside of their declaration scope
// x[0] = MayWrap(ref inner).Slice(1)[0];
Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(19, 32),
// (19,20): error CS8521: Cannot use a result of 'Program.MayWrap(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// x[0] = MayWrap(ref inner).Slice(1)[0];
Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref inner)").WithArguments("Program.MayWrap(ref int)", "arg").WithLocation(19, 20),
// (24,32): error CS8520: Cannot use local 'inner' in this context because it may expose referenced variables outside of their declaration scope
// x[x] = MayWrap(ref inner).Slice(1)[0];
Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(24, 32),
// (24,20): error CS8521: Cannot use a result of 'Program.MayWrap(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// x[x] = MayWrap(ref inner).Slice(1)[0];
Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref inner)").WithArguments("Program.MayWrap(ref int)", "arg").WithLocation(24, 20),
// (27,50): error CS8520: Cannot use local 'inner' in this context because it may expose referenced variables outside of their declaration scope
// x.ReturnsRefArg(ref x) = MayWrap(ref inner).Slice(1)[0];
Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(27, 50),
// (27,38): error CS8521: Cannot use a result of 'Program.MayWrap(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// x.ReturnsRefArg(ref x) = MayWrap(ref inner).Slice(1)[0];
Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref inner)").WithArguments("Program.MayWrap(ref int)", "arg").WithLocation(27, 38)
);
}
[Fact()]
public void RefLikeScopeEscapeField()
{
var text = @"
class Program
{
static void Main()
{
int outer = 1;
S1 x = MayWrap(ref outer);
{
int inner = 1;
// valid
x.field = MayWrap(ref outer).Slice(1).field;
// error
x.field = MayWrap(ref inner).Slice(1).field;
}
}
static S1 MayWrap(ref int arg)
{
return default;
}
ref struct S1
{
public S0 field;
public S1 Slice(int x) => this;
}
ref struct S0
{
}
}
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (17,35): error CS8520: Cannot use local 'inner' in this context because it may expose referenced variables outside of their declaration scope
// x.field = MayWrap(ref inner).Slice(1).field;
Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(17, 35),
// (17,23): error CS8521: Cannot use a result of 'Program.MayWrap(ref int)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// x.field = MayWrap(ref inner).Slice(1).field;
Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref inner)").WithArguments("Program.MayWrap(ref int)", "arg").WithLocation(17, 23)
); );
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册