Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1097,14 +1097,14 @@ fn check_region_bounds_on_impl_item<'tcx>(
.expect("expected impl item to have generics or else we can't compare them")
.span;

let mut generics_span = None;
let mut generics_span = tcx.def_span(trait_m.def_id);
let mut bounds_span = vec![];
let mut where_span = None;

if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id)
&& let Some(trait_generics) = trait_node.generics()
{
generics_span = Some(trait_generics.span);
generics_span = trait_generics.span;
// FIXME: we could potentially look at the impl's bounds to not point at bounds that
// *are* present in the impl.
for p in trait_generics.predicates {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ pub(crate) struct LifetimesOrBoundsMismatchOnTrait {
#[label]
pub span: Span,
#[label(hir_analysis_generics_label)]
pub generics_span: Option<Span>,
pub generics_span: Span,
#[label(hir_analysis_where_label)]
pub where_span: Option<Span>,
#[label(hir_analysis_bounds_label)]
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_resolve/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ resolve_added_macro_use =
resolve_ancestor_only =
visibilities can only be restricted to ancestor modules

resolve_anonymous_lifetime_non_gat_report_error =
in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
resolve_anonymous_lifetime_non_gat_report_error = missing lifetime in associated type
.label = this lifetime must come from the implemented type
.note = in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type

resolve_arguments_macro_use_not_allowed = arguments to `macro_use` are not allowed here

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,8 @@ pub(crate) struct AnonymousLifetimeNonGatReportError {
#[primary_span]
#[label]
pub(crate) lifetime: Span,
#[note]
pub(crate) decl: MultiSpan,
}

#[derive(Subdiagnostic)]
Expand Down
110 changes: 95 additions & 15 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::assert_matches::debug_assert_matches;
use std::borrow::Cow;
use std::collections::hash_map::Entry;
use std::mem::{replace, swap, take};
use std::ops::ControlFlow;

use rustc_ast::visit::{
AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, try_visit, visit_opt, walk_list,
Expand All @@ -19,21 +20,21 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagArgValue, ErrorGuaranteed, IntoDiagArg, StashKey, Suggestions,
pluralize,
Applicability, Diag, DiagArgValue, ErrorGuaranteed, IntoDiagArg, MultiSpan, StashKey,
Suggestions, pluralize,
};
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate};
use rustc_middle::middle::resolve_bound_vars::Set1;
use rustc_middle::ty::{DelegationFnSig, Visibility};
use rustc_middle::ty::{AssocTag, DelegationFnSig, Visibility};
use rustc_middle::{bug, span_bug};
use rustc_session::config::{CrateType, ResolveDocLinks};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::source_map::{Spanned, respan};
use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, SyntaxContext, kw, sym};
use smallvec::{SmallVec, smallvec};
use thin_vec::ThinVec;
use tracing::{debug, instrument, trace};
Expand Down Expand Up @@ -373,11 +374,14 @@ enum LifetimeBinderKind {
FnPtrType,
PolyTrait,
WhereBound,
// Item covers foreign items, ADTs, type aliases, trait associated items and
// trait alias associated items.
Item,
ConstItem,
Function,
Closure,
ImplBlock,
// Covers only `impl` associated types.
ImplAssocType,
}

Expand Down Expand Up @@ -724,6 +728,9 @@ struct DiagMetadata<'ast> {
/// The current impl items (used to suggest).
current_impl_items: Option<&'ast [Box<AssocItem>]>,

/// The current impl items (used to suggest).
current_impl_item: Option<&'ast AssocItem>,

/// When processing impl trait
currently_processing_impl_trait: Option<(TraitRef, Ty)>,

Expand Down Expand Up @@ -1877,9 +1884,31 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
ty: ty.span,
});
} else {
let decl = if !trait_id.is_local()
&& let Some(assoc) = self.diag_metadata.current_impl_item
&& let AssocItemKind::Type(_) = assoc.kind
&& let assocs = self.r.tcx.associated_items(trait_id)
&& let Some(ident) = assoc.kind.ident()
&& let Some(assoc) = assocs.find_by_ident_and_kind(
self.r.tcx,
ident,
AssocTag::Type,
trait_id,
) {
let mut decl: MultiSpan =
self.r.tcx.def_span(assoc.def_id).into();
decl.push_span_label(
self.r.tcx.def_span(trait_id),
String::new(),
);
decl
} else {
DUMMY_SP.into()
};
let mut err = self.r.dcx().create_err(
errors::AnonymousLifetimeNonGatReportError {
lifetime: lifetime.ident.span,
decl,
},
);
self.point_at_impl_lifetimes(&mut err, i, lifetime.ident.span);
Expand Down Expand Up @@ -1921,17 +1950,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}

fn point_at_impl_lifetimes(&mut self, err: &mut Diag<'_>, i: usize, lifetime: Span) {
let Some((rib, span)) = self.lifetime_ribs[..i]
.iter()
.rev()
.skip(1)
.filter_map(|rib| match rib.kind {
let Some((rib, span)) =
self.lifetime_ribs[..i].iter().rev().find_map(|rib| match rib.kind {
LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::ImplBlock, .. } => {
Some((rib, span))
}
_ => None,
})
.next()
else {
return;
};
Expand All @@ -1953,11 +1978,63 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
);
}
} else {
err.span_label(
span,
"you could add a lifetime on the impl block, if the trait or the self type can \
have one",
);
struct AnonRefFinder;
impl<'ast> Visitor<'ast> for AnonRefFinder {
type Result = ControlFlow<Span>;

fn visit_ty(&mut self, ty: &'ast ast::Ty) -> Self::Result {
if let ast::TyKind::Ref(None, mut_ty) = &ty.kind {
return ControlFlow::Break(mut_ty.ty.span.shrink_to_lo());
}
visit::walk_ty(self, ty)
}

fn visit_lifetime(
&mut self,
lt: &'ast ast::Lifetime,
_cx: visit::LifetimeCtxt,
) -> Self::Result {
if lt.ident.name == kw::UnderscoreLifetime {
return ControlFlow::Break(lt.ident.span);
}
visit::walk_lifetime(self, lt)
}
}

if let Some(ty) = &self.diag_metadata.current_self_type
&& let ControlFlow::Break(sp) = AnonRefFinder.visit_ty(ty)
{
err.multipart_suggestion_verbose(
"add a lifetime to the impl block and use it in the self type and associated \
type",
vec![
(span, "<'a>".to_string()),
(sp, "'a ".to_string()),
(lifetime.shrink_to_hi(), "'a ".to_string()),
],
Applicability::MaybeIncorrect,
);
} else if let Some(item) = &self.diag_metadata.current_item
&& let ItemKind::Impl(impl_) = &item.kind
&& let Some(of_trait) = &impl_.of_trait
&& let ControlFlow::Break(sp) = AnonRefFinder.visit_trait_ref(&of_trait.trait_ref)
{
err.multipart_suggestion_verbose(
"add a lifetime to the impl block and use it in the trait and associated type",
vec![
(span, "<'a>".to_string()),
(sp, "'a".to_string()),
(lifetime.shrink_to_hi(), "'a ".to_string()),
],
Applicability::MaybeIncorrect,
);
} else {
err.span_label(
span,
"you could add a lifetime on the impl block, if the trait or the self type \
could have one",
);
}
}
}

Expand Down Expand Up @@ -3301,6 +3378,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
) {
use crate::ResolutionError::*;
self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis)));
let prev = self.diag_metadata.current_impl_item.take();
self.diag_metadata.current_impl_item = Some(&item);
match &item.kind {
AssocItemKind::Const(box ast::ConstItem {
ident,
Expand Down Expand Up @@ -3449,6 +3528,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
panic!("unexpanded macro in resolve!")
}
}
self.diag_metadata.current_impl_item = prev;
}

fn check_trait_item<F>(
Expand Down
15 changes: 14 additions & 1 deletion tests/ui/impl-header-lifetime-elision/assoc-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,27 @@ trait MyTrait {

impl MyTrait for &i32 {
type Output = &i32;
//~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
//~^ ERROR missing lifetime in associated type
}

impl MyTrait for &u32 {
type Output = &'_ i32;
//~^ ERROR `'_` cannot be used here
}

impl<'a> MyTrait for &f64 {
type Output = &f64;
//~^ ERROR missing lifetime in associated type
}

trait OtherTrait<'a> {
type Output;
}
impl OtherTrait<'_> for f64 {
type Output = &f64;
//~^ ERROR missing lifetime in associated type
}

// This is what you have to do:
impl<'a> MyTrait for &'a f32 {
type Output = &'a f32;
Expand Down
40 changes: 36 additions & 4 deletions tests/ui/impl-header-lifetime-elision/assoc-type.stderr
Original file line number Diff line number Diff line change
@@ -1,17 +1,49 @@
error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
error: missing lifetime in associated type
--> $DIR/assoc-type.rs:11:19
|
LL | impl MyTrait for &i32 {
| - you could add a lifetime on the impl block, if the trait or the self type can have one
LL | type Output = &i32;
| ^ this lifetime must come from the implemented type
|
= note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
help: add a lifetime to the impl block and use it in the self type and associated type
|
LL ~ impl<'a> MyTrait for &'a i32 {
LL ~ type Output = &'a i32;
|

error[E0637]: `'_` cannot be used here
--> $DIR/assoc-type.rs:16:20
|
LL | type Output = &'_ i32;
| ^^ `'_` is a reserved lifetime name

error: aborting due to 2 previous errors
error: missing lifetime in associated type
--> $DIR/assoc-type.rs:21:19
|
LL | impl<'a> MyTrait for &f64 {
| ---- there is a named lifetime specified on the impl block you could use
LL | type Output = &f64;
| ^ this lifetime must come from the implemented type
|
= note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
help: consider using the lifetime from the impl block
|
LL | type Output = &'a f64;
| ++

error: missing lifetime in associated type
--> $DIR/assoc-type.rs:29:19
|
LL | type Output = &f64;
| ^ this lifetime must come from the implemented type
|
= note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
help: add a lifetime to the impl block and use it in the trait and associated type
|
LL ~ impl<'a> OtherTrait<'a> for f64 {
LL ~ type Output = &'a f64;
|

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0637`.
3 changes: 2 additions & 1 deletion tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ impl<'a> IntoIterator for &S {
//~| NOTE unconstrained lifetime parameter
//~| HELP consider using the named lifetime here instead of an implicit lifetime
type Item = &T;
//~^ ERROR in the trait associated type
//~^ ERROR missing lifetime in associated type
//~| HELP consider using the lifetime from the impl block
//~| NOTE this lifetime must come from the implemented type
//~| NOTE in the trait the associated type is declared without lifetime parameters
type IntoIter = std::collections::btree_map::Values<'a, i32, T>;

fn into_iter(self) -> Self::IntoIter {
Expand Down
4 changes: 3 additions & 1 deletion tests/ui/lifetimes/missing-lifetime-in-assoc-type-1.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
error: missing lifetime in associated type
--> $DIR/missing-lifetime-in-assoc-type-1.rs:9:17
|
LL | impl<'a> IntoIterator for &S {
Expand All @@ -7,6 +7,8 @@ LL | impl<'a> IntoIterator for &S {
LL | type Item = &T;
| ^ this lifetime must come from the implemented type
|
note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
help: consider using the lifetime from the impl block
|
LL | type Item = &'a T;
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ struct T;

impl IntoIterator for &S {
type Item = &T;
//~^ ERROR in the trait associated type
//~^ ERROR missing lifetime in associated type
type IntoIter = std::collections::btree_map::Values<'a, i32, T>;
//~^ ERROR use of undeclared lifetime name `'a`

Expand Down
12 changes: 9 additions & 3 deletions tests/ui/lifetimes/missing-lifetime-in-assoc-type-2.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
error: missing lifetime in associated type
--> $DIR/missing-lifetime-in-assoc-type-2.rs:5:17
|
LL | impl IntoIterator for &S {
| - you could add a lifetime on the impl block, if the trait or the self type can have one
LL | type Item = &T;
| ^ this lifetime must come from the implemented type
|
note: in the trait the associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
help: add a lifetime to the impl block and use it in the self type and associated type
|
LL ~ impl<'a> IntoIterator for &'a S {
LL ~ type Item = &'a T;
|

error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/missing-lifetime-in-assoc-type-2.rs:7:57
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/lifetimes/missing-lifetime-in-assoc-type-3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ struct T;

impl IntoIterator for &S {
type Item = &T;
//~^ ERROR in the trait associated type
//~^ ERROR missing lifetime in associated type
type IntoIter = std::collections::btree_map::Values<i32, T>;
//~^ ERROR missing lifetime specifier

Expand Down
Loading
Loading