diff options
| author | Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> | 2021-09-16 19:08:25 +0000 |
|---|---|---|
| committer | Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> | 2021-09-23 13:35:16 +0000 |
| commit | 6067eadb65fbc7ba13c32cd76d888d8868a450c5 (patch) | |
| tree | 79503fb19785815eb5aa683f38bfbc29946cba15 /compiler/rustc_borrowck | |
| parent | 15d9ba0133ce0b35348e1c8367afe00aec841ffa (diff) | |
| download | rust-6067eadb65fbc7ba13c32cd76d888d8868a450c5.tar.gz rust-6067eadb65fbc7ba13c32cd76d888d8868a450c5.zip | |
Check that TAIT generics are fully generic in mir typeck instead of wf-check, as wf-check can by definition only check TAIT in return position and not account for TAITs defined in the body of the function
Diffstat (limited to 'compiler/rustc_borrowck')
| -rw-r--r-- | compiler/rustc_borrowck/src/region_infer/opaque_types.rs | 109 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/type_check/mod.rs | 18 |
2 files changed, 116 insertions, 11 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d790e31105c..b35e76b96ad 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,5 +1,9 @@ +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; +use rustc_hir::OpaqueTyOrigin; +use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::InferCtxt; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::opaque_types::InferCtxtExt; @@ -50,13 +54,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'_, 'tcx>, - opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, + opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>, span: Span, ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> { opaque_ty_decls .into_iter() - .map(|(opaque_type_key, concrete_type)| { + .filter_map(|(opaque_type_key, decl)| { let substs = opaque_type_key.substs; + let concrete_type = decl.concrete_ty; debug!(?concrete_type, ?substs); let mut subst_regions = vec![self.universal_regions.fr_static]; @@ -94,7 +99,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { universal_concrete_type, span, ); - (opaque_type_key, remapped_type) + + check_opaque_type_parameter_valid( + infcx.tcx, + opaque_type_key, + OpaqueTypeDecl { concrete_ty: remapped_type, ..decl }, + ) + .then_some((opaque_type_key, remapped_type)) }) .collect() } @@ -119,3 +130,95 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } } + +fn check_opaque_type_parameter_valid( + tcx: TyCtxt<'_>, + opaque_type_key: OpaqueTypeKey<'_>, + decl: OpaqueTypeDecl<'_>, +) -> bool { + match decl.origin { + // No need to check return position impl trait (RPIT) + // because for type and const parameters they are correct + // by construction: we convert + // + // fn foo<P0..Pn>() -> impl Trait + // + // into + // + // type Foo<P0...Pn> + // fn foo<P0..Pn>() -> Foo<P0...Pn>. + // + // For lifetime parameters we convert + // + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> + // + // into + // + // type foo::<'p0..'pn>::Foo<'q0..'qm> + // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. + // + // which would error here on all of the `'static` args. + OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true, + // Check these + OpaqueTyOrigin::TyAlias => {} + } + let span = decl.definition_span; + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); + for (i, arg) in opaque_type_key.substs.iter().enumerate() { + let arg_is_param = match arg.unpack() { + GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), + GenericArgKind::Lifetime(ty::ReStatic) => { + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_label( + tcx.def_span(opaque_generics.param_at(i, tcx).def_id), + "cannot use static lifetime; use a bound lifetime \ + instead or remove the lifetime parameter from the \ + opaque type", + ) + .emit(); + return false; + } + GenericArgKind::Lifetime(lt) => { + matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_)) + } + GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), + }; + + if arg_is_param { + seen_params.entry(arg).or_default().push(i); + } else { + // Prevent `fn foo() -> Foo<u32>` from being defining. + let opaque_param = opaque_generics.param_at(i, tcx); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note( + tcx.def_span(opaque_param.def_id), + &format!( + "used non-generic {} `{}` for generic parameter", + opaque_param.kind.descr(), + arg, + ), + ) + .emit(); + return false; + } + } + + for (_, indices) in seen_params { + if indices.len() > 1 { + let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); + let spans: Vec<_> = indices + .into_iter() + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) + .collect(); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note(spans, &format!("{} used multiple times", descr)) + .emit(); + return false; + } + } + true +} diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 5ccf3806025..3e536eb845f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -14,6 +14,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ @@ -193,16 +194,17 @@ pub(crate) fn type_check<'mir, 'tcx>( opaque_type_values .into_iter() - .filter_map(|(opaque_type_key, decl)| { - let mut revealed_ty = infcx.resolve_vars_if_possible(decl.concrete_ty); - if revealed_ty.has_infer_types_or_consts() { + .filter_map(|(opaque_type_key, mut decl)| { + decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty); + if decl.concrete_ty.has_infer_types_or_consts() { infcx.tcx.sess.delay_span_bug( body.span, - &format!("could not resolve {:#?}", revealed_ty.kind()), + &format!("could not resolve {:#?}", decl.concrete_ty.kind()), ); - revealed_ty = infcx.tcx.ty_error(); + decl.concrete_ty = infcx.tcx.ty_error(); } - let concrete_is_opaque = if let ty::Opaque(def_id, _) = revealed_ty.kind() { + let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind() + { *def_id == opaque_type_key.def_id } else { false @@ -234,7 +236,7 @@ pub(crate) fn type_check<'mir, 'tcx>( ); None } else { - Some((opaque_type_key, revealed_ty)) + Some((opaque_type_key, decl)) } }) .collect() @@ -890,7 +892,7 @@ struct BorrowCheckContext<'a, 'tcx> { crate struct MirTypeckResults<'tcx> { crate constraints: MirTypeckRegionConstraints<'tcx>, crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, - crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, + crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>, } /// A collection of region constraints that must be satisfied for the |
