From eca0ead17d3b591ed1e1cdeac434179fcda5ca33 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 31 Mar 2022 13:52:40 +0000 Subject: [PATCH] Enforce well formedness for type alias impl trait's hidden type --- compiler/rustc_typeck/src/check/check.rs | 10 +++++- compiler/rustc_typeck/src/check/regionck.rs | 2 +- .../underconstrained_generic.rs | 28 +++++++++++++++ .../underconstrained_generic.stderr | 19 +++++++++++ .../underconstrained_lifetime.rs | 34 +++++++++++++++++++ .../underconstrained_lifetime.stderr | 20 +++++++++++ 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/underconstrained_generic.rs create mode 100644 src/test/ui/type-alias-impl-trait/underconstrained_generic.stderr create mode 100644 src/test/ui/type-alias-impl-trait/underconstrained_lifetime.rs create mode 100644 src/test/ui/type-alias-impl-trait/underconstrained_lifetime.stderr diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 5362ca8d719..33682177253 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -12,12 +12,13 @@ use rustc_hir::{def::Res, ItemKind, Node, PathSegment}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::traits::Obligation; use rustc_middle::hir::nested_filter; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, ParamEnv, ToPredicate, Ty, TyCtxt}; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_span::symbol::sym; use rustc_span::{self, MultiSpan, Span}; @@ -674,6 +675,13 @@ fn check_opaque_meets_bounds<'tcx>( } } + // Additionally require the hidden type to be well-formed with only the generics of the opaque type. + // Defining use functions may have more bounds than the opaque type, which is ok, as long as the + // hidden type is well formed even without those bounds. + let predicate = + ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx); + inh.register_predicate(Obligation::new(misc_cause, param_env, predicate)); + // Check that all obligations are satisfied by the implementation's // version. let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 513e8576f2d..e18cb31acbd 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -171,8 +171,8 @@ pub fn regionck_expr(&self, body: &'tcx hir::Body<'tcx>) { /// Region checking during the WF phase for items. `wf_tys` are the /// types from which we should derive implied bounds, if any. + #[instrument(level = "debug", skip(self))] pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: FxHashSet>) { - debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys); let subject = self.tcx.hir().local_def_id(item_id); let mut rcx = RegionCtxt::new(self, item_id, Subject(subject), self.param_env); rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span); diff --git a/src/test/ui/type-alias-impl-trait/underconstrained_generic.rs b/src/test/ui/type-alias-impl-trait/underconstrained_generic.rs new file mode 100644 index 00000000000..22264670f37 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/underconstrained_generic.rs @@ -0,0 +1,28 @@ +#![feature(type_alias_impl_trait)] + +use std::marker::PhantomData; + +trait Trait { + fn foo(t: T) -> U; +} + +trait ProofForConversion { + fn convert(_: PhantomData, r: T) -> U; +} + +impl ProofForConversion for () { + fn convert(_: PhantomData, r: T) -> U { + X::foo(r) + } +} + +type Converter = impl ProofForConversion; +//~^ ERROR the trait bound `T: Trait` is not satisfied + +fn _defining_use() -> Converter { + () +} + + +fn main() { +} diff --git a/src/test/ui/type-alias-impl-trait/underconstrained_generic.stderr b/src/test/ui/type-alias-impl-trait/underconstrained_generic.stderr new file mode 100644 index 00000000000..1c305abcfeb --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/underconstrained_generic.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `T: Trait` is not satisfied + --> $DIR/underconstrained_generic.rs:19:21 + | +LL | type Converter = impl ProofForConversion; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | +note: required because of the requirements on the impl of `ProofForConversion` for `()` + --> $DIR/underconstrained_generic.rs:13:16 + | +LL | impl ProofForConversion for () { + | ^^^^^^^^^^^^^^^^^^^^^ ^^ +help: consider restricting type parameter `T` + | +LL | type Converter = impl ProofForConversion; + | +++++++ + +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/underconstrained_lifetime.rs b/src/test/ui/type-alias-impl-trait/underconstrained_lifetime.rs new file mode 100644 index 00000000000..c5b2e8a1c5e --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/underconstrained_lifetime.rs @@ -0,0 +1,34 @@ +#![feature(type_alias_impl_trait)] + +use std::marker::PhantomData; + +trait ProofForConversion<'a, 'b> { + fn convert(_: PhantomData, r: &'a T) -> &'b T; +} + +impl<'a, 'b> ProofForConversion<'a, 'b> for &'b &'a () { + fn convert(_: PhantomData, r: &'a T) -> &'b T { + r + } +} + +type Converter<'a, 'b> = impl ProofForConversion<'a, 'b>; +//~^ ERROR reference has a longer lifetime than the data it references + +// Even _defining_use with an explicit `'a: 'b` compiles fine, too. +fn _defining_use<'a, 'b>(x: &'b &'a ()) -> Converter<'a, 'b> { + x +} + +fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { + Converter::<'a, 'b>::convert(PhantomData, x) +} + +fn main() { + let d; + { + let x = "Hello World".to_string(); + d = extend_lifetime(&x); + } + println!("{}", d); +} diff --git a/src/test/ui/type-alias-impl-trait/underconstrained_lifetime.stderr b/src/test/ui/type-alias-impl-trait/underconstrained_lifetime.stderr new file mode 100644 index 00000000000..12d85a49d01 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/underconstrained_lifetime.stderr @@ -0,0 +1,20 @@ +error[E0491]: in type `&'b &'a ()`, reference has a longer lifetime than the data it references + --> $DIR/underconstrained_lifetime.rs:15:26 + | +LL | type Converter<'a, 'b> = impl ProofForConversion<'a, 'b>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'b` as defined here + --> $DIR/underconstrained_lifetime.rs:15:20 + | +LL | type Converter<'a, 'b> = impl ProofForConversion<'a, 'b>; + | ^^ +note: but the referenced data is only valid for the lifetime `'a` as defined here + --> $DIR/underconstrained_lifetime.rs:15:16 + | +LL | type Converter<'a, 'b> = impl ProofForConversion<'a, 'b>; + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0491`. -- GitLab