-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Introduce TypeVisitor::BreakTy
#78779
Conversation
81f4cb3
to
b52a299
Compare
@@ -227,8 +217,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { | |||
|
|||
if !self.type_marked_structural(ty) { | |||
debug!("Search found ty: {:?}", ty); | |||
self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); | |||
return ControlFlow::BREAK; | |||
return ControlFlow::Break(NonStructuralMatchTy::Adt(&adt_def)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I find the code so much cleaner this way 😄
@@ -73,7 +73,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { | |||
} | |||
|
|||
fn has_type_flags(&self, flags: TypeFlags) -> bool { | |||
self.visit_with(&mut HasTypeFlagsVisitor { flags }).is_break() | |||
self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see the advantage of using a type other than ()
for the break in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(This was #78182 (comment))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, I remember that comment. @lcnr can you elaborate on the motivation? We should encode it in documentation/comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a ZST we explicitly document the reasons we stop visiting and the reason we check if we terminated early.
While it isn't too relevant, it makes it easier to prevent bugs like stopping early because of a different reason and forgetting to update a call site. I also feel like using a ZST here has a very low cost and removes some questions on why we are using is_break
and under which conditions we want to stop visiting.
Don't really care too much about this though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have nothing to argue against that 😆
If we can manage to remove is_break
in that case (when all visitors have been migrated), then that would enforce this by there not being a way around it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh... now that I finished reading the PR, I think we should also stop having ()
as a default for BreakTy
and require the user to specify one (or use !
as the default?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using !
as a default would be interesting 🤔 can't be misused and makes people notice the possibility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
65cdc21 🙂
b52a299
to
6995765
Compare
r? @oli-obk |
compiler/rustc_middle/src/ty/fold.rs
Outdated
@@ -964,14 +993,16 @@ impl LateBoundRegionsCollector { | |||
} | |||
|
|||
impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { | |||
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { | |||
type BreakTy = !; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✨
debug!("Search visiting ty: {:?}", ty); | ||
|
||
let (adt_def, substs) = match *ty.kind() { | ||
ty::Adt(adt_def, substs) => (adt_def, substs), | ||
ty::Param(_) => { | ||
self.found = Some(NonStructuralMatchTy::Param); | ||
return ControlFlow::BREAK; | ||
return ControlFlow::Break(NonStructuralMatchTy::Param); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is such a huge improvement to the implementation which still used bool
s ❤️ thank you for implementing all of this
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); | ||
if t != self.opaque_identity_ty && t.super_visit_with(self).is_break() { | ||
self.ty = Some(t); | ||
return ControlFlow::BREAK; | ||
return ControlFlow::Break(Some(t)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks to me like there are actually 2 visitors merged into 1 here.
The first one finds all opaque types and the second one then searches for inherited parent lifetimes, might make sense to try and split this. Not sure if you want to do this in one PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
debug!( | ||
"check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", | ||
prohibit_opaque, visitor | ||
); | ||
|
||
if prohibit_opaque { | ||
if let Some(ty) = prohibit_opaque.break_value() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can ty.unwrap()
fail here? I would expect this to not be the case. Might be missing something though.
Maybe if we have a PredicateAtom::RegionOutlives
🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, but this only ends up returning None
if we aren't inside of a type, as we would otherwise return Some(ty)
there
edit: this may happen if the predicate is an outlives predicate though I don't know if they are possible for opaque types, don't have the capacity to look into this myself atm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally would like to push a bit more to using ZST here and pretty much never use ()
. So I wouldn't add a associated type default here.
afaict @oli-obk has a different opinion so I am also fine with merging this as is.
We could change things in follow-up PRs. I made every change in a separate commit so I can easily drop some. |
df22308
to
a815e9e
Compare
fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> { | ||
debug!( | ||
"HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", | ||
t, | ||
t.flags(), | ||
self.flags | ||
); | ||
if t.flags().intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } | ||
if t.flags().intersects(self.flags) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe create a self.check_flags
method that handles this intersects
call and the if-condition?
r=me,lcnr with the dead function removed |
Done. |
@bors r+ yea, I think we can safely send it to bors, too |
📌 Commit f6e6a15 has been approved by |
Should this be rollup=never as a medium-sized refractor? (I'm still trying to understand what deserves |
for non-perf non prioritized things that probably conflict with a bunch of things we have @bors rollup=iffy |
⌛ Testing commit f6e6a15 with merge aacb816092fb150a8459de3135f62d6199fedf62... |
💥 Test timed out |
@bors retry |
…r=oli-obk Introduce `TypeVisitor::BreakTy` Implements MCP rust-lang/compiler-team#383. r? `@ghost` cc `@lcnr` `@oli-obk` ~~Blocked on FCP in rust-lang/compiler-team#383.~~
☀️ Test successful - checks-actions |
…oli-obk Introduce `TypeVisitor::BreakTy` Implements MCP rust-lang/compiler-team#383. r? `@ghost` cc `@lcnr` `@oli-obk` ~~Blocked on FCP in rust-lang/compiler-team#383.~~
Implements MCP rust-lang/compiler-team#383.
r? @ghost
cc @lcnr @oli-obk
Blocked on FCP in rust-lang/compiler-team#383.