Skip to content

Commit 5bd98e3

Browse files
committed
Auto merge of rust-lang#13335 - lowr:patch/change-generic-param-order, r=Veykril
internal: change generic parameter order tl;dr: This PR changes the `Substitution` for trait items and methods like so: ```rust trait Trait<TP, const CP: usize> { // note the implicit Self as first parameter type Type<TC, const CC: usize>; fn f<TC, const CC: usize>() {} } impl<TP, const CP: usize> S { fn f<TC, const CC: usize>() {} } ``` - before this PR: `[Self, TP, CP, TC, CC]` for each trait item, `[TP, CP, TC, CC]` for `S::f` - after this PR: `[TC, CC, Self, TP, CP]` for each trait item, `[TC, CC, TP, CP]` for `S::f` --- This PR "inverts" the generic parameters/arguments of an item and its parent. This is to fulfill [chalk's expectation](https://github.com/rust-lang/chalk/blob/d875af0ff196dd6430b5f5fd87a640fa5ab59d1e/chalk-solve/src/rust_ir.rs#L498-L502) on the order of generic arguments in `Substitution`s for generic associated types and it's one step forward for GATs support (hopefully). Although chalk doesn't put any constraint for other items, it feels more natural to get everything aligned than special casing GATs. One complication is that `TyBuilder` now demands its users to pass in parent's `Substitution` upon construction unless it's obvious that the the item has no parent (e.g. an ADT never has parent). All users *should* already know the parent of the item in question, and without this, it cannot be easily reasoned about whether we're pushing the argument for the item or for its parent. Some additional notes: - f8f5a5e: This isn't related to the change, but I felt it's nicer. - 78977cd: There's one major change here other than the generic param order: Default arguments are now bound by the same `Binder` as the item in question rather than a `Binder` limited to parameters they can refer to (i.e. arguments that syntactically appear before them). Now that the order of generic parameters is changed, it would be somewhat complicated to make such `Binder`s as before, and the "full" `Binder`s shouldn't be a problem because we already make sure that the default arguments don't refer to the generic arguments after them with `fallback_bound_vars()`. - 7556f74: This is split from 4385d3d to make it easy to revert if it turns out that the GATs with const generics panic is actually not resolved with this PR. cc rust-lang#11878 rust-lang#11957
2 parents f087ebe + 7556f74 commit 5bd98e3

15 files changed

+444
-353
lines changed

crates/hir-ty/src/autoderef.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,14 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
123123
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
124124

125125
let projection = {
126-
let b = TyBuilder::assoc_type_projection(db, target);
126+
let b = TyBuilder::subst_for_def(db, deref_trait, None);
127127
if b.remaining() != 1 {
128128
// the Target type + Deref trait should only have one generic parameter,
129129
// namely Deref's Self type
130130
return None;
131131
}
132-
b.push(ty).build()
132+
let deref_subst = b.push(ty).build();
133+
TyBuilder::assoc_type_projection(db, target, Some(deref_subst)).build()
133134
};
134135

135136
// Check that the type implements Deref at all

crates/hir-ty/src/builder.rs

+119-102
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use chalk_ir::{
66
cast::{Cast, CastTo, Caster},
77
fold::TypeFoldable,
88
interner::HasInterner,
9-
AdtId, BoundVar, DebruijnIndex, Scalar,
9+
AdtId, DebruijnIndex, Scalar,
1010
};
1111
use hir_def::{
1212
builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
@@ -16,9 +16,9 @@ use smallvec::SmallVec;
1616

1717
use crate::{
1818
consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
19-
to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
20-
ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
21-
TyDefId, TyExt, TyKind, ValueTyDefId,
19+
to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig,
20+
GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
21+
ValueTyDefId,
2222
};
2323

2424
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -34,31 +34,51 @@ pub struct TyBuilder<D> {
3434
data: D,
3535
vec: SmallVec<[GenericArg; 2]>,
3636
param_kinds: SmallVec<[ParamKind; 2]>,
37+
parent_subst: Substitution,
3738
}
3839

3940
impl<A> TyBuilder<A> {
4041
fn with_data<B>(self, data: B) -> TyBuilder<B> {
41-
TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
42+
TyBuilder {
43+
data,
44+
vec: self.vec,
45+
param_kinds: self.param_kinds,
46+
parent_subst: self.parent_subst,
47+
}
4248
}
4349
}
4450

4551
impl<D> TyBuilder<D> {
46-
fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
47-
TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
52+
fn new(
53+
data: D,
54+
param_kinds: SmallVec<[ParamKind; 2]>,
55+
parent_subst: Option<Substitution>,
56+
) -> Self {
57+
let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner));
58+
Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
59+
}
60+
61+
fn new_empty(data: D) -> Self {
62+
TyBuilder::new(data, SmallVec::new(), None)
4863
}
4964

5065
fn build_internal(self) -> (D, Substitution) {
5166
assert_eq!(self.vec.len(), self.param_kinds.len());
5267
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
5368
self.assert_match_kind(a, e);
5469
}
55-
let subst = Substitution::from_iter(Interner, self.vec);
70+
let subst = Substitution::from_iter(
71+
Interner,
72+
self.vec.into_iter().chain(self.parent_subst.iter(Interner).cloned()),
73+
);
5674
(self.data, subst)
5775
}
5876

5977
pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
78+
assert!(self.remaining() > 0);
6079
let arg = arg.cast(Interner);
6180
let expected_kind = &self.param_kinds[self.vec.len()];
81+
6282
let arg_kind = match arg.data(Interner) {
6383
chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
6484
chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
@@ -68,7 +88,9 @@ impl<D> TyBuilder<D> {
6888
}
6989
};
7090
assert_eq!(*expected_kind, arg_kind);
91+
7192
self.vec.push(arg);
93+
7294
self
7395
}
7496

@@ -79,20 +101,12 @@ impl<D> TyBuilder<D> {
79101
pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
80102
// self.fill is inlined to make borrow checker happy
81103
let mut this = self;
82-
let other = this.param_kinds.iter().skip(this.vec.len());
104+
let other = &this.param_kinds[this.vec.len()..];
83105
let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
84-
ParamKind::Type => {
85-
GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
86-
.intern(Interner)
106+
ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
107+
ParamKind::Const(ty) => {
108+
BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
87109
}
88-
ParamKind::Const(ty) => GenericArgData::Const(
89-
ConstData {
90-
value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
91-
ty: ty.clone(),
92-
}
93-
.intern(Interner),
94-
)
95-
.intern(Interner),
96110
});
97111
this.vec.extend(filler.take(this.remaining()).casted(Interner));
98112
assert_eq!(this.remaining(), 0);
@@ -102,8 +116,8 @@ impl<D> TyBuilder<D> {
102116
pub fn fill_with_unknown(self) -> Self {
103117
// self.fill is inlined to make borrow checker happy
104118
let mut this = self;
105-
let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
106-
ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
119+
let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
120+
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
107121
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
108122
});
109123
this.vec.extend(filler.casted(Interner));
@@ -113,33 +127,17 @@ impl<D> TyBuilder<D> {
113127

114128
pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
115129
self.fill(|x| match x {
116-
ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
117-
ParamKind::Const(ty) => {
118-
GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
119-
}
130+
ParamKind::Type => table.new_type_var().cast(Interner),
131+
ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
120132
})
121133
}
122134

123135
pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
124-
self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
136+
self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
125137
assert_eq!(self.remaining(), 0);
126138
self
127139
}
128140

