From c02d1a65534244532aba0f42a6719d87084865d2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 16 Jul 2023 22:42:46 +0000 Subject: [PATCH] Restore tuple unsizing feature gate --- compiler/rustc_hir_typeck/src/coercion.rs | 24 +++++++++++++++--- compiler/rustc_middle/src/traits/mod.rs | 12 ++++++--- .../src/traits/structural_impls.rs | 2 ++ .../src/solve/eval_ctxt/select.rs | 3 +++ .../src/traits/project.rs | 6 +++-- .../src/traits/select/confirmation.rs | 25 ++++++++++++------- compiler/rustc_ty_utils/src/instance.rs | 4 ++- 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), + // Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y` + TupleUnsizing(Vec), + /// ImplSource for trait upcasting coercion TraitUpcasting(ImplSourceTraitUpcastingData), } @@ -665,7 +668,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { pub fn nested_obligations(self) -> Vec { 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>, 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, }) }