Skip to content

Don't bind hidden types when searching for matching impls #93859

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// Equal types, all is good.
return true;
}
// Normalization reveals opaque types, but we may be validating MIR while computing
// said opaque types, causing cycles.
if (src, dest).has_opaque_types() {
return true;
}
// Normalize projections and things like that.
let param_env = self.param_env;
let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
let src = self.tcx.normalize_erasing_regions(param_env, src);
let dest = self.tcx.normalize_erasing_regions(param_env, dest);

Expand Down
6 changes: 1 addition & 5 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Ok(_) => span_bug!(
cause.span,
"opaque types are never equal to anything but themselves: {:#?}",
(a, b)
(a.kind(), b.kind())
),
Err(e) => Err(e),
}
Expand Down Expand Up @@ -450,10 +450,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
trace!(?origin);
origin
}

pub fn opaque_types(&self) -> OpaqueTypeMap<'tcx> {
self.inner.borrow().opaque_type_storage.opaque_types()
}
}

// Visitor that requires that (almost) all regions in the type visited outlive
Expand Down
10 changes: 1 addition & 9 deletions compiler/rustc_infer/src/infer/opaque_types/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,6 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
}
}

pub fn get_decl(&self, key: &OpaqueTypeKey<'tcx>) -> Option<&OpaqueTypeDecl<'tcx>> {
self.opaque_types.get(key)
}

pub fn opaque_types(&self) -> OpaqueTypeMap<'tcx> {
self.opaque_types.clone()
}

#[instrument(level = "debug")]
pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> {
std::mem::take(&mut self.opaque_types)
Expand Down Expand Up @@ -69,7 +61,7 @@ pub struct OpaqueTypeTable<'a, 'tcx> {

impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
pub fn register(
pub(crate) fn register(
&mut self,
key: OpaqueTypeKey<'tcx>,
hidden_type: OpaqueHiddenType<'tcx>,
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_trait_selection/src/traits/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,11 @@ pub fn codegen_fulfill_obligation<'tcx>(
});
let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);

// We may constrain the hidden types of opaque types in this query, but this is
// not information our callers need, as all that information is handled by borrowck
// and typeck.
drop(infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types());
// There should be no opaque types during codegen, they all get revealed.
let opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
if !opaque_types.is_empty() {
bug!("{:#?}", opaque_types);
}

debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
Ok(impl_source)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2163,6 +2163,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let InferOk { obligations, .. } = self
.infcx
.at(&cause, obligation.param_env)
.define_opaque_types(false)
.eq(placeholder_obligation_trait_ref, impl_trait_ref)
.map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
nested_obligations.extend(obligations);
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/impl-trait/nested_impl_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ fn fine(x: impl Into<u32>) -> impl Into<u32> { x }

fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
//~^ ERROR nested `impl Trait` is not allowed
//~| ERROR `impl Into<u32>` doesn't implement `Debug`
//~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied

fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
//~^ ERROR nested `impl Trait` is not allowed
Expand All @@ -17,7 +17,7 @@ struct X;
impl X {
fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
//~^ ERROR nested `impl Trait` is not allowed
//~| ERROR `impl Into<u32>` doesn't implement `Debug`
//~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
}

fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> {
Expand Down
18 changes: 6 additions & 12 deletions src/test/ui/impl-trait/nested_impl_trait.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,21 @@ error[E0562]: `impl Trait` not allowed outside of function and method return typ
LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
| ^^^^^^^^^^^^^^

error[E0277]: `impl Into<u32>` doesn't implement `Debug`
error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
--> $DIR/nested_impl_trait.rs:5:70
|
LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
| ^ `impl Into<u32>` cannot be formatted using `{:?}` because it doesn't implement `Debug`
| ^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
|
help: consider further restricting this bound
|
LL | fn bad_in_ret_position(x: impl Into<u32> + std::fmt::Debug) -> impl Into<impl Debug> { x }
| +++++++++++++++++
= note: required because of the requirements on the impl of `Into<impl Debug>` for `impl Into<u32>`

error[E0277]: `impl Into<u32>` doesn't implement `Debug`
error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
--> $DIR/nested_impl_trait.rs:18:58
|
LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
| ^ `impl Into<u32>` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
help: consider further restricting this bound
| ^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
|
LL | fn bad(x: impl Into<u32> + std::fmt::Debug) -> impl Into<impl Debug> { x }
| +++++++++++++++++
= note: required because of the requirements on the impl of `Into<impl Debug>` for `impl Into<u32>`

error: aborting due to 8 previous errors

Expand Down
29 changes: 29 additions & 0 deletions src/test/ui/impl-trait/projection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// build-pass
// needs to be build-pass, because it is a regression test for a mir validation failure
// that only happens during codegen.

struct D;

trait Tr {
type It;
fn foo(self) -> Option<Self::It>;
}

impl<'a> Tr for &'a D {
type It = ();
fn foo(self) -> Option<()> { None }
}

fn run<F>(f: F)
where for<'a> &'a D: Tr,
F: Fn(<&D as Tr>::It),
{
let d = &D;
while let Some(i) = d.foo() {
f(i);
}
}

fn main() {
run(|_| {});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![feature(type_alias_impl_trait)]

type Foo = impl PartialEq<(Foo, i32)>;

struct Bar;

impl PartialEq<(Foo, i32)> for Bar {
fn eq(&self, _other: &(Foo, i32)) -> bool {
true
}
}

fn foo() -> Foo {
Bar //~ ERROR can't compare `Bar` with `(Bar, i32)`
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0277]: can't compare `Bar` with `(Bar, i32)`
--> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:14:5
|
LL | Bar
| ^^^ no implementation for `Bar == (Bar, i32)`
|
= help: the trait `PartialEq<(Bar, i32)>` is not implemented for `Bar`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,18 @@

#![feature(type_alias_impl_trait)]

mod direct {
type Foo = impl PartialEq<(Foo, i32)>;
type Foo = impl PartialEq<(Foo, i32)>;

struct Bar;
struct Bar;

impl PartialEq<(Foo, i32)> for Bar {
fn eq(&self, _other: &(Foo, i32)) -> bool {
true
}
}

fn foo() -> Foo {
Bar
impl PartialEq<(Bar, i32)> for Bar {
fn eq(&self, _other: &(Bar, i32)) -> bool {
true
}
}

mod indirect {
type Foo = impl PartialEq<(Foo, i32)>;

struct Bar;

impl PartialEq<(Bar, i32)> for Bar {
fn eq(&self, _other: &(Bar, i32)) -> bool {
true
}
}

fn foo() -> Foo {
Bar
}
fn foo() -> Foo {
Bar
}

fn main() {}
30 changes: 30 additions & 0 deletions src/test/ui/impl-trait/trait_resolution.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// check-pass

use std::fmt::Debug;

pub struct EventStream<S> {
stream: S,
}

impl<S: Debug> EventStream<S> {
fn into_stream(self) -> impl Debug {
unimplemented!()
}

pub fn into_reader(self) -> impl Debug {
ReaderStream::from(self.into_stream())
}
}

#[derive(Debug)]
pub struct ReaderStream<S> {
stream: S,
}

impl<S> From<S> for ReaderStream<S> {
fn from(stream: S) -> Self {
ReaderStream { stream }
}
}

fn main() {}