diff options
7 files changed, 118 insertions, 58 deletions
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index aae870f7ee3..924779f8dc0 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 1f3969bd93c..fbbd6e9957f 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1,4 +1,3 @@ -use std::assert_matches::debug_assert_matches; use std::cell::{Cell, RefCell}; use std::cmp::max; use std::ops::Deref; @@ -16,7 +15,7 @@ use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, use rustc_infer::traits::ObligationCauseCode; use rustc_middle::middle::stability; use rustc_middle::ty::elaborate::supertrait_def_ids; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; +use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; use rustc_middle::ty::{ self, AssocItem, AssocItemContainer, GenericArgs, GenericArgsRef, GenericParamDefKind, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, Upcast, @@ -803,8 +802,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ); } } - ty::Param(_) => { - self.assemble_inherent_candidates_from_param(raw_self_ty); + ty::Param(p) => { + self.assemble_inherent_candidates_from_param(p); } ty::Bool | ty::Char @@ -905,16 +904,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - fn assemble_inherent_candidates_from_param(&mut self, param_ty: Ty<'tcx>) { - debug_assert_matches!(param_ty.kind(), ty::Param(_)); - - let tcx = self.tcx; + fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) { let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::ClauseKind::Trait(trait_predicate) => DeepRejectCtxt::relate_rigid_rigid(tcx) - .types_may_unify(param_ty, trait_predicate.trait_ref.self_ty()) - .then(|| bound_predicate.rebind(trait_predicate.trait_ref)), + ty::ClauseKind::Trait(trait_predicate) => { + match *trait_predicate.trait_ref.self_ty().kind() { + ty::Param(p) if p == param_ty => { + Some(bound_predicate.rebind(trait_predicate.trait_ref)) + } + _ => None, + } + } ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::Projection(_) diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent.current.stderr b/tests/ui/methods/rigid-alias-bound-is-not-inherent.current.stderr new file mode 100644 index 00000000000..4652bf5e3c5 --- /dev/null +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent.current.stderr @@ -0,0 +1,30 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/rigid-alias-bound-is-not-inherent.rs:42:7 + | +LL | x.method(); + | ^^^^^^ multiple `method` found + | +note: candidate #1 is defined in the trait `Trait1` + --> $DIR/rigid-alias-bound-is-not-inherent.rs:21:5 + | +LL | fn method(&self) { + | ^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `Trait2` for the type `T` + --> $DIR/rigid-alias-bound-is-not-inherent.rs:27:5 + | +LL | fn method(&self) { + | ^^^^^^^^^^^^^^^^ +help: disambiguate the method for candidate #1 + | +LL - x.method(); +LL + Trait1::method(&x); + | +help: disambiguate the method for candidate #2 + | +LL - x.method(); +LL + Trait2::method(&x); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr b/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr new file mode 100644 index 00000000000..afacb3a7d52 --- /dev/null +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr @@ -0,0 +1,30 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/rigid-alias-bound-is-not-inherent.rs:42:7 + | +LL | x.method(); + | ^^^^^^ multiple `method` found + | +note: candidate #1 is defined in the trait `Trait1` + --> $DIR/rigid-alias-bound-is-not-inherent.rs:21:5 + | +LL | fn method(&self) { + | ^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in the trait `Trait2` + --> $DIR/rigid-alias-bound-is-not-inherent.rs:27:5 + | +LL | fn method(&self) { + | ^^^^^^^^^^^^^^^^ +help: disambiguate the method for candidate #1 + | +LL - x.method(); +LL + Trait1::method(&x); + | +help: disambiguate the method for candidate #2 + | +LL - x.method(); +LL + Trait2::method(&x); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent.rs b/tests/ui/methods/rigid-alias-bound-is-not-inherent.rs new file mode 100644 index 00000000000..3dd63df3f39 --- /dev/null +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent.rs @@ -0,0 +1,46 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// See the code below. +// +// We were using `DeepRejectCtxt` to ensure that `assemble_inherent_candidates_from_param` +// did not rely on the param-env being eagerly normalized. Since aliases unify with all +// types, this meant that a rigid param-env candidate like `<T as Deref>::Target: Trait1` +// would be registered as a "WhereClauseCandidate", which is treated as inherent. Since +// we evaluate these candidates for all self types in the deref chain, this candidate +// would be satisfied for `<T as Deref>::Target`, meaning that it would be preferred over +// an "extension" candidate like `<T as Deref>::Target: Trait2` even though it holds. +// This is problematic, since it causes ambiguities to be broken somewhat arbitrarily. +// And as a side-effect, it also caused our computation of "used" traits to be miscalculated +// since inherent candidates don't count as an import usage. + +use std::ops::Deref; + +trait Trait1 { + fn method(&self) { + println!("1"); + } +} + +trait Trait2 { + fn method(&self) { + println!("2"); + } +} +impl<T: Other + ?Sized> Trait2 for T {} + +trait Other {} + +fn foo<T>(x: T) +where + T: Deref, + <T as Deref>::Target: Trait1 + Other, +{ + // Make sure that we don't prefer methods from where clauses for rigid aliases, + // just for params. We could revisit this behavior, but it would be a lang change. + x.method(); + //~^ ERROR multiple applicable items in scope +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs deleted file mode 100644 index ffb99d6d638..00000000000 --- a/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ check-pass -//@ revisions: current next -//@ ignore-compare-mode-next-solver (explicit revisions) -//@[next] compile-flags: -Znext-solver - -// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/214>. -// See comment below. - -trait A { - fn hello(&self) {} -} - -trait B { - fn hello(&self) {} -} - -impl<T> A for T {} -impl<T> B for T {} - -fn test<F, R>(q: F::Item) -where - F: Iterator<Item = R>, - // We want to prefer `A` for `R.hello()` - F::Item: A, -{ - q.hello(); -} - -fn main() {} diff --git a/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs deleted file mode 100644 index dde4f745879..00000000000 --- a/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ check-pass -//@ compile-flags: -Znext-solver - -// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/214>. - -fn execute<K, F, R>(q: F::Item) -> R -where - F: Iterator<Item = R>, - // Both of the below bounds should be considered for `.into()`, and then be combined - // into a single `R: Into<?0>` bound which can be inferred to `?0 = R`. - F::Item: Into<K>, - R: Into<String>, -{ - q.into() -} - -fn main() {} |
