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

Copy escape scope of pattern locals from source expressions #27803

Merged
merged 2 commits into from
Jun 14, 2018
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -131,4 +131,5 @@ Example:
- Visual Studio 2017 version 15.8: https://github.com/dotnet/roslyn/issues/22455 C# compiler will now produce errors if there was an "in" or an "out" argument to an "__arglist" call. "out" was always allowed, and "in" was introduced in 15.5.
- Visual Studio 2017 version 15.8: https://github.com/dotnet/roslyn/issues/26418 C# compiler will now produce errors on out variable declarations that have "ref" or "ref readonly" ref kinds. Example: M(out ref int x);
- Visual Studio 2017 version 15.8: https://github.com/dotnet/roslyn/issues/27047 The C# compiler will now produce diagnostics for operators marked as obsolete when they are used as part of a tuple comparison.
- Visual Studio 2017 version 15.8: https://github.com/dotnet/roslyn/pull/27461 The method `LanguaguageVersionFacts.TryParse` is no longer an extension method.
- Visual Studio 2017 version 15.8: https://github.com/dotnet/roslyn/pull/27461 The method `LanguaguageVersionFacts.TryParse` is no longer an extension method.
- Visual Studio 2017 version 15.8: https://github.com/dotnet/roslyn/pull/27803 pattern matching now will produce errors when trying to return a stack bound value to an invalid escape scope.
7 changes: 5 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node,
}
}

var pattern = BindPattern(node.Pattern, expressionType, hasErrors, diagnostics);
var pattern = BindPattern(expression, node.Pattern, expressionType, hasErrors, diagnostics);
if (!hasErrors && pattern is BoundDeclarationPattern p && !p.IsVar && expression.ConstantValue == ConstantValue.Null)
{
diagnostics.Add(ErrorCode.WRN_IsAlwaysFalse, node.Location, p.DeclaredType.Type);
Expand All @@ -38,6 +38,7 @@ private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node,
}

internal BoundPattern BindPattern(
BoundExpression sourceExpression,
PatternSyntax node,
TypeSymbol operandType,
bool hasErrors,
Expand All @@ -47,7 +48,7 @@ private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node,
{
case SyntaxKind.DeclarationPattern:
return BindDeclarationPattern(
(DeclarationPatternSyntax)node, operandType, hasErrors, diagnostics);
sourceExpression, (DeclarationPatternSyntax)node, operandType, hasErrors, diagnostics);

case SyntaxKind.ConstantPattern:
var constantPattern = (ConstantPatternSyntax)node;
Expand Down Expand Up @@ -234,6 +235,7 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
}

private BoundPattern BindDeclarationPattern(
BoundExpression sourceExpression,
DeclarationPatternSyntax node,
TypeSymbol operandType,
bool hasErrors,
Expand Down Expand Up @@ -290,6 +292,7 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
}

localSymbol.SetType(declType);
localSymbol.SetValEscape(GetValEscape(sourceExpression, LocalScopeDepth));

// Check for variable declaration errors.
hasErrors |= localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ internal override void BindPatternSwitchLabelForInference(CasePatternSwitchLabel
{
var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node;
var pattern = sectionBinder.BindPattern(
matchLabelSyntax.Pattern, SwitchGoverningType, node.HasErrors, diagnostics);
SwitchGoverningExpression, matchLabelSyntax.Pattern, SwitchGoverningType, node.HasErrors, diagnostics);
return new BoundPatternSwitchLabel(node, label, pattern,
matchLabelSyntax.WhenClause != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.WhenClause.Condition, diagnostics) : null,
true, node.HasErrors);
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,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);
SwitchGoverningExpression, matchLabel.Pattern, SwitchGoverningType, labelSyntax.HasErrors, tempDiagnosticBag);
break;

default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6503,5 +6503,56 @@ static bool Dummy(int x)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "int x1").WithArguments("declaration of expression variables in member initializers and queries", "7.3").WithLocation(9, 61)
);
}

[Fact]
[WorkItem(27218, "https://github.com/dotnet/roslyn/issues/27218")]
public void IsPatternMatchingDoesNotCopyEscapeScopes()
{
CreateCompilationWithMscorlibAndSpan(@"
using System;
public class C
{
public ref int M()
{
Span<int> outer = stackalloc int[100];
if (outer is Span<int> inner)
{
return ref inner[5];
}

throw null;
}
}").VerifyDiagnostics(
// (10,24): error CS8352: Cannot use local 'inner' in this context because it may expose referenced variables outside of their declaration scope
// return ref inner[5];
Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(10, 24));
}

[Fact]
[WorkItem(27218, "https://github.com/dotnet/roslyn/issues/27218")]
public void CasePatternMatchingDoesNotCopyEscapeScopes()
{
CreateCompilationWithMscorlibAndSpan(@"
using System;
public class C
{
public ref int M()
{
Span<int> outer = stackalloc int[100];
switch (outer)
{
case Span<int> inner:
{
return ref inner[5];
}
}

throw null;
}
}").VerifyDiagnostics(
// (12,28): error CS8352: Cannot use local 'inner' in this context because it may expose referenced variables outside of their declaration scope
// return ref inner[5];
Diagnostic(ErrorCode.ERR_EscapeLocal, "inner").WithArguments("inner").WithLocation(12, 28));
}
}
}