Skip to content

We generally emit an additional error if a trait object lifetime bound defaults to an unresolved lifetime in item signatures #152014

@fmease

Description

@fmease

If we fail to deduce a trait object lifetime default in an item signature1 we generally emit an error for that. More specifically, we generally do that if TyCtxt::named_bound_var returns None. For context, named_bound_var actually returns None iff RBV didn't register a mapping from a given hir::Lifetime to a ResolvedArg. Now, since RBV doesn't actually map unresolved lifetimes to ResolvedArg::Error, we ultimately emit two errors in certain cases (1st: unresolved lifetime, 2nd: indeterminate trait object lifetime bound).

I'm not super familiar with the early resolution of lifetimes. Therefore, I don't know if we map unresolved lifetimes to LifetimeRes::Error in rustc_resolve or not (I have a hunch we don't (possibly a remnant of the now removed feature inband lifetimes?)). In any case, ideally we would map unresolved lifetimes to ResolvedArg::Error(_) in RBV which would automatically suppress the "indeterminate trait object lifetime bound" error.

Between AST lowering, name resolution and HIR ty lowering, we have LifetimeRes::Error, hir::LifetimeKind::Error, ResolvedArg::Error(ErrorGuaranteed) & ty::RegionKind::Error(ErrorGuaranteed) but none or only some are actually used for unresolved lifetimes IINM (they're mainly used for other early lifetime issues). Ideally, we'd use these for unresolved lifetimes, too, I guess (for that, ideally LifetimeRes and LifetimeKind::Error would carry an ErrorGuaranteed).

I've used the word "generally" a few times above, that's because in the special case of &'undefined dyn Trait (i.e., trait object type passed to a reference type constructor), we manually suppress the follow-up error. However, if we were to implement the scheme I'm describing above that would become unnecessary allowing us to remove this minor hack in HIR ty lowering:

if let hir::Node::Ty(hir::Ty {
kind: hir::TyKind::Ref(parent_lifetime, _),
..
}) = tcx.parent_hir_node(hir_id)
&& tcx.named_bound_var(parent_lifetime.hir_id).is_none()
{
// Parent lifetime must have failed to resolve. Don't emit a redundant error.
RegionInferReason::ExplicitObjectLifetime
} else {
RegionInferReason::ObjectLifetimeDefault
}

Example Reproducer

fn f(_: std::cell::Ref<'undefined, dyn std::fmt::Debug>) {}
error[E0261]: use of undeclared lifetime name `'undefined`
 --> src/lib.rs:1:24
  |
1 | fn f(_: std::cell::Ref<'undefined, dyn std::fmt::Debug>) {}
  |                        ^^^^^^^^^^ undeclared lifetime
  |
help: consider introducing lifetime `'undefined` here
  |
1 | fn f<'undefined>(_: std::cell::Ref<'undefined, dyn std::fmt::Debug>) {}
  |     ++++++++++++

error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
 --> src/lib.rs:1:36
  |
1 | fn f(_: std::cell::Ref<'undefined, dyn std::fmt::Debug>) {}
  |                                    ^^^^^^^^^^^^^^^^^^^

Footnotes

  1. aka item ctxt aka non-body

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-dyn-traitArea: trait objects, vtable layoutA-lifetimesArea: Lifetimes / regionsD-verboseDiagnostics: Too much output caused by a single piece of incorrect code.S-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions