From fb327ab85575af7d66ab2fb0a10164365717a32b Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Sun, 25 Apr 2021 15:11:49 -0400 Subject: [PATCH 1/4] Deduplicate ParamCandidates with the same value except for bound vars --- .../src/traits/select/mod.rs | 12 ++++++++++- src/test/ui/lifetimes/issue-84398.rs | 20 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/lifetimes/issue-84398.rs diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e4aabbdb7ede7..c9ba8e6dc8ce7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1361,7 +1361,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) => false, (ParamCandidate(other), ParamCandidate(victim)) => { - if other.value == victim.value && victim.constness == Constness::NotConst { + let value_same_except_bound_vars = other.value.skip_binder() + == victim.value.skip_binder() + && !other.value.skip_binder().has_escaping_bound_vars(); + if value_same_except_bound_vars { + // See issue #84398. In short, we can generate multiple ParamCandidates which are + // the same except for unused bound vars. Just pick the current one (the should + // both evaluate to the same answer). This is probably best characterized as a + // "hack", since we might prefer to just do our best to *not* create essentially + // duplicate candidates in the first place. + true + } else if other.value == victim.value && victim.constness == Constness::NotConst { // Drop otherwise equivalent non-const candidates in favor of const candidates. true } else { diff --git a/src/test/ui/lifetimes/issue-84398.rs b/src/test/ui/lifetimes/issue-84398.rs new file mode 100644 index 0000000000000..1912fa59b7990 --- /dev/null +++ b/src/test/ui/lifetimes/issue-84398.rs @@ -0,0 +1,20 @@ +// check-pass + +pub trait Deserialize<'de>: Sized {} +pub trait DeserializeOwned: for<'de> Deserialize<'de> {} + +pub trait Extensible { + type Config; +} + +// The `C` here generates a `C: Sized` candidate +pub trait Installer { + fn init>(&mut self) -> () + where + // This clause generates a `for<'de> C: Sized` candidate + B::Config: DeserializeOwned, + { + } +} + +fn main() {} From 40e2c346c632426346bcb8c06c40d465bbb78d55 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Thu, 6 May 2021 10:19:51 -0400 Subject: [PATCH 2/4] Pick candidate with fewer bound vars --- .../rustc_trait_selection/src/traits/select/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c9ba8e6dc8ce7..727285e4927a0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1366,11 +1366,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { && !other.value.skip_binder().has_escaping_bound_vars(); if value_same_except_bound_vars { // See issue #84398. In short, we can generate multiple ParamCandidates which are - // the same except for unused bound vars. Just pick the current one (the should - // both evaluate to the same answer). This is probably best characterized as a - // "hack", since we might prefer to just do our best to *not* create essentially - // duplicate candidates in the first place. - true + // the same except for unused bound vars. Just pick the one with the fewest bound vars + // or the current one if tied (they should both evaluate to the same answer). This is + // probably best characterized as a "hack", since we might prefer to just do our + // best to *not* create essentially duplicate candidates in the first place. + other.value.bound_vars().len() <= victim.value.bound_vars().len() } else if other.value == victim.value && victim.constness == Constness::NotConst { // Drop otherwise equivalent non-const candidates in favor of const candidates. true From 8c48c6e8ab841f980b015870aff8ccd72974d820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 1 May 2021 17:18:04 -0700 Subject: [PATCH 3/4] Account for unsatisfied bounds in E0599 Fix #84769, follow up to #84499, #83667. --- .../rustc_typeck/src/check/method/suggest.rs | 6 +++++- .../import-trait-for-method-call.rs | 9 ++++++++- .../import-trait-for-method-call.stderr | 18 +++++++++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 73e35f0171aa7..b2e4e7a981d20 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -579,6 +579,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let mut restrict_type_params = false; + let mut unsatisfied_bounds = false; if !unsatisfied_predicates.is_empty() { let def_span = |def_id| { self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id)) @@ -739,6 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(&format!( "the following trait bounds were not satisfied:\n{bound_list}" )); + unsatisfied_bounds = true; } } @@ -752,6 +754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source, out_of_scope_traits, &unsatisfied_predicates, + unsatisfied_bounds, ); } @@ -984,9 +987,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: SelfSource<'tcx>, valid_out_of_scope_traits: Vec, unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option>)], + unsatisfied_bounds: bool, ) { let mut alt_rcvr_sugg = false; - if let SelfSource::MethodCall(rcvr) = source { + if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) { debug!(?span, ?item_name, ?rcvr_ty, ?rcvr); let skippable = [ self.tcx.lang_items().clone_trait(), diff --git a/src/test/ui/suggestions/import-trait-for-method-call.rs b/src/test/ui/suggestions/import-trait-for-method-call.rs index 646f68dea14e8..4dbadbdf98206 100644 --- a/src/test/ui/suggestions/import-trait-for-method-call.rs +++ b/src/test/ui/suggestions/import-trait-for-method-call.rs @@ -6,4 +6,11 @@ fn next_u64() -> u64 { h.finish() //~ ERROR no method named `finish` found for struct `DefaultHasher` } -fn main() {} +trait Bar {} +impl Bar for String {} + +fn main() { + let s = String::from("hey"); + let x: &dyn Bar = &s; + x.as_ref(); //~ ERROR the method `as_ref` exists for reference `&dyn Bar`, but its trait bounds +} diff --git a/src/test/ui/suggestions/import-trait-for-method-call.stderr b/src/test/ui/suggestions/import-trait-for-method-call.stderr index f3ae20552f3d5..a2b9b9d14ab09 100644 --- a/src/test/ui/suggestions/import-trait-for-method-call.stderr +++ b/src/test/ui/suggestions/import-trait-for-method-call.stderr @@ -15,6 +15,22 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f LL | use std::hash::Hasher; | -error: aborting due to previous error +error[E0599]: the method `as_ref` exists for reference `&dyn Bar`, but its trait bounds were not satisfied + --> $DIR/import-trait-for-method-call.rs:15:7 + | +LL | trait Bar {} + | --------- doesn't satisfy `dyn Bar: AsRef<_>` +... +LL | x.as_ref(); + | ^^^^^^ method cannot be called on `&dyn Bar` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `dyn Bar: AsRef<_>` + which is required by `&dyn Bar: AsRef<_>` + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `as_ref`, perhaps you need to implement it: + candidate #1: `AsRef` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0599`. From 0013b4442f1c4f89c3683a8fda06555494e0cee7 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 6 May 2021 18:08:57 +0200 Subject: [PATCH 4/4] bump stage0 to production 1.52.0 --- src/stage0.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stage0.txt b/src/stage0.txt index 3a76177474908..231e66719d00a 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # stable release's version number. `date` is the date where the release we're # bootstrapping off was released. -date: 2021-05-04 +date: 2021-05-06 rustc: 1.52.0 # We use a nightly rustfmt to format the source because it solves some @@ -39,4 +39,4 @@ rustc: 1.52.0 # looking at a beta source tarball and it's uncommented we'll shortly comment it # out. -dev: 1 +#dev: 1