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

Considering receivers of calls + more tests

上级 0e9dc4ca
......@@ -911,6 +911,7 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV
private static bool CheckInvocationEscape(
SyntaxNode syntax,
Symbol symbol,
BoundExpression receiverOpt,
ImmutableArray<ParameterSymbol> parameters,
ImmutableArray<BoundExpression> args,
ImmutableArray<RefKind> argRefKinds,
......@@ -920,8 +921,6 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV
uint escapeTo,
DiagnosticBag diagnostics)
{
//TODO: VS ref-like receiver
ArrayBuilder<bool> inParametersMatchedWithArgs = null;
// check all arguments that are not passed by value
......@@ -981,8 +980,14 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV
}
}
}
inParametersMatchedWithArgs?.Free();
// check receiver if ref-like
if (receiverOpt?.Type?.IsByRefLikeType == true)
{
return CheckValEscape(receiverOpt.Syntax, receiverOpt, escapeFrom, escapeTo, false, diagnostics);
}
return true;
}
......@@ -992,14 +997,13 @@ private static ErrorCode GetStandardCallEscapeError(bool checkingReceiver)
}
private static uint GetInvocationEscape(
BoundExpression receiverOpt,
ImmutableArray<ParameterSymbol> parameters,
ImmutableArray<BoundExpression> args,
ImmutableArray<RefKind> argRefKinds,
ImmutableArray<int> argToParamsOpt,
uint scopeOfTheContainingExpression)
{
//TODO: VS ref-like receiver
ArrayBuilder<bool> inParametersMatchedWithArgs = null;
//by default it is safe to escape
......@@ -1059,6 +1063,13 @@ private static ErrorCode GetStandardCallEscapeError(bool checkingReceiver)
}
inParametersMatchedWithArgs?.Free();
// check receiver if ref-like
if (receiverOpt?.Type?.IsByRefLikeType == true)
{
return GetValEscape(receiverOpt, scopeOfTheContainingExpression);
}
return escapeScope;
}
......@@ -1417,6 +1428,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape(
call.Syntax,
methodSymbol,
call.ReceiverOpt,
methodSymbol.Parameters,
call.Arguments,
call.ArgumentRefKindsOpt,
......@@ -1438,6 +1450,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape(
indexerAccess.Syntax,
indexerSymbol,
indexerAccess.ReceiverOpt,
indexerSymbol.Parameters,
indexerAccess.Arguments,
indexerAccess.ArgumentRefKindsOpt,
......@@ -1460,6 +1473,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape(
propertyAccess.Syntax,
propertySymbol,
propertyAccess.ReceiverOpt,
default,
default,
default,
......@@ -1603,6 +1617,7 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin
}
return GetInvocationEscape(
call.ReceiverOpt,
methodSymbol.Parameters,
call.Arguments,
call.ArgumentRefKindsOpt,
......@@ -1614,6 +1629,7 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin
var indexerSymbol = indexerAccess.Indexer;
return GetInvocationEscape(
indexerAccess.ReceiverOpt,
indexerSymbol.Parameters,
indexerAccess.Arguments,
indexerAccess.ArgumentRefKindsOpt,
......@@ -1626,6 +1642,7 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin
// not passing any arguments/parameters
return GetInvocationEscape(
propertyAccess.ReceiverOpt,
default,
default,
default,
......@@ -1704,6 +1721,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape(
call.Syntax,
methodSymbol,
call.ReceiverOpt,
methodSymbol.Parameters,
call.Arguments,
call.ArgumentRefKindsOpt,
......@@ -1720,6 +1738,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape(
indexerAccess.Syntax,
indexerSymbol,
indexerAccess.ReceiverOpt,
indexerSymbol.Parameters,
indexerAccess.Arguments,
indexerAccess.ArgumentRefKindsOpt,
......@@ -1737,6 +1756,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
return CheckInvocationEscape(
propertyAccess.Syntax,
propertySymbol,
propertyAccess.ReceiverOpt,
default,
default,
default,
......@@ -1753,6 +1773,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
var escape = CheckInvocationEscape(
objectCreation.Syntax,
constructorSymbol,
null,
constructorSymbol.Parameters,
objectCreation.Arguments,
objectCreation.ArgumentRefKindsOpt,
......@@ -1823,6 +1844,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
var methodSymbol = call.Method;
return GetInvocationEscape(
call.ReceiverOpt,
methodSymbol.Parameters,
call.Arguments,
call.ArgumentRefKindsOpt,
......@@ -1834,6 +1856,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
var indexerSymbol = indexerAccess.Indexer;
return GetInvocationEscape(
indexerAccess.ReceiverOpt,
indexerSymbol.Parameters,
indexerAccess.Arguments,
indexerAccess.ArgumentRefKindsOpt,
......@@ -1846,6 +1869,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
// not passing any arguments/parameters
return GetInvocationEscape(
propertyAccess.ReceiverOpt,
default,
default,
default,
......@@ -1857,6 +1881,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
var constructorSymbol = objectCreation.Constructor;
var escape = GetInvocationEscape(
null,
constructorSymbol.Parameters,
objectCreation.Arguments,
objectCreation.ArgumentRefKindsOpt,
......
......@@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
public class RefEscapingTests : CompilingTestBase
{
[Fact()]
public void SimpleRefLikeReturnEscape()
public void RefLikeReturnEscape()
{
var text = @"
class Program
......@@ -29,7 +29,7 @@ static void Main()
return ref (new int[1])[0];
}
static S1 Test2(ref int arg)
static S1 MayWrap(ref int arg)
{
return default;
}
......@@ -37,7 +37,7 @@ static S1 Test2(ref int arg)
static ref int Test3()
{
int local = 42;
return ref Test1(Test2(ref local));
return ref Test1(MayWrap(ref local));
}
ref struct S1
......@@ -46,20 +46,20 @@ static S1 Test2(ref int arg)
}
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (21,40): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// return ref Test1(Test2(ref local));
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(21, 40),
// (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
// return ref Test1(Test2(ref local));
Diagnostic(ErrorCode.ERR_EscapeCall, "Test2(ref local)").WithArguments("Program.Test2(ref int)", "arg").WithLocation(21, 30),
// (21,42): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// return ref Test1(MayWrap(ref local));
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(21, 42),
// (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(MayWrap(ref local));
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
// return ref Test1(Test2(ref local));
Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(Test2(ref local))").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(21, 24)
// return ref Test1(MayWrap(ref local));
Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(MayWrap(ref local))").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(21, 24)
);
}
[Fact()]
public void SimpleRefLikeReturnEscape1()
public void RefLikeReturnEscape1()
{
var text = @"
class Program
......@@ -73,7 +73,7 @@ static void Main()
return ref (new int[1])[0];
}
static S1 Test2(ref int arg)
static S1 MayWrap(ref int arg)
{
return default;
}
......@@ -81,7 +81,7 @@ static S1 Test2(ref int arg)
static ref int Test3()
{
int local = 42;
var sp = Test2(ref local);
var sp = MayWrap(ref local);
return ref Test1(sp);
}
......@@ -98,7 +98,7 @@ static S1 Test2(ref int arg)
}
[Fact()]
public void SimpleRefLikeReturnEscapeInParam()
public void RefLikeReturnEscapeInParam()
{
var text = @"
class Program
......@@ -112,7 +112,7 @@ static void Main()
return ref (new int[1])[0];
}
static S1 Test2(in int arg)
static S1 MayWrap(in int arg)
{
return default;
}
......@@ -120,10 +120,10 @@ static S1 Test2(in int arg)
static ref int Test3()
{
int local = 42;
var sp = Test2(local);
var sp = MayWrap(local);
// not an error
sp = Test2(local);
sp = MayWrap(local);
// not an error
sp = sp;
......@@ -148,7 +148,7 @@ static S1 Test2(in int arg)
}
[Fact()]
public void SimpleRefLikeReturnEscapeInParamOptional()
public void RefLikeReturnEscapeInParamOptional()
{
var text = @"
class Program
......@@ -162,7 +162,7 @@ static void Main()
return ref (new int[1])[0];
}
static S1 Test2(in int arg = 123)
static S1 MayWrap(in int arg = 123)
{
return default;
}
......@@ -170,7 +170,7 @@ static S1 Test2(in int arg = 123)
static ref int Test3()
{
// error here
return ref Test1(Test2());
return ref Test1(MayWrap());
}
ref struct S1
......@@ -179,62 +179,276 @@ static S1 Test2(in int arg = 123)
}
";
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
// return ref Test1(Test2());
Diagnostic(ErrorCode.ERR_EscapeCall, "Test2()").WithArguments("Program.Test2(in int)", "arg").WithLocation(21, 30),
// (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(MayWrap());
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
// return ref Test1(Test2());
Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(Test2())").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(21, 24)
// return ref Test1(MayWrap());
Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(MayWrap())").WithArguments("Program.Test1(Program.S1)", "arg").WithLocation(21, 24)
);
}
[Fact()]
public void SimpleRefLikeScopeEscape()
public void RefLikeScopeEscape()
{
var text = @"
class Program
{
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;
{
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;
S1 x = MayWrap(ref outer);
{
int inner = 1;
// valid
x = Test1(ref outer);
x = S1.NotSlice(1);
// valid
x = MayWrap(ref outer).Slice(1);
// 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;
}
ref struct S1
{
public static S1 NotSlice(int x) => default;
public S1 Slice(int x) => this;
}
}
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (14,31): error CS8168: Cannot return local 'outer' by reference because it is not a ref local
// x = Test1(ref outer);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "outer").WithArguments("outer").WithLocation(14, 31),
// (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
// x = Test1(ref outer);
Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(ref outer)").WithArguments("Program.Test1(ref int)", "arg").WithLocation(14, 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
// x = Test1(ref inner);
Diagnostic(ErrorCode.ERR_EscapeCall, "Test1(ref inner)").WithArguments("Program.Test1(ref int)", "arg").WithLocation(17, 21)
// (20,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).Slice(1);
Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(20, 33),
// (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 = MayWrap(ref inner).Slice(1);
Diagnostic(ErrorCode.ERR_EscapeCall, "MayWrap(ref inner)").WithArguments("Program.MayWrap(ref int)", "arg").WithLocation(20, 21)
);
}
[Fact()]
public void RefLikeScopeEscapeThisRef()
{
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.
先完成此消息的编辑!
想要评论请 注册