Delete tuple unsizing
This commit is contained in:
parent
2af87eab3b
commit
44cccae02a
47 changed files with 55 additions and 879 deletions
|
@ -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
|
||||
|
|
|
@ -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::{
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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![],
|
||||
}
|
||||
})
|
||||
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
@ -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 \
|
||||
|
|
|
@ -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,
|
||||
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -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}"),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue