Auto merge of #12054 - HKalbasi:const_generic, r=flodiebold

Fix const generic panic in dyn trait

fix #12048
This commit is contained in:
bors 2022-04-22 15:22:49 +00:00
commit ebe6e30f04
2 changed files with 71 additions and 36 deletions

View file

@ -681,7 +681,10 @@ impl<'a> TyLoweringContext<'a> {
let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner); let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
for eid in def_generics.iter_id().take(parent_params) { let mut def_generic_iter = def_generics.iter_id();
for _ in 0..parent_params {
if let Some(eid) = def_generic_iter.next() {
match eid { match eid {
Either::Left(_) => substs.push(ty_error.clone()), Either::Left(_) => substs.push(ty_error.clone()),
Either::Right(x) => { Either::Right(x) => {
@ -689,15 +692,20 @@ impl<'a> TyLoweringContext<'a> {
} }
} }
} }
}
let fill_self_params = || { let fill_self_params = || {
substs.extend( for x in explicit_self_ty
explicit_self_ty
.into_iter() .into_iter()
.map(|x| GenericArgData::Ty(x).intern(Interner)) .map(|x| GenericArgData::Ty(x).intern(Interner))
.chain(iter::repeat(ty_error.clone())) .chain(iter::repeat(ty_error.clone()))
.take(self_params), .take(self_params)
) {
if let Some(id) = def_generic_iter.next() {
assert!(id.is_left());
substs.push(x);
}
}
}; };
let mut had_explicit_args = false; let mut had_explicit_args = false;
@ -712,14 +720,14 @@ impl<'a> TyLoweringContext<'a> {
}; };
let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 }; let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 };
// if args are provided, it should be all of them, but we can't rely on that // if args are provided, it should be all of them, but we can't rely on that
for (arg, id) in generic_args for arg in generic_args
.args .args
.iter() .iter()
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_))) .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
.skip(skip) .skip(skip)
.take(expected_num) .take(expected_num)
.zip(def_generics.iter_id().skip(parent_params + skip))
{ {
if let Some(id) = def_generic_iter.next() {
if let Some(x) = generic_arg_to_chalk( if let Some(x) = generic_arg_to_chalk(
self.db, self.db,
id, id,
@ -740,6 +748,10 @@ impl<'a> TyLoweringContext<'a> {
) { ) {
had_explicit_args = true; had_explicit_args = true;
substs.push(x); substs.push(x);
} else {
// we just filtered them out
never!("Unexpected lifetime argument");
}
} }
} }
} else { } else {
@ -757,14 +769,16 @@ impl<'a> TyLoweringContext<'a> {
for default_ty in defaults.iter().skip(substs.len()) { for default_ty in defaults.iter().skip(substs.len()) {
// each default can depend on the previous parameters // each default can depend on the previous parameters
let substs_so_far = Substitution::from_iter(Interner, substs.clone()); let substs_so_far = Substitution::from_iter(Interner, substs.clone());
if let Some(_id) = def_generic_iter.next() {
substs.push(default_ty.clone().substitute(Interner, &substs_so_far)); substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
} }
} }
} }
}
// add placeholders for args that were not provided // add placeholders for args that were not provided
// FIXME: emit diagnostics in contexts where this is not allowed // FIXME: emit diagnostics in contexts where this is not allowed
for eid in def_generics.iter_id().skip(substs.len()) { for eid in def_generic_iter {
match eid { match eid {
Either::Left(_) => substs.push(ty_error.clone()), Either::Left(_) => substs.push(ty_error.clone()),
Either::Right(x) => { Either::Right(x) => {
@ -772,6 +786,7 @@ impl<'a> TyLoweringContext<'a> {
} }
} }
} }
// If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
assert_eq!(substs.len(), total_len); assert_eq!(substs.len(), total_len);
Substitution::from_iter(Interner, substs) Substitution::from_iter(Interner, substs)
@ -1659,6 +1674,10 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
} }
} }
/// Checks if the provided generic arg matches its expected kind, then lower them via
/// provided closures. Use unknown if there was kind mismatch.
///
/// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime.
pub(crate) fn generic_arg_to_chalk<'a, T>( pub(crate) fn generic_arg_to_chalk<'a, T>(
db: &dyn HirDatabase, db: &dyn HirDatabase,
kind_id: Either<TypeParamId, ConstParamId>, kind_id: Either<TypeParamId, ConstParamId>,

View file

@ -1470,6 +1470,22 @@ fn regression_11688_3() {
); );
} }
#[test]
fn regression_11688_4() {
check_types(
r#"
trait Bar<const C: usize> {
fn baz(&self) -> [i32; C];
}
fn foo(x: &dyn Bar<2>) {
x.baz();
//^^^^^^^ [i32; 2]
}
"#,
)
}
#[test] #[test]
fn gat_crash_1() { fn gat_crash_1() {
cov_mark::check!(ignore_gats); cov_mark::check!(ignore_gats);