Skip to content

Commit

Permalink
Auto merge of #100251 - compiler-errors:tuple-trait-2, r=jackh726
Browse files Browse the repository at this point in the history
Implement `std::marker::Tuple`

Split out from #99943 (#99943 (review)).

Implements part of rust-lang/compiler-team#537
r? `@jackh726`
  • Loading branch information
bors committed Sep 12, 2022
2 parents fa521a4 + 109cc1d commit 3194958
Show file tree
Hide file tree
Showing 15 changed files with 181 additions and 11 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -750,6 +756,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
nested: i.nested.into_iter().map(f).collect(),
})
}
ImplSource::Tuple => ImplSource::Tuple,
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,7 @@ symbols! {
tuple,
tuple_from_req,
tuple_indexing,
tuple_trait,
two_phase,
ty,
type_alias_enum_variants,
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(_) => {}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -1629,15 +1630,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
BuiltinCandidate { has_nested: false }
| DiscriminantKindCandidate
| PointeeCandidate
| ConstDestructCandidate(_),
| ConstDestructCandidate(_)
| TupleCandidate,
_,
) => true,
(
_,
BuiltinCandidate { has_nested: false }
| DiscriminantKindCandidate
| PointeeCandidate
| ConstDestructCandidate(_),
| ConstDestructCandidate(_)
| TupleCandidate,
) => false,

(ParamCandidate(other), ParamCandidate(victim)) => {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ty_utils/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
}

Expand Down
9 changes: 9 additions & 0 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/explore-issue-38412.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
19 changes: 19 additions & 0 deletions src/test/ui/tuple/builtin-fail.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 55 additions & 0 deletions src/test/ui/tuple/builtin-fail.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 20 additions & 0 deletions src/test/ui/tuple/builtin.rs
Original file line number Diff line number Diff line change
@@ -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,)>();
}

0 comments on commit 3194958

Please sign in to comment.