Skip to content

Commit 272a8dc

Browse files
committed
Fix crash on syn involving lifetimes returned by Chalk
If we get lifetime variables back in autoderef, just immediately replace them by static lifetimes for now. Method resolution doesn't really deal correctly with new variables being introduced (this needs to be fixed more properly). This fixes `rust-analyzer analysis-stats --with-deps` crashing in the RA repo.
1 parent 354151d commit 272a8dc

File tree

3 files changed

+77
-6
lines changed

3 files changed

+77
-6
lines changed

crates/hir_ty/src/autoderef.rs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
use std::iter::successors;
77

88
use base_db::CrateId;
9-
use chalk_ir::cast::Cast;
9+
use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
1010
use hir_def::lang_item::LangItemTarget;
1111
use hir_expand::name::name;
1212
use log::{info, warn};
1313

1414
use crate::{
15-
db::HirDatabase, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex,
16-
InEnvironment, Interner, ProjectionTyExt, Solution, Ty, TyBuilder, TyKind,
15+
db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
16+
DebruijnIndex, InEnvironment, Interner, ProjectionTyExt, Solution, Substitution, Ty, TyBuilder,
17+
TyKind,
1718
};
1819

1920
const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -103,7 +104,7 @@ fn deref_by_trait(
103104
binders: CanonicalVarKinds::from_iter(
104105
&Interner,
105106
ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new(
106-
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
107+
VariableKind::Ty(chalk_ir::TyVariableKind::General),
107108
chalk_ir::UniverseIndex::ROOT,
108109
))),
109110
),
@@ -136,19 +137,50 @@ fn deref_by_trait(
136137
return None;
137138
}
138139
}
139-
Some(Canonical {
140+
// FIXME: we remove lifetime variables here since they can confuse
141+
// the method resolution code later
142+
Some(fixup_lifetime_variables(Canonical {
140143
value: vars
141144
.value
142145
.subst
143146
.at(&Interner, vars.value.subst.len(&Interner) - 1)
144147
.assert_ty_ref(&Interner)
145148
.clone(),
146149
binders: vars.binders.clone(),
147-
})
150+
}))
148151
}
149152
Solution::Ambig(_) => {
150153
info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution);
151154
None
152155
}
153156
}
154157
}
158+
159+
fn fixup_lifetime_variables<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
160+
c: Canonical<T>,
161+
) -> Canonical<T> {
162+
// Removes lifetime variables from the Canonical, replacing them by static lifetimes.
163+
let mut i = 0;
164+
let subst = Substitution::from_iter(
165+
&Interner,
166+
c.binders.iter(&Interner).map(|vk| match vk.kind {
167+
VariableKind::Ty(_) => {
168+
let index = i;
169+
i += 1;
170+
BoundVar::new(DebruijnIndex::INNERMOST, index).to_ty(&Interner).cast(&Interner)
171+
}
172+
VariableKind::Lifetime => static_lifetime().cast(&Interner),
173+
VariableKind::Const(_) => unimplemented!(),
174+
}),
175+
);
176+
let binders = CanonicalVarKinds::from_iter(
177+
&Interner,
178+
c.binders.iter(&Interner).filter(|vk| match vk.kind {
179+
VariableKind::Ty(_) => true,
180+
VariableKind::Lifetime => false,
181+
VariableKind::Const(_) => true,
182+
}),
183+
);
184+
let value = subst.apply(c.value, &Interner);
185+
Canonical { binders, value }
186+
}

crates/hir_ty/src/method_resolution.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ fn iterate_trait_method_candidates(
609609
}
610610
}
611611
known_implemented = true;
612+
// FIXME: we shouldn't be ignoring the binders here
612613
if callback(&self_ty.value, *item) {
613614
return true;
614615
}

crates/hir_ty/src/tests/regression.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,3 +974,41 @@ fn param_overrides_fn() {
974974
"#,
975975
)
976976
}
977+
978+
#[test]
979+
fn lifetime_from_chalk_during_deref() {
980+
check_types(
981+
r#"
982+
#[lang = "deref"]
983+
pub trait Deref {
984+
type Target;
985+
}
986+
987+
struct Box<T: ?Sized> {}
988+
impl<T> Deref for Box<T> {
989+
type Target = T;
990+
991+
fn deref(&self) -> &Self::Target {
992+
loop {}
993+
}
994+
}
995+
996+
trait Iterator {
997+
type Item;
998+
}
999+
1000+
pub struct Iter<'a, T: 'a> {
1001+
inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
1002+
}
1003+
1004+
trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
1005+
fn clone_box(&self);
1006+
}
1007+
1008+
fn clone_iter<T>(s: Iter<T>) {
1009+
s.inner.clone_box();
1010+
//^^^^^^^^^^^^^^^^^^^ ()
1011+
}
1012+
"#,
1013+
)
1014+
}

0 commit comments

Comments
 (0)