From e8d4fb8aaafa598d3021f2378705f780ee173458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 18 Oct 2023 22:54:35 +0000 Subject: [PATCH 1/6] Suggest relaxing implicit `type Assoc: Sized;` bound Fix #85378. --- .../src/traits/error_reporting/suggestions.rs | 23 +++++++++++++++++++ .../assoc_type_bounds_implicit_sized.fixed | 10 ++++++++ .../assoc_type_bounds_implicit_sized.rs | 10 ++++++++ .../assoc_type_bounds_implicit_sized.stderr | 20 ++++++++++++++++ .../assoc_type_bounds_sized_used.stderr | 4 ++++ 5 files changed, 67 insertions(+) create mode 100644 tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed create mode 100644 tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs create mode 100644 tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 78f7f915f7269..8f1ebc24b9455 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2652,6 +2652,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Check for foreign traits being reachable. self.tcx.visible_parent_map(()).get(&def_id).is_some() }; + if Some(def_id) == self.tcx.lang_items().sized_trait() + && let Some(hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Type(bounds, None), + .. + })) = tcx.hir().get_if_local(item_def_id) + // Do not suggest relaxing if there is an explicit `Sized` obligation. + && !bounds.iter() + .filter_map(|bound| bound.trait_ref()) + .any(|tr| tr.trait_def_id() == self.tcx.lang_items().sized_trait()) + { + let (span, separator) = if let [.., last] = bounds { + (last.span().shrink_to_hi(), " +") + } else { + (ident.span.shrink_to_hi(), ":") + }; + err.span_suggestion_verbose( + span, + "consider relaxing the implicit `Sized` restriction", + format!("{separator} ?Sized"), + Applicability::MachineApplicable, + ); + } if let DefKind::Trait = tcx.def_kind(item_def_id) && !visible_item { diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed new file mode 100644 index 0000000000000..45c7e07a26471 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed @@ -0,0 +1,10 @@ +// run-rustfix +trait TraitWithAType { + type Item: ?Sized; +} +trait Trait {} +struct A {} +impl TraitWithAType for A { + type Item = dyn Trait; //~ ERROR E0277 +} +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs new file mode 100644 index 0000000000000..c3e958f498390 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs @@ -0,0 +1,10 @@ +// run-rustfix +trait TraitWithAType { + type Item; +} +trait Trait {} +struct A {} +impl TraitWithAType for A { + type Item = dyn Trait; //~ ERROR E0277 +} +fn main() {} diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr new file mode 100644 index 0000000000000..110e715073371 --- /dev/null +++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr @@ -0,0 +1,20 @@ +error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time + --> $DIR/assoc_type_bounds_implicit_sized.rs:8:17 + | +LL | type Item = dyn Trait; + | ^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` +note: required by a bound in `TraitWithAType::Item` + --> $DIR/assoc_type_bounds_implicit_sized.rs:3:5 + | +LL | type Item; + | ^^^^^^^^^^ required by this bound in `TraitWithAType::Item` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Item: ?Sized; + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr index 224d33fb2da18..b67a1244eceab 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr +++ b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr @@ -33,6 +33,10 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` LL - fn bop() { LL + fn bop() { | +help: consider relaxing the implicit `Sized` restriction + | +LL | type Bar: Default + ?Sized + | ++++++++ error: aborting due to 2 previous errors From 6ed2a76bcc2a963c28080d6ee3ad928ec9367a03 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 19 Oct 2023 17:06:53 -0700 Subject: [PATCH 2/6] Add stable Instance::body() and RustcInternal trait The `Instance::body()` returns a monomorphized body. For that, we had to implement visitor that monomorphize types and constants. We are also introducing the RustcInternal trait that will allow us to convert back from Stable to Internal. Note that this trait is not yet visible for our users as it depends on Tables. We should probably add a new trait that can be exposed. --- .../rustc_smir/src/rustc_internal/internal.rs | 61 +++++++++++++++++++ compiler/rustc_smir/src/rustc_internal/mod.rs | 10 +++ compiler/rustc_smir/src/rustc_smir/builder.rs | 55 +++++++++++++++++ compiler/rustc_smir/src/rustc_smir/mod.rs | 22 +++++-- compiler/stable_mir/src/error.rs | 7 +++ compiler/stable_mir/src/lib.rs | 4 ++ compiler/stable_mir/src/mir/body.rs | 27 +++++++- compiler/stable_mir/src/mir/mono.rs | 11 +++- compiler/stable_mir/src/ty.rs | 2 + .../{instance.rs => check_instance.rs} | 26 +++++++- 10 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 compiler/rustc_smir/src/rustc_internal/internal.rs create mode 100644 compiler/rustc_smir/src/rustc_smir/builder.rs rename tests/ui-fulldeps/stable-mir/{instance.rs => check_instance.rs} (73%) diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs new file mode 100644 index 0000000000000..f42a973932065 --- /dev/null +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -0,0 +1,61 @@ +//! Module containing the translation from stable mir constructs to the rustc counterpart. +//! +//! This module will only include a few constructs to allow users to invoke internal rustc APIs +//! due to incomplete stable coverage. + +// Prefer importing stable_mir over internal rustc constructs to make this file more readable. +use crate::rustc_smir::{MaybeStable, Tables}; +use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy}; +use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty}; +use stable_mir::DefId; + +use super::RustcInternal; + +impl<'tcx> RustcInternal<'tcx> for DefId { + type T = rustc_span::def_id::DefId; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.def_ids[*self] + } +} + +impl<'tcx> RustcInternal<'tcx> for GenericArgs { + type T = rustc_ty::GenericArgsRef<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.tcx.mk_args_from_iter(self.0.iter().map(|arg| arg.internal(tables))) + } +} + +impl<'tcx> RustcInternal<'tcx> for GenericArgKind { + type T = rustc_ty::GenericArg<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + GenericArgKind::Lifetime(reg) => reg.internal(tables).into(), + GenericArgKind::Type(ty) => ty.internal(tables).into(), + GenericArgKind::Const(cnst) => cnst.internal(tables).into(), + } + } +} + +impl<'tcx> RustcInternal<'tcx> for Region { + type T = rustc_ty::Region<'tcx>; + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + todo!() + } +} + +impl<'tcx> RustcInternal<'tcx> for Ty { + type T = InternalTy<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + match tables.types[self.0] { + MaybeStable::Stable(_) => todo!(), + MaybeStable::Rustc(ty) => ty, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for Const { + type T = rustc_ty::Const<'tcx>; + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + todo!() + } +} diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 5ea805e5739b5..473a59f750a7e 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -20,6 +20,8 @@ use std::fmt::Debug; use std::hash::Hash; use std::ops::{ControlFlow, Index}; +mod internal; + impl<'tcx> Index for Tables<'tcx> { type Output = DefId; @@ -231,3 +233,11 @@ impl Index { + type T; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T; +} diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs new file mode 100644 index 0000000000000..8ff3958da7bd9 --- /dev/null +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -0,0 +1,55 @@ +//! Logic required to produce a monomorphic stable body. +//! +//! We first retrieve and monomorphize the rustc body representation, i.e., we generate a +//! monomorphic body using internal representation. +//! After that, we convert the internal representation into a stable one. +use crate::rustc_smir::{Stable, Tables}; +use rustc_middle::mir; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +/// Builds a monomorphic body for a given instance. +pub struct BodyBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, +} + +impl<'tcx> BodyBuilder<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { + BodyBuilder { tcx, instance } + } + + pub fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body { + let mut body = self.tcx.instance_mir(self.instance.def).clone(); + let generics = self.tcx.generics_of(self.instance.def_id()); + if generics.requires_monomorphization(self.tcx) { + self.visit_body(&mut body); + } + body.stable(tables) + } + + fn monomorphize(&self, value: T) -> T + where + T: ty::TypeFoldable>, + { + self.instance.instantiate_mir_and_normalize_erasing_regions( + self.tcx, + ty::ParamEnv::reveal_all(), + ty::EarlyBinder::bind(value), + ) + } +} + +impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { + fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, _location: mir::Location) { + *ct = self.monomorphize(*ct); + } + + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: mir::visit::TyContext) { + *ty = self.monomorphize(*ty); + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 94dc15b4767c1..604dc3582b53a 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -7,7 +7,7 @@ //! //! For now, we are developing everything inside `rustc`, thus, we keep this module private. -use crate::rustc_internal::IndexMap; +use crate::rustc_internal::{IndexMap, RustcInternal}; use crate::rustc_smir::hir::def::DefKind; use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyBoundRegion, Region}; use rustc_hir as hir; @@ -26,6 +26,7 @@ use stable_mir::{self, opaque, Context, Filename}; use tracing::debug; mod alloc; +mod builder; impl<'tcx> Context for Tables<'tcx> { fn local_crate(&self) -> stable_mir::Crate { @@ -171,8 +172,9 @@ impl<'tcx> Context for Tables<'tcx> { } } - fn instance_body(&mut self, _def: InstanceDef) -> Body { - todo!("Monomorphize the body") + fn instance_body(&mut self, def: InstanceDef) -> Body { + let instance = self.instances[def]; + builder::BodyBuilder::new(self.tcx, instance).build(self) } fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty { @@ -195,9 +197,21 @@ impl<'tcx> Context for Tables<'tcx> { let def_id = self[def_id]; let generics = self.tcx.generics_of(def_id); let result = generics.requires_monomorphization(self.tcx); - println!("req {result}: {def_id:?}"); result } + + fn resolve_instance( + &mut self, + def: stable_mir::ty::FnDef, + args: &stable_mir::ty::GenericArgs, + ) -> Option { + let def_id = def.0.internal(self); + let args_ref = args.internal(self); + match Instance::resolve(self.tcx, ParamEnv::reveal_all(), def_id, args_ref) { + Ok(Some(instance)) => Some(instance.stable(self)), + Ok(None) | Err(_) => None, + } + } } #[derive(Clone)] diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs index 12ac8f1ca65ab..1991069145628 100644 --- a/compiler/stable_mir/src/error.rs +++ b/compiler/stable_mir/src/error.rs @@ -4,6 +4,7 @@ //! - [CompilerError]: This represents errors that can be raised when invoking the compiler. //! - [Error]: Generic error that represents the reason why a request that could not be fulfilled. +use std::convert::From; use std::fmt::{Debug, Display, Formatter}; use std::{error, fmt}; @@ -31,6 +32,12 @@ impl Error { } } +impl From<&str> for Error { + fn from(value: &str) -> Self { + Self(value.into()) + } +} + impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 59af3f64ad342..be5ccac78c7c6 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -39,6 +39,7 @@ pub mod visitor; pub use error::*; use mir::mono::Instance; +use ty::{FnDef, GenericArgs}; /// Use String for now but we should replace it. pub type Symbol = String; @@ -233,6 +234,9 @@ pub trait Context { /// Item requires monomorphization. fn requires_monomorphization(&self, def_id: DefId) -> bool; + + /// Resolve an instance from the given function definition and generic arguments. + fn resolve_instance(&mut self, def: FnDef, args: &GenericArgs) -> Option; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 72f026ee8de09..46fa8f4d922a7 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -5,9 +5,11 @@ use crate::{ty::Ty, Span}; #[derive(Clone, Debug)] pub struct Body { pub blocks: Vec, - pub locals: Vec, + pub locals: LocalDecls, } +type LocalDecls = Vec; + #[derive(Clone, Debug)] pub struct LocalDecl { pub ty: Ty, @@ -344,6 +346,7 @@ pub enum Operand { #[derive(Clone, Debug)] pub struct Place { pub local: Local, + /// projection out of a place (access a field, deref a pointer, etc) pub projection: String, } @@ -462,3 +465,25 @@ pub enum NullOp { /// Returns the offset of a field. OffsetOf(Vec), } + +impl Operand { + pub fn ty(&self, locals: &LocalDecls) -> Ty { + match self { + Operand::Copy(place) | Operand::Move(place) => place.ty(locals), + Operand::Constant(c) => c.ty(), + } + } +} + +impl Constant { + pub fn ty(&self) -> Ty { + self.literal.ty + } +} + +impl Place { + pub fn ty(&self, locals: &LocalDecls) -> Ty { + let _start_ty = locals[self.local].ty; + todo!("Implement projection") + } +} diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index d8e8ccb045480..997576fc7cbf0 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -1,5 +1,5 @@ use crate::mir::Body; -use crate::ty::{IndexedVal, Ty}; +use crate::ty::{FnDef, GenericArgs, IndexedVal, Ty}; use crate::{with, CrateItem, DefId, Error, Opaque}; use std::fmt::Debug; @@ -41,6 +41,15 @@ impl Instance { pub fn ty(&self) -> Ty { with(|context| context.instance_ty(self.def)) } + + /// Resolve an instance starting from a function definition and generic arguments. + pub fn resolve(def: FnDef, args: &GenericArgs) -> Result { + with(|context| { + context.resolve_instance(def, args).ok_or_else(|| { + crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`")) + }) + }) + } } /// Try to convert a crate item into an instance. diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 003045a4696d5..440c9a1f031c2 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -225,6 +225,8 @@ pub struct ImplDef(pub DefId); #[derive(Clone, PartialEq, Eq, Debug)] pub struct RegionDef(pub DefId); +/// A list of generic arguments. +/// The second field is for internal usage to allow retrieving the internal representation. #[derive(Clone, Debug)] pub struct GenericArgs(pub Vec); diff --git a/tests/ui-fulldeps/stable-mir/instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs similarity index 73% rename from tests/ui-fulldeps/stable-mir/instance.rs rename to tests/ui-fulldeps/stable-mir/check_instance.rs index fe06d9b5cc967..288c163a6a3fa 100644 --- a/tests/ui-fulldeps/stable-mir/instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -15,7 +15,8 @@ extern crate rustc_smir; extern crate stable_mir; use rustc_middle::ty::TyCtxt; - +use mir::{mono::Instance, TerminatorKind::*}; +use stable_mir::ty::{TyKind, RigidTy}; use stable_mir::*; use rustc_smir::rustc_internal; use std::io::Write; @@ -43,9 +44,28 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { // For all generic items, try_from should fail. assert!(generic.iter().all(|item| mir::mono::Instance::try_from(*item).is_err())); + for instance in instances { + test_body(instance.body()) + } ControlFlow::Continue(()) } +/// Inspect the instance body +fn test_body(body: mir::Body) { + for term in body.blocks.iter().map(|bb| &bb.terminator) { + match &term.kind { + Call{ func, .. } => { + let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() }; + let RigidTy::FnDef(def, args) = ty else { unreachable!() }; + let result = Instance::resolve(def, &args); + assert!(result.is_ok()); + } + Goto {..} | Assert{..} | SwitchInt{..} | Return | Drop {..} => { /* Do nothing */} + _ => { unreachable!("Unexpected terminator {term:?}") } + } + } +} + /// This test will generate and analyze a dummy crate using the stable mir. /// For that, it will first write the dummy crate into a file. @@ -56,6 +76,7 @@ fn main() { generate_input(&path).unwrap(); let args = vec![ "rustc".to_string(), + "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), @@ -78,6 +99,9 @@ fn generate_input(path: &str) -> std::io::Result<()> { }} pub fn monomorphic() {{ + let v = vec![10]; + let dup = ty_param(&v); + assert_eq!(v, dup); }} pub mod foo {{ From 6e643e12bb7b0381052696bfe1f7ecbd47769904 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Fri, 20 Oct 2023 08:23:16 -0700 Subject: [PATCH 3/6] Remove obsolete comment --- compiler/stable_mir/src/ty.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 440c9a1f031c2..d4a9b318cfc49 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -226,7 +226,6 @@ pub struct ImplDef(pub DefId); pub struct RegionDef(pub DefId); /// A list of generic arguments. -/// The second field is for internal usage to allow retrieving the internal representation. #[derive(Clone, Debug)] pub struct GenericArgs(pub Vec); From b0d17f35d98c5cafd43a673c70f8ab5d393c31a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 19 Oct 2023 22:34:45 +0000 Subject: [PATCH 4/6] Typo suggestion to change bindings with leading underscore When encountering a binding that isn't found but has a typo suggestion for a binding with a leading underscore, suggest changing the binding definition instead of the use place. Fix #60164. --- compiler/rustc_resolve/src/diagnostics.rs | 17 +++++++++++++++-- .../ui/suggestions/silenced-binding-typo.fixed | 5 +++++ tests/ui/suggestions/silenced-binding-typo.rs | 5 +++++ .../ui/suggestions/silenced-binding-typo.stderr | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/ui/suggestions/silenced-binding-typo.fixed create mode 100644 tests/ui/suggestions/silenced-binding-typo.rs create mode 100644 tests/ui/suggestions/silenced-binding-typo.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 925ee615b095b..4ad838e5aed20 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1511,9 +1511,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ), ); } + + let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + && let Some(span) = suggestion.span + && let Some(candidate) = suggestion.candidate.as_str().strip_prefix("_") + && snippet == candidate + { + // When the suggested binding change would be from `x` to `_x`, suggest changing the + // original binding definition instead. (#60164) + (span, snippet, ", consider changing it") + } else { + (span, suggestion.candidate.to_string(), "") + }; let msg = match suggestion.target { SuggestionTarget::SimilarlyNamed => format!( - "{} {} with a similar name exists", + "{} {} with a similar name exists{post}", suggestion.res.article(), suggestion.res.descr() ), @@ -1521,7 +1534,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { format!("maybe you meant this {}", suggestion.res.descr()) } }; - err.span_suggestion(span, msg, suggestion.candidate, Applicability::MaybeIncorrect); + err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); true } diff --git a/tests/ui/suggestions/silenced-binding-typo.fixed b/tests/ui/suggestions/silenced-binding-typo.fixed new file mode 100644 index 0000000000000..e0f9e31bef310 --- /dev/null +++ b/tests/ui/suggestions/silenced-binding-typo.fixed @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let x = 42; //~ HELP + let _y = x; //~ ERROR +} diff --git a/tests/ui/suggestions/silenced-binding-typo.rs b/tests/ui/suggestions/silenced-binding-typo.rs new file mode 100644 index 0000000000000..6cadd5a93a752 --- /dev/null +++ b/tests/ui/suggestions/silenced-binding-typo.rs @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let _x = 42; //~ HELP + let _y = x; //~ ERROR +} diff --git a/tests/ui/suggestions/silenced-binding-typo.stderr b/tests/ui/suggestions/silenced-binding-typo.stderr new file mode 100644 index 0000000000000..9c0e6e2656904 --- /dev/null +++ b/tests/ui/suggestions/silenced-binding-typo.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/silenced-binding-typo.rs:4:14 + | +LL | let _y = x; + | ^ + | +help: a local variable with a similar name exists, consider changing it + | +LL | let x = 42; + | ~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. From 939a224ce39fbc422e14d8255616fc587b845b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 20 Oct 2023 22:11:01 +0000 Subject: [PATCH 5/6] Point at assoc fn definition on type param divergence When the number of type parameters in the associated function of an impl and its trait differ, we now *always* point at the trait one, even if it comes from a foreign crate. When it is local, we point at the specific params, when it is foreign, we point at the whole associated item. Fix #69944. --- .../src/check/compare_impl_item.rs | 24 ++++--------------- tests/ui/typeck/issue-36708.stderr | 7 +++++- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index a1470cc69c306..74e2b157dd0a4 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1557,38 +1557,24 @@ fn compare_number_of_generics<'tcx>( DiagnosticId::Error("E0049".into()), ); - let mut suffix = None; - + let msg = + format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),); if let Some(spans) = trait_spans { let mut spans = spans.iter(); if let Some(span) = spans.next() { - err.span_label( - *span, - format!( - "expected {} {} parameter{}", - trait_count, - kind, - pluralize!(trait_count), - ), - ); + err.span_label(*span, msg); } for span in spans { err.span_label(*span, ""); } } else { - suffix = Some(format!(", expected {trait_count}")); + err.span_label(tcx.def_span(trait_.def_id), msg); } if let Some(span) = span { err.span_label( span, - format!( - "found {} {} parameter{}{}", - impl_count, - kind, - pluralize!(impl_count), - suffix.unwrap_or_default(), - ), + format!("found {} {} parameter{}", impl_count, kind, pluralize!(impl_count),), ); } diff --git a/tests/ui/typeck/issue-36708.stderr b/tests/ui/typeck/issue-36708.stderr index 140f19f1ff774..f1e0f4719281c 100644 --- a/tests/ui/typeck/issue-36708.stderr +++ b/tests/ui/typeck/issue-36708.stderr @@ -2,7 +2,12 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 --> $DIR/issue-36708.rs:8:12 | LL | fn foo() {} - | ^ found 1 type parameter, expected 0 + | ^ found 1 type parameter + | + ::: $DIR/auxiliary/issue-36708.rs:4:5 + | +LL | fn foo(); + | --------- expected 0 type parameters error: aborting due to previous error From 8950d80a337ea6116987d02560fcd480e4e5cb7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 20 Oct 2023 20:03:44 +0000 Subject: [PATCH 6/6] Mention the syntax for `use` on `mod foo;` if `foo` doesn't exist Newcomers might get confused that `mod` is the only way of defining scopes, and that it can be used as if it were `use`. Fix #69492. --- compiler/rustc_expand/messages.ftl | 1 + compiler/rustc_expand/src/errors.rs | 1 + tests/run-make/unknown-mod-stdin/unknown-mod.stderr | 1 + tests/ui/error-codes/E0583.stderr | 1 + .../invalid-module-declaration.stderr | 1 + tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr | 1 + .../missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr | 1 + tests/ui/modules/special_module_name.stderr | 2 ++ tests/ui/parser/mod_file_not_exist.stderr | 1 + tests/ui/parser/unsafe-mod.stderr | 1 + .../mod_file_nonascii_forbidden.stderr | 1 + 11 files changed, 12 insertions(+) diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 6c7e68246ea5f..8b93829623dbf 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -86,6 +86,7 @@ expand_module_circular = expand_module_file_not_found = file not found for module `{$name}` .help = to create the module `{$name}`, create file "{$default_path}" or "{$secondary_path}" + .note = if there is a `mod {$name}` elsewhere in the crate already, import it with `use crate::...` instead expand_module_in_block = cannot declare a non-inline module inside a block unless it has a path attribute diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index e3a0ae3570eb0..d86632c47fc5d 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -350,6 +350,7 @@ pub(crate) struct ModuleInBlockName { #[derive(Diagnostic)] #[diag(expand_module_file_not_found, code = "E0583")] #[help] +#[note] pub(crate) struct ModuleFileNotFound { #[primary_span] pub span: Span, diff --git a/tests/run-make/unknown-mod-stdin/unknown-mod.stderr b/tests/run-make/unknown-mod-stdin/unknown-mod.stderr index d7258fe4f68d8..81ff83938378c 100644 --- a/tests/run-make/unknown-mod-stdin/unknown-mod.stderr +++ b/tests/run-make/unknown-mod-stdin/unknown-mod.stderr @@ -5,6 +5,7 @@ error[E0583]: file not found for module `unknown` | ^^^^^^^^^^^^ | = help: to create the module `unknown`, create file "unknown.rs" or "unknown/mod.rs" + = note: if there is a `mod unknown` elsewhere in the crate already, import it with `use crate::...` instead error: aborting due to previous error diff --git a/tests/ui/error-codes/E0583.stderr b/tests/ui/error-codes/E0583.stderr index c7bbbf114997d..6707f2864f23c 100644 --- a/tests/ui/error-codes/E0583.stderr +++ b/tests/ui/error-codes/E0583.stderr @@ -5,6 +5,7 @@ LL | mod module_that_doesnt_exist; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs" or "$DIR/module_that_doesnt_exist/mod.rs" + = note: if there is a `mod module_that_doesnt_exist` elsewhere in the crate already, import it with `use crate::...` instead error: aborting due to previous error diff --git a/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr b/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr index 7bc8efd7e4a97..08aec25928c0d 100644 --- a/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr +++ b/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr @@ -5,6 +5,7 @@ LL | pub mod baz; | ^^^^^^^^^^^^ | = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" or "$DIR/auxiliary/foo/bar/baz/mod.rs" + = note: if there is a `mod baz` elsewhere in the crate already, import it with `use crate::...` instead error: aborting due to previous error diff --git a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr index 31e4206a5463a..5f4d19439accd 100644 --- a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr +++ b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr @@ -5,6 +5,7 @@ LL | mod missing; | ^^^^^^^^^^^^ | = help: to create the module `missing`, create file "$DIR/foo/missing.rs" or "$DIR/foo/missing/mod.rs" + = note: if there is a `mod missing` elsewhere in the crate already, import it with `use crate::...` instead error: aborting due to previous error diff --git a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr index 9d252398b7a14..d5f5ea8705971 100644 --- a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr +++ b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr @@ -5,6 +5,7 @@ LL | mod missing; | ^^^^^^^^^^^^ | = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs" or "$DIR/foo_inline/inline/missing/mod.rs" + = note: if there is a `mod missing` elsewhere in the crate already, import it with `use crate::...` instead error: aborting due to previous error diff --git a/tests/ui/modules/special_module_name.stderr b/tests/ui/modules/special_module_name.stderr index bc4b4f1b3181c..84473bf8c0bc6 100644 --- a/tests/ui/modules/special_module_name.stderr +++ b/tests/ui/modules/special_module_name.stderr @@ -5,6 +5,7 @@ LL | mod lib; | ^^^^^^^^ | = help: to create the module `lib`, create file "$DIR/lib.rs" or "$DIR/lib/mod.rs" + = note: if there is a `mod lib` elsewhere in the crate already, import it with `use crate::...` instead error[E0583]: file not found for module `main` --> $DIR/special_module_name.rs:4:1 @@ -13,6 +14,7 @@ LL | mod main; | ^^^^^^^^^ | = help: to create the module `main`, create file "$DIR/main.rs" or "$DIR/main/mod.rs" + = note: if there is a `mod main` elsewhere in the crate already, import it with `use crate::...` instead warning: found module declaration for lib.rs --> $DIR/special_module_name.rs:1:1 diff --git a/tests/ui/parser/mod_file_not_exist.stderr b/tests/ui/parser/mod_file_not_exist.stderr index 62456d518804f..c2f9d30d9ec40 100644 --- a/tests/ui/parser/mod_file_not_exist.stderr +++ b/tests/ui/parser/mod_file_not_exist.stderr @@ -5,6 +5,7 @@ LL | mod not_a_real_file; | ^^^^^^^^^^^^^^^^^^^^ | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs" + = note: if there is a `mod not_a_real_file` elsewhere in the crate already, import it with `use crate::...` instead error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist.rs:7:16 diff --git a/tests/ui/parser/unsafe-mod.stderr b/tests/ui/parser/unsafe-mod.stderr index dac6e7a355056..fbe24aa10da42 100644 --- a/tests/ui/parser/unsafe-mod.stderr +++ b/tests/ui/parser/unsafe-mod.stderr @@ -5,6 +5,7 @@ LL | unsafe mod n; | ^^^^^^^^^^^^^ | = help: to create the module `n`, create file "$DIR/n.rs" or "$DIR/n/mod.rs" + = note: if there is a `mod n` elsewhere in the crate already, import it with `use crate::...` instead error: module cannot be declared unsafe --> $DIR/unsafe-mod.rs:1:1 diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr index 7639ae9f6a4fd..8ca6a37c62518 100644 --- a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr @@ -5,6 +5,7 @@ LL | mod řųśť; | ^^^^^^^^^ | = help: to create the module `řųśť`, create file "$DIR/řųśť.rs" or "$DIR/řųśť/mod.rs" + = note: if there is a `mod řųśť` elsewhere in the crate already, import it with `use crate::...` instead error[E0754]: trying to load file for module `řųśť` with non-ascii identifier name --> $DIR/mod_file_nonascii_forbidden.rs:1:5