From 769b1cfd0311e3ab58fc4ba77b5a0381f5511a31 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 3 Jul 2019 22:20:16 +0200 Subject: [PATCH] Normalize projections in opaque types --- src/librustc/infer/opaque_types/mod.rs | 6 + src/librustc_typeck/check/mod.rs | 1 + .../ui/async-await/bound-normalization.rs | 16 +++ .../ui/impl-trait/bound-normalization-fail.rs | 53 +++++++++ .../bound-normalization-fail.stderr | 29 +++++ .../ui/impl-trait/bound-normalization-pass.rs | 103 ++++++++++++++++++ .../bound-normalization-pass.stderr | 6 + 7 files changed, 214 insertions(+) create mode 100644 src/test/ui/async-await/bound-normalization.rs create mode 100644 src/test/ui/impl-trait/bound-normalization-fail.rs create mode 100644 src/test/ui/impl-trait/bound-normalization-fail.stderr create mode 100644 src/test/ui/impl-trait/bound-normalization-pass.rs create mode 100644 src/test/ui/impl-trait/bound-normalization-pass.stderr diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index f43e3fa0b77..0c660aab65d 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -1037,6 +1037,12 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let predicates_of = tcx.predicates_of(def_id); debug!("instantiate_opaque_types: predicates={:#?}", predicates_of,); let bounds = predicates_of.instantiate(tcx, substs); + + let param_env = tcx.param_env(def_id); + let InferOk { value: bounds, obligations } = + infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, &bounds); + self.obligations.extend(obligations); + debug!("instantiate_opaque_types: bounds={:?}", bounds); let required_region_bounds = tcx.required_region_bounds(ty, bounds.predicates.clone()); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 907cc23d667..05fdfaa9a80 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1065,6 +1065,7 @@ fn check_fn<'a, 'tcx>( &declared_ret_ty, decl.output.span(), ); + debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); fn_sig = fcx.tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), diff --git a/src/test/ui/async-await/bound-normalization.rs b/src/test/ui/async-await/bound-normalization.rs new file mode 100644 index 00000000000..8026350aaf2 --- /dev/null +++ b/src/test/ui/async-await/bound-normalization.rs @@ -0,0 +1,16 @@ +// check-pass +// edition:2018 + +#![feature(async_await)] + +// See issue 60414 + +trait Trait { + type Assoc; +} + +async fn foo>() -> T::Assoc { + () +} + +fn main() {} diff --git a/src/test/ui/impl-trait/bound-normalization-fail.rs b/src/test/ui/impl-trait/bound-normalization-fail.rs new file mode 100644 index 00000000000..476ae62fa0f --- /dev/null +++ b/src/test/ui/impl-trait/bound-normalization-fail.rs @@ -0,0 +1,53 @@ +// compile-fail +// edition:2018 + +#![feature(async_await)] +#![feature(existential_type)] +#![feature(impl_trait_in_bindings)] +//~^ WARNING the feature `impl_trait_in_bindings` is incomplete + +// See issue 60414 + +///////////////////////////////////////////// +// Reduction to `impl Trait` + +struct Foo(T); + +trait FooLike { type Output; } + +impl FooLike for Foo { + type Output = T; +} + +mod impl_trait { + use super::*; + + trait Trait { + type Assoc; + } + + /// `T::Assoc` can't be normalized any further here. + fn foo_fail() -> impl FooLike { + //~^ ERROR: type mismatch + Foo(()) + } +} + +///////////////////////////////////////////// +// Same with lifetimes in the trait + +mod lifetimes { + use super::*; + + trait Trait<'a> { + type Assoc; + } + + /// Missing bound constraining `Assoc`, `T::Assoc` can't be normalized further. + fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike { + //~^ ERROR: type mismatch + Foo(()) + } +} + +fn main() {} diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr new file mode 100644 index 00000000000..fa2dd20a6ee --- /dev/null +++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr @@ -0,0 +1,29 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/bound-normalization-fail.rs:6:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving ` as FooLike>::Output == ::Assoc` + --> $DIR/bound-normalization-fail.rs:30:32 + | +LL | fn foo_fail() -> impl FooLike { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found associated type + | + = note: expected type `()` + found type `::Assoc` + = note: the return type of a function must have a statically known size + +error[E0271]: type mismatch resolving ` as FooLike>::Output == >::Assoc` + --> $DIR/bound-normalization-fail.rs:47:41 + | +LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found associated type + | + = note: expected type `()` + found type `>::Assoc` + = note: the return type of a function must have a statically known size + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/impl-trait/bound-normalization-pass.rs b/src/test/ui/impl-trait/bound-normalization-pass.rs new file mode 100644 index 00000000000..1c7e776a479 --- /dev/null +++ b/src/test/ui/impl-trait/bound-normalization-pass.rs @@ -0,0 +1,103 @@ +// check-pass +// edition:2018 + +#![feature(async_await)] +#![feature(existential_type)] +#![feature(impl_trait_in_bindings)] +//~^ WARNING the feature `impl_trait_in_bindings` is incomplete + +// See issue 60414 + +///////////////////////////////////////////// +// Reduction to `impl Trait` + +struct Foo(T); + +trait FooLike { type Output; } + +impl FooLike for Foo { + type Output = T; +} + +mod impl_trait { + use super::*; + + trait Trait { + type Assoc; + } + + /// `T::Assoc` should be normalized to `()` here. + fn foo_pass>() -> impl FooLike { + Foo(()) + } +} + +///////////////////////////////////////////// +// Same with lifetimes in the trait + +mod lifetimes { + use super::*; + + trait Trait<'a> { + type Assoc; + } + + /// Like above. + fn foo2_pass<'a, T: Trait<'a, Assoc=()> + 'a>() -> impl FooLike + 'a { + Foo(()) + } + + /// Normalization to type containing bound region. + fn foo2_pass2<'a, T: Trait<'a, Assoc=&'a ()> + 'a>() -> impl FooLike + 'a { + Foo(&()) + } +} + +///////////////////////////////////////////// +// Reduction using `impl Trait` in bindings + +mod impl_trait_in_bindings { + struct Foo; + + trait FooLike { type Output; } + + impl FooLike for Foo { + type Output = u32; + } + + trait Trait { + type Assoc; + } + + fn foo>() { + let _: impl FooLike = Foo; + } +} + +///////////////////////////////////////////// +// The same applied to `existential type`s + +mod existential_types { + trait Implemented { + type Assoc; + } + impl Implemented for T { + type Assoc = u8; + } + + trait Trait { + type Out; + } + + impl Trait for () { + type Out = u8; + } + + existential type Ex: Trait::Assoc>; + + fn define() -> Ex { + () + } +} + +fn main() {} diff --git a/src/test/ui/impl-trait/bound-normalization-pass.stderr b/src/test/ui/impl-trait/bound-normalization-pass.stderr new file mode 100644 index 00000000000..c1b7fb2c253 --- /dev/null +++ b/src/test/ui/impl-trait/bound-normalization-pass.stderr @@ -0,0 +1,6 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/bound-normalization-pass.rs:6:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ +