From 5b279c801635c2762c013c1d13a9bead3bcd9df4 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 28 Jun 2020 16:46:02 +0100 Subject: [PATCH] Check opaque types satisfy their bounds --- .../rustc_trait_selection/src/opaque_types.rs | 3 +- compiler/rustc_typeck/src/check/check.rs | 68 ++++++++++++++++++- ...mpl-trait-return-missing-constraint.stderr | 1 - .../ui/async-await/async-error-span.stderr | 3 - .../issue-64130-4-async-move.stderr | 1 - src/test/ui/async-await/issue-70818.stderr | 1 - .../type-mismatch-signature-deduction.stderr | 1 - .../bound-normalization-fail.stderr | 2 - src/test/ui/impl-trait/issue-55872-1.stderr | 2 - src/test/ui/issues-71798.stderr | 2 - .../lifetime-elision-return-type-trait.stderr | 5 -- .../feature-gate-never_type_fallback.stderr | 5 -- ...mpl-trait-return-trailing-semicolon.stderr | 2 - .../bounds-are-checked-2.rs | 19 ++++++ .../bounds-are-checked-2.stderr | 14 ++++ .../bounds-are-checked.rs | 25 +++++++ .../bounds-are-checked.stderr | 26 +++++++ .../generic_duplicate_param_use10.rs | 4 +- .../generic_duplicate_param_use7.rs | 4 +- .../type-alias-impl-trait/issue-60371.stderr | 1 - .../type-alias-impl-trait/issue-63279.stderr | 1 - .../type-alias-impl-trait.rs | 4 +- 22 files changed, 158 insertions(+), 36 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs create mode 100644 src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr create mode 100644 src/test/ui/type-alias-impl-trait/bounds-are-checked.rs create mode 100644 src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 1babfb8508e..0621d9bf09e 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -1170,7 +1170,8 @@ fn fold_opaque_ty( // This also instantiates nested instances of `impl Trait`. let predicate = self.instantiate_opaque_types_in_map(&predicate); - let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType); + let cause = + traits::ObligationCause::new(span, self.body_id, traits::MiscObligation); // Require that the predicate holds for the concrete type. debug!("instantiate_opaque_types: predicate={:?}", predicate); diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 2df9007195f..f5e6ff07b88 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -387,7 +387,10 @@ pub(super) fn check_opaque<'tcx>( ) { check_opaque_for_inheriting_lifetimes(tcx, def_id, span); tcx.ensure().type_of(def_id); - check_opaque_for_cycles(tcx, def_id, substs, span, origin); + if check_opaque_for_cycles(tcx, def_id, substs, span, origin).is_err() { + return; + } + check_opaque_meets_bounds(tcx, def_id, substs, span, origin); } /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result @@ -504,7 +507,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>( substs: SubstsRef<'tcx>, span: Span, origin: &hir::OpaqueTyOrigin, -) { +) -> Result<(), ErrorReported> { if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs) { match origin { @@ -514,7 +517,68 @@ pub(super) fn check_opaque_for_cycles<'tcx>( } _ => opaque_type_cycle_error(tcx, def_id, span), } + Err(ErrorReported) + } else { + Ok(()) + } +} + +/// Check that the concrete type behind `impl Trait` actually implements `Trait`. +fn check_opaque_meets_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + substs: SubstsRef<'tcx>, + span: Span, + origin: &hir::OpaqueTyOrigin, +) { + match origin { + // Checked when type checking the function containing them. + hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => return, + // Can have different predicates to their defining use + hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::Misc => {} } + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let param_env = tcx.param_env(def_id); + + tcx.infer_ctxt().enter(move |infcx| { + let inh = Inherited::new(infcx, def_id); + let infcx = &inh.infcx; + let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); + + let misc_cause = traits::ObligationCause::misc(span, hir_id); + + let (_, opaque_type_map) = inh.register_infer_ok_obligations( + infcx.instantiate_opaque_types(def_id.to_def_id(), hir_id, param_env, &opaque_ty, span), + ); + + for (def_id, opaque_defn) in opaque_type_map { + match infcx + .at(&misc_cause, param_env) + .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs)) + { + Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok), + Err(ty_err) => tcx.sess.delay_span_bug( + opaque_defn.definition_span, + &format!( + "could not unify `{}` with revealed type:\n{}", + opaque_defn.concrete_ty, ty_err, + ), + ), + } + } + + // Check that all obligations are satisfied by the implementation's + // version. + if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(errors, None, false); + } + + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let fcx = FnCtxt::new(&inh, param_env, hir_id); + fcx.regionck_item(hir_id, span, &[]); + }); } pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { diff --git a/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr index 566e390a31e..b0e9e33a6c3 100644 --- a/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr +++ b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr @@ -9,7 +9,6 @@ LL | fn baz() -> impl Bar { | = note: expected associated type `::Item` found type `i32` - = note: the return type of a function must have a statically known size help: consider constraining the associated type `::Item` to `i32` | LL | fn bar() -> impl Bar { diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr index d808a5939bb..8cd0e40c8cf 100644 --- a/src/test/ui/async-await/async-error-span.stderr +++ b/src/test/ui/async-await/async-error-span.stderr @@ -3,9 +3,6 @@ error[E0277]: `()` is not a future | LL | fn get_future() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future -LL | -LL | panic!() - | -------- this returned value is of type `!` | = help: the trait `Future` is not implemented for `()` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr index 440ea0a38e6..f5d023ab781 100644 --- a/src/test/ui/async-await/issue-64130-4-async-move.stderr +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -30,7 +30,6 @@ help: consider moving this into a `let` binding to create a shorter lived borrow | LL | match client.status() { | ^^^^^^^^^^^^^^^ - = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/async-await/issue-70818.stderr b/src/test/ui/async-await/issue-70818.stderr index 364194bea10..20ee22e448c 100644 --- a/src/test/ui/async-await/issue-70818.stderr +++ b/src/test/ui/async-await/issue-70818.stderr @@ -12,7 +12,6 @@ note: captured value is not `Send` | LL | async { (ty, ty1) } | ^^^ has type `U` which is not `Send` - = note: the return type of a function must have a statically known size help: consider restricting type parameter `U` | LL | fn foo(ty: T, ty1: U) -> impl Future + Send { diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr index 260fbb2ec7e..8f6f87f78de 100644 --- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -15,7 +15,6 @@ LL | fn foo() -> impl Generator { | = note: expected enum `std::result::Result<{integer}, _>` found type `i32` - = note: the return type of a function must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr index 03aba10cc79..a7d06c71663 100644 --- a/src/test/ui/impl-trait/bound-normalization-fail.stderr +++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr @@ -15,7 +15,6 @@ LL | fn foo_fail() -> impl FooLike { | = note: expected type `()` found associated type `::Assoc` - = note: the return type of a function must have a statically known size help: consider constraining the associated type `::Assoc` to `()` | LL | fn foo_fail>() -> impl FooLike { @@ -35,7 +34,6 @@ LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike { | = note: expected type `()` found associated type `>::Assoc` - = note: the return type of a function must have a statically known size help: consider constraining the associated type `>::Assoc` to `()` | LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike { diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr index db49d988bb8..64c536cf1fe 100644 --- a/src/test/ui/impl-trait/issue-55872-1.stderr +++ b/src/test/ui/impl-trait/issue-55872-1.stderr @@ -14,7 +14,6 @@ LL | type E = impl Copy; | ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` | = note: required because it appears within the type `(S, T)` - = note: the return type of a function must have a statically known size help: consider further restricting this bound | LL | impl Bar for S { @@ -27,7 +26,6 @@ LL | type E = impl Copy; | ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` | = note: required because it appears within the type `(S, T)` - = note: the return type of a function must have a statically known size help: consider further restricting this bound | LL | fn foo() -> Self::E { diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr index 867f8f0496c..835d479f28f 100644 --- a/src/test/ui/issues-71798.stderr +++ b/src/test/ui/issues-71798.stderr @@ -9,8 +9,6 @@ error[E0277]: `u32` is not a future | LL | fn test_ref(x: &u32) -> impl std::future::Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future -LL | *x - | -- this returned value is of type `u32` | = help: the trait `Future` is not implemented for `u32` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr index e43fb6d0edf..c3d597bec2e 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr @@ -3,11 +3,6 @@ error[E0277]: the trait bound `std::result::Result<(), _>: Future` is not satisf | LL | fn foo() -> impl Future> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `std::result::Result<(), _>` -LL | -LL | Ok(()) - | ------ this returned value is of type `std::result::Result<(), _>` - | - = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr index c652faafad4..670f76867ce 100644 --- a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr +++ b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr @@ -3,11 +3,6 @@ error[E0277]: the trait bound `(): T` is not satisfied | LL | fn should_ret_unit() -> impl T { | ^^^^^^ the trait `T` is not implemented for `()` -LL | -LL | panic!() - | -------- this returned value is of type `!` - | - = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr index cc3a2b9419c..d826222a06a 100644 --- a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr +++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr @@ -5,8 +5,6 @@ LL | fn foo() -> impl Bar { | ^^^^^^^^ the trait `Bar` is not implemented for `()` LL | 5; | - consider removing this semicolon - | - = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs b/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs new file mode 100644 index 00000000000..5566f40f960 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs @@ -0,0 +1,19 @@ +// Make sure that we check that impl trait types implement the traits that they +// claim to. + +#![feature(type_alias_impl_trait)] + +type X = impl Clone; +//~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied + +fn f(t: T) -> X { + t +} + +fn g(o : Option>) -> Option> { + o.clone() +} + +fn main() { + g(None::>); +} diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr b/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr new file mode 100644 index 00000000000..e20130007ee --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied + --> $DIR/bounds-are-checked-2.rs:6:13 + | +LL | type X = impl Clone; + | ^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | type X = impl Clone; + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs b/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs new file mode 100644 index 00000000000..759bf4f4f0d --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs @@ -0,0 +1,25 @@ +// Make sure that we check that impl trait types implement the traits that they +// claim to. + +#![feature(type_alias_impl_trait)] + +type X<'a> = impl Into<&'static str> + From<&'a str>; +//~^ ERROR mismatched types + +fn f<'a: 'static>(t: &'a str) -> X<'a> { + //~^ WARNING unnecessary lifetime parameter + t +} + +fn extend_lt<'a>(o: &'a str) -> &'static str { + X::<'_>::from(o).into() +} + +fn main() { + let r = + { + let s = "abcdef".to_string(); + extend_lt(&s) + }; + println!("{}", r); +} diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr new file mode 100644 index 00000000000..42468b91a62 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr @@ -0,0 +1,26 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/bounds-are-checked.rs:9:6 + | +LL | fn f<'a: 'static>(t: &'a str) -> X<'a> { + | ^^^^^^^^^^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +error[E0308]: mismatched types + --> $DIR/bounds-are-checked.rs:6:14 + | +LL | type X<'a> = impl Into<&'static str> + From<&'a str>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected type `std::convert::From<&'a str>` + found type `std::convert::From<&'static str>` +note: the lifetime `'a` as defined on the item at 6:8... + --> $DIR/bounds-are-checked.rs:6:8 + | +LL | type X<'a> = impl Into<&'static str> + From<&'a str>; + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use10.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use10.rs index 898dab1b0b9..c17d595dbb3 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use10.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use10.rs @@ -1,11 +1,11 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass #![feature(type_alias_impl_trait)] use std::fmt::Debug; fn main() {} -type Two = impl Debug; +type Two = impl Debug; fn two(t: T, _: U) -> Two { (t, 4u32) diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use7.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use7.rs index 712a6539f01..feebf81eef2 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use7.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use7.rs @@ -1,11 +1,11 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass #![feature(type_alias_impl_trait)] use std::fmt::Debug; fn main() {} -type Two = impl Debug; +type Two = impl Debug; fn two(t: T, u: U) -> Two { (t, t) diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr index bf2d612fcdb..905248fb337 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr @@ -15,7 +15,6 @@ LL | type Item = impl Bug; | = help: the following implementations were found: <&() as Bug> - = note: the return type of a function must have a statically known size error: could not find defining uses --> $DIR/issue-60371.rs:8:17 diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr index 9ad181b3684..8615b3f741b 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr @@ -6,7 +6,6 @@ LL | type Closure = impl FnOnce(); | = note: expected opaque type `impl FnOnce<()>` found unit type `()` - = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs index 209134acf01..80192d19af9 100644 --- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs @@ -70,14 +70,14 @@ fn my_other_iter(u: U) -> MyOtherIter { } trait Trait {} -type GenericBound<'a, T: Trait> = impl Sized + 'a; +type GenericBound<'a, T: Trait + 'a> = impl Sized + 'a; fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> { t } mod pass_through { - pub type Passthrough = impl Sized + 'static; + pub type Passthrough = impl Sized + 'static; fn define_passthrough(t: T) -> Passthrough { t -- 2.44.0