Skip to content

Commit b1a4ba3

Browse files
committed
Auto merge of #13223 - lowr:fix/hir-proj-normalization, r=flodiebold
fix: handle lifetime variables in projection normalization Fixes #12674 The problem is that we've been skipping the binders of normalized projections assuming they should be empty, but the assumption is unfortunately wrong. We may get back lifetime variables and should handle them before returning them as normalized projections. For those who are curious why we get those even though we treat all lifetimes as 'static, [this comment in chalk](https://github.com/rust-lang/chalk/blob/d875af0ff196dd6430b5f5fd87a640fa5ab59d1e/chalk-solve/src/infer/unify.rs#L888-L908) may be interesting. I thought using `InferenceTable` would be cleaner than the other ways as it already has the methods for canonicalization, normalizing projection, and resolving variables, so moved goal building and trait solving logic to a new `HirDatabase` query. I made it transparent query as the query itself doesn't do much work but the eventual call to `HirDatabase::trait_solve_query()` does.
2 parents b54d22d + efb5616 commit b1a4ba3

File tree

5 files changed

+94
-42
lines changed

5 files changed

+94
-42
lines changed

crates/hir-ty/src/db.rs

+8
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
150150
id: chalk_db::AssociatedTyValueId,
151151
) -> Arc<chalk_db::AssociatedTyValue>;
152152

153+
#[salsa::invoke(crate::traits::normalize_projection_query)]
154+
#[salsa::transparent]
155+
fn normalize_projection(
156+
&self,
157+
projection: crate::ProjectionTy,
158+
env: Arc<crate::TraitEnvironment>,
159+
) -> Option<crate::Ty>;
160+
153161
#[salsa::invoke(trait_solve_wait)]
154162
#[salsa::transparent]
155163
fn trait_solve(

crates/hir-ty/src/lib.rs

-14
Original file line numberDiff line numberDiff line change
@@ -196,20 +196,6 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
196196
make_binders_with_count(db, usize::MAX, generics, value)
197197
}
198198

199-
// FIXME: get rid of this
200-
pub fn make_canonical<T: HasInterner<Interner = Interner>>(
201-
value: T,
202-
kinds: impl IntoIterator<Item = TyVariableKind>,
203-
) -> Canonical<T> {
204-
let kinds = kinds.into_iter().map(|tk| {
205-
chalk_ir::CanonicalVarKind::new(
206-
chalk_ir::VariableKind::Ty(tk),
207-
chalk_ir::UniverseIndex::ROOT,
208-
)
209-
});
210-
Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
211-
}
212-
213199
// FIXME: get rid of this, just replace it by FnPointer
214200
/// A function signature as seen by type inference: Several parameter types and
215201
/// one return type.

crates/hir-ty/src/traits.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Trait solving using Chalk.
22
3-
use std::env::var;
3+
use std::{env::var, sync::Arc};
44

55
use chalk_ir::GoalData;
66
use chalk_recursive::Cache;
@@ -12,8 +12,9 @@ use stdx::panic_context;
1212
use syntax::SmolStr;
1313

1414
use crate::{
15-
db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
16-
Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
15+
db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
16+
Guidance, InEnvironment, Interner, ProjectionTy, Solution, TraitRefExt, Ty, TyKind,
17+
WhereClause,
1718
};
1819

1920
/// This controls how much 'time' we give the Chalk solver before giving up.
@@ -64,6 +65,16 @@ impl TraitEnvironment {
6465
}
6566
}
6667

68+
pub(crate) fn normalize_projection_query(
69+
db: &dyn HirDatabase,
70+
projection: ProjectionTy,
71+
env: Arc<TraitEnvironment>,
72+
) -> Option<Ty> {
73+
let mut table = InferenceTable::new(db, env.clone());
74+
let ty = table.normalize_projection_ty(projection);
75+
Some(table.resolve_completely(ty))
76+
}
77+
6778
/// Solve a trait goal using Chalk.
6879
pub(crate) fn trait_solve_query(
6980
db: &dyn HirDatabase,

crates/hir/src/lib.rs

+4-25
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,9 @@ use hir_ty::{
6363
primitive::UintTy,
6464
subst_prefix,
6565
traits::FnTrait,
66-
AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
67-
ClosureId, DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind,
68-
QuantifiedWhereClause, Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty,
69-
TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause,
66+
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
67+
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
68+
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause,
7069
};
7170
use itertools::Itertools;
7271
use nameres::diagnostics::DefDiagnosticKind;
@@ -2892,28 +2891,8 @@ impl Type {
28922891
}
28932892
})
28942893
.build();
2895-
let goal = hir_ty::make_canonical(
2896-
InEnvironment::new(
2897-
&self.env.env,
2898-
AliasEq {
2899-
alias: AliasTy::Projection(projection),
2900-
ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
2901-
.intern(Interner),
2902-
}
2903-
.cast(Interner),
2904-
),
2905-
[TyVariableKind::General].into_iter(),
2906-
);
29072894

2908-
match db.trait_solve(self.env.krate, goal)? {
2909-
Solution::Unique(s) => s
2910-
.value
2911-
.subst
2912-
.as_slice(Interner)
2913-
.first()
2914-
.map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())),
2915-
Solution::Ambig(_) => None,
2916-
}
2895+
db.normalize_projection(projection, self.env.clone()).map(|ty| self.derived(ty))
29172896
}
29182897

29192898
pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {

crates/ide/src/inlay_hints.rs

+68
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,74 @@ fn main() {
16871687
);
16881688
}
16891689

1690+
#[test]
1691+
fn iterator_hint_regression_issue_12674() {
1692+
// Ensure we don't crash while solving the projection type of iterators.
1693+
check_expect(
1694+
InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
1695+
r#"
1696+
//- minicore: iterators
1697+
struct S<T>(T);
1698+
impl<T> S<T> {
1699+
fn iter(&self) -> Iter<'_, T> { loop {} }
1700+
}
1701+
struct Iter<'a, T: 'a>(&'a T);
1702+
impl<'a, T> Iterator for Iter<'a, T> {
1703+
type Item = &'a T;
1704+
fn next(&mut self) -> Option<Self::Item> { loop {} }
1705+
}
1706+
struct Container<'a> {
1707+
elements: S<&'a str>,
1708+
}
1709+
struct SliceIter<'a, T>(&'a T);
1710+
impl<'a, T> Iterator for SliceIter<'a, T> {
1711+
type Item = &'a T;
1712+
fn next(&mut self) -> Option<Self::Item> { loop {} }
1713+
}
1714+
1715+
fn main(a: SliceIter<'_, Container>) {
1716+
a
1717+
.filter_map(|c| Some(c.elements.iter().filter_map(|v| Some(v))))
1718+
.map(|e| e);
1719+
}
1720+
"#,
1721+
expect![[r#"
1722+
[
1723+
InlayHint {
1724+
range: 484..554,
1725+
kind: ChainingHint,
1726+
label: [
1727+
"impl Iterator<Item = impl Iterator<Item = &&str>>",
1728+
],
1729+
tooltip: Some(
1730+
HoverRanged(
1731+
FileId(
1732+
0,
1733+
),
1734+
484..554,
1735+
),
1736+
),
1737+
},
1738+
InlayHint {
1739+
range: 484..485,
1740+
kind: ChainingHint,
1741+
label: [
1742+
"SliceIter<Container>",
1743+
],
1744+
tooltip: Some(
1745+
HoverRanged(
1746+
FileId(
1747+
0,
1748+
),
1749+
484..485,
1750+
),
1751+
),
1752+
},
1753+
]
1754+
"#]],
1755+
);
1756+
}
1757+
16901758
#[test]
16911759
fn infer_call_method_return_associated_types_with_generic() {
16921760
check_types(

0 commit comments

Comments
 (0)