Skip to content

Commit c542b6c

Browse files
committed
Auto merge of #17529 - Veykril:fix-17065, r=Veykril
fix: Fix lifetime parameters moving parameter defaults Fixes #17075, #17515 We were incorrectly filling the default params due to our odd order of lifetime parameters vs type/const params. So this needs some special handling so that we don't shift the defaults around.
2 parents 1b283db + 90e0e2e commit c542b6c

File tree

5 files changed

+109
-68
lines changed

5 files changed

+109
-68
lines changed

crates/hir-ty/src/builder.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,14 @@ impl<D> TyBuilder<D> {
6363
}
6464

6565
fn build_internal(self) -> (D, Substitution) {
66-
assert_eq!(self.vec.len(), self.param_kinds.len(), "{:?}", &self.param_kinds);
66+
assert_eq!(
67+
self.vec.len(),
68+
self.param_kinds.len(),
69+
"{} args received, {} expected ({:?})",
70+
self.vec.len(),
71+
self.param_kinds.len(),
72+
&self.param_kinds
73+
);
6774
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
6875
self.assert_match_kind(a, e);
6976
}
@@ -297,7 +304,8 @@ impl TyBuilder<hir_def::AdtId> {
297304
) -> Self {
298305
// Note that we're building ADT, so we never have parent generic parameters.
299306
let defaults = db.generic_defaults(self.data.into());
300-
for default_ty in defaults.iter().skip(self.vec.len()) {
307+
308+
for default_ty in &defaults[self.vec.len()..] {
301309
// NOTE(skip_binders): we only check if the arg type is error type.
302310
if let Some(x) = default_ty.skip_binders().ty(Interner) {
303311
if x.is_unknown() {

crates/hir-ty/src/generics.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use hir_def::{
2020
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
2121
};
2222
use intern::Interned;
23+
use stdx::TupleExt;
2324

2425
use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution};
2526

@@ -57,7 +58,7 @@ impl Generics {
5758
self.iter_self().map(|(id, _)| id)
5859
}
5960

60-
fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
61+
pub(crate) fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
6162
self.iter_parent().map(|(id, _)| id)
6263
}
6364

@@ -67,6 +68,16 @@ impl Generics {
6768
self.params.iter_type_or_consts()
6869
}
6970

71+
pub(crate) fn iter_self_type_or_consts_id(
72+
&self,
73+
) -> impl DoubleEndedIterator<Item = GenericParamId> + '_ {
74+
self.params.iter_type_or_consts().map(from_toc_id(self)).map(TupleExt::head)
75+
}
76+
77+
pub(crate) fn iter_self_lt_id(&self) -> impl DoubleEndedIterator<Item = GenericParamId> + '_ {
78+
self.params.iter_lt().map(from_lt_id(self)).map(TupleExt::head)
79+
}
80+
7081
/// Iterate over the params followed by the parent params.
7182
pub(crate) fn iter(
7283
&self,

crates/hir-ty/src/lower.rs

Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -812,13 +812,13 @@ impl<'a> TyLoweringContext<'a> {
812812
infer_args: bool,
813813
explicit_self_ty: Option<Ty>,
814814
) -> Substitution {
815-
// Remember that the item's own generic args come before its parent's.
816-
let mut substs = Vec::new();
817-
let def = if let Some(d) = def {
818-
d
819-
} else {
820-
return Substitution::empty(Interner);
821-
};
815+
let Some(def) = def else { return Substitution::empty(Interner) };
816+
817+
// Order is
818+
// - Optional Self parameter
819+
// - Type or Const parameters
820+
// - Lifetime parameters
821+
// - Parent parameters
822822
let def_generics = generics(self.db.upcast(), def);
823823
let (
824824
parent_params,
@@ -832,45 +832,46 @@ impl<'a> TyLoweringContext<'a> {
832832
self_param as usize + type_params + const_params + impl_trait_params + lifetime_params;
833833
let total_len = parent_params + item_len;
834834

835-
let ty_error = TyKind::Error.intern(Interner).cast(Interner);
835+
let mut substs = Vec::new();
836836

837-
let mut def_generic_iter = def_generics.iter_id();
837+
// we need to iterate the lifetime and type/const params separately as our order of them
838+
// differs from the supplied syntax
838839

839-
let fill_self_params = || {
840+
let ty_error = || TyKind::Error.intern(Interner).cast(Interner);
841+
let mut def_toc_iter = def_generics.iter_self_type_or_consts_id();
842+
let mut def_lt_iter = def_generics.iter_self_lt_id();
843+
let fill_self_param = || {
840844
if self_param {
841-
let self_ty =
842-
explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(|| ty_error.clone());
845+
let self_ty = explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(ty_error);
843846

844-
if let Some(id) = def_generic_iter.next() {
845-
assert!(matches!(
846-
id,
847-
GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_)
848-
));
847+
if let Some(id) = def_toc_iter.next() {
848+
assert!(matches!(id, GenericParamId::TypeParamId(_)));
849849
substs.push(self_ty);
850850
}
851851
}
852852
};
853853
let mut had_explicit_args = false;
854854

855-
if let Some(generic_args) = &args_and_bindings {
856-
if !generic_args.has_self_type {
857-
fill_self_params();
855+
let mut lifetimes = SmallVec::<[_; 1]>::new();
856+
if let Some(&GenericArgs { ref args, has_self_type, .. }) = args_and_bindings {
857+
if !has_self_type {
858+
fill_self_param();
858859
}
859-
let expected_num = if generic_args.has_self_type {
860+
let expected_num = if has_self_type {
860861
self_param as usize + type_params + const_params
861862
} else {
862863
type_params + const_params
863864
};
864-
let skip = if generic_args.has_self_type && !self_param { 1 } else { 0 };
865-
// if args are provided, it should be all of them, but we can't rely on that
866-
for arg in generic_args
867-
.args
865+
let skip = if has_self_type && !self_param { 1 } else { 0 };
866+
// if non-lifetime args are provided, it should be all of them, but we can't rely on that
867+
for arg in args
868868
.iter()
869869
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
870870
.skip(skip)
871871
.take(expected_num)
872872
{
873-
if let Some(id) = def_generic_iter.next() {
873+
if let Some(id) = def_toc_iter.next() {
874+
had_explicit_args = true;
874875
let arg = generic_arg_to_chalk(
875876
self.db,
876877
id,
@@ -880,20 +881,16 @@ impl<'a> TyLoweringContext<'a> {
880881
|_, const_ref, ty| self.lower_const(const_ref, ty),
881882
|_, lifetime_ref| self.lower_lifetime(lifetime_ref),
882883
);
883-
had_explicit_args = true;
884884
substs.push(arg);
885885
}
886886
}
887887

888-
for arg in generic_args
889-
.args
888+
for arg in args
890889
.iter()
891890
.filter(|arg| matches!(arg, GenericArg::Lifetime(_)))
892891
.take(lifetime_params)
893892
{
894-
// Taking into the fact that def_generic_iter will always have lifetimes at the end
895-
// Should have some test cases tho to test this behaviour more properly
896-
if let Some(id) = def_generic_iter.next() {
893+
if let Some(id) = def_lt_iter.next() {
897894
let arg = generic_arg_to_chalk(
898895
self.db,
899896
id,
@@ -903,59 +900,61 @@ impl<'a> TyLoweringContext<'a> {
903900
|_, const_ref, ty| self.lower_const(const_ref, ty),
904901
|_, lifetime_ref| self.lower_lifetime(lifetime_ref),
905902
);
906-
had_explicit_args = true;
907-
substs.push(arg);
903+
lifetimes.push(arg);
908904
}
909905
}
910906
} else {
911-
fill_self_params();
907+
fill_self_param();
912908
}
913909

914-
// These params include those of parent.
915-
let remaining_params: SmallVec<[_; 2]> = def_generic_iter
916-
.map(|id| match id {
917-
GenericParamId::ConstParamId(x) => {
918-
unknown_const_as_generic(self.db.const_param_ty(x))
919-
}
920-
GenericParamId::TypeParamId(_) => ty_error.clone(),
921-
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
922-
})
923-
.collect();
924-
assert_eq!(remaining_params.len() + substs.len(), total_len);
925-
910+
let param_to_err = |id| match id {
911+
GenericParamId::ConstParamId(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
912+
GenericParamId::TypeParamId(_) => ty_error(),
913+
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
914+
};
926915
// handle defaults. In expression or pattern path segments without
927916
// explicitly specified type arguments, missing type arguments are inferred
928917
// (i.e. defaults aren't used).
929918
// Generic parameters for associated types are not supposed to have defaults, so we just
930919
// ignore them.
931-
let is_assoc_ty = if let GenericDefId::TypeAliasId(id) = def {
932-
let container = id.lookup(self.db.upcast()).container;
933-
matches!(container, ItemContainerId::TraitId(_))
934-
} else {
935-
false
920+
let is_assoc_ty = || match def {
921+
GenericDefId::TypeAliasId(id) => {
922+
matches!(id.lookup(self.db.upcast()).container, ItemContainerId::TraitId(_))
923+
}
924+
_ => false,
936925
};
937-
if !is_assoc_ty && (!infer_args || had_explicit_args) {
938-
let defaults = self.db.generic_defaults(def);
939-
assert_eq!(total_len, defaults.len());
926+
if (!infer_args || had_explicit_args) && !is_assoc_ty() {
927+
let defaults = &*self.db.generic_defaults(def);
928+
let (item, _parent) = defaults.split_at(item_len);
929+
let (toc, lt) = item.split_at(item_len - lifetime_params);
940930
let parent_from = item_len - substs.len();
941931

942-
for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
932+
let mut rem =
933+
def_generics.iter_id().skip(substs.len()).map(param_to_err).collect::<Vec<_>>();
934+
// Fill in defaults for type/const params
935+
for (idx, default_ty) in toc[substs.len()..].iter().enumerate() {
943936
// each default can depend on the previous parameters
944937
let substs_so_far = Substitution::from_iter(
945938
Interner,
946-
substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
939+
substs.iter().cloned().chain(rem[idx..].iter().cloned()),
947940
);
948941
substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
949942
}
950-
951-
// Keep parent's params as unknown.
952-
let mut remaining_params = remaining_params;
953-
substs.extend(remaining_params.drain(parent_from..));
943+
let n_lifetimes = lifetimes.len();
944+
substs.extend(lifetimes);
945+
// Fill in defaults for lifetime params
946+
for default_ty in &lt[n_lifetimes..] {
947+
// these are always errors so skipping is fine
948+
substs.push(default_ty.skip_binders().clone());
949+
}
950+
// Fill in remaining def params and parent params
951+
substs.extend(rem.drain(parent_from..));
954952
} else {
955-
substs.extend(remaining_params);
953+
// Fill in remaining def params and parent params
954+
substs.extend(def_generics.iter_id().skip(substs.len()).map(param_to_err));
956955
}
957956

958-
assert_eq!(substs.len(), total_len);
957+
assert_eq!(substs.len(), total_len, "expected {} substs, got {}", total_len, substs.len());
959958
Substitution::from_iter(Interner, substs)
960959
}
961960

crates/hir-ty/src/tests/regression.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,3 +2018,26 @@ fn tait_async_stack_overflow_17199() {
20182018
"#,
20192019
);
20202020
}
2021+
2022+
#[test]
2023+
fn lifetime_params_move_param_defaults() {
2024+
check_types(
2025+
r#"
2026+
pub struct Thing<'s, T = u32>;
2027+
2028+
impl <'s> Thing<'s> {
2029+
pub fn new() -> Thing<'s> {
2030+
Thing
2031+
//^^^^^ Thing<'?, u32>
2032+
}
2033+
}
2034+
2035+
fn main() {
2036+
let scope =
2037+
//^^^^^ &'? Thing<'?, u32>
2038+
&Thing::new();
2039+
//^^^^^^^^^^^^ Thing<'?, u32>
2040+
}
2041+
"#,
2042+
);
2043+
}

crates/hir/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3602,9 +3602,9 @@ impl ConstParam {
36023602
}
36033603

36043604
fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<GenericArg> {
3605-
let params = db.generic_defaults(id.parent);
36063605
let local_idx = hir_ty::param_idx(db, id)?;
3607-
let ty = params.get(local_idx)?.clone();
3606+
let defaults = db.generic_defaults(id.parent);
3607+
let ty = defaults.get(local_idx)?.clone();
36083608
let subst = TyBuilder::placeholder_subst(db, id.parent);
36093609
Some(ty.substitute(Interner, &subst))
36103610
}

0 commit comments

Comments
 (0)