Skip to content

Conversation

@fmease
Copy link
Member

@fmease fmease commented Aug 25, 2024

Object Lifetime Defaults (Primer, Refresher & Definitions)

You can read this section in The Reference but has several issues1. Here's a small explainer by me that only mentions the parts relevant to this PR:

Basically, given dyn Trait (≠ dyn Trait + '_) we want to deduce its object lifetime bound from context (without relying on rustc_infer's region inference as we might not be in a body2). The "context" means the closest — what I call — eligible generic container C<X0, …, Xn> that wraps this trait object type. (Eligible generic) container is almost synonymous with type constructor but it also includes type aliases, traits & enum variants.

So if we have C<…, dyn Trait, …> (e.g., &'r dyn Trait or Struct<'r, dyn Trait>) or C<…, N<…, dyn Trait, …>, …> (e.g., &'r (dyn Trait,) or Struct<'r, (dyn Trait,)>) where N denotes a generic type that is not an eligible generic container, we use the explicit3 outlives-bounds on the corresp. type param of C to determine the object lifetime bound (the details4 aren't relevant here) (e.g., given struct Struct<'a, T: 'a + ?Sized>(…);, we elaborate Struct<'r, dyn Trait> to Struct<'r, dyn Trait + 'r>).

Lastly, I call object lifetime bounds used as the default for constituent trait object types of an eligible generic container C the ambient object lifetime defaults for / induced by C (these ambient defaults may be shadowed by inner containers).


Changes Made by This PR

  1. Make resolved associated type paths (projections) eligible generic containers.
    • <Y0 as TraitRef<X0, …, Xn>>::AssocTy<Y1, …, Ym> now induces ambient object lifetime defaults for constituents Y0 to Ym (TraitRef is considered a separate container, see also list item (2)).
    • Notably, for the self type Y0 of (resolved) projections we now look at the bounds on the Self type param of the relevant trait (e.g., given trait Outer<'a>: 'a { type Proj; } or trait Outer<'a> where Self: 'a { type Proj; } we elaborate <dyn Inner as Outer<'r>>::Proj to <dyn Inner + 'r as Outer<'r>>::Proj).
  2. In type-relative paths Y0::AssocTy<Y1, …, Ym> consider the ambient object lifetime default indeterminate
    • Meaning if we're in an item context ("item signature", "non-body") & the trait object type isn't bounded by any outlives-bounds (which would take precedence over the default) we will reject the type
    • Reason: Limitations of the current implementation which can't be easily overcome
      • RBV (which resolves object lifetime defaults by recursing into the local crate "in one sitting") would require the resolution of type-relative paths in order to look up the generics but these paths are only resolved in HIR ty lowering (that can selectively lower local items) which depends on the results of RBV (cyclic dependency!)
      • While one might be able to resolve type-relative paths in RBV in an ad-hoc fashion, it would require a lot of duplication with HIR ty lowering and its impl would be very brittle (RTN does something like that in RBV but we require a more sophisticated resolver)
      • I did attempt that but it got too gnarly
      • See also this GH thread
      • See also #t-types/meetings > 2025-09-16 weekly @ 💬
    • IINM this should still be maximally forward compatible
  3. Fixes object lifetime defaults inside trait refs TraitRef<X0, …, Xn> (this fell out from the previous changes). They used to be completely broken due to a gnarly off-by-one error for not accounting for the implicit Self type param of traits which lead to cases like
    • Outer<'r, dyn Inner> (with trait Outer<'a, T: 'a + ?Sized> {}) getting rejected as indeterminate (it tries to access a lifetime at index 1 instead 0) (playground)
    • Outer<'r, 's, dyn Inner> (with trait Outer<'a, 'b, T: 'a + ?Sized> {}) elaborating dyn Inner to dyn Inner + 's instead of dyn Inner + 'r(!) (playground)

These changes are theoretically breaking because in certain cases they lead to different object lifetime bounds getting deduced compared to master which is obviously user observable. However, the latest crater run found 0 non-spurious regressions.

Motivation: Both object lifetime default RFCs never explicitly specify what constitutes an — what I call — eligible generic container but it only makes sense to include any type constructor or (generic) type alias that can bear outlives-bounds … like associated types. So it's only consistent to make this change.

Fixes #115379.

TODO(#129543 (comment)): Add a clear example regression to the PR description.
TODO: Add lcnr's tests.
TODO: #129543 (comment) needs to be decided.

Footnotes

  1. https://github.com/rust-lang/reference/issues/1407

  2. If we are in a body, we do however use to normal region inference as a fallback.

  3. Indeed, we don't consider implied bounds (inferred outlives-bounds).

  4. Like how we deal with 'ambiguities' or how bounds 'on' inner TOTs take precedence.

@fmease fmease added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. T-types Relevant to the types team, which will review and decide on the PR/issue. labels Aug 25, 2024
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 25, 2024
@fmease
Copy link
Member Author

fmease commented Aug 25, 2024

@bors try

bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 25, 2024
[crater] Properly deduce the object lifetime default in GAT paths

Fixes rust-lang#115379.

r? ghost
@bors
Copy link
Collaborator

bors commented Aug 25, 2024

⌛ Trying commit 8bfcd86 with merge 24cd45d...

@fmease fmease removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 25, 2024
@bors
Copy link
Collaborator

bors commented Aug 25, 2024

☀️ Try build successful - checks-actions
Build commit: 24cd45d (24cd45d7714ba43afd4b8e62fb677b069b21c4a5)

@fmease
Copy link
Member Author

fmease commented Aug 25, 2024

@craterbot check

@craterbot
Copy link
Collaborator

👌 Experiment pr-129543 created and queued.
🤖 Automatically detected try build 24cd45d
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 25, 2024
@fmease fmease changed the title [crater] Properly deduce the object lifetime default in GAT paths [crater] Properly deduce object lifetime defaults in GAT paths Aug 25, 2024
bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 27, 2024
[CRATER] Crater Rollup

This is a " crater rollup" of:
* rust-lang#126452
* rust-lang#128784
* rust-lang#129392
* rust-lang#129422
* rust-lang#129543

**What is a crater rollup?** It's simply a crater job that is run on all of the containing PRs *together*, and then we can set the crates list for each of these jobs to just the failures after it's done. It should cut out on the bulk of "normal" crates that do nothing and simply just take time to build.

r? `@ghost`
bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 28, 2024
[CRATER] Crater Rollup

This is a " crater rollup" of:
* rust-lang#126452
* rust-lang#128784
* rust-lang#129392
* rust-lang#129422
* rust-lang#129543
* rust-lang#129604

**What is a crater rollup?** It's simply a crater job that is run on all of the containing PRs *together*, and then we can set the crates list for each of these jobs to just the failures after it's done. It should cut out on the bulk of "normal" crates that do nothing and simply just take time to build.

r? `@ghost`
bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 28, 2024
[CRATER] Crater Rollup

This is a " crater rollup" of:
* rust-lang#126452
* rust-lang#128784
* rust-lang#129392
* rust-lang#129422
* rust-lang#129543
* rust-lang#129604

**What is a crater rollup?** It's simply a crater job that is run on all of the containing PRs *together*, and then we can set the crates list for each of these jobs to just the failures after it's done. It should cut out on the bulk of "normal" crates that do nothing and simply just take time to build.

r? `@ghost`
@craterbot
Copy link
Collaborator

📝 Configuration of the pr-129543 experiment changed.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@traviscross
Copy link
Contributor

@craterbot
Copy link
Collaborator

📝 Configuration of the pr-129543 experiment changed.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🚧 Experiment pr-129543 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-129543 is completed!
📊 6 regressed and 0 fixed (98236 total)
📰 Open the full report.

⚠️ If you notice any spurious failure please add them to the blacklist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Sep 1, 2024
@fmease fmease added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 2, 2024
@workingjubilee workingjubilee added the C-crater Category: Issue for tracking crater runs label Feb 14, 2025
@fmease fmease removed the C-crater Category: Issue for tracking crater runs label Apr 17, 2025
@bors

This comment was marked as resolved.

@Urgau Urgau added S-waiting-on-t-types Status: Awaiting decision from T-types and removed S-waiting-on-team labels Oct 6, 2025
@rustbot
Copy link
Collaborator

rustbot commented Nov 30, 2025

Some changes occurred in compiler/rustc_attr_parsing

cc @jdonszelmann

@rustbot
Copy link
Collaborator

rustbot commented Nov 30, 2025

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@rust-log-analyzer

This comment has been minimized.

@fmease
Copy link
Member Author

fmease commented Nov 30, 2025

please add a test for

trait Trait<T> {
    type Assoc<'a>
    where
        T: 'a;
}

I would assume that we don't have a default for (): Trait<dyn Inner>. What about (): Trait<dyn Inner, Assoc<'r> = ()> or <() as Trait<dyn Inner>>::Assoc<'r>

In all three cases, the following holds:

  1. trait Inner presumably isn't bounded by a lifetime
  2. We're in an item ctxt / item signature / non-body
    • Cases 1 & 2: in a where-clause to be precise
    • Case 3: the projection could be inside of a body, we don't know, but then it'd resolve to a fresh region var, so that case isn't interesting
  3. Trait's T doesn't impose any lifetime requirements (we don't traverse into the associated items) aka it's Empty

We therefore default to 'static which is the fallback / used for Empty in non-bodies.

I don't know, do you expect that we default to 'r in the third case? I think I could make that work, just let me know.

@fmease
Copy link
Member Author

fmease commented Nov 30, 2025

I've now dropped the final commit again, the one that attempted to resolve type-relative paths inside RBV. See #t-types/meetings > 2025-09-16 weekly @ 💬 for a rationale.

I'm now fully set on considering ambient object lifetime defaults induced by type-relative paths indeterminate, so this PR has a realistic chance of getting merged within a reasonable time frame.

I've updated the PR description. Still three minor-ish TODOs left (see the PR description).
I might make a patch available somewhere which impls object lifetime defaulting in type-relative paths (which is pretty hacky be warned). The more principled approach would be to somehow intertwine RBV & HIR ty lowering (requires rearchitecture).

@rust-log-analyzer

This comment has been minimized.

Notably, this excludes the self ty.

This automatically fixes object lifetime defaulting for trait refs, too.
These used to be broken because the index calculation for going from
middle generic args back to HIR ones didn't take into account the implicit
self ty param present of traits.
* print `Empty` as it's called in code, otherwise it's unnecessarily confusing
* go through the middle::ty Generics instead of the HIR ones, so we can dump the
  default for the implicit `Self` type parameter of traits, too
* allow the attribute on more targets (it used to be allowed anywhere for the
  longest time but someone must've incorrectly restricted it during the
  migration to the new attribute parsing API)
@rustbot
Copy link
Collaborator

rustbot commented Jan 14, 2026

⚠️ Warning ⚠️

@fmease
Copy link
Member Author

fmease commented Jan 14, 2026

I've pushed a tmp commit to address #115379 (comment) which I'll need to crater. It's good to rerun crater anyway cuz the last one was almost a year ago.

@bors try

@rust-bors

This comment has been minimized.

rust-bors bot pushed a commit that referenced this pull request Jan 14, 2026
Properly deduce object lifetime defaults in projections & trait refs
@rust-log-analyzer
Copy link
Collaborator

The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
[TIMING:end] tool::ToolBuild { build_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu, tool: "tidy", path: "src/tools/tidy", mode: ToolBootstrap, source_type: InTree, extra_features: [], allow_features: "", cargo_args: [], artifact_kind: Binary } -- 11.850
[TIMING:end] tool::Tidy { compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu } -- 0.000
fmt check
Diff in /checkout/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs:1826:
         // in the trait ref `YY<...>` in `Item: YY<...>`.
         for constraint in generic_args.constraints {
             let scope = Scope::ObjectLifetimeDefault {
-                lifetime: if has_lifetime_parameters || constraint.gen_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) {
+                lifetime: if has_lifetime_parameters
+                    || constraint
+                        .gen_args
+                        .args
+                        .iter()
+                        .any(|arg| matches!(arg, GenericArg::Lifetime(_)))
+                {
                     None
                 } else {
                     Some(ResolvedArg::StaticLifetime)
fmt: checked 6650 files

@rust-bors
Copy link
Contributor

rust-bors bot commented Jan 14, 2026

☀️ Try build successful (CI)
Build commit: 5ff9315 (5ff93158e08fa2205cd4b86cddf9eae95952cc96, parent: 86a49fd71fecd25b0fd20247db0ba95eeceaba28)

@fmease
Copy link
Member Author

fmease commented Jan 15, 2026

@craterbot check

@craterbot
Copy link
Collaborator

👌 Experiment pr-129543-2 created and queued.
🤖 Automatically detected try build 5ff9315
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-waiting-on-t-types Status: Awaiting decision from T-types labels Jan 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. perf-regression Performance regression. proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. S-waiting-on-crater Status: Waiting on a crater run to be completed. T-types Relevant to the types team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Object lifetime defaults of GATs are not respected