From 3602e0e262275c898966c45553c406c4873472fe Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Fri, 14 Jan 2022 20:51:30 -0500 Subject: [PATCH 1/2] Don't match any projection predicates when the obligation has inference types or consts in GAT substs --- .../src/traits/error_reporting/suggestions.rs | 4 +-- .../src/traits/select/mod.rs | 10 +++++++ .../generic-associated-types/issue-91762.rs | 30 +++++++++++++++++++ .../issue-91762.stderr | 22 ++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/generic-associated-types/issue-91762.rs create mode 100644 src/test/ui/generic-associated-types/issue-91762.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 6634f3e364d32..9a7d06ef6406d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2470,8 +2470,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let projection_ty = ty::ProjectionTy { // `T` substs: self.tcx.mk_substs_trait( - trait_pred.self_ty().skip_binder(), - self.fresh_substs_for_item(span, item_def_id), + trait_ref.self_ty().skip_binder(), + &self.fresh_substs_for_item(span, item_def_id)[1..], ), // `Future::Output` item_def_id, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 47427395b93b3..562535b0fea39 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1521,6 +1521,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infer_predicate.projection_ty }; + // If the obligation contains any inference types or consts in associated + // type substs, then we don't match any projection candidates against it. + // This isn't really correct, but otherwise we can end up in a case where + // we constrain inference variables by selecting a single predicate, when + // we need to stay general. See issue #91762. + let (_, predicate_own_substs) = + obligation.predicate.trait_ref_and_own_substs(self.infcx.tcx); + if predicate_own_substs.iter().any(|g| g.has_infer_types_or_consts()) { + return false; + } self.infcx .at(&obligation.cause, obligation.param_env) .sup(obligation.predicate, infer_projection) diff --git a/src/test/ui/generic-associated-types/issue-91762.rs b/src/test/ui/generic-associated-types/issue-91762.rs new file mode 100644 index 0000000000000..e39a127abfd81 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-91762.rs @@ -0,0 +1,30 @@ +// check-fail + +// FIXME(generic_associated_types): We almost certaintly want this to pass, but +// it's particularly difficult currently, because we need a way of specifying +// that `::With = Self` without using that when we have +// a `U`. See `https://github.com/rust-lang/rust/pull/92728` for a (hacky) +// solution. This might be better to just wait for Chalk. + +#![feature(generic_associated_types)] + +pub trait Functor { + type With; + + fn fmap(this: Self::With) -> Self::With; +} + +pub trait FunctorExt: Sized { + type Base: Functor = Self>; + + fn fmap(self) { + let arg: ::With; + let ret: ::With; + + arg = self; + ret = ::fmap(arg); + //~^ mismatched types + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-91762.stderr b/src/test/ui/generic-associated-types/issue-91762.stderr new file mode 100644 index 0000000000000..e177e151d8aac --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-91762.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/issue-91762.rs:25:45 + | +LL | / pub trait FunctorExt: Sized { +LL | | type Base: Functor = Self>; +LL | | +LL | | fn fmap(self) { +... | +LL | | ret = ::fmap(arg); + | | ^^^ expected associated type, found type parameter `Self` +LL | | +LL | | } +LL | | } + | |_- this type parameter + | + = note: expected associated type `<>::Base as Functor>::With<_>` + found type parameter `Self` + = note: you might be missing a type parameter or trait bound + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 7ad48bd4e22aaffa5ac32809b9196fab9c04de2c Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Fri, 14 Jan 2022 21:21:40 -0500 Subject: [PATCH 2/2] Change inference var check to be in project_type --- .../src/traits/error_reporting/suggestions.rs | 2 +- .../src/traits/project.rs | 10 ++++++++ .../src/traits/select/mod.rs | 10 -------- .../generic-associated-types/issue-74824.rs | 1 + .../issue-74824.stderr | 11 +++++++-- .../generic-associated-types/issue-91762.rs | 2 +- .../issue-91762.stderr | 23 ++++--------------- 7 files changed, 27 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9a7d06ef6406d..b594723aa0bd2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2470,7 +2470,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let projection_ty = ty::ProjectionTy { // `T` substs: self.tcx.mk_substs_trait( - trait_ref.self_ty().skip_binder(), + trait_pred.self_ty().skip_binder(), &self.fresh_substs_for_item(span, item_def_id)[1..], ), // `Future::Output` diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 5e7d4c8b415c3..36cc14610cb4b 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1073,6 +1073,16 @@ fn project<'cx, 'tcx>( return Ok(Projected::Progress(Progress::error(selcx.tcx()))); } + // If the obligation contains any inference types or consts in associated + // type substs, then we don't assemble any candidates. + // This isn't really correct, but otherwise we can end up in a case where + // we constrain inference variables by selecting a single predicate, when + // we need to stay general. See issue #91762. + let (_, predicate_own_substs) = obligation.predicate.trait_ref_and_own_substs(selcx.tcx()); + if predicate_own_substs.iter().any(|g| g.has_infer_types_or_consts()) { + return Err(ProjectionError::TooManyCandidates); + } + let mut candidates = ProjectionCandidateSet::None; // Make sure that the following procedures are kept in order. ParamEnv diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 562535b0fea39..47427395b93b3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1521,16 +1521,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infer_predicate.projection_ty }; - // If the obligation contains any inference types or consts in associated - // type substs, then we don't match any projection candidates against it. - // This isn't really correct, but otherwise we can end up in a case where - // we constrain inference variables by selecting a single predicate, when - // we need to stay general. See issue #91762. - let (_, predicate_own_substs) = - obligation.predicate.trait_ref_and_own_substs(self.infcx.tcx); - if predicate_own_substs.iter().any(|g| g.has_infer_types_or_consts()) { - return false; - } self.infcx .at(&obligation.cause, obligation.param_env) .sup(obligation.predicate, infer_projection) diff --git a/src/test/ui/generic-associated-types/issue-74824.rs b/src/test/ui/generic-associated-types/issue-74824.rs index 1bbf7aac5cdab..01f99fa448749 100644 --- a/src/test/ui/generic-associated-types/issue-74824.rs +++ b/src/test/ui/generic-associated-types/issue-74824.rs @@ -17,6 +17,7 @@ impl UnsafeCopy for T {} fn main() { let b = Box::new(42usize); let copy = <()>::copy(&b); + //~^ type annotations needed let raw_b = Box::deref(&b) as *const _; let raw_copy = Box::deref(©) as *const _; diff --git a/src/test/ui/generic-associated-types/issue-74824.stderr b/src/test/ui/generic-associated-types/issue-74824.stderr index 8517eb9fa2102..e7ebf5964ba41 100644 --- a/src/test/ui/generic-associated-types/issue-74824.stderr +++ b/src/test/ui/generic-associated-types/issue-74824.stderr @@ -27,6 +27,13 @@ help: consider restricting type parameter `T` LL | type Copy: Copy = Box; | +++++++++++++++++++ -error: aborting due to 2 previous errors +error[E0282]: type annotations needed + --> $DIR/issue-74824.rs:19:16 + | +LL | let copy = <()>::copy(&b); + | ^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `copy` + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0282. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-91762.rs b/src/test/ui/generic-associated-types/issue-91762.rs index e39a127abfd81..b259a3c6e06bc 100644 --- a/src/test/ui/generic-associated-types/issue-91762.rs +++ b/src/test/ui/generic-associated-types/issue-91762.rs @@ -23,7 +23,7 @@ pub trait FunctorExt: Sized { arg = self; ret = ::fmap(arg); - //~^ mismatched types + //~^ type annotations needed } } diff --git a/src/test/ui/generic-associated-types/issue-91762.stderr b/src/test/ui/generic-associated-types/issue-91762.stderr index e177e151d8aac..a9c465cdd7ea2 100644 --- a/src/test/ui/generic-associated-types/issue-91762.stderr +++ b/src/test/ui/generic-associated-types/issue-91762.stderr @@ -1,22 +1,9 @@ -error[E0308]: mismatched types - --> $DIR/issue-91762.rs:25:45 +error[E0282]: type annotations needed + --> $DIR/issue-91762.rs:25:15 | -LL | / pub trait FunctorExt: Sized { -LL | | type Base: Functor = Self>; -LL | | -LL | | fn fmap(self) { -... | -LL | | ret = ::fmap(arg); - | | ^^^ expected associated type, found type parameter `Self` -LL | | -LL | | } -LL | | } - | |_- this type parameter - | - = note: expected associated type `<>::Base as Functor>::With<_>` - found type parameter `Self` - = note: you might be missing a type parameter or trait bound +LL | ret = ::fmap(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `fmap` error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0282`.