Skip to content

Commit a570f6b

Browse files
committed
add tests for #[derive(GenericTypeVisitable)] and bounds
1 parent 6413782 commit a570f6b

3 files changed

Lines changed: 156 additions & 0 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ edition: 2024
2+
//@ check-fail
3+
4+
#![crate_type = "rlib"]
5+
#![feature(rustc_private)]
6+
7+
extern crate rustc_type_ir;
8+
extern crate rustc_type_ir_macros;
9+
10+
use rustc_type_ir_macros::GenericTypeVisitable;
11+
12+
#[derive(GenericTypeVisitable)]
13+
struct MissingBound<T> {
14+
// This should fail, as `T: GenericTypeVisitable<__V>` wasn't specified
15+
#[generic_type_visitable(bounds())]
16+
//~^ ERROR: the trait bound `T: GenericTypeVisitable<__V>` is not satisfied
17+
partially_rec: (Vec<Self>, T),
18+
other: u32,
19+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0277]: the trait bound `T: GenericTypeVisitable<__V>` is not satisfied
2+
--> $DIR/derive-generic-type-visitable-missing-bound.rs:15:5
3+
|
4+
LL | #[derive(GenericTypeVisitable)]
5+
| --------------------
6+
| |
7+
| required by a bound introduced by this call
8+
| in this derive macro expansion
9+
...
10+
LL | #[generic_type_visitable(bounds())]
11+
| ^ the nightly-only, unstable trait `GenericTypeVisitable<__V>` is not implemented for `T`
12+
|
13+
= note: required for `(Vec<MissingBound<T>>, T)` to implement `GenericTypeVisitable<__V>`
14+
= note: this error originates in the derive macro `GenericTypeVisitable` (in Nightly builds, run with -Z macro-backtrace for more info)
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//@ edition: 2024
2+
//@ run-pass
3+
4+
#![feature(rustc_private)]
5+
6+
extern crate rustc_type_ir;
7+
extern crate rustc_type_ir_macros;
8+
9+
use rustc_type_ir::GenericTypeVisitable;
10+
use rustc_type_ir_macros::GenericTypeVisitable;
11+
12+
// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
13+
// files.
14+
#[expect(unused_extern_crates)]
15+
extern crate rustc_driver;
16+
17+
#[derive(GenericTypeVisitable)]
18+
struct DerivesGenericTypeVisitable;
19+
20+
#[derive(GenericTypeVisitable)]
21+
struct Foo {
22+
one: Incrementer,
23+
two: Vec<Incrementer>,
24+
}
25+
26+
#[derive(GenericTypeVisitable)]
27+
enum Enum {
28+
A,
29+
B(Incrementer),
30+
C { one: Incrementer, two: Vec<Incrementer> },
31+
}
32+
33+
#[derive(GenericTypeVisitable)]
34+
struct Generic<T>(Vec<T>);
35+
36+
#[derive(GenericTypeVisitable)]
37+
struct Recursive {
38+
#[generic_type_visitable(bounds())]
39+
rec: Vec<Self>,
40+
other: Incrementer,
41+
}
42+
43+
#[derive(GenericTypeVisitable)]
44+
struct PartiallyRecursiveField<T> {
45+
#[generic_type_visitable(bounds(T: GenericTypeVisitable<__V>))]
46+
partially_rec: (Vec<Self>, T),
47+
other: Incrementer,
48+
}
49+
50+
// start testing setup
51+
52+
use std::sync::atomic::{AtomicU8, Ordering};
53+
54+
static COUNT: AtomicU8 = AtomicU8::new(0);
55+
56+
/// A type that, when visited, increments a global counter.
57+
///
58+
/// Used to (weakly) test the correctness of the derive by making sure that
59+
/// it traverses all the fields, and thus reaches all the incrementers.
60+
#[derive(Clone)]
61+
struct Incrementer;
62+
63+
unsafe impl<V> GenericTypeVisitable<V> for Incrementer {
64+
fn generic_visit_with(&self, _visitor: &mut V) {
65+
COUNT.fetch_add(1, Ordering::AcqRel);
66+
}
67+
}
68+
69+
// end testing setup
70+
71+
fn main() {
72+
use Incrementer as Inc; // for brevity
73+
74+
#[track_caller]
75+
fn check<T: GenericTypeVisitable<()>>(item: T, count: u8) {
76+
let mut v = ();
77+
item.generic_visit_with(&mut v);
78+
assert_eq!(COUNT.swap(0, Ordering::AcqRel), count);
79+
}
80+
81+
check(DerivesGenericTypeVisitable, 0);
82+
check(Foo { one: Inc, two: vec![] }, 1);
83+
check(Foo { one: Inc, two: vec![Inc; 2] }, 1 + 2);
84+
check(Enum::A, 0);
85+
check(Enum::B(Inc), 1);
86+
check(Enum::C { one: Inc, two: vec![] }, 1);
87+
check(Enum::C { one: Inc, two: vec![Inc; 3] }, 1 + 3);
88+
check(Generic::<Inc>(vec![]), 0);
89+
// visits each of the nested `Inc`s
90+
check(Generic(vec![Inc; 5]), 5);
91+
92+
// Every (nested) `rec!` adds another `Recursive`, and therefore 1 more visited `Inc`.
93+
macro_rules! rec {
94+
[$($i:expr),* $(,)?] => {
95+
Recursive { rec: vec![$($i),*], other: Inc }
96+
}
97+
}
98+
check(rec![], 1);
99+
check(rec![rec![]], 2);
100+
check(rec![rec![], rec![]], 3);
101+
check(rec![rec![rec![]]], 3);
102+
103+
// Every (nested) `prec!` adds another `PartiallyRecursiveField`, and therefore 1 more visited `Inc`.
104+
macro_rules! prec {
105+
([$($i:expr),* $(,)?], $o:expr) => {
106+
PartiallyRecursiveField { partially_rec: (vec![$($i),*], $o), other: Inc }
107+
}
108+
}
109+
// Every nested `a()`, `b()`, and `c()` adds 0, 1, and 2 more visited `Inc`s, respectively.
110+
let a = || Enum::A;
111+
let b = || Enum::B(Inc);
112+
let c = || Enum::C { one: Inc, two: vec![Inc] };
113+
check(prec!([], a()), 1 + 0);
114+
check(prec!([], b()), 1 + 1);
115+
check(prec!([], c()), 1 + 2);
116+
check(prec!([prec!([], a())], a()), 1 + (1 + 0) + 0);
117+
check(prec!([prec!([], b())], a()), 1 + (1 + 1) + 0);
118+
check(prec!([prec!([], b())], b()), 1 + (1 + 1) + 1);
119+
}

0 commit comments

Comments
 (0)