Skip to content

UseDefaultLiteral and RemoveUnnecessaryCast shouldn't introduce invalid default literal in pattern or case label#25538

Merged
jinujoseph merged 11 commits intodotnet:masterfrom
Neme12:useDefaultLiteral
Apr 4, 2018
Merged

UseDefaultLiteral and RemoveUnnecessaryCast shouldn't introduce invalid default literal in pattern or case label#25538
jinujoseph merged 11 commits intodotnet:masterfrom
Neme12:useDefaultLiteral

Conversation

@Neme12
Copy link
Copy Markdown
Contributor

@Neme12 Neme12 commented Mar 16, 2018

Customer scenario

Type case default(bool):, or case (bool)default:, or b is default(bool), or b is (bool)default.
In all those cases, no code fix should be offered to simplify to the default literal, as this results in a compilation error.

Bugs this fixes

fixes #25456

Risk

Performance impact

Low. A few syntax checks were added to the logic that verifies if a change results in different semantics.

Is this a regression from a previous update?

No

Root cause analysis

At least for the is case, it was allowed for a short while, then we made a language change to reserve default for use in C# 8 match expressions. For case, I don't remember.

How was the bug found?

Reported internally.

@Neme12 Neme12 requested a review from a team as a code owner March 16, 2018 20:42
// First, check to see if the node ultimately parenting this cast has any syntax errors.
// If so, we bail. If removing the cast introduces a syntax error, bail out too.
if (speculationAnalyzer.SemanticRootOfOriginalExpression.ContainsDiagnostics ||
speculationAnalyzer.SemanticRootOfReplacedExpression.ContainsDiagnostics)
Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CyrusNajmabadi what do you think about this approach? are there any concerns with this? performance concerns possibly?

this seems like generally a good idea but could also hide bugs if for some reason we generate an invalid syntax node

Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whatever we do (whtether a check for diagnostics or special-case check for default inside a switch case/pattern) should probably be done inside the speculation analyzer itself in ReplacementChangesSemantics - there are probably other IDE features that might introduce broken code here and doing that would ensure they all behave correctly and don't need to each handle this separately

Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another thing i like about this is that it doesn't duplicate the logic in the compiler

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems reasonable to me.

Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CyrusNajmabadi well it shouldn't 😄 that's all wrong, forget what i said.

the "replaced" expression does not contain any new diagnostics... all the tests passed because i didn't pass in c# 7.1 to the tests that expect to not get this offered - it simply wasn't offered because it used c# 7.0 where default is always a syntax error

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turns out manual testing is still useful

}

if (defaultExpression.WalkUpParentheses().IsParentKind(SyntaxKind.ConstantPattern, SyntaxKind.CaseSwitchLabel))
{
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it's done in the speculation analyzer, this can be removed

{
switch (true)
{
case ((bool)default):
Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

obviously another bug - it adds unnecessary parentheses

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

created an issue here: #25554

protected abstract TestWorkspace CreateWorkspaceFromFile(string initialMarkup, TestParameters parameters);

private TestParameters WithRegularOptions(TestParameters parameters)
=> parameters.WithParseOptions(parameters.parseOptions?.WithKind(SourceCodeKind.Regular));
Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an important change so that TestMissingInRegularAndScriptAsync and the other methods actually use the language version we asked for by giving ParseOptions inside TestParameters, rather than ignoring it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did this reveal any errant tests that were passing when tehy shouldn't hve been?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually no, i was surprised by that

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but it revealed a lot of tests that would have passed even if the code they were supposed to test didn't work

// We can't have a default literal inside a case label or constant pattern.
return true;
}
}
Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CyrusNajmabadi having the check here will be the most correct and will work for all IDE features equally well, the only thing I don't like is that this is just a special edge case that is at the very beginning and steals focus from the rest of this method which is far more important

also, this doesn't really feel like a "changing the semantics" all that much

Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I really feel like this code has to be somewhere in the speculation analyzer and not scattered around individual features. Doing this fixes bugs in other features too. One example I found is:

const bool b = default;

switch (true)
{
    case b:
        break;
}

do inline temporary on 'b' - it will use replace 'b' with 'default' and produce the error.
But with this change, it will introduce a cast and the resulting code will be correct:

switch (true)
{
    case ((bool)(default)):
        break;
}

edit: I'm wrong, this particular case actually works with either approach because the simplifier uses the same helper.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, this doesn't really feel like a "changing the semantics" all that much

"changes semantics" is just the term we used for "breaks the code" :)

the only thing I don't like is that this is just a special edge case that is at the very beginning and steals focus from the rest of this method which is far more important

The method is just a bunch of checks that was added in the order we found and fixed thigns while doing this feature. I don't see any problem with your addition.

{
private static ITypeSymbol GetOuterCastType(ExpressionSyntax expression, SemanticModel semanticModel, out bool parentIsOrAsExpression)
private static ITypeSymbol GetOuterCastType(ExpressionSyntax expression, SemanticModel semanticModel,
out bool parentIsIsOrAsExpression)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this name doesn't roll off the tongue as well, but at least it makes sense - i couldn't figure out what the old one was supposed to mean until i looked at the implementation

@jcouv jcouv added Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee. labels Mar 17, 2018
Copy link
Copy Markdown
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM Thanks

@jcouv
Copy link
Copy Markdown
Member

jcouv commented Mar 21, 2018

@dotnet/roslyn-ide Please review this community PR. Thanks

@jinujoseph
Copy link
Copy Markdown
Contributor

@dotnet-bot Test this please

@jinujoseph
Copy link
Copy Markdown
Contributor

@dotnet-bot retest this please

@Neme12 Neme12 closed this Apr 1, 2018
@Neme12 Neme12 reopened this Apr 1, 2018
@Neme12
Copy link
Copy Markdown
Contributor Author

Neme12 commented Apr 1, 2018

@dotnet-bot retest windows_debug_unit32_prtest please

@Neme12
Copy link
Copy Markdown
Contributor Author

Neme12 commented Apr 3, 2018

@jinujoseph You were right to try to retest this, there was the build issue with a missing using again. Thanks

@jinujoseph jinujoseph merged commit 81c63b7 into dotnet:master Apr 4, 2018
@Neme12 Neme12 deleted the useDefaultLiteral branch April 6, 2018 06:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Simplify Default Expression" produces bad constant pattern.

4 participants