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

Fix subst issues with return-position impl Trait in trait #102334

Merged
merged 4 commits into from
Oct 16, 2022

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Sep 26, 2022

  1. Fix an issue where we were rebase impl substs onto trait method substs, instead of trait substs
  2. Fix an issue where early-bound regions aren't being mapped correctly for RPITIT hidden types

Fixes #102301
Fixes #102310
Fixes #102334
Fixes #102918

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Sep 26, 2022
@rust-highfive
Copy link
Collaborator

r? @estebank

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 26, 2022
@bors
Copy link
Contributor

bors commented Sep 27, 2022

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

@compiler-errors compiler-errors added the F-return_position_impl_trait_in_trait `#![feature(return_position_impl_trait_in_trait)]` label Sep 30, 2022
name: e.name,
index: (e.index as usize - trait_to_impl_substs.len()
+ tcx.generics_of(impl_m.container_id(tcx)).params.len())
as u32,
Copy link
Contributor

Choose a reason for hiding this comment

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

Generics::param_def_id_to_index should give the correct answer. Is e.def_id the wrong definition to refer to?

Copy link
Member Author

@compiler-errors compiler-errors Oct 1, 2022

Choose a reason for hiding this comment

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

Yes, technically e.def_id points to the RPIT lifetime on the trait. There is no corresponding RPIT generics for the impl.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see 3 cases:

  • there exists some early-bound lifetime on the impl that we could map to;
  • the corresponding lifetime in the impl is late-bound, and we should build the correct binder;
  • there is no lifetime because there is no unification, and we should probably return re_static.

Copy link
Member Author

@compiler-errors compiler-errors Oct 11, 2022

Choose a reason for hiding this comment

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

@cjgillot:

I'm not really sure what you mean by this. The inferred opaque type shouldn't have any late-bound regions -- associated types don't have late-bound regions, do they?

I guess an example might help explain my thinking in this change -- let's look at a manual desugaring of an RPITIT:

RPITIT:

trait Foo {
  fn foo<'a>(&'a self) -> impl Display + 'a;
}

struct Wrapper<T>(T);

impl<T: Display> Foo for Wrapper<T> {
  fn foo<'a>(&'a self) -> impl Display + 'a {
    &self.0
  }
}

GAT:

trait Foo {
  type FooRpit<'a>: Display + 'a;

  fn foo<'a>(&'a self) -> &'a T;
}

struct Wrapper<T>(T);

impl Foo for Wrapper<i32> {
  type FooRpit<'a> = &'a i32;

  fn foo<'a>(&'a self) -> Self::FooRpit<'a> {
    &self.0
  }
}

In the GAT example, when we're projecting <Wrapper<i32> as Foo>::FooRpit<'_#0r> (substs = [Wrapper<i32>, '_#0r]), we first infer that the {impl#0} provides the asociated type. That impl itself is inferred to have the substs [], and the {impl#0}::FooRpit unsubstituted type value is &'a/0 i32, where 'a/0 is an early-bound region with index 0 in the substs list. We rebase the substs above onto the impl substs to get ['_#0r], substitute to get &'_#0r i32.

However, in the RPITIT example {impl#0}::FooRpit isn't actually a real item, so during the RPIT inference step, we need to "renumber" the opaque type's early-bound lifetimes (taken from the opaque item in the trait) counting up from the impl's own substs as if a corresponding associated item existed, so we can later substitute things correctly during projection. Since the impl has no substs of its own, the early bound regions of FooRpit start counting from zero, not one.

If we don't do this, then the type_of value of the corresponding RPITIT to {impl#0}::FooRpit would be &'a/1 i32 (since 'a/1 comes from the trait, which has a Self subst in the 0th position), which would be out of bounds considering the rebased impl substs I mentioned above.

the corresponding lifetime in the impl is late-bound, and we should build the correct binder

If we wrapped things in binders instead, then I think we'd be treating the function foo in the impl like for<'a> fn(&'a self) -> for<'b> &'b i32 even though the lifetime of &self and &i32 in that above example should be related through substs.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thank you for the detailed explanation. This is definitely subtle.

Do you mind adding a comment in the code to explain that we are working around the non-existence of {impl#0}::FooRpit?

You shift the subst index by the length difference between the trait generic length and the impl generic length. I would have expected the difference between the trait method generic length and the impl method generic length, since the opaques are based on them in generics_of. We should perhaps explain that this is ok since we check the number of generics before reaching this point.

r=me with that comment

@bors
Copy link
Contributor

bors commented Oct 7, 2022

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

@estebank
Copy link
Contributor

estebank commented Oct 7, 2022

r=me after rebasing

index: (e.index as usize - trait_to_impl_substs.len()
+ tcx.generics_of(impl_m.container_id(tcx)).params.len())
as u32,
}))
});
debug!(%ty);
Copy link
Contributor

Choose a reason for hiding this comment

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

While trying to understand what happens, I remarked that this scheme leaks inference variables.
For instance, in src/test/ui/async-await/in-trait/issue-102310.rs, you get ty=Opaque(DefId(0:14 ~ issue_102310[ed7a]::{impl#0}::transaction::{opaque#0}), [F, R, '_#0r]).

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed by equating the full signature instead of just equating the return types, which allows us to infer things fully.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also #102903 asserts against this more strongly, since fully_resolve really shouldn't be returning inference variables..

@compiler-errors
Copy link
Member Author

@estebank this could use a quick review of the final commit, since I added that to fix the issue that @cjgillot mentioned above about leaking inference variables.

@compiler-errors
Copy link
Member Author

@bors r=cjgillot

@bors
Copy link
Contributor

bors commented Oct 15, 2022

📌 Commit 4259f33 has been approved by cjgillot

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 15, 2022
@bors
Copy link
Contributor

bors commented Oct 16, 2022

⌛ Testing commit 4259f33 with merge 8be3ce9...

@bors
Copy link
Contributor

bors commented Oct 16, 2022

☀️ Test successful - checks-actions
Approved by: cjgillot
Pushing 8be3ce9 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Oct 16, 2022
@bors bors closed this in 8be3ce9 Oct 16, 2022
@bors bors merged commit 8be3ce9 into rust-lang:master Oct 16, 2022
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (8be3ce9): comparison URL.

Overall result: ✅ improvements - no action needed

@rustbot label: -perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean1 range count2
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-0.5% [-0.5%, -0.5%] 1
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean1 range count2
Regressions ❌
(primary)
2.9% [2.9%, 2.9%] 1
Regressions ❌
(secondary)
3.0% [2.0%, 3.8%] 20
Improvements ✅
(primary)
-3.8% [-3.8%, -3.8%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -0.5% [-3.8%, 2.9%] 2

Cycles

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean1 range count2
Regressions ❌
(primary)
2.2% [1.6%, 2.6%] 3
Regressions ❌
(secondary)
3.2% [3.2%, 3.2%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-3.3% [-3.3%, -3.3%] 1
All ❌✅ (primary) 2.2% [1.6%, 2.6%] 3

Footnotes

  1. the arithmetic mean of the percent change 2 3

  2. number of relevant changes 2 3

@compiler-errors compiler-errors deleted the rpitit-substs-issue branch November 2, 2022 02:56
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Nov 22, 2022
…pty-hack, r=TaKO8Ki

Remove a lifetime resolution hack from `compare_predicate_entailment`

This is not needed anymore, probably due to rust-lang#102334 equating the function signatures fully in `collect_trait_impl_trait_tys`. Also, the assertion in in rust-lang#102903 makes sure that this is actually fixed, so I'm pretty confident this isn't needed.
@cuviper cuviper added this to the 1.66.0 milestone Nov 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-return_position_impl_trait_in_trait `#![feature(return_position_impl_trait_in_trait)]` merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
8 participants