about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs24
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs12
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs25
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs4
7 files changed, 57 insertions, 19 deletions
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index f8efe4ad585..9a25669ed31 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -622,6 +622,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target])
         )];
 
+        let mut has_unsized_tuple_coercion = false;
         let mut has_trait_upcasting_coercion = None;
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
@@ -686,11 +687,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 }
 
                 Ok(Some(impl_source)) => {
-                    if matches!(impl_source, traits::ImplSource::TraitUpcasting(..)) {
-                        has_trait_upcasting_coercion =
-                            Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1)));
+                    match impl_source {
+                        traits::ImplSource::TraitUpcasting(..) => {
+                            has_trait_upcasting_coercion =
+                                Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1)));
+                        }
+                        traits::ImplSource::TupleUnsizing(_) => {
+                            has_unsized_tuple_coercion = true;
+                        }
+                        _ => {}
                     }
-
                     queue.extend(impl_source.nested_obligations())
                 }
             }
@@ -711,6 +717,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             err.emit();
         }
 
+        if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
+            feature_err(
+                &self.tcx.sess.parse_sess,
+                sym::unsized_tuple_coercion,
+                self.cause.span,
+                "unsized tuple coercion is not stable enough for use and is subject to change",
+            )
+            .emit();
+        }
+
         Ok(coercion)
     }
 
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index b7ffed57a0b..fb791d564a2 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -657,6 +657,9 @@ pub enum ImplSource<'tcx, N> {
     /// Successful resolution for a builtin trait.
     Builtin(Vec<N>),
 
+    // Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`
+    TupleUnsizing(Vec<N>),
+
     /// ImplSource for trait upcasting coercion
     TraitUpcasting(ImplSourceTraitUpcastingData<N>),
 }
@@ -665,7 +668,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
     pub fn nested_obligations(self) -> Vec<N> {
         match self {
             ImplSource::UserDefined(i) => i.nested,
-            ImplSource::Param(n, _) | ImplSource::Builtin(n) => n,
+            ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => n,
             ImplSource::Object(d) => d.nested,
             ImplSource::TraitUpcasting(d) => d.nested,
         }
@@ -674,7 +677,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
     pub fn borrow_nested_obligations(&self) -> &[N] {
         match self {
             ImplSource::UserDefined(i) => &i.nested,
-            ImplSource::Param(n, _) | ImplSource::Builtin(n) => &n,
+            ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => &n,
             ImplSource::Object(d) => &d.nested,
             ImplSource::TraitUpcasting(d) => &d.nested,
         }
@@ -683,7 +686,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
     pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
         match self {
             ImplSource::UserDefined(i) => &mut i.nested,
-            ImplSource::Param(n, _) | ImplSource::Builtin(n) => n,
+            ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => n,
             ImplSource::Object(d) => &mut d.nested,
             ImplSource::TraitUpcasting(d) => &mut d.nested,
         }
@@ -701,6 +704,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
             }),
             ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct),
             ImplSource::Builtin(n) => ImplSource::Builtin(n.into_iter().map(f).collect()),
+            ImplSource::TupleUnsizing(n) => {
+                ImplSource::TupleUnsizing(n.into_iter().map(f).collect())
+            }
             ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData {
                 vtable_base: o.vtable_base,
                 nested: o.nested.into_iter().map(f).collect(),
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index e2cd118500b..b7bce05300d 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -17,6 +17,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
                 write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
             }
 
+            super::ImplSource::TupleUnsizing(ref d) => write!(f, "{:?}", d),
+
             super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
         }
     }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index 1cedbb6b761..e2f91d7668d 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -456,6 +456,9 @@ fn rematch_unsize<'tcx>(
                 goal.param_env,
                 ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
             ));
+
+            // We need to be able to detect tuple unsizing to require its feature gate.
+            return Ok(Some(ImplSource::TupleUnsizing(nested)));
         }
         // FIXME: We *could* ICE here if either:
         // 1. the certainty is `Certainty::Yes`,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index a39fc1f1771..18470d520f7 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1925,7 +1925,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 // why we special case object types.
                 false
             }
-            | super::ImplSource::TraitUpcasting(_) => {
+            super::ImplSource::TraitUpcasting(_)
+            | super::ImplSource::TupleUnsizing(_) => {
                 // These traits have no associated types.
                 selcx.tcx().sess.delay_span_bug(
                     obligation.cause.span,
@@ -2005,7 +2006,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
         }
         super::ImplSource::Object(_)
         | super::ImplSource::Param(..)
-        | super::ImplSource::TraitUpcasting(_) => {
+        | super::ImplSource::TraitUpcasting(_)
+        | super::ImplSource::TupleUnsizing(_) => {
             // we don't create Select candidates with this kind of resolution
             span_bug!(
                 obligation.cause.span,
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 2cb2895b476..f423d40b994 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -114,8 +114,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             BuiltinUnsizeCandidate => {
-                let data = self.confirm_builtin_unsize_candidate(obligation)?;
-                ImplSource::Builtin(data)
+                let source =
+                    self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
+                let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
+                let target = self.infcx.shallow_resolve(target);
+                let data = self.confirm_builtin_unsize_candidate(obligation, source, target)?;
+                // If the source and target are both unsize goals, then we need to signify that
+                // this is tuple unsizing so that during unsized coercion we require the proper
+                // feature gate.
+                if matches!(source.kind(), ty::Tuple(..)) && matches!(target.kind(), ty::Tuple(..))
+                {
+                    ImplSource::TupleUnsizing(data)
+                } else {
+                    ImplSource::Builtin(data)
+                }
             }
 
             TraitUpcastingUnsizeCandidate(idx) => {
@@ -1000,15 +1012,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_builtin_unsize_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
+        source: Ty<'tcx>,
+        target: Ty<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
         let tcx = self.tcx();
-
-        // `assemble_candidates_for_unsizing` should ensure there are no late-bound
-        // regions here. See the comment there for more details.
-        let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
-        let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
-        let target = self.infcx.shallow_resolve(target);
-
         debug!(?source, ?target, "confirm_builtin_unsize_candidate");
 
         let mut nested = vec![];
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 16b1836ba9f..88eb33fee37 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -290,7 +290,9 @@ fn resolve_associated_item<'tcx>(
                 None
             }
         }
-        traits::ImplSource::Param(..) | traits::ImplSource::TraitUpcasting(_) => None,
+        traits::ImplSource::Param(..)
+        | traits::ImplSource::TraitUpcasting(_)
+        | traits::ImplSource::TupleUnsizing(_) => None,
     })
 }