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
32 changes: 19 additions & 13 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ use rustc_abi::{ExternAbi, Size};
use rustc_ast::Recovered;
use rustc_data_structures::assert_matches;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err,
};
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
Expand Down Expand Up @@ -316,16 +314,24 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
}

fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
if let RegionInferReason::ObjectLifetimeDefault = reason {
let e = struct_span_code_err!(
self.dcx(),
span,
E0228,
"the lifetime bound for this object type cannot be deduced \
from context; please supply an explicit bound"
)
.emit();
ty::Region::new_error(self.tcx(), e)
if let RegionInferReason::ObjectLifetimeDefault(sugg_sp) = reason {
// FIXME: Account for trailing plus `dyn Trait+`, the need of parens in
// `*const dyn Trait` and `Fn() -> *const dyn Trait`.
Comment on lines +318 to +319
Copy link
Member Author

@fmease fmease Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've decided against fixing these ~minor issues in this PR because it's a rabbit hole I didn't want to pursue at the moment:

Most diagnostics in the compiler that suggest adding + /* bound */ to a type don't consider both last cases mentioned in the FIXME above (and I bet none properly account for trailing pluses1). E.g., suggest_new_region_bound (see FIXME).

We do have some helpers in place for cases like this like hir::Generics::bounds_span_for_suggestions but it's not general enough (e.g., I can't use it here) & it doesn't account for everything (like raw pointers).

I hope this paints a clear enough picture. I'd rather fix a bunch of these diagnostic suggestions at once in a separate future PR by providing better HIR helpers for these cases. I'm already tracking this in my internal issue tracker (and I might upstream this issue to r-l/r if I won't get to write a PR soon-ish). From a technical standpoint, it shouldn't be hard at all, you just need to check the parent & the child of the HIR type. I just really want to avoid duplicating code for this.

Footnotes

  1. Since trailing pluses aren't represented in the AST, HIR etc. and you can't just trim & contains('+')-check the relevant part of the source text as obtained via source_map() since it wouldn't account for source code comments; you'd actually need to re-lex the snippet (which is overkill for such a niche issue)

let guar = self
.dcx()
.struct_span_err(
span,
"cannot deduce the lifetime bound for this trait object type from context",
)
.with_code(E0228)
.with_span_suggestion_verbose(
sugg_sp,
"please supply an explicit bound",
" + /* 'a */",
Applicability::HasPlaceholders,
)
.emit();
ty::Region::new_error(self.tcx(), guar)
} else {
// This indicates an illegal lifetime in a non-assoc-trait position
ty::Region::new_error_with_message(self.tcx(), span, "unelided lifetime in signature")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Parent lifetime must have failed to resolve. Don't emit a redundant error.
RegionInferReason::ExplicitObjectLifetime
} else {
RegionInferReason::ObjectLifetimeDefault
RegionInferReason::ObjectLifetimeDefault(span.shrink_to_hi())
}
} else {
RegionInferReason::ExplicitObjectLifetime
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub enum RegionInferReason<'a> {
/// Lifetime on a trait object that is spelled explicitly, e.g. `+ 'a` or `+ '_`.
ExplicitObjectLifetime,
/// A trait object's lifetime when it is elided, e.g. `dyn Any`.
ObjectLifetimeDefault,
ObjectLifetimeDefault(Span),
/// Generic lifetime parameter
Param(&'a ty::GenericParamDef),
RegionPredicate,
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/object-lifetime/object-lifetime-default-ambiguous.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ struct Ref2<'a,'b:'a,T:'a+'b+?Sized> {
}

fn a<'a,'b>(t: Ref2<'a,'b, dyn Test>) {
//~^ ERROR lifetime bound for this object type cannot be deduced from context
//~^ ERROR cannot deduce the lifetime bound for this trait object type
}

fn b(t: Ref2<dyn Test>) {
//~^ ERROR lifetime bound for this object type cannot be deduced from context
//~^ ERROR cannot deduce the lifetime bound for this trait object type
}

fn c(t: Ref2<&dyn Test>) {
Expand All @@ -41,7 +41,7 @@ fn e(t: Ref2<Ref0<dyn Test>>) {
}

fn f(t: &Ref2<dyn Test>) {
//~^ ERROR lifetime bound for this object type cannot be deduced from context
//~^ ERROR cannot deduce the lifetime bound for this trait object type
}

fn main() {
Expand Down
21 changes: 18 additions & 3 deletions tests/ui/object-lifetime/object-lifetime-default-ambiguous.stderr
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
--> $DIR/object-lifetime-default-ambiguous.rs:23:28
|
LL | fn a<'a,'b>(t: Ref2<'a,'b, dyn Test>) {
| ^^^^^^^^
|
help: please supply an explicit bound
|
LL | fn a<'a,'b>(t: Ref2<'a,'b, dyn Test + /* 'a */>) {
| ++++++++++

error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
--> $DIR/object-lifetime-default-ambiguous.rs:27:14
|
LL | fn b(t: Ref2<dyn Test>) {
| ^^^^^^^^
|
help: please supply an explicit bound
|
LL | fn b(t: Ref2<dyn Test + /* 'a */>) {
| ++++++++++

error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
--> $DIR/object-lifetime-default-ambiguous.rs:43:15
|
LL | fn f(t: &Ref2<dyn Test>) {
| ^^^^^^^^
|
help: please supply an explicit bound
|
LL | fn f(t: &Ref2<dyn Test + /* 'a */>) {
| ++++++++++

error: aborting due to 3 previous errors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn is_static<T>(_: T) where T: 'static { }
// Here, we should default to `dyn Bar + 'static`, but the current
// code forces us into a conservative, hacky path.
fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
//~^ ERROR please supply an explicit bound
//~^ ERROR cannot deduce the lifetime bound for this trait object type

fn main() {
let s = format!("foo");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
--> $DIR/object-lifetime-default-dyn-binding-nonstatic1.rs:20:50
|
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
| ^^^^^^^
|
help: please supply an explicit bound
|
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar + /* 'a */> { &() }
| ++++++++++

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn is_static<T>(_: T) where T: 'static { }
// Here, we default to `dyn Bar + 'a`. Or, we *should*, but the
// current code forces us into a conservative, hacky path.
fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
//~^ ERROR please supply an explicit bound
//~^ ERROR cannot deduce the lifetime bound for this trait object type

fn main() {
let s = format!("foo");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
--> $DIR/object-lifetime-default-dyn-binding-nonstatic2.rs:20:50
|
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
| ^^^^^^^
|
help: please supply an explicit bound
|
LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar + /* 'a */> { &() }
| ++++++++++

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn is_static<T>(_: T) where T: 'static { }
// Here, we should default to `dyn Bar + 'static`, but the current
// code forces us into a conservative, hacky path.
fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
//~^ ERROR please supply an explicit bound
//~^ ERROR cannot deduce the lifetime bound for this trait object type

fn main() {
let s = format!("foo");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
error[E0228]: cannot deduce the lifetime bound for this trait object type from context
--> $DIR/object-lifetime-default-dyn-binding-nonstatic3.rs:16:36
|
LL | fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
| ^^^^^^^
|
help: please supply an explicit bound
|
LL | fn bar(x: &str) -> &dyn Foo<Item = dyn Bar + /* 'a */> { &() }
| ++++++++++

error: aborting due to 1 previous error

Expand Down
Loading