-/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
-/// laid for "higher-order pattern unification".
-/// This ensures that inference is tractable.
-/// In particular, definitions of opaque types can only use other generics as arguments,
-/// and they cannot repeat an argument. Example:
-///
-/// ```rust
-/// type Foo<A, B> = impl Bar<A, B>;
-///
-/// // Okay -- `Foo` is applied to two distinct, generic types.
-/// fn a<T, U>() -> Foo<T, U> { .. }
-///
-/// // Not okay -- `Foo` is applied to `T` twice.
-/// fn b<T>() -> Foo<T, T> { .. }
-///
-/// // Not okay -- `Foo` is applied to a non-generic type.
-/// fn b<T>() -> Foo<T, u32> { .. }
-/// ```
-///
-fn check_opaque_types<'fcx, 'tcx>(
- fcx: &FnCtxt<'fcx, 'tcx>,
- fn_def_id: LocalDefId,
- span: Span,
- ty: Ty<'tcx>,
-) {
- trace!("check_opaque_types(fn_def_id={:?}, ty={:?})", fn_def_id, ty);
- let tcx = fcx.tcx;
-
- ty.fold_with(&mut ty::fold::BottomUpFolder {
- 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);
-
- let opaque_hir_id = if let Some(local_id) = def_id.as_local() {
- tcx.hir().local_def_id_to_hir_id(local_id)
- } else {
- // Opaque types from other crates won't have defining uses in this crate.
- return ty;
- };
- if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) =
- tcx.hir().expect_item(opaque_hir_id).kind
- {
- // 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;
- }
- 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;
- }
-
- GenericArgKind::Lifetime(_) => 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();
- }
- } // 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
- ty
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- });
-}
-