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

UseExplicitType for var in deconstruction #23975

Merged
merged 5 commits into from
Jan 10, 2018
Merged

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Dec 30, 2017

Customer scenario

UseExplicitType should trigger on var in a deconstruction. For instance: var (x, y) = new C(); should trigger. A proper fix should be offered (something like (int x, string y) = new C();).

Bugs this fixes

Fixes #23752

Workarounds, if any

You can fix the code manually when the code fix doesn't trigger.

Risk

There are two parts of this change, both which are low risk:

  • the GetTypeInfo returned by the semantic model on var (x, y) in a deconstruction foreach should have proper ConvertedType.
  • the UseExplicitType code fixer needs to generate proper replacement code.

Performance impact

Low. The analyzer only performs one additional and cheap check to see if "var" is a declaration expression with parenthesized designation.

Is this a regression from a previous update?

No

Root cause analysis

For the code fix, I didn't realize we should expect that code fix to trigger in this scenario.

How was the bug found?

Reported internally.

Question for IDE team: should short discards should also trigger this code fix (since the type isn't apparent)?

@jcouv jcouv added the Area-IDE label Dec 30, 2017
@jcouv jcouv added this to the 15.6 milestone Dec 30, 2017
@jcouv jcouv self-assigned this Dec 30, 2017
@jcouv jcouv requested a review from a team as a code owner December 30, 2017 07:01
/*x1*/int x/*x2*/,
/*yz1*/(
/*y1*/int y/*y2*/,
/*z1*/Program z/*z2*/)/*yz2*/) /*after*/ = new Program();
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure what causes this weird formatting. I'll check with @DustinCampbell for any tips before debugging in depth.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks @DustinCampbell for the pointer.
If I understood properly, the approach is to drop some trivia that would cause formatting problems. I'm not sure I like this approach for this PR.
I'd rather either: (1) leave the odd formatting for the edge case of comments in such positions in a deconstruction, or (2) fix the formatter (it should not introduce newlines in certain positions).

If the IDE team is ok, I'll leave the current behavior (odd formatting).

Copy link
Member

Choose a reason for hiding this comment

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

This looks pretty broken if you ask me...

Copy link
Member Author

Choose a reason for hiding this comment

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

@jasonmalinowski I spent the afternoon deep in trivia formatter and could not figure it out.
As far as I can tell the root cause of the newlines getting added is AbstractTriviaFormatter.GetLineColumnOfWhitespace which returns a value with lines=1. This causes AbstractTriviaFormatter.AddWhitespaceTextChange to add a newline.

I filed a follow-up issue: #24060

Copy link
Member Author

Choose a reason for hiding this comment

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

Never mind. I finally understood how Dustin's workaround works and applied a similar trick ;-)

The key is that parens and commas introduced by the codefix come with elastic whitespace trivia which causes the formatter to misbehave. Removing those avoids the problem.

Copy link
Member Author

Choose a reason for hiding this comment

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

@jasonmalinowski Any other review feedback?

@jcouv jcouv added Area-Compilers PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. labels Dec 30, 2017
@jcouv
Copy link
Member Author

jcouv commented Jan 2, 2018

I need to revise this. From discussion with @gafter, he'd rather the semantic model not expose a type for the var in such a deconstruction.
After a recent reframing (due to patterns), var now means "declare something", rather than being a placeholder for a type.

Update: done. Most of the work is in the IDE layer now, with just one small fix in the compiler.

@jcouv jcouv added PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. and removed PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. labels Jan 3, 2018
@jcouv jcouv changed the title SemanticModel and UseExplicitType for var in deconstruction [WIP] SemanticModel and UseExplicitType for var in deconstruction Jan 3, 2018
@jcouv jcouv removed the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Jan 3, 2018
@jcouv jcouv changed the title [WIP] SemanticModel and UseExplicitType for var in deconstruction UseExplicitType for var in deconstruction Jan 3, 2018
@jcouv
Copy link
Member Author

jcouv commented Jan 3, 2018

@dotnet/roslyn-ide for review. Thanks

@jcouv
Copy link
Member Author

jcouv commented Jan 5, 2018

@dotnet/roslyn-ide for review. Thanks

@jcouv
Copy link
Member Author

jcouv commented Jan 8, 2018

@Pilchie for ask-mode approval. Thanks

@Pilchie
Copy link
Member

Pilchie commented Jan 8, 2018

@jcouv I don't see appropriate compiler reviews for the compiler portions.

@jcouv
Copy link
Member Author

jcouv commented Jan 8, 2018

Good call. I forgot there were there.
@dotnet/roslyn-compiler for review. Thanks

for (int i = 1; i < builder.Count; i++)
{
separatorBuilder.Add(SyntaxFactory.Token(SyntaxKind.CommaToken).WithoutTrivia());
}
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps: var separatorBuilder = ArrayBuilder<SyntaxToken>.GetInstance(builder.Count - 1, SyntaxFactory.Token(...));

Copy link
Member Author

Choose a reason for hiding this comment

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

Done. Thanks!

@jcouv
Copy link
Member Author

jcouv commented Jan 8, 2018

@dotnet/roslyn-compiler for a second review. Thanks

@@ -277,7 +277,7 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
hasErrors = true;
}

boundIterationVariableType = new BoundTypeExpression(variables, aliasOpt: null, type: iterationVariableType);
boundIterationVariableType = new BoundTypeExpression(variables, aliasOpt: null, type: iterationVariableType).MakeCompilerGenerated();
Copy link
Member

Choose a reason for hiding this comment

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

boundIterationVariableType [](start = 24, length = 26)

As we discussed, bound types are supposed to reflect types in source; you're filing a follow-up issue to separate the representation of the type in source from the type of the iterator.

Copy link
Member Author

Choose a reason for hiding this comment

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

Filed #24105 from our discussion. Thanks

Copy link
Member

@gafter gafter left a comment

Choose a reason for hiding this comment

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

Compiler code looks correct to me, modulo a new issue you filed. IDE code looks plausible, but I assume you're getting review from the IDE team.

@jcouv
Copy link
Member Author

jcouv commented Jan 8, 2018

@Pilchie Thanks for reminding me on compiler review. That's now done. Please approve for ask-mode. Thanks

@Pilchie
Copy link
Member

Pilchie commented Jan 9, 2018

Approved - thanks @jcouv

@jcouv jcouv changed the base branch from master to dev15.6.x January 9, 2018 03:59
@jcouv
Copy link
Member Author

jcouv commented Jan 9, 2018

Retargetd to dev15.6.x branch.

@jcouv
Copy link
Member Author

jcouv commented Jan 9, 2018

test ubuntu_14_debug_prtest please

@@ -1227,6 +1227,7 @@ public void Deconstruct(out int a, out int b)
Assert.Equal("(System.Int32 a, System.Int32 b)", tuple2.ToTestDisplayString());
var underlying2 = tuple2.TupleUnderlyingType;
Assert.Equal("System.ValueTuple<System.Int32, System.Int32>[missing]", underlying2.ToTestDisplayString());
Assert.Equal("(System.Int32 a, System.Int32 b)", model.GetTypeInfo(ab).ConvertedType.ToTestDisplayString());
Copy link
Contributor

Choose a reason for hiding this comment

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

Assert.Equal("(System.Int32 a, System.Int32 b)", model.GetTypeInfo(ab).ConvertedType.ToTestDisplayString()); [](start = 12, length = 108)

Do we have similar test for a regular deconstruction declaration?

Copy link
Member Author

Choose a reason for hiding this comment

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

@AlekseyTs I can't find one. I'll start a PR to add such test. Thanks

@jcouv jcouv merged commit 6dc3522 into dotnet:dev15.6.x Jan 10, 2018
@jcouv jcouv deleted the var-decon branch January 10, 2018 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants