Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check elaborated projections from dyn don't mention unconstrained late bound lifetimes #130367

Merged
merged 2 commits into from
Oct 5, 2024

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Sep 14, 2024

Check that the projections that are not explicitly written but which we deduce from elaborating the principal of a dyn also do not reference unconstrained late-bound lifetimes, just like the ones that the user writes by hand.

That is to say, given:

trait Foo<T>: Bar<Assoc = T> {}

trait Bar {
    type Assoc;
}

The type dyn for<'a> Foo<&'a T> (basically) elaborates to dyn for<'a> Foo<&'a T> + for<'a> Bar<Assoc = &'a T>1. However, the Bar projection predicate is not well-formed, since 'a must show up in the trait's arguments to be referenced in the term of a projection. We must error in this situation2, or else dyn for<'a> Foo<&'a T> is unsound.

We already detect this for user-written projections during HIR->rustc_middle conversion, so this largely replicates that logic using the helper functions that were already conveniently defined.


I'm cratering this first to see the fallout; if it's minimal or zero, then let's land it as-is. If not, the way that this is implemented is very conducive to an FCW.


Fixes #130347

Footnotes

  1. We don't actually elaborate it like that in rustc; we only keep the principal trait ref Foo<&'a T> and the projection part of Bar<Assoc = ...>, but it's useful to be a bit verbose here for the purpose of explaining the issue.

  2. Well, we could also make dyn for<'a> Foo<&'a T> not implement for<'a> Bar<Assoc = &'a T>, but this is inconsistent with the case where the user writes Assoc = ... in the type itself, and it overly complicates the implementation of trait objects' built-in impls.

@compiler-errors
Copy link
Member Author

@bors try

@rustbot
Copy link
Collaborator

rustbot commented Sep 14, 2024

r? @nnethercote

rustbot has assigned @nnethercote.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 14, 2024
@rustbot
Copy link
Collaborator

rustbot commented Sep 14, 2024

HIR ty lowering was modified

cc @fmease

@compiler-errors
Copy link
Member Author

r? types

@rustbot rustbot added the T-types Relevant to the types team, which will review and decide on the PR/issue. label Sep 14, 2024
@rustbot rustbot assigned spastorino and unassigned nnethercote Sep 14, 2024
@compiler-errors
Copy link
Member Author

If this ends up having too much fallout, I guess we could easily make this an FCW. But this seems pretty soundness-critical, given the number of creative ways that people have found in #130347 to make this unsound :D

bors added a commit to rust-lang-ci/rust that referenced this pull request Sep 14, 2024
… r=<try>

Check elaborated projections from dyn don't mention unconstrained late bound lifetimes

Check that the projections that are *not* explicitly written but which we deduce from elaborating the principal of a `dyn` *also* do not reference unconstrained late-bound lifetimes, just like the ones that the user writes by hand.

Fixes rust-lang#130347
@bors
Copy link
Contributor

bors commented Sep 14, 2024

⌛ Trying commit f16d211 with merge f827120...

@compiler-errors compiler-errors removed the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Sep 14, 2024
@bors
Copy link
Contributor

bors commented Sep 14, 2024

☀️ Try build successful - checks-actions
Build commit: f827120 (f827120c9528a1a0e4c9881169eacd52170f9a08)

@compiler-errors
Copy link
Member Author

@craterbot check

@craterbot
Copy link
Collaborator

👌 Experiment pr-130367 created and queued.
🤖 Automatically detected try build f827120
🔍 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-review Status: Awaiting review from the assignee but also interested parties. labels Sep 14, 2024
bors added a commit to rust-lang-ci/rust that referenced this pull request Sep 14, 2024
[CRATER] Crater rollup

This is a crater rollup of:
* rust-lang#124141
* rust-lang#130285
* rust-lang#130367

**What is a crater rollup?** It's simply a (manually set-up) 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 list of failures after it's done. It should cut out on the bulk of "normal" crates that do nothing and simply just waste time to build without being affected by the union of all of these changes.

After this is finished, I will adjust all of the jobs to use only the list of failed crates. That should significantly speed up these jobs from taking like ~6 days to taking ~2. See the last time I did this: rust-lang#129660.

Given that rust-lang#130285 is running in build-and-test mode, let's run all of them in build-and-test mode.
@jackh726
Copy link
Member

I'm curious why the constrained case (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9a297b502ceb3bd1e07ceae618f9a31e) does fail today.

If it was only elaboration that played a role here, I would expect the above example to both compile (but also be unsound). The deeper problem here is likely instead around implied bounds for higher-ranked lifetimes resulting in implied 'static.

@compiler-errors
Copy link
Member Author

compiler-errors commented Sep 14, 2024

@jackh726:

I'm curious why the constrained case (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9a297b502ceb3bd1e07ceae618f9a31e) does fail today.

I think you wrote that example wrong. we want T to be equal to &'?0 str here, but due to the way you added that new X variable to B, it's being set to the dyn type. That's why it's resulting in a type mismatch rather than a lifetime error. I believe a more faithful way of representing this is:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9483d15a409bdeac141dd529b4465da2

Specifically, I've renamed the T variable of the Erase struct to DYN to make it clear that it isn't the same as the T variable in traits A and B.

The deeper problem here is likely instead around implied bounds for higher-ranked lifetimes resulting in implied 'static.

I don't think this has to do with implied bounds. It really does only have to do with elaboration AFAICT.

@compiler-errors
Copy link
Member Author

compiler-errors commented Sep 14, 2024

Perhaps a more illustrative example is taking this example:

trait A<T>: B<T = T> {}

trait B {
    type T;
}

fn foo<'b>(a: &'b str) -> <dyn for<'a> A<&'a str> as B>::T {
    a
}

fn main() {
    let x = foo(String::from("hello").as_str());
    dbg!(x);
}

In order to properly constrain B, we'd need to introduce a new type parameter T to B:

trait A<T>: B<T, T = T> {}

trait B<T> {
    type T;
}

That necessitates modifying foo like:

fn foo<'b>(a: &'b str) -> <dyn for<'a> A<&'a str> as B</* what do we put here? */>>::T {
    a
}

But wait... what do we need to put in /* what do we put here? */.

@craterbot
Copy link
Collaborator

🚧 Experiment pr-130367 is now running

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

@craterbot
Copy link
Collaborator

🎉 Experiment pr-130367 is completed!
📊 6 regressed and 2 fixed (513136 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 23, 2024
@compiler-errors
Copy link
Member Author

I looked at all the regressions and none seem relevant; just "no space" and "signal bus" and linker errors that every crater run features.

See the description for what this PR now validates.

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Sep 23, 2024

Team member @compiler-errors has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Sep 23, 2024
@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Sep 24, 2024
@rfcbot
Copy link

rfcbot commented Sep 24, 2024

🔔 This is now entering its final comment period, as per the review above. 🔔

Copy link
Member

@spastorino spastorino left a comment

Choose a reason for hiding this comment

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

r=me after FCP finishes

@bors
Copy link
Contributor

bors commented Sep 28, 2024

☔ The latest upstream changes (presumably #130946) made this pull request unmergeable. Please resolve the merge conflicts.

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Oct 4, 2024
@rfcbot
Copy link

rfcbot commented Oct 4, 2024

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This will be merged soon.

@compiler-errors
Copy link
Member Author

@bors r=spastorino

@bors
Copy link
Contributor

bors commented Oct 4, 2024

📌 Commit fd7ee48 has been approved by spastorino

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 4, 2024
bors added a commit to rust-lang-ci/rust that referenced this pull request Oct 5, 2024
…kingjubilee

Rollup of 9 pull requests

Successful merges:

 - rust-lang#129517 (Compute array length from type for unconditional panic lint. )
 - rust-lang#130367 (Check elaborated projections from dyn don't mention unconstrained late bound lifetimes)
 - rust-lang#130403 (Stabilize `const_slice_from_raw_parts_mut`)
 - rust-lang#130633 (Add support for reborrowing pinned method receivers)
 - rust-lang#131105 (update `Literal`'s intro)
 - rust-lang#131194 (Fix needless_lifetimes in stable_mir)
 - rust-lang#131260 (rustdoc: cleaner errors on disambiguator/namespace mismatches)
 - rust-lang#131267 (Stabilize `BufRead::skip_until`)
 - rust-lang#131273 (Account for `impl Trait {` when `impl Trait for Type {` was intended)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 9510c73 into rust-lang:master Oct 5, 2024
6 checks passed
@rustbot rustbot added this to the 1.83.0 milestone Oct 5, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Oct 5, 2024
Rollup merge of rust-lang#130367 - compiler-errors:super-unconstrained, r=spastorino

Check elaborated projections from dyn don't mention unconstrained late bound lifetimes

Check that the projections that are *not* explicitly written but which we deduce from elaborating the principal of a `dyn` *also* do not reference unconstrained late-bound lifetimes, just like the ones that the user writes by hand.

That is to say, given:

```
trait Foo<T>: Bar<Assoc = T> {}

trait Bar {
    type Assoc;
}
```

The type `dyn for<'a> Foo<&'a T>` (basically) elaborates to `dyn for<'a> Foo<&'a T> + for<'a> Bar<Assoc = &'a T>`[^1]. However, the `Bar` projection predicate is not well-formed, since `'a` must show up in the trait's arguments to be referenced in the term of a projection. We must error in this situation[^well], or else `dyn for<'a> Foo<&'a T>` is unsound.

We already detect this for user-written projections during HIR->rustc_middle conversion, so this largely replicates that logic using the helper functions that were already conveniently defined.

---

I'm cratering this first to see the fallout; if it's minimal or zero, then let's land it as-is. If not, the way that this is implemented is very conducive to an FCW.

---

Fixes rust-lang#130347

[^1]: We don't actually elaborate it like that in rustc; we only keep the principal trait ref `Foo<&'a T>` and the projection part of `Bar<Assoc = ...>`, but it's useful to be a bit verbose here for the purpose of explaining the issue.
[^well]: Well, we could also make `dyn for<'a> Foo<&'a T>` *not* implement `for<'a> Bar<Assoc = &'a T>`, but this is inconsistent with the case where the user writes `Assoc = ...` in the type itself, and it overly complicates the implementation of trait objects' built-in impls.
@compiler-errors compiler-errors deleted the super-unconstrained branch October 5, 2024 15:47
@Mark-Simulacrum Mark-Simulacrum added the relnotes Marks issues that should be documented in the release notes of the next release. label Nov 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-types Relevant to the types team, which will review and decide on the PR/issue. to-announce Announce this issue on triage meeting
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unconstrained lifetime in associated type using trait object leads to unsound lifetime extension and ICE
9 participants