about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs9
-rw-r--r--tests/ui/implied-bounds/implied_bounds_entailment_alias_var.rs32
2 files changed, 40 insertions, 1 deletions
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 ad02ca252c4..bd0ab6463f0 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 00000000000..e0df96b0de8
--- /dev/null
+++ b/tests/ui/implied-bounds/implied_bounds_entailment_alias_var.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+trait Data {
+    type Elem;
+}
+
+impl<F, S: Data<Elem = F>> Data for ArrayBase<S> {
+    type Elem = F;
+}
+
+struct DatasetIter<'a, R: Data> {
+    data: &'a R::Elem,
+}
+
+pub struct ArrayBase<S> {
+    data: S,
+}
+
+trait Trait {
+    type Item;
+    fn next() -> Option<Self::Item>;
+}
+
+impl<'a, D: Data> Trait for DatasetIter<'a, ArrayBase<D>> {
+    type Item = ();
+
+    fn next() -> Option<Self::Item> {
+        None
+    }
+}
+
+fn main() {}