diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index b385b1cafa..dd5639f00d 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -150,6 +150,14 @@ pub trait HirDatabase: DefDatabase + Upcast { id: chalk_db::AssociatedTyValueId, ) -> Arc; + #[salsa::invoke(crate::traits::normalize_projection_query)] + #[salsa::transparent] + fn normalize_projection( + &self, + projection: crate::ProjectionTy, + env: Arc, + ) -> Option; + #[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 a82a331d4b..de4a5446e5 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -196,20 +196,6 @@ pub(crate) fn make_binders>( make_binders_with_count(db, usize::MAX, generics, value) } -// FIXME: get rid of this -pub fn make_canonical>( - value: T, - kinds: impl IntoIterator, -) -> Canonical { - 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 77afeb3217..aaff894b34 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, +) -> Option { + 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 e4bb63a864..d49d2e1ca3 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; @@ -2880,28 +2879,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 d1b1d2c331..93fcd7cad7 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -1687,6 +1687,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); +impl S { + 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 { 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 { 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>", + ], + tooltip: Some( + HoverRanged( + FileId( + 0, + ), + 484..554, + ), + ), + }, + InlayHint { + range: 484..485, + kind: ChainingHint, + label: [ + "SliceIter", + ], + tooltip: Some( + HoverRanged( + FileId( + 0, + ), + 484..485, + ), + ), + }, + ] + "#]], + ); + } + #[test] fn infer_call_method_return_associated_types_with_generic() { check_types(