diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index ad02ca252c406..bd0ab6463f08a 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -342,9 +342,16 @@ fn compare_method_predicate_entailment<'tcx>( continue; }; for obligation in obligations { + debug!(?obligation); match obligation.predicate.kind().skip_binder() { + // We need to register Projection oblgiations too, because we may end up with + // an implied `X::Item: 'a`, which gets desugared into `X::Item = ?0`, `?0: 'a`. + // If we only register the region outlives obligation, this leads to an unconstrained var. + // See `implied_bounds_entailment_alias_var` test. ty::PredicateKind::Clause( - ty::ClauseKind::RegionOutlives(..) | ty::ClauseKind::TypeOutlives(..), + ty::ClauseKind::RegionOutlives(..) + | ty::ClauseKind::TypeOutlives(..) + | ty::ClauseKind::Projection(..), ) => ocx.register_obligation(obligation), ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { if wf_args_seen.insert(arg) { diff --git a/tests/ui/implied-bounds/implied_bounds_entailment_alias_var.rs b/tests/ui/implied-bounds/implied_bounds_entailment_alias_var.rs new file mode 100644 index 0000000000000..e0df96b0de8ea --- /dev/null +++ b/tests/ui/implied-bounds/implied_bounds_entailment_alias_var.rs @@ -0,0 +1,32 @@ +// check-pass + +trait Data { + type Elem; +} + +impl> Data for ArrayBase { + type Elem = F; +} + +struct DatasetIter<'a, R: Data> { + data: &'a R::Elem, +} + +pub struct ArrayBase { + data: S, +} + +trait Trait { + type Item; + fn next() -> Option; +} + +impl<'a, D: Data> Trait for DatasetIter<'a, ArrayBase> { + type Item = (); + + fn next() -> Option { + None + } +} + +fn main() {}