Skip to content

diagnostics: improve message when empty#154232

Draft
Jengamon wants to merge 1 commit intorust-lang:mainfrom
Jengamon:issue-154220
Draft

diagnostics: improve message when empty#154232
Jengamon wants to merge 1 commit intorust-lang:mainfrom
Jengamon:issue-154220

Conversation

@Jengamon
Copy link

@Jengamon Jengamon commented Mar 23, 2026

This adds a more accurate suggestion around the program

fn foo(_: Option()) {}

by suggesting a fix to

fn foo(_: Option<()>) {}

TODO

  • currently Option(T) is being suggested by the compiler in the second error (E0107)
    help: add missing generic argument
        |
      1 | fn foo(_: Option(T)) {}
        |                  + 
    
    fix to suggest Option<T> instead

Fixes #154220

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 23, 2026
@rust-log-analyzer

This comment has been minimized.

@Kivooeo Kivooeo self-assigned this Mar 23, 2026
@Kivooeo
Copy link
Member

Kivooeo commented Mar 23, 2026

Hi! Thanks for your contribution! Take your time, and mark this as ready for review whenever you're set. Feel free to ask any questions along the way -- happy to help!

@rust-log-analyzer

This comment has been minimized.

@Jengamon
Copy link
Author

Hi! Thanks for your contribution! Take your time, and mark this as ready for review whenever you're set. Feel free to ask any questions along the way -- happy to help!

Thanks @Kivooeo! I have 2 right off the bat:

  1. Is it pretty important the errors remain the same? I have a commit (to push soon) that narrows down changes, but it still makes certain changes to tests b/c the stage where the check is at sees no difference between
    let x: usize() = 1;
    and the code that motivated this PR.
  2. I found the code most likely responsible for the mistaken "fix" in E0107, but I'm not sure how to go about fixing it.
    AngleBrackets::Available => {
    let gen_args_span = self.gen_args.span().unwrap();
    let sugg_offset =
    self.get_lifetime_args_offset() + self.num_provided_type_or_const_args();
    let (sugg_span, is_first) = if sugg_offset == 0 {
    (gen_args_span.shrink_to_lo(), true)
    } else {
    let arg_span = self.gen_args.args[sugg_offset - 1].span();
    // If we came here then inferred lifetime's spans can only point
    // to either the opening bracket or to the space right after.
    // Both of these spans have an `hi` lower than or equal to the span
    // of the generics excluding the brackets.
    // This allows us to check if `arg_span` is the artificial span of
    // an inferred lifetime, in which case the generic we're suggesting to
    // add will be the first visible, even if it isn't the actual first generic.
    (arg_span.shrink_to_hi(), arg_span.hi() <= gen_args_span.lo())
    };
    let sugg_prefix = if is_first { "" } else { ", " };
    let sugg_suffix =
    if is_first && !self.gen_args.constraints.is_empty() { ", " } else { "" };
    let sugg = format!("{sugg_prefix}{suggested_args}{sugg_suffix}");
    debug!("sugg: {:?}", sugg);
    err.span_suggestion_verbose(sugg_span, msg, sugg, Applicability::HasPlaceholders);
    }
    I think that at this point the distinction between parentheses and angle brackets is not present.

@rust-log-analyzer
Copy link
Collaborator

The job aarch64-gnu-llvm-21-1 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
##[endgroup]
Executing "/scripts/stage_2_test_set1.sh"
+ /scripts/stage_2_test_set1.sh
+ '[' 1 == 1 ']'
+ echo 'PR_CI_JOB set; skipping tidy'
+ SKIP_TIDY='--skip tidy'
+ ../x.py --stage 2 test --skip tidy --skip compiler --skip src
PR_CI_JOB set; skipping tidy
##[group]Building bootstrap
    Finished `dev` profile [unoptimized] target(s) in 0.04s
##[endgroup]
---
5    |            ^^^^^^^ only `Fn` traits may use parentheses
+    |
+ help: use angle brackets instead
+    |
+ LL |     let x: usize<()> = 1;
+    |                 +  +
6 
7 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
8   --> $DIR/issue-32995.rs:5:19

39    |
40 LL |     let d : X() = Default::default();
41    |             ^^^ only `Fn` traits may use parentheses
+    |
+ help: use angle brackets instead
+    |
+ LL |     let d : X<()> = Default::default();
+    |              +  +
42 
43 error: aborting due to 7 previous errors
44 


The actual stderr differed from the expected stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args issues/issue-32995.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/issues/issue-32995.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/issues/issue-32995" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers"
stdout: none
--- stderr -------------------------------
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/issues/issue-32995.rs:2:12
   |
LL |     let x: usize() = 1;
   |            ^^^^^^^ only `Fn` traits may use parentheses
   |
help: use angle brackets instead
   |
LL |     let x: usize<()> = 1;
   |                 +  +

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/issues/issue-32995.rs:5:19
   |
LL |     let b: ::std::boxed()::Box<_> = Box::new(1);
   |                   ^^^^^^^ only `Fn` traits may use parentheses

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/issues/issue-32995.rs:8:20
   |
LL |     let p = ::std::str::()::from_utf8(b"foo").unwrap();
   |                    ^^^^^^^ only `Fn` traits may use parentheses

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/issues/issue-32995.rs:11:25
   |
LL |     let p = ::std::str::from_utf8::()(b"foo").unwrap();
   |                         ^^^^^^^^^^^^^ only `Fn` traits may use parentheses

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/issues/issue-32995.rs:14:29
   |
LL |     let o : Box<dyn (::std::marker()::Send)> = Box::new(1);
   |                             ^^^^^^^^ only `Fn` traits may use parentheses

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/issues/issue-32995.rs:17:35
   |
LL |     let o : Box<dyn Send + ::std::marker()::Sync> = Box::new(1);
   |                                   ^^^^^^^^ only `Fn` traits may use parentheses

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/issues/issue-32995.rs:22:13
   |
LL |     let d : X() = Default::default();
   |             ^^^ only `Fn` traits may use parentheses
   |
help: use angle brackets instead
   |
LL |     let d : X<()> = Default::default();
   |              +  +

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0214`.
---
Saved the actual stderr to `/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1/unboxed-closure-sugar-used-on-struct-1.stderr`
diff of stderr:

3    |
4 LL |     let x: Box<Bar()> = panic!();
5    |                ^^^^^ only `Fn` traits may use parentheses
+    |
+ help: use angle brackets instead
+    |
+ LL |     let x: Box<Bar<()>> = panic!();
+    |                   +  +
6 
7 error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
8   --> $DIR/unboxed-closure-sugar-used-on-struct-1.rs:8:16


The actual stderr differed from the expected stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers"
stdout: none
--- stderr -------------------------------
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs:8:16
   |
LL |     let x: Box<Bar()> = panic!();
   |                ^^^^^ only `Fn` traits may use parentheses
   |
help: use angle brackets instead
   |
LL |     let x: Box<Bar<()>> = panic!();
   |                   +  +

error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
##[error]  --> /checkout/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs:8:16
   |
LL |     let x: Box<Bar()> = panic!();
   |                ^^^ expected 1 generic argument
   |
note: struct defined here, with 1 generic parameter: `A`
  --> /checkout/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs:3:8
   |
LL | struct Bar<A> {
   |        ^^^ -
help: add missing generic argument
   |
LL |     let x: Box<Bar(A)> = panic!();
   |                    +

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0107, E0214.
---
Saved the actual stderr to `/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct/unboxed-closure-sugar-used-on-struct.stderr`
diff of stderr:

3    |
4 LL | fn foo(b: Box<Bar()>) {
5    |               ^^^^^ only `Fn` traits may use parentheses
+    |
+ help: use angle brackets instead
+    |
+ LL | fn foo(b: Box<Bar<()>>) {
+    |                  +  +
6 
7 error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
8   --> $DIR/unboxed-closure-sugar-used-on-struct.rs:7:15


The actual stderr differed from the expected stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args unboxed-closures/unboxed-closure-sugar-used-on-struct.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers"
stdout: none
--- stderr -------------------------------
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs:7:15
   |
LL | fn foo(b: Box<Bar()>) {
   |               ^^^^^ only `Fn` traits may use parentheses
   |
help: use angle brackets instead
   |
LL | fn foo(b: Box<Bar<()>>) {
   |                  +  +

error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
##[error]  --> /checkout/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs:7:15
   |
LL | fn foo(b: Box<Bar()>) {
   |               ^^^ expected 1 generic argument
   |
note: struct defined here, with 1 generic parameter: `A`
  --> /checkout/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs:3:8
   |
LL | struct Bar<A> {
   |        ^^^ -
help: add missing generic argument
   |
LL | fn foo(b: Box<Bar(A)>) {
   |                   +

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0107, E0214.
For more information about an error, try `rustc --explain E0107`.
------------------------------------------

---- [ui] tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs stdout end ----
---- [ui] tests/ui/unpretty/exhaustive.rs#hir stdout ----
Saved the actual stderr to `/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/unpretty/exhaustive.hir/exhaustive.hir.stderr`
diff of stderr:

99    |
100 LL |         let _: T() -> !;
101    |                ^^^^^^^^ only `Fn` traits may use parentheses
+    |
+ help: use angle brackets instead
+    |
+ LL |         let _: T<()> -> !;
+    |                 +  +
102 
103 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
104   --> $DIR/exhaustive.rs:810:16

Note: some mismatched output was normalized before being compared
- LL |         let _: T<()> -> !;    //[hir]~ ERROR parenthesized type parameters
+    |
+ help: use angle brackets instead
+    |
+ LL |         let _: T<()> -> !;
+    |                 +  +


The actual stderr differed from the expected stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args unpretty/exhaustive.rs`

error in revision `hir`: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/unpretty/exhaustive.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--cfg" "hir" "--check-cfg" "cfg(test,FALSE,expanded,hir)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/unpretty/exhaustive.hir" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2024" "-Zunpretty=hir"
--- stdout -------------------------------
//@ revisions: expanded hir
//@[expanded]compile-flags: -Zunpretty=expanded
//@[expanded]check-pass
//@[hir]compile-flags: -Zunpretty=hir
//@[hir]check-fail
//@ edition:2024

// Note: the HIR revision includes a `.stderr` file because there are some
// errors that only occur once we get past the AST.

#![allow(incomplete_features)]
#![attr = Feature([auto_traits#0, box_patterns#0, builtin_syntax#0,
const_trait_impl#0, coroutines#0, decl_macro#0, deref_patterns#0,
explicit_tail_calls#0, gen_blocks#0, more_qualified_paths#0, never_patterns#0,
never_type#0, pattern_types#0, pattern_type_macro#0, prelude_import#0,
specialization#0, trace_macros#0, trait_alias#0, try_blocks#0,
try_blocks_heterogeneous#0, yeet_expr#0])]
extern crate std;
#[attr = PreludeImport]
use std::prelude::rust_2024::*;

mod prelude {
    use std::prelude::rust_2024::*;

---

    /// outer single-line doc comment
    /**
     * outer multi-line doc comment
     */
    #[doc = "outer doc attribute"]
    #[doc = "macro"]
    #[allow()]
    #[attr = Repr {reprs: [ReprC]}]
    struct Struct;
}

mod expressions {
    /// ExprKind::Array
    fn expr_array() {
        [];
        [true];
        [true];
        [true, true];
        ["long........................................................................"];
        ["long............................................................",
                true];
    }

    /// ExprKind::ConstBlock
    fn expr_const_block() {
---
                };
    }

    /// ExprKind::Call
    fn expr_call() {
        let f;
        f();
        f::<u8>();
        f::<1>();
        f::<'static, u8, 1>();
        f(true);
        f(true);
        ()();
    }

    /// ExprKind::MethodCall
    fn expr_method_call() {
        let x;
        x.f();
        x.f::<u8>();
        x.collect::<Vec<_>>();
    }

    /// ExprKind::Tup
    fn expr_tup() { (); (true,); (true, false); (true, false); }

    /// ExprKind::Binary
    fn expr_binary() {
        let (a, b, c, d, x, y);
        true || false;
        true || false && false;
        a < 1 && 2 < b && c > 3 && 4 > d;
        a & b & !c;
        a + b * c - d + -1 * -2 - -3;
        x = !y;
    }

    /// ExprKind::Unary
    fn expr_unary() { let expr; *expr; !expr; -expr; }

    /// ExprKind::Lit
    fn expr_lit() { 'x'; 1000i8; 1.00000000000000000000001; }

    /// ExprKind::Cast
    fn expr_cast() { let expr; expr as T; expr as T<u8>; }

    /// ExprKind::Type
    fn expr_type() { let expr; type_ascribe!(expr, T); }

    /// ExprKind::Let
    fn expr_let() {
        let b;
        if let Some(a) = b { }
        if let _ = true && false { }
        if let _ = (true && false) { }
    }

    /// ExprKind::If
    fn expr_if() {
        if true { }
        if !true { }
        if let true = true { } else { }
        if true { } else if false { }
        if true { } else if false { } else { }
        if true { return; } else if false { 0 } else { 0 }
    }

    /// ExprKind::While
    fn expr_while() {
        loop { if false { } else { break; } }
        'a: loop { if false { } else { break; } }
        loop { if let true = true { } else { break; } }
    }

    /// ExprKind::ForLoop
    fn expr_for_loop() {
        let x;
        {
            let _t =
                match into_iter(x) {
                    mut iter =>
                        loop {
                            match next(&mut iter) {
                                None {} => break,
                                Some {  0: _ } => { }
                            }
                        },
                };
            _t
        };
        {
            let _t =
                match into_iter(x) {
                    mut iter =>
                        'a: loop {
                            match next(&mut iter) {
                                None {} => break,
                                Some {  0: _ } => { }
                            }
                        },
                };
            _t
        }
    }

    /// ExprKind::Loop
    fn expr_loop() { loop { } 'a: loop { } }

    /// ExprKind::Match
    fn expr_match() {
        let value;
        match value { }
        match value { ok => 1, }
        match value { ok => 1, err => 0, }
    }

    /// ExprKind::Closure
    fn expr_closure() {
        let value;
        || { };
        |x| { };
        |x: u8| { };
        || ();
        move || value;
        || |mut _task_context: ResumeTy| { { let _t = value; _t } };
        move || |mut _task_context: ResumeTy| { { let _t = value; _t } };
        || value; //[hir]~ ERROR closures cannot be static
        move || value; //[hir]~ ERROR closures cannot be static
        || |mut _task_context: ResumeTy| { { let _t = value; _t } };
        move || |mut _task_context: ResumeTy| { { let _t = value; _t } };
        || -> u8 { value };
        1 + (|| { });
    }

    /// ExprKind::Block
    fn expr_block() {
        { }
        unsafe { }
        'a: { }
        #[allow()]
        { }
        #[allow()]
        { }
    }

    /// ExprKind::Gen
    fn expr_gen() {
        |mut _task_context: ResumeTy| { };
        move |mut _task_context: ResumeTy| { };
        || { };
        move || { };
        |mut _task_context: ResumeTy| { };
        move |mut _task_context: ResumeTy| { };
    }

    /// ExprKind::Await
    fn expr_await() {
        let fut;
        {
            fut; //[hir]~ ERROR `await` is only allowed
            (/*ERROR*/)
        };
    }

    /// ExprKind::TryBlock
    fn expr_try_block() {
        { from_output(()) }
        { return; from_output(()) }
        type_ascribe!({ from_output(()) }, Option<_>);
        type_ascribe!({
                from_output(match branch(None) {
                        Break {  0: residual } => #[allow(unreachable_code)]
                            break from_residual(residual),
                        Continue {  0: val } => #[allow(unreachable_code)]
                            val,
                    })
            }, Option<String>)
    }

    /// ExprKind::Assign
    fn expr_assign() { let expr; expr = true; }

    /// ExprKind::AssignOp
    fn expr_assign_op() { let expr; expr += true; }

    /// ExprKind::Field
    fn expr_field() { let expr; expr.field; expr.0; }

    /// ExprKind::Index
    fn expr_index() { let expr; expr[true]; }

    /// ExprKind::Range
    fn expr_range() {
        let (lo, hi);
        RangeFull {  };
        RangeTo { end: hi };
        RangeFrom { start: lo };
        Range { start: lo, end: hi };
        Range { start: lo, end: hi };
        RangeToInclusive { end: hi };
        range_inclusive_new(lo, hi);
        range_inclusive_new(-2, -1);
    }

    /// ExprKind::Underscore
    fn expr_underscore() {
        (/*ERROR*/); //[hir]~ ERROR in expressions, `_` can only
    }

    /// ExprKind::Path
    fn expr_path() {
        let x;
        crate::expressions::expr_path;
        crate::expressions::expr_path::<'static>;
        <T as Default>::default;
        <T as ::core::default::Default>::default;
        x; //[hir]~ ERROR parenthesized type parameters
        x::<T, T>; //[hir]~ ERROR parenthesized type parameters
        crate::expressions::expr_path;
        //[hir]~^ ERROR parenthesized type parameters
        //[hir]~| ERROR parenthesized type parameters
        core::marker::PhantomData;
        //[hir]~^ ERROR parenthesized type parameters
        //[hir]~| ERROR parenthesized type parameters
    }

    /// ExprKind::AddrOf
    fn expr_addr_of() {
        let expr;
        &expr;
        &mut expr;
        &raw const expr;
        &raw mut expr;
    }

    /// ExprKind::Break
    fn expr_break() { 'a: { break; break 'a; break true; break 'a true; } }

    /// ExprKind::Continue
    fn expr_continue() { 'a: { continue; continue 'a; } }

    /// ExprKind::Ret
    fn expr_ret() { return; return true; }


---




        //[hir]~ ERROR `yield` can only be used





---


        // ...

        //[hir]~ ERROR invalid ABI





---




        //[hir]~ ERROR `..` patterns are not allowed here





---




        //[hir]~ ERROR parenthesized type parameters


        //[hir]~ ERROR `impl Trait` is not allowed
        //[hir]~ ERROR `impl Trait` is not allowed
        //[hir]~ ERROR `impl Trait` is not allowed
        //[hir]~ ERROR `impl Trait` is not allowed
        //[hir]~ ERROR `impl Trait` is not allowed
        //[hir]~ ERROR `impl Trait` is not allowed









        const { offset_of!(T, field) };
    }
    /// ExprKind::MacCall
    fn expr_mac_call() { "..."; "..."; "..."; }
    /// ExprKind::Struct
    fn expr_struct() {
        struct Struct {
        }
        let (x, base);
        Struct {  };
        <Struct as ToOwned>::Owned {  };
        Struct { .. };
        Struct { ..base };
        Struct { x };
        Struct { x, ..base };
        Struct { x: true };
        Struct { x: true, .. };
        Struct { x: true, ..base };
        Struct { 0: true, ..base };
    }
    /// ExprKind::Repeat
    fn expr_repeat() { [(); 0]; }
    /// ExprKind::Paren
    fn expr_paren() { let expr; expr; }
    /// ExprKind::Try
    fn expr_try() {
        let expr;
        match branch(expr) {
            Break {  0: residual } => #[allow(unreachable_code)]
                return from_residual(residual),
            Continue {  0: val } => #[allow(unreachable_code)]
                val,
        };
    }
    /// ExprKind::Yield
    fn expr_yield() { yield (); yield true; }
    /// ExprKind::Yeet
    fn expr_yeet() { return from_yeet(()); return from_yeet(0); }
    /// ExprKind::Become
    fn expr_become() { become true; }
    /// ExprKind::IncludedBytes
    fn expr_include_bytes() {
        b"data for include_bytes in ../expanded-exhaustive.rs\n";
    }
    /// ExprKind::FormatArgs
    fn expr_format_args() {
        let expr;
        format_arguments::from_str("");
        {
            super let args = (&expr,);
            super let args = [format_argument::new_display(args.0)];
            unsafe { format_arguments::new(b"\xc0\x00", &args) }
        };
    }
}
mod items {
    /// ItemKind::ExternCrate
    mod item_extern_crate {
        extern crate core;
        extern crate self as unpretty;
        extern crate core as _;
    }
    /// ItemKind::Use
    mod item_use {
        use ::{};
        use crate::expressions;
        use crate::items::item_use;
        use core::*;
    }
    /// ItemKind::Static
    mod item_static {
        static A: () = { };
        static mut B: () = { };
    }
    /// ItemKind::Const
    mod item_const {
        const A: () = { };
        trait TraitItems {
            const
            B:
            ();
            const
            C:
---
    mod item_fn {
        const unsafe extern "C" fn f() { }
        async unsafe extern "C" fn g()
            ->
                /*impl Trait*/ |mut _task_context: ResumeTy|
            { { let _t = { }; _t } }
        fn h<'a, T>() where T: 'a { }
        trait TraitItems {
            unsafe extern "C" fn f();
        }
        impl TraitItems for _ {
            unsafe extern "C" fn f() { }
        }
    }
    /// ItemKind::Mod
    mod item_mod { }
    /// ItemKind::ForeignMod
    mod item_foreign_mod {
        extern "Rust" { }
        extern "C" { }
    }
    /// ItemKind::GlobalAsm: see exhaustive-asm.rs
    /// ItemKind::TyAlias
    mod item_ty_alias {
        type Type<'a> where T: 'a = T;
    }
    /// ItemKind::Enum
    mod item_enum {
        enum Void { }
        enum Empty {
            Unit,
            Tuple(),
            Struct {
                },
        }
        enum Generic<'a, T> where T: 'a {
            Tuple(T),
            Struct {
                    t: T,
                },
        }
    }
    /// ItemKind::Struct
    mod item_struct {
        struct Unit;
        struct Tuple();
        struct Newtype(Unit);
        struct Struct {
        }
        struct Generic<'a, T> where T: 'a {
            t: T,
        }
    }
    /// ItemKind::Union
    mod item_union {
        union Generic<'a, T> where T: 'a {
            t: T,
        }
    }
    /// ItemKind::Trait
    mod item_trait {
        auto unsafe trait Send { }
        trait Trait<'a>: Sized where Self: 'a { }
    }
    /// ItemKind::TraitAlias
    mod item_trait_alias {
        trait Trait<T> = Sized where for<'a> T: 'a;
    }
    /// ItemKind::Impl
    mod item_impl {
        impl () { }
        impl <T> () { }
        impl Default for () { }
        impl <T> const Default for () { }
    }
    /// ItemKind::MacCall
    mod item_mac_call { }
    /// ItemKind::MacroDef
    mod item_macro_def {
        macro_rules! mac { () => {...}; }
        macro stringify { () => {} }
    }
    /// ItemKind::Delegation
    /** FIXME: todo */
    mod item_delegation { }
    /// ItemKind::DelegationMac
    /** FIXME: todo */
    mod item_delegation_mac { }
}
mod patterns {
    /// PatKind::Missing
    fn pat_missing() { let _: for fn(u32, T, &'_ str); }
    /// PatKind::Wild
    fn pat_wild() { let _; }
    /// PatKind::Ident
    fn pat_ident() {
        let x;
        let ref x;
        let mut x;
        let ref mut x;
        let ref mut x@_;
    }
    /// PatKind::Struct
    fn pat_struct() {
        let T {};
        let T::<T> {};
        let T::<'static> {};
        let T {  x };
        let T {  x: _x };
        let T { .. };
        let T {  x, .. };
        let T {  x: _x, .. };
        let T {  0: _x, .. };
        let <T as ToOwned>::Owned {};
    }
    /// PatKind::TupleStruct
    fn pat_tuple_struct() {
        struct Tuple();
        let Tuple();
        let Tuple::<T>();
        let Tuple::<'static>();
        let Tuple(x);
        let Tuple(..);
        let Tuple(x, ..);
    }
    /// PatKind::Or
    fn pat_or() { let true | false; let true; let true | false; }
    /// PatKind::Path
    fn pat_path() {
        let core::marker::PhantomData;
        let core::marker::PhantomData::<T>;
        let core::marker::PhantomData::<'static>;
        let <T as Trait>::CONST;
    }
    /// PatKind::Tuple
    fn pat_tuple() { let (); let (true,); let (true, false); }
    /// PatKind::Box
    fn pat_box() { let box pat; }
    /// PatKind::Deref
    fn pat_deref() { let deref!(pat); }
    /// PatKind::Ref
    fn pat_ref() { let &pat; let &mut pat; }
    /// PatKind::Expr
    fn pat_expr() { let 1000i8; let -""; }
    /// PatKind::Range
    fn pat_range() { let ..1; let 0...; let 0..1; let 0...1; let -2...-1; }
    /// PatKind::Slice
    fn pat_slice() { let []; let [true]; let [true]; let [true, false]; }
    /// PatKind::Rest
    fn pat_rest() { let _; }
    /// PatKind::Never
    fn pat_never() { let !; let Some(!); }
    /// PatKind::Paren
    fn pat_paren() { let pat; }
    /// PatKind::MacCall
    fn pat_mac_call() { let ""; let ""; let ""; }
}
mod statements {
    /// StmtKind::Let
    fn stmt_let() {
        let _;
        let _ = true;
        let _: T = true;
        let _ = true else { return; };
    }
    /// StmtKind::Item
    fn stmt_item() {
        struct Struct {
        }
        struct Unit;
    }
    /// StmtKind::Expr
    fn stmt_expr() { () }
    /// StmtKind::Semi
    fn stmt_semi() { 1 + 1; }
    /// StmtKind::Empty
    fn stmt_empty() { }
    /// StmtKind::MacCall
    fn stmt_mac_call() { "..."; "..."; "..."; }
}
mod types {
    /// TyKind::Slice
    fn ty_slice() { let _: [T]; }
    /// TyKind::Array
    fn ty_array() { let _: [T; 0]; }
    /// TyKind::Ptr
    fn ty_ptr() { let _: *const T; let _: *mut T; }
    /// TyKind::Ref
    fn ty_ref() {
        let _: &T;
        let _: &mut T;
        let _: &'static T;
        let _: &'static mut [T];
        let _: &T<T<T<T<T>>>>;
        let _: &T<T<T<T<T>>>>;
    }
    /// TyKind::BareFn
    fn ty_bare_fn() {
        let _: fn();
        let _: fn() -> ();
        let _: fn(T);
        let _: fn(t: T);
        let _: fn();
        let _: for<'a> fn();
    }
    /// TyKind::Never
    fn ty_never() { let _: !; }
    /// TyKind::Tup
    fn ty_tup() { let _: (); let _: (T,); let _: (T, T); }
    /// TyKind::Path
    fn ty_path() {
        let _: T;
        let _: T<'static>;
        let _: T<T>;
        let _: T<T>;
        let _: T;
        let _: <T as ToOwned>::Owned;
    }
    /// TyKind::TraitObject
    fn ty_trait_object() {
        let _: dyn Send;
        let _: dyn Send + 'static;
        let _: dyn Send + 'static;
        let _: dyn for<'a> Send;
    }
    /// TyKind::ImplTrait
    const fn ty_impl_trait() {
        let _: (/*ERROR*/);
        let _: (/*ERROR*/);
        let _: (/*ERROR*/);
        let _: (/*ERROR*/);
        let _: (/*ERROR*/);
        let _: (/*ERROR*/);
    }
    /// TyKind::Paren
    fn ty_paren() { let _: T; }
    /// TyKind::Typeof
    /** unused for now */
    fn ty_typeof() { }
    /// TyKind::Infer
    fn ty_infer() { let _: _; }
    /// TyKind::ImplicitSelf
    /** there is no syntax for this */
    fn ty_implicit_self() { }
    /// TyKind::MacCall
    fn ty_mac_call() {
        macro_rules! ty { ($ty:ty) => { $ty } }
        let _: T;
        let _: T;
        let _: T;
    }
    /// TyKind::CVarArgs
    /** FIXME: todo */
    fn ty_c_var_args() { }
    /// TyKind::Pat
    fn ty_pat() { let _: u32 is 1..=RangeMax; }
}
mod visibilities {
    /// VisibilityKind::Public
    mod visibility_public {
        struct Pub;
    }
    /// VisibilityKind::Restricted
    mod visibility_restricted {
        struct PubCrate;
        struct PubSelf;
        struct PubSuper;
        struct PubInCrate;
        struct PubInSelf;
        struct PubInSuper;
        struct PubInCrateVisibilities;
        struct PubInSelfSuper;
        struct PubInSuperMod;
    }
}
------------------------------------------
--- stderr -------------------------------
error[E0697]: closures cannot be static
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:211:9
   |
LL |         static || value;            //[hir]~ ERROR closures cannot be static
   |         ^^^^^^^^^

error[E0697]: closures cannot be static
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:212:9
   |
LL |         static move || value;       //[hir]~ ERROR closures cannot be static
   |         ^^^^^^^^^^^^^^

error[E0728]: `await` is only allowed inside `async` functions and blocks
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:241:13
   |
LL |     fn expr_await() {
   |     --------------- this is not `async`
LL |         let fut;
LL |         fut.await;  //[hir]~ ERROR `await` is only allowed
   |             ^^^^^ only allowed inside `async` functions and blocks

error: in expressions, `_` can only be used on the left-hand side of an assignment
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:292:9
   |
LL |         _;      //[hir]~ ERROR in expressions, `_` can only
   |         ^ `_` not allowed here

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:302:9
   |
LL |         x::();            //[hir]~ ERROR parenthesized type parameters
   |         ^^^^^ only `Fn` traits may use parentheses

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:303:9
   |
LL |         x::(T, T) -> T;   //[hir]~ ERROR parenthesized type parameters
   |         ^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
   |
help: use angle brackets instead
   |
LL -         x::(T, T) -> T;   //[hir]~ ERROR parenthesized type parameters
LL +         x::<T, T> -> T;   //[hir]~ ERROR parenthesized type parameters
   |

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:304:9
   |
LL |         crate::() -> ()::expressions::() -> ()::expr_path;
   |         ^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:304:26
   |
LL |         crate::() -> ()::expressions::() -> ()::expr_path;
   |                          ^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:307:9
   |
LL |         core::()::marker::()::PhantomData;
   |         ^^^^^^^^ only `Fn` traits may use parentheses

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:307:19
   |
LL |         core::()::marker::()::PhantomData;
   |                   ^^^^^^^^^^ only `Fn` traits may use parentheses

error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:394:9
   |
LL |         yield;          //[hir]~ ERROR `yield` can only be used
   |         ^^^^^
   |
help: use `#[coroutine]` to make this closure a coroutine
   |
LL |     #[coroutine] fn expr_yield() {
   |     ++++++++++++

error[E0703]: invalid ABI: found `C++`
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:474:23
   |
LL |         unsafe extern "C++" {}  //[hir]~ ERROR invalid ABI
   |                       ^^^^^ invalid ABI
   |
   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions

error: `..` patterns are not allowed here
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:681:13
   |
LL |         let ..;     //[hir]~ ERROR `..` patterns are not allowed here
   |             ^^
   |
   = note: only allowed in tuple, tuple struct, and slice patterns

error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:796:16
   |
LL |         let _: T() -> !;    //[hir]~ ERROR parenthesized type parameters
   |                ^^^^^^^^ only `Fn` traits may use parentheses
   |
help: use angle brackets instead
   |
LL |         let _: T<()> -> !;    //[hir]~ ERROR parenthesized type parameters
   |                 +  +

error[E0562]: `impl Trait` is not allowed in the type of variable bindings
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:810:16
   |
LL |         let _: impl Send;               //[hir]~ ERROR `impl Trait` is not allowed
   |                ^^^^^^^^^
   |
   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0562]: `impl Trait` is not allowed in the type of variable bindings
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:811:16
   |
LL |         let _: impl Send + 'static;     //[hir]~ ERROR `impl Trait` is not allowed
   |                ^^^^^^^^^^^^^^^^^^^
   |
   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0562]: `impl Trait` is not allowed in the type of variable bindings
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:812:16
   |
LL |         let _: impl 'static + Send;     //[hir]~ ERROR `impl Trait` is not allowed
   |                ^^^^^^^^^^^^^^^^^^^
   |
   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0562]: `impl Trait` is not allowed in the type of variable bindings
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:813:16
   |
LL |         let _: impl ?Sized;             //[hir]~ ERROR `impl Trait` is not allowed
   |                ^^^^^^^^^^^
   |
   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0562]: `impl Trait` is not allowed in the type of variable bindings
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:814:16
   |
LL |         let _: impl [const] Clone;       //[hir]~ ERROR `impl Trait` is not allowed
   |                ^^^^^^^^^^^^^^^^^^
   |
   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0562]: `impl Trait` is not allowed in the type of variable bindings
##[error]  --> /checkout/tests/ui/unpretty/exhaustive.rs:815:16
   |
LL |         let _: impl for<'a> Send;       //[hir]~ ERROR `impl Trait` is not allowed
   |                ^^^^^^^^^^^^^^^^^
   |
   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
   = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 20 previous errors

Some errors have detailed explanations: E0214, E0562, E0697, E0703, E0728.
For more information about an error, try `rustc --explain E0214`.

@Kivooeo
Copy link
Member

Kivooeo commented Mar 23, 2026

Sorry for the late reply -- I spent some time digging into this issue today and tried a few different approaches, but I should note that it turned out to be a bit more complex than it seemed at first glance.

As for the expected output in the tests, yes, you can definitely change it if needed. The main thing is to make sure the error messages don't become worse or less informative across different scenarios - that's what we need to watch out for. For example, in the usize() case, it's probably better not to suggest <>.

@Jengamon Jengamon changed the title diagnostics: improve message when emp diagnostics: improve message when empty Mar 23, 2026
@Jengamon
Copy link
Author

My instinct is that if we can get the difference between () and <> into AngleBrackets::Available, then I could revert the AST lowering changes and instead correct the suggestion made by rust/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs:725-752, because rust/‎compiler/rustc_ast_lowering/src/path.rs is too early in the process to tell if angle brackets need to be added, but by the hir analysis step, the compiler has thrown away the information needed to make this call.

I run on a looooot this is the short version and no worries Im just really free rn.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Suboptimal diagnostic on Output() type ascription

4 participants