Skip to content

implement or-patterns for pattern types #139909

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

oli-obk
Copy link
Contributor

@oli-obk oli-obk commented Apr 16, 2025

These are necessary to represent NonZeroI32, as the range for that is ..0 | 1... The rustc_scalar_layout_range_* attributes avoided this by just implementing wraparound and having a single 1..=-1 range effectively. See https://rust-lang.zulipchat.com/#narrow/channel/481660-t-lang.2Fpattern-types/topic/.60or.20pattern.60.20representation.20in.20type.20system/with/504217694 for some background discussion

r? @BoxyUwU

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 16, 2025
@rustbot
Copy link
Collaborator

rustbot commented Apr 16, 2025

changes to the core type system

cc @compiler-errors, @lcnr

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

changes to the core type system

cc @compiler-errors, @lcnr

Some changes occurred in src/tools/rustfmt

cc @rust-lang/rustfmt

HIR ty lowering was modified

cc @fmease

Comment on lines +1252 to +1254
// FIXME(pattern_types): check that the value is covered by one of the variants.
// The layout may pessimistically cover actually illegal ranges.
ty::PatternKind::Or(_patterns) => {}
Copy link
Member

Choose a reason for hiding this comment

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

Is it clear how one would do this? Do we have to try one after the other? That seems very tricky as it means we have to validate the value "speculatively" where we ignore errors, until we know that all paths error, then we report one of them... as long as it's just integers this is fairly harmless, but something like Ok(true) | Err(5) | Err(7) should ideally be checked by "read discriminant, then proceed with the pattern restricted to what we see there" -- basically, compiling the pattern to a discrimination tree similar to what happens during match lowering, and executing that here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we'll have to do something similar to whatever we'll want to do if pattern types can have user defined trait impls. We'll need to detect overlap and possibly exhaustiveness some day. I leave this problem to future me, because it's not necessary for the MVP of replacing the rustc_scalar_layout attributes

Copy link
Member

Choose a reason for hiding this comment

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

Checking the validity of NonZeroI32 is definitely necessary, Miri must be able to detect that UB.

Checking the validity of general or patterns can be deferred, though I'd prefer if we did not use any or patterns in std that Miri can't support -- at least not for code that can be reached on stable.

Copy link
Contributor Author

@oli-obk oli-obk Apr 16, 2025

Choose a reason for hiding this comment

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

This is checked via the layout. That's what I was trying to convey with the comment.

Copy link
Member

Choose a reason for hiding this comment

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

Okay so if the "or" pattern happens to fall into the fragment layout can handle, then Miri can check validity. If not, we don't actually use this information for codegen, so it's okay for Miri to not check validity. I take it patterns never reduce the size of the type, only the set of allowed values?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes

Comment on lines +1096 to +1108
ast::TyPatKind::Or(ref variants) => {
let mut first = true;
let mut s = String::new();
for variant in variants {
if first {
first = false
} else {
s.push_str(" | ");
}
s.push_str(&variant.rewrite_result(context, shape)?);
}
Ok(s)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have a syntax for this? looking at the UI tests I'm just seeing macro calls.

Also, I'm not sure the formatting implementation is correct. The TyPatKind::Or could exceed the max_width without wrapping if it's very long. I feel like we should implement this similarly to PatKind::Or.

If possible, can you add a test case with the relevant #![feature()] annotation?

Comment on lines +1252 to +1253
// FIXME(pattern_types): check that the value is covered by one of the variants.
// The layout may pessimistically cover actually illegal ranges.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// FIXME(pattern_types): check that the value is covered by one of the variants.
// The layout may pessimistically cover actually illegal ranges.
// FIXME(pattern_types): check that the value is covered by one of the variants.
// For now, we rely on layout computation setting the scalar's `valid_range` to
// match the pattern. However, this cannot always work; the layout may
// pessimistically cover actually illegal ranges and Miri would miss that UB.
// The consolation here is that codegen also will miss that UB, so at least
// we won't see optimizations actually breaking such programs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants