From 0276d9f1f41740d9757de9e0b0e3500a77f0cfb1 Mon Sep 17 00:00:00 2001 From: Haoran Wang Date: Mon, 25 May 2026 01:59:27 +0800 Subject: [PATCH] Suggest function-local constructors without enclosing function path --- .../src/fn_ctxt/suggestions.rs | 7 +- .../wrap-function-local-constructors.fixed | 63 ++++++++++++ .../wrap-function-local-constructors.rs | 63 ++++++++++++ .../wrap-function-local-constructors.stderr | 95 +++++++++++++++++++ 4 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 tests/ui/suggestions/wrap-function-local-constructors.fixed create mode 100644 tests/ui/suggestions/wrap-function-local-constructors.rs create mode 100644 tests/ui/suggestions/wrap-function-local-constructors.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 323f0fb040d6..6007c4ca9e35 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -18,7 +18,7 @@ use rustc_hir_analysis::suggest_impl_trait; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{with_no_trimmed_paths, with_types_for_suggestion}; use rustc_middle::ty::{ self, Article, Binder, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, Unnormalized, Upcast, suggest_constraining_type_params, @@ -2679,8 +2679,9 @@ pub(crate) fn suggest_compatible_variants( let sole_field_ty = sole_field.ty(self.tcx, args).skip_norm_wip(); if self.may_coerce(expr_ty, sole_field_ty) { - let variant_path = - with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id)); + let variant_path = with_types_for_suggestion!(with_no_trimmed_paths!( + self.tcx.def_path_str(variant.def_id) + )); // FIXME #56861: DRYer prelude filtering if let Some(path) = variant_path.strip_prefix("std::prelude::") && let Some((_, path)) = path.split_once("::") diff --git a/tests/ui/suggestions/wrap-function-local-constructors.fixed b/tests/ui/suggestions/wrap-function-local-constructors.fixed new file mode 100644 index 000000000000..bc71d874e3dc --- /dev/null +++ b/tests/ui/suggestions/wrap-function-local-constructors.fixed @@ -0,0 +1,63 @@ +//@ run-rustfix + +// Regression test for https://github.com/rust-lang/rust/issues/144319. +// Function-local constructors cannot be named through the enclosing function +// path. The suggestion must omit path segments that cannot be written in source, +// while preserving real path segments like local modules and enums. + +#![allow(dead_code)] + +fn direct_tuple_struct() { + struct Foo(bool); + struct Bar(Foo); + + _ = Bar(Foo(false)); + //~^ ERROR mismatched types + //~| HELP try wrapping the expression in `Foo` +} + +fn enum_variant() { + enum LocalResult { + Ok(T), + } + struct Bar(LocalResult); + + _ = Bar(LocalResult::Ok(false)); + //~^ ERROR mismatched types + //~| HELP try wrapping the expression in `LocalResult::Ok` +} + +fn local_module() { + mod inner { + pub struct Foo(pub bool); + } + struct Bar(inner::Foo); + + _ = Bar(inner::Foo(false)); + //~^ ERROR mismatched types + //~| HELP try wrapping the expression in `inner::Foo` +} + +fn closure_body() { + let _ = || { + struct Foo(bool); + struct Bar(Foo); + + _ = Bar(Foo(false)); + //~^ ERROR mismatched types + //~| HELP try wrapping the expression in `Foo` + }; +} + +fn inline_const_block() { + const { + struct Foo(bool); + struct Bar(Foo); + + _ = Bar(Foo(false)); + //~^ ERROR mismatched types + //~| HELP try wrapping the expression in `Foo` + }; +} + +pub fn main() {} diff --git a/tests/ui/suggestions/wrap-function-local-constructors.rs b/tests/ui/suggestions/wrap-function-local-constructors.rs new file mode 100644 index 000000000000..88ba87edadcb --- /dev/null +++ b/tests/ui/suggestions/wrap-function-local-constructors.rs @@ -0,0 +1,63 @@ +//@ run-rustfix + +// Regression test for https://github.com/rust-lang/rust/issues/144319. +// Function-local constructors cannot be named through the enclosing function +// path. The suggestion must omit path segments that cannot be written in source, +// while preserving real path segments like local modules and enums. + +#![allow(dead_code)] + +fn direct_tuple_struct() { + struct Foo(bool); + struct Bar(Foo); + + _ = Bar(false); + //~^ ERROR mismatched types + //~| HELP try wrapping the expression in `Foo` +} + +fn enum_variant() { + enum LocalResult { + Ok(T), + } + struct Bar(LocalResult); + + _ = Bar(false); + //~^ ERROR mismatched types + //~| HELP try wrapping the expression in `LocalResult::Ok` +} + +fn local_module() { + mod inner { + pub struct Foo(pub bool); + } + struct Bar(inner::Foo); + + _ = Bar(false); + //~^ ERROR mismatched types + //~| HELP try wrapping the expression in `inner::Foo` +} + +fn closure_body() { + let _ = || { + struct Foo(bool); + struct Bar(Foo); + + _ = Bar(false); + //~^ ERROR mismatched types + //~| HELP try wrapping the expression in `Foo` + }; +} + +fn inline_const_block() { + const { + struct Foo(bool); + struct Bar(Foo); + + _ = Bar(false); + //~^ ERROR mismatched types + //~| HELP try wrapping the expression in `Foo` + }; +} + +pub fn main() {} diff --git a/tests/ui/suggestions/wrap-function-local-constructors.stderr b/tests/ui/suggestions/wrap-function-local-constructors.stderr new file mode 100644 index 000000000000..e883697721ca --- /dev/null +++ b/tests/ui/suggestions/wrap-function-local-constructors.stderr @@ -0,0 +1,95 @@ +error[E0308]: mismatched types + --> $DIR/wrap-function-local-constructors.rs:14:13 + | +LL | _ = Bar(false); + | --- ^^^^^ expected `Foo`, found `bool` + | | + | arguments to this struct are incorrect + | +note: tuple struct defined here + --> $DIR/wrap-function-local-constructors.rs:12:12 + | +LL | struct Bar(Foo); + | ^^^ +help: try wrapping the expression in `Foo` + | +LL | _ = Bar(Foo(false)); + | ++++ + + +error[E0308]: mismatched types + --> $DIR/wrap-function-local-constructors.rs:25:13 + | +LL | _ = Bar(false); + | --- ^^^^^ expected `LocalResult`, found `bool` + | | + | arguments to this struct are incorrect + | + = note: expected enum `LocalResult` + found type `bool` +note: tuple struct defined here + --> $DIR/wrap-function-local-constructors.rs:23:12 + | +LL | struct Bar(LocalResult); + | ^^^ +help: try wrapping the expression in `LocalResult::Ok` + | +LL | _ = Bar(LocalResult::Ok(false)); + | ++++++++++++++++ + + +error[E0308]: mismatched types + --> $DIR/wrap-function-local-constructors.rs:36:13 + | +LL | _ = Bar(false); + | --- ^^^^^ expected `Foo`, found `bool` + | | + | arguments to this struct are incorrect + | +note: tuple struct defined here + --> $DIR/wrap-function-local-constructors.rs:34:12 + | +LL | struct Bar(inner::Foo); + | ^^^ +help: try wrapping the expression in `inner::Foo` + | +LL | _ = Bar(inner::Foo(false)); + | +++++++++++ + + +error[E0308]: mismatched types + --> $DIR/wrap-function-local-constructors.rs:46:17 + | +LL | _ = Bar(false); + | --- ^^^^^ expected `Foo`, found `bool` + | | + | arguments to this struct are incorrect + | +note: tuple struct defined here + --> $DIR/wrap-function-local-constructors.rs:44:16 + | +LL | struct Bar(Foo); + | ^^^ +help: try wrapping the expression in `Foo` + | +LL | _ = Bar(Foo(false)); + | ++++ + + +error[E0308]: mismatched types + --> $DIR/wrap-function-local-constructors.rs:57:17 + | +LL | _ = Bar(false); + | --- ^^^^^ expected `Foo`, found `bool` + | | + | arguments to this struct are incorrect + | +note: tuple struct defined here + --> $DIR/wrap-function-local-constructors.rs:55:16 + | +LL | struct Bar(Foo); + | ^^^ +help: try wrapping the expression in `Foo` + | +LL | _ = Bar(Foo(false)); + | ++++ + + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`.