about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-01-19 01:23:23 -0800
committerMichael Goulet <michael@errs.io>2022-01-19 01:28:14 -0800
commit0eccd5feef7ff3dc9d903368ae39acb54179a424 (patch)
treee5dcd6ef1412d4285137827b3612a7f65d983bfb
parente3f01b2b6ff177359504e42a99665a8abc388cb7 (diff)
downloadrust-0eccd5feef7ff3dc9d903368ae39acb54179a424.tar.gz
rust-0eccd5feef7ff3dc9d903368ae39acb54179a424.zip
skip some layers in const drop confirmation
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs161
1 files changed, 91 insertions, 70 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 35aebd9900f..4c74627f3c6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -1103,90 +1103,111 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let tcx = self.tcx();
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
 
-        // Skip binder here (*)
-        let nested_tys = match *self_ty.skip_binder().kind() {
-            ty::Bool
-            | ty::Char
-            | ty::Int(_)
-            | ty::Uint(_)
-            | ty::Float(_)
-            | ty::Infer(ty::IntVar(_))
-            | ty::Infer(ty::FloatVar(_))
-            | ty::Str
-            | ty::RawPtr(_)
-            | ty::Ref(..)
-            | ty::FnDef(..)
-            | ty::FnPtr(_)
-            | ty::Never => vec![],
-
-            ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(tcx, substs)).collect(),
-
-            ty::Array(ty, _) | ty::Slice(ty) => vec![ty],
-
-            ty::Tuple(tys) => tys.iter().map(|ty| ty.expect_ty()).collect(),
-
-            ty::Closure(_, substs) => vec![substs.as_closure().tupled_upvars_ty()],
-
-            ty::Generator(_, substs, _) => {
-                vec![substs.as_generator().tupled_upvars_ty(), substs.as_generator().witness()]
-            }
-
-            ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys).to_vec(),
-
-            ty::Opaque(_, _)
-            | ty::Dynamic(_, _)
-            | ty::Error(_)
-            | ty::Bound(_, _)
-            | ty::Param(_)
-            | ty::Placeholder(_)
-            | ty::Foreign(_)
-            | ty::Projection(_)
-            | ty::Infer(_) => {
-                unreachable!();
-            }
-        };
-
-        info!(
-            "confirm_const_drop_candidate: self_ty={:?}, nested_tys={:?} impl_def_id={:?}",
-            self_ty, nested_tys, impl_def_id
-        );
-
-        let cause = obligation.derived_cause(BuiltinDerivedObligation);
         let mut nested = vec![];
+        let cause = obligation.derived_cause(BuiltinDerivedObligation);
 
-        // If we have a custom `impl const Drop`, then check it like a regular impl candidate.
+        // If we have a custom `impl const Drop`, then
+        // first check it like a regular impl candidate
         if let Some(impl_def_id) = impl_def_id {
             nested.extend(self.confirm_impl_candidate(obligation, impl_def_id).nested);
         }
 
-        for ty in nested_tys {
-            let predicate = self.infcx.commit_unconditionally(|_| {
-                normalize_with_depth_to(
-                    self,
-                    obligation.param_env,
-                    cause.clone(),
-                    obligation.recursion_depth + 1,
-                    // Rebinding here (*)
-                    self_ty
+        // We want to confirm the ADT's fields if we have an ADT
+        let mut stack = match *self_ty.skip_binder().kind() {
+            ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(tcx, substs)).collect(),
+            _ => vec![self_ty.skip_binder()],
+        };
+
+        while let Some(nested_ty) = stack.pop() {
+            match *nested_ty.kind() {
+                // We know these types are trivially drop
+                ty::Bool
+                | ty::Char
+                | ty::Int(_)
+                | ty::Uint(_)
+                | ty::Float(_)
+                | ty::Infer(ty::IntVar(_))
+                | ty::Infer(ty::FloatVar(_))
+                | ty::Str
+                | ty::RawPtr(_)
+                | ty::Ref(..)
+                | ty::FnDef(..)
+                | ty::FnPtr(_)
+                | ty::Never => {}
+
+                // These types are built-in, so we can fast-track by registering
+                // nested predicates for their constituient type(s)
+                ty::Array(ty, _) | ty::Slice(ty) => {
+                    stack.push(ty);
+                }
+                ty::Tuple(tys) => {
+                    stack.extend(tys.iter().map(|ty| ty.expect_ty()));
+                }
+                ty::Closure(_, substs) => {
+                    stack.push(substs.as_closure().tupled_upvars_ty());
+                }
+                ty::Generator(_, substs, _) => {
+                    let generator = substs.as_generator();
+                    stack.extend([generator.tupled_upvars_ty(), generator.witness()]);
+                }
+                ty::GeneratorWitness(tys) => {
+                    stack.extend(tcx.erase_late_bound_regions(tys).to_vec());
+                }
+
+                // If we have a projection type, make sure to normalize it so we replace it
+                // with a fresh infer variable
+                ty::Projection(..) => {
+                    self.infcx.commit_unconditionally(|_| {
+                        let predicate = normalize_with_depth_to(
+                            self,
+                            obligation.param_env,
+                            cause.clone(),
+                            obligation.recursion_depth + 1,
+                            self_ty
+                                .rebind(ty::TraitPredicate {
+                                    trait_ref: ty::TraitRef {
+                                        def_id: self.tcx().require_lang_item(LangItem::Drop, None),
+                                        substs: self.tcx().mk_substs_trait(nested_ty, &[]),
+                                    },
+                                    constness: ty::BoundConstness::ConstIfConst,
+                                    polarity: ty::ImplPolarity::Positive,
+                                })
+                                .to_predicate(tcx),
+                            &mut nested,
+                        );
+
+                        nested.push(Obligation::with_depth(
+                            cause.clone(),
+                            obligation.recursion_depth + 1,
+                            obligation.param_env,
+                            predicate,
+                        ));
+                    });
+                }
+
+                // If we have any other type (e.g. an ADT), just register a nested obligation
+                // since it's either not `const Drop` (and we raise an error during selection),
+                // or it's an ADT (and we need to check for a custom impl during selection)
+                _ => {
+                    let predicate = self_ty
                         .rebind(ty::TraitPredicate {
                             trait_ref: ty::TraitRef {
                                 def_id: self.tcx().require_lang_item(LangItem::Drop, None),
-                                substs: self.tcx().mk_substs_trait(ty, &[]),
+                                substs: self.tcx().mk_substs_trait(nested_ty, &[]),
                             },
                             constness: ty::BoundConstness::ConstIfConst,
                             polarity: ty::ImplPolarity::Positive,
                         })
-                        .to_predicate(tcx),
-                    &mut nested,
-                )
-            });
+                        .to_predicate(tcx);
 
-            nested.push(Obligation::with_depth(
-                cause.clone(),
-                obligation.recursion_depth + 1,
-                obligation.param_env,
-                predicate,
-            ));
+                    nested.push(Obligation::with_depth(
+                        cause.clone(),
+                        obligation.recursion_depth + 1,
+                        obligation.param_env,
+                        predicate,
+                    ));
+                }
+            }
         }
 
         Ok(ImplSourceConstDropData { nested })