Auto merge of #100251 - compiler-errors:tuple-trait-2, r=jackh726

Implement `std::marker::Tuple`

Split out from #99943 (https://github.com/rust-lang/rust/pull/99943#pullrequestreview-1064459183).

Implements part of rust-lang/compiler-team#537
r? `@jackh726`
This commit is contained in:
bors 2022-09-12 03:24:29 +00:00
commit 3194958217
15 changed files with 181 additions and 11 deletions

View File

@ -289,6 +289,8 @@ language_item_table! {
Try, sym::Try, try_trait, Target::Trait, GenericRequirement::None;
Tuple, sym::tuple_trait, tuple_trait, Target::Trait, GenericRequirement::Exact(0);
SliceLen, sym::slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None;
// Language items from AST lowering

View File

@ -651,6 +651,10 @@ pub enum ImplSource<'tcx, N> {
/// ImplSource for a `const Drop` implementation.
ConstDestruct(ImplSourceConstDestructData<N>),
/// ImplSource for a `std::marker::Tuple` implementation.
/// This has no nested predicates ever, so no data.
Tuple,
}
impl<'tcx, N> ImplSource<'tcx, N> {
@ -665,7 +669,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
ImplSource::Object(d) => d.nested,
ImplSource::FnPointer(d) => d.nested,
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
| ImplSource::Pointee(ImplSourcePointeeData)
| ImplSource::Tuple => Vec::new(),
ImplSource::TraitAlias(d) => d.nested,
ImplSource::TraitUpcasting(d) => d.nested,
ImplSource::ConstDestruct(i) => i.nested,
@ -683,7 +688,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
ImplSource::Object(d) => &d.nested,
ImplSource::FnPointer(d) => &d.nested,
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
| ImplSource::Pointee(ImplSourcePointeeData)
| ImplSource::Tuple => &[],
ImplSource::TraitAlias(d) => &d.nested,
ImplSource::TraitUpcasting(d) => &d.nested,
ImplSource::ConstDestruct(i) => &i.nested,
@ -750,6 +756,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
nested: i.nested.into_iter().map(f).collect(),
})
}
ImplSource::Tuple => ImplSource::Tuple,
}
}
}

View File

@ -160,6 +160,9 @@ pub enum SelectionCandidate<'tcx> {
/// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
ConstDestructCandidate(Option<DefId>),
/// Witnesses the fact that a type is a tuple.
TupleCandidate,
}
/// The result of trait evaluation. The order is important

View File

@ -34,6 +34,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d),
super::ImplSource::Tuple => write!(f, "ImplSource::Tuple"),
}
}
}

View File

@ -1497,6 +1497,7 @@ symbols! {
tuple,
tuple_from_req,
tuple_indexing,
tuple_trait,
two_phase,
ty,
type_alias_enum_variants,

View File

@ -1751,7 +1751,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
super::ImplSource::AutoImpl(..)
| super::ImplSource::Builtin(..)
| super::ImplSource::TraitUpcasting(_)
| super::ImplSource::ConstDestruct(_) => {
| super::ImplSource::ConstDestruct(_)
| super::ImplSource::Tuple => {
// These traits have no associated types.
selcx.tcx().sess.delay_span_bug(
obligation.cause.span,
@ -1829,7 +1830,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
| super::ImplSource::Builtin(..)
| super::ImplSource::TraitUpcasting(_)
| super::ImplSource::TraitAlias(..)
| super::ImplSource::ConstDestruct(_) => {
| super::ImplSource::ConstDestruct(_)
| super::ImplSource::Tuple => {
// we don't create Select candidates with this kind of resolution
span_bug!(
obligation.cause.span,

View File

@ -309,6 +309,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// User-defined transmutability impls are permitted.
self.assemble_candidates_from_impls(obligation, &mut candidates);
self.assemble_candidates_for_transmutability(obligation, &mut candidates);
} else if lang_items.tuple_trait() == Some(def_id) {
self.assemble_candidate_for_tuple(obligation, &mut candidates);
} else {
if lang_items.clone_trait() == Some(def_id) {
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
@ -1009,4 +1011,46 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
}
fn assemble_candidate_for_tuple(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
let self_ty = self.infcx().shallow_resolve(obligation.self_ty().skip_binder());
match self_ty.kind() {
ty::Tuple(_) => {
candidates.vec.push(TupleCandidate);
}
ty::Infer(ty::TyVar(_)) => {
candidates.ambiguous = true;
}
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Adt(_, _)
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Slice(_)
| ty::RawPtr(_)
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(_)
| ty::Dynamic(_, _)
| ty::Closure(_, _)
| ty::Generator(_, _, _)
| ty::GeneratorWitness(_)
| ty::Never
| ty::Projection(_)
| ty::Opaque(_, _)
| ty::Param(_)
| ty::Bound(_, _)
| ty::Error(_)
| ty::Infer(_)
| ty::Placeholder(_) => {}
}
}
}

View File

@ -126,6 +126,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
ImplSource::ConstDestruct(data)
}
TupleCandidate => ImplSource::Tuple,
};
if !obligation.predicate.is_const_if_const() {

View File

@ -1609,7 +1609,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
// `DiscriminantKindCandidate`, and `ConstDestructCandidate` to anything else.
// `DiscriminantKindCandidate`, `ConstDestructCandidate`, and `TupleCandidate`
// to anything else.
//
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
@ -1629,7 +1630,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
BuiltinCandidate { has_nested: false }
| DiscriminantKindCandidate
| PointeeCandidate
| ConstDestructCandidate(_),
| ConstDestructCandidate(_)
| TupleCandidate,
_,
) => true,
(
@ -1637,7 +1639,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
BuiltinCandidate { has_nested: false }
| DiscriminantKindCandidate
| PointeeCandidate
| ConstDestructCandidate(_),
| ConstDestructCandidate(_)
| TupleCandidate,
) => false,
(ParamCandidate(other), ParamCandidate(victim)) => {

View File

@ -291,7 +291,8 @@ fn resolve_associated_item<'tcx>(
| traits::ImplSource::DiscriminantKind(..)
| traits::ImplSource::Pointee(..)
| traits::ImplSource::TraitUpcasting(_)
| traits::ImplSource::ConstDestruct(_) => None,
| traits::ImplSource::ConstDestruct(_)
| traits::ImplSource::Tuple => None,
})
}

View File

@ -800,6 +800,15 @@ impl<T: ?Sized> Unpin for *mut T {}
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
pub trait Destruct {}
/// A marker for tuple types.
///
/// The implementation of this trait is built-in and cannot be implemented
/// for any user type.
#[unstable(feature = "tuple_trait", issue = "none")]
#[cfg_attr(not(bootstrap), lang = "tuple_trait")]
#[rustc_on_unimplemented(message = "`{Self}` is not a tuple")]
pub trait Tuple {}
/// Implementations of `Copy` for primitive types.
///
/// Implementations that cannot be described in Rust

View File

@ -43,19 +43,19 @@ LL | t.2;
= note: see issue #38412 <https://github.com/rust-lang/rust/issues/38412> for more information
= help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable
error[E0616]: field `3` of struct `Tuple` is private
error[E0616]: field `3` of struct `pub_and_stability::Tuple` is private
--> $DIR/explore-issue-38412.rs:36:7
|
LL | t.3;
| ^ private field
error[E0616]: field `4` of struct `Tuple` is private
error[E0616]: field `4` of struct `pub_and_stability::Tuple` is private
--> $DIR/explore-issue-38412.rs:37:7
|
LL | t.4;
| ^ private field
error[E0616]: field `5` of struct `Tuple` is private
error[E0616]: field `5` of struct `pub_and_stability::Tuple` is private
--> $DIR/explore-issue-38412.rs:38:7
|
LL | t.5;

View File

@ -0,0 +1,19 @@
#![feature(tuple_trait)]
fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
struct TupleStruct(i32, i32);
fn from_param_env<T>() {
assert_is_tuple::<T>();
//~^ ERROR `T` is not a tuple
}
fn main() {
assert_is_tuple::<i32>();
//~^ ERROR `i32` is not a tuple
assert_is_tuple::<(i32)>();
//~^ ERROR `i32` is not a tuple
assert_is_tuple::<TupleStruct>();
//~^ ERROR `TupleStruct` is not a tuple
}

View File

@ -0,0 +1,55 @@
error[E0277]: `T` is not a tuple
--> $DIR/builtin-fail.rs:8:23
|
LL | assert_is_tuple::<T>();
| ^ the trait `Tuple` is not implemented for `T`
|
note: required by a bound in `assert_is_tuple`
--> $DIR/builtin-fail.rs:3:23
|
LL | fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
| ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple`
help: consider restricting type parameter `T`
|
LL | fn from_param_env<T: std::marker::Tuple>() {
| ++++++++++++++++++++
error[E0277]: `i32` is not a tuple
--> $DIR/builtin-fail.rs:13:23
|
LL | assert_is_tuple::<i32>();
| ^^^ the trait `Tuple` is not implemented for `i32`
|
note: required by a bound in `assert_is_tuple`
--> $DIR/builtin-fail.rs:3:23
|
LL | fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
| ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple`
error[E0277]: `i32` is not a tuple
--> $DIR/builtin-fail.rs:15:24
|
LL | assert_is_tuple::<(i32)>();
| ^^^ the trait `Tuple` is not implemented for `i32`
|
note: required by a bound in `assert_is_tuple`
--> $DIR/builtin-fail.rs:3:23
|
LL | fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
| ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple`
error[E0277]: `TupleStruct` is not a tuple
--> $DIR/builtin-fail.rs:17:23
|
LL | assert_is_tuple::<TupleStruct>();
| ^^^^^^^^^^^ the trait `Tuple` is not implemented for `TupleStruct`
|
note: required by a bound in `assert_is_tuple`
--> $DIR/builtin-fail.rs:3:23
|
LL | fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
| ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,20 @@
// check-pass
#![feature(tuple_trait)]
fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
struct Unsized([u8]);
fn from_param_env<T: std::marker::Tuple + ?Sized>() {
assert_is_tuple::<T>();
}
fn main() {
assert_is_tuple::<()>();
assert_is_tuple::<(i32,)>();
assert_is_tuple::<(Unsized,)>();
from_param_env::<()>();
from_param_env::<(i32,)>();
from_param_env::<(Unsized,)>();
}