Skip to content

Commit

Permalink
Don't match any projection predicates when the obligation has inferen…
Browse files Browse the repository at this point in the history
…ce types or consts in GAT substs
  • Loading branch information
jackh726 committed Feb 7, 2022
1 parent c5e4148 commit 3602e0e
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
30 changes: 30 additions & 0 deletions src/test/ui/generic-associated-types/issue-91762.rs
Original file line number Diff line number Diff line change
@@ -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 `<Self::Base as Functor>::With<T> = 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<T>;

fn fmap<T, U>(this: Self::With<T>) -> Self::With<U>;
}

pub trait FunctorExt<T>: Sized {
type Base: Functor<With<T> = Self>;

fn fmap<U>(self) {
let arg: <Self::Base as Functor>::With<T>;
let ret: <Self::Base as Functor>::With<U>;

arg = self;
ret = <Self::Base as Functor>::fmap(arg);
//~^ mismatched types
}
}

fn main() {}
22 changes: 22 additions & 0 deletions src/test/ui/generic-associated-types/issue-91762.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
error[E0308]: mismatched types
--> $DIR/issue-91762.rs:25:45
|
LL | / pub trait FunctorExt<T>: Sized {
LL | | type Base: Functor<With<T> = Self>;
LL | |
LL | | fn fmap<U>(self) {
... |
LL | | ret = <Self::Base as Functor>::fmap(arg);
| | ^^^ expected associated type, found type parameter `Self`
LL | |
LL | | }
LL | | }
| |_- this type parameter
|
= note: expected associated type `<<Self as FunctorExt<T>>::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`.

0 comments on commit 3602e0e

Please sign in to comment.