Skip to content

Commit

Permalink
Auto merge of rust-lang#137728 - Darksonn:no-tuple-unsize, r=<try>
Browse files Browse the repository at this point in the history
Remove unsizing coercions for tuples

See rust-lang#42877 (comment) and below comments for justification.

Tracking issue: rust-lang#42877
Fixes: rust-lang#135217
  • Loading branch information
bors committed Feb 27, 2025
2 parents 96cfc75 + 8cab0ba commit 802c9b5
Show file tree
Hide file tree
Showing 47 changed files with 55 additions and 881 deletions.
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,8 +655,6 @@ declare_features! (
(internal, unsized_fn_params, "1.49.0", Some(48055)),
/// Allows unsized rvalues at arguments and parameters.
(incomplete, unsized_locals, "1.30.0", Some(48055)),
/// Allows unsized tuple coercion.
(unstable, unsized_tuple_coercion, "1.20.0", Some(42877)),
/// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
(unstable, used_with_arg, "1.60.0", Some(93798)),
/// Allows use of x86 `AMX` target-feature attributes and intrinsics
Expand Down
29 changes: 2 additions & 27 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,13 @@ use rustc_infer::traits::{
PredicateObligations,
};
use rustc_middle::span_bug;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
use rustc_session::parse::feature_err;
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span, sym};
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
Expand Down Expand Up @@ -610,8 +608,6 @@ 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;

// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
// inference might unify those two inner type variables later.
Expand Down Expand Up @@ -690,31 +686,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// be silent, as it causes a type mismatch later.
}

Ok(Some(impl_source)) => {
// Some builtin coercions are still unstable so we detect
// these here and emit a feature error if coercion doesn't fail
// due to another reason.
match impl_source {
traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
has_unsized_tuple_coercion = true;
}
_ => {}
}
queue.extend(impl_source.nested_obligations())
}
Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()),
}
}

if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion() {
feature_err(
&self.tcx.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)
}

Expand Down
49 changes: 0 additions & 49 deletions compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -787,13 +787,6 @@ where
)
}

// `(A, B, T)` -> `(A, B, U)` where `T: Unsize<U>`
(ty::Tuple(a_tys), ty::Tuple(b_tys))
if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
{
result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys))
}

_ => vec![],
}
})
Expand Down Expand Up @@ -1085,48 +1078,6 @@ where
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
}

/// We generate the following builtin impl for tuples of all sizes.
///
/// This impl is still unstable and we emit a feature error when it
/// when it is used by a coercion.
/// ```ignore (builtin impl example)
/// impl<T: ?Sized, U: ?Sized, V: ?Sized> Unsize<(T, V)> for (T, U)
/// where
/// U: Unsize<V>,
/// {}
/// ```
fn consider_builtin_tuple_unsize(
&mut self,
goal: Goal<I, (I::Ty, I::Ty)>,
a_tys: I::Tys,
b_tys: I::Tys,
) -> Result<Candidate<I>, NoSolution> {
let cx = self.cx();
let Goal { predicate: (_a_ty, b_ty), .. } = goal;

let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
let b_last_ty = b_tys.last().unwrap();

// Instantiate just the tail field of B., and require that they're equal.
let unsized_a_ty = Ty::new_tup_from_iter(cx, a_rest_tys.iter().copied().chain([b_last_ty]));
self.eq(goal.param_env, unsized_a_ty, b_ty)?;

// Similar to ADTs, require that we can unsize the tail.
self.add_goal(
GoalSource::ImplWhereBound,
goal.with(
cx,
ty::TraitRef::new(
cx,
cx.require_lang_item(TraitSolverLangItem::Unsize),
[a_last_ty, b_last_ty],
),
),
);
self.probe_builtin_trait_candidate(BuiltinImplSource::TupleUnsizing)
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
}

// Return `Some` if there is an impl (built-in or user provided) that may
// hold for the self type of the goal, which for coherence and soundness
// purposes must disqualify the built-in auto impl assembled by considering
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//! An "interner" is a data structure that associates values with usize tags and
//! allows bidirectional lookup; i.e., given a value, one can easily find the
//! An "interner" is a data structure that associates values with usize tags and allows bidirectional lookup; i.e., given a value, one can easily find the
//! type, and vice versa.
use std::hash::{Hash, Hasher};
Expand Down Expand Up @@ -2165,7 +2164,6 @@ symbols! {
unsized_const_params,
unsized_fn_params,
unsized_locals,
unsized_tuple_coercion,
unstable,
unstable_location_reason_default: "this crate is being loaded from the sysroot, an \
unstable location; did you mean to load this crate \
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1232,8 +1232,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// why we special case object types.
false
}
ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
| ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) => {
// These traits have no associated types.
selcx.tcx().dcx().span_delayed_bug(
obligation.cause.span,
Expand Down Expand Up @@ -1325,8 +1324,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
}
ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)
| ImplSource::Param(..)
| ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
| ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
| ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) => {
// we don't create Select candidates with this kind of resolution
span_bug!(
obligation.cause.span,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1017,13 +1017,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}

// `(.., T)` -> `(.., U)`
(&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
if tys_a.len() == tys_b.len() {
candidates.vec.push(BuiltinUnsizeCandidate);
}
}

_ => {}
};
}
Expand Down
29 changes: 0 additions & 29 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//! [rustc dev guide]:
//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
use std::iter;
use std::ops::ControlFlow;

use rustc_ast::Mutability;
Expand Down Expand Up @@ -1320,34 +1319,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, nested)
}

// `(.., T)` -> `(.., U)`
(&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
assert_eq!(tys_a.len(), tys_b.len());

// The last field of the tuple has to exist.
let (&a_last, a_mid) = tys_a.split_last().ok_or(Unimplemented)?;
let &b_last = tys_b.last().unwrap();

// Check that the source tuple with the target's
// last element is equal to the target.
let new_tuple =
Ty::new_tup_from_iter(tcx, a_mid.iter().copied().chain(iter::once(b_last)));
let InferOk { mut obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::Yes, target, new_tuple)
.map_err(|_| Unimplemented)?;

// Add a nested `T: Unsize<U>` predicate.
let last_unsize_obligation = obligation.with(
tcx,
ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]),
);
obligations.push(last_unsize_obligation);

ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, obligations)
}

_ => bug!("source: {source}, target: {target}"),
})
}
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_ty_utils/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,7 @@ fn resolve_associated_item<'tcx>(
}
}
traits::ImplSource::Param(..)
| traits::ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
| traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => None,
| traits::ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) => None,
})
}

Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_type_ir/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,6 @@ pub enum BuiltinImplSource {
///
/// The index is only used for winnowing.
TraitUpcasting(usize),
/// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
///
/// This can be removed when `feature(tuple_unsizing)` is stabilized, since we only
/// use it to detect when unsizing tuples in hir typeck.
TupleUnsizing,
}

#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
Expand Down
1 change: 0 additions & 1 deletion library/coretests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@
#![feature(try_find)]
#![feature(try_trait_v2)]
#![feature(unsize)]
#![feature(unsized_tuple_coercion)]
#![feature(unwrap_infallible)]
// tidy-alphabetical-end
#![allow(internal_features)]
Expand Down
10 changes: 1 addition & 9 deletions library/coretests/tests/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,31 +525,24 @@ fn ptr_metadata() {
assert_eq!(metadata("foo"), 3_usize);
assert_eq!(metadata(&[4, 7][..]), 2_usize);

let dst_tuple: &(bool, [u8]) = &(true, [0x66, 0x6F, 0x6F]);
let dst_struct: &Pair<bool, [u8]> = &Pair(true, [0x66, 0x6F, 0x6F]);
assert_eq!(metadata(dst_tuple), 3_usize);
assert_eq!(metadata(dst_struct), 3_usize);
unsafe {
let dst_tuple: &(bool, str) = std::mem::transmute(dst_tuple);
let dst_struct: &Pair<bool, str> = std::mem::transmute(dst_struct);
assert_eq!(&dst_tuple.1, "foo");
assert_eq!(&dst_struct.1, "foo");
assert_eq!(metadata(dst_tuple), 3_usize);
assert_eq!(metadata(dst_struct), 3_usize);
}

let vtable_1: DynMetadata<dyn Debug> = metadata(&4_u16 as &dyn Debug);
let vtable_2: DynMetadata<dyn Display> = metadata(&4_u16 as &dyn Display);
let vtable_3: DynMetadata<dyn Display> = metadata(&4_u32 as &dyn Display);
let vtable_4: DynMetadata<dyn Display> = metadata(&(true, 7_u32) as &(bool, dyn Display));
let vtable_5: DynMetadata<dyn Display> =
let vtable_4: DynMetadata<dyn Display> =
metadata(&Pair(true, 7_u32) as &Pair<bool, dyn Display>);
unsafe {
let address_1: *const () = std::mem::transmute(vtable_1);
let address_2: *const () = std::mem::transmute(vtable_2);
let address_3: *const () = std::mem::transmute(vtable_3);
let address_4: *const () = std::mem::transmute(vtable_4);
let address_5: *const () = std::mem::transmute(vtable_5);
// Different trait => different vtable pointer
assert_ne!(address_1, address_2);
// Different erased type => different vtable pointer
Expand All @@ -558,7 +551,6 @@ fn ptr_metadata() {
// This is *not guaranteed*, so we skip it in Miri.
if !cfg!(miri) {
assert_eq!(address_3, address_4);
assert_eq!(address_3, address_5);
}
}
}
Expand Down

This file was deleted.

15 changes: 0 additions & 15 deletions src/tools/miri/tests/pass/unsized.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
#![feature(unsized_tuple_coercion)]
#![feature(unsized_fn_params)]
#![feature(custom_mir, core_intrinsics)]

use std::mem;

fn unsized_tuple() {
let x: &(i32, i32, [i32]) = &(0, 1, [2, 3]);
let y: &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]);
let mut a = [y, x];
a.sort();
assert_eq!(a, [x, y]);

assert_eq!(&format!("{:?}", a), "[(0, 1, [2, 3]), (0, 1, [2, 3, 4])]");
assert_eq!(mem::size_of_val(x), 16);
}

fn unsized_params() {
pub fn f0(_f: dyn FnOnce()) {}
pub fn f1(_s: str) {}
Expand Down Expand Up @@ -56,7 +42,6 @@ fn unsized_field_projection() {
}

fn main() {
unsized_tuple();
unsized_params();
unsized_field_projection();
}
34 changes: 0 additions & 34 deletions src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12311,40 +12311,6 @@ fn main() {
```

will unnecessarily extend the stack frame.
"##,
default_severity: Severity::Allow,
warn_since: None,
deny_since: None,
},
Lint {
label: "unsized_tuple_coercion",
description: r##"# `unsized_tuple_coercion`

The tracking issue for this feature is: [#42877]

[#42877]: https://github.com/rust-lang/rust/issues/42877

------------------------

This is a part of [RFC0401]. According to the RFC, there should be an implementation like this:

```rust,ignore (partial-example)
impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized<U> {}
```

This implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this:

```rust
#![feature(unsized_tuple_coercion)]

fn main() {
let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]);
let y : &([i32; 3], [i32]) = &x;
assert_eq!(y.1[0], 4);
}
```

[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
"##,
default_severity: Severity::Allow,
warn_since: None,
Expand Down
Loading

0 comments on commit 802c9b5

Please sign in to comment.