未验证 提交 9d5bd878 编写于 作者: N Neal Gafter 提交者: GitHub

Compute val escape for recursive pattern-matching (#29188)

Fixes #28633
上级 eee9bf96
......@@ -30,7 +30,8 @@ private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node,
expression = BadExpression(expression.Syntax, expression);
}
BoundPattern pattern = BindPattern(node.Pattern, expression.Type, hasErrors, diagnostics);
uint inputValEscape = GetValEscape(expression, LocalScopeDepth);
BoundPattern pattern = BindPattern(node.Pattern, expression.Type, inputValEscape, hasErrors, diagnostics);
hasErrors |= pattern.HasErrors;
return MakeIsPatternExpression(
node, expression, pattern, GetSpecialType(SpecialType.System_Boolean, diagnostics, node),
......@@ -84,6 +85,7 @@ internal virtual BoundExpression BindSwitchExpressionCore(SwitchExpressionSyntax
internal BoundPattern BindPattern(
PatternSyntax node,
TypeSymbol inputType,
uint inputValEscape,
bool hasErrors,
DiagnosticBag diagnostics)
{
......@@ -93,16 +95,16 @@ internal virtual BoundExpression BindSwitchExpressionCore(SwitchExpressionSyntax
return BindDiscardPattern((DiscardPatternSyntax)node, inputType, hasErrors, diagnostics);
case SyntaxKind.DeclarationPattern:
return BindDeclarationPattern((DeclarationPatternSyntax)node, inputType, hasErrors, diagnostics);
return BindDeclarationPattern((DeclarationPatternSyntax)node, inputType, inputValEscape, hasErrors, diagnostics);
case SyntaxKind.ConstantPattern:
return BindConstantPattern((ConstantPatternSyntax)node, inputType, hasErrors, diagnostics);
case SyntaxKind.RecursivePattern:
return BindRecursivePattern((RecursivePatternSyntax)node, inputType, hasErrors, diagnostics);
return BindRecursivePattern((RecursivePatternSyntax)node, inputType, inputValEscape, hasErrors, diagnostics);
case SyntaxKind.VarPattern:
return BindVarPattern((VarPatternSyntax)node, inputType, hasErrors, diagnostics);
return BindVarPattern((VarPatternSyntax)node, inputType, inputValEscape, hasErrors, diagnostics);
default:
throw ExceptionUtilities.UnexpectedValue(node.Kind());
......@@ -364,6 +366,7 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
private BoundPattern BindDeclarationPattern(
DeclarationPatternSyntax node,
TypeSymbol inputType,
uint inputValEscape,
bool hasErrors,
DiagnosticBag diagnostics)
{
......@@ -383,7 +386,8 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
}
TypeSymbol declType = boundDeclType.Type;
BindPatternDesignation(node, node.Designation, declType, typeSyntax, diagnostics, ref hasErrors, out Symbol variableSymbol, out BoundExpression variableAccess);
inputValEscape = GetValEscape(declType, inputValEscape);
BindPatternDesignation(node, node.Designation, declType, inputValEscape, typeSyntax, diagnostics, ref hasErrors, out Symbol variableSymbol, out BoundExpression variableAccess);
return new BoundDeclarationPattern(node, variableSymbol, variableAccess, boundDeclType, isVar, inputType, hasErrors);
}
......@@ -419,6 +423,7 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
PatternSyntax node,
VariableDesignationSyntax designation,
TypeSymbol declType,
uint inputValEscape,
TypeSyntax typeSyntax,
DiagnosticBag diagnostics,
ref bool hasErrors,
......@@ -439,9 +444,7 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
}
localSymbol.SetType(declType);
// https://github.com/dotnet/roslyn/issues/28633: need to preserve/compute the val escape. The following line
// from master does not work because we don't have a source expression at this point.
// localSymbol.SetValEscape(GetValEscape(sourceExpression, LocalScopeDepth));
localSymbol.SetValEscape(GetValEscape(declType, inputValEscape));
// Check for variable declaration errors.
hasErrors |= localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics);
......@@ -481,6 +484,16 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
}
}
/// <summary>
/// Compute the val escape of an expression of the given <paramref name="type"/>, which is known to be derived
/// from an expression whose escape scope is <paramref name="possibleValEscape"/>. By the language rules, the
/// result is either that same scope (if the type is a ref struct type) or <see cref="Binder.ExternalScope"/>.
/// </summary>
private static uint GetValEscape(TypeSymbol type, uint possibleValEscape)
{
return type.IsByRefLikeType ? possibleValEscape : Binder.ExternalScope;
}
TypeSymbol BindRecursivePatternType(TypeSyntax typeSyntax, TypeSymbol inputType, DiagnosticBag diagnostics, ref bool hasErrors, out BoundTypeExpression boundDeclType)
{
if (typeSyntax != null)
......@@ -507,10 +520,11 @@ TypeSymbol BindRecursivePatternType(TypeSyntax typeSyntax, TypeSymbol inputType,
}
}
private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbol inputType, bool hasErrors, DiagnosticBag diagnostics)
private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbol inputType, uint inputValEscape, bool hasErrors, DiagnosticBag diagnostics)
{
TypeSyntax typeSyntax = node.Type;
TypeSymbol declType = BindRecursivePatternType(typeSyntax, inputType, diagnostics, ref hasErrors, out BoundTypeExpression boundDeclType);
inputValEscape = GetValEscape(declType, inputValEscape);
if (ShouldUseITuple(node, declType, diagnostics, out NamedTypeSymbol iTupleType, out MethodSymbol iTupleGetLength, out MethodSymbol iTupleGetItem))
{
......@@ -521,16 +535,16 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbo
ImmutableArray<BoundSubpattern> deconstructionSubpatterns = default;
if (node.DeconstructionPatternClause != null)
{
deconstructionSubpatterns = BindDeconstructionPatternClause(node.DeconstructionPatternClause, declType, diagnostics, out deconstructMethod, ref hasErrors);
deconstructionSubpatterns = BindDeconstructionPatternClause(node.DeconstructionPatternClause, declType, inputValEscape, diagnostics, out deconstructMethod, ref hasErrors);
}
ImmutableArray<BoundSubpattern> properties = default;
if (node.PropertyPatternClause != null)
{
properties = BindPropertyPatternClause(node.PropertyPatternClause, declType, diagnostics, ref hasErrors);
properties = BindPropertyPatternClause(node.PropertyPatternClause, declType, inputValEscape, diagnostics, ref hasErrors);
}
BindPatternDesignation(node, node.Designation, declType, typeSyntax, diagnostics, ref hasErrors, out Symbol variableSymbol, out BoundExpression variableAccess);
BindPatternDesignation(node, node.Designation, declType, inputValEscape, typeSyntax, diagnostics, ref hasErrors, out Symbol variableSymbol, out BoundExpression variableAccess);
return new BoundRecursivePattern(
syntax: node, declaredType: boundDeclType, inputType: inputType, deconstructMethod: deconstructMethod,
deconstruction: deconstructionSubpatterns, properties: properties, variable: variableSymbol, variableAccess: variableAccess, hasErrors: hasErrors);
......@@ -557,10 +571,12 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbo
diagnostics.Add(ErrorCode.ERR_ArgumentNameInITuplePattern, subpatternSyntax.NameColon.Location);
}
// Since the input has been cast to ITuple, it must be escapable.
const uint valEscape = Binder.ExternalScope;
var boundSubpattern = new BoundSubpattern(
subpatternSyntax,
null,
BindPattern(subpatternSyntax.Pattern, elementType, false, diagnostics));
BindPattern(subpatternSyntax.Pattern, elementType, valEscape, false, diagnostics));
patterns.Add(boundSubpattern);
}
......@@ -570,6 +586,7 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbo
private ImmutableArray<BoundSubpattern> BindDeconstructionPatternClause(
DeconstructionPatternClauseSyntax node,
TypeSymbol declType,
uint inputValEscape,
DiagnosticBag diagnostics,
out MethodSymbol deconstructMethod,
ref bool hasErrors)
......@@ -602,7 +619,7 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbo
BoundSubpattern boundSubpattern = new BoundSubpattern(
subpatternSyntax,
foundField,
BindPattern(subpatternSyntax.Pattern, elementType, isError, diagnostics));
BindPattern(subpatternSyntax.Pattern, elementType, GetValEscape(elementType, inputValEscape), isError, diagnostics));
patterns.Add(boundSubpattern);
}
}
......@@ -648,7 +665,7 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbo
var boundSubpattern = new BoundSubpattern(
subPattern,
parameter,
BindPattern(subPattern.Pattern, elementType, isError, diagnostics)
BindPattern(subPattern.Pattern, elementType, GetValEscape(elementType, inputValEscape), isError, diagnostics)
);
patterns.Add(boundSubpattern);
}
......@@ -786,7 +803,7 @@ private static FieldSymbol CheckIsTupleElement(SyntaxNode node, NamedTypeSymbol
return foundElement;
}
private BoundPattern BindVarPattern(VarPatternSyntax node, TypeSymbol inputType, bool hasErrors, DiagnosticBag diagnostics)
private BoundPattern BindVarPattern(VarPatternSyntax node, TypeSymbol inputType, uint inputValEscape, bool hasErrors, DiagnosticBag diagnostics)
{
TypeSymbol declType = inputType;
Symbol foundSymbol = BindTypeOrAliasOrKeyword(node.VarKeyword, node, diagnostics, out bool isVar);
......@@ -797,10 +814,10 @@ private BoundPattern BindVarPattern(VarPatternSyntax node, TypeSymbol inputType,
hasErrors = true;
}
return BindVarDesignation(node, node.Designation, inputType, hasErrors, diagnostics);
return BindVarDesignation(node, node.Designation, inputType, inputValEscape, hasErrors, diagnostics);
}
private BoundPattern BindVarDesignation(VarPatternSyntax node, VariableDesignationSyntax designation, TypeSymbol inputType, bool hasErrors, DiagnosticBag diagnostics)
private BoundPattern BindVarDesignation(VarPatternSyntax node, VariableDesignationSyntax designation, TypeSymbol inputType, uint inputValEscape, bool hasErrors, DiagnosticBag diagnostics)
{
switch (designation.Kind())
{
......@@ -811,7 +828,7 @@ private BoundPattern BindVarDesignation(VarPatternSyntax node, VariableDesignati
case SyntaxKind.SingleVariableDesignation:
{
BindPatternDesignation(
node: node, designation: designation, declType: inputType, typeSyntax: null, diagnostics: diagnostics,
node: node, designation: designation, declType: inputType, inputValEscape: inputValEscape, typeSyntax: null, diagnostics: diagnostics,
hasErrors: ref hasErrors, variableSymbol: out Symbol variableSymbol, variableAccess: out BoundExpression variableAccess);
var boundOperandType = new BoundTypeExpression(syntax: node, aliasOpt: null, type: inputType); // fake a type expression for the variable's type
return new BoundDeclarationPattern(designation, variableSymbol, variableAccess, boundOperandType, isVar: true, inputType: inputType, hasErrors: hasErrors);
......@@ -837,7 +854,7 @@ private BoundPattern BindVarDesignation(VarPatternSyntax node, VariableDesignati
var variable = tupleDesignation.Variables[i];
bool isError = i >= elementTypes.Length;
TypeSymbol elementType = isError ? CreateErrorType() : elementTypes[i];
BoundPattern pattern = BindVarDesignation(node, variable, elementType, isError, diagnostics);
BoundPattern pattern = BindVarDesignation(node, variable, elementType, GetValEscape(elementType, inputValEscape), isError, diagnostics);
subPatterns.Add(new BoundSubpattern(variable, symbol: null, pattern));
}
}
......@@ -853,7 +870,7 @@ private BoundPattern BindVarDesignation(VarPatternSyntax node, VariableDesignati
var variable = tupleDesignation.Variables[i];
bool isError = outPlaceholders.IsDefaultOrEmpty || i >= outPlaceholders.Length;
TypeSymbol elementType = isError ? CreateErrorType() : outPlaceholders[i].Type;
BoundPattern pattern = BindVarDesignation(node, variable, elementType, isError, diagnostics);
BoundPattern pattern = BindVarDesignation(node, variable, elementType, GetValEscape(elementType, inputValEscape), isError, diagnostics);
subPatterns.Add(new BoundSubpattern(variable, symbol: null, pattern));
}
}
......@@ -872,6 +889,7 @@ private BoundPattern BindVarDesignation(VarPatternSyntax node, VariableDesignati
ImmutableArray<BoundSubpattern> BindPropertyPatternClause(
PropertyPatternClauseSyntax node,
TypeSymbol inputType,
uint inputValEscape,
DiagnosticBag diagnostics,
ref bool hasErrors)
{
......@@ -897,7 +915,7 @@ private BoundPattern BindVarDesignation(VarPatternSyntax node, VariableDesignati
member = LookupMemberForPropertyPattern(inputType, name, diagnostics, ref hasErrors, out memberType);
}
BoundPattern boundPattern = BindPattern(pattern, memberType, hasErrors, diagnostics);
BoundPattern boundPattern = BindPattern(pattern, memberType, GetValEscape(memberType, inputValEscape), hasErrors, diagnostics);
builder.Add(new BoundSubpattern(p, member, boundPattern));
}
......
......@@ -43,6 +43,8 @@ protected BoundExpression SwitchGoverningExpression
protected TypeSymbol SwitchGoverningType => SwitchGoverningExpression.Type;
protected uint SwitchGoverningValEscape => GetValEscape(SwitchGoverningExpression, LocalScopeDepth);
protected DiagnosticBag SwitchGoverningDiagnostics
{
get
......@@ -212,7 +214,7 @@ private void BuildSwitchLabels(SyntaxList<SwitchLabelSyntax> labelsSyntax, Binde
// bind the pattern, to cause its pattern variables to be inferred if necessary
var matchLabel = (CasePatternSwitchLabelSyntax)labelSyntax;
var pattern = sectionBinder.BindPattern(
matchLabel.Pattern, SwitchGoverningType, labelSyntax.HasErrors, tempDiagnosticBag);
matchLabel.Pattern, SwitchGoverningType, SwitchGoverningValEscape, labelSyntax.HasErrors, tempDiagnosticBag);
break;
default:
......
......@@ -253,7 +253,7 @@ internal override void BindPatternSwitchLabelForInference(CasePatternSwitchLabel
{
var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node;
BoundPattern pattern = sectionBinder.BindPattern(
matchLabelSyntax.Pattern, SwitchGoverningType, node.HasErrors, diagnostics);
matchLabelSyntax.Pattern, SwitchGoverningType, SwitchGoverningValEscape, node.HasErrors, diagnostics);
return new BoundPatternSwitchLabel(node, label, pattern,
matchLabelSyntax.WhenClause != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.WhenClause.Condition, diagnostics) : null,
node.HasErrors);
......
......@@ -36,7 +36,7 @@ internal override BoundSwitchExpressionArm BindSwitchExpressionArm(SwitchExpress
Binder armBinder = this.GetBinder(node);
bool hasErrors = _switchExpressionBinder.SwitchGoverningType.IsErrorType();
ImmutableArray<LocalSymbol> locals = _armScopeBinder.Locals;
BoundPattern pattern = armBinder.BindPattern(node.Pattern, _switchExpressionBinder.SwitchGoverningType, hasErrors, diagnostics);
BoundPattern pattern = armBinder.BindPattern(node.Pattern, _switchExpressionBinder.SwitchGoverningType, _switchExpressionBinder.SwitchGoverningValEscape, hasErrors, diagnostics);
BoundExpression whenClause = node.WhenClause != null
? armBinder.BindBooleanExpression(node.WhenClause.Condition, diagnostics)
: null;
......
......@@ -162,6 +162,8 @@ internal BoundExpression InputExpression
internal TypeSymbol SwitchGoverningType => InputExpression.Type;
internal uint SwitchGoverningValEscape => GetValEscape(InputExpression, LocalScopeDepth);
protected DiagnosticBag InputExpressionDiagnostics
{
get
......
......@@ -381,6 +381,7 @@ protected virtual TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
internal void SetType(TypeSymbol newType)
{
Debug.Assert(!(newType is null));
TypeSymbol originalType = _type;
// In the event that we race to set the type of a local, we should
......
......@@ -6558,9 +6558,9 @@ public static bool M2(bool e)
False");
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/28633")]
[Fact]
[WorkItem(27218, "https://github.com/dotnet/roslyn/issues/27218")]
public void IsPatternMatchingDoesNotCopyEscapeScopes()
public void IsPatternMatchingDoesNotCopyEscapeScopes_01()
{
CreateCompilationWithMscorlibAndSpan(@"
using System;
......@@ -6582,9 +6582,9 @@ public class C
Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(10, 24));
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/28633")]
[Fact]
[WorkItem(27218, "https://github.com/dotnet/roslyn/issues/27218")]
public void CasePatternMatchingDoesNotCopyEscapeScopes()
public void CasePatternMatchingDoesNotCopyEscapeScopes_01()
{
CreateCompilationWithMscorlibAndSpan(@"
using System;
......@@ -6608,5 +6608,235 @@ public class C
// return ref inner[5];
Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(12, 28));
}
[Fact]
[WorkItem(28633, "https://github.com/dotnet/roslyn/issues/28633")]
public void CasePatternMatchingDoesNotCopyEscapeScopes_02()
{
CreateCompilationWithMscorlibAndSpan(parseOptions: TestOptions.RegularWithRecursivePatterns, text: @"
using System;
public ref struct R
{
public R Prop => this;
public void Deconstruct(out R X, out R Y) => X = Y = this;
public static implicit operator R(Span<int> span) => new R();
}
public class C
{
public R M1()
{
R outer = stackalloc int[100];
switch (outer)
{
case { Prop: var x }: return x; // error 1
}
}
public R M2()
{
R outer = stackalloc int[100];
switch (outer)
{
case { Prop: R x }: return x; // error 2
}
}
public R M3()
{
R outer = stackalloc int[100];
switch (outer)
{
case (var x, var y): return x; // error 3
}
}
public R M4()
{
R outer = stackalloc int[100];
switch (outer)
{
case (R x, R y): return x; // error 4
}
}
public R M5()
{
R outer = stackalloc int[100];
switch (outer)
{
case var (x, y): return x; // error 5
}
}
public R M6()
{
R outer = stackalloc int[100];
switch (outer)
{
case { } x: return x; // error 6
}
}
public R M7()
{
R outer = stackalloc int[100];
switch (outer)
{
case (_, _) x: return x; // error 7
}
}
}
").VerifyDiagnostics(
// (16,42): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// case { Prop: var x }: return x; // error 1
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(16, 42),
// (24,40): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// case { Prop: R x }: return x; // error 2
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(24, 40),
// (32,41): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// case (var x, var y): return x; // error 3
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(32, 41),
// (40,37): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// case (R x, R y): return x; // error 4
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(40, 37),
// (48,37): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// case var (x, y): return x; // error 5
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(48, 37),
// (56,32): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// case { } x: return x; // error 6
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(56, 32),
// (64,35): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// case (_, _) x: return x; // error 7
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(64, 35)
);
}
[Fact]
[WorkItem(28633, "https://github.com/dotnet/roslyn/issues/28633")]
public void IsPatternMatchingDoesNotCopyEscapeScopes_02()
{
CreateCompilationWithMscorlibAndSpan(parseOptions: TestOptions.RegularWithRecursivePatterns, text: @"
using System;
public ref struct R
{
public R Prop => this;
public void Deconstruct(out R X, out R Y) => X = Y = this;
public static implicit operator R(Span<int> span) => new R();
}
public class C
{
public R M1()
{
R outer = stackalloc int[100];
if (outer is { Prop: var x }) return x; // error 1
throw null;
}
public R M2()
{
R outer = stackalloc int[100];
if (outer is { Prop: R x }) return x; // error 2
throw null;
}
public R M3()
{
R outer = stackalloc int[100];
if (outer is (var x, var y)) return x; // error 3
throw null;
}
public R M4()
{
R outer = stackalloc int[100];
if (outer is (R x, R y)) return x; // error 4
throw null;
}
public R M5()
{
R outer = stackalloc int[100];
if (outer is var (x, y)) return x; // error 5
throw null;
}
public R M6()
{
R outer = stackalloc int[100];
if (outer is { } x) return x; // error 6
throw null;
}
public R M7()
{
R outer = stackalloc int[100];
if (outer is (_, _) x) return x; // error 7
throw null;
}
}
").VerifyDiagnostics(
// (14,46): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// if (outer is { Prop: var x }) return x; // error 1
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(14, 46),
// (20,44): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// if (outer is { Prop: R x }) return x; // error 2
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(20, 44),
// (26,45): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// if (outer is (var x, var y)) return x; // error 3
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(26, 45),
// (32,41): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// if (outer is (R x, R y)) return x; // error 4
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(32, 41),
// (38,41): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// if (outer is var (x, y)) return x; // error 5
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(38, 41),
// (44,36): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// if (outer is { } x) return x; // error 6
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(44, 36),
// (50,39): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// if (outer is (_, _) x) return x; // error 7
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(50, 39)
);
}
[Fact]
[WorkItem(28633, "https://github.com/dotnet/roslyn/issues/28633")]
public void EscapeScopeInSubpatternOfNonRefType()
{
CreateCompilationWithMscorlibAndSpan(parseOptions: TestOptions.RegularWithRecursivePatterns, text: @"
using System;
public ref struct R
{
public R RProp => this;
public S SProp => new S();
public void Deconstruct(out S X, out S Y) => X = Y = new S();
public static implicit operator R(Span<int> span) => new R();
}
public struct S
{
public R RProp => new R();
}
public class C
{
public R M1()
{
R outer = stackalloc int[100];
if (outer is { SProp: { RProp: var x }}) return x; // OK
throw null;
}
public R M2()
{
R outer = stackalloc int[100];
switch (outer)
{
case { SProp: { RProp: var x }}: return x; // OK
}
}
public R M3()
{
R outer = stackalloc int[100];
if (outer is ({ RProp: var x }, _)) return x; // OK
throw null;
}
public R M4()
{
R outer = stackalloc int[100];
switch (outer)
{
case ({ RProp: var x }, _): return x; // OK
}
}
}
").VerifyDiagnostics(
);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册