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

Make inductive cycles always ambiguous #122791

Merged
merged 3 commits into from Apr 3, 2024

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Mar 20, 2024

This makes inductive cycles always result in ambiguity rather than be treated like a stack-dependent error.

This has some interactions with specialization, and so breaks a few UI tests that I don't agree should've ever worked in the first place, and also breaks a handful of crates in a way that I don't believe is a problem.

On the bright side, it puts us in a better spot when it comes to eventually enabling coinduction everywhere.

Results

This was cratered in #116494 (comment), which boils down to two regressions:

  • lu_packets - This code should have never compiled in the first place. More below.
  • ALL other regressions are due to commit_verify@0.11.0-beta.1 (edit: and commit_verify@0.10.x) - This actually seems to be fixed in version 0.11.0-beta.5, which is the most up to date version, but it's still prerelease on crates.io so I don't think cargo ends up picking beta.5 when building dependent crates.

lu_packets

Firstly, this crate uses specialization, so I think it's automatically worth breaking. However, I've minimized the regression to:

// Upstream crate
pub trait Serialize {}
impl Serialize for &() {}
impl<S> Serialize for &[S] where for<'a> &'a S: Serialize {}

// ----------------------------------------------------------------------- //

// Downstream crate
#![feature(specialization)]
#![allow(incomplete_features, unused)]

use upstream::Serialize;

trait Replica {
    fn serialize();
}

impl<T> Replica for T {
    default fn serialize() {}
}

impl<T> Replica for Option<T>
where
    for<'a> &'a T: Serialize,
{
    fn serialize() {}
}

Specifically this fails when computing the specialization graph for the downstream crate.

The code ends up cycling on &[?0]: Serialize when we equate &?0 = &[?1] during impl matching, which ends up needing to prove &[?1]: Serialize, which since cycles are treated like ambiguity, ends up in a fatal overflow. For some reason this requires two crates, squashing them into one crate doesn't work.

Side-note: This code is subtly order dependent. When minimizing, I ended up having the code start failing on nightly very easily after removing and reordering impls. This seems to me all the more reason to remove this behavior altogether.

Side-note: Item Bounds (edit: this was fixed independently in #121123)

Due to the changes in #120584 where we now consider an alias's item bounds and all the item bounds of the alias's nested self type aliases, I've had to add e6b64c6 which is a hack to make sure we're not eagerly normalizing bounds that have nothing to do with the predicate we're trying to solve, and which result in.

This is fixed in a more principled way in #121123.


r? lcnr for an initial review

@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 Mar 20, 2024
@workingjubilee
Copy link
Contributor

ALL other regressions are due to commit_verify@0.11.0-beta.1 - This actually seems to be fixed in version 0.11.0-beta.5, which is the most up to date version, but it's still prerelease on crates.io so I don't think cargo ends up picking beta.5 when building dependent crates.

-beta.5 should be a higher SemVer than -beta.1, and cargo should resolve these appropriately.

@compiler-errors
Copy link
Member Author

Apologies. I misread the crater report. The regressions are a combination of 0.10.x and 0.11.0-beta.1 (I guess they're hard-coding that in their cargo toml? or have their cargo locks commited? or something).

For the record, the regression was removed when a bunch of impls were reworked in: LNP-BP/client_side_validation#152.

@compiler-errors
Copy link
Member Author

compiler-errors commented Mar 21, 2024

Regarding commit_verify, the regression is because there's a fatal overflow when trying to prove: for<'a> Holder<&'a &T, strategies::AsRef>: encode::CommitEncode:

/// Used only internally for blank implementation on reference types.
#[doc(hidden)]
pub enum AsRef {}

impl<'a, T> CommitEncode for Holder<&'a T, AsRef>
where
    T: CommitEncode,
{
    fn commit_encode(&self, e: &mut impl io::Write) {
        self.as_type().commit_encode(e);
    }
}

impl<T> CommitStrategy for &T
where
    T: CommitEncode,
{
    type Strategy = AsRef;
}

impl<T> CommitEncode for T
where
    T: CommitStrategy,
    for<'a> Holder<&'a T, T::Strategy>: CommitEncode,
{
    fn commit_encode(&self, e: &mut impl io::Write) 
        Holder::new(self).commit_encode(e)
    }
}

... which I guess because we don't treat ambiguity as error, we end up actually evaluating to overflow.

Removing AsRef (which is #[doc(hidden)] in the code anyways, and "[u]sed only internally for blank implementation on reference types") fixes the problem, for the record.

Copy link
Contributor

@lcnr lcnr left a comment

Choose a reason for hiding this comment

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

which is a hack to make sure we're not eagerly normalizing bounds that have nothing to do with the predicate we're trying to solve, and which result in.

"fatal overflow" i guess?

What is a test which is affected here. How does this handle <AssocTy as Id>::Assoc: Bound? writing a test rn

@@ -219,52 +218,9 @@ pub enum EvaluationResult {
/// variables. We are somewhat imprecise there, so we don't actually
/// know the real result.
///
/// This can't be trivially cached for the same reason as `EvaluatedToErrStackDependent`.
/// This can't be trivially cached because the result depends on the
/// stack results.
EvaluatedToAmbigStackDependent,
Copy link
Contributor

Choose a reason for hiding this comment

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

unrelated: isn't this just utterly broken if you have stack dependent ambiguity resulting in difference inference constraints, causing a later goal to error without stack dependence?

anyways, the old solver cannot be salvaged. This is an existing issue 😁

compiler/rustc_trait_selection/src/traits/select/mod.rs Outdated Show resolved Hide resolved
@lcnr
Copy link
Contributor

lcnr commented Mar 21, 2024

This already fails on nightly, so this PR seems good to me. I am a bit confused why though, we somehow keep the <Self::Assoc as Id>::This: Copy as a trait where-bound instead of an alias item bound?

trait Id {
    type This: ?Sized;
}
impl<T: ?Sized> Id for T {
    type This = T;
}

trait Trait
where
    <Self::Assoc as Id>::This: Copy,
{
    type Assoc;
}

fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc) {
    (x, x)
}

edit: it's because that hasn't landed yet '^^ that is from a separate PR #120752

The following also already fails, which makes sense, but seems like a shortcoming of our approach to normalization

#![feature(associated_type_bounds)]
trait Id {
    type This: ?Sized;
}
impl<T: ?Sized> Id for T {
    type This = T;
}

trait Trait {
    type Assoc: Id<This: Copy>;
}

fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc) {
    (x, x)
}

however, why does the following compile?

#![feature(associated_type_bounds)]
trait Id {
    type This: ?Sized;
}

trait Trait {
    type Assoc: Id<This: Copy>;
}

fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc)
where
    T::Assoc: Id<This = T::Assoc>,
{
    (x, x)
}

please add these all as tests 😁

@lcnr lcnr added T-types Relevant to the types team, which will review and decide on the PR/issue. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 21, 2024
@lcnr
Copy link
Contributor

lcnr commented Mar 21, 2024

Ignoring the question about nested item_bounds, this PR changes inductive cycles to always result in ambiguity. This matches the behavior of the new trait solver and is an imo necessary step towards changing more cycles to be coinductive, at which point the cycles change to success. This is already the behavior during coherence since #118649.

For more details, see the PR description by @compiler-errors.

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Mar 21, 2024

Team member @lcnr 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 Mar 21, 2024
@bors
Copy link
Contributor

bors commented Mar 21, 2024

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

@compiler-errors

This comment was marked as outdated.

@compiler-errors
Copy link
Member Author

Actually, yeah, it's due to candidate shadowing, just for associated item bounds shadowing the global impl.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Mar 21, 2024
…und-tests, r=lcnr

Add tests for shortcomings of associated type bounds

Adds the test in rust-lang#122791 (comment)

Turns out that rust-lang#121123 is what breaks `tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs` (passes on nightly), but given that associated type bounds haven't landed anywhere yet, I'm happy with breaking it.

This is unrelated to rust-lang#122791, which just needed that original commit e6b64c6 stacked on top of it so that it wouldn't have tests failing.

r? lcnr
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Mar 22, 2024
…und-tests, r=lcnr

Add tests for shortcomings of associated type bounds

Adds the test in rust-lang#122791 (comment)

Turns out that rust-lang#121123 is what breaks `tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs` (passes on nightly), but given that associated type bounds haven't landed anywhere yet, I'm happy with breaking it.

This is unrelated to rust-lang#122791, which just needed that original commit e6b64c6 stacked on top of it so that it wouldn't have tests failing.

r? lcnr
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Mar 22, 2024
Rollup merge of rust-lang#122826 - compiler-errors:associated-type-bound-tests, r=lcnr

Add tests for shortcomings of associated type bounds

Adds the test in rust-lang#122791 (comment)

Turns out that rust-lang#121123 is what breaks `tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs` (passes on nightly), but given that associated type bounds haven't landed anywhere yet, I'm happy with breaking it.

This is unrelated to rust-lang#122791, which just needed that original commit e6b64c6 stacked on top of it so that it wouldn't have tests failing.

r? lcnr
@rfcbot rfcbot added the final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. label Mar 22, 2024
@rfcbot
Copy link

rfcbot commented Mar 22, 2024

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

@rfcbot rfcbot removed the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Mar 22, 2024
@compiler-errors
Copy link
Member Author

Hehe this turns out to also fix #123303

@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 Apr 1, 2024
@rfcbot
Copy link

rfcbot commented Apr 1, 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 compiler-errors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 2, 2024
@lcnr
Copy link
Contributor

lcnr commented Apr 2, 2024

@bors r+ rollup=never

@bors
Copy link
Contributor

bors commented Apr 2, 2024

📌 Commit 56dbeeb has been approved by lcnr

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 Apr 2, 2024
@bors
Copy link
Contributor

bors commented Apr 2, 2024

⌛ Testing commit 56dbeeb with merge 32f1b4a...

bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 2, 2024
…ays, r=lcnr

Make inductive cycles always ambiguous

 This makes inductive cycles always result in ambiguity rather than be treated like a stack-dependent error.

This has some  interactions with specialization, and so breaks a few UI tests that I don't agree should've ever worked in the first place, and also breaks a handful of crates in a way that I don't believe is a problem.

On the bright side, it puts us in a better spot when it comes to eventually enabling coinduction everywhere.

## Results

This was cratered in rust-lang#116494 (comment), which boils down to two regressions:
* `lu_packets` - This code should have never compiled in the first place. More below.
* **ALL** other regressions are due to `commit_verify@0.11.0-beta.1` (edit: and `commit_verify@0.10.x`) - This actually seems to be fixed in version `0.11.0-beta.5`, which is the *most* up to date version, but it's still prerelease on crates.io so I don't think cargo ends up picking `beta.5` when building dependent crates.

### `lu_packets`

Firstly, this crate uses specialization, so I think it's automatically worth breaking. However, I've minimized [the regression](https://crater-reports.s3.amazonaws.com/pr-116494-3/try%23d614ed876e31a5f3ad1d0fbf848fcdab3a29d1d8/gh/lcdr.lu_packets/log.txt) to:

```rust
// Upstream crate
pub trait Serialize {}
impl Serialize for &() {}
impl<S> Serialize for &[S] where for<'a> &'a S: Serialize {}

// ----------------------------------------------------------------------- //

// Downstream crate
#![feature(specialization)]
#![allow(incomplete_features, unused)]

use upstream::Serialize;

trait Replica {
    fn serialize();
}

impl<T> Replica for T {
    default fn serialize() {}
}

impl<T> Replica for Option<T>
where
    for<'a> &'a T: Serialize,
{
    fn serialize() {}
}
```

Specifically this fails when computing the specialization graph for the `downstream` crate.

The code ends up cycling on `&[?0]: Serialize` when we equate `&?0 = &[?1]` during impl matching, which ends up needing to prove `&[?1]: Serialize`, which since cycles are treated like ambiguity, ends up in a **fatal overflow**. For some reason this requires two crates, squashing them into one crate doesn't work.

Side-note: This code is subtly order dependent. When minimizing, I ended up having the code start failing on `nightly` very easily after removing and reordering impls. This seems to me all the more reason to remove this behavior altogether.

## Side-note: Item Bounds (edit: this was fixed independently in rust-lang#121123)

Due to the changes in rust-lang#120584 where we now consider an alias's item bounds *and* all the item bounds of the alias's nested self type aliases, I've had to add e6b64c6 which is a hack to make sure we're not eagerly normalizing bounds that have nothing to do with the predicate we're trying to solve, and which result in.

This is fixed in a more principled way in rust-lang#121123.

---

r? lcnr for an initial review
@rust-log-analyzer
Copy link
Collaborator

The job aarch64-gnu failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
[RUSTC-TIMING] rustc_monomorphize test:false 25.753
   Compiling rustc_trait_selection v0.0.0 (/checkout/compiler/rustc_trait_selection)
[RUSTC-TIMING] rustc_pattern_analysis test:false 26.309
[RUSTC-TIMING] rustc_smir test:false 29.654
##[error]The runner has received a shutdown signal. This can happen when the runner service is stopped, or a manually started runner is canceled.

@bors
Copy link
Contributor

bors commented Apr 3, 2024

💔 Test failed - checks-actions

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Apr 3, 2024
@compiler-errors
Copy link
Member Author

@bors retry

@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 Apr 3, 2024
@bors
Copy link
Contributor

bors commented Apr 3, 2024

⌛ Testing commit 56dbeeb with merge 40f743d...

@bors
Copy link
Contributor

bors commented Apr 3, 2024

☀️ Test successful - checks-actions
Approved by: lcnr
Pushing 40f743d to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Apr 3, 2024
@bors bors merged commit 40f743d into rust-lang:master Apr 3, 2024
12 checks passed
@rustbot rustbot added this to the 1.79.0 milestone Apr 3, 2024
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (40f743d): comparison URL.

Overall result: no relevant changes - no action needed

@rustbot label: -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

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.

mean range count
Regressions ❌
(primary)
2.2% [0.8%, 4.2%] 5
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.2% [0.8%, 4.2%] 5

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.

mean range count
Regressions ❌
(primary)
1.1% [1.1%, 1.1%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-1.0% [-1.0%, -1.0%] 1
All ❌✅ (primary) 1.1% [1.1%, 1.1%] 1

Binary size

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.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.2% [-0.2%, -0.2%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -0.2% [-0.2%, -0.2%] 1

Bootstrap: 668.585s -> 668.957s (0.06%)
Artifact size: 315.61 MiB -> 315.62 MiB (0.00%)

@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Apr 4, 2024
@compiler-errors compiler-errors deleted the make-coinductive-always branch April 23, 2024 15:23
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. 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-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.

Order-dependence of dyn Trait: Supertrait goals causes incompleteness (old solver)
10 participants