-
Notifications
You must be signed in to change notification settings - Fork 13.5k
More robustly deal with relaxed bounds and improve their diagnostics #142693
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
base: master
Are you sure you want to change the base?
Conversation
8d31700
to
4634541
Compare
69e237d
to
03d01fa
Compare
8a6f65d
to
04dad4e
Compare
@bors2 try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (bfa10de): comparison URL. Overall result: ❌ regressions - please read the text belowBenchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf. Next Steps: If you can justify the regressions found in this try perf run, please do so in sufficient writing along with @bors rollup=never Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (secondary -2.7%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary 2.9%, secondary 4.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 1.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 692.606s -> 692.191s (-0.06%) |
☔ The latest upstream changes (presumably #143091) made this pull request unmergeable. Please resolve the merge conflicts. |
Looks spurious? |
This comment has been minimized.
This comment has been minimized.
Finished benchmarking commit (6893bb5): comparison URL. Overall result: ✅ improvements - no action neededBenchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf. @bors rollup=never Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (secondary -3.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 689.948s -> 690.572s (0.09%) |
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.
Previously, we would pass "fake" trait bound modifiers (constness=never, polarity=positive) for object bounds to HIR ty lowering, now we pass the actual modifiers.
This ofc means the compiler output becomes more verbose for inputs like this but these new errors are perfectly reasonable.
Motivation: If we ever start supporting const bounds in dyn-Trait (not unlikely) then we will have proper validation already in place thanks to this change. Continuing to pass fake modifiers runs the risk that we forget to add the validation before stabilization in this hypothetical scenario (sadly we have a bad track record for this, cc relaxed bounds).
// later desugars into a trait predicate. | ||
let bounds = self.lower_param_bounds(bounds, itctx); | ||
|
||
// FIXME(#135229): These should be forbidden! |
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.
My plan is to make this change in PR #135331 once this PR merges and ask for a types FCP over there.
span: Span, | ||
rbp: RelaxedBoundPolicy<'_>, | ||
) { | ||
let err = |message| feature_err(&self.tcx.sess, sym::more_maybe_bounds, span, message); |
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'm not super fond of the fact that we currently advertise the internal feature more_maybe_bounds
(it's a bit distracting, too). I'd rather get rid of the feature suggestion similar to the internal feature negative_bounds
. LMKWYT
if let Some(res) = self.resolver.get_partial_res(id).and_then(|r| r.full_res()) | ||
&& let Res::Def(DefKind::TyParam, def_id) = res | ||
&& params.iter().any(|p| def_id == self.local_def_id(p.id).to_def_id()) | ||
{ | ||
return; | ||
} |
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.
The old approach in lower_generics
cached the datum of whether the bounded ty was a "good ty param" which we no longer do.
However if you think about it, the caching on master doesn't make any sense in practice for real user-written code: It did avoid recomputation in where T: ?Sized + ?Sized + ?Sized
(nobody writes multiple relaxed bounds since they're later rejected during HIR ty lowering) but it didn't avoid the recalculation in where T: ?Sized, U: ?Sized, V: ?Sized
which is what users actually write (to be clear, the new code also recomputes this, it just throws out the unnecessary caching logic).
diag.emit(); | ||
return; | ||
} | ||
RelaxedBoundForbiddenReason::LateBoundVarsInScope => {} |
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.
We could emit a custom diagnostic for this but it's simply not worth it.
err("`?Trait` bounds are only permitted at the point where a type parameter is declared") | ||
err("this relaxed bound is not permitted here") | ||
.with_note( | ||
"in this context, relaxed bounds are only allowed on \ |
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.
"in this context" because in other contexts like in assoc tys, relaxed bounds are also allowed in other places (in that case: assoc ty item bounds).
} | ||
rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds), | ||
rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds), | ||
// FIXME(fmease): This is super hacky! `Option<Polarity>` is also sad. |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
r? compiler-errors or reassign if you're busy or not interested |
This comment was marked as resolved.
This comment was marked as resolved.
Only relevant to the internal feature `more_maybe_bounds`.
We no longer move trait predicates where the self ty is a ty param to "the bounds of a ty param".
* The phrasing "only does something for" made sense back when this diagnostic was a (hard) warning. Now however, it's simply a hard error and thus completely rules out "doing something". * The primary message was way too long * The new wording more closely mirrors the wording we use for applying other bound modifiers (like `const` and `async`) to incompatible traits. * "all other traits are not bound by default" is no longer accurate under Sized Hierarchy. E.g., traits and assoc tys are (currently) bounded by `MetaSized` by default but can't be relaxed using `?MetaSized` (instead, you relax it by adding `PointeeSized`). * I've decided against adding any diagnositic notes or suggestions for now like "trait `Trait` can't be relaxed as it's not bound by default" which would be incorrect for `MetaSized` and assoc tys as mentioned above) or "consider changing `?MetaSized` to `PointeeSized`" as the Sized Hierarchy impl is still WIP)
Having multiple relaxed bounds like `?Sized + ?Iterator` is actually *fine*. We actually want to reject *duplicate* relaxed bounds like `?Sized + ?Sized` because these most certainly represent a user error. Note that this doesn't mean that we accept more code because a bound like `?Iterator` is still invalid as it's not relaxing a *default* trait and the only way to define / use more default bounds is under the experimental and internal feature `more_maybe_bounds` plus `lang_items` plus unstable flag `-Zexperimental-default-bounds`. Ultimately, this simply *reframes* the diagnostic. The scope of `more_maybe_bounds` / `-Zexperimental-default-bounds` remains unchanged as well.
c74e11c
to
45a63cb
Compare
@@ -70,13 +69,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { | |||
let guar = self.report_trait_object_addition_traits(®ular_traits); | |||
return Ty::new_error(tcx, guar); | |||
} | |||
// We don't support `PointeeSized` principals |
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.
My PR predates #143104.
This commit basically reverts this logic because it's unreachable due to us filtering out PointeeSized
inside lower_poly_trait_ref
. The diagnostic is definitely worse, we now say at least one trait is required for an object type
instead of `PointeeSized` cannot be used with trait objects
.
Welp, I guess I should address the diagnostic regression (😩) since it only makes sense if you know the lowering… This kinda ties in with finding a better solution for #142693 (comment)
// reject relaxed bounds outright during AST lowering. | ||
// However, this can easily get out of sync! Ideally, we would perform this step | ||
// where we are guaranteed to catch *all* bounds like in | ||
// `Self::lower_poly_trait_ref`. List of concrete issues: |
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.
(We likely can't actually do it in lower_poly_trait_ref
because we need access to all the neighboring HIR bounds)
if let Some(res) = self.resolver.get_partial_res(id).and_then(|r| r.full_res()) | ||
&& let Res::Def(DefKind::TyParam, def_id) = res | ||
&& params.iter().any(|p| def_id == self.local_def_id(p.id).to_def_id()) |
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.
(If you're curious, we can't simply replace this with something that's based on rustc_middle::ty
and located in HIR ty lowering while preserving stable behavior: We need it to be based on the HIR to reject cases like (T): ?Sized
at which point AST lowering remains a good enough place)
rustc_ast::BoundPolarity::Maybe(_) => { | ||
(ty::PredicatePolarity::Positive, &mut Vec::new()) | ||
} |
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.
(repost of #142693 (comment) which is on an outdated diff)
I'm not happy about the way this is structured and the fact that we map Maybe
to Positive
, it's a hack. The non-sentinel approach of using Option<ty::PredicatePolarity>
just yields very verbose and still ugly code.
Bigger picture: As you can see a few lines further down we used to duplicate the lower_assoc_item_constraint
loop to catch bad bounds like ?Sized<Undefined = ()>
. This is obv annoying and not scalable (e.g., for PointeeSized
we also need to validate the bound constness which is a lot more code I don't want to dupe / extract into a method (hmmm...)). So the new approach is to do as much normal lowering for these "fake bounds" as possible but send everything into the drain (&mut Vec::new()
).
Idk :|
The job Click to see the possible cause of the failure (guessed by this bot)
|
Scaffolding for #135229 (CC #135331)
Fixes #136944.
Fixes #142718.