diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 512a49d13e7cf..c0b49bb591838 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -114,7 +114,7 @@ use rustc::ty::{ use rustc::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast }; -use rustc::ty::fold::TypeFoldable; +use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::query::Providers; use rustc::ty::subst::{ GenericArgKind, Subst, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts, @@ -872,6 +872,58 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: DefId) -> &DefIdSet { &*tcx.typeck_tables_of(def_id).used_trait_imports } +/// Inspects the substs of opaque types, replacing any inference variables +/// with proper generic parameter from the identity substs. +/// +/// This is run after we normalize the function signature, to fix any inference +/// variables introduced by the projection of associated types. This ensures that +/// any opaque types used in the signature continue to refer to generic parameters, +/// allowing them to be considered for defining uses in the function body +fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: &T) -> T where T: TypeFoldable<'tcx> { + struct FixupFolder<'tcx> { + tcx: TyCtxt<'tcx> + } + + impl<'tcx> TypeFolder<'tcx> for FixupFolder<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.kind { + ty::Opaque(def_id, substs) => { + debug!("fixup_opaque_types: found type {:?}", ty); + if ty.has_infer_types() { + let new_substs = InternalSubsts::for_item(self.tcx, def_id, |param, _| { + let old_param = substs[param.index as usize]; + match old_param.unpack() { + GenericArgKind::Type(old_ty) => { + if let ty::Infer(_) = old_ty.kind { + // Replace inference type with a generic parameter + self.tcx.mk_param_from_def(param) + } else { + old_param.fold_with(self) + } + }, + _ => old_param + } + }); + let new_ty = self.tcx.mk_opaque(def_id, new_substs); + debug!("fixup_opaque_types: new type: {:?}", new_ty); + new_ty + } else { + ty + } + }, + _ => ty.super_fold_with(self) + } + } + } + + debug!("fixup_opaque_types({:?})", val); + val.fold_with(&mut FixupFolder { tcx }) +} + fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> { // Closures' tables come from their outermost function, // as they are part of the same "inference environment". @@ -911,6 +963,8 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> { param_env, &fn_sig); + let fn_sig = fixup_opaque_types(tcx, &fn_sig); + let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0; fcx } else { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8dced83b987ea..7732ac4a1c85e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2059,6 +2059,9 @@ fn explicit_predicates_of( ty::print::with_no_queries(|| { let substs = InternalSubsts::identity_for_item(tcx, def_id); let opaque_ty = tcx.mk_opaque(def_id, substs); + debug!("explicit_predicates_of({:?}): created opaque type {:?}", + def_id, opaque_ty); + // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`. let bounds = AstConv::compute_bounds( diff --git a/src/test/ui/impl-trait/type-alias-generic-param.rs b/src/test/ui/impl-trait/type-alias-generic-param.rs new file mode 100644 index 0000000000000..d834d9bb112f5 --- /dev/null +++ b/src/test/ui/impl-trait/type-alias-generic-param.rs @@ -0,0 +1,22 @@ +// Regression test for issue #59342 +// Checks that we properly detect defining uses of opaque +// types in 'item' position when generic parameters are involved +// +// run-pass +#![feature(type_alias_impl_trait)] + +trait Meow { + type MeowType; + fn meow(self) -> Self::MeowType; +} + +impl Meow for I + where I: Iterator +{ + type MeowType = impl Iterator; + fn meow(self) -> Self::MeowType { + self + } +} + +fn main() {}