Skip to content

Annotate SyntaxTrivia#41801

Merged
jaredpar merged 7 commits intodotnet:masterfrom
jaredpar:nullable-trivia
Feb 27, 2020
Merged

Annotate SyntaxTrivia#41801
jaredpar merged 7 commits intodotnet:masterfrom
jaredpar:nullable-trivia

Conversation

@jaredpar
Copy link
Copy Markdown
Member

No description provided.

@jaredpar jaredpar added Area-Compilers Concept-Null Annotations The issue involves annotating an API for nullable reference types labels Feb 20, 2020
@jaredpar jaredpar marked this pull request as ready for review February 20, 2020 00:50
@jaredpar jaredpar requested review from a team as code owners February 20, 2020 00:50
@jaredpar
Copy link
Copy Markdown
Member Author

@dotnet/roslyn-compiler PTAL

Comment thread src/Compilers/Core/Portable/Diagnostic/SourceLocation.cs Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should this use RequiredUnderlyingNode?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

or is this actually a situation where we just want the compiler to accept it, we don't want to assert about it in debug builds?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The use of UnderlyingNode! is deliberate here. The rational in the Nullable Annotation Guidance document is roughly:

  1. Use ! when the method already verifies a value is non-null but the compiler just can't follow along
  2. Use Debug.Assert, or more formal methods, when the method doesn't do the verification.

In this case the switch statement effectively verifies that the repsective nodes are non-null. Essentially _nodes will have a non-null value for whatever the _count of the list is. Hence the method already verifies so use !.


case SyntaxKind.SkippedTokensTrivia:
ClassifySkippedTokens((SkippedTokensTriviaSyntax)trivia.GetStructure());
ClassifySkippedTokens((SkippedTokensTriviaSyntax)trivia.GetStructure()!);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How do we know this suppression is safe from surrounding code? Should this instead be an assertion?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is another really sutbtle one. Essentially we can't get SyntaxKind.SkippedTokensTrivia unless trivia.UnderlyingNode is a non-null value. This particular node is by definition a structured one hence it will always be non-null if there is a non-null UnderlyingNode value.

I have no idea how to handle this though. There really isn't anything I can Debug.Assert here because it's a method return, not a property. I could add a new member to StructuredTriviaSyntax but that would be new public API surface. So far haven't added such a member for nullability yet (doesn't mean we shouldn't though).

var list = this.ToList();
list.RemoveAt(index);
return new SyntaxTriviaList(default(SyntaxToken), Node.CreateList(list.Select(n => n.UnderlyingNode)), 0, 0);
return new SyntaxTriviaList(default(SyntaxToken), Node!.CreateList(list.Select(n => n.RequiredUnderlyingNode)), 0, 0);
Copy link
Copy Markdown
Member

@jcouv jcouv Feb 26, 2020

Choose a reason for hiding this comment

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

Node! [](start = 62, length = 5)

nit: Should this be an assertion? (ditto below)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The code does validate that Node is not null but it's really subtle. Basically for the code to reach this point Count must be greater than zero. In that case Node is guaranteed to be non-null.

I'm open to how to make this clearer: either by using Debug.Assert or by adding a comment. I agree it's really subtle.

public SyntaxNode? GetStructure()
{
return HasStructure ? UnderlyingNode.GetStructure(this) : null;
return HasStructure ? UnderlyingNode!.GetStructure(this) : null;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

UnderlyingNode! [](start = 34, length = 15)

nit: Consider adding a comment to mark HasStructure with MemberNotNull(nameof(UnderlyingNode)) once we have the capability

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good idea. Filed a general issue we can use to track all places like this.

#41964

@jcouv jcouv added this to the 16.6 milestone Feb 26, 2020
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 (iteration 7) with a couple nits/questions

@jcouv
Copy link
Copy Markdown
Member

jcouv commented Feb 27, 2020

@jaredpar This looks ready to merge. Thanks

@jaredpar jaredpar merged commit 5bd4b1a into dotnet:master Feb 27, 2020
@jaredpar jaredpar deleted the nullable-trivia branch February 27, 2020 00:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Compilers Concept-Null Annotations The issue involves annotating an API for nullable reference types

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants