Skip to content

Enable nullability in ResourceCodeDomSerializer.SerializationResourceManager#9457

Merged
lonitra merged 4 commits intodotnet:mainfrom
halgab:SerializationResourceManager-null
Nov 28, 2023
Merged

Enable nullability in ResourceCodeDomSerializer.SerializationResourceManager#9457
lonitra merged 4 commits intodotnet:mainfrom
halgab:SerializationResourceManager-null

Conversation

@halgab
Copy link
Copy Markdown
Contributor

@halgab halgab commented Jul 10, 2023

As dicussed here

Proposed changes

Microsoft Reviewers: Open in CodeFlow

@ghost ghost assigned halgab Jul 10, 2023
@ghost ghost added the area-NRT label Jul 10, 2023
// Provide null as a sentinel so we don't repeatedly ask for the same resource. If this is the invariant culture, always provide one.
ResourceTable[culture] = culture.Equals(CultureInfo.InvariantCulture)
? new Dictionary<string, object>() : s_resourceSetSentinel;
? new Dictionary<string, object?>() : null;
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.

Before #8332 the sentinel value used to be an object. As ResourceTable was a Hashtable, it was fine putting both dictionaries and simple objects in it. But changing it to a strongly typed dictionary, the type of the sentinel was also changed to a dictionary. The problem with that approach is that now we're actually updating the sentinel dictionary. Replacing the sentinel object by null should solve it

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.

@halgab halgab force-pushed the SerializationResourceManager-null branch from 8da1243 to 313e277 Compare July 10, 2023 14:17
@halgab halgab marked this pull request as ready for review July 10, 2023 14:40
@halgab halgab requested a review from a team as a code owner July 10, 2023 14:40
@elachlan
Copy link
Copy Markdown
Contributor

Thank you for taking this on.

@halgab halgab force-pushed the SerializationResourceManager-null branch 2 times, most recently from 0af7d7f to 1b25b11 Compare July 15, 2023 15:04
@halgab
Copy link
Copy Markdown
Contributor Author

halgab commented Jul 21, 2023

Note that if we merge this in .Net 9 timeframe, we are going to keep a bug that was not here in .Net 7. Is this deemed less risky than taking a fix so late? @dreddy-work

@halgab halgab force-pushed the SerializationResourceManager-null branch from 1b25b11 to 094c46c Compare July 21, 2023 20:53
@halgab
Copy link
Copy Markdown
Contributor Author

halgab commented Aug 2, 2023

@dreddy-work do you want me to send over a PR just with the bugfix for .Net 8?

@dreddy-work
Copy link
Copy Markdown
Member

@dreddy-work do you want me to send over a PR just with the bugfix for .Net 8?

Yes please. We are trying to mitigate risk by limiting what we ship in .NET 8.0.

@elachlan
Copy link
Copy Markdown
Contributor

elachlan commented Aug 2, 2023

@dreddy-work do you want me to send over a PR just with the bugfix for .Net 8?

I'd just submit the PR and let them decide.

@halgab
Copy link
Copy Markdown
Contributor Author

halgab commented Aug 3, 2023

I've just pushed #9642. After taking another look, I found another introduced by #8332. I guess there's no point in updating this PR accordingly for now

@halgab halgab force-pushed the SerializationResourceManager-null branch from 094c46c to b2d88cc Compare August 15, 2023 09:59
@halgab
Copy link
Copy Markdown
Contributor Author

halgab commented Aug 15, 2023

Now that #9642 was merged, I rebased this one, removing the second commit that was about the bugfix.

@halgab halgab force-pushed the SerializationResourceManager-null branch from b2d88cc to fbed8c8 Compare September 29, 2023 19:42
@halgab halgab force-pushed the SerializationResourceManager-null branch from fbed8c8 to f8d7c8f Compare October 31, 2023 21:49
@halgab halgab force-pushed the SerializationResourceManager-null branch from f8d7c8f to c5daded Compare November 15, 2023 12:26
Copy link
Copy Markdown
Member

@lonitra lonitra left a comment

Choose a reason for hiding this comment

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

I added a few comments. Appreciate your patience here

Comment on lines +132 to +133
manager.GetContext<PropertyDescriptor>()!,
manager.GetContext<ExpressionContext>()!);
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.

Please add comment of how do we know these are not null

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.

Well, I don't know the actual reason... I just know the call sites of those properties always expect them not to be null as they are used as parameters in manager.Context.Push calls. That's another case of inconsistent checks I think

Copy link
Copy Markdown
Member

@lonitra lonitra Nov 20, 2023

Choose a reason for hiding this comment

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

I see, it looks like these are used as arguments to manager.Context.Push only when isMetadata = false. So it seems that it is OK for ResourceEntry.PropertyDescription and ResourceEntry.ExpressionContext to be nullable and should be annotated as so. If these are null when isMetadata = false, we should actually throw ArgumentException here since manager did not have the non-nullables required instead of later getting an ArgumentNullException from manager.Context.Push which might be confusing.

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.

I've pushed something to address this. I've tried to stick to what you indicated. Let me know if this needs some more tweaking


// Note that when we read metadata, for backwards compatibility, we also merge in regular data from the invariant resource. We need to clear that data here, since we are going to write out metadata separately.
invariant.Remove(resourceName);
invariant!.Remove(resourceName);
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 is not nullable?

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.

GetResourceSet returns null only in an error scenario. Which I know is not satisfying... As often in internal classes, checks are pretty inconsistent

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.

Generally we are moving to add comments whenever ! is used, but given that the codebase is so old, it can be hard to determine when exactly things are null in which case we should throw a specific exception instead of getting an NRE. For this case I think the right answer would be to throw an InvalidOperationException, but of course if there was more context, we should throw exception that would be most helpful.

if (invariant is null) {
    throw new InvalidOperationException();
}

invariant.Remove(resourceName);

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.

I was too quick in my first reply. Turns out that we can perfectly explain why invariant can't be null. I've added a comment near the null forgiving operator (which move earlier in the code).

@lonitra lonitra added the waiting-author-feedback The team requires more information from the author label Nov 17, 2023
@ghost ghost removed the waiting-author-feedback The team requires more information from the author label Nov 18, 2023
@lonitra lonitra added the waiting-author-feedback The team requires more information from the author label Nov 20, 2023
@ghost ghost removed the waiting-author-feedback The team requires more information from the author label Nov 23, 2023
@halgab halgab force-pushed the SerializationResourceManager-null branch from d537771 to 5d38185 Compare November 23, 2023 13:42
@halgab halgab requested a review from lonitra November 26, 2023 08:49
Copy link
Copy Markdown
Member

@lonitra lonitra left a comment

Choose a reason for hiding this comment

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

Awesome :shipit:

@lonitra lonitra merged commit 75aaf6a into dotnet:main Nov 28, 2023
@ghost ghost added this to the 9.0 Preview1 milestone Nov 28, 2023
@halgab halgab deleted the SerializationResourceManager-null branch November 28, 2023 18:22
@github-actions github-actions bot locked and limited conversation to collaborators Dec 29, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants