-
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
Report a specialized error when a 'static
obligation comes from an impl dyn Trait
#121274
base: master
Are you sure you want to change the base?
Conversation
rustbot has assigned @compiler-errors. Use r? to explicitly pick a reviewer |
There are a couple of things I need to clean up, but most of the logic is close to done. |
9c53987
to
27a728a
Compare
This comment has been minimized.
This comment has been minimized.
27a728a
to
8cd50f0
Compare
This comment has been minimized.
This comment has been minimized.
Thanks for considering a different approach! <3 Could this be generalized to trait impls? I don't see why this needs to be specific to inherent impls. Ideally we would provide a very similar suggestion & note for trait impls: trait Foo {}
impl<'a> Foo for &'a u32 {}
trait Trait { fn hello(&self) {} }
impl Trait for dyn Foo {
fn hello(&self) {}
}
fn convert<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x;
y.hello();
} current stderr
|
8cd50f0
to
5b76e77
Compare
This comment was marked as resolved.
This comment was marked as resolved.
@fmease with the last change to the PR, on that code:
Edit: added to the test suite. |
5b76e77
to
5be054b
Compare
r? fmease |
These commits modify the If this was unintentional then you should revert the changes before this PR is merged. |
This comment has been minimized.
This comment has been minimized.
5be054b
to
beb547e
Compare
This comment has been minimized.
This comment has been minimized.
3bc0441
to
5074501
Compare
This comment has been minimized.
This comment has been minimized.
Some changes occurred in src/tools/clippy cc @rust-lang/clippy |
This comment has been minimized.
This comment has been minimized.
a3711d9
to
2a75eb8
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
f9a9a5e
to
20e6a6c
Compare
``` error[E0478]: lifetime bound not satisfied --> tests/ui/lifetimes/point-at-lifetime-obligation-from-trait-in-trait-object.rs:4:21 | 4 | broken: Box<dyn Any + 'a> | ^^^ ^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here --> tests/ui/lifetimes/point-at-lifetime-obligation-from-trait-in-trait-object.rs:3:18 | 3 | struct Something<'a> { | ^^ = note: but lifetime parameter must outlive the static lifetime note: unmet `'static` obligations introduced here --> rust/library/core/src/any.rs:115:16 | 115 | pub trait Any: 'static { | ^^^^^^^ ``` Fix rust-lang#83325.
``` error[E0478]: lifetime bound not satisfied --> $DIR/point-at-lifetime-obligation-from-trait-in-trait-object.rs:4:27 | LL | broken: Box<dyn Any + 'a> | --- ^^ lifetime bound not satisfied | | | this requires `'static` | note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/point-at-lifetime-obligation-from-trait-in-trait-object.rs:3:18 | LL | struct Something<'a> { | ^^ = note: but lifetime parameter must outlive the static lifetime note: `'static` requirement introduced here --> $SRC_DIR/core/src/any.rs:LL:COL ```
0f249f5
to
8766658
Compare
☔ The latest upstream changes (presumably #122852) made this pull request unmergeable. Please resolve the merge conflicts. |
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 have the energy to continue reviewing this since there's a lot going on, but in general, I would really urge you to you leave this code cleaner that you found it. I'm sorry if that requires a lot of annoying work, but that's really the price of making large changes if you care for the code's long-term maintainability.
Please at the very least remove those utility methods you added to the util crate. They're footguns at best.
@@ -235,6 +236,37 @@ pub fn elaborate<'tcx, O: Elaboratable<'tcx>>( | |||
elaborator | |||
} | |||
|
|||
pub fn elaborate_predicates_of<'tcx>( |
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.
Is this only guaranteed to be called on a trait? Never a trait item? If not, using this function is a hazard because it only computes the predicates of the item and not its parents. I would prefer if you remove it and inline it into its callsites like:
elaborate(tcx, tcx.predicates_of(def_id).instantiate_own_identity())
Though if this is intended to be called on non-top-level-items, you need to use:
elaborate(tcx, tcx.predicates_of(def_id).instantiate_identity())
(and a .map(|(clause, sp)| (clause.as_predicate(), sp))
if necessary, but you can likely rework the call-sites to operate solely on Clause
s and not Predicate
s.)
) | ||
} | ||
|
||
pub fn filter_predicates<'tcx>( |
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 think this function should get moved closer to the error reporting. It doesn't seem useful to me other than for making some filter
calls in error reporting shorter.
Also, like, what's up with the name? filter_predicates
plus the lack of documentation plus the fact that this is in the util
module makes it incredibly unclear that this is meant to filter outlives regions only. It should be called filter_outlives_regions
or something.
Also, the fact that it only filters TypeOutlives
obligations and always takes RegionOutlives
obligations seems somewhat unintuitive
@@ -451,6 +451,9 @@ pub enum ObligationCauseCode<'tcx> { | |||
|
|||
/// Obligations emitted during the normalization of a weak type alias. | |||
TypeAlias(InternedObligationCauseCode<'tcx>, Span, DefId), | |||
|
|||
/// During borrowck we've found a method call that could have introduced a lifetime requirement. | |||
MethodCallConstraint(Ty<'tcx>, Span), |
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.
Please rename this to make it clear that it's a constraint that only ever results from a region constraint category. MethodCallRegionConstraint
or something would be nice.
// ``` | ||
if let ty::Ref(region, _, _) = self | ||
.infcx | ||
.instantiate_binder_with_fresh_vars( |
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.
You don't need to instantiate this binder with vars just to check the region on its self type. You should use skip_binder
.
// Look at the receiver for `&'static self`, which introduces a `'static` obligation. | ||
// ``` | ||
// impl dyn Trait { | ||
// fn foo(&'static self) {} |
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 comment should be adjusted to make it obvious that this has nothing to do with dyn
as the Self type of the impl.
let mut parent = tcx.parent(def_id); | ||
debug!(?def_id, ?parent); | ||
let trait_preds: Vec<_> = match tcx.def_kind(parent) { | ||
hir::def::DefKind::Impl { .. } => tcx |
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.
Please import DefKind
tcx.for_each_relevant_impl(parent, ty, |id| { | ||
impls.push(id); | ||
}); | ||
if let [def_id] = impls[..] { |
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 won't work if there's a built-in impl that applies, and I kind of prefer that we remove this hack. If Instance::resolve
doesn't give you the right item back, it's probably because there's actual polymorphism going on here.
let mut predicates: Vec<Span> = elaborate_predicates_of(tcx, def_id) | ||
.chain(elaborate_predicates_of(tcx, parent)) |
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.
You shouldn't need to do the elaboration twice if you actually elaborated the full set of predicates for the item, which already contains the parent's predicates, i.e.
elaborate(tcx.predicates_of(tcx, def_id).instantiate_identity())
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 only case where this matters is when you set the parent manually due to that impl hack above. I don't think you've explained why it's needed, and I'm kinda tempted to say that we should not have it even if it regresses tests, since it's definitely not well-founded type theoretically.
.chain(elaborate_predicates_of(tcx, parent)) | ||
.chain(trait_preds) | ||
.filter_map(filter_predicates(tcx.lifetimes.re_static, |pred_ty| { | ||
self.infcx.can_eq(self.param_env, ty, pred_ty) |
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 doesn't work if there are placeholder types, so this code will fail in weird and unnecessary ways for generic code. The predicates need to be instantiated with inference vars.
.chain(trait_preds) | ||
.filter_map(filter_predicates(tcx.lifetimes.re_static, |pred_ty| { | ||
self.infcx.can_eq(self.param_env, ty, pred_ty) | ||
|| matches!( |
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.
Ah, see, that's why you needed to add this hack. it should be unnecessary.
@estebank |
They are on vacation rn and will return soon |
Fix #83246, fix #80701.
Fix #83325.