diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index e1d2b53366066..8a437c4995724 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -48,11 +48,15 @@ decl_derive!( /// struct Foo { /// #[generic_type_visitable(bounds())] /// just_self: Box, - /// #[generic_type_visitable(bounds(Bar: GenericTypeVisitable))] + /// #[generic_type_visitable(bounds(Bar: GenericTypeVisitable<__V>))] /// contains_self: (Box, Bar), /// } /// struct Bar; /// ``` + /// + /// Note: the `__V` lifetime is an implementation detail of the derive macro. + /// We could probably handle this in a nicer way, but we don't expect this form + /// to really be necessary any time soon, so for now we don't. customizable_type_visitable_derive ); @@ -461,7 +465,7 @@ mod kw { /// Parses a bound like: /// /// ```ignore (would need to import GenericTypeVisitable to get this to compile) -/// #[generic_type_visitable(bounds(Foo: GenericTypeVisitable, Bar: GenericTypeVisitable))] +/// #[generic_type_visitable(bounds(Foo: GenericTypeVisitable<__V>, Bar: GenericTypeVisitable<__V>))] /// ``` fn parse_generic_type_visitable_bound( attr: &Attribute, diff --git a/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md b/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md index 110fd1331bc44..2b06f5b414c1b 100644 --- a/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md +++ b/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md @@ -115,7 +115,7 @@ For rust-analyzer, the corresponding implementations are located across several These two traits correspond to the role of [`InferCtxt`][rustc inferctxt] in rustc. [`InferCtxtLike`][ir inferctxtlike] must be defined in `rustc_infer` due to coherence -constraints(orphan rules). +constraints (orphan rules). As a result, it cannot provide functionality that lives in `rustc_trait_selection`. Instead, behavior that depends on trait-solving logic is abstracted into a separate trait, [`SolverDelegate`][ir solverdelegate]. @@ -214,9 +214,9 @@ non-obvious considerations: 1. The generic parameters `I` and `J` are reserved for `I: Interner` and `J` being the interner it is being lifted to. -2. `PhantomData` is handled automatically, creating a new `PhantomData` but - _has_ to be included in the file through; `use std::marker::PhantomData;` - you cannot use `std::marker::PhantomData` directly on the field of a struct. +2. `PhantomData` is handled automatically, creating a new `PhantomData`. But it + _has_ to be used in the fully unqualified form -- you cannot use + `std::marker::PhantomData` directly in the field. 3. The bounds are deliberately written as associated type bounds on the `Interner` trait rather than as `where` clauses on `LiftInto`. Given only `I: LiftInto`, Rust can then treat bounds such as the following as implied: @@ -255,12 +255,6 @@ There is intentionally no ignore attribute. The traversal must visit every field. This is a soundness requirement for rust-analyzer's use of the traversal when tracing and garbage-collecting interned types. -When the macro crate's `nightly` feature is enabled, the derive macro remains -registered but emits no tokens. The `GenericTypeVisitable` trait and its -traversal module are also excluded from the nightly configuration of -`rustc_type_ir`; they exist only in its non-nightly configuration. - - ## Long-term plans for supporting rust-analyzer In general, we aim to support rust-analyzer just as well as rustc in these shared crates—provided @@ -310,4 +304,4 @@ There are still duplicated implementations between rustc and rust-analyzer—suc [r-a coerce]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/infer/coerce.rs [rustc_lift]: https://github.com/rust-lang/rust/blob/0913b18e489ac1011b580e31fa5559654be12bfc/compiler/rustc_type_ir/src/lift.rs#L18 [rustc_typevisitable]: https://github.com/rust-lang/rust/blob/0913b18e489ac1011b580e31fa5559654be12bfc/compiler/rustc_type_ir/src/visit.rs#L62 -[rustc_typefoldable]: https://github.com/rust-lang/rust/blob/0913b18e489ac1011b580e31fa5559654be12bfc/compiler/rustc_type_ir/src/fold.rs#L71 \ No newline at end of file +[rustc_typefoldable]: https://github.com/rust-lang/rust/blob/0913b18e489ac1011b580e31fa5559654be12bfc/compiler/rustc_type_ir/src/fold.rs#L71 diff --git a/src/doc/rustc-dev-guide/src/solve/the-solver.md b/src/doc/rustc-dev-guide/src/solve/the-solver.md index 0151c0482d109..3d66ec272698d 100644 --- a/src/doc/rustc-dev-guide/src/solve/the-solver.md +++ b/src/doc/rustc-dev-guide/src/solve/the-solver.md @@ -7,7 +7,7 @@ as it is very similar to this implementation and also talks about limitations of ## A rough walkthrough -The entry-point of the solver is `InferCtxtEvalExt::evaluate_root_goal`. +The entry-point of the solver is `SolverDelegateEvalExt::evaluate_root_goal`. This function sets up the root `EvalCtxt` and then calls `EvalCtxt::evaluate_goal`, to actually enter the trait solver. diff --git a/tests/ui-fulldeps/derive-generic-type-visitable-missing-bound.rs b/tests/ui-fulldeps/derive-generic-type-visitable-missing-bound.rs new file mode 100644 index 0000000000000..af44ff7e92252 --- /dev/null +++ b/tests/ui-fulldeps/derive-generic-type-visitable-missing-bound.rs @@ -0,0 +1,19 @@ +//@ edition: 2024 +//@ check-fail + +#![crate_type = "rlib"] +#![feature(rustc_private)] + +extern crate rustc_type_ir; +extern crate rustc_type_ir_macros; + +use rustc_type_ir_macros::GenericTypeVisitable; + +#[derive(GenericTypeVisitable)] +struct MissingBound { + // This should fail, as `T: GenericTypeVisitable<__V>` wasn't specified + #[generic_type_visitable(bounds())] + //~^ ERROR: the trait bound `T: GenericTypeVisitable<__V>` is not satisfied + partially_rec: (Vec, T), + other: u32, +} diff --git a/tests/ui-fulldeps/derive-generic-type-visitable-missing-bound.stderr b/tests/ui-fulldeps/derive-generic-type-visitable-missing-bound.stderr new file mode 100644 index 0000000000000..44433984e4a7f --- /dev/null +++ b/tests/ui-fulldeps/derive-generic-type-visitable-missing-bound.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `T: GenericTypeVisitable<__V>` is not satisfied + --> $DIR/derive-generic-type-visitable-missing-bound.rs:15:5 + | +LL | #[derive(GenericTypeVisitable)] + | -------------------- + | | + | required by a bound introduced by this call + | in this derive macro expansion +... +LL | #[generic_type_visitable(bounds())] + | ^ the nightly-only, unstable trait `GenericTypeVisitable<__V>` is not implemented for `T` + | + = note: required for `(Vec>, T)` to implement `GenericTypeVisitable<__V>` + = note: this error originates in the derive macro `GenericTypeVisitable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui-fulldeps/derive-generic-type-visitable.rs b/tests/ui-fulldeps/derive-generic-type-visitable.rs new file mode 100644 index 0000000000000..91c7a502a87d8 --- /dev/null +++ b/tests/ui-fulldeps/derive-generic-type-visitable.rs @@ -0,0 +1,119 @@ +//@ edition: 2024 +//@ run-pass + +#![feature(rustc_private)] + +extern crate rustc_type_ir; +extern crate rustc_type_ir_macros; + +use rustc_type_ir::GenericTypeVisitable; +use rustc_type_ir_macros::GenericTypeVisitable; + +// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta +// files. +#[expect(unused_extern_crates)] +extern crate rustc_driver; + +#[derive(GenericTypeVisitable)] +struct DerivesGenericTypeVisitable; + +#[derive(GenericTypeVisitable)] +struct Foo { + one: Incrementer, + two: Vec, +} + +#[derive(GenericTypeVisitable)] +enum Enum { + A, + B(Incrementer), + C { one: Incrementer, two: Vec }, +} + +#[derive(GenericTypeVisitable)] +struct Generic(Vec); + +#[derive(GenericTypeVisitable)] +struct Recursive { + #[generic_type_visitable(bounds())] + rec: Vec, + other: Incrementer, +} + +#[derive(GenericTypeVisitable)] +struct PartiallyRecursiveField { + #[generic_type_visitable(bounds(T: GenericTypeVisitable<__V>))] + partially_rec: (Vec, T), + other: Incrementer, +} + +// start testing setup + +use std::sync::atomic::{AtomicU8, Ordering}; + +static COUNT: AtomicU8 = AtomicU8::new(0); + +/// A type that, when visited, increments a global counter. +/// +/// Used to (weakly) test the correctness of the derive by making sure that +/// it traverses all the fields, and thus reaches all the incrementers. +#[derive(Clone)] +struct Incrementer; + +unsafe impl GenericTypeVisitable for Incrementer { + fn generic_visit_with(&self, _visitor: &mut V) { + COUNT.fetch_add(1, Ordering::Relaxed); + } +} + +// end testing setup + +fn main() { + use Incrementer as Inc; // for brevity + + #[track_caller] + fn check>(item: T, count: u8) { + let mut v = (); + item.generic_visit_with(&mut v); + assert_eq!(COUNT.swap(0, Ordering::Relaxed), count); + } + + check(DerivesGenericTypeVisitable, 0); + check(Foo { one: Inc, two: vec![] }, 1); + check(Foo { one: Inc, two: vec![Inc; 2] }, 1 + 2); + check(Enum::A, 0); + check(Enum::B(Inc), 1); + check(Enum::C { one: Inc, two: vec![] }, 1); + check(Enum::C { one: Inc, two: vec![Inc; 3] }, 1 + 3); + check(Generic::(vec![]), 0); + // visits each of the nested `Inc`s + check(Generic(vec![Inc; 5]), 5); + + // Every (nested) `rec!` adds another `Recursive`, and thus 1 more visited `Inc`. + macro_rules! rec { + [$($i:expr),* $(,)?] => { + Recursive { rec: vec![$($i),*], other: Inc } + } + } + check(rec![], 1); + check(rec![rec![]], 2); + check(rec![rec![], rec![]], 3); + check(rec![rec![rec![]]], 3); + + // Every (nested) `prec!` adds another `PartiallyRecursiveField`, and thus 1 more visited `Inc`. + macro_rules! prec { + ([$($i:expr),* $(,)?], $o:expr) => { + PartiallyRecursiveField { partially_rec: (vec![$($i),*], $o), other: Inc } + } + } + // Every nested `a()`, `b()`, and `c()` adds 0, 1, and 2 more visited `Inc`s, respectively. + let a = || Enum::A; + let b = || Enum::B(Inc); + let c = || Enum::C { one: Inc, two: vec![Inc] }; + check(prec!([], a()), 1 + 0); + check(prec!([], b()), 1 + 1); + check(prec!([], c()), 1 + 2); + check(prec!([prec!([], a())], a()), 1 + (1 + 0) + 0); + check(prec!([prec!([], b())], a()), 1 + (1 + 1) + 0); + check(prec!([prec!([], b())], b()), 1 + (1 + 1) + 1); +}