From 102997a9391cb4c4eac6cddf5e8fdf1aa369ea69 Mon Sep 17 00:00:00 2001 From: Veera Date: Sat, 13 Jul 2024 11:49:14 -0400 Subject: [PATCH 001/156] Update Tests --- .../dyn-keyword/dyn-2021-edition-error.stderr | 10 +- ...t-in-fn-inputs-and-outputs-issue-125139.rs | 142 ++++ ...-fn-inputs-and-outputs-issue-125139.stderr | 673 ++++++++++++++++++ 3 files changed, 824 insertions(+), 1 deletion(-) create mode 100644 tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs create mode 100644 tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr diff --git a/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr b/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr index b39689afd1ca..52ee6c81ab79 100644 --- a/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr +++ b/tests/ui/dyn-keyword/dyn-2021-edition-error.stderr @@ -4,7 +4,15 @@ error[E0782]: trait objects must include the `dyn` keyword LL | fn function(x: &SomeTrait, y: Box) { | ^^^^^^^^^ | -help: add `dyn` keyword before this trait +help: use a new generic type parameter, constrained by `SomeTrait` + | +LL | fn function(x: &T, y: Box) { + | ++++++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn function(x: &impl SomeTrait, y: Box) { + | ++++ +help: alternatively, use a trait object to accept any type that implements `SomeTrait`, accessing its methods at runtime using dynamic dispatch | LL | fn function(x: &dyn SomeTrait, y: Box) { | +++ diff --git a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs new file mode 100644 index 000000000000..dceb6e0fe710 --- /dev/null +++ b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs @@ -0,0 +1,142 @@ +//@ edition:2021 + +trait Trait {} + +struct IceCream; + +impl IceCream { + fn foo(_: &Trait) {} + //~^ ERROR: trait objects must include the `dyn` keyword + + fn bar(self, _: &'a Trait) {} + //~^ ERROR: trait objects must include the `dyn` keyword + //~| ERROR: use of undeclared lifetime name + + fn alice<'a>(&self, _: &Trait) {} + //~^ ERROR: trait objects must include the `dyn` keyword + + fn bob<'a>(_: &'a Trait) {} + //~^ ERROR: trait objects must include the `dyn` keyword + + fn cat() -> &Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn dog<'a>() -> &Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn kitten() -> &'a Trait { + //~^ ERROR: use of undeclared lifetime name + //~| ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn puppy<'a>() -> &'a Trait { + //~^ ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn parrot() -> &mut Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: cannot return a mutable reference to a bare trait + &mut Type + //~^ ERROR: cannot return reference to temporary value + } +} + +trait Sing { + fn foo(_: &Trait); + //~^ ERROR: trait objects must include the `dyn` keyword + + fn bar(_: &'a Trait); + //~^ ERROR: trait objects must include the `dyn` keyword + //~| ERROR: use of undeclared lifetime name + + fn alice<'a>(_: &Trait); + //~^ ERROR: trait objects must include the `dyn` keyword + + fn bob<'a>(_: &'a Trait); + //~^ ERROR: trait objects must include the `dyn` keyword + + fn cat() -> &Trait; + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + + fn dog<'a>() -> &Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn kitten() -> &'a Trait { + //~^ ERROR: use of undeclared lifetime name + //~| ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn puppy<'a>() -> &'a Trait { + //~^ ERROR: trait objects must include the `dyn` keyword + &Type + } + + fn parrot() -> &mut Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: cannot return a mutable reference to a bare trait + &mut Type + //~^ ERROR: cannot return reference to temporary value + } +} + +fn foo(_: &Trait) {} +//~^ ERROR: trait objects must include the `dyn` keyword + +fn bar(_: &'a Trait) {} +//~^ ERROR: trait objects must include the `dyn` keyword +//~| ERROR: use of undeclared lifetime name + +fn alice<'a>(_: &Trait) {} +//~^ ERROR: trait objects must include the `dyn` keyword + +fn bob<'a>(_: &'a Trait) {} +//~^ ERROR: trait objects must include the `dyn` keyword + +struct Type; + +impl Trait for Type {} + +fn cat() -> &Trait { +//~^ ERROR: missing lifetime specifier +//~| ERROR: trait objects must include the `dyn` keyword + &Type +} + +fn dog<'a>() -> &Trait { +//~^ ERROR: missing lifetime specifier +//~| ERROR: trait objects must include the `dyn` keyword + &Type +} + +fn kitten() -> &'a Trait { +//~^ ERROR: use of undeclared lifetime name +//~| ERROR: trait objects must include the `dyn` keyword + &Type +} + +fn puppy<'a>() -> &'a Trait { +//~^ ERROR: trait objects must include the `dyn` keyword + &Type +} + +fn parrot() -> &mut Trait { + //~^ ERROR: missing lifetime specifier + //~| ERROR: cannot return a mutable reference to a bare trait + &mut Type + //~^ ERROR: cannot return reference to temporary value +} + +fn main() {} diff --git a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr new file mode 100644 index 000000000000..15c8eb5d16c2 --- /dev/null +++ b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr @@ -0,0 +1,673 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:11:22 + | +LL | fn bar(self, _: &'a Trait) {} + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | fn bar<'a>(self, _: &'a Trait) {} + | ++++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> IceCream { + | ++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:21:17 + | +LL | fn cat() -> &Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn cat() -> &'static Trait { + | +++++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:27:21 + | +LL | fn dog<'a>() -> &Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'a` lifetime + | +LL | fn dog<'a>() -> &'a Trait { + | ++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:33:21 + | +LL | fn kitten() -> &'a Trait { + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | fn kitten<'a>() -> &'a Trait { + | ++++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> IceCream { + | ++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:44:20 + | +LL | fn parrot() -> &mut Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn parrot() -> &'static mut Trait { + | +++++++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:56:16 + | +LL | fn bar(_: &'a Trait); + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | fn bar<'a>(_: &'a Trait); + | ++++ +help: consider introducing lifetime `'a` here + | +LL | trait Sing<'a> { + | ++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:66:17 + | +LL | fn cat() -> &Trait; + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn cat() -> &'static Trait; + | +++++++ +help: instead, you are more likely to want to return an owned value + | +LL - fn cat() -> &Trait; +LL + fn cat() -> Trait; + | + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:70:21 + | +LL | fn dog<'a>() -> &Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'a` lifetime + | +LL | fn dog<'a>() -> &'a Trait { + | ++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:76:21 + | +LL | fn kitten() -> &'a Trait { + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | fn kitten<'a>() -> &'a Trait { + | ++++ +help: consider introducing lifetime `'a` here + | +LL | trait Sing<'a> { + | ++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:87:20 + | +LL | fn parrot() -> &mut Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn parrot() -> &'static mut Trait { + | +++++++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:98:12 + | +LL | fn bar(_: &'a Trait) {} + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:112:13 + | +LL | fn cat() -> &Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn cat() -> &'static Trait { + | +++++++ + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:118:17 + | +LL | fn dog<'a>() -> &Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'a` lifetime + | +LL | fn dog<'a>() -> &'a Trait { + | ++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:124:17 + | +LL | fn kitten() -> &'a Trait { + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + +error[E0106]: missing lifetime specifier + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:135:16 + | +LL | fn parrot() -> &mut Trait { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn parrot() -> &'static mut Trait { + | +++++++ + +error[E0515]: cannot return reference to temporary value + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:47:9 + | +LL | &mut Type + | ^^^^^---- + | | | + | | temporary value created here + | returns a reference to data owned by the current function + +error[E0515]: cannot return reference to temporary value + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:90:9 + | +LL | &mut Type + | ^^^^^---- + | | | + | | temporary value created here + | returns a reference to data owned by the current function + +error[E0515]: cannot return reference to temporary value + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:138:5 + | +LL | &mut Type + | ^^^^^---- + | | | + | | temporary value created here + | returns a reference to data owned by the current function + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:53:16 + | +LL | fn foo(_: &Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn foo(_: &T); + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn foo(_: &impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn foo(_: &dyn Trait); + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:56:19 + | +LL | fn bar(_: &'a Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bar(_: &'a T); + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bar(_: &'a impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bar(_: &'a dyn Trait); + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:60:22 + | +LL | fn alice<'a>(_: &Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn alice<'a, T: Trait>(_: &T); + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn alice<'a>(_: &impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn alice<'a>(_: &dyn Trait); + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:63:23 + | +LL | fn bob<'a>(_: &'a Trait); + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bob<'a, T: Trait>(_: &'a T); + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bob<'a>(_: &'a impl Trait); + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bob<'a>(_: &'a dyn Trait); + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:66:18 + | +LL | fn cat() -> &Trait; + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn cat<'a>() -> &'a impl Trait; + | ++++ +++++++ +help: alternatively, you can return an owned trait object + | +LL | fn cat() -> Box; + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:70:22 + | +LL | fn dog<'a>() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn dog<'b, 'a>() -> &'b impl Trait { + | +++ +++++++ +help: alternatively, you can return an owned trait object + | +LL | fn dog<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:76:24 + | +LL | fn kitten() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn kitten() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn kitten() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:82:27 + | +LL | fn puppy<'a>() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn puppy<'a>() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn puppy<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: cannot return a mutable reference to a bare trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:87:25 + | +LL | fn parrot() -> &mut Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn parrot() -> impl Trait { + | ~~~~~~~~~~ +help: alternatively, you can return an owned trait object + | +LL | fn parrot() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:95:12 + | +LL | fn foo(_: &Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn foo(_: &T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn foo(_: &impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn foo(_: &dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:98:15 + | +LL | fn bar(_: &'a Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bar(_: &'a T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bar(_: &'a impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bar(_: &'a dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:102:18 + | +LL | fn alice<'a>(_: &Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn alice<'a, T: Trait>(_: &T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn alice<'a>(_: &impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn alice<'a>(_: &dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:105:19 + | +LL | fn bob<'a>(_: &'a Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bob<'a, T: Trait>(_: &'a T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bob<'a>(_: &'a impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bob<'a>(_: &'a dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:112:14 + | +LL | fn cat() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn cat<'a>() -> &'a impl Trait { + | ++++ +++++++ +help: alternatively, you can return an owned trait object + | +LL | fn cat() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:118:18 + | +LL | fn dog<'a>() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn dog<'b, 'a>() -> &'b impl Trait { + | +++ +++++++ +help: alternatively, you can return an owned trait object + | +LL | fn dog<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:124:20 + | +LL | fn kitten() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn kitten() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn kitten() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:130:23 + | +LL | fn puppy<'a>() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn puppy<'a>() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn puppy<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: cannot return a mutable reference to a bare trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:135:21 + | +LL | fn parrot() -> &mut Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn parrot() -> impl Trait { + | ~~~~~~~~~~ +help: alternatively, you can return an owned trait object + | +LL | fn parrot() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:8:16 + | +LL | fn foo(_: &Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn foo(_: &T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn foo(_: &impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn foo(_: &dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:11:25 + | +LL | fn bar(self, _: &'a Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bar(self, _: &'a T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bar(self, _: &'a impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bar(self, _: &'a dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:15:29 + | +LL | fn alice<'a>(&self, _: &Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn alice<'a, T: Trait>(&self, _: &T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn alice<'a>(&self, _: &impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn alice<'a>(&self, _: &dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:18:23 + | +LL | fn bob<'a>(_: &'a Trait) {} + | ^^^^^ + | +help: use a new generic type parameter, constrained by `Trait` + | +LL | fn bob<'a, T: Trait>(_: &'a T) {} + | ++++++++++ ~ +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bob<'a>(_: &'a impl Trait) {} + | ++++ +help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch + | +LL | fn bob<'a>(_: &'a dyn Trait) {} + | +++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:21:18 + | +LL | fn cat() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn cat<'a>() -> &'a impl Trait { + | ++++ +++++++ +help: alternatively, you can return an owned trait object + | +LL | fn cat() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:27:22 + | +LL | fn dog<'a>() -> &Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn dog<'b, 'a>() -> &'b impl Trait { + | +++ +++++++ +help: alternatively, you can return an owned trait object + | +LL | fn dog<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:33:24 + | +LL | fn kitten() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn kitten() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn kitten() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:39:27 + | +LL | fn puppy<'a>() -> &'a Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn puppy<'a>() -> &'a impl Trait { + | ++++ +help: alternatively, you can return an owned trait object + | +LL | fn puppy<'a>() -> Box { + | ~~~~~~~~~~~~~~ + +error[E0782]: cannot return a mutable reference to a bare trait + --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:44:25 + | +LL | fn parrot() -> &mut Trait { + | ^^^^^ + | +help: use `impl Trait` to return an opaque type, as long as you return a single underlying type + | +LL | fn parrot() -> impl Trait { + | ~~~~~~~~~~ +help: alternatively, you can return an owned trait object + | +LL | fn parrot() -> Box { + | ~~~~~~~~~~~~~~ + +error: aborting due to 45 previous errors + +Some errors have detailed explanations: E0106, E0261, E0515, E0782. +For more information about an error, try `rustc --explain E0106`. From 315a16fced68f63f1f396756c1f5c192cdac44ed Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 8 Jul 2024 03:21:53 +0000 Subject: [PATCH 002/156] doc: Fold inline methods from Deref --- src/librustdoc/html/render/mod.rs | 17 +++++++++++++---- src/librustdoc/html/static/css/rustdoc.css | 5 +++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 877a00e206d1..acc21faa464a 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1256,6 +1256,7 @@ fn render_assoc_items_inner( let Some(v) = cache.impls.get(&it) else { return }; let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { + let mut close_tags = >::with_capacity(1); let mut tmp_buf = Buffer::html(); let (render_mode, id, class_html) = match what { AssocItemRender::All => { @@ -1266,6 +1267,8 @@ fn render_assoc_items_inner( let id = cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx)))); let derived_id = cx.derive_id(&id); + tmp_buf.write_str("
"); + close_tags.push("
"); write_impl_section_heading( &mut tmp_buf, &format!( @@ -1275,6 +1278,7 @@ fn render_assoc_items_inner( ), &id, ); + tmp_buf.write_str(""); if let Some(def_id) = type_.def_id(cx.cache()) { cx.deref_id_map.insert(def_id, id); } @@ -1308,6 +1312,9 @@ fn render_assoc_items_inner( impls_buf.into_inner() ) .unwrap(); + for tag in close_tags.into_iter().rev() { + w.write_str(tag).unwrap(); + } } } @@ -1565,7 +1572,7 @@ fn render_impl( let cache = &shared.cache; let traits = &cache.traits; let trait_ = i.trait_did().map(|did| &traits[&did]); - let mut close_tags = String::new(); + let mut close_tags = >::with_capacity(2); // For trait implementations, the `interesting` output contains all methods that have doc // comments, and the `boring` output contains all methods that do not. The distinction is @@ -1853,7 +1860,7 @@ fn render_impl( if render_mode == RenderMode::Normal { let toggled = !(impl_items.is_empty() && default_impl_items.is_empty()); if toggled { - close_tags.insert_str(0, ""); + close_tags.push(""); write!( w, "
\ @@ -1899,14 +1906,16 @@ fn render_impl( } if !default_impl_items.is_empty() || !impl_items.is_empty() { w.write_str("
"); - close_tags.insert_str(0, "
"); + close_tags.push(""); } } if !default_impl_items.is_empty() || !impl_items.is_empty() { w.push_buffer(default_impl_items); w.push_buffer(impl_items); } - w.write_str(&close_tags); + for tag in close_tags.into_iter().rev() { + w.write_str(tag); + } } // Render the items that appear on the right side of methods, impls, and diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4c0ba75d2612..7362ea79025d 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1733,6 +1733,11 @@ details.toggle { position: relative; } +details.implementors-toggle { + /* This makes [-] on the same line as . */ + contain: inline-size; +} + /* The hideme class is used on summary tags that contain a span with placeholder text shown only when the toggle is closed. For instance, "Expand description" or "Show methods". */ From fbc794fe1e812fb719063b90e8e915fff6781057 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 15 Jul 2024 17:43:46 +0200 Subject: [PATCH 003/156] Fix style --- src/librustdoc/html/static/css/rustdoc.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 7362ea79025d..4a8c7d3e0f0e 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1828,6 +1828,11 @@ details.toggle > summary:not(.hideme)::before { left: -24px; } +details.implementors-toggle > summary:not(.hideme)::before { + left: -34px; + top: 9px; +} + /* When a "hideme" summary is open and the "Expand description" or "Show methods" text is hidden, we want the [-] toggle that remains to not affect the layout of the items to its right. To do that, we use From a868b3fce74c11e2efc54ed1e9f13894a4bc6381 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 15 Jul 2024 18:10:26 +0200 Subject: [PATCH 004/156] Create new CSS class for "big toggles" --- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/static/css/rustdoc.css | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index acc21faa464a..547d8d82eae9 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1267,7 +1267,7 @@ fn render_assoc_items_inner( let id = cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx)))); let derived_id = cx.derive_id(&id); - tmp_buf.write_str("
"); + tmp_buf.write_str("
"); close_tags.push("
"); write_impl_section_heading( &mut tmp_buf, diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4a8c7d3e0f0e..b104fbf4e970 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1733,7 +1733,7 @@ details.toggle { position: relative; } -details.implementors-toggle { +details.big-toggle { /* This makes [-] on the same line as . */ contain: inline-size; } @@ -1828,7 +1828,7 @@ details.toggle > summary:not(.hideme)::before { left: -24px; } -details.implementors-toggle > summary:not(.hideme)::before { +details.big-toggle > summary:not(.hideme)::before { left: -34px; top: 9px; } From 9855a3844bbe96d03f18541bdee3e325c35c8a34 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 15 Jul 2024 18:10:50 +0200 Subject: [PATCH 005/156] Add tests for new toggle on deref blocks --- tests/rustdoc-gui/deref-block.goml | 30 ++++++++++++++++++++++++++++++ tests/rustdoc-gui/src/lib2/lib.rs | 10 ++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/rustdoc-gui/deref-block.goml diff --git a/tests/rustdoc-gui/deref-block.goml b/tests/rustdoc-gui/deref-block.goml new file mode 100644 index 000000000000..24f612f8a6fd --- /dev/null +++ b/tests/rustdoc-gui/deref-block.goml @@ -0,0 +1,30 @@ +// This test ensures that several clickable items actually have the pointer cursor. +go-to: "file://" + |DOC_PATH| + "/lib2/struct.Derefer.html" + +assert-text: (".big-toggle summary", "Methods from Deref§") +// We ensure it doesn't go over `§`. +assert-css: (".big-toggle summary::before", { + "left": "-34px", + "top": "9px", +}) +// It should NOT have the same X or Y position as the other toggles. +compare-elements-position-false: ( + ".big-toggle summary::before", + ".method-toggle summary::before", + ["x", "y"], +) + +// We now check that if we're in mobile mode, it gets back to its original X position. +set-window-size: (600, 600) +assert-css: (".big-toggle summary::before", { + "left": "-11px", + "top": "9px", +}) +// It should have the same X position as the other toggles. +compare-elements-position: (".big-toggle summary::before", ".method-toggle summary::before", ["x"]) +// But still shouldn't have the same Y position. +compare-elements-position-false: ( + ".big-toggle summary::before", + ".method-toggle summary::before", + ["y"], +) diff --git a/tests/rustdoc-gui/src/lib2/lib.rs b/tests/rustdoc-gui/src/lib2/lib.rs index b467b0440523..fafb8f3b59b3 100644 --- a/tests/rustdoc-gui/src/lib2/lib.rs +++ b/tests/rustdoc-gui/src/lib2/lib.rs @@ -355,3 +355,13 @@ pub mod scroll_traits { fn this_is_a_method_with_a_long_name_returning_something() -> String; } } + +pub struct Derefer(String); + +impl std::ops::Deref for Derefer { + type Target = str; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} From 764675e01aa4f32fd5a84e5f3b6a6e1ca8a1d31e Mon Sep 17 00:00:00 2001 From: Veera Date: Tue, 6 Aug 2024 14:06:29 -0400 Subject: [PATCH 006/156] Add Tests --- .../break-inside-inline-const-issue-128604.rs | 18 +++++++++ ...ak-inside-inline-const-issue-128604.stderr | 39 +++++++++++++++++++ .../break-inside-unsafe-block-issue-128604.rs | 18 +++++++++ ...ak-inside-unsafe-block-issue-128604.stderr | 39 +++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 tests/ui/inline-const/break-inside-inline-const-issue-128604.rs create mode 100644 tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr create mode 100644 tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs create mode 100644 tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs new file mode 100644 index 000000000000..648c9582510e --- /dev/null +++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs @@ -0,0 +1,18 @@ +fn main() { + let _ = ['a'; { break 2; 1 }]; + //~^ ERROR `break` outside of a loop or labeled block + //~| HELP consider labeling this block to be able to break within it + + const { + { + //~^ HELP consider labeling this block to be able to break within it + break; + //~^ ERROR `break` outside of a loop or labeled block + } + }; + + const { + break; + //~^ ERROR `break` outside of a loop or labeled block + }; +} diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr new file mode 100644 index 000000000000..c240fab11133 --- /dev/null +++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr @@ -0,0 +1,39 @@ +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:2:21 + | +LL | let _ = ['a'; { break 2; 1 }]; + | ^^^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL | let _ = ['a'; 'block: { break 'block 2; 1 }]; + | +++++++ ++++++ + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:9:13 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ 'block: { +LL | +LL ~ break 'block; + | + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:15:9 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ const 'block: { +LL ~ break 'block; + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs new file mode 100644 index 000000000000..cbe7a03d3890 --- /dev/null +++ b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs @@ -0,0 +1,18 @@ +fn main() { + let a = ["_"; unsafe { break; 1 + 2 }]; + //~^ ERROR `break` outside of a loop or labeled block + + unsafe { + { + //~^ HELP consider labeling this block to be able to break within it + break; + //~^ ERROR `break` outside of a loop or labeled block + } + } + + unsafe { + break; + //~^ ERROR `break` outside of a loop or labeled block + } + +} diff --git a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr new file mode 100644 index 000000000000..7acfaf403fb0 --- /dev/null +++ b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr @@ -0,0 +1,39 @@ +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-unsafe-block-issue-128604.rs:2:28 + | +LL | let a = ["_"; unsafe { break; 1 + 2 }]; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL | let a = ["_"; 'block: unsafe { break 'block; 1 + 2 }]; + | +++++++ ++++++ + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-unsafe-block-issue-128604.rs:8:13 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ 'block: { +LL | +LL ~ break 'block; + | + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-unsafe-block-issue-128604.rs:14:9 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ 'block: unsafe { +LL ~ break 'block; + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0268`. From f003e92a5ba73c673f0faeaac01b6eac6ba3f76a Mon Sep 17 00:00:00 2001 From: Veera Date: Tue, 6 Aug 2024 14:10:00 -0400 Subject: [PATCH 007/156] Don't Suggest Labeling `const` and `unsafe` Blocks --- compiler/rustc_passes/src/loops.rs | 40 ++++++++++++------- .../break-inside-inline-const-issue-128604.rs | 7 ++++ ...ak-inside-inline-const-issue-128604.stderr | 26 ++++++------ .../break-inside-unsafe-block-issue-128604.rs | 16 ++++++++ ...ak-inside-unsafe-block-issue-128604.stderr | 23 ++++++----- 5 files changed, 75 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 25115c5cafd8..c11562ae39e3 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -19,17 +19,25 @@ use crate::errors::{ OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, }; +/// The context in which a block is encountered. #[derive(Clone, Copy, Debug, PartialEq)] enum Context { Normal, Fn, Loop(hir::LoopSource), Closure(Span), - Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource }, + Coroutine { + coroutine_span: Span, + kind: hir::CoroutineDesugaring, + source: hir::CoroutineSource, + }, UnlabeledBlock(Span), UnlabeledIfBlock(Span), LabeledBlock, - Constant, + /// E.g. The labeled block inside `['_'; 'block: { break 'block 1 + 2; }]`. + AnonConst, + /// E.g. `const { ... }`. + ConstBlock, } #[derive(Clone)] @@ -90,11 +98,11 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) { - self.with_context(Constant, |v| intravisit::walk_anon_const(v, c)); + self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c)); } fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) { - self.with_context(Constant, |v| intravisit::walk_inline_const(v, c)); + self.with_context(ConstBlock, |v| intravisit::walk_inline_const(v, c)); } fn visit_fn( @@ -128,7 +136,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { && matches!( ck_loop.cx_stack.last(), Some(&Normal) - | Some(&Constant) + | Some(&AnonConst) | Some(&UnlabeledBlock(_)) | Some(&UnlabeledIfBlock(_)) ) @@ -175,14 +183,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprKind::Block(ref b, Some(_label)) => { self.with_context(LabeledBlock, |v| v.visit_block(b)); } - hir::ExprKind::Block(ref b, None) if matches!(self.cx_stack.last(), Some(&Fn)) => { + hir::ExprKind::Block(ref b, None) + if matches!(self.cx_stack.last(), Some(&Fn) | Some(&ConstBlock)) => + { self.with_context(Normal, |v| v.visit_block(b)); } - hir::ExprKind::Block(ref b, None) - if matches!( - self.cx_stack.last(), - Some(&Normal) | Some(&Constant) | Some(&UnlabeledBlock(_)) - ) => + hir::ExprKind::Block( + ref b @ hir::Block { rules: hir::BlockCheckMode::DefaultBlock, .. }, + None, + ) if matches!( + self.cx_stack.last(), + Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock(_)) + ) => { self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b)); } @@ -353,7 +365,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => { self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1); } - Normal | Constant | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) => { + Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => { self.sess.dcx().emit_err(OutsideLoop { spans: vec![span], name: &br_cx_kind.to_string(), @@ -365,7 +377,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { } fn require_label_in_labeled_block( - &mut self, + &self, span: Span, label: &Destination, cf_type: &str, @@ -380,7 +392,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { false } - fn report_outside_loop_error(&mut self) { + fn report_outside_loop_error(&self) { for (s, block) in &self.block_breaks { self.sess.dcx().emit_err(OutsideLoop { spans: block.spans.clone(), diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs index 648c9582510e..a9795d1569c8 100644 --- a/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs +++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs @@ -15,4 +15,11 @@ fn main() { break; //~^ ERROR `break` outside of a loop or labeled block }; + + { + const { + break; + //~^ ERROR `break` outside of a loop or labeled block + } + } } diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr index c240fab11133..300cd45ad691 100644 --- a/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr +++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr @@ -1,3 +1,15 @@ +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:15:9 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:21:13 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + error[E0268]: `break` outside of a loop or labeled block --> $DIR/break-inside-inline-const-issue-128604.rs:2:21 | @@ -22,18 +34,6 @@ LL | LL ~ break 'block; | -error[E0268]: `break` outside of a loop or labeled block - --> $DIR/break-inside-inline-const-issue-128604.rs:15:9 - | -LL | break; - | ^^^^^ cannot `break` outside of a loop or labeled block - | -help: consider labeling this block to be able to break within it - | -LL ~ const 'block: { -LL ~ break 'block; - | - -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs index cbe7a03d3890..a83141f0e4ed 100644 --- a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs +++ b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs @@ -15,4 +15,20 @@ fn main() { //~^ ERROR `break` outside of a loop or labeled block } + { + //~^ HELP consider labeling this block to be able to break within it + unsafe { + break; + //~^ ERROR `break` outside of a loop or labeled block + } + } + + while 2 > 1 { + unsafe { + if true || false { + break; + } + } + } + } diff --git a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr index 7acfaf403fb0..b7cbe1a5cf46 100644 --- a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr +++ b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr @@ -3,11 +3,12 @@ error[E0268]: `break` outside of a loop or labeled block | LL | let a = ["_"; unsafe { break; 1 + 2 }]; | ^^^^^ cannot `break` outside of a loop or labeled block + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-unsafe-block-issue-128604.rs:14:9 | -help: consider labeling this block to be able to break within it - | -LL | let a = ["_"; 'block: unsafe { break 'block; 1 + 2 }]; - | +++++++ ++++++ +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block error[E0268]: `break` outside of a loop or labeled block --> $DIR/break-inside-unsafe-block-issue-128604.rs:8:13 @@ -23,17 +24,19 @@ LL ~ break 'block; | error[E0268]: `break` outside of a loop or labeled block - --> $DIR/break-inside-unsafe-block-issue-128604.rs:14:9 + --> $DIR/break-inside-unsafe-block-issue-128604.rs:21:13 | -LL | break; - | ^^^^^ cannot `break` outside of a loop or labeled block +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block | help: consider labeling this block to be able to break within it | -LL ~ 'block: unsafe { -LL ~ break 'block; +LL ~ 'block: { +LL | +LL | unsafe { +LL ~ break 'block; | -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0268`. From 27f92b6c10ecb0385f22409430b64d13c02dd7a4 Mon Sep 17 00:00:00 2001 From: yifei Date: Thu, 8 Aug 2024 19:29:47 +0800 Subject: [PATCH 008/156] fix: get llvm type of global val --- compiler/rustc_codegen_llvm/src/consts.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 75b298f14ca1..49d0281775bf 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -390,7 +390,7 @@ impl<'ll> CodegenCx<'ll, '_> { let val_llty = self.val_ty(v); let g = self.get_static_inner(def_id, val_llty); - let llty = self.val_ty(g); + let llty = llvm::LLVMGlobalGetValueType(g); let g = if val_llty == llty { g diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 80b13c0e1d4b..e2557ee8800d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -974,6 +974,7 @@ extern "C" { pub fn LLVMGetAlignment(Global: &Value) -> c_uint; pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint); pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass); + pub fn LLVMGlobalGetValueType(Global: &Value) -> &Type; // Operations on global variables pub fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; From 12de141df2d247177e9ca0498ba99bd433cfa500 Mon Sep 17 00:00:00 2001 From: Veera Date: Sat, 13 Jul 2024 12:05:16 -0400 Subject: [PATCH 009/156] Suggest `impl Trait` for References to Bare Trait in Function Header --- .../src/hir_ty_lowering/lint.rs | 78 +++++++++++++------ .../src/error_reporting/traits/suggestions.rs | 16 +++- ...t-in-fn-inputs-and-outputs-issue-125139.rs | 8 +- ...-fn-inputs-and-outputs-issue-125139.stderr | 42 +++++----- 4 files changed, 92 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 29c71c3fa50b..a480d0b38862 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -120,9 +120,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; }; let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name); - if sugg.is_empty() { - return; - }; diag.multipart_suggestion( format!( "alternatively use a blanket implementation to implement `{of_trait_name}` for \ @@ -157,6 +154,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; // FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0` // and suggest `Trait0`. + // Functions are found in three different contexts. + // 1. Independent functions + // 2. Functions inside trait blocks + // 3. Functions inside impl blocks let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => { (sig, generics, None) @@ -167,6 +168,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { owner_id, .. }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))), + hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(sig, _), + generics, + owner_id, + .. + }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))), _ => return false, }; let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { @@ -174,6 +181,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())]; let mut is_downgradable = true; + + // Check if trait object is safe for suggesting dynamic dispatch. let is_object_safe = match self_ty.kind { hir::TyKind::TraitObject(objects, ..) => { objects.iter().all(|o| match o.trait_ref.path.res { @@ -189,8 +198,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } _ => false, }; + + let borrowed = matches!( + tcx.parent_hir_node(self_ty.hir_id), + hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. }) + ); + + // Suggestions for function return type. if let hir::FnRetTy::Return(ty) = sig.decl.output - && ty.hir_id == self_ty.hir_id + && ty.peel_refs().hir_id == self_ty.hir_id { let pre = if !is_object_safe { format!("`{trait_name}` is not object safe, ") @@ -201,14 +217,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { "{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \ single underlying type", ); + diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable); + + // Suggest `Box` for return type if is_object_safe { - diag.multipart_suggestion_verbose( - "alternatively, you can return an owned trait object", + // If the return type is `&Trait`, we don't want + // the ampersand to be displayed in the `Box` + // suggestion. + let suggestion = if borrowed { + vec![(ty.span, format!("Box"))] + } else { vec![ (ty.span.shrink_to_lo(), "Box".to_string()), - ], + ] + }; + + diag.multipart_suggestion_verbose( + "alternatively, you can return an owned trait object", + suggestion, Applicability::MachineApplicable, ); } else if is_downgradable { @@ -217,24 +245,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } return true; } + + // Suggestions for function parameters. for ty in sig.decl.inputs { - if ty.hir_id != self_ty.hir_id { + if ty.peel_refs().hir_id != self_ty.hir_id { continue; } let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name); - if !sugg.is_empty() { - diag.multipart_suggestion_verbose( - format!("use a new generic type parameter, constrained by `{trait_name}`"), - sugg, - Applicability::MachineApplicable, - ); - diag.multipart_suggestion_verbose( - "you can also use an opaque type, but users won't be able to specify the type \ - parameter when calling the `fn`, having to rely exclusively on type inference", - impl_sugg, - Applicability::MachineApplicable, - ); - } + diag.multipart_suggestion_verbose( + format!("use a new generic type parameter, constrained by `{trait_name}`"), + sugg, + Applicability::MachineApplicable, + ); + diag.multipart_suggestion_verbose( + "you can also use an opaque type, but users won't be able to specify the type \ + parameter when calling the `fn`, having to rely exclusively on type inference", + impl_sugg, + Applicability::MachineApplicable, + ); if !is_object_safe { diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`")); if is_downgradable { @@ -242,14 +270,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { diag.downgrade_to_delayed_bug(); } } else { + // No ampersand in suggestion if it's borrowed already + let (dyn_str, paren_dyn_str) = + if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") }; + let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind { // There are more than one trait bound, we need surrounding parentheses. vec![ - (self_ty.span.shrink_to_lo(), "&(dyn ".to_string()), + (self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()), (self_ty.span.shrink_to_hi(), ")".to_string()), ] } else { - vec![(self_ty.span.shrink_to_lo(), "&dyn ".to_string())] + vec![(self_ty.span.shrink_to_lo(), dyn_str.to_string())] }; diag.multipart_suggestion_verbose( format!( diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2cf808f962f0..43bc925d09bb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4925,24 +4925,32 @@ impl<'v> Visitor<'v> for AwaitsVisitor { } } +/// Suggest a new type parameter name for diagnostic purposes. +/// +/// `name` is the preferred name you'd like to suggest if it's not in use already. pub trait NextTypeParamName { fn next_type_param_name(&self, name: Option<&str>) -> String; } impl NextTypeParamName for &[hir::GenericParam<'_>] { fn next_type_param_name(&self, name: Option<&str>) -> String { - // This is the list of possible parameter names that we might suggest. + // Type names are usually single letters in uppercase. So convert the first letter of input string to uppercase. let name = name.and_then(|n| n.chars().next()).map(|c| c.to_uppercase().to_string()); let name = name.as_deref(); + + // This is the list of possible parameter names that we might suggest. let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"]; - let used_names = self + + // Filter out used names based on `filter_fn`. + let used_names: Vec = self .iter() - .filter_map(|p| match p.name { + .filter_map(|param| match param.name { hir::ParamName::Plain(ident) => Some(ident.name), _ => None, }) - .collect::>(); + .collect(); + // Find a name from `possible_names` that is not in `used_names`. possible_names .iter() .find(|n| !used_names.contains(&Symbol::intern(n))) diff --git a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs index dceb6e0fe710..dabaa309c16a 100644 --- a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs +++ b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs @@ -43,7 +43,7 @@ impl IceCream { fn parrot() -> &mut Trait { //~^ ERROR: missing lifetime specifier - //~| ERROR: cannot return a mutable reference to a bare trait + //~| ERROR: trait objects must include the `dyn` keyword &mut Type //~^ ERROR: cannot return reference to temporary value } @@ -86,12 +86,12 @@ trait Sing { fn parrot() -> &mut Trait { //~^ ERROR: missing lifetime specifier - //~| ERROR: cannot return a mutable reference to a bare trait + //~| ERROR: trait objects must include the `dyn` keyword &mut Type //~^ ERROR: cannot return reference to temporary value } } - + fn foo(_: &Trait) {} //~^ ERROR: trait objects must include the `dyn` keyword @@ -134,7 +134,7 @@ fn puppy<'a>() -> &'a Trait { fn parrot() -> &mut Trait { //~^ ERROR: missing lifetime specifier - //~| ERROR: cannot return a mutable reference to a bare trait + //~| ERROR: trait objects must include the `dyn` keyword &mut Type //~^ ERROR: cannot return reference to temporary value } diff --git a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr index 15c8eb5d16c2..8bdfea7766e3 100644 --- a/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr +++ b/tests/ui/object-safety/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr @@ -298,8 +298,8 @@ LL | fn cat() -> &Trait; | help: use `impl Trait` to return an opaque type, as long as you return a single underlying type | -LL | fn cat<'a>() -> &'a impl Trait; - | ++++ +++++++ +LL | fn cat() -> &impl Trait; + | ++++ help: alternatively, you can return an owned trait object | LL | fn cat() -> Box; @@ -313,8 +313,8 @@ LL | fn dog<'a>() -> &Trait { | help: use `impl Trait` to return an opaque type, as long as you return a single underlying type | -LL | fn dog<'b, 'a>() -> &'b impl Trait { - | +++ +++++++ +LL | fn dog<'a>() -> &impl Trait { + | ++++ help: alternatively, you can return an owned trait object | LL | fn dog<'a>() -> Box { @@ -350,7 +350,7 @@ help: alternatively, you can return an owned trait object LL | fn puppy<'a>() -> Box { | ~~~~~~~~~~~~~~ -error[E0782]: cannot return a mutable reference to a bare trait +error[E0782]: trait objects must include the `dyn` keyword --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:87:25 | LL | fn parrot() -> &mut Trait { @@ -358,8 +358,8 @@ LL | fn parrot() -> &mut Trait { | help: use `impl Trait` to return an opaque type, as long as you return a single underlying type | -LL | fn parrot() -> impl Trait { - | ~~~~~~~~~~ +LL | fn parrot() -> &mut impl Trait { + | ++++ help: alternatively, you can return an owned trait object | LL | fn parrot() -> Box { @@ -449,8 +449,8 @@ LL | fn cat() -> &Trait { | help: use `impl Trait` to return an opaque type, as long as you return a single underlying type | -LL | fn cat<'a>() -> &'a impl Trait { - | ++++ +++++++ +LL | fn cat() -> &impl Trait { + | ++++ help: alternatively, you can return an owned trait object | LL | fn cat() -> Box { @@ -464,8 +464,8 @@ LL | fn dog<'a>() -> &Trait { | help: use `impl Trait` to return an opaque type, as long as you return a single underlying type | -LL | fn dog<'b, 'a>() -> &'b impl Trait { - | +++ +++++++ +LL | fn dog<'a>() -> &impl Trait { + | ++++ help: alternatively, you can return an owned trait object | LL | fn dog<'a>() -> Box { @@ -501,7 +501,7 @@ help: alternatively, you can return an owned trait object LL | fn puppy<'a>() -> Box { | ~~~~~~~~~~~~~~ -error[E0782]: cannot return a mutable reference to a bare trait +error[E0782]: trait objects must include the `dyn` keyword --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:135:21 | LL | fn parrot() -> &mut Trait { @@ -509,8 +509,8 @@ LL | fn parrot() -> &mut Trait { | help: use `impl Trait` to return an opaque type, as long as you return a single underlying type | -LL | fn parrot() -> impl Trait { - | ~~~~~~~~~~ +LL | fn parrot() -> &mut impl Trait { + | ++++ help: alternatively, you can return an owned trait object | LL | fn parrot() -> Box { @@ -600,8 +600,8 @@ LL | fn cat() -> &Trait { | help: use `impl Trait` to return an opaque type, as long as you return a single underlying type | -LL | fn cat<'a>() -> &'a impl Trait { - | ++++ +++++++ +LL | fn cat() -> &impl Trait { + | ++++ help: alternatively, you can return an owned trait object | LL | fn cat() -> Box { @@ -615,8 +615,8 @@ LL | fn dog<'a>() -> &Trait { | help: use `impl Trait` to return an opaque type, as long as you return a single underlying type | -LL | fn dog<'b, 'a>() -> &'b impl Trait { - | +++ +++++++ +LL | fn dog<'a>() -> &impl Trait { + | ++++ help: alternatively, you can return an owned trait object | LL | fn dog<'a>() -> Box { @@ -652,7 +652,7 @@ help: alternatively, you can return an owned trait object LL | fn puppy<'a>() -> Box { | ~~~~~~~~~~~~~~ -error[E0782]: cannot return a mutable reference to a bare trait +error[E0782]: trait objects must include the `dyn` keyword --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:44:25 | LL | fn parrot() -> &mut Trait { @@ -660,8 +660,8 @@ LL | fn parrot() -> &mut Trait { | help: use `impl Trait` to return an opaque type, as long as you return a single underlying type | -LL | fn parrot() -> impl Trait { - | ~~~~~~~~~~ +LL | fn parrot() -> &mut impl Trait { + | ++++ help: alternatively, you can return an owned trait object | LL | fn parrot() -> Box { From fa6d54f5c4373c19f0f63b64df483a5537b42c30 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 20 Aug 2024 15:59:35 +0300 Subject: [PATCH 010/156] don't copy `.rustc-dev-contents` from CI rustc Since https://github.com/rust-lang/rust/pull/127188, copying files from `.rustc-dev-contents` regressed https://github.com/rust-lang/rust/issues/108767 again. Since `rustc-src` is already included in the CI rustc sysroot, we don't need to copy these files to have `rustc-src` component. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/compile.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 4353cfadd8d3..e669f1064388 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1672,16 +1672,8 @@ impl Step for Sysroot { build_helper::exit!(1); } - // Unlike rust-src component, we have to handle rustc-src a bit differently. - // When using CI rustc, we copy rustc-src component from its sysroot, - // otherwise we handle it in a similar way what we do for rust-src above. - if builder.download_rustc() { - cp_rustc_component_to_ci_sysroot( - builder, - &sysroot, - builder.config.ci_rustc_dev_contents(), - ); - } else { + // rustc-src component is already part of CI rustc's sysroot + if !builder.download_rustc() { let sysroot_lib_rustlib_rustcsrc = sysroot.join("lib/rustlib/rustc-src"); t!(fs::create_dir_all(&sysroot_lib_rustlib_rustcsrc)); let sysroot_lib_rustlib_rustcsrc_rust = sysroot_lib_rustlib_rustcsrc.join("rust"); From 1aebff96ade6518038e0f7522d3304bd0f9bf891 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 6 Feb 2024 10:22:24 -0700 Subject: [PATCH 011/156] Add Top TOC support to rustdoc This commit adds the headers for the top level documentation to rustdoc's existing table of contents, along with associated items. It only show two levels of headers. Going further would require the sidebar to be wider, and that seems unnecessary (the crates that have manually-built TOCs usually don't need deeply nested headers). --- src/librustdoc/clean/types.rs | 6 - src/librustdoc/html/markdown.rs | 47 +++- src/librustdoc/html/render/context.rs | 3 +- src/librustdoc/html/render/sidebar.rs | 242 ++++++++++-------- src/librustdoc/html/static/css/rustdoc.css | 6 +- src/librustdoc/html/templates/sidebar.html | 17 +- src/librustdoc/html/toc.rs | 15 +- src/librustdoc/markdown.rs | 1 + tests/rustdoc-gui/sidebar.goml | 4 +- .../rustdoc/{ => sidebar}/sidebar-all-page.rs | 0 tests/rustdoc/{ => sidebar}/sidebar-items.rs | 0 .../{ => sidebar}/sidebar-link-generation.rs | 0 .../sidebar-links-to-foreign-impl.rs | 0 tests/rustdoc/sidebar/top-toc-html.rs | 19 ++ tests/rustdoc/sidebar/top-toc-idmap.rs | 44 ++++ 15 files changed, 271 insertions(+), 133 deletions(-) rename tests/rustdoc/{ => sidebar}/sidebar-all-page.rs (100%) rename tests/rustdoc/{ => sidebar}/sidebar-items.rs (100%) rename tests/rustdoc/{ => sidebar}/sidebar-link-generation.rs (100%) rename tests/rustdoc/{ => sidebar}/sidebar-links-to-foreign-impl.rs (100%) create mode 100644 tests/rustdoc/sidebar/top-toc-html.rs create mode 100644 tests/rustdoc/sidebar/top-toc-idmap.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ff5c16f2b3e9..3ba4ae4bd0c8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -506,9 +506,6 @@ impl Item { pub(crate) fn is_mod(&self) -> bool { self.type_() == ItemType::Module } - pub(crate) fn is_trait(&self) -> bool { - self.type_() == ItemType::Trait - } pub(crate) fn is_struct(&self) -> bool { self.type_() == ItemType::Struct } @@ -536,9 +533,6 @@ impl Item { pub(crate) fn is_ty_method(&self) -> bool { self.type_() == ItemType::TyMethod } - pub(crate) fn is_type_alias(&self) -> bool { - self.type_() == ItemType::TypeAlias - } pub(crate) fn is_primitive(&self) -> bool { self.type_() == ItemType::Primitive } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 7bfe5d87d399..58795508a582 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -55,7 +55,7 @@ use crate::html::format::Buffer; use crate::html::highlight; use crate::html::length_limit::HtmlWithLimit; use crate::html::render::small_url_encode; -use crate::html::toc::TocBuilder; +use crate::html::toc::{Toc, TocBuilder}; #[cfg(test)] mod tests; @@ -101,6 +101,7 @@ pub struct Markdown<'a> { /// A struct like `Markdown` that renders the markdown with a table of contents. pub(crate) struct MarkdownWithToc<'a> { pub(crate) content: &'a str, + pub(crate) links: &'a [RenderedLink], pub(crate) ids: &'a mut IdMap, pub(crate) error_codes: ErrorCodes, pub(crate) edition: Edition, @@ -532,9 +533,9 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator let id = self.id_map.derive(id); if let Some(ref mut builder) = self.toc { - let mut html_header = String::new(); - html::push_html(&mut html_header, self.buf.iter().map(|(ev, _)| ev.clone())); - let sec = builder.push(level as u32, html_header, id.clone()); + let mut text_header = String::new(); + plain_text_from_events(self.buf.iter().map(|(ev, _)| ev.clone()), &mut text_header); + let sec = builder.push(level as u32, text_header, id.clone()); self.buf.push_front((Event::Html(format!("{sec} ").into()), 0..0)); } @@ -1415,10 +1416,23 @@ impl Markdown<'_> { } impl MarkdownWithToc<'_> { - pub(crate) fn into_string(self) -> String { - let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self; + pub(crate) fn into_parts(self) -> (Toc, String) { + let MarkdownWithToc { content: md, links, ids, error_codes: codes, edition, playground } = + self; - let p = Parser::new_ext(md, main_body_opts()).into_offset_iter(); + // This is actually common enough to special-case + if md.is_empty() { + return (Toc { entries: Vec::new() }, String::new()); + } + let mut replacer = |broken_link: BrokenLink<'_>| { + links + .iter() + .find(|link| &*link.original_text == &*broken_link.reference) + .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) + }; + + let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer)); + let p = p.into_offset_iter(); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -1432,7 +1446,11 @@ impl MarkdownWithToc<'_> { html::push_html(&mut s, p); } - format!("{s}", toc = toc.into_toc().print()) + (toc.into_toc(), s) + } + pub(crate) fn into_string(self) -> String { + let (toc, s) = self.into_parts(); + format!("{s}", toc = toc.print()) } } @@ -1611,7 +1629,16 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer)); - for event in p { + plain_text_from_events(p, &mut s); + + s +} + +pub(crate) fn plain_text_from_events<'a>( + events: impl Iterator>, + s: &mut String, +) { + for event in events { match &event { Event::Text(text) => s.push_str(text), Event::Code(code) => { @@ -1626,8 +1653,6 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin _ => (), } } - - s } #[derive(Debug)] diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 0ed8921b1e8d..5734b59134a6 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -616,7 +616,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let all = shared.all.replace(AllTypes::new()); let mut sidebar = Buffer::html(); - let blocks = sidebar_module_like(all.item_sections()); + // all.html is not customizable, so a blank id map is fine + let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new()); let bar = Sidebar { title_prefix: "", title: "", diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 101cc839f098..a5a22618f223 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -7,12 +7,13 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefIdSet; use rustc_middle::ty::{self, TyCtxt}; +use crate::{ + clean, + formats::{item_type::ItemType, Impl}, + html::{format::Buffer, markdown::IdMap, markdown::MarkdownWithToc}, +}; + use super::{item_ty_to_section, Context, ItemSection}; -use crate::clean; -use crate::formats::item_type::ItemType; -use crate::formats::Impl; -use crate::html::format::Buffer; -use crate::html::markdown::IdMap; #[derive(Template)] #[template(path = "sidebar.html")] @@ -66,11 +67,13 @@ pub(crate) struct Link<'a> { name: Cow<'a, str>, /// The id of an anchor within the page (without a `#` prefix) href: Cow<'a, str>, + /// Nested list of links (used only in top-toc) + children: Vec>, } impl<'a> Link<'a> { pub fn new(href: impl Into>, name: impl Into>) -> Self { - Self { href: href.into(), name: name.into() } + Self { href: href.into(), name: name.into(), children: vec![] } } pub fn empty() -> Link<'static> { Link::new("", "") @@ -94,17 +97,19 @@ pub(crate) mod filters { } pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { - let blocks: Vec> = match *it.kind { - clean::StructItem(ref s) => sidebar_struct(cx, it, s), - clean::TraitItem(ref t) => sidebar_trait(cx, it, t), - clean::PrimitiveItem(_) => sidebar_primitive(cx, it), - clean::UnionItem(ref u) => sidebar_union(cx, it, u), - clean::EnumItem(ref e) => sidebar_enum(cx, it, e), - clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t), - clean::ModuleItem(ref m) => vec![sidebar_module(&m.items)], - clean::ForeignTypeItem => sidebar_foreign_type(cx, it), - _ => vec![], - }; + let mut ids = IdMap::new(); + let mut blocks: Vec> = docblock_toc(cx, it, &mut ids).into_iter().collect(); + match *it.kind { + clean::StructItem(ref s) => sidebar_struct(cx, it, s, &mut blocks), + clean::TraitItem(ref t) => sidebar_trait(cx, it, t, &mut blocks), + clean::PrimitiveItem(_) => sidebar_primitive(cx, it, &mut blocks), + clean::UnionItem(ref u) => sidebar_union(cx, it, u, &mut blocks), + clean::EnumItem(ref e) => sidebar_enum(cx, it, e, &mut blocks), + clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t, &mut blocks), + clean::ModuleItem(ref m) => blocks.push(sidebar_module(&m.items, &mut ids)), + clean::ForeignTypeItem => sidebar_foreign_type(cx, it, &mut blocks), + _ => {} + } // The sidebar is designed to display sibling functions, modules and // other miscellaneous information. since there are lots of sibling // items (and that causes quadratic growth in large modules), @@ -112,15 +117,9 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf // still, we don't move everything into JS because we want to preserve // as much HTML as possible in order to allow non-JS-enabled browsers // to navigate the documentation (though slightly inefficiently). - let (title_prefix, title) = if it.is_struct() - || it.is_trait() - || it.is_primitive() - || it.is_union() - || it.is_enum() - // crate title is displayed as part of logo lockup - || (it.is_mod() && !it.is_crate()) - || it.is_type_alias() - { + // + // crate title is displayed as part of logo lockup + let (title_prefix, title) = if !blocks.is_empty() && !it.is_crate() { ( match *it.kind { clean::ModuleItem(..) => "Module ", @@ -162,30 +161,75 @@ fn get_struct_fields_name<'a>(fields: &'a [clean::Item]) -> Vec> { fields } +fn docblock_toc<'a>( + cx: &'a Context<'_>, + it: &'a clean::Item, + ids: &mut IdMap, +) -> Option> { + let (toc, _) = MarkdownWithToc { + content: &it.doc_value(), + links: &it.links(cx), + ids, + error_codes: cx.shared.codes, + edition: cx.shared.edition(), + playground: &cx.shared.playground, + custom_code_classes_in_docs: cx.tcx().features().custom_code_classes_in_docs, + } + .into_parts(); + let links: Vec> = toc + .entries + .into_iter() + .map(|entry| { + Link { + name: entry.name.into(), + href: entry.id.into(), + children: entry + .children + .entries + .into_iter() + .map(|entry| Link { + name: entry.name.into(), + href: entry.id.into(), + // Only a single level of nesting is shown here. + // Going the full six could break the layout, + // so we have to cut it off somewhere. + children: vec![], + }) + .collect(), + } + }) + .collect(); + if links.is_empty() { + None + } else { + Some(LinkBlock::new(Link::new("#", "Sections"), "top-toc", links)) + } +} + fn sidebar_struct<'a>( cx: &'a Context<'_>, it: &'a clean::Item, s: &'a clean::Struct, -) -> Vec> { + items: &mut Vec>, +) { let fields = get_struct_fields_name(&s.fields); let field_name = match s.ctor_kind { Some(CtorKind::Fn) => Some("Tuple Fields"), None => Some("Fields"), _ => None, }; - let mut items = vec![]; if let Some(name) = field_name { items.push(LinkBlock::new(Link::new("fields", name), "structfield", fields)); } - sidebar_assoc_items(cx, it, &mut items); - items + sidebar_assoc_items(cx, it, items); } fn sidebar_trait<'a>( cx: &'a Context<'_>, it: &'a clean::Item, t: &'a clean::Trait, -) -> Vec> { + blocks: &mut Vec>, +) { fn filter_items<'a>( items: &'a [clean::Item], filt: impl Fn(&clean::Item) -> bool, @@ -222,19 +266,20 @@ fn sidebar_trait<'a>( foreign_impls.sort(); } - let mut blocks: Vec> = [ - ("required-associated-types", "Required Associated Types", req_assoc), - ("provided-associated-types", "Provided Associated Types", prov_assoc), - ("required-associated-consts", "Required Associated Constants", req_assoc_const), - ("provided-associated-consts", "Provided Associated Constants", prov_assoc_const), - ("required-methods", "Required Methods", req_method), - ("provided-methods", "Provided Methods", prov_method), - ("foreign-impls", "Implementations on Foreign Types", foreign_impls), - ] - .into_iter() - .map(|(id, title, items)| LinkBlock::new(Link::new(id, title), "", items)) - .collect(); - sidebar_assoc_items(cx, it, &mut blocks); + blocks.extend( + [ + ("required-associated-types", "Required Associated Types", req_assoc), + ("provided-associated-types", "Provided Associated Types", prov_assoc), + ("required-associated-consts", "Required Associated Constants", req_assoc_const), + ("provided-associated-consts", "Provided Associated Constants", prov_assoc_const), + ("required-methods", "Required Methods", req_method), + ("provided-methods", "Provided Methods", prov_method), + ("foreign-impls", "Implementations on Foreign Types", foreign_impls), + ] + .into_iter() + .map(|(id, title, items)| LinkBlock::new(Link::new(id, title), "", items)), + ); + sidebar_assoc_items(cx, it, blocks); if !t.is_object_safe(cx.tcx()) { blocks.push(LinkBlock::forced( @@ -250,20 +295,17 @@ fn sidebar_trait<'a>( "impl-auto", )); } - blocks } -fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec> { +fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item, items: &mut Vec>) { if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) { - let mut items = vec![]; - sidebar_assoc_items(cx, it, &mut items); - items + sidebar_assoc_items(cx, it, items); } else { let shared = Rc::clone(&cx.shared); let (concrete, synthetic, blanket_impl) = super::get_filtered_impls_for_reference(&shared, it); - sidebar_render_assoc_items(cx, &mut IdMap::new(), concrete, synthetic, blanket_impl).into() + sidebar_render_assoc_items(cx, &mut IdMap::new(), concrete, synthetic, blanket_impl, items); } } @@ -271,8 +313,8 @@ fn sidebar_type_alias<'a>( cx: &'a Context<'_>, it: &'a clean::Item, t: &'a clean::TypeAlias, -) -> Vec> { - let mut items = vec![]; + items: &mut Vec>, +) { if let Some(inner_type) = &t.inner_type { items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased type"), "type")); match inner_type { @@ -294,19 +336,18 @@ fn sidebar_type_alias<'a>( } } } - sidebar_assoc_items(cx, it, &mut items); - items + sidebar_assoc_items(cx, it, items); } fn sidebar_union<'a>( cx: &'a Context<'_>, it: &'a clean::Item, u: &'a clean::Union, -) -> Vec> { + items: &mut Vec>, +) { let fields = get_struct_fields_name(&u.fields); - let mut items = vec![LinkBlock::new(Link::new("fields", "Fields"), "structfield", fields)]; - sidebar_assoc_items(cx, it, &mut items); - items + items.push(LinkBlock::new(Link::new("fields", "Fields"), "structfield", fields)); + sidebar_assoc_items(cx, it, items); } /// Adds trait implementations into the blocks of links @@ -345,33 +386,6 @@ fn sidebar_assoc_items<'a>( methods.sort(); } - let mut deref_methods = Vec::new(); - let [concrete, synthetic, blanket] = if v.iter().any(|i| i.inner_impl().trait_.is_some()) { - if let Some(impl_) = - v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait()) - { - let mut derefs = DefIdSet::default(); - derefs.insert(did); - sidebar_deref_methods( - cx, - &mut deref_methods, - impl_, - v, - &mut derefs, - &mut used_links, - ); - } - - let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = - v.iter().partition::, _>(|i| i.inner_impl().kind.is_auto()); - let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = - concrete.into_iter().partition::, _>(|i| i.inner_impl().kind.is_blanket()); - - sidebar_render_assoc_items(cx, &mut id_map, concrete, synthetic, blanket_impl) - } else { - std::array::from_fn(|_| LinkBlock::new(Link::empty(), "", vec![])) - }; - let mut blocks = vec![ LinkBlock::new( Link::new("implementations", "Associated Constants"), @@ -380,8 +394,30 @@ fn sidebar_assoc_items<'a>( ), LinkBlock::new(Link::new("implementations", "Methods"), "method", methods), ]; - blocks.append(&mut deref_methods); - blocks.extend([concrete, synthetic, blanket]); + + if v.iter().any(|i| i.inner_impl().trait_.is_some()) { + if let Some(impl_) = + v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait()) + { + let mut derefs = DefIdSet::default(); + derefs.insert(did); + sidebar_deref_methods(cx, &mut blocks, impl_, v, &mut derefs, &mut used_links); + } + + let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = + v.iter().partition::, _>(|i| i.inner_impl().kind.is_auto()); + let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = + concrete.into_iter().partition::, _>(|i| i.inner_impl().kind.is_blanket()); + + sidebar_render_assoc_items( + cx, + &mut id_map, + concrete, + synthetic, + blanket_impl, + &mut blocks, + ); + } links.append(&mut blocks); } } @@ -471,7 +507,8 @@ fn sidebar_enum<'a>( cx: &'a Context<'_>, it: &'a clean::Item, e: &'a clean::Enum, -) -> Vec> { + items: &mut Vec>, +) { let mut variants = e .variants() .filter_map(|v| v.name) @@ -479,24 +516,24 @@ fn sidebar_enum<'a>( .collect::>(); variants.sort_unstable(); - let mut items = vec![LinkBlock::new(Link::new("variants", "Variants"), "variant", variants)]; - sidebar_assoc_items(cx, it, &mut items); - items + items.push(LinkBlock::new(Link::new("variants", "Variants"), "variant", variants)); + sidebar_assoc_items(cx, it, items); } pub(crate) fn sidebar_module_like( item_sections_in_use: FxHashSet, + ids: &mut IdMap, ) -> LinkBlock<'static> { let item_sections = ItemSection::ALL .iter() .copied() .filter(|sec| item_sections_in_use.contains(sec)) - .map(|sec| Link::new(sec.id(), sec.name())) + .map(|sec| Link::new(ids.derive(sec.id()), sec.name())) .collect(); LinkBlock::new(Link::empty(), "", item_sections) } -fn sidebar_module(items: &[clean::Item]) -> LinkBlock<'static> { +fn sidebar_module(items: &[clean::Item], ids: &mut IdMap) -> LinkBlock<'static> { let item_sections_in_use: FxHashSet<_> = items .iter() .filter(|it| { @@ -517,13 +554,15 @@ fn sidebar_module(items: &[clean::Item]) -> LinkBlock<'static> { .map(|it| item_ty_to_section(it.type_())) .collect(); - sidebar_module_like(item_sections_in_use) + sidebar_module_like(item_sections_in_use, ids) } -fn sidebar_foreign_type<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec> { - let mut items = vec![]; - sidebar_assoc_items(cx, it, &mut items); - items +fn sidebar_foreign_type<'a>( + cx: &'a Context<'_>, + it: &'a clean::Item, + items: &mut Vec>, +) { + sidebar_assoc_items(cx, it, items); } /// Renders the trait implementations for this type @@ -533,7 +572,8 @@ fn sidebar_render_assoc_items( concrete: Vec<&Impl>, synthetic: Vec<&Impl>, blanket_impl: Vec<&Impl>, -) -> [LinkBlock<'static>; 3] { + items: &mut Vec>, +) { let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| { let mut links = FxHashSet::default(); @@ -558,7 +598,7 @@ fn sidebar_render_assoc_items( let concrete = format_impls(concrete, id_map); let synthetic = format_impls(synthetic, id_map); let blanket = format_impls(blanket_impl, id_map); - [ + items.extend([ LinkBlock::new( Link::new("trait-implementations", "Trait Implementations"), "trait-implementation", @@ -574,7 +614,7 @@ fn sidebar_render_assoc_items( "blanket-implementation", blanket, ), - ] + ]); } fn get_next_url(used_links: &mut FxHashSet, url: String) -> String { diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index eb5a5d935e20..58e27735035f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -568,12 +568,16 @@ img { width: 48px; } -ul.block, .block li { +ul.block, .block li, .block ul { padding: 0; margin: 0; list-style: none; } +.block ul { + margin-left: 12px; +} + .sidebar-elems a, .sidebar > h2 a { display: block; diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index 0990c2716b8f..ac6aa849f5c8 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -15,14 +15,23 @@ {% for block in blocks %} {% if block.should_render() %} {% if !block.heading.name.is_empty() %} -

{# #} - {{block.heading.name|wrapped|safe}} {# #} -

{# #} + {# #} + {{block.heading.name|wrapped|safe}} {# #} + {# #} {% endif %} {% if !block.links.is_empty() %}
    {% for link in block.links %} -
  • {{link.name}}
  • +
  • {# #} + {{link.name}} {# #} + {% if !link.children.is_empty() %} +
      {# #} + {% for child in link.children %} +
    • {{child.name}}
    • + {% endfor %} +
    {# #} + {% endif %} +
  • {# #} {% endfor %}
{% endif %} diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs index a12c2a6a16c3..a44c4a1b59ee 100644 --- a/src/librustdoc/html/toc.rs +++ b/src/librustdoc/html/toc.rs @@ -1,4 +1,5 @@ //! Table-of-contents creation. +use crate::html::escape::EscapeBodyText; /// A (recursive) table of contents #[derive(Debug, PartialEq)] @@ -16,7 +17,7 @@ pub(crate) struct Toc { /// ### A /// ## B /// ``` - entries: Vec, + pub(crate) entries: Vec, } impl Toc { @@ -27,11 +28,11 @@ impl Toc { #[derive(Debug, PartialEq)] pub(crate) struct TocEntry { - level: u32, - sec_number: String, - name: String, - id: String, - children: Toc, + pub(crate) level: u32, + pub(crate) sec_number: String, + pub(crate) name: String, + pub(crate) id: String, + pub(crate) children: Toc, } /// Progressive construction of a table of contents. @@ -173,7 +174,7 @@ impl Toc { "\n
  • {num} {name}", id = entry.id, num = entry.sec_number, - name = entry.name + name = EscapeBodyText(&entry.name) ); entry.children.print_inner(&mut *v); v.push_str("
  • "); diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index a98f81d011e8..581ebbbe58d7 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -72,6 +72,7 @@ pub(crate) fn render>( let text = if !options.markdown_no_toc { MarkdownWithToc { content: text, + links: &[], ids: &mut ids, error_codes, edition, diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index e499c159c6c7..5ac36bd4cc27 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -118,7 +118,7 @@ assert-false: ".sidebar-elems > .crate" go-to: "./module/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") -assert-text: (".sidebar > .location", "Module module") +assert-text: (".sidebar .location", "Module module") assert-count: (".sidebar .location", 1) assert-text: (".sidebar-elems ul.block > li.current > a", "module") // Module page requires three headings: @@ -136,7 +136,7 @@ assert-false: ".sidebar-elems > .crate" go-to: "./sub_module/sub_sub_module/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") -assert-text: (".sidebar > .location", "Module sub_sub_module") +assert-text: (".sidebar .location", "Module sub_sub_module") assert-text: (".sidebar > .sidebar-elems > h2", "In lib2::module::sub_module") assert-property: (".sidebar > .sidebar-elems > h2 > a", { "href": "/module/sub_module/index.html", diff --git a/tests/rustdoc/sidebar-all-page.rs b/tests/rustdoc/sidebar/sidebar-all-page.rs similarity index 100% rename from tests/rustdoc/sidebar-all-page.rs rename to tests/rustdoc/sidebar/sidebar-all-page.rs diff --git a/tests/rustdoc/sidebar-items.rs b/tests/rustdoc/sidebar/sidebar-items.rs similarity index 100% rename from tests/rustdoc/sidebar-items.rs rename to tests/rustdoc/sidebar/sidebar-items.rs diff --git a/tests/rustdoc/sidebar-link-generation.rs b/tests/rustdoc/sidebar/sidebar-link-generation.rs similarity index 100% rename from tests/rustdoc/sidebar-link-generation.rs rename to tests/rustdoc/sidebar/sidebar-link-generation.rs diff --git a/tests/rustdoc/sidebar-links-to-foreign-impl.rs b/tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs similarity index 100% rename from tests/rustdoc/sidebar-links-to-foreign-impl.rs rename to tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs new file mode 100644 index 000000000000..6fc84c1964c3 --- /dev/null +++ b/tests/rustdoc/sidebar/top-toc-html.rs @@ -0,0 +1,19 @@ +// ignore-tidy-linelength + +#![crate_name = "foo"] +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +//! # Basic [link](https://example.com) and *emphasis* +//! +//! This test case covers TOC entries with rich text inside. +//! Rustdoc normally supports headers with links, but for the +//! TOC, that would break the layout. +//! +//! For consistency, emphasis is also filtered out. + +// @has foo/index.html +// User header +// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]' 'Basic link and emphasis' +// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/em' 0 +// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/a' 0 diff --git a/tests/rustdoc/sidebar/top-toc-idmap.rs b/tests/rustdoc/sidebar/top-toc-idmap.rs new file mode 100644 index 000000000000..ccfc7336e9f2 --- /dev/null +++ b/tests/rustdoc/sidebar/top-toc-idmap.rs @@ -0,0 +1,44 @@ +#![crate_name = "foo"] +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +//! # Structs +//! +//! This header has the same name as a built-in header, +//! and we need to make sure they're disambiguated with +//! suffixes. +//! +//! Module-like headers get derived from the internal ID map, +//! so the *internal* one gets a suffix here. To make sure it +//! works right, the one in the `top-toc` needs to match the one +//! in the `top-doc`, and the one that's not in the `top-doc` +//! needs to match the one that isn't in the `top-toc`. + +// @has foo/index.html +// User header +// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs' +// @has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs' +// Built-in header +// @has - '//section[@id="TOC"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs' +// @has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs' + +/// # Fields +/// ## Fields +/// ### Fields +/// +/// The difference between struct-like headers and module-like headers +/// is strange, but not actually a problem as long as we're consistent. + +// @has foo/struct.MyStruct.html +// User header +// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields' +// @has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields' +// Only one level of nesting +// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]//a' 2 +// Built-in header +// @has - '//section[@id="TOC"]/h3/a[@href="#fields"]' 'Fields' +// @has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields' + +pub struct MyStruct { + pub fields: i32, +} From a7aea5d96bcafb7046ed7440122395e7f5e5d43d Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 6 Feb 2024 18:21:48 -0700 Subject: [PATCH 012/156] Add configuration options to hide TOC or module navigation --- src/librustdoc/html/render/context.rs | 1 + src/librustdoc/html/render/sidebar.rs | 15 +++++--- src/librustdoc/html/static/css/rustdoc.css | 12 +++++-- src/librustdoc/html/static/js/main.js | 4 +-- src/librustdoc/html/static/js/settings.js | 29 +++++++++++++++ src/librustdoc/html/static/js/storage.js | 13 ++++--- src/librustdoc/html/templates/sidebar.html | 20 ++++++----- tests/rustdoc-gui/sidebar.goml | 41 +++++++++++++++++++--- 8 files changed, 111 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 5734b59134a6..a167681b3163 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -623,6 +623,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { title: "", is_crate: false, is_mod: false, + parent_is_crate: false, blocks: vec![blocks], path: String::new(), }; diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index a5a22618f223..5e59754da79c 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -21,6 +21,7 @@ pub(super) struct Sidebar<'a> { pub(super) title_prefix: &'static str, pub(super) title: &'a str, pub(super) is_crate: bool, + pub(super) parent_is_crate: bool, pub(super) is_mod: bool, pub(super) blocks: Vec>, pub(super) path: String, @@ -144,8 +145,15 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf } else { "".into() }; - let sidebar = - Sidebar { title_prefix, title, is_mod: it.is_mod(), is_crate: it.is_crate(), blocks, path }; + let sidebar = Sidebar { + title_prefix, + title, + is_mod: it.is_mod(), + is_crate: it.is_crate(), + parent_is_crate: sidebar_path.len() == 1, + blocks, + path, + }; sidebar.render_into(buffer).unwrap(); } @@ -173,7 +181,6 @@ fn docblock_toc<'a>( error_codes: cx.shared.codes, edition: cx.shared.edition(), playground: &cx.shared.playground, - custom_code_classes_in_docs: cx.tcx().features().custom_code_classes_in_docs, } .into_parts(); let links: Vec> = toc @@ -202,7 +209,7 @@ fn docblock_toc<'a>( if links.is_empty() { None } else { - Some(LinkBlock::new(Link::new("#", "Sections"), "top-toc", links)) + Some(LinkBlock::new(Link::new("", "Sections"), "top-toc", links)) } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 58e27735035f..c2bb5fa8f2ac 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -574,8 +574,8 @@ ul.block, .block li, .block ul { list-style: none; } -.block ul { - margin-left: 12px; +.block ul a { + padding-left: 1rem; } .sidebar-elems a, @@ -589,6 +589,14 @@ ul.block, .block li, .block ul { background-clip: border-box; } +.hide-toc #TOC, .hide-toc .in-crate { + display: none; +} + +.hide-modnav #ModNav { + display: none; +} + .sidebar h2 { text-wrap: balance; overflow-wrap: anywhere; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 75f2a1418cd8..4135341b22e9 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -499,7 +499,7 @@ function preLoadCss(cssUrl) { if (!window.SIDEBAR_ITEMS) { return; } - const sidebar = document.getElementsByClassName("sidebar-elems")[0]; + const sidebar = document.getElementById("ModNav"); /** * Append to the sidebar a "block" of links - a heading along with a list (`
      `) of items. @@ -885,7 +885,7 @@ function preLoadCss(cssUrl) { if (!window.ALL_CRATES) { return; } - const sidebarElems = document.getElementsByClassName("sidebar-elems")[0]; + const sidebarElems = document.getElementById("ModNav"); if (!sidebarElems) { return; } diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 2b42fbebb803..c52a19ef9873 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -36,6 +36,20 @@ removeClass(document.documentElement, "hide-sidebar"); } break; + case "hide-toc": + if (value === true) { + addClass(document.documentElement, "hide-toc"); + } else { + removeClass(document.documentElement, "hide-toc"); + } + break; + case "hide-modnav": + if (value === true) { + addClass(document.documentElement, "hide-modnav"); + } else { + removeClass(document.documentElement, "hide-modnav"); + } + break; } } @@ -102,6 +116,11 @@ let output = ""; for (const setting of settings) { + if (setting === "hr") { + output += "
      "; + continue; + } + const js_data_name = setting["js_name"]; const setting_name = setting["name"]; @@ -198,6 +217,16 @@ "js_name": "hide-sidebar", "default": false, }, + { + "name": "Hide table of contents", + "js_name": "hide-toc", + "default": false, + }, + { + "name": "Hide module navigation", + "js_name": "hide-modnav", + "default": false, + }, { "name": "Disable keyboard shortcuts", "js_name": "disable-shortcuts", diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 4a27ca92fff3..d75fb7a7fb5a 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -196,16 +196,21 @@ updateTheme(); // This needs to be done here because this JS is render-blocking, // so that the sidebar doesn't "jump" after appearing on screen. // The user interaction to change this is set up in main.js. +// +// At this point in page load, `document.body` is not available yet. +// Set a class on the `` element instead. if (getSettingValue("source-sidebar-show") === "true") { - // At this point in page load, `document.body` is not available yet. - // Set a class on the `` element instead. addClass(document.documentElement, "src-sidebar-expanded"); } if (getSettingValue("hide-sidebar") === "true") { - // At this point in page load, `document.body` is not available yet. - // Set a class on the `` element instead. addClass(document.documentElement, "hide-sidebar"); } +if (getSettingValue("hide-toc") === "true") { + addClass(document.documentElement, "hide-toc"); +} +if (getSettingValue("hide-modnav") === "true") { + addClass(document.documentElement, "hide-modnav"); +} function updateSidebarWidth() { const desktopSidebarWidth = getSettingValue("desktop-sidebar-width"); if (desktopSidebarWidth && desktopSidebarWidth !== "null") { diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index ac6aa849f5c8..c0a9b2544259 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -1,8 +1,3 @@ -{% if !title.is_empty() %} -

      {# #} - {{title_prefix}}{{title|wrapped|safe}} {# #} -

      -{% endif %} diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index 5ac36bd4cc27..3253e6ea86a8 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -126,8 +126,8 @@ assert-text: (".sidebar-elems ul.block > li.current > a", "module") // - Module name, followed by TOC for module headings // - "In crate [name]" parent pointer, followed by sibling navigation assert-count: (".sidebar h2", 3) -assert-text: (".sidebar > .sidebar-elems > h2", "In crate lib2") -assert-property: (".sidebar > .sidebar-elems > h2 > a", { +assert-text: (".sidebar > .sidebar-elems > #ModNav > h2", "In crate lib2") +assert-property: (".sidebar > .sidebar-elems > #ModNav > h2 > a", { "href": "/lib2/index.html", }, ENDS_WITH) // We check that we don't have the crate list. @@ -137,8 +137,8 @@ go-to: "./sub_module/sub_sub_module/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") assert-text: (".sidebar .location", "Module sub_sub_module") -assert-text: (".sidebar > .sidebar-elems > h2", "In lib2::module::sub_module") -assert-property: (".sidebar > .sidebar-elems > h2 > a", { +assert-text: (".sidebar > .sidebar-elems > #ModNav > h2", "In lib2::module::sub_module") +assert-property: (".sidebar > .sidebar-elems > #ModNav > h2 > a", { "href": "/module/sub_module/index.html", }, ENDS_WITH) assert-text: (".sidebar-elems ul.block > li.current > a", "sub_sub_module") @@ -198,3 +198,36 @@ assert-position-false: (".sidebar-crate > h2 > a", {"x": -3}) // when line-wrapped, see that it becomes flush-left again drag-and-drop: ((205, 100), (108, 100)) assert-position: (".sidebar-crate > h2 > a", {"x": -3}) + +// Configuration option to show TOC in sidebar. +set-local-storage: {"rustdoc-hide-toc": "true"} +go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" +assert-css: ("#TOC", {"display": "none"}) +assert-css: (".sidebar .in-crate", {"display": "none"}) +set-local-storage: {"rustdoc-hide-toc": "false"} +go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" +assert-css: ("#TOC", {"display": "block"}) +assert-css: (".sidebar .in-crate", {"display": "block"}) + +set-local-storage: {"rustdoc-hide-modnav": "true"} +go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" +assert-css: ("#ModNav", {"display": "none"}) +set-local-storage: {"rustdoc-hide-modnav": "false"} +go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" +assert-css: ("#ModNav", {"display": "block"}) + +set-local-storage: {"rustdoc-hide-toc": "true"} +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +assert-css: ("#TOC", {"display": "none"}) +assert-false: ".sidebar .in-crate" +set-local-storage: {"rustdoc-hide-toc": "false"} +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +assert-css: ("#TOC", {"display": "block"}) +assert-false: ".sidebar .in-crate" + +set-local-storage: {"rustdoc-hide-modnav": "true"} +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +assert-css: ("#ModNav", {"display": "none"}) +set-local-storage: {"rustdoc-hide-modnav": "false"} +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +assert-css: ("#ModNav", {"display": "block"}) From 5a6054b4a2850d195bf54d7176b4a32382a8df49 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 22 Jul 2024 10:31:24 -0700 Subject: [PATCH 013/156] rustdoc: add separate section for module items --- src/librustdoc/html/render/context.rs | 9 +++++--- src/librustdoc/html/render/sidebar.rs | 27 +++++++++++++++++++--- src/librustdoc/html/templates/sidebar.html | 10 ++++---- tests/rustdoc/sidebar/top-toc-nil.rs | 7 ++++++ 4 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 tests/rustdoc/sidebar/top-toc-nil.rs diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index a167681b3163..510da99c9eff 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -14,9 +14,12 @@ use rustc_span::edition::Edition; use rustc_span::{sym, FileName, Symbol}; use super::print_item::{full_path, item_path, print_item}; -use super::sidebar::{print_sidebar, sidebar_module_like, Sidebar}; use super::write_shared::write_shared; -use super::{collect_spans_and_sources, scrape_examples_help, AllTypes, LinkFromSrc, StylePath}; +use super::{ + collect_spans_and_sources, scrape_examples_help, + sidebar::{print_sidebar, sidebar_module_like, ModuleLike, Sidebar}, + AllTypes, LinkFromSrc, StylePath, +}; use crate::clean::types::ExternalLocation; use crate::clean::utils::has_doc_flag; use crate::clean::{self, ExternalCrate}; @@ -617,7 +620,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let mut sidebar = Buffer::html(); // all.html is not customizable, so a blank id map is fine - let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new()); + let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new(), ModuleLike::Crate); let bar = Sidebar { title_prefix: "", title: "", diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 5e59754da79c..c76253c9fc3c 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -15,6 +15,18 @@ use crate::{ use super::{item_ty_to_section, Context, ItemSection}; +#[derive(Clone, Copy)] +pub(crate) enum ModuleLike { + Module, + Crate, +} + +impl ModuleLike { + pub(crate) fn is_crate(self) -> bool { + matches!(self, ModuleLike::Crate) + } +} + #[derive(Template)] #[template(path = "sidebar.html")] pub(super) struct Sidebar<'a> { @@ -530,14 +542,23 @@ fn sidebar_enum<'a>( pub(crate) fn sidebar_module_like( item_sections_in_use: FxHashSet, ids: &mut IdMap, + module_like: ModuleLike, ) -> LinkBlock<'static> { - let item_sections = ItemSection::ALL + let item_sections: Vec> = ItemSection::ALL .iter() .copied() .filter(|sec| item_sections_in_use.contains(sec)) .map(|sec| Link::new(ids.derive(sec.id()), sec.name())) .collect(); - LinkBlock::new(Link::empty(), "", item_sections) + let header = if let Some(first_section) = item_sections.get(0) { + Link::new( + first_section.href.to_owned(), + if module_like.is_crate() { "Crate Items" } else { "Module Items" }, + ) + } else { + Link::empty() + }; + LinkBlock::new(header, "", item_sections) } fn sidebar_module(items: &[clean::Item], ids: &mut IdMap) -> LinkBlock<'static> { @@ -561,7 +582,7 @@ fn sidebar_module(items: &[clean::Item], ids: &mut IdMap) -> LinkBlock<'static> .map(|it| item_ty_to_section(it.type_())) .collect(); - sidebar_module_like(item_sections_in_use, ids) + sidebar_module_like(item_sections_in_use, ids, ModuleLike::Module) } fn sidebar_foreign_type<'a>( diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index c0a9b2544259..f49cdbabb885 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -17,7 +17,7 @@ {% if !block.heading.name.is_empty() %}

      {# #} {{block.heading.name|wrapped|safe}} {# #} -

      {# #} + {% endif %} {% if !block.links.is_empty() %}
        @@ -25,13 +25,13 @@
      • {# #} {{link.name}} {# #} {% if !link.children.is_empty() %} -
          {# #} + {# #} +
        {% endif %} -
      • {# #} + {% endfor %}
      {% endif %} @@ -43,7 +43,7 @@ {% if !path.is_empty() %} {# #} In {{+ path|wrapped|safe}} {# #} - {# #} + {% endif %} {# #} diff --git a/tests/rustdoc/sidebar/top-toc-nil.rs b/tests/rustdoc/sidebar/top-toc-nil.rs new file mode 100644 index 000000000000..91c7df50ab48 --- /dev/null +++ b/tests/rustdoc/sidebar/top-toc-nil.rs @@ -0,0 +1,7 @@ +#![crate_name = "foo"] + +//! This test case covers missing top TOC entries. + +// @has foo/index.html +// User header +// @!has - '//section[@id="TOC"]/ul[@class="block top-toc"]' 'Basic link and emphasis' From 68773c789a6a84a888b69f7287fd294b6dd3625c Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 22 Jul 2024 11:12:38 -0700 Subject: [PATCH 014/156] rustdoc: add separate section for module items --- src/librustdoc/html/render/sidebar.rs | 17 ++++++++++++++--- tests/rustdoc/sidebar/module.rs | 16 ++++++++++++++++ tests/rustdoc/sidebar/top-toc-html.rs | 1 + 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 tests/rustdoc/sidebar/module.rs diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index c76253c9fc3c..a6b22a18de26 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -26,6 +26,11 @@ impl ModuleLike { matches!(self, ModuleLike::Crate) } } +impl<'a> From<&'a clean::Item> for ModuleLike { + fn from(it: &'a clean::Item) -> ModuleLike { + if it.is_crate() { ModuleLike::Crate } else { ModuleLike::Module } + } +} #[derive(Template)] #[template(path = "sidebar.html")] @@ -119,7 +124,9 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf clean::UnionItem(ref u) => sidebar_union(cx, it, u, &mut blocks), clean::EnumItem(ref e) => sidebar_enum(cx, it, e, &mut blocks), clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t, &mut blocks), - clean::ModuleItem(ref m) => blocks.push(sidebar_module(&m.items, &mut ids)), + clean::ModuleItem(ref m) => { + blocks.push(sidebar_module(&m.items, &mut ids, ModuleLike::from(it))) + } clean::ForeignTypeItem => sidebar_foreign_type(cx, it, &mut blocks), _ => {} } @@ -561,7 +568,11 @@ pub(crate) fn sidebar_module_like( LinkBlock::new(header, "", item_sections) } -fn sidebar_module(items: &[clean::Item], ids: &mut IdMap) -> LinkBlock<'static> { +fn sidebar_module( + items: &[clean::Item], + ids: &mut IdMap, + module_like: ModuleLike, +) -> LinkBlock<'static> { let item_sections_in_use: FxHashSet<_> = items .iter() .filter(|it| { @@ -582,7 +593,7 @@ fn sidebar_module(items: &[clean::Item], ids: &mut IdMap) -> LinkBlock<'static> .map(|it| item_ty_to_section(it.type_())) .collect(); - sidebar_module_like(item_sections_in_use, ids, ModuleLike::Module) + sidebar_module_like(item_sections_in_use, ids, module_like) } fn sidebar_foreign_type<'a>( diff --git a/tests/rustdoc/sidebar/module.rs b/tests/rustdoc/sidebar/module.rs new file mode 100644 index 000000000000..926af71ddfb8 --- /dev/null +++ b/tests/rustdoc/sidebar/module.rs @@ -0,0 +1,16 @@ +#![crate_name = "foo"] + +//@ has 'foo/index.html' +//@ has - '//section[@id="TOC"]/h3' 'Crate Items' + +//@ has 'foo/bar/index.html' +//@ has - '//section[@id="TOC"]/h3' 'Module Items' +pub mod bar { + //@ has 'foo/bar/struct.Baz.html' + //@ !has - '//section[@id="TOC"]/h3' 'Module Items' + pub struct Baz; +} + +//@ has 'foo/baz/index.html' +//@ !has - '//section[@id="TOC"]/h3' 'Module Items' +pub mod baz {} diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs index 6fc84c1964c3..fa1325c8dca0 100644 --- a/tests/rustdoc/sidebar/top-toc-html.rs +++ b/tests/rustdoc/sidebar/top-toc-html.rs @@ -14,6 +14,7 @@ // @has foo/index.html // User header +// @has - '//section[@id="TOC"]/h3' 'Sections' // @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]' 'Basic link and emphasis' // @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/em' 0 // @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/a' 0 From 7091fa5880db84392783147171f5709b72ffa784 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 22 Jul 2024 12:59:34 -0700 Subject: [PATCH 015/156] rustdoc: show code spans as `` in TOC --- src/librustdoc/html/markdown.rs | 29 +++++++++++++++++-- src/librustdoc/html/render/sidebar.rs | 12 ++++++-- src/librustdoc/html/templates/sidebar.html | 18 ++++++++++-- src/librustdoc/html/toc.rs | 15 +++++++--- src/librustdoc/html/toc/tests.rs | 6 +++- tests/rustdoc/sidebar/top-toc-html.rs | 15 ++++++---- tests/rustdoc/sidebar/top-toc-idmap.rs | 22 +++++++------- tests/rustdoc/sidebar/top-toc-nil.rs | 4 +-- .../strip-enum-variant.no-not-shown.html | 2 +- 9 files changed, 92 insertions(+), 31 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 58795508a582..4b82f2327653 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -50,7 +50,7 @@ use rustc_span::{Span, Symbol}; use crate::clean::RenderedLink; use crate::doctest; use crate::doctest::GlobalTestOptions; -use crate::html::escape::Escape; +use crate::html::escape::{Escape, EscapeBodyText}; use crate::html::format::Buffer; use crate::html::highlight; use crate::html::length_limit::HtmlWithLimit; @@ -535,7 +535,9 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator if let Some(ref mut builder) = self.toc { let mut text_header = String::new(); plain_text_from_events(self.buf.iter().map(|(ev, _)| ev.clone()), &mut text_header); - let sec = builder.push(level as u32, text_header, id.clone()); + let mut html_header = String::new(); + html_text_from_events(self.buf.iter().map(|(ev, _)| ev.clone()), &mut html_header); + let sec = builder.push(level as u32, text_header, html_header, id.clone()); self.buf.push_front((Event::Html(format!("{sec} ").into()), 0..0)); } @@ -1655,6 +1657,29 @@ pub(crate) fn plain_text_from_events<'a>( } } +pub(crate) fn html_text_from_events<'a>( + events: impl Iterator>, + s: &mut String, +) { + for event in events { + match &event { + Event::Text(text) => { + write!(s, "{}", EscapeBodyText(text)).expect("string alloc infallible") + } + Event::Code(code) => { + s.push_str(""); + write!(s, "{}", EscapeBodyText(code)).expect("string alloc infallible"); + s.push_str(""); + } + Event::HardBreak | Event::SoftBreak => s.push(' '), + Event::Start(Tag::CodeBlock(..)) => break, + Event::End(TagEnd::Paragraph) => break, + Event::End(TagEnd::Heading(..)) => break, + _ => (), + } + } +} + #[derive(Debug)] pub(crate) struct MarkdownLink { pub kind: LinkType, diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index a6b22a18de26..351a23b880d4 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -81,8 +81,10 @@ impl<'a> LinkBlock<'a> { /// A link to an item. Content should not be escaped. #[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone)] pub(crate) struct Link<'a> { - /// The content for the anchor tag + /// The content for the anchor tag and title attr name: Cow<'a, str>, + /// The content for the anchor tag (if different from name) + name_html: Option>, /// The id of an anchor within the page (without a `#` prefix) href: Cow<'a, str>, /// Nested list of links (used only in top-toc) @@ -91,7 +93,7 @@ pub(crate) struct Link<'a> { impl<'a> Link<'a> { pub fn new(href: impl Into>, name: impl Into>) -> Self { - Self { href: href.into(), name: name.into(), children: vec![] } + Self { href: href.into(), name: name.into(), children: vec![], name_html: None } } pub fn empty() -> Link<'static> { Link::new("", "") @@ -207,6 +209,7 @@ fn docblock_toc<'a>( .into_iter() .map(|entry| { Link { + name_html: if entry.html == entry.name { None } else { Some(entry.html.into()) }, name: entry.name.into(), href: entry.id.into(), children: entry @@ -214,6 +217,11 @@ fn docblock_toc<'a>( .entries .into_iter() .map(|entry| Link { + name_html: if entry.html == entry.name { + None + } else { + Some(entry.html.into()) + }, name: entry.name.into(), href: entry.id.into(), // Only a single level of nesting is shown here. diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index f49cdbabb885..31823848ec38 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -23,11 +23,25 @@
        {% for link in block.links %}
      • {# #} - {{link.name}} {# #} + + {% match link.name_html %} + {% when Some with (html) %} + {{html|safe}} + {% else %} + {{link.name}} + {% endmatch %} + {# #} {% if !link.children.is_empty() %} {% endif %} diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs index a44c4a1b59ee..7fdce41a6342 100644 --- a/src/librustdoc/html/toc.rs +++ b/src/librustdoc/html/toc.rs @@ -1,5 +1,5 @@ //! Table-of-contents creation. -use crate::html::escape::EscapeBodyText; +use crate::html::escape::Escape; /// A (recursive) table of contents #[derive(Debug, PartialEq)] @@ -30,7 +30,12 @@ impl Toc { pub(crate) struct TocEntry { pub(crate) level: u32, pub(crate) sec_number: String, + // name is a plain text header that works in a `title` tag + // html includes `` tags + // the tooltip is used so that, when a toc is truncated, + // you can mouse over it to see the whole thing pub(crate) name: String, + pub(crate) html: String, pub(crate) id: String, pub(crate) children: Toc, } @@ -116,7 +121,7 @@ impl TocBuilder { /// Push a level `level` heading into the appropriate place in the /// hierarchy, returning a string containing the section number in /// `..` format. - pub(crate) fn push(&mut self, level: u32, name: String, id: String) -> &str { + pub(crate) fn push(&mut self, level: u32, name: String, html: String, id: String) -> &str { assert!(level >= 1); // collapse all previous sections into their parents until we @@ -150,6 +155,7 @@ impl TocBuilder { self.chain.push(TocEntry { level, name, + html, sec_number, id, children: Toc { entries: Vec::new() }, @@ -171,10 +177,11 @@ impl Toc { // recursively format this table of contents let _ = write!( v, - "\n
      • {num} {name}", + "\n
      • {num} {html}", id = entry.id, num = entry.sec_number, - name = EscapeBodyText(&entry.name) + name = Escape(&entry.name), + html = &entry.html, ); entry.children.print_inner(&mut *v); v.push_str("
      • "); diff --git a/src/librustdoc/html/toc/tests.rs b/src/librustdoc/html/toc/tests.rs index 014f346862b3..81aca737baf1 100644 --- a/src/librustdoc/html/toc/tests.rs +++ b/src/librustdoc/html/toc/tests.rs @@ -9,7 +9,10 @@ fn builder_smoke() { // there's been no macro mistake. macro_rules! push { ($level: expr, $name: expr) => { - assert_eq!(builder.push($level, $name.to_string(), "".to_string()), $name); + assert_eq!( + builder.push($level, $name.to_string(), $name.to_string(), "".to_string()), + $name + ); }; } push!(2, "0.1"); @@ -48,6 +51,7 @@ fn builder_smoke() { TocEntry { level: $level, name: $name.to_string(), + html: $name.to_string(), sec_number: $name.to_string(), id: "".to_string(), children: toc!($($sub),*) diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs index fa1325c8dca0..db9987756443 100644 --- a/tests/rustdoc/sidebar/top-toc-html.rs +++ b/tests/rustdoc/sidebar/top-toc-html.rs @@ -4,7 +4,7 @@ #![feature(lazy_type_alias)] #![allow(incomplete_features)] -//! # Basic [link](https://example.com) and *emphasis* +//! # Basic [link](https://example.com) and *emphasis* and `code` //! //! This test case covers TOC entries with rich text inside. //! Rustdoc normally supports headers with links, but for the @@ -12,9 +12,12 @@ //! //! For consistency, emphasis is also filtered out. -// @has foo/index.html +//@ has foo/index.html // User header -// @has - '//section[@id="TOC"]/h3' 'Sections' -// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]' 'Basic link and emphasis' -// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/em' 0 -// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/a' 0 +//@ has - '//section[@id="TOC"]/h3' 'Sections' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/@title' 'Basic link and emphasis and `code`' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]' 'Basic link and emphasis and code' +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/em' 0 +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/a' 0 +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/code' 1 +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/code' 'code' diff --git a/tests/rustdoc/sidebar/top-toc-idmap.rs b/tests/rustdoc/sidebar/top-toc-idmap.rs index ccfc7336e9f2..fdb99fd05a1b 100644 --- a/tests/rustdoc/sidebar/top-toc-idmap.rs +++ b/tests/rustdoc/sidebar/top-toc-idmap.rs @@ -14,13 +14,13 @@ //! in the `top-doc`, and the one that's not in the `top-doc` //! needs to match the one that isn't in the `top-toc`. -// @has foo/index.html +//@ has foo/index.html // User header -// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs' -// @has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs' +//@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs' // Built-in header -// @has - '//section[@id="TOC"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs' -// @has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs' +//@ has - '//section[@id="TOC"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs' +//@ has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs' /// # Fields /// ## Fields @@ -29,15 +29,15 @@ /// The difference between struct-like headers and module-like headers /// is strange, but not actually a problem as long as we're consistent. -// @has foo/struct.MyStruct.html +//@ has foo/struct.MyStruct.html // User header -// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields' -// @has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields' +//@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields' // Only one level of nesting -// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]//a' 2 +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]//a' 2 // Built-in header -// @has - '//section[@id="TOC"]/h3/a[@href="#fields"]' 'Fields' -// @has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields' +//@ has - '//section[@id="TOC"]/h3/a[@href="#fields"]' 'Fields' +//@ has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields' pub struct MyStruct { pub fields: i32, diff --git a/tests/rustdoc/sidebar/top-toc-nil.rs b/tests/rustdoc/sidebar/top-toc-nil.rs index 91c7df50ab48..c338bd67fcf3 100644 --- a/tests/rustdoc/sidebar/top-toc-nil.rs +++ b/tests/rustdoc/sidebar/top-toc-nil.rs @@ -2,6 +2,6 @@ //! This test case covers missing top TOC entries. -// @has foo/index.html +//@ has foo/index.html // User header -// @!has - '//section[@id="TOC"]/ul[@class="block top-toc"]' 'Basic link and emphasis' +//@ !has - '//section[@id="TOC"]/ul[@class="block top-toc"]' 'Basic link and emphasis' diff --git a/tests/rustdoc/strip-enum-variant.no-not-shown.html b/tests/rustdoc/strip-enum-variant.no-not-shown.html index e072335297d6..d7a36cc631ac 100644 --- a/tests/rustdoc/strip-enum-variant.no-not-shown.html +++ b/tests/rustdoc/strip-enum-variant.no-not-shown.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From 95fcddd29f7127bbca70375b8db3d455019843e0 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 23 Jul 2024 09:11:52 -0700 Subject: [PATCH 016/156] Add more test case --- tests/rustdoc/sidebar/top-toc-html.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs index db9987756443..8991ed0330e0 100644 --- a/tests/rustdoc/sidebar/top-toc-html.rs +++ b/tests/rustdoc/sidebar/top-toc-html.rs @@ -4,7 +4,7 @@ #![feature(lazy_type_alias)] #![allow(incomplete_features)] -//! # Basic [link](https://example.com) and *emphasis* and `code` +//! # Basic [link](https://example.com), *emphasis*, **_very emphasis_** and `code` //! //! This test case covers TOC entries with rich text inside. //! Rustdoc normally supports headers with links, but for the @@ -15,9 +15,9 @@ //@ has foo/index.html // User header //@ has - '//section[@id="TOC"]/h3' 'Sections' -//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/@title' 'Basic link and emphasis and `code`' -//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]' 'Basic link and emphasis and code' -//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/em' 0 -//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/a' 0 -//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/code' 1 -//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/code' 'code' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/@title' 'Basic link, emphasis, very emphasis and `code`' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]' 'Basic link, emphasis, very emphasis and code' +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/em' 0 +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/a' 0 +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 1 +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 'code' From 12a3c42cccd18d5fadcbad44c3c5442e4aca1a13 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 24 Jul 2024 13:16:08 -0700 Subject: [PATCH 017/156] rustdoc: consistentify `#TOC` and `#ModNav` to lowercase --- src/doc/not_found.md | 2 +- src/librustdoc/html/markdown.rs | 5 +++-- src/librustdoc/html/static/css/rustdoc.css | 4 ++-- src/librustdoc/html/static/js/main.js | 4 ++-- src/librustdoc/html/templates/sidebar.html | 4 ++-- tests/rustdoc-gui/sidebar.goml | 24 +++++++++++----------- tests/rustdoc/sidebar/module.rs | 8 ++++---- tests/rustdoc/sidebar/top-toc-html.rs | 14 ++++++------- tests/rustdoc/sidebar/top-toc-idmap.rs | 10 ++++----- tests/rustdoc/sidebar/top-toc-nil.rs | 2 +- 10 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/doc/not_found.md b/src/doc/not_found.md index f0794fc0be37..9552759d2b8b 100644 --- a/src/doc/not_found.md +++ b/src/doc/not_found.md @@ -2,7 +2,7 @@