about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-04-22 15:22:49 +0000
committerbors <bors@rust-lang.org>2022-04-22 15:22:49 +0000
commitebe6e30f0459ef3eedfb4fef9f02bd95db111d2d (patch)
tree308b79e67996543a4eb492eee863e231547dd5ac
parentb6b5214c666b64cf9125bebc39d6a8ad08262870 (diff)
parent785ae4dfa8816028cd75dc71ae7cc2ff4f7ff7b8 (diff)
downloadrust-ebe6e30f0459ef3eedfb4fef9f02bd95db111d2d.tar.gz
rust-ebe6e30f0459ef3eedfb4fef9f02bd95db111d2d.zip
Auto merge of #12054 - HKalbasi:const_generic, r=flodiebold
Fix const generic panic in dyn trait

fix #12048
-rw-r--r--crates/hir_ty/src/lower.rs91
-rw-r--r--crates/hir_ty/src/tests/regression.rs16
2 files changed, 71 insertions, 36 deletions
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 24eff4cc9a9..a3787728eac 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -681,23 +681,31 @@ impl<'a> TyLoweringContext<'a> {
 
         let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
 
-        for eid in def_generics.iter_id().take(parent_params) {
-            match eid {
-                Either::Left(_) => substs.push(ty_error.clone()),
-                Either::Right(x) => {
-                    substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
+        let mut def_generic_iter = def_generics.iter_id();
+
+        for _ in 0..parent_params {
+            if let Some(eid) = def_generic_iter.next() {
+                match eid {
+                    Either::Left(_) => substs.push(ty_error.clone()),
+                    Either::Right(x) => {
+                        substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
+                    }
                 }
             }
         }
 
         let fill_self_params = || {
-            substs.extend(
-                explicit_self_ty
-                    .into_iter()
-                    .map(|x| GenericArgData::Ty(x).intern(Interner))
-                    .chain(iter::repeat(ty_error.clone()))
-                    .take(self_params),
-            )
+            for x in explicit_self_ty
+                .into_iter()
+                .map(|x| GenericArgData::Ty(x).intern(Interner))
+                .chain(iter::repeat(ty_error.clone()))
+                .take(self_params)
+            {
+                if let Some(id) = def_generic_iter.next() {
+                    assert!(id.is_left());
+                    substs.push(x);
+                }
+            }
         };
         let mut had_explicit_args = false;
 
@@ -712,34 +720,38 @@ impl<'a> TyLoweringContext<'a> {
             };
             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
-            for (arg, id) in generic_args
+            for arg in generic_args
                 .args
                 .iter()
                 .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
                 .skip(skip)
                 .take(expected_num)
-                .zip(def_generics.iter_id().skip(parent_params + skip))
             {
-                if let Some(x) = generic_arg_to_chalk(
-                    self.db,
-                    id,
-                    arg,
-                    &mut (),
-                    |_, type_ref| self.lower_ty(type_ref),
-                    |_, c, ty| {
-                        const_or_path_to_chalk(
-                            self.db,
-                            &self.resolver,
-                            ty,
-                            c,
-                            self.type_param_mode,
-                            || self.generics(),
-                            self.in_binders,
-                        )
-                    },
-                ) {
-                    had_explicit_args = true;
-                    substs.push(x);
+                if let Some(id) = def_generic_iter.next() {
+                    if let Some(x) = generic_arg_to_chalk(
+                        self.db,
+                        id,
+                        arg,
+                        &mut (),
+                        |_, type_ref| self.lower_ty(type_ref),
+                        |_, c, ty| {
+                            const_or_path_to_chalk(
+                                self.db,
+                                &self.resolver,
+                                ty,
+                                c,
+                                self.type_param_mode,
+                                || self.generics(),
+                                self.in_binders,
+                            )
+                        },
+                    ) {
+                        had_explicit_args = true;
+                        substs.push(x);
+                    } else {
+                        // we just filtered them out
+                        never!("Unexpected lifetime argument");
+                    }
                 }
             }
         } else {
@@ -757,14 +769,16 @@ impl<'a> TyLoweringContext<'a> {
                 for default_ty in defaults.iter().skip(substs.len()) {
                     // each default can depend on the previous parameters
                     let substs_so_far = Substitution::from_iter(Interner, substs.clone());
-                    substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
+                    if let Some(_id) = def_generic_iter.next() {
+                        substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
+                    }
                 }
             }
         }
 
         // add placeholders for args that were not provided
         // 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 {
                 Either::Left(_) => substs.push(ty_error.clone()),
                 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);
 
         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>(
     db: &dyn HirDatabase,
     kind_id: Either<TypeParamId, ConstParamId>,
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index c3c934c4680..ef27667ffa5 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1471,6 +1471,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]
 fn gat_crash_1() {
     cov_mark::check!(ignore_gats);
     check_no_mismatches(