diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index f8e5764878579..1c4b161d5b545 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -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); diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 46420fbe0c305..38b092cfd7034 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -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), } @@ -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 diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index 9b8f225ce367b..50c90d20d101b 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -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) @@ -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>, diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 04a7da06063ba..2c9bdb2086110 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -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) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a183a20a2fed0..80f3037041eba 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -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); diff --git a/src/test/ui/impl-trait/nested_impl_trait.rs b/src/test/ui/impl-trait/nested_impl_trait.rs index 6eac2dece1f12..5132413b08fe9 100644 --- a/src/test/ui/impl-trait/nested_impl_trait.rs +++ b/src/test/ui/impl-trait/nested_impl_trait.rs @@ -4,7 +4,7 @@ fn fine(x: impl Into) -> impl Into { x } fn bad_in_ret_position(x: impl Into) -> impl Into { x } //~^ ERROR nested `impl Trait` is not allowed -//~| ERROR `impl Into` doesn't implement `Debug` +//~| ERROR the trait bound `impl Debug: From>` is not satisfied fn bad_in_fn_syntax(x: fn() -> impl Into) {} //~^ ERROR nested `impl Trait` is not allowed @@ -17,7 +17,7 @@ struct X; impl X { fn bad(x: impl Into) -> impl Into { x } //~^ ERROR nested `impl Trait` is not allowed - //~| ERROR `impl Into` doesn't implement `Debug` + //~| ERROR the trait bound `impl Debug: From>` is not satisfied } fn allowed_in_assoc_type() -> impl Iterator { diff --git a/src/test/ui/impl-trait/nested_impl_trait.stderr b/src/test/ui/impl-trait/nested_impl_trait.stderr index 87ff4ffc4fb17..07fc39f7f4f90 100644 --- a/src/test/ui/impl-trait/nested_impl_trait.stderr +++ b/src/test/ui/impl-trait/nested_impl_trait.stderr @@ -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 { | ^^^^^^^^^^^^^^ -error[E0277]: `impl Into` doesn't implement `Debug` +error[E0277]: the trait bound `impl Debug: From>` is not satisfied --> $DIR/nested_impl_trait.rs:5:70 | LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } - | ^ `impl Into` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^ the trait `From>` is not implemented for `impl Debug` | -help: consider further restricting this bound - | -LL | fn bad_in_ret_position(x: impl Into + std::fmt::Debug) -> impl Into { x } - | +++++++++++++++++ + = note: required because of the requirements on the impl of `Into` for `impl Into` -error[E0277]: `impl Into` doesn't implement `Debug` +error[E0277]: the trait bound `impl Debug: From>` is not satisfied --> $DIR/nested_impl_trait.rs:18:58 | LL | fn bad(x: impl Into) -> impl Into { x } - | ^ `impl Into` cannot be formatted using `{:?}` because it doesn't implement `Debug` - | -help: consider further restricting this bound + | ^ the trait `From>` is not implemented for `impl Debug` | -LL | fn bad(x: impl Into + std::fmt::Debug) -> impl Into { x } - | +++++++++++++++++ + = note: required because of the requirements on the impl of `Into` for `impl Into` error: aborting due to 8 previous errors diff --git a/src/test/ui/impl-trait/projection.rs b/src/test/ui/impl-trait/projection.rs new file mode 100644 index 0000000000000..21fc6591e97bf --- /dev/null +++ b/src/test/ui/impl-trait/projection.rs @@ -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; +} + +impl<'a> Tr for &'a D { + type It = (); + fn foo(self) -> Option<()> { None } +} + +fn run(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(|_| {}); +} \ No newline at end of file diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs new file mode 100644 index 0000000000000..6b200d7e3a89e --- /dev/null +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs @@ -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() {} diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr new file mode 100644 index 0000000000000..5476bf9d27745 --- /dev/null +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr @@ -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`. diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs index bdabc13c36a96..ad0a003e87948 100644 --- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs @@ -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() {} diff --git a/src/test/ui/impl-trait/trait_resolution.rs b/src/test/ui/impl-trait/trait_resolution.rs new file mode 100644 index 0000000000000..8dcbbfd6e6492 --- /dev/null +++ b/src/test/ui/impl-trait/trait_resolution.rs @@ -0,0 +1,30 @@ +// check-pass + +use std::fmt::Debug; + +pub struct EventStream { + stream: S, +} + +impl EventStream { + fn into_stream(self) -> impl Debug { + unimplemented!() + } + + pub fn into_reader(self) -> impl Debug { + ReaderStream::from(self.into_stream()) + } +} + +#[derive(Debug)] +pub struct ReaderStream { + stream: S, +} + +impl From for ReaderStream { + fn from(stream: S) -> Self { + ReaderStream { stream } + } +} + +fn main() {}