about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-ty/src/db.rs8
-rw-r--r--crates/hir-ty/src/lib.rs14
-rw-r--r--crates/hir-ty/src/traits.rs17
-rw-r--r--crates/hir/src/lib.rs29
-rw-r--r--crates/ide/src/inlay_hints.rs68
5 files changed, 94 insertions, 42 deletions
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index b385b1cafae..dd5639f00d2 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -150,6 +150,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
         id: chalk_db::AssociatedTyValueId,
     ) -> Arc<chalk_db::AssociatedTyValue>;
 
+    #[salsa::invoke(crate::traits::normalize_projection_query)]
+    #[salsa::transparent]
+    fn normalize_projection(
+        &self,
+        projection: crate::ProjectionTy,
+        env: Arc<crate::TraitEnvironment>,
+    ) -> Option<crate::Ty>;
+
     #[salsa::invoke(trait_solve_wait)]
     #[salsa::transparent]
     fn trait_solve(
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index a82a331d4b8..de4a5446e57 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -196,20 +196,6 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
     make_binders_with_count(db, usize::MAX, generics, value)
 }
 
-// FIXME: get rid of this
-pub fn make_canonical<T: HasInterner<Interner = Interner>>(
-    value: T,
-    kinds: impl IntoIterator<Item = TyVariableKind>,
-) -> Canonical<T> {
-    let kinds = kinds.into_iter().map(|tk| {
-        chalk_ir::CanonicalVarKind::new(
-            chalk_ir::VariableKind::Ty(tk),
-            chalk_ir::UniverseIndex::ROOT,
-        )
-    });
-    Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
-}
-
 // FIXME: get rid of this, just replace it by FnPointer
 /// A function signature as seen by type inference: Several parameter types and
 /// one return type.
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index 77afeb3217d..aaff894b34f 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -1,6 +1,6 @@
 //! Trait solving using Chalk.
 
-use std::env::var;
+use std::{env::var, sync::Arc};
 
 use chalk_ir::GoalData;
 use chalk_recursive::Cache;
@@ -12,8 +12,9 @@ use stdx::panic_context;
 use syntax::SmolStr;
 
 use crate::{
-    db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
-    Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
+    db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
+    Guidance, InEnvironment, Interner, ProjectionTy, Solution, TraitRefExt, Ty, TyKind,
+    WhereClause,
 };
 
 /// This controls how much 'time' we give the Chalk solver before giving up.
@@ -64,6 +65,16 @@ impl TraitEnvironment {
     }
 }
 
+pub(crate) fn normalize_projection_query(
+    db: &dyn HirDatabase,
+    projection: ProjectionTy,
+    env: Arc<TraitEnvironment>,
+) -> Option<Ty> {
+    let mut table = InferenceTable::new(db, env.clone());
+    let ty = table.normalize_projection_ty(projection);
+    Some(table.resolve_completely(ty))
+}
+
 /// Solve a trait goal using Chalk.
 pub(crate) fn trait_solve_query(
     db: &dyn HirDatabase,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 5fa4c151624..7dd891c86e8 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -63,10 +63,9 @@ use hir_ty::{
     primitive::UintTy,
     subst_prefix,
     traits::FnTrait,
-    AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
-    ClosureId, DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind,
-    QuantifiedWhereClause, Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty,
-    TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause,
+    AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
+    GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
+    TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause,
 };
 use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
@@ -2892,28 +2891,8 @@ impl Type {
                 }
             })
             .build();
-        let goal = hir_ty::make_canonical(
-            InEnvironment::new(
-                &self.env.env,
-                AliasEq {
-                    alias: AliasTy::Projection(projection),
-                    ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
-                        .intern(Interner),
-                }
-                .cast(Interner),
-            ),
-            [TyVariableKind::General].into_iter(),
-        );
 
-        match db.trait_solve(self.env.krate, goal)? {
-            Solution::Unique(s) => s
-                .value
-                .subst
-                .as_slice(Interner)
-                .first()
-                .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())),
-            Solution::Ambig(_) => None,
-        }
+        db.normalize_projection(projection, self.env.clone()).map(|ty| self.derived(ty))
     }
 
     pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index d1b1d2c331a..93fcd7cad7a 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1688,6 +1688,74 @@ fn main() {
     }
 
     #[test]
+    fn iterator_hint_regression_issue_12674() {
+        // Ensure we don't crash while solving the projection type of iterators.
+        check_expect(
+            InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
+            r#"
+//- minicore: iterators
+struct S<T>(T);
+impl<T> S<T> {
+    fn iter(&self) -> Iter<'_, T> { loop {} }
+}
+struct Iter<'a, T: 'a>(&'a T);
+impl<'a, T> Iterator for Iter<'a, T> {
+    type Item = &'a T;
+    fn next(&mut self) -> Option<Self::Item> { loop {} }
+}
+struct Container<'a> {
+    elements: S<&'a str>,
+}
+struct SliceIter<'a, T>(&'a T);
+impl<'a, T> Iterator for SliceIter<'a, T> {
+    type Item = &'a T;
+    fn next(&mut self) -> Option<Self::Item> { loop {} }
+}
+
+fn main(a: SliceIter<'_, Container>) {
+    a
+    .filter_map(|c| Some(c.elements.iter().filter_map(|v| Some(v))))
+    .map(|e| e);
+}
+            "#,
+            expect![[r#"
+                [
+                    InlayHint {
+                        range: 484..554,
+                        kind: ChainingHint,
+                        label: [
+                            "impl Iterator<Item = impl Iterator<Item = &&str>>",
+                        ],
+                        tooltip: Some(
+                            HoverRanged(
+                                FileId(
+                                    0,
+                                ),
+                                484..554,
+                            ),
+                        ),
+                    },
+                    InlayHint {
+                        range: 484..485,
+                        kind: ChainingHint,
+                        label: [
+                            "SliceIter<Container>",
+                        ],
+                        tooltip: Some(
+                            HoverRanged(
+                                FileId(
+                                    0,
+                                ),
+                                484..485,
+                            ),
+                        ),
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
     fn infer_call_method_return_associated_types_with_generic() {
         check_types(
             r#"