Skip to content

Commit 3194958

Browse files
committed
Auto merge of #100251 - compiler-errors:tuple-trait-2, r=jackh726
Implement `std::marker::Tuple` Split out from #99943 (#99943 (review)). Implements part of rust-lang/compiler-team#537 r? `@jackh726`
2 parents fa521a4 + 109cc1d commit 3194958

File tree

15 files changed

+181
-11
lines changed

15 files changed

+181
-11
lines changed

compiler/rustc_hir/src/lang_items.rs

+2
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ language_item_table! {
289289

290290
Try, sym::Try, try_trait, Target::Trait, GenericRequirement::None;
291291

292+
Tuple, sym::tuple_trait, tuple_trait, Target::Trait, GenericRequirement::Exact(0);
293+
292294
SliceLen, sym::slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None;
293295

294296
// Language items from AST lowering

compiler/rustc_middle/src/traits/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,10 @@ pub enum ImplSource<'tcx, N> {
651651

652652
/// ImplSource for a `const Drop` implementation.
653653
ConstDestruct(ImplSourceConstDestructData<N>),
654+
655+
/// ImplSource for a `std::marker::Tuple` implementation.
656+
/// This has no nested predicates ever, so no data.
657+
Tuple,
654658
}
655659

656660
impl<'tcx, N> ImplSource<'tcx, N> {
@@ -665,7 +669,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
665669
ImplSource::Object(d) => d.nested,
666670
ImplSource::FnPointer(d) => d.nested,
667671
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
668-
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
672+
| ImplSource::Pointee(ImplSourcePointeeData)
673+
| ImplSource::Tuple => Vec::new(),
669674
ImplSource::TraitAlias(d) => d.nested,
670675
ImplSource::TraitUpcasting(d) => d.nested,
671676
ImplSource::ConstDestruct(i) => i.nested,
@@ -683,7 +688,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
683688
ImplSource::Object(d) => &d.nested,
684689
ImplSource::FnPointer(d) => &d.nested,
685690
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
686-
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
691+
| ImplSource::Pointee(ImplSourcePointeeData)
692+
| ImplSource::Tuple => &[],
687693
ImplSource::TraitAlias(d) => &d.nested,
688694
ImplSource::TraitUpcasting(d) => &d.nested,
689695
ImplSource::ConstDestruct(i) => &i.nested,
@@ -750,6 +756,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
750756
nested: i.nested.into_iter().map(f).collect(),
751757
})
752758
}
759+
ImplSource::Tuple => ImplSource::Tuple,
753760
}
754761
}
755762
}

compiler/rustc_middle/src/traits/select.rs

+3
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ pub enum SelectionCandidate<'tcx> {
160160

161161
/// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
162162
ConstDestructCandidate(Option<DefId>),
163+
164+
/// Witnesses the fact that a type is a tuple.
165+
TupleCandidate,
163166
}
164167

165168
/// The result of trait evaluation. The order is important

compiler/rustc_middle/src/traits/structural_impls.rs

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
3434
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
3535

3636
super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d),
37+
38+
super::ImplSource::Tuple => write!(f, "ImplSource::Tuple"),
3739
}
3840
}
3941
}

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,7 @@ symbols! {
14971497
tuple,
14981498
tuple_from_req,
14991499
tuple_indexing,
1500+
tuple_trait,
15001501
two_phase,
15011502
ty,
15021503
type_alias_enum_variants,

compiler/rustc_trait_selection/src/traits/project.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1751,7 +1751,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
17511751
super::ImplSource::AutoImpl(..)
17521752
| super::ImplSource::Builtin(..)
17531753
| super::ImplSource::TraitUpcasting(_)
1754-
| super::ImplSource::ConstDestruct(_) => {
1754+
| super::ImplSource::ConstDestruct(_)
1755+
| super::ImplSource::Tuple => {
17551756
// These traits have no associated types.
17561757
selcx.tcx().sess.delay_span_bug(
17571758
obligation.cause.span,
@@ -1829,7 +1830,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
18291830
| super::ImplSource::Builtin(..)
18301831
| super::ImplSource::TraitUpcasting(_)
18311832
| super::ImplSource::TraitAlias(..)
1832-
| super::ImplSource::ConstDestruct(_) => {
1833+
| super::ImplSource::ConstDestruct(_)
1834+
| super::ImplSource::Tuple => {
18331835
// we don't create Select candidates with this kind of resolution
18341836
span_bug!(
18351837
obligation.cause.span,

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+44
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
309309
// User-defined transmutability impls are permitted.
310310
self.assemble_candidates_from_impls(obligation, &mut candidates);
311311
self.assemble_candidates_for_transmutability(obligation, &mut candidates);
312+
} else if lang_items.tuple_trait() == Some(def_id) {
313+
self.assemble_candidate_for_tuple(obligation, &mut candidates);
312314
} else {
313315
if lang_items.clone_trait() == Some(def_id) {
314316
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -1009,4 +1011,46 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10091011
}
10101012
}
10111013
}
1014+
1015+
fn assemble_candidate_for_tuple(
1016+
&mut self,
1017+
obligation: &TraitObligation<'tcx>,
1018+
candidates: &mut SelectionCandidateSet<'tcx>,
1019+
) {
1020+
let self_ty = self.infcx().shallow_resolve(obligation.self_ty().skip_binder());
1021+
match self_ty.kind() {
1022+
ty::Tuple(_) => {
1023+
candidates.vec.push(TupleCandidate);
1024+
}
1025+
ty::Infer(ty::TyVar(_)) => {
1026+
candidates.ambiguous = true;
1027+
}
1028+
ty::Bool
1029+
| ty::Char
1030+
| ty::Int(_)
1031+
| ty::Uint(_)
1032+
| ty::Float(_)
1033+
| ty::Adt(_, _)
1034+
| ty::Foreign(_)
1035+
| ty::Str
1036+
| ty::Array(_, _)
1037+
| ty::Slice(_)
1038+
| ty::RawPtr(_)
1039+
| ty::Ref(_, _, _)
1040+
| ty::FnDef(_, _)
1041+
| ty::FnPtr(_)
1042+
| ty::Dynamic(_, _)
1043+
| ty::Closure(_, _)
1044+
| ty::Generator(_, _, _)
1045+
| ty::GeneratorWitness(_)
1046+
| ty::Never
1047+
| ty::Projection(_)
1048+
| ty::Opaque(_, _)
1049+
| ty::Param(_)
1050+
| ty::Bound(_, _)
1051+
| ty::Error(_)
1052+
| ty::Infer(_)
1053+
| ty::Placeholder(_) => {}
1054+
}
1055+
}
10121056
}

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+2
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
126126
let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
127127
ImplSource::ConstDestruct(data)
128128
}
129+
130+
TupleCandidate => ImplSource::Tuple,
129131
};
130132

131133
if !obligation.predicate.is_const_if_const() {

compiler/rustc_trait_selection/src/traits/select/mod.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1609,7 +1609,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16091609
};
16101610

16111611
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
1612-
// `DiscriminantKindCandidate`, and `ConstDestructCandidate` to anything else.
1612+
// `DiscriminantKindCandidate`, `ConstDestructCandidate`, and `TupleCandidate`
1613+
// to anything else.
16131614
//
16141615
// This is a fix for #53123 and prevents winnowing from accidentally extending the
16151616
// lifetime of a variable.
@@ -1629,15 +1630,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16291630
BuiltinCandidate { has_nested: false }
16301631
| DiscriminantKindCandidate
16311632
| PointeeCandidate
1632-
| ConstDestructCandidate(_),
1633+
| ConstDestructCandidate(_)
1634+
| TupleCandidate,
16331635
_,
16341636
) => true,
16351637
(
16361638
_,
16371639
BuiltinCandidate { has_nested: false }
16381640
| DiscriminantKindCandidate
16391641
| PointeeCandidate
1640-
| ConstDestructCandidate(_),
1642+
| ConstDestructCandidate(_)
1643+
| TupleCandidate,
16411644
) => false,
16421645

16431646
(ParamCandidate(other), ParamCandidate(victim)) => {

compiler/rustc_ty_utils/src/instance.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ fn resolve_associated_item<'tcx>(
291291
| traits::ImplSource::DiscriminantKind(..)
292292
| traits::ImplSource::Pointee(..)
293293
| traits::ImplSource::TraitUpcasting(_)
294-
| traits::ImplSource::ConstDestruct(_) => None,
294+
| traits::ImplSource::ConstDestruct(_)
295+
| traits::ImplSource::Tuple => None,
295296
})
296297
}
297298

library/core/src/marker.rs

+9
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,15 @@ impl<T: ?Sized> Unpin for *mut T {}
800800
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
801801
pub trait Destruct {}
802802

803+
/// A marker for tuple types.
804+
///
805+
/// The implementation of this trait is built-in and cannot be implemented
806+
/// for any user type.
807+
#[unstable(feature = "tuple_trait", issue = "none")]
808+
#[cfg_attr(not(bootstrap), lang = "tuple_trait")]
809+
#[rustc_on_unimplemented(message = "`{Self}` is not a tuple")]
810+
pub trait Tuple {}
811+
803812
/// Implementations of `Copy` for primitive types.
804813
///
805814
/// Implementations that cannot be described in Rust

src/test/ui/explore-issue-38412.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,19 @@ LL | t.2;
4343
= note: see issue #38412 <https://github.com/rust-lang/rust/issues/38412> for more information
4444
= help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable
4545

46-
error[E0616]: field `3` of struct `Tuple` is private
46+
error[E0616]: field `3` of struct `pub_and_stability::Tuple` is private
4747
--> $DIR/explore-issue-38412.rs:36:7
4848
|
4949
LL | t.3;
5050
| ^ private field
5151

52-
error[E0616]: field `4` of struct `Tuple` is private
52+
error[E0616]: field `4` of struct `pub_and_stability::Tuple` is private
5353
--> $DIR/explore-issue-38412.rs:37:7
5454
|
5555
LL | t.4;
5656
| ^ private field
5757

58-
error[E0616]: field `5` of struct `Tuple` is private
58+
error[E0616]: field `5` of struct `pub_and_stability::Tuple` is private
5959
--> $DIR/explore-issue-38412.rs:38:7
6060
|
6161
LL | t.5;

src/test/ui/tuple/builtin-fail.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![feature(tuple_trait)]
2+
3+
fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
4+
5+
struct TupleStruct(i32, i32);
6+
7+
fn from_param_env<T>() {
8+
assert_is_tuple::<T>();
9+
//~^ ERROR `T` is not a tuple
10+
}
11+
12+
fn main() {
13+
assert_is_tuple::<i32>();
14+
//~^ ERROR `i32` is not a tuple
15+
assert_is_tuple::<(i32)>();
16+
//~^ ERROR `i32` is not a tuple
17+
assert_is_tuple::<TupleStruct>();
18+
//~^ ERROR `TupleStruct` is not a tuple
19+
}

src/test/ui/tuple/builtin-fail.stderr

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
error[E0277]: `T` is not a tuple
2+
--> $DIR/builtin-fail.rs:8:23
3+
|
4+
LL | assert_is_tuple::<T>();
5+
| ^ the trait `Tuple` is not implemented for `T`
6+
|
7+
note: required by a bound in `assert_is_tuple`
8+
--> $DIR/builtin-fail.rs:3:23
9+
|
10+
LL | fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
11+
| ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple`
12+
help: consider restricting type parameter `T`
13+
|
14+
LL | fn from_param_env<T: std::marker::Tuple>() {
15+
| ++++++++++++++++++++
16+
17+
error[E0277]: `i32` is not a tuple
18+
--> $DIR/builtin-fail.rs:13:23
19+
|
20+
LL | assert_is_tuple::<i32>();
21+
| ^^^ the trait `Tuple` is not implemented for `i32`
22+
|
23+
note: required by a bound in `assert_is_tuple`
24+
--> $DIR/builtin-fail.rs:3:23
25+
|
26+
LL | fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
27+
| ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple`
28+
29+
error[E0277]: `i32` is not a tuple
30+
--> $DIR/builtin-fail.rs:15:24
31+
|
32+
LL | assert_is_tuple::<(i32)>();
33+
| ^^^ the trait `Tuple` is not implemented for `i32`
34+
|
35+
note: required by a bound in `assert_is_tuple`
36+
--> $DIR/builtin-fail.rs:3:23
37+
|
38+
LL | fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
39+
| ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple`
40+
41+
error[E0277]: `TupleStruct` is not a tuple
42+
--> $DIR/builtin-fail.rs:17:23
43+
|
44+
LL | assert_is_tuple::<TupleStruct>();
45+
| ^^^^^^^^^^^ the trait `Tuple` is not implemented for `TupleStruct`
46+
|
47+
note: required by a bound in `assert_is_tuple`
48+
--> $DIR/builtin-fail.rs:3:23
49+
|
50+
LL | fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
51+
| ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple`
52+
53+
error: aborting due to 4 previous errors
54+
55+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/tuple/builtin.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// check-pass
2+
3+
#![feature(tuple_trait)]
4+
5+
fn assert_is_tuple<T: std::marker::Tuple + ?Sized>() {}
6+
7+
struct Unsized([u8]);
8+
9+
fn from_param_env<T: std::marker::Tuple + ?Sized>() {
10+
assert_is_tuple::<T>();
11+
}
12+
13+
fn main() {
14+
assert_is_tuple::<()>();
15+
assert_is_tuple::<(i32,)>();
16+
assert_is_tuple::<(Unsized,)>();
17+
from_param_env::<()>();
18+
from_param_env::<(i32,)>();
19+
from_param_env::<(Unsized,)>();
20+
}

0 commit comments

Comments
 (0)