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:
commit
3194958217
15 changed files with 181 additions and 11 deletions
|
@ -289,6 +289,8 @@ language_item_table! {
|
||||||
|
|
||||||
Try, sym::Try, try_trait, Target::Trait, GenericRequirement::None;
|
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;
|
SliceLen, sym::slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None;
|
||||||
|
|
||||||
// Language items from AST lowering
|
// Language items from AST lowering
|
||||||
|
|
|
@ -651,6 +651,10 @@ pub enum ImplSource<'tcx, N> {
|
||||||
|
|
||||||
/// ImplSource for a `const Drop` implementation.
|
/// ImplSource for a `const Drop` implementation.
|
||||||
ConstDestruct(ImplSourceConstDestructData<N>),
|
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> {
|
impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
|
@ -665,7 +669,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
ImplSource::Object(d) => d.nested,
|
ImplSource::Object(d) => d.nested,
|
||||||
ImplSource::FnPointer(d) => d.nested,
|
ImplSource::FnPointer(d) => d.nested,
|
||||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||||
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
|
| ImplSource::Pointee(ImplSourcePointeeData)
|
||||||
|
| ImplSource::Tuple => Vec::new(),
|
||||||
ImplSource::TraitAlias(d) => d.nested,
|
ImplSource::TraitAlias(d) => d.nested,
|
||||||
ImplSource::TraitUpcasting(d) => d.nested,
|
ImplSource::TraitUpcasting(d) => d.nested,
|
||||||
ImplSource::ConstDestruct(i) => i.nested,
|
ImplSource::ConstDestruct(i) => i.nested,
|
||||||
|
@ -683,7 +688,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
ImplSource::Object(d) => &d.nested,
|
ImplSource::Object(d) => &d.nested,
|
||||||
ImplSource::FnPointer(d) => &d.nested,
|
ImplSource::FnPointer(d) => &d.nested,
|
||||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||||
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
|
| ImplSource::Pointee(ImplSourcePointeeData)
|
||||||
|
| ImplSource::Tuple => &[],
|
||||||
ImplSource::TraitAlias(d) => &d.nested,
|
ImplSource::TraitAlias(d) => &d.nested,
|
||||||
ImplSource::TraitUpcasting(d) => &d.nested,
|
ImplSource::TraitUpcasting(d) => &d.nested,
|
||||||
ImplSource::ConstDestruct(i) => &i.nested,
|
ImplSource::ConstDestruct(i) => &i.nested,
|
||||||
|
@ -750,6 +756,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
nested: i.nested.into_iter().map(f).collect(),
|
nested: i.nested.into_iter().map(f).collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ImplSource::Tuple => ImplSource::Tuple,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,6 +160,9 @@ pub enum SelectionCandidate<'tcx> {
|
||||||
|
|
||||||
/// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
|
/// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
|
||||||
ConstDestructCandidate(Option<DefId>),
|
ConstDestructCandidate(Option<DefId>),
|
||||||
|
|
||||||
|
/// Witnesses the fact that a type is a tuple.
|
||||||
|
TupleCandidate,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of trait evaluation. The order is important
|
/// The result of trait evaluation. The order is important
|
||||||
|
|
|
@ -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::TraitUpcasting(ref d) => write!(f, "{:?}", d),
|
||||||
|
|
||||||
super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d),
|
super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d),
|
||||||
|
|
||||||
|
super::ImplSource::Tuple => write!(f, "ImplSource::Tuple"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1497,6 +1497,7 @@ symbols! {
|
||||||
tuple,
|
tuple,
|
||||||
tuple_from_req,
|
tuple_from_req,
|
||||||
tuple_indexing,
|
tuple_indexing,
|
||||||
|
tuple_trait,
|
||||||
two_phase,
|
two_phase,
|
||||||
ty,
|
ty,
|
||||||
type_alias_enum_variants,
|
type_alias_enum_variants,
|
||||||
|
|
|
@ -1751,7 +1751,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||||
super::ImplSource::AutoImpl(..)
|
super::ImplSource::AutoImpl(..)
|
||||||
| super::ImplSource::Builtin(..)
|
| super::ImplSource::Builtin(..)
|
||||||
| super::ImplSource::TraitUpcasting(_)
|
| super::ImplSource::TraitUpcasting(_)
|
||||||
| super::ImplSource::ConstDestruct(_) => {
|
| super::ImplSource::ConstDestruct(_)
|
||||||
|
| super::ImplSource::Tuple => {
|
||||||
// These traits have no associated types.
|
// These traits have no associated types.
|
||||||
selcx.tcx().sess.delay_span_bug(
|
selcx.tcx().sess.delay_span_bug(
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
|
@ -1829,7 +1830,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
||||||
| super::ImplSource::Builtin(..)
|
| super::ImplSource::Builtin(..)
|
||||||
| super::ImplSource::TraitUpcasting(_)
|
| super::ImplSource::TraitUpcasting(_)
|
||||||
| super::ImplSource::TraitAlias(..)
|
| super::ImplSource::TraitAlias(..)
|
||||||
| super::ImplSource::ConstDestruct(_) => {
|
| super::ImplSource::ConstDestruct(_)
|
||||||
|
| super::ImplSource::Tuple => {
|
||||||
// we don't create Select candidates with this kind of resolution
|
// we don't create Select candidates with this kind of resolution
|
||||||
span_bug!(
|
span_bug!(
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
|
|
|
@ -309,6 +309,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// User-defined transmutability impls are permitted.
|
// User-defined transmutability impls are permitted.
|
||||||
self.assemble_candidates_from_impls(obligation, &mut candidates);
|
self.assemble_candidates_from_impls(obligation, &mut candidates);
|
||||||
self.assemble_candidates_for_transmutability(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 {
|
} else {
|
||||||
if lang_items.clone_trait() == Some(def_id) {
|
if lang_items.clone_trait() == Some(def_id) {
|
||||||
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
|
// 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(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
|
let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
|
||||||
ImplSource::ConstDestruct(data)
|
ImplSource::ConstDestruct(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TupleCandidate => ImplSource::Tuple,
|
||||||
};
|
};
|
||||||
|
|
||||||
if !obligation.predicate.is_const_if_const() {
|
if !obligation.predicate.is_const_if_const() {
|
||||||
|
|
|
@ -1609,7 +1609,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
|
// (*) 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
|
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
||||||
// lifetime of a variable.
|
// lifetime of a variable.
|
||||||
|
@ -1629,7 +1630,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
BuiltinCandidate { has_nested: false }
|
BuiltinCandidate { has_nested: false }
|
||||||
| DiscriminantKindCandidate
|
| DiscriminantKindCandidate
|
||||||
| PointeeCandidate
|
| PointeeCandidate
|
||||||
| ConstDestructCandidate(_),
|
| ConstDestructCandidate(_)
|
||||||
|
| TupleCandidate,
|
||||||
_,
|
_,
|
||||||
) => true,
|
) => true,
|
||||||
(
|
(
|
||||||
|
@ -1637,7 +1639,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
BuiltinCandidate { has_nested: false }
|
BuiltinCandidate { has_nested: false }
|
||||||
| DiscriminantKindCandidate
|
| DiscriminantKindCandidate
|
||||||
| PointeeCandidate
|
| PointeeCandidate
|
||||||
| ConstDestructCandidate(_),
|
| ConstDestructCandidate(_)
|
||||||
|
| TupleCandidate,
|
||||||
) => false,
|
) => false,
|
||||||
|
|
||||||
(ParamCandidate(other), ParamCandidate(victim)) => {
|
(ParamCandidate(other), ParamCandidate(victim)) => {
|
||||||
|
|
|
@ -291,7 +291,8 @@ fn resolve_associated_item<'tcx>(
|
||||||
| traits::ImplSource::DiscriminantKind(..)
|
| traits::ImplSource::DiscriminantKind(..)
|
||||||
| traits::ImplSource::Pointee(..)
|
| traits::ImplSource::Pointee(..)
|
||||||
| traits::ImplSource::TraitUpcasting(_)
|
| traits::ImplSource::TraitUpcasting(_)
|
||||||
| traits::ImplSource::ConstDestruct(_) => None,
|
| traits::ImplSource::ConstDestruct(_)
|
||||||
|
| traits::ImplSource::Tuple => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -800,6 +800,15 @@ impl<T: ?Sized> Unpin for *mut T {}
|
||||||
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
|
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
|
||||||
pub trait Destruct {}
|
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 of `Copy` for primitive types.
|
||||||
///
|
///
|
||||||
/// Implementations that cannot be described in Rust
|
/// Implementations that cannot be described in Rust
|
||||||
|
|
|
@ -43,19 +43,19 @@ LL | t.2;
|
||||||
= note: see issue #38412 <https://github.com/rust-lang/rust/issues/38412> for more information
|
= 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
|
= 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
|
--> $DIR/explore-issue-38412.rs:36:7
|
||||||
|
|
|
|
||||||
LL | t.3;
|
LL | t.3;
|
||||||
| ^ private field
|
| ^ 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
|
--> $DIR/explore-issue-38412.rs:37:7
|
||||||
|
|
|
|
||||||
LL | t.4;
|
LL | t.4;
|
||||||
| ^ private field
|
| ^ 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
|
--> $DIR/explore-issue-38412.rs:38:7
|
||||||
|
|
|
|
||||||
LL | t.5;
|
LL | t.5;
|
||||||
|
|
19
src/test/ui/tuple/builtin-fail.rs
Normal file
19
src/test/ui/tuple/builtin-fail.rs
Normal 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
|
||||||
|
}
|
55
src/test/ui/tuple/builtin-fail.stderr
Normal file
55
src/test/ui/tuple/builtin-fail.stderr
Normal 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`.
|
20
src/test/ui/tuple/builtin.rs
Normal file
20
src/test/ui/tuple/builtin.rs
Normal 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,)>();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue