Skip to content

Commit 162481d

Browse files
Merge #4023
4023: Fix another crash from wrong binders r=matklad a=flodiebold Basically, if we had something like `dyn Trait<T>` (where `T` is a type parameter) in an impl we lowered that to `dyn Trait<^0.0>`, when it should be `dyn Trait<^1.0>` because the `dyn` introduces a new binder. With one type parameter, that's just wrong, with two, it'll lead to crashes. Co-authored-by: Florian Diebold <[email protected]>
2 parents 746b2e0 + d3cb9ea commit 162481d

File tree

4 files changed

+92
-27
lines changed

4 files changed

+92
-27
lines changed

crates/ra_hir_ty/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,12 +396,12 @@ impl Substs {
396396
}
397397

398398
/// Return Substs that replace each parameter by a bound variable.
399-
pub(crate) fn bound_vars(generic_params: &Generics) -> Substs {
399+
pub(crate) fn bound_vars(generic_params: &Generics, debruijn: DebruijnIndex) -> Substs {
400400
Substs(
401401
generic_params
402402
.iter()
403403
.enumerate()
404-
.map(|(idx, _)| Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx)))
404+
.map(|(idx, _)| Ty::Bound(BoundVar::new(debruijn, idx)))
405405
.collect(),
406406
)
407407
}

crates/ra_hir_ty/src/lower.rs

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use crate::{
3939
pub struct TyLoweringContext<'a> {
4040
pub db: &'a dyn HirDatabase,
4141
pub resolver: &'a Resolver,
42+
in_binders: DebruijnIndex,
4243
/// Note: Conceptually, it's thinkable that we could be in a location where
4344
/// some type params should be represented as placeholders, and others
4445
/// should be converted to variables. I think in practice, this isn't
@@ -53,7 +54,27 @@ impl<'a> TyLoweringContext<'a> {
5354
let impl_trait_counter = std::cell::Cell::new(0);
5455
let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
5556
let type_param_mode = TypeParamLoweringMode::Placeholder;
56-
Self { db, resolver, impl_trait_mode, impl_trait_counter, type_param_mode }
57+
let in_binders = DebruijnIndex::INNERMOST;
58+
Self { db, resolver, in_binders, impl_trait_mode, impl_trait_counter, type_param_mode }
59+
}
60+
61+
pub fn with_shifted_in<T>(
62+
&self,
63+
debruijn: DebruijnIndex,
64+
f: impl FnOnce(&TyLoweringContext) -> T,
65+
) -> T {
66+
let new_ctx = Self {
67+
in_binders: self.in_binders.shifted_in_from(debruijn),
68+
impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()),
69+
..*self
70+
};
71+
let result = f(&new_ctx);
72+
self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
73+
result
74+
}
75+
76+
pub fn shifted_in(self, debruijn: DebruijnIndex) -> Self {
77+
Self { in_binders: self.in_binders.shifted_in_from(debruijn), ..self }
5778
}
5879

5980
pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
@@ -134,22 +155,26 @@ impl Ty {
134155
}
135156
TypeRef::DynTrait(bounds) => {
136157
let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
137-
let predicates = bounds
138-
.iter()
139-
.flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone()))
140-
.collect();
158+
let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| {
159+
bounds
160+
.iter()
161+
.flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone()))
162+
.collect()
163+
});
141164
Ty::Dyn(predicates)
142165
}
143166
TypeRef::ImplTrait(bounds) => {
144167
match ctx.impl_trait_mode {
145168
ImplTraitLoweringMode::Opaque => {
146169
let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
147-
let predicates = bounds
148-
.iter()
149-
.flat_map(|b| {
150-
GenericPredicate::from_type_bound(ctx, b, self_ty.clone())
151-
})
152-
.collect();
170+
let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| {
171+
bounds
172+
.iter()
173+
.flat_map(|b| {
174+
GenericPredicate::from_type_bound(ctx, b, self_ty.clone())
175+
})
176+
.collect()
177+
});
153178
Ty::Opaque(predicates)
154179
}
155180
ImplTraitLoweringMode::Param => {
@@ -180,7 +205,7 @@ impl Ty {
180205
(0, 0, 0, 0)
181206
};
182207
Ty::Bound(BoundVar::new(
183-
DebruijnIndex::INNERMOST,
208+
ctx.in_binders,
184209
idx as usize + parent_params + self_params + list_params,
185210
))
186211
}
@@ -293,7 +318,7 @@ impl Ty {
293318
TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id),
294319
TypeParamLoweringMode::Variable => {
295320
let idx = generics.param_idx(param_id).expect("matching generics");
296-
Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, idx))
321+
Ty::Bound(BoundVar::new(ctx.in_binders, idx))
297322
}
298323
}
299324
}
@@ -303,7 +328,9 @@ impl Ty {
303328
TypeParamLoweringMode::Placeholder => {
304329
Substs::type_params_for_generics(&generics)
305330
}
306-
TypeParamLoweringMode::Variable => Substs::bound_vars(&generics),
331+
TypeParamLoweringMode::Variable => {
332+
Substs::bound_vars(&generics, ctx.in_binders)
333+
}
307334
};
308335
ctx.db.impl_self_ty(impl_id).subst(&substs)
309336
}
@@ -313,7 +340,9 @@ impl Ty {
313340
TypeParamLoweringMode::Placeholder => {
314341
Substs::type_params_for_generics(&generics)
315342
}
316-
TypeParamLoweringMode::Variable => Substs::bound_vars(&generics),
343+
TypeParamLoweringMode::Variable => {
344+
Substs::bound_vars(&generics, ctx.in_binders)
345+
}
317346
};
318347
ctx.db.ty(adt.into()).subst(&substs)
319348
}
@@ -797,7 +826,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
797826
/// function body.
798827
fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
799828
let generics = generics(db.upcast(), def.into());
800-
let substs = Substs::bound_vars(&generics);
829+
let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
801830
Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs))
802831
}
803832

@@ -851,7 +880,7 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<T
851880
return type_for_adt(db, def.into());
852881
}
853882
let generics = generics(db.upcast(), def.into());
854-
let substs = Substs::bound_vars(&generics);
883+
let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
855884
Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs))
856885
}
857886

@@ -876,13 +905,13 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
876905
return type_for_adt(db, def.parent.into());
877906
}
878907
let generics = generics(db.upcast(), def.parent.into());
879-
let substs = Substs::bound_vars(&generics);
908+
let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
880909
Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs))
881910
}
882911

883912
fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
884913
let generics = generics(db.upcast(), adt.into());
885-
let substs = Substs::bound_vars(&generics);
914+
let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
886915
Binders::new(substs.len(), Ty::apply(TypeCtor::Adt(adt), substs))
887916
}
888917

@@ -892,7 +921,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
892921
let ctx =
893922
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
894923
let type_ref = &db.type_alias_data(t).type_ref;
895-
let substs = Substs::bound_vars(&generics);
924+
let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST);
896925
let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error));
897926
Binders::new(substs.len(), inner)
898927
}

crates/ra_hir_ty/src/tests/traits.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,42 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
12101210
);
12111211
}
12121212

1213+
#[test]
1214+
fn dyn_trait_in_impl() {
1215+
assert_snapshot!(
1216+
infer(r#"
1217+
trait Trait<T, U> {
1218+
fn foo(&self) -> (T, U);
1219+
}
1220+
struct S<T, U> {}
1221+
impl<T, U> S<T, U> {
1222+
fn bar(&self) -> &dyn Trait<T, U> { loop {} }
1223+
}
1224+
trait Trait2<T, U> {
1225+
fn baz(&self) -> (T, U);
1226+
}
1227+
impl<T, U> Trait2<T, U> for dyn Trait<T, U> { }
1228+
1229+
fn test(s: S<u32, i32>) {
1230+
s.bar().baz();
1231+
}
1232+
"#),
1233+
@r###"
1234+
[33; 37) 'self': &Self
1235+
[103; 107) 'self': &S<T, U>
1236+
[129; 140) '{ loop {} }': &dyn Trait<T, U>
1237+
[131; 138) 'loop {}': !
1238+
[136; 138) '{}': ()
1239+
[176; 180) 'self': &Self
1240+
[252; 253) 's': S<u32, i32>
1241+
[268; 290) '{ ...z(); }': ()
1242+
[274; 275) 's': S<u32, i32>
1243+
[274; 281) 's.bar()': &dyn Trait<u32, i32>
1244+
[274; 287) 's.bar().baz()': (u32, i32)
1245+
"###
1246+
);
1247+
}
1248+
12131249
#[test]
12141250
fn dyn_trait_bare() {
12151251
assert_snapshot!(

crates/ra_hir_ty/src/traits/chalk.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use ra_db::{
1717
use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
1818
use crate::{
1919
db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
20-
ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
20+
ApplicationTy, DebruijnIndex, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
2121
};
2222

2323
pub(super) mod tls;
@@ -815,7 +815,7 @@ pub(crate) fn associated_ty_data_query(
815815
// Lower bounds -- we could/should maybe move this to a separate query in `lower`
816816
let type_alias_data = db.type_alias_data(type_alias);
817817
let generic_params = generics(db.upcast(), type_alias.into());
818-
let bound_vars = Substs::bound_vars(&generic_params);
818+
let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
819819
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
820820
let ctx = crate::TyLoweringContext::new(db, &resolver)
821821
.with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
@@ -849,7 +849,7 @@ pub(crate) fn trait_datum_query(
849849
let trait_data = db.trait_data(trait_);
850850
debug!("trait {:?} = {:?}", trait_id, trait_data.name);
851851
let generic_params = generics(db.upcast(), trait_.into());
852-
let bound_vars = Substs::bound_vars(&generic_params);
852+
let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
853853
let flags = chalk_rust_ir::TraitFlags {
854854
auto: trait_data.auto,
855855
upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate,
@@ -888,7 +888,7 @@ pub(crate) fn struct_datum_query(
888888
.as_generic_def()
889889
.map(|generic_def| {
890890
let generic_params = generics(db.upcast(), generic_def);
891-
let bound_vars = Substs::bound_vars(&generic_params);
891+
let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
892892
convert_where_clauses(db, generic_def, &bound_vars)
893893
})
894894
.unwrap_or_else(Vec::new);
@@ -934,7 +934,7 @@ fn impl_def_datum(
934934
let impl_data = db.impl_data(impl_id);
935935

936936
let generic_params = generics(db.upcast(), impl_id.into());
937-
let bound_vars = Substs::bound_vars(&generic_params);
937+
let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
938938
let trait_ = trait_ref.trait_;
939939
let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate {
940940
chalk_rust_ir::ImplType::Local

0 commit comments

Comments
 (0)