From d7d701a9dc6c424e01d49d937925dc3bf7718138 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 14:54:53 +0200 Subject: [PATCH 1/6] Create specific ConstantHasGenerics for ConstantItemRibKind. --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/ident.rs | 12 ++++++-- compiler/rustc_resolve/src/late.rs | 35 ++++++++++++++--------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 325b0458638af..193610ff57d55 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -550,7 +550,7 @@ impl<'a> Resolver<'a> { } } - if has_generic_params == HasGenericParams::Yes { + if let HasGenericParams::Yes = has_generic_params { // Try to retrieve the span of the function signature and generate a new // message with a local type or const parameter. let sugg_msg = "try using a local generic parameter instead"; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 6e6782881427b..be50eecf4b128 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -13,7 +13,9 @@ use rustc_span::{Span, DUMMY_SP}; use std::ptr; -use crate::late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind}; +use crate::late::{ + ConstantHasGenerics, ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind, +}; use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; @@ -1180,7 +1182,9 @@ impl<'a> Resolver<'a> { ConstantItemRibKind(trivial, _) => { let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) { + if !(trivial == ConstantHasGenerics::Yes + || features.generic_const_exprs) + { // HACK(min_const_generics): If we encounter `Self` in an anonymous constant // we can't easily tell if it's generic at this stage, so we instead remember // this and then enforce the self type to be concrete later on. @@ -1253,7 +1257,9 @@ impl<'a> Resolver<'a> { ConstantItemRibKind(trivial, _) => { let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) { + if !(trivial == ConstantHasGenerics::Yes + || features.generic_const_exprs) + { if let Some(span) = finalize { self.report_error( span, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 58a4cff55db7d..b6fedd838bb33 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -91,13 +91,20 @@ enum PatBoundCtx { } /// Does this the item (from the item rib scope) allow generic parameters? -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug)] pub(crate) enum HasGenericParams { Yes, No, } -impl HasGenericParams { +/// May this constant have generics? +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(crate) enum ConstantHasGenerics { + Yes, + No, +} + +impl ConstantHasGenerics { fn force_yes_if(self, b: bool) -> Self { if b { Self::Yes } else { self } } @@ -136,7 +143,7 @@ pub(crate) enum RibKind<'a> { /// /// The item may reference generic parameters in trivial constant expressions. /// All other constants aren't allowed to use generic params at all. - ConstantItemRibKind(HasGenericParams, Option<(Ident, ConstantItemKind)>), + ConstantItemRibKind(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>), /// We passed through a module. ModuleRibKind(Module<'a>), @@ -995,7 +1002,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // non-trivial constants this is doesn't matter. self.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| { this.smart_resolve_path( @@ -2251,7 +2258,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // so it doesn't matter whether this is a trivial constant. this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, Some((item.ident, constant_item_kind)), |this| this.visit_expr(expr), ); @@ -2450,7 +2457,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn with_constant_rib( &mut self, is_repeat: IsRepeatExpr, - may_use_generics: HasGenericParams, + may_use_generics: ConstantHasGenerics, item: Option<(Ident, ConstantItemKind)>, f: impl FnOnce(&mut Self), ) { @@ -2517,7 +2524,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { |this| { this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| this.visit_expr(expr), ) @@ -2689,7 +2696,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| this.visit_expr(expr), ) @@ -3696,9 +3703,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_constant_rib( is_repeat, if constant.value.is_potential_trivial_const_param() { - HasGenericParams::Yes + ConstantHasGenerics::Yes } else { - HasGenericParams::No + ConstantHasGenerics::No }, None, |this| visit::walk_anon_const(this, constant), @@ -3707,8 +3714,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn resolve_inline_const(&mut self, constant: &'ast AnonConst) { debug!("resolve_anon_const {constant:?}"); - self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| { - visit::walk_anon_const(this, constant); + self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| { + visit::walk_anon_const(this, constant) }); } @@ -3814,9 +3821,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_constant_rib( IsRepeatExpr::No, if argument.is_potential_trivial_const_param() { - HasGenericParams::Yes + ConstantHasGenerics::Yes } else { - HasGenericParams::No + ConstantHasGenerics::No }, None, |this| { From 613dc2204dc628e6804b9d2be8bdeb6f6f43611e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 15:09:30 +0200 Subject: [PATCH 2/6] Improve local generic parameter suggestions. --- compiler/rustc_resolve/src/diagnostics.rs | 33 +++++++++---------- compiler/rustc_resolve/src/ident.rs | 8 ++--- compiler/rustc_resolve/src/late.rs | 18 +++++----- compiler/rustc_resolve/src/lib.rs | 10 ++++++ compiler/rustc_span/src/symbol.rs | 1 + .../early/const-param-from-outer-fn.stderr | 2 +- src/test/ui/error-codes/E0401.stderr | 8 ++--- src/test/ui/generics/issue-98432.stderr | 6 ++-- src/test/ui/issues/issue-3214.stderr | 5 ++- src/test/ui/issues/issue-5997-enum.stderr | 8 ++--- src/test/ui/issues/issue-5997-struct.stderr | 8 ++--- src/test/ui/nested-ty-params.stderr | 12 +++---- .../ui/resolve/bad-type-env-capture.stderr | 6 ++-- src/test/ui/resolve/issue-3021-c.stderr | 16 ++++----- ...resolve-type-param-in-item-in-trait.stderr | 18 +++++----- src/test/ui/type/type-arg-out-of-scope.stderr | 12 +++---- 16 files changed, 90 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 193610ff57d55..fc19835019881 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -511,7 +511,7 @@ impl<'a> Resolver<'a> { err.span_label(span, "use of generic parameter from outer function"); let sm = self.session.source_map(); - match outer_res { + let def_id = match outer_res { Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => { if let Some(impl_span) = maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id)) @@ -536,11 +536,13 @@ impl<'a> Resolver<'a> { if let Some(span) = self.opt_span(def_id) { err.span_label(span, "type parameter from outer function"); } + def_id } Res::Def(DefKind::ConstParam, def_id) => { if let Some(span) = self.opt_span(def_id) { err.span_label(span, "const parameter from outer function"); } + def_id } _ => { bug!( @@ -548,28 +550,23 @@ impl<'a> Resolver<'a> { DefKind::TyParam or DefKind::ConstParam" ); } - } + }; - if let HasGenericParams::Yes = has_generic_params { + if let HasGenericParams::Yes(span) = has_generic_params { // Try to retrieve the span of the function signature and generate a new // message with a local type or const parameter. let sugg_msg = "try using a local generic parameter instead"; - if let Some((sugg_span, snippet)) = sm.generate_local_type_param_snippet(span) { - // Suggest the modification to the user - err.span_suggestion( - sugg_span, - sugg_msg, - snippet, - Applicability::MachineApplicable, - ); - } else if let Some(sp) = sm.generate_fn_name_span(span) { - err.span_label( - sp, - "try adding a local generic parameter in this method instead", - ); + let name = self.opt_name(def_id).unwrap_or(sym::T); + let (span, snippet) = if span.is_empty() { + let snippet = format!("<{}>", name); + (span, snippet) } else { - err.help("try using a local generic parameter instead"); - } + let span = sm.span_through_char(span, '<').shrink_to_hi(); + let snippet = format!("{}, ", name); + (span, snippet) + }; + // Suggest the modification to the user + err.span_suggestion(span, sugg_msg, snippet, Applicability::MachineApplicable); } err diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index be50eecf4b128..0d8f1cf365643 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1170,10 +1170,11 @@ impl<'a> Resolver<'a> { let has_generic_params: HasGenericParams = match rib.kind { NormalRibKind | ClosureOrAsyncRibKind - | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind + | FnItemRibKind + | AssocItemRibKind | ForwardGenericParamBanRibKind => { // Nothing to do. Continue. continue; @@ -1211,7 +1212,6 @@ impl<'a> Resolver<'a> { // This was an attempt to use a type parameter outside its scope. ItemRibKind(has_generic_params) => has_generic_params, - FnItemRibKind => HasGenericParams::Yes, ConstParamTyRibKind => { if let Some(span) = finalize { self.report_error( @@ -1248,10 +1248,11 @@ impl<'a> Resolver<'a> { let has_generic_params = match rib.kind { NormalRibKind | ClosureOrAsyncRibKind - | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind + | FnItemRibKind + | AssocItemRibKind | ForwardGenericParamBanRibKind => continue, ConstantItemRibKind(trivial, _) => { @@ -1278,7 +1279,6 @@ impl<'a> Resolver<'a> { } ItemRibKind(has_generic_params) => has_generic_params, - FnItemRibKind => HasGenericParams::Yes, ConstParamTyRibKind => { if let Some(span) = finalize { self.report_error( diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b6fedd838bb33..748a0781c4f7a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -93,7 +93,7 @@ enum PatBoundCtx { /// Does this the item (from the item rib scope) allow generic parameters? #[derive(Copy, Clone, Debug)] pub(crate) enum HasGenericParams { - Yes, + Yes(Span), No, } @@ -758,7 +758,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Item, @@ -772,7 +772,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Function, @@ -2078,7 +2078,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_current_self_item(item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2148,7 +2148,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::TyAlias(box TyAlias { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2161,7 +2161,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::Fn(box Fn { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Function, @@ -2193,7 +2193,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2217,7 +2217,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2605,7 +2605,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // If applicable, create a rib for the type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { span: generics.span, binder: item_id, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9c213da8c2a2c..eb727debc91bb 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1945,6 +1945,16 @@ impl<'a> Resolver<'a> { def_id.as_local().map(|def_id| self.source_span[def_id]) } + /// Retrieves the name of the given `DefId`. + #[inline] + pub fn opt_name(&self, def_id: DefId) -> Option { + let def_key = match def_id.as_local() { + Some(def_id) => self.definitions.def_key(def_id), + None => self.cstore().def_key(def_id), + }; + def_key.get_opt_name() + } + /// Checks if an expression refers to a function marked with /// `#[rustc_legacy_const_generics]` and returns the argument index list /// from the attribute. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 156f53ac48626..c8978845ffb0d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -280,6 +280,7 @@ symbols! { StructuralPartialEq, SubdiagnosticMessage, Sync, + T, Target, ToOwned, ToString, diff --git a/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr b/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr index a9f9787d87595..e3bf38b702e75 100644 --- a/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr +++ b/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr @@ -4,7 +4,7 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo() { | - const parameter from outer function LL | fn bar() -> u32 { - | --- try adding a local generic parameter in this method instead + | - help: try using a local generic parameter instead: `` LL | X | ^ use of generic parameter from outer function diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 81715621dd921..b0e2ef5b6f7e3 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo(x: T) { | - type parameter from outer function LL | fn bfnr, W: Fn()>(y: T) { - | --------------------------- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bfnr, W: Fn(), T>` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `T,` error[E0401]: can't use generic parameters from outer function --> $DIR/E0401.rs:9:16 @@ -15,7 +15,7 @@ LL | fn foo(x: T) { | - type parameter from outer function ... LL | fn baz Struct { | - type parameter from outer function LL | const CONST: fn() = || { LL | struct _Obligation where T:; - | ^ use of generic parameter from outer function - | - = help: try using a local generic parameter instead + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3214.stderr b/src/test/ui/issues/issue-3214.stderr index 4d8eb6360e640..aa0b5ce64b421 100644 --- a/src/test/ui/issues/issue-3214.stderr +++ b/src/test/ui/issues/issue-3214.stderr @@ -2,10 +2,9 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-3214.rs:3:12 | LL | fn foo() { - | --- - type parameter from outer function - | | - | try adding a local generic parameter in this method instead + | - type parameter from outer function LL | struct Foo { + | - help: try using a local generic parameter instead: `` LL | x: T, | ^ use of generic parameter from outer function diff --git a/src/test/ui/issues/issue-5997-enum.stderr b/src/test/ui/issues/issue-5997-enum.stderr index 1c58b9c391104..3a79215d3ae9c 100644 --- a/src/test/ui/issues/issue-5997-enum.stderr +++ b/src/test/ui/issues/issue-5997-enum.stderr @@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-5997-enum.rs:2:16 | LL | fn f() -> bool { - | - - type parameter from outer function - | | - | try adding a local generic parameter in this method instead + | - type parameter from outer function LL | enum E { V(Z) } - | ^ use of generic parameter from outer function + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5997-struct.stderr b/src/test/ui/issues/issue-5997-struct.stderr index 5b388d16d7553..d2e97f767719f 100644 --- a/src/test/ui/issues/issue-5997-struct.stderr +++ b/src/test/ui/issues/issue-5997-struct.stderr @@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-5997-struct.rs:2:14 | LL | fn f() -> bool { - | - - type parameter from outer function - | | - | try adding a local generic parameter in this method instead + | - type parameter from outer function LL | struct S(T); - | ^ use of generic parameter from outer function + | -^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/nested-ty-params.stderr b/src/test/ui/nested-ty-params.stderr index f6741b5e5e82a..8f4746f5ec3bd 100644 --- a/src/test/ui/nested-ty-params.stderr +++ b/src/test/ui/nested-ty-params.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn hd(v: Vec ) -> U { | - type parameter from outer function LL | fn hd1(w: [U]) -> U { return w[0]; } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `hd1` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error[E0401]: can't use generic parameters from outer function --> $DIR/nested-ty-params.rs:3:23 @@ -14,9 +14,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn hd(v: Vec ) -> U { | - type parameter from outer function LL | fn hd1(w: [U]) -> U { return w[0]; } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `hd1` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/bad-type-env-capture.stderr b/src/test/ui/resolve/bad-type-env-capture.stderr index 6f24c0d86997e..b6282c2d0703b 100644 --- a/src/test/ui/resolve/bad-type-env-capture.stderr +++ b/src/test/ui/resolve/bad-type-env-capture.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo() { | - type parameter from outer function LL | fn bar(b: T) { } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bar` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-3021-c.stderr b/src/test/ui/resolve/issue-3021-c.stderr index 8764ac8a8563c..5176efc3a6be7 100644 --- a/src/test/ui/resolve/issue-3021-c.stderr +++ b/src/test/ui/resolve/issue-3021-c.stderr @@ -3,22 +3,22 @@ error[E0401]: can't use generic parameters from outer function | LL | fn siphash() { | - type parameter from outer function -... +LL | +LL | trait U { + | - help: try using a local generic parameter instead: `` LL | fn g(&self, x: T) -> T; - | - ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `g` + | ^ use of generic parameter from outer function error[E0401]: can't use generic parameters from outer function --> $DIR/issue-3021-c.rs:4:30 | LL | fn siphash() { | - type parameter from outer function -... +LL | +LL | trait U { + | - help: try using a local generic parameter instead: `` LL | fn g(&self, x: T) -> T; - | - ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `g` + | ^ use of generic parameter from outer function error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr b/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr index 10a703ee09351..0a6d1cc3bcd45 100644 --- a/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr +++ b/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr @@ -4,8 +4,8 @@ error[E0401]: can't use generic parameters from outer function LL | trait TraitA { | - type parameter from outer function LL | fn outer(&self) { - | ----- try adding a local generic parameter in this method instead LL | enum Foo { + | - help: try using a local generic parameter instead: `A,` LL | Variance(A) | ^ use of generic parameter from outer function @@ -15,9 +15,10 @@ error[E0401]: can't use generic parameters from outer function LL | trait TraitB { | - type parameter from outer function LL | fn outer(&self) { - | ----- try adding a local generic parameter in this method instead LL | struct Foo(A); - | ^ use of generic parameter from outer function + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `A,` error[E0401]: can't use generic parameters from outer function --> $DIR/resolve-type-param-in-item-in-trait.rs:23:28 @@ -25,9 +26,10 @@ error[E0401]: can't use generic parameters from outer function LL | trait TraitC { | - type parameter from outer function LL | fn outer(&self) { - | ----- try adding a local generic parameter in this method instead LL | struct Foo { a: A } - | ^ use of generic parameter from outer function + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `A,` error[E0401]: can't use generic parameters from outer function --> $DIR/resolve-type-param-in-item-in-trait.rs:30:22 @@ -36,9 +38,9 @@ LL | trait TraitD { | - type parameter from outer function LL | fn outer(&self) { LL | fn foo(a: A) { } - | ------ ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `foo` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `A,` error: aborting due to 4 previous errors diff --git a/src/test/ui/type/type-arg-out-of-scope.stderr b/src/test/ui/type/type-arg-out-of-scope.stderr index 0b6283fbc51e9..7f18b4510f4b2 100644 --- a/src/test/ui/type/type-arg-out-of-scope.stderr +++ b/src/test/ui/type/type-arg-out-of-scope.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo(x: T) { | - type parameter from outer function LL | fn bar(f: Box T>) { } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bar` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error[E0401]: can't use generic parameters from outer function --> $DIR/type-arg-out-of-scope.rs:3:35 @@ -14,9 +14,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo(x: T) { | - type parameter from outer function LL | fn bar(f: Box T>) { } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bar` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to 2 previous errors From 362e6361d09f554b438f638fc8113b6091aa01b8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 17:27:49 +0200 Subject: [PATCH 3/6] Do not call generate_fn_name_span in typeck. --- .../rustc_typeck/src/check/compare_method.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index dfef924f6993a..df171c2531a7a 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -858,8 +858,7 @@ fn compare_synthetic_generics<'tcx>( { if impl_synthetic != trait_synthetic { let impl_def_id = impl_def_id.expect_local(); - let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id); - let impl_span = tcx.hir().span(impl_hir_id); + let impl_span = tcx.def_span(impl_def_id); let trait_span = tcx.def_span(trait_def_id); let mut err = struct_span_err!( tcx.sess, @@ -878,17 +877,16 @@ fn compare_synthetic_generics<'tcx>( // try taking the name from the trait impl // FIXME: this is obviously suboptimal since the name can already be used // as another generic argument - let new_name = tcx.sess.source_map().span_to_snippet(trait_span).ok()?; + let new_name = tcx.opt_item_name(trait_def_id)?; let trait_m = trait_m.def_id.as_local()?; - let trait_m = tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m }); + let trait_m = tcx.hir().expect_trait_item(trait_m); let impl_m = impl_m.def_id.as_local()?; - let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m }); + let impl_m = tcx.hir().expect_impl_item(impl_m); // in case there are no generics, take the spot between the function name // and the opening paren of the argument list - let new_generics_span = - tcx.sess.source_map().generate_fn_name_span(impl_span)?.shrink_to_hi(); + let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi(); // in case there are generics, just replace them let generics_span = impl_m.generics.span.substitute_dummy(new_generics_span); @@ -900,7 +898,7 @@ fn compare_synthetic_generics<'tcx>( "try changing the `impl Trait` argument to a generic parameter", vec![ // replace `impl Trait` with `T` - (impl_span, new_name), + (impl_span, new_name.to_string()), // replace impl method generics with trait method generics // This isn't quite right, as users might have changed the names // of the generics, but it works for the common case @@ -917,7 +915,7 @@ fn compare_synthetic_generics<'tcx>( err.span_label(impl_span, "expected `impl Trait`, found generic parameter"); (|| { let impl_m = impl_m.def_id.as_local()?; - let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m }); + let impl_m = tcx.hir().expect_impl_item(impl_m); let input_tys = match impl_m.kind { hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs, _ => unreachable!(), From 6e88d738be05637824f581fc9cb59990406bf2ba Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 17:28:34 +0200 Subject: [PATCH 4/6] Remove generate_fn_name_span and generate_local_type_param_snippet. --- compiler/rustc_span/src/source_map.rs | 87 --------------------------- 1 file changed, 87 deletions(-) diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 5f928707ea826..a32cabab4c407 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -982,93 +982,6 @@ impl SourceMap { self.files().iter().fold(0, |a, f| a + f.count_lines()) } - pub fn generate_fn_name_span(&self, span: Span) -> Option { - let prev_span = self.span_extend_to_prev_str(span, "fn", true, true)?; - if let Ok(snippet) = self.span_to_snippet(prev_span) { - debug!( - "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}", - span, prev_span, snippet - ); - - if snippet.is_empty() { - return None; - }; - - let len = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - Some(prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32))) - } else { - None - } - } - - /// Takes the span of a type parameter in a function signature and try to generate a span for - /// the function name (with generics) and a new snippet for this span with the pointed type - /// parameter as a new local type parameter. - /// - /// For instance: - /// ```rust,ignore (pseudo-Rust) - /// // Given span - /// fn my_function(param: T) - /// // ^ Original span - /// - /// // Result - /// fn my_function(param: T) - /// // ^^^^^^^^^^^ Generated span with snippet `my_function` - /// ``` - /// - /// Attention: The method used is very fragile since it essentially duplicates the work of the - /// parser. If you need to use this function or something similar, please consider updating the - /// `SourceMap` functions and this function to something more robust. - pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> { - // Try to extend the span to the previous "fn" keyword to retrieve the function - // signature. - if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) { - if let Ok(snippet) = self.span_to_snippet(sugg_span) { - // Consume the function name. - let mut offset = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - - // Consume the generics part of the function signature. - let mut bracket_counter = 0; - let mut last_char = None; - for c in snippet[offset..].chars() { - match c { - '<' => bracket_counter += 1, - '>' => bracket_counter -= 1, - '(' => { - if bracket_counter == 0 { - break; - } - } - _ => {} - } - offset += c.len_utf8(); - last_char = Some(c); - } - - // Adjust the suggestion span to encompass the function name with its generics. - let sugg_span = sugg_span.with_hi(BytePos(sugg_span.lo().0 + offset as u32)); - - // Prepare the new suggested snippet to append the type parameter that triggered - // the error in the generics of the function signature. - let mut new_snippet = if last_char == Some('>') { - format!("{}, ", &snippet[..(offset - '>'.len_utf8())]) - } else { - format!("{}<", &snippet[..offset]) - }; - new_snippet - .push_str(&self.span_to_snippet(span).unwrap_or_else(|_| "T".to_string())); - new_snippet.push('>'); - - return Some((sugg_span, new_snippet)); - } - } - - None - } pub fn ensure_source_file_source_present(&self, source_file: Lrc) -> bool { source_file.add_external_src(|| { match source_file.name { From da9ccc2c98ac4d88e5f2b940b9b61ec6d25facaa Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 17:40:43 +0200 Subject: [PATCH 5/6] Remove FnItemRibKind. --- compiler/rustc_resolve/src/ident.rs | 12 +----------- compiler/rustc_resolve/src/late.rs | 25 +++++++++---------------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 0d8f1cf365643..41a0c76d83a95 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1105,7 +1105,7 @@ impl<'a> Resolver<'a> { | ForwardGenericParamBanRibKind => { // Nothing to do. Continue. } - ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => { + ItemRibKind(_) | AssocItemRibKind => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. @@ -1173,7 +1173,6 @@ impl<'a> Resolver<'a> { | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind - | FnItemRibKind | AssocItemRibKind | ForwardGenericParamBanRibKind => { // Nothing to do. Continue. @@ -1236,14 +1235,6 @@ impl<'a> Resolver<'a> { } } Res::Def(DefKind::ConstParam, _) => { - let mut ribs = ribs.iter().peekable(); - if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() { - // When declaring const parameters inside function signatures, the first rib - // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it - // (spuriously) conflicting with the const param. - ribs.next(); - } - for rib in ribs { let has_generic_params = match rib.kind { NormalRibKind @@ -1251,7 +1242,6 @@ impl<'a> Resolver<'a> { | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind - | FnItemRibKind | AssocItemRibKind | ForwardGenericParamBanRibKind => continue, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 748a0781c4f7a..693ec86616ee4 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -132,10 +132,6 @@ pub(crate) enum RibKind<'a> { /// We passed through a closure. Disallow labels. ClosureOrAsyncRibKind, - /// We passed through a function definition. Disallow upvars. - /// Permit only those const parameters that are specified in the function's generics. - FnItemRibKind, - /// We passed through an item scope. Disallow upvars. ItemRibKind(HasGenericParams), @@ -172,7 +168,6 @@ impl RibKind<'_> { match self { NormalRibKind | ClosureOrAsyncRibKind - | FnItemRibKind | ConstantItemRibKind(..) | ModuleRibKind(_) | MacroDefinition(_) @@ -189,7 +184,6 @@ impl RibKind<'_> { AssocItemRibKind | ClosureOrAsyncRibKind - | FnItemRibKind | ItemRibKind(..) | ConstantItemRibKind(..) | ModuleRibKind(..) @@ -793,7 +787,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) { - let rib_kind = match fn_kind { + let previous_value = self.diagnostic_metadata.current_function; + match fn_kind { // Bail if the function is foreign, and thus cannot validly have // a body, or if there's no body for some other reason. FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) @@ -816,20 +811,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { ); return; } - FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind, - FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind, - FnKind::Closure(..) => ClosureOrAsyncRibKind, + FnKind::Fn(..) => { + self.diagnostic_metadata.current_function = Some((fn_kind, sp)); + } + // Do not update `current_function` for closures: it suggests `self` parameters. + FnKind::Closure(..) => {} }; - let previous_value = self.diagnostic_metadata.current_function; - if matches!(fn_kind, FnKind::Fn(..)) { - self.diagnostic_metadata.current_function = Some((fn_kind, sp)); - } debug!("(resolving function) entering function"); // Create a value rib for the function. - self.with_rib(ValueNS, rib_kind, |this| { + self.with_rib(ValueNS, ClosureOrAsyncRibKind, |this| { // Create a label rib for the function. - this.with_label_rib(FnItemRibKind, |this| { + this.with_label_rib(ClosureOrAsyncRibKind, |this| { match fn_kind { FnKind::Fn(_, _, sig, _, generics, body) => { this.visit_generics(generics); From dff428013dde1e89b6c644b9649f0dc53ceac354 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 23 Aug 2022 00:09:58 +0200 Subject: [PATCH 6/6] Mark suggestion as MaybeIncorrect. --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index fc19835019881..25013036d8749 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -566,7 +566,7 @@ impl<'a> Resolver<'a> { (span, snippet) }; // Suggest the modification to the user - err.span_suggestion(span, sugg_msg, snippet, Applicability::MachineApplicable); + err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect); } err