diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_borrowck/src/diagnostics/region_name.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_error_messages/locales/en-US/parser.ftl | 18 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/def.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/lib.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/mod.rs | 62 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs | 50 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/print/pretty.rs | 71 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 121 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/check.rs | 177 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/compare_method.rs | 20 |
12 files changed, 336 insertions, 213 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 4d2a16aa609..cb4b154d271 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -567,15 +567,17 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; match lifetime.name { - hir::LifetimeName::Param(_) + hir::LifetimeName::Param(hir::ParamName::Plain(_) | hir::ParamName::Error) | hir::LifetimeName::Error - | hir::LifetimeName::Static - | hir::LifetimeName::Underscore => { + | hir::LifetimeName::Static => { let lifetime_span = lifetime.span; Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) } - hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => { + hir::LifetimeName::Param(hir::ParamName::Fresh(_)) + | hir::LifetimeName::ImplicitObjectLifetimeDefault + | hir::LifetimeName::Implicit + | hir::LifetimeName::Underscore => { // In this case, the user left off the lifetime; so // they wrote something like: // diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index c98989b23c1..076b1b1caed 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -14,3 +14,21 @@ parser-add-paren = try adding parentheses parser-forgot-paren = perhaps you forgot parentheses? parser-expect-path = expected a path + +parser-maybe-recover-from-bad-qpath-stage-2 = + missing angle brackets in associated item path + .suggestion = try: `{$ty}` + +parser-incorrect-semicolon = + expected item, found `;` + .suggestion = remove this semicolon + .help = {$name} declarations are not followed by a semicolon + +parser-incorrect-use-of-await = + incorrect use of `await` + .parentheses-suggestion = `await` is not a method call, remove the parentheses + .postfix-suggestion = `await` is a postfix operation + +parser-in-in-typo = + expected iterable, found keyword `in` + .suggestion = remove the duplicated `in` diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 68876e89c4b..414f6272591 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -671,7 +671,10 @@ impl<Id> Res<Id> { #[track_caller] pub fn expect_non_local<OtherId>(self) -> Res<OtherId> { - self.map_id(|_| panic!("unexpected `Res::Local`")) + self.map_id( + #[track_caller] + |_| panic!("unexpected `Res::Local`"), + ) } pub fn macro_kind(self) -> Option<MacroKind> { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bda7affe529..dbe6fe6ea84 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -131,6 +131,17 @@ impl LifetimeName { } } + pub fn is_anonymous(&self) -> bool { + match *self { + LifetimeName::ImplicitObjectLifetimeDefault + | LifetimeName::Implicit + | LifetimeName::Underscore + | LifetimeName::Param(ParamName::Fresh(_)) + | LifetimeName::Error => true, + LifetimeName::Static | LifetimeName::Param(_) => false, + } + } + pub fn is_elided(&self) -> bool { match self { LifetimeName::ImplicitObjectLifetimeDefault diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 7833571f88d..d845c433d8c 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -3,6 +3,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html #![feature(associated_type_defaults)] +#![feature(closure_track_caller)] #![feature(const_btree_new)] #![feature(let_else)] #![feature(once_cell)] diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e156930cc89..579d7efb568 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -72,7 +72,7 @@ use rustc_middle::ty::{ subst::{GenericArgKind, Subst, SubstsRef}, Binder, EarlyBinder, List, Region, Ty, TyCtxt, TypeFoldable, }; -use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span}; +use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; use std::ops::ControlFlow; use std::{cmp, fmt, iter}; @@ -161,35 +161,45 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>( { sp = param.span; } - (format!("the lifetime `{}` as defined here", br.name), sp) + let text = if br.has_name() { + format!("the lifetime `{}` as defined here", br.name) + } else { + format!("the anonymous lifetime as defined here") + }; + (text, sp) } - ty::ReFree(ty::FreeRegion { - bound_region: ty::BoundRegionKind::BrNamed(_, name), .. - }) => { - let mut sp = sm.guess_head_span(tcx.def_span(scope)); - if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) + ty::ReFree(ref fr) => { + if !fr.bound_region.is_named() + && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) { - sp = param.span; - } - (format!("the lifetime `{}` as defined here", name), sp) - } - ty::ReFree(ref fr) => match fr.bound_region { - ty::BrAnon(idx) => { - if let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) { - ("the anonymous lifetime defined here".to_string(), ty.span) - } else { - ( + ("the anonymous lifetime defined here".to_string(), ty.span) + } else { + match fr.bound_region { + ty::BoundRegionKind::BrNamed(_, name) => { + let mut sp = sm.guess_head_span(tcx.def_span(scope)); + if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) + { + sp = param.span; + } + let text = if name == kw::UnderscoreLifetime { + format!("the anonymous lifetime as defined here") + } else { + format!("the lifetime `{}` as defined here", name) + }; + (text, sp) + } + ty::BrAnon(idx) => ( format!("the anonymous lifetime #{} defined here", idx + 1), - tcx.def_span(scope), - ) + tcx.def_span(scope) + ), + _ => ( + format!("the lifetime `{}` as defined here", region), + sm.guess_head_span(tcx.def_span(scope)), + ), } } - _ => ( - format!("the lifetime `{}` as defined here", region), - sm.guess_head_span(tcx.def_span(scope)), - ), - }, + } _ => bug!(), } } @@ -2552,7 +2562,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. }) | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }), _, - ) => { + ) if name != kw::UnderscoreLifetime => { // Does the required lifetime have a nice name we can print? let mut err = struct_span_err!( self.tcx.sess, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index cb72cb41a7c..b744594ddb7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -12,6 +12,7 @@ use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::{GenericParamKind, Ty}; use rustc_middle::ty::Region; +use rustc_span::symbol::kw; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when both the concerned regions are anonymous. @@ -169,7 +170,7 @@ pub fn suggest_adding_lifetime_params<'tcx>( return false; }; - if !lifetime_sub.name.is_elided() || !lifetime_sup.name.is_elided() { + if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() { return false; }; @@ -188,32 +189,37 @@ pub fn suggest_adding_lifetime_params<'tcx>( _ => return false, }; - let (suggestion_param_name, introduce_new) = generics + let suggestion_param_name = generics .params .iter() - .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) - .and_then(|p| tcx.sess.source_map().span_to_snippet(p.span).ok()) - .map(|name| (name, false)) - .unwrap_or_else(|| ("'a".to_string(), true)); - - let mut suggestions = vec![ - if let hir::LifetimeName::Underscore = lifetime_sub.name { - (lifetime_sub.span, suggestion_param_name.clone()) + .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + .map(|p| p.name.ident().name) + .find(|i| *i != kw::UnderscoreLifetime); + let introduce_new = suggestion_param_name.is_none(); + let suggestion_param_name = + suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned()); + + debug!(?lifetime_sup.span); + debug!(?lifetime_sub.span); + let make_suggestion = |span: rustc_span::Span| { + if span.is_empty() { + (span, format!("{}, ", suggestion_param_name)) + } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() { + (span.shrink_to_hi(), format!("{} ", suggestion_param_name)) } else { - (lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ") - }, - if let hir::LifetimeName::Underscore = lifetime_sup.name { - (lifetime_sup.span, suggestion_param_name.clone()) - } else { - (lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ") - }, - ]; + (span, suggestion_param_name.clone()) + } + }; + let mut suggestions = + vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)]; if introduce_new { - let new_param_suggestion = match &generics.params { - [] => (generics.span, format!("<{}>", suggestion_param_name)), - [first, ..] => (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)), - }; + let new_param_suggestion = + if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) { + (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)) + } else { + (generics.span, format!("<{}>", suggestion_param_name)) + }; suggestions.push(new_param_suggestion); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 3de5273d8c7..375ad8d3736 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -4,6 +4,7 @@ use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_middle::ty; +use rustc_span::symbol::kw; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// When given a `ConcreteFailure` for a function with parameters containing a named region and @@ -67,7 +68,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let is_impl_item = region_info.is_impl_item; match br { - ty::BrAnon(_) => {} + ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {} _ => { /* not an anonymous region */ debug!("try_report_named_anon_conflict: not an anonymous region"); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 4c0bc2e4337..64c63e3d567 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2177,61 +2177,47 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { define_scoped_cx!(self); let mut region_index = self.region_index; + let mut next_name = |this: &Self| loop { + let name = name_by_region_index(region_index); + region_index += 1; + if !this.used_region_names.contains(&name) { + break name; + } + }; + // If we want to print verbosely, then print *all* binders, even if they // aren't named. Eventually, we might just want this as the default, but // this is not *quite* right and changes the ordering of some output // anyways. let (new_value, map) = if self.tcx().sess.verbose() { // anon index + 1 (BrEnv takes 0) -> name - let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default(); + let mut region_map: FxHashMap<_, _> = Default::default(); let bound_vars = value.bound_vars(); for var in bound_vars { + let ty::BoundVariableKind::Region(var) = var else { continue }; match var { - ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => { + ty::BrAnon(_) | ty::BrEnv => { start_or_continue(&mut self, "for<", ", "); + let name = next_name(&self); do_continue(&mut self, name); + region_map.insert(var, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)); } - ty::BoundVariableKind::Region(ty::BrAnon(i)) => { + ty::BrNamed(def_id, kw::UnderscoreLifetime) => { start_or_continue(&mut self, "for<", ", "); - let name = loop { - let name = name_by_region_index(region_index); - region_index += 1; - if !self.used_region_names.contains(&name) { - break name; - } - }; + let name = next_name(&self); do_continue(&mut self, name); - region_map.insert(i + 1, name); + region_map.insert(var, ty::BrNamed(def_id, name)); } - ty::BoundVariableKind::Region(ty::BrEnv) => { + ty::BrNamed(_, name) => { start_or_continue(&mut self, "for<", ", "); - let name = loop { - let name = name_by_region_index(region_index); - region_index += 1; - if !self.used_region_names.contains(&name) { - break name; - } - }; do_continue(&mut self, name); - region_map.insert(0, name); } - _ => continue, } } start_or_continue(&mut self, "", "> "); self.tcx.replace_late_bound_regions(value.clone(), |br| { - let kind = match br.kind { - ty::BrNamed(_, _) => br.kind, - ty::BrAnon(i) => { - let name = region_map[&(i + 1)]; - ty::BrNamed(CRATE_DEF_ID.to_def_id(), name) - } - ty::BrEnv => { - let name = region_map[&0]; - ty::BrNamed(CRATE_DEF_ID.to_def_id(), name) - } - }; + let kind = region_map[&br.kind]; self.tcx.mk_region(ty::ReLateBound( ty::INNERMOST, ty::BoundRegion { var: br.var, kind }, @@ -2242,21 +2228,20 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { let mut name = |br: ty::BoundRegion| { start_or_continue(&mut self, "for<", ", "); let kind = match br.kind { - ty::BrNamed(_, name) => { - do_continue(&mut self, name); - br.kind - } ty::BrAnon(_) | ty::BrEnv => { - let name = loop { - let name = name_by_region_index(region_index); - region_index += 1; - if !self.used_region_names.contains(&name) { - break name; - } - }; + let name = next_name(&self); do_continue(&mut self, name); ty::BrNamed(CRATE_DEF_ID.to_def_id(), name) } + ty::BrNamed(def_id, kw::UnderscoreLifetime) => { + let name = next_name(&self); + do_continue(&mut self, name); + ty::BrNamed(def_id, name) + } + ty::BrNamed(_, name) => { + do_continue(&mut self, name); + br.kind + } }; tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind })) }; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ee8e4162001..a4cdfdf55f9 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -285,6 +285,54 @@ pub enum BadTypePlusSub { }, } +#[derive(SessionDiagnostic)] +#[error(slug = "parser-maybe-recover-from-bad-qpath-stage-2")] +struct BadQPathStage2 { + #[primary_span] + #[suggestion(applicability = "maybe-incorrect")] + span: Span, + ty: String, +} + +#[derive(SessionDiagnostic)] +#[error(slug = "parser-incorrect-semicolon")] +struct IncorrectSemicolon<'a> { + #[primary_span] + #[suggestion_short(applicability = "machine-applicable")] + span: Span, + #[help] + opt_help: Option<()>, + name: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error(slug = "parser-incorrect-use-of-await")] +struct IncorrectUseOfAwait { + #[primary_span] + #[suggestion(message = "parentheses-suggestion", applicability = "machine-applicable")] + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(slug = "parser-incorrect-use-of-await")] +struct IncorrectAwait { + #[primary_span] + span: Span, + #[suggestion(message = "postfix-suggestion", code = "{expr}.await{question_mark}")] + sugg_span: (Span, Applicability), + expr: String, + question_mark: &'static str, +} + +#[derive(SessionDiagnostic)] +#[error(slug = "parser-in-in-typo")] +struct InInTypo { + #[primary_span] + span: Span, + #[suggestion(applicability = "machine-applicable")] + sugg_span: Span, +} + // SnapshotParser is used to create a snapshot of the parser // without causing duplicate errors being emitted when the `Parser` // is dropped. @@ -1451,15 +1499,10 @@ impl<'a> Parser<'a> { path.span = ty_span.to(self.prev_token.span); let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty)); - self.struct_span_err(path.span, "missing angle brackets in associated item path") - .span_suggestion( - // This is a best-effort recovery. - path.span, - "try", - format!("<{}>::{}", ty_str, pprust::path_to_string(&path)), - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(BadQPathStage2 { + span: path.span, + ty: format!("<{}>::{}", ty_str, pprust::path_to_string(&path)), + }); let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`. Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path))) @@ -1468,13 +1511,10 @@ impl<'a> Parser<'a> { pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool { if self.token.kind == TokenKind::Semi { self.bump(); - let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`"); - err.span_suggestion_short( - self.prev_token.span, - "remove this semicolon", - String::new(), - Applicability::MachineApplicable, - ); + + let mut err = + IncorrectSemicolon { span: self.prev_token.span, opt_help: None, name: "" }; + if !items.is_empty() { let previous_item = &items[items.len() - 1]; let previous_item_kind_name = match previous_item.kind { @@ -1487,10 +1527,11 @@ impl<'a> Parser<'a> { _ => None, }; if let Some(name) = previous_item_kind_name { - err.help(&format!("{name} declarations are not followed by a semicolon")); + err.opt_help = Some(()); + err.name = name; } } - err.emit(); + self.sess.emit_err(err); true } else { false @@ -1604,18 +1645,20 @@ impl<'a> Parser<'a> { } fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span { - let expr_str = - self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(&expr)); - let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" }); - let sp = lo.to(hi); - let app = match expr.kind { + let span = lo.to(hi); + let applicability = match expr.kind { ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?` _ => Applicability::MachineApplicable, }; - self.struct_span_err(sp, "incorrect use of `await`") - .span_suggestion(sp, "`await` is a postfix operation", suggestion, app) - .emit(); - sp + + self.sess.emit_err(IncorrectAwait { + span, + sugg_span: (span, applicability), + expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(&expr)), + question_mark: if is_question { "?" } else { "" }, + }); + + span } /// If encountering `future.await()`, consumes and emits an error. @@ -1626,16 +1669,10 @@ impl<'a> Parser<'a> { // future.await() let lo = self.token.span; self.bump(); // ( - let sp = lo.to(self.token.span); + let span = lo.to(self.token.span); self.bump(); // ) - self.struct_span_err(sp, "incorrect use of `await`") - .span_suggestion( - sp, - "`await` is not a method call, remove the parentheses", - String::new(), - Applicability::MachineApplicable, - ) - .emit(); + + self.sess.emit_err(IncorrectUseOfAwait { span }); } } @@ -1907,14 +1944,10 @@ impl<'a> Parser<'a> { pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) { if self.eat_keyword(kw::In) { // a common typo: `for _ in in bar {}` - self.struct_span_err(self.prev_token.span, "expected iterable, found keyword `in`") - .span_suggestion_short( - in_span.until(self.prev_token.span), - "remove the duplicated `in`", - String::new(), - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(InInTypo { + span: self.prev_token.span, + sugg_span: in_span.until(self.prev_token.span), + }); } } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 7499e5efdee..de5367ca27c 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -8,10 +8,11 @@ use super::*; use rustc_attr as attr; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir::{def::Res, ItemKind, Node, PathSegment}; +use rustc_hir::{ItemKind, Node, PathSegment}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; @@ -29,7 +30,6 @@ use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_ty_utils::representability::{self, Representability}; -use rustc_hir::def::DefKind; use std::iter; use std::ops::ControlFlow; @@ -93,7 +93,6 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.return_type_pre_known = return_type_pre_known; let tcx = fcx.tcx; - let sess = tcx.sess; let hir = tcx.hir(); let declared_ret_ty = fn_sig.output(); @@ -259,85 +258,123 @@ pub(super) fn check_fn<'a, 'tcx>( if let Some(panic_impl_did) = tcx.lang_items().panic_impl() && panic_impl_did == hir.local_def_id(fn_id).to_def_id() { - if let Some(panic_info_did) = tcx.lang_items().panic_info() { - if *declared_ret_ty.kind() != ty::Never { - sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - let span = hir.span(fn_id); - if inputs.len() == 1 { - let arg_is_panic_info = match *inputs[0].kind() { - ty::Ref(region, ty, mutbl) => match *ty.kind() { - ty::Adt(ref adt, _) => { - adt.did() == panic_info_did - && mutbl == hir::Mutability::Not - && !region.is_static() - } - _ => false, - }, - _ => false, - }; - - if !arg_is_panic_info { - sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); - } - - if let Node::Item(item) = hir.get(fn_id) - && let ItemKind::Fn(_, ref generics, _) = item.kind - && !generics.params.is_empty() - { - sess.span_err(span, "should have no type parameters"); - } - } else { - let span = sess.source_map().guess_head_span(span); - sess.span_err(span, "function should have one argument"); - } - } else { - sess.err("language item required, but not found: `panic_info`"); - } + check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty); } // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` if let Some(alloc_error_handler_did) = tcx.lang_items().oom() && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() { - if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() { - if *declared_ret_ty.kind() != ty::Never { - sess.span_err(decl.output.span(), "return type should be `!`"); - } + check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty); + } - let inputs = fn_sig.inputs(); - let span = hir.span(fn_id); - if inputs.len() == 1 { - let arg_is_alloc_layout = match inputs[0].kind() { - ty::Adt(ref adt, _) => adt.did() == alloc_layout_did, - _ => false, - }; + (fcx, gen_ty) +} - if !arg_is_alloc_layout { - sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); - } +fn check_panic_info_fn( + tcx: TyCtxt<'_>, + fn_id: LocalDefId, + fn_sig: ty::FnSig<'_>, + decl: &hir::FnDecl<'_>, + declared_ret_ty: Ty<'_>, +) { + let Some(panic_info_did) = tcx.lang_items().panic_info() else { + tcx.sess.err("language item required, but not found: `panic_info`"); + return; + }; - if let Node::Item(item) = hir.get(fn_id) - && let ItemKind::Fn(_, ref generics, _) = item.kind - && !generics.params.is_empty() - { - sess.span_err( - span, - "`#[alloc_error_handler]` function should have no type parameters", - ); - } - } else { - let span = sess.source_map().guess_head_span(span); - sess.span_err(span, "function should have one argument"); + if *declared_ret_ty.kind() != ty::Never { + tcx.sess.span_err(decl.output.span(), "return type should be `!`"); + } + + let span = tcx.def_span(fn_id); + let inputs = fn_sig.inputs(); + if inputs.len() != 1 { + let span = tcx.sess.source_map().guess_head_span(span); + tcx.sess.span_err(span, "function should have one argument"); + return; + } + + let arg_is_panic_info = match *inputs[0].kind() { + ty::Ref(region, ty, mutbl) => match *ty.kind() { + ty::Adt(ref adt, _) => { + adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static() } - } else { - sess.err("language item required, but not found: `alloc_layout`"); - } + _ => false, + }, + _ => false, + }; + + if !arg_is_panic_info { + tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); } - (fcx, gen_ty) + let DefKind::Fn = tcx.def_kind(fn_id) else { + let span = tcx.def_span(fn_id); + tcx.sess.span_err(span, "should be a function"); + return; + }; + + let generic_counts = tcx.generics_of(fn_id).own_counts(); + if generic_counts.types != 0 { + let span = tcx.def_span(fn_id); + tcx.sess.span_err(span, "should have no type parameters"); + } + if generic_counts.consts != 0 { + let span = tcx.def_span(fn_id); + tcx.sess.span_err(span, "should have no const parameters"); + } +} + +fn check_alloc_error_fn( + tcx: TyCtxt<'_>, + fn_id: LocalDefId, + fn_sig: ty::FnSig<'_>, + decl: &hir::FnDecl<'_>, + declared_ret_ty: Ty<'_>, +) { + let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else { + tcx.sess.err("language item required, but not found: `alloc_layout`"); + return; + }; + + if *declared_ret_ty.kind() != ty::Never { + tcx.sess.span_err(decl.output.span(), "return type should be `!`"); + } + + let inputs = fn_sig.inputs(); + if inputs.len() != 1 { + let span = tcx.def_span(fn_id); + let span = tcx.sess.source_map().guess_head_span(span); + tcx.sess.span_err(span, "function should have one argument"); + return; + } + + let arg_is_alloc_layout = match inputs[0].kind() { + ty::Adt(ref adt, _) => adt.did() == alloc_layout_did, + _ => false, + }; + + if !arg_is_alloc_layout { + tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); + } + + let DefKind::Fn = tcx.def_kind(fn_id) else { + let span = tcx.def_span(fn_id); + tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function"); + return; + }; + + let generic_counts = tcx.generics_of(fn_id).own_counts(); + if generic_counts.types != 0 { + let span = tcx.def_span(fn_id); + tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters"); + } + if generic_counts.consts != 0 { + let span = tcx.def_span(fn_id); + tcx.sess + .span_err(span, "`#[alloc_error_handler]` function should have no const parameters"); + } } fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) { diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 277bc1cf0f0..4d17307ddb9 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -660,8 +660,24 @@ fn compare_number_of_generics<'tcx>( _ => None, }) .collect(); - let spans = impl_item.generics.spans(); - let span = spans.primary_span(); + let spans = if impl_item.generics.params.is_empty() { + vec![impl_item.generics.span] + } else { + impl_item + .generics + .params + .iter() + .filter(|p| { + matches!( + p.kind, + hir::GenericParamKind::Type { .. } + | hir::GenericParamKind::Const { .. } + ) + }) + .map(|p| p.span) + .collect::<Vec<Span>>() + }; + let span = spans.first().copied(); let mut err = tcx.sess.struct_span_err_with_code( spans, |
