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

add tracking of NotNullInfo for Match, Case, Try trees (fix #21380) #21389

Merged
merged 4 commits into from
Sep 11, 2024

Conversation

olhotak
Copy link
Contributor

@olhotak olhotak commented Aug 14, 2024

No description provided.

@olhotak
Copy link
Contributor Author

olhotak commented Aug 14, 2024

This would benefit from additional tests. @noti0na1 would you be able to add some?

@olhotak olhotak requested a review from noti0na1 August 14, 2024 20:40
@noti0na1 noti0na1 self-assigned this Aug 14, 2024
@hamzaremmal hamzaremmal linked an issue Aug 15, 2024 that may be closed by this pull request
@noti0na1
Copy link
Member

I fixed the NotNullInfos for Try and added some more tests.

We want the retracted NotNullInfo from the body of Try to type check the cases and finalizer, so we have to type tree.expr first using some trick.

)
)
val nni = pat1.notNullInfo
.seq(guard1.notNullInfoIf(false).alt(guard1.notNullInfoIf(true)))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the guard is false, the body does not execute. I don't think it's sound to .seq the body after an .alt that includes the case of the guard being false.

This comment was marked as outdated.

// Hence, we create a copy of cases with empty body and type check that first, then type check
// the rest of the tree in order.
val casesEmptyBody1 = tree.cases.mapconserve(cpy.CaseDef(_)(body = EmptyTree))
val casesEmptyBody2 = typedCases(casesEmptyBody1, EmptyTree, defn.ThrowableType, WildcardType)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does this work if the pattern uses a variable whose nullability is changed by the try block (expr)? Won't we be typing such a variable in the pattern with the wrong type here?

Copy link
Member

Choose a reason for hiding this comment

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

The addCanThrowCapabilities only uses the types of exception patterns and whether the guards are empty, so I think it is ok here.
In general, since we don't know at which point the try body will throw an exception, the catch cases and statements after try should only rely on the retracted info from the body.

).seq(finalizer1.notNullInfo)

var nni = expr2.notNullInfo.retractedInfo
if cases2.nonEmpty then nni = nni.seq(cases2.map(_.notNullInfo).reduce(_.alt(_)))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's possible that none of the cases match (i.e. that no exception is thrown). So we either need an .alt with an empty NotNullInfo or we need to take the .retractedInfo of the cases (those two alternatives should be equivalent).

Copy link
Member

Choose a reason for hiding this comment

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

Yes, we could have no catch case in try.

@noti0na1
Copy link
Member

I may not have time to work on this PR until next week. Feel free to modify/remove my commit.

@noti0na1
Copy link
Member

Emm, one test fails with best-effort enabled, not sure what happens here.

scalac -Ybest-effort tests/neg/i13864.scala

@noti0na1
Copy link
Member

noti0na1 commented Sep 6, 2024

scalac -Ybest-effort tests/neg/i13864.scala

It is tricky to fix the error: in the example, when the pat of the case is typed, the type argument is bind with a fresh name, so if we type check the cases twice, the CanThrow Capability would refer to a different name.

Normally, this is not an issue, because this kind of CanThrow is invalid, but in this case, the best-effort forces the pickler to run.

cc @jchyb

@jchyb
Copy link
Contributor

jchyb commented Sep 6, 2024

@noti0na1 Feel free to add i13864.scala to compiler/test/dotc/neg-best-effort-pickling.blacklist (and feel free to use that exclusion list liberally in the future).
Best effort should never hamper any progress on the issues in the compiler (I should probably make that more clear in the message in the CI, sorry about that!). But thank you for looking at this either way, it should help me fix this later on (usually the fix would be something like avoiding pickling certain parts, so now I know where to look.)

Copy link
Contributor Author

@olhotak olhotak left a comment

Choose a reason for hiding this comment

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

LGTM now, but github requires a review from someone other than me. @noti0na1 can you approve and merge?

@olhotak olhotak assigned noti0na1 and unassigned olhotak Sep 11, 2024
@noti0na1 noti0na1 merged commit f95a131 into scala:main Sep 11, 2024
28 checks passed
@noti0na1 noti0na1 deleted the fix-i21380 branch September 11, 2024 13:32
@WojciechMazur WojciechMazur added this to the 3.6.0 milestone Oct 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

-Yexplicit-nulls fails to detect null pointer dereference
5 participants