Adding missing completion after 'ref'#25570
Conversation
| // the syntax tree is completely broken and there is no lambda expression at all here. | ||
| // 'ref' starts a new local declaration and therefore we do offer 'readonly'. | ||
| // Fixing that would have to involve either changing the parser or doing some really nasty hacks. | ||
| // Delegate lambda = (ref $$ int p) => p; |
There was a problem hiding this comment.
not sure what to do here
There was a problem hiding this comment.
I don't think this is a bug
There was a problem hiding this comment.
Yeah, I agree with @CyrusNajmabadi. File a bug. We can do a better job with error recovery in the parser here.
|
Thanks! Tagging @VSadov and @OmarTawfik as FYI |
| // cases: | ||
| // const var | ||
| // ref var | ||
| // ref readonly var |
There was a problem hiding this comment.
these comment should move down to the new block you added. right?
There was a problem hiding this comment.
actually all cases are on the top of the method here, see the rest of the comment - it's all below code i added
There was a problem hiding this comment.
or do you want me to move each comment to the relevant place where it's handled?
There was a problem hiding this comment.
i'm not sure if i should make code style changes like that unrelated to what i'm doing and mess with half of this method by moving comments, given that this PR is already large enough
There was a problem hiding this comment.
that's fair. do as you wish.
| } | ||
|
|
||
| if (token.IsKind(SyntaxKind.RefKeyword, SyntaxKind.ReadOnlyKeyword) && | ||
| token.Parent.IsKind(SyntaxKind.RefType) && |
There was a problem hiding this comment.
didn't you jsut add a new helper that does this?
There was a problem hiding this comment.
no I didn't... and even if I did, this is a special case because this is used for var, which can't be offer in other places after a ref type (eg in a method return type)
There was a problem hiding this comment.
So this is not just the same as "IsAfterRefTypeContext"?
There was a problem hiding this comment.
no it's not:
class C
{
ref $$
}here you're in a ref type but not in a local declaration and can't use var
There was a problem hiding this comment.
this method is called 'IsLocalVariableDeclarationContext'
|
Tagging @dotnet/roslyn-ide @jinujoe . it looks large, but the majority is just a super-exhaustive test suite (yaay). Actual code change is quite minor and easy to review. |
|
I should note: all the "type" "keywords" behave the same and have the same tests except for
|
| } | ||
| } | ||
| "; | ||
| await VerifyItemExistsAsync(markup, "String"); |
There was a problem hiding this comment.
@jcouv String.Empty.MyRefReturningExtensionMethod()
| context.IsPrimaryFunctionExpressionContext || | ||
| context.IsCrefContext || | ||
| syntaxTree.IsAfterKeyword(position, SyntaxKind.ConstKeyword, cancellationToken) || | ||
| syntaxTree.IsAfterKeyword(position, SyntaxKind.RefKeyword, cancellationToken) || |
There was a problem hiding this comment.
I'm surprised this doesn't fall under a more abstract category, like "IsTypeContext" or "IsPossibleTypeContext" (those are made-up, I'm not sure whether such methods exist). If there is not one, consider factoring one out, or filing an issue to do so.
Note: this would avoid duplicating the fix to multiple recommenders.
@dotnet/roslyn-ide for advice. Is there already a check that would be suitable for this?
There was a problem hiding this comment.
One more thought on this. Is there a reason that all the recommenders for intrinsic types (bool, byte, string, object, etc) don't just share code?
In reply to: 175509814 [](ancestors = 175509814)
There was a problem hiding this comment.
@jcouv I was really surprised by this too and asked @CyrusNajmabadi who said this is very much by design. I would still like to do some cleanup here and reduce the duplication to some degree but I'm not going to do that as part of this PR. Is that OK?
There was a problem hiding this comment.
@CyrusNajmabadi mentioned to me that for starters there are some cases (enum base list, stackalloc) where only some of those keywords are allowed, that's why they can't share everything and often do require special treatment. That said, I still think the duplication could be reduced significantly, but I'm treating this PR as a bugfix rather than code quality improvement/refactoring. It would not be as trivial as it seems.
(but I agree with you 100%, I don't like the code the way it is)
There was a problem hiding this comment.
It woud require refactoring some of the existing helpers to be more fine-grained to support this sort of distinction. Yes, there is a helper called IsTypeContext but it is more general and offered in more places than these keywords, not less - so it's not as easy as using that helper and then adding more checks with ||.
There was a problem hiding this comment.
But @CyrusNajmabadi has a lot more to say about this than I do. I talked to him about this and and he was clearly opposed to the idea of generalizing these too much. I think I understand his concerns and hope we can find a good tradeoff here. But that would be for another PR.
There was a problem hiding this comment.
I'm surprised this doesn't fall under a more abstract category, like "IsTypeContext" or "IsPossibleTypeContext" (those are made-up, I'm not sure whether such methods exist). If there is not one, consider factoring one out, or filing an issue to do so.
We can consider these sorts of things. However, as i mentioned to @Neme12 it gets a little subtle due to different types being legal in different contexts.
One more thought on this. Is there a reason that all the recommenders for intrinsic types (bool, byte, string, object, etc) don't just share code?
Yes. Not all of them are allowed in the same contexts. For example, after stackalloc, you can have types, but not all types.
Similarly, you can have integral types (but not floating point types) in an enum-base-list.
--
Now, as i mentioned to @Neme12 we could certainly extract out some contexts that were well defined, and would make sense for large sets of these providers. For example: IsIntegralTypeContext (for non-floating point numeric types).
There was a problem hiding this comment.
Thanks for the clarification. I certainly agree it doesn't need to be solved in this PR.
There was a problem hiding this comment.
@Neme12 has shown a great interest in improving things here based on supporting all our existing goals, while also massively reducing duplication. I'm really excited to see what we can do here!
|
@dotnet/roslyn-ide for review of this community PR. Thanks |
|
@dotnet/roslyn-ide Please review this community PR and merge. Thanks |
|
retest windows_release_unit32_prtest please |
|
@dotnet-bot retest windows_debug_vs-integration_prtest please |
|
the test shows 404 😕 |
|
@dotnet/roslyn-ide Please review this community PR and merge. Thanks |
|
retest windows_debug_vs-integration_prtest please |
|
retest windows_release_vs-integration_prtest please |
|
@dotnet/roslyn-ide Cyrus and I reviewed this community PR. Can you complete the review? It's been a week without response. Thanks |
There was a problem hiding this comment.
This is great work @Neme12! Thank you for all of the added tests.
|
@dotnet-bot retest this please |
1 similar comment
|
@dotnet-bot retest this please |
|
retest windows_release_unit64_prtest please |
|
retest windows_debug_unit32_prtest please |
|
Whoever ends up merging this PR. Beware that it contains some merge commits (ie. do not squash this merge). |
|
This is another great contribution @Neme12 -- thanks! |
Customer scenario
Type 'ref' and expect completion for 'readonly'
Type 'ref' or 'ref readonly' and expect symbol & keyword completion
(examples in the issue)
Bugs this fixes
fixes #25569
Workarounds, if any
Type whatever you need to type manually.
Risk
not sure
Performance impact
I only added syntax checks, so... low?
Is this a regression from a previous update?
No.
Root cause analysis
New language feature without full completion.
How was the bug found?
I found it by exploration.