about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2020-06-07 19:52:05 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2020-06-11 17:08:23 +0100
commitf975eceb62f3ecd9152c1eac998d2d9630323853 (patch)
tree0c58dc0dcd97b5bbdb713c927339ab4f917171e6
parent1e0832faaa45b2b2488885f06073c3f1eda9094d (diff)
downloadrust-f975eceb62f3ecd9152c1eac998d2d9630323853.tar.gz
rust-f975eceb62f3ecd9152c1eac998d2d9630323853.zip
Document some opaque types code
-rw-r--r--src/librustc_resolve/late/lifetimes.rs4
-rw-r--r--src/librustc_trait_selection/opaque_types.rs14
-rw-r--r--src/librustc_typeck/check/wfcheck.rs181
-rw-r--r--src/librustc_typeck/collect/type_of.rs10
4 files changed, 109 insertions, 100 deletions
diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs
index 0af49075c67..5bbf8703f0b 100644
--- a/src/librustc_resolve/late/lifetimes.rs
+++ b/src/librustc_resolve/late/lifetimes.rs
@@ -258,8 +258,8 @@ enum Elide {
     Exact(Region),
     /// Less or more than one lifetime were found, error on unspecified.
     Error(Vec<ElisionFailureInfo>),
-    /// Forbid lifetime elision inside of a larger scope that does. For
-    /// example, in let position impl trait.
+    /// Forbid lifetime elision inside of a larger scope where it would be
+    /// permitted. For example, in let position impl trait.
     Forbid,
 }
 
diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs
index e1f0c579a3c..d53a0ec9ef8 100644
--- a/src/librustc_trait_selection/opaque_types.rs
+++ b/src/librustc_trait_selection/opaque_types.rs
@@ -407,12 +407,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
         let first_own_region = match opaque_defn.origin {
             hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
-                // For these opaque types, only the item's own lifetime
-                // parameters are considered.
+                // We lower
+                //
+                // 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>.
+                //
+                // For these types we onlt iterate over `'l0..lm` below.
                 tcx.generics_of(def_id).parent_count
             }
             // These opaque type inherit all lifetime parameters from their
-            // parent.
+            // parent, so we have to check them all.
             hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::Misc => 0,
         };
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index c0be1d42d13..f3297ed6743 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -801,18 +801,14 @@ fn check_where_clauses<'tcx, 'fcx>(
             traits::Obligation::new(cause, fcx.param_env, pred)
         });
 
-    let mut predicates = predicates.instantiate_identity(fcx.tcx);
+    let predicates = predicates.instantiate_identity(fcx.tcx);
 
     if let Some((mut return_ty, span)) = return_ty {
         if return_ty.has_infer_types_or_consts() {
             fcx.select_obligations_where_possible(false, |_| {});
             return_ty = fcx.resolve_vars_if_possible(&return_ty);
         }
-        let opaque_types = check_opaque_types(tcx, fcx, def_id.expect_local(), span, return_ty);
-        for _ in 0..opaque_types.len() {
-            predicates.spans.push(span);
-        }
-        predicates.predicates.extend(opaque_types);
+        check_opaque_types(tcx, fcx, def_id.expect_local(), span, return_ty);
     }
 
     let predicates = fcx.normalize_associated_types_in(span, &predicates);
@@ -884,113 +880,109 @@ fn check_opaque_types<'fcx, 'tcx>(
     fn_def_id: LocalDefId,
     span: Span,
     ty: Ty<'tcx>,
-) -> Vec<ty::Predicate<'tcx>> {
+) {
     trace!("check_opaque_types(ty={:?})", ty);
-    let mut substituted_predicates = Vec::new();
     ty.fold_with(&mut ty::fold::BottomUpFolder {
         tcx: fcx.tcx,
         ty_op: |ty| {
             if let ty::Opaque(def_id, substs) = ty.kind {
                 trace!("check_opaque_types: opaque_ty, {:?}, {:?}", def_id, substs);
                 let generics = tcx.generics_of(def_id);
-                // Only check named `impl Trait` types defined in this crate.
-                if !def_id.is_local() {
+
+                let opaque_hir_id = if let Some(local_id) = def_id.as_local() {
+                    tcx.hir().as_local_hir_id(local_id)
+                } else {
+                    // Opaque types from other crates won't have defining uses in this crate.
                     return ty;
-                }
-                let opaque_hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
+                };
                 if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) =
                     tcx.hir().expect_item(opaque_hir_id).kind
                 {
-                    // Don't check return position impl trait.
+                    // 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.
+                    return ty;
+                }
+                if !may_define_opaque_type(tcx, fn_def_id, opaque_hir_id) {
                     return ty;
                 }
-                if may_define_opaque_type(tcx, fn_def_id, opaque_hir_id) {
-                    trace!("check_opaque_types: may define, generics={:#?}", generics);
-                    let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
-                    for (i, arg) in substs.iter().enumerate() {
-                        let arg_is_param = match arg.unpack() {
-                            GenericArgKind::Type(ty) => matches!(ty.kind, ty::Param(_)),
-
-                            GenericArgKind::Lifetime(region) => {
-                                if let ty::ReStatic = region {
-                                    tcx.sess
-                                        .struct_span_err(
-                                            span,
-                                            "non-defining opaque type use in defining scope",
-                                        )
-                                        .span_label(
-                                            tcx.def_span(generics.param_at(i, tcx).def_id),
-                                            "cannot use static lifetime; use a bound lifetime \
+                trace!("check_opaque_types: may define, generics={:#?}", generics);
+                let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
+                for (i, arg) in substs.iter().enumerate() {
+                    let arg_is_param = match arg.unpack() {
+                        GenericArgKind::Type(ty) => matches!(ty.kind, ty::Param(_)),
+
+                        GenericArgKind::Lifetime(region) => {
+                            if let ty::ReStatic = region {
+                                tcx.sess
+                                    .struct_span_err(
+                                        span,
+                                        "non-defining opaque type use in defining scope",
+                                    )
+                                    .span_label(
+                                        tcx.def_span(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();
-                                    continue;
-                                }
-
-                                true
+                                    )
+                                    .emit();
+                                continue;
                             }
 
-                            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 = 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();
-                        }
-                    } // for (arg, param)
-
-                    for (_, indices) in seen_params {
-                        if indices.len() > 1 {
-                            let descr = generics.param_at(indices[0], tcx).kind.descr();
-                            let spans: Vec<_> = indices
-                                .into_iter()
-                                .map(|i| tcx.def_span(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();
+                            true
                         }
+
+                        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 = 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();
                     }
-                } // if may_define_opaque_type
-
-                // Now register the bounds on the parameters of the opaque type
-                // so the parameters given by the function need to fulfill them.
-                //
-                //     type Foo<T: Bar> = impl Baz + 'static;
-                //     fn foo<U>() -> Foo<U> { .. *}
-                //
-                // becomes
-                //
-                //     type Foo<T: Bar> = impl Baz + 'static;
-                //     fn foo<U: Bar>() -> Foo<U> { .. *}
-                let predicates = tcx.predicates_of(def_id);
-                trace!("check_opaque_types: may define, predicates={:#?}", predicates,);
-                for &(pred, _) in predicates.predicates {
-                    let substituted_pred = pred.subst(fcx.tcx, substs);
-                    // Avoid duplication of predicates that contain no parameters, for example.
-                    if !predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
-                        substituted_predicates.push(substituted_pred);
+                } // for (arg, param)
+
+                for (_, indices) in seen_params {
+                    if indices.len() > 1 {
+                        let descr = generics.param_at(indices[0], tcx).kind.descr();
+                        let spans: Vec<_> = indices
+                            .into_iter()
+                            .map(|i| tcx.def_span(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();
                     }
                 }
             } // if let Opaque
@@ -999,7 +991,6 @@ fn check_opaque_types<'fcx, 'tcx>(
         lt_op: |lt| lt,
         ct_op: |ct| ct,
     });
-    substituted_predicates
 }
 
 const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, \
diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs
index 0ef561fdbbb..549a20531e2 100644
--- a/src/librustc_typeck/collect/type_of.rs
+++ b/src/librustc_typeck/collect/type_of.rs
@@ -573,6 +573,16 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
     }
 }
 
+/// Retrieve the inferred concrete type for let position impl trait.
+///
+/// This is different to other kinds of impl trait because:
+///
+/// 1. We know which function contains the defining use (the function that
+///    contains the let statement)
+/// 2. We do not currently allow (free) lifetimes in the return type. `let`
+///    statements in some statically unreachable code are removed from the MIR
+///    by the time we borrow check, and it's not clear how we should handle
+///    those.
 fn let_position_impl_trait_type(tcx: TyCtxt<'_>, opaque_ty_id: LocalDefId) -> Ty<'_> {
     let scope = tcx.hir().get_defining_scope(tcx.hir().as_local_hir_id(opaque_ty_id));
     let scope_def_id = tcx.hir().local_def_id(scope);