129-
pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
130-
assert!(self.vec.is_empty());
131-
assert!(parent_substs.len(Interner) <= self.param_kinds.len());
132-
self.extend(parent_substs.iter(Interner).cloned());
133-
self
134-
}
135-
136-
fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
137-
for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
138-
self.assert_match_kind(&x.0, &x.1);
139-
}
140-
self.vec.extend(it);
141-
}
142-
143141
fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
144142
match (a.data(Interner), e) {
145143
(chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
@@ -188,53 +186,44 @@ impl TyBuilder<()> {
188186
params.placeholder_subst(db)
189187
}
190188

191-
pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
192-
let def = def.into();
193-
let params = generics(db.upcast(), def);
194-
TyBuilder::new(
195-
(),
196-
params
197-
.iter()
198-
.map(|(id, data)| match data {
199-
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
200-
TypeOrConstParamData::ConstParamData(_) => {
201-
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
202-
}
203-
})
204-
.collect(),
205-
)
189+
pub fn subst_for_def(
190+
db: &dyn HirDatabase,
191+
def: impl Into<GenericDefId>,
192+
parent_subst: Option<Substitution>,
193+
) -> TyBuilder<()> {
194+
let generics = generics(db.upcast(), def.into());
195+
// FIXME: this assertion should hold but some adjustment around
196+
// `ValueTyDefId::EnumVariantId` is needed.
197+
// assert!(generics.parent_generics().is_some() == parent_subst.is_some());
198+
let params = generics
199+
.iter_self()
200+
.map(|(id, data)| match data {
201+
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
202+
TypeOrConstParamData::ConstParamData(_) => {
203+
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
204+
}
205+
})
206+
.collect();
207+
TyBuilder::new((), params, parent_subst)
206208
}
207209

208210
/// Creates a `TyBuilder` to build `Substitution` for a generator defined in `parent`.
209211
///
210212
/// A generator's substitution consists of:
211-
/// - generic parameters in scope on `parent`
212213
/// - resume type of generator
213214
/// - yield type of generator ([`Generator::Yield`](std::ops::Generator::Yield))
214215
/// - return type of generator ([`Generator::Return`](std::ops::Generator::Return))
216+
/// - generic parameters in scope on `parent`
215217
/// in this order.
216218
///
217219
/// This method prepopulates the builder with placeholder substitution of `parent`, so you
218220
/// should only push exactly 3 `GenericArg`s before building.
219221
pub fn subst_for_generator(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
220-
let parent_subst = match parent.as_generic_def_id() {
221-
Some(parent) => generics(db.upcast(), parent).placeholder_subst(db),
222-
// Static initializers *may* contain generators.
223-
None => Substitution::empty(Interner),
224-
};
225-
let builder = TyBuilder::new(
226-
(),
227-
parent_subst
228-
.iter(Interner)
229-
.map(|arg| match arg.constant(Interner) {
230-
Some(c) => ParamKind::Const(c.data(Interner).ty.clone()),
231-
None => ParamKind::Type,
232-
})
233-
// These represent resume type, yield type, and return type of generator.
234-
.chain(std::iter::repeat(ParamKind::Type).take(3))
235-
.collect(),
236-
);
237-
builder.use_parent_substs(&parent_subst)
222+
let parent_subst =
223+
parent.as_generic_def_id().map(|p| generics(db.upcast(), p).placeholder_subst(db));
224+
// These represent resume type, yield type, and return type of generator.
225+
let params = std::iter::repeat(ParamKind::Type).take(3).collect();
226+
TyBuilder::new((), params, parent_subst)
238227
}
239228

240229
pub fn build(self) -> Substitution {
@@ -245,24 +234,35 @@ impl TyBuilder<()> {
245234

246235
impl TyBuilder<hir_def::AdtId> {
247236
pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
248-
TyBuilder::subst_for_def(db, def).with_data(def)
237+
TyBuilder::subst_for_def(db, def, None).with_data(def)
249238
}
250239

251240
pub fn fill_with_defaults(
252241
mut self,
253242
db: &dyn HirDatabase,
254243
mut fallback: impl FnMut() -> Ty,
255244
) -> Self {
245+
// Note that we're building ADT, so we never have parent generic parameters.
256246
let defaults = db.generic_defaults(self.data.into());
247+
let dummy_ty = TyKind::Error.intern(Interner).cast(Interner);
257248
for default_ty in defaults.iter().skip(self.vec.len()) {
258-
if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
249+
// NOTE(skip_binders): we only check if the arg type is error type.
250+
if let Some(x) = default_ty.skip_binders().ty(Interner) {
259251
if x.is_unknown() {
260252
self.vec.push(fallback().cast(Interner));
261253
continue;
262254
}
263-
};
264-
// each default can depend on the previous parameters
265-
let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
255+
}
256+
// Each default can only depend on the previous parameters.
257+
// FIXME: we don't handle const generics here.
258+
let subst_so_far = Substitution::from_iter(
259+
Interner,
260+
self.vec
261+
.iter()
262+
.cloned()
263+
.chain(iter::repeat(dummy_ty.clone()))
264+
.take(self.param_kinds.len()),
265+
);
266266
self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
267267
}
268268
self
@@ -277,7 +277,7 @@ impl TyBuilder<hir_def::AdtId> {
277277
pub struct Tuple(usize);
278278
impl TyBuilder<Tuple> {
279279
pub fn tuple(size: usize) -> TyBuilder<Tuple> {
280-
TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
280+
TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect(), None)
281281
}
282282

283283
pub fn build(self) -> Ty {
@@ -288,7 +288,7 @@ impl TyBuilder<Tuple> {
288288

289289
impl TyBuilder<TraitId> {
290290
pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
291-
TyBuilder::subst_for_def(db, def).with_data(def)
291+
TyBuilder::subst_for_def(db, def, None).with_data(def)
292292
}
293293

294294
pub fn build(self) -> TraitRef {
@@ -298,8 +298,12 @@ impl TyBuilder<TraitId> {
298298
}
299299

300300
impl TyBuilder<TypeAliasId> {
301-
pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
302-
TyBuilder::subst_for_def(db, def).with_data(def)
301+
pub fn assoc_type_projection(
302+
db: &dyn HirDatabase,
303+
def: TypeAliasId,
304+
parent_subst: Option<Substitution>,
305+
) -> TyBuilder<TypeAliasId> {
306+
TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
303307
}
304308

305309
pub fn build(self) -> ProjectionTy {
@@ -309,35 +313,48 @@ impl TyBuilder<TypeAliasId> {
309313
}
310314

311315
impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
312-
fn subst_binders(b: Binders<T>) -> Self {
313-
let param_kinds = b
314-
.binders
315-
.iter(Interner)
316-
.map(|x| match x {
317-
chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
318-
chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
319-
chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
320-
})
321-
.collect();
322-
TyBuilder::new(b, param_kinds)
323-
}
324-
325316
pub fn build(self) -> T {
326317
let (b, subst) = self.build_internal();
327318
b.substitute(Interner, &subst)
328319
}
329320
}
330321

331322
impl TyBuilder<Binders<Ty>> {
332-
pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
333-
TyBuilder::subst_binders(db.ty(def))
323+
pub fn def_ty(
324+
db: &dyn HirDatabase,
325+
def: TyDefId,
326+
parent_subst: Option<Substitution>,
327+
) -> TyBuilder<Binders<Ty>> {
328+
let poly_ty = db.ty(def);
329+
let id: GenericDefId = match def {
330+
TyDefId::BuiltinType(_) => {
331+
assert!(parent_subst.is_none());
332+
return TyBuilder::new_empty(poly_ty);
333+
}
334+
TyDefId::AdtId(id) => id.into(),
335+
TyDefId::TypeAliasId(id) => id.into(),
336+
};
337+
TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
334338
}
335339

336340
pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
337-
TyBuilder::subst_binders(db.impl_self_ty(def))
341+
TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
338342
}
339343

340-
pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> {
341-
TyBuilder::subst_binders(db.value_ty(def))
344+
pub fn value_ty(
345+
db: &dyn HirDatabase,
346+
def: ValueTyDefId,
347+
parent_subst: Option<Substitution>,
348+
) -> TyBuilder<Binders<Ty>> {
349+
let poly_value_ty = db.value_ty(def);
350+
let id = match def.to_generic_def_id() {
351+
Some(id) => id,
352+
None => {
353+
// static items
354+
assert!(parent_subst.is_none());
355+
return TyBuilder::new_empty(poly_value_ty);
356+
}
357+
};
358+
TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_value_ty)
342359
}
343360
}

0 commit comments

Comments
 (0)