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

Specifying one associated type makes Rust forget about the constraint on the other ones #72207

Open
Ten0 opened this issue May 14, 2020 · 2 comments
Labels
A-associated-items Area: Associated items (types, constants & functions) A-closures Area: Closures (`|…| { … }`) A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-trait-system Area: Trait system C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@Ten0
Copy link

Ten0 commented May 14, 2020

I tried this code (which is actually the minimum reproduction I could find, as the bug seems to disappear when I try to reduce it more):

use std::marker::PhantomData;

pub struct XImpl<T, E, F2, F1>
where
	F2: Fn(E),
{
	f1: F1,
	f2: F2,
	_ghost: PhantomData<(T, E)>,
}

pub trait X<T>: Sized {
	type F1;
	type F2: Fn(Self::E);
	type E;

	fn and<NewF1, NewF1Generator>(self, f: NewF1Generator) -> XImpl<T, Self::E, Self::F2, NewF1>
	where
		NewF1Generator: FnOnce(Self::F1) -> NewF1;
}

impl<T, E, F2, F1> X<T> for XImpl<T, E, F2, F1>
where
	F2: Fn(E),
{
	type E = E;
	type F2 = F2;
	type F1 = F1;

	fn and<NewF1, NewF1Generator>(self, f: NewF1Generator) -> XImpl<T, E, F2, NewF1>
	where
		NewF1Generator: FnOnce(F1) -> NewF1,
	{
		XImpl {
			f1: f(self.f1),
			f2: self.f2,
			_ghost: PhantomData,
		}
	}
}

fn f() -> impl X<()> {
	XImpl {
		f1: || (),
		f2: |()| (),
		_ghost: PhantomData,
	}
}

fn f2() -> impl X<()> {
	f().and(|rb| rb)
}

It does compile: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=54e239ced207241c8438dddbc325ef19

If however we specify the value for the associated type E in f and f2, so that code calling f2() can depend on knowing the type E:

fn f() -> impl X<(), E = ()> {
	XImpl {
		f1: || (),
		f2: |()| (),
		_ghost: PhantomData,
	}
}

fn f2() -> impl X<(), E = ()> {
	f().and(|rb| rb)
}

The compiler seems to forget that any X::F2 implements Fn(Self::E), and stops compiling: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1e84aea4402bd45da498aace9682b1ad

   Compiling playground v0.0.1 (/playground)
error[E0277]: expected a `std::ops::Fn<((),)>` closure, found `<impl X<()> as X<()>>::F2`
  --> src/lib.rs:51:6
   |
51 |     f().and(|rb| rb)
   |         ^^^ expected an `Fn<((),)>` closure, found `<impl X<()> as X<()>>::F2`
   |
   = help: the trait `std::ops::Fn<((),)>` is not implemented for `<impl X<()> as X<()>>::F2`

error[E0277]: expected a `std::ops::Fn<((),)>` closure, found `<impl X<()> as X<()>>::F2`
  --> src/lib.rs:51:2
   |
12 | pub trait X<T>: Sized {
   | --------------------- required by `X`
...
51 |     f().and(|rb| rb)
   |     ^^^^^^^^^^^^^^^^ expected an `Fn<((),)>` closure, found `<impl X<()> as X<()>>::F2`
   |
   = help: the trait `std::ops::Fn<((),)>` is not implemented for `<impl X<()> as X<()>>::F2`

error[E0277]: expected a `std::ops::Fn<((),)>` closure, found `<impl X<()> as X<()>>::F2`
  --> src/lib.rs:50:12
   |
50 | fn f2() -> impl X<(), E = ()> {
   |            ^^^^^^^^^^^^^^^^^^ expected an `Fn<((),)>` closure, found `<impl X<()> as X<()>>::F2`
51 |     f().and(|rb| rb)
   |     ---------------- this returned value is of type `XImpl<(), (), <impl X<()> as X<()>>::F2, <impl X<()> as X<()>>::F1>`
   |
   = help: the trait `std::ops::Fn<((),)>` is not implemented for `<impl X<()> as X<()>>::F2`
   = note: required because of the requirements on the impl of `X<()>` for `XImpl<(), (), <impl X<()> as X<()>>::F2, <impl X<()> as X<()>>::F1>`
   = note: the return type of a function must have a statically known size

Note that the bug does not happen if F2: Fn() instead of F2: Fn(E):
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=266f91f2ba2f0730148c4dea8c3732a4

It does not happen either if F2: Fn(T) instead of F2: Fn(E):
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e37b04bfdeec2a1ebddc10a4422931e8

Meta

rustc --version --verbose:

rustc 1.43.1 (8d69840ab 2020-05-04)
binary: rustc
commit-hash: 8d69840ab92ea7f4d323420088dd8c9775f180cd
commit-date: 2020-05-04
host: x86_64-unknown-linux-gnu
release: 1.43.1
LLVM version: 9.0

This also happens on nightly.

@Ten0 Ten0 added the C-bug Category: This is a bug. label May 14, 2020
@Alexendoo Alexendoo added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-associated-items Area: Associated items (types, constants & functions) labels May 20, 2020
@fmease fmease added A-trait-system Area: Trait system T-types Relevant to the types team, which will review and decide on the PR/issue. A-closures Area: Closures (`|…| { … }`) A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. labels Sep 19, 2024
@fmease
Copy link
Member

fmease commented Sep 19, 2024

Triage: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=1e84aea4402bd45da498aace9682b1ad now compiles successfully. I'm not sure if we have a test for this, we might have one already. It's hard to pinpoint which PR fixed this issue, we might want to bisect this.

@oli-obk oli-obk added the E-needs-bisection Call for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustc label Sep 19, 2024
@fmease fmease added A-trait-system Area: Trait system and removed A-trait-system Area: Trait system labels Dec 21, 2024
@moxian
Copy link
Contributor

moxian commented Mar 20, 2025

Bisects to #73905

full cargo-bisect-rustc output
********************************************************************************
Regression in nightly-2020-10-07
********************************************************************************

fetching https://static.rust-lang.org/dist/2020-10-06/channel-rust-nightly-git-commit-hash.txt
nightly manifest 2020-10-06: 40 B / 40 B [=======================================================] 100.00 % 20.19 KB/s converted 2020-10-06 to a1dfd2490a6cb456b92e469fa550dc217e20ad6d
fetching https://static.rust-lang.org/dist/2020-10-07/channel-rust-nightly-git-commit-hash.txt
nightly manifest 2020-10-07: 40 B / 40 B [======================================================] 100.00 % 205.05 KB/s converted 2020-10-07 to 98edd1fbf8a68977a2a7c1312eb1ebff80515a92
looking for regression commit between 2020-10-06 and 2020-10-07
fetching (via remote github) commits from max(a1dfd2490a6cb456b92e469fa550dc217e20ad6d, 2020-10-04) to 98edd1fbf8a68977a2a7c1312eb1ebff80515a92
ending github query because we found starting sha: a1dfd2490a6cb456b92e469fa550dc217e20ad6d
get_commits_between returning commits, len: 6
  commit[0] 2020-10-05: Auto merge of #77080 - richkadel:llvm-coverage-counters-2, r=tmandry
  commit[1] 2020-10-06: Auto merge of #77606 - JohnTitor:rollup-7rgahdt, r=JohnTitor
  commit[2] 2020-10-06: Auto merge of #77594 - timvermeulen:chain_advance_by, r=scottmcm
  commit[3] 2020-10-06: Auto merge of #73905 - matthewjasper:projection-bounds-2, r=nikomatsakis
  commit[4] 2020-10-06: Auto merge of #76356 - caass:hooks, r=jyn514
  commit[5] 2020-10-06: Auto merge of #77386 - joshtriplett:static-glibc, r=petrochenkov
ERROR: no CI builds available between a1dfd2490a6cb456b92e469fa550dc217e20ad6d and 98edd1fbf8a68977a2a7c1312eb1ebff80515a92 within last 167 days

I see that the PR did add a bunch of tests, but I don't think this specific case was covered (at least, judging by the pre-#73905 error messages of new tests).

@rustbot labels: -E-needs-bisection

@rustbot rustbot removed the E-needs-bisection Call for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustc label Mar 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-associated-items Area: Associated items (types, constants & functions) A-closures Area: Closures (`|…| { … }`) A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-trait-system Area: Trait system C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants