]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / select / candidate_assembly.rs
index 752f6a8debc9ef5c064f0d937cfff2ecbf26811f..e18828fec3f6bf6aedaabb5ff8e5f605ae0ee007 100644 (file)
@@ -144,7 +144,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // Instead, we select the right impl now but report "`Bar` does
         // not implement `Clone`".
         if candidates.len() == 1 {
-            return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
+            return self.filter_impls(candidates.pop().unwrap(), stack.obligation);
         }
 
         // Winnow, but record the exact outcome of evaluation, which
@@ -217,7 +217,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         // Just one candidate left.
-        self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
+        self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
     }
 
     pub(super) fn assemble_candidates<'o>(
@@ -690,29 +690,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         debug!(?source, ?target, "assemble_candidates_for_unsizing");
 
-        let may_apply = match (source.kind(), target.kind()) {
+        match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
             (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
-                // Upcasts permit two things:
+                // Upcast coercions permit several things:
                 //
                 // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
                 // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
+                // 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
                 //
-                // Note that neither of these changes requires any
-                // change at runtime. Eventually this will be
-                // generalized.
+                // Note that neither of the first two of these changes requires any
+                // change at runtime. The third needs to change pointer metadata at runtime.
                 //
-                // We always upcast when we can because of reason
+                // We always perform upcasting coercions when we can because of reason
                 // #2 (region bounds).
-                data_a.principal_def_id() == data_b.principal_def_id()
-                    && data_b
-                        .auto_traits()
-                        // All of a's auto traits need to be in b's auto traits.
-                        .all(|b| data_a.auto_traits().any(|a| a == b))
+                let auto_traits_compatible = data_b
+                    .auto_traits()
+                    // All of a's auto traits need to be in b's auto traits.
+                    .all(|b| data_a.auto_traits().any(|a| a == b));
+                if auto_traits_compatible {
+                    let principal_def_id_a = data_a.principal_def_id();
+                    let principal_def_id_b = data_b.principal_def_id();
+                    if principal_def_id_a == principal_def_id_b {
+                        // no cyclic
+                        candidates.vec.push(BuiltinUnsizeCandidate);
+                    } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() {
+                        // not casual unsizing, now check whether this is trait upcasting coercion.
+                        let principal_a = data_a.principal().unwrap();
+                        let target_trait_did = principal_def_id_b.unwrap();
+                        let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
+                        for (idx, upcast_trait_ref) in
+                            util::supertraits(self.tcx(), source_trait_ref).enumerate()
+                        {
+                            if upcast_trait_ref.def_id() == target_trait_did {
+                                candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
+                            }
+                        }
+                    }
+                }
             }
 
             // `T` -> `Trait`
-            (_, &ty::Dynamic(..)) => true,
+            (_, &ty::Dynamic(..)) => {
+                candidates.vec.push(BuiltinUnsizeCandidate);
+            }
 
             // Ambiguous handling is below `T` -> `Trait`, because inference
             // variables can still implement `Unsize<Trait>` and nested
@@ -720,26 +741,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
                 debug!("assemble_candidates_for_unsizing: ambiguous");
                 candidates.ambiguous = true;
-                false
             }
 
             // `[T; n]` -> `[T]`
-            (&ty::Array(..), &ty::Slice(_)) => true,
+            (&ty::Array(..), &ty::Slice(_)) => {
+                candidates.vec.push(BuiltinUnsizeCandidate);
+            }
 
             // `Struct<T>` -> `Struct<U>`
             (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => {
-                def_id_a == def_id_b
+                if def_id_a == def_id_b {
+                    candidates.vec.push(BuiltinUnsizeCandidate);
+                }
             }
 
             // `(.., T)` -> `(.., U)`
-            (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(),
+            (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
+                if tys_a.len() == tys_b.len() {
+                    candidates.vec.push(BuiltinUnsizeCandidate);
+                }
+            }
 
-            _ => false,
+            _ => {}
         };
-
-        if may_apply {
-            candidates.vec.push(BuiltinUnsizeCandidate);
-        }
     }
 
     fn assemble_candidates_for_trait_alias(