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

Dedup bounds with parent impl block #105325

Closed

Conversation

GuillaumeGomez
Copy link
Member

This is another part of #104886.

It still doesn't fix it as I need to handle Self as the last part.

r? @notriddle

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. labels Dec 5, 2022
Comment on lines 275 to 313
let (check_not_in_parent_bounds, check_not_in_parent_params): (
Box<dyn Fn(&GenericBound) -> bool>,
Box<dyn Fn(&Lifetime) -> bool>,
) = if let Some((bounds, bound_params)) = parent_where_predicates
.iter()
.filter_map(|pred| match pred {
WherePredicate::BoundPredicate { ty: parent_ty, bounds, bound_params }
if *parent_ty == ty =>
{
Some((bounds, bound_params))
}
_ => None,
})
.next()
{
(
Box::new(move |bound: &GenericBound| !bounds.contains(&bound)),
Box::new(move |bound_param: &Lifetime| !bound_params.contains(&bound_param)),
)
} else {
(Box::new(|_: &GenericBound| true), Box::new(|_: &Lifetime| true))
};

let (check_not_in_parent_tys, check_not_in_parent_lifetimes): (
Box<dyn Fn(&GenericBound) -> bool>,
Box<dyn Fn(&Lifetime) -> bool>,
) = if let Some(parent_bound) =
parent_params.iter().filter(|gen| Type::Generic(gen.name) == ty).next()
{
(
Box::new(move |bound: &GenericBound| match &parent_bound.kind {
GenericParamDefKind::Type { bounds, .. } => !bounds.contains(&bound),
_ => true,
}),
Box::new(move |bound: &Lifetime| match &parent_bound.kind {
GenericParamDefKind::Lifetime { outlives } => !outlives.contains(&bound),
_ => true,
}),
)
} else {
(Box::new(|_: &GenericBound| true), Box::new(|_: &Lifetime| true))
};
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 whole code isn't great but I don't know how to make it a bit better. If someone has an idea...

Copy link
Member

@fmease fmease Dec 5, 2022

Choose a reason for hiding this comment

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

What if instead of creating closures closing over bounds / bound_params / outlives, you simply return those aforementioned variables from the two if lets (returning Default::default() / None / Vec::new() from the else branch) and later write closures inline: .filter(check_not_in_parent_bounds).filter(|bound| !parent_bounds.contains(bound)). Cloning should not be necessary since you should be able to use references. Not sure if that works out well and looks better but might be worth a shot.

Copy link
Member

@fmease fmease Dec 5, 2022

Choose a reason for hiding this comment

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

To illustrate:

- let (check_not_in_parent_bounds, check_not_in_parent_params): (
-     Box<dyn Fn(&GenericBound) -> bool>,
-     Box<dyn Fn(&Lifetime) -> bool>,
- ) = if let Some((bounds, bound_params)) =
-     parent_where_predicates.iter().find_map(|pred| match pred {
-         WherePredicate::BoundPredicate { ty: parent_ty, bounds, bound_params }
-             if *parent_ty == ty =>
-         {
-             Some((bounds, bound_params))
-         }
-         _ => None,
-     }) {
-     (
-         Box::new(move |bound: &GenericBound| !bounds.contains(&bound)),
-         Box::new(move |bound_param: &Lifetime| !bound_params.contains(&bound_param)),
-     )
- } else {
-     (Box::new(|_: &GenericBound| true), Box::new(|_: &Lifetime| true))
- };
+ let (parent_bounds, parent_bound_params) = parent_where_predicates
+     .iter()
+     .find_map(|pred| match pred {
+         WherePredicate::BoundPredicate {
+             ty: parent_ty,
+             bounds,
+             bound_params,
+         } if *parent_ty == ty => Some((bounds, bound_params)),
+         _ => None,
+     })
+     .unwrap_or(const { (&Vec::new(), &Vec::new()) });

Copy link
Member

@fmease fmease Dec 5, 2022

Choose a reason for hiding this comment

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

bounds & bound_params are of type &Vec<_> as far as I can tell, so I guess .unwrap_or_default() does not work (Vec<_> impls Default but &Vec<_> does not). However, you could instead write sth. like .unwrap_or(const { (&Vec::new(), &Vec::new()) }) instead where the const block const { … } creates &'static Vec<_>s. Instead of const blocks, you could also use const items or apart from that Cow::Owned(Vec::new()) (and Cow::Borrowed in the Some case).

Edit 0: I've updated the patch above.
Edit 1: What do you think about that?

}
_ => None,
})
.next()
Copy link
Member

Choose a reason for hiding this comment

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

.filter_map(…).next().find_map(…)

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice, thanks!

@GuillaumeGomez GuillaumeGomez force-pushed the dedup-bounds-with-parent branch from 2829fc0 to 8a78f42 Compare December 5, 2022 20:58
@oli-obk
Copy link
Contributor

oli-obk commented Dec 5, 2022

This is a lot of code doing something half way what the type system knows how to do perfectly. Basically you could get the param env of the parent and see if any of the predicates of the child can be proven just with that param env. Any that can, can be safely ignored.

Should hopefully be as simple as building an obligation and calling tcx.evaluate_obligation on it.

@oli-obk
Copy link
Contributor

oli-obk commented Dec 8, 2022

Closing in favor of #105392

@oli-obk oli-obk closed this Dec 8, 2022
@GuillaumeGomez GuillaumeGomez deleted the dedup-bounds-with-parent branch December 8, 2022 09:54
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-rustdoc Relevant to the rustdoc 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