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

Do not resolve diagnostics early during attribute binding #71140

Merged
merged 10 commits into from
Dec 15, 2023

Conversation

333fred
Copy link
Member

@333fred 333fred commented Dec 7, 2023

We were attempt to resolve diagnostics in ColorColor attribute argument scenarios while we were in the middle of attribute argument binding. This then caused us to need to bind attributes to resolve the diagnostic, entering an infinite loop that eventually overflows. To solve this, I've allowed ImmutableBindingDiagnostics to avoid eagerly resolving diagnostics during construction. To better convey this new contract, I've also renamed the type to ReadOnlyBindingDiagnostics. As there are extensive uses of ReadOnlyBindingDiagnostics, and many should continue to eagerly resolve diagnostics, I've left it as resolving by default, and only adjusted this one codepath. Fixes #71039.

We were attempt to resolve diagnostics in ColorColor attribute argument scenarios while we were in the middle of attribute argument binding. This then caused us to need to bind attributes to resolve the diagnostic, entering an infinite loop that eventually overflows. To solve this, I've avoided binding diagnostics in this scenario by passing around a BindingDiagnosticBag, rather than an `ImmutableBindingDiagnostic<AssemblySymbol>`. Doing this does require some limited and controlled mutation in the tree; to help ensure future maintainability, the mutation only occurs in one direction (the binder taking ownership of the bag). However, if we're uncomfortable with the mutation approach, we can instead simply leak the BindingDiagnosticBags in this scenario. This is a small enough source of them that we're unlikely to see major issues not pooling them. Fixes dotnet#71039.
@333fred 333fred requested a review from a team as a code owner December 7, 2023 01:47
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Dec 7, 2023
@@ -6846,7 +6846,7 @@ private BoundExpression BindLeftIdentifierOfPotentialColorColorMemberAccess(Iden
// NOTE: ReplaceTypeOrValueReceiver will call CheckValue explicitly.
boundValue = BindToNaturalType(boundValue, valueDiagnostics);
return new BoundTypeOrValueExpression(left,
new BoundTypeOrValueData(leftSymbol, boundValue, valueDiagnostics.ToReadOnlyAndFree(), boundType, typeDiagnostics.ToReadOnlyAndFree()), leftType);
Copy link
Member Author

Choose a reason for hiding this comment

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

This was recursion source 1. ToReadOnlyAndFree forces resolution of lazy diagnostics. We would attempt to resolve whether to report obsolete on the value, which then forced us to bind assembly attributes, bringing us right back here.

{
if (d.Code == (int)ErrorCode.WRN_PrimaryConstructorParameterIsShadowedAndNotPassedToBase &&
Copy link
Member Author

Choose a reason for hiding this comment

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

.Code was the second source of recursion, once the first was addressed. It forces resolution of the diagnostic info, throwing us right back into the same problem. To address this, I added an IsCode method on Diagnostic, which will not force resolution of lazy diagnostics. The only thing lazy about lazy diagnostics is whether or not they should be reported: we do know what code they are ahead of time. Arguably, we could avoid resolving lazy diagnostics with the Code property. I felt that I wasn't comfortable with that big a change here, but if we'd prefer that approach, I can do that.

@AlekseyTs
Copy link
Contributor

Does VB have similar problem?

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 1)

…gs, we instead construct an ImmutableBindingDiagnostic with unresolved Diagnostics.
…e clearly communicate that it may have lazily-resolved diagnostics in it.
@333fred
Copy link
Member Author

333fred commented Dec 7, 2023

@AlekseyTs addressed your feedback. I would recommend reviewing the two new commits separately: I put the rename into a commit of its own with no other changes for easier review.

@AlekseyTs
Copy link
Contributor

It looks like VB build is broken

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 4). There was no response to the following threads: #71140 (comment), #71140 (comment).

@333fred
Copy link
Member Author

333fred commented Dec 12, 2023

@AlekseyTs feedback addressed.

@@ -960,7 +960,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Dim displayName As String = TryCast(attrData.CommonConstructorArguments(0).ValueInternal, String)

If displayName Is Nothing Then
diagnostics.Add(ERRID.ERR_FriendAssemblyNameInvalid, If(nodeOpt IsNot Nothing, nodeOpt.GetLocation(), NoLocation.Singleton), displayName)
diagnostics.Add(ERRID.ERR_FriendAssemblyNameInvalid, If(nodeOpt IsNot Nothing, nodeOpt.GetLocation(), NoLocation.Singleton), "")
Copy link
Member Author

Choose a reason for hiding this comment

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

This change wasn't a cycle, we just clearly didn't have any tests covering it, as it is guaranteed to hit a Debug.Assert.

AlekseyTs
AlekseyTs previously approved these changes Dec 13, 2023
Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (commit 7)

@333fred
Copy link
Member Author

333fred commented Dec 13, 2023

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

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Dec 13, 2023

        return bindingDiagnostics.ToReadOnlyAndFree().Diagnostics;

It looks like this place should filter out "void" instances #Closed


Refers to: src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs:3053 in 47f13c0. [](commit_id = 47f13c0, deletion_comment = False)

@AlekseyTs AlekseyTs dismissed their stale review December 13, 2023 18:11

It looks like an additional follow up is needed

@AlekseyTs
Copy link
Contributor

        return bindingDiagnostics.ToReadOnlyAndFree().Diagnostics;

This place doesn't even have to use ToReadOnlyAndFree API.


In reply to: 1854473186


Refers to: src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs:3053 in 47f13c0. [](commit_id = 47f13c0, deletion_comment = False)

@333fred
Copy link
Member Author

333fred commented Dec 13, 2023

@AlekseyTs reverted the broader resolution change after our discussion.

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (commit 9)

@333fred
Copy link
Member Author

333fred commented Dec 14, 2023

@dotnet/roslyn-compiler for a second review please

@333fred 333fred enabled auto-merge (squash) December 15, 2023 18:16
@333fred 333fred merged commit 38f6bcf into dotnet:main Dec 15, 2023
27 checks passed
@ghost ghost added this to the Next milestone Dec 15, 2023
@333fred 333fred deleted the colorcolor-cycle branch December 15, 2023 19:47
@Cosifne Cosifne modified the milestones: Next, 17.9 P3 Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Stack overflow in Rosyln CodeAnalysis when ambiguous name is used
4 participants