about summary refs log tree commit diff
path: root/compiler/rustc_borrowck
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2021-09-16 19:08:25 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2021-09-23 13:35:16 +0000
commit6067eadb65fbc7ba13c32cd76d888d8868a450c5 (patch)
tree79503fb19785815eb5aa683f38bfbc29946cba15 /compiler/rustc_borrowck
parent15d9ba0133ce0b35348e1c8367afe00aec841ffa (diff)
downloadrust-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.rs109
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs18
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