From 63940322792240a936d60e7fee062275891bf920 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 8 Dec 2019 17:12:57 +0000 Subject: [PATCH] Correctly lower bounds on GATs --- src/librustc_typeck/collect.rs | 119 +++++++++++++++++++++++++++------ 1 file changed, 100 insertions(+), 19 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 27285632fdc6d..f25d2da13eea6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2300,25 +2300,7 @@ fn explicit_predicates_of( // Add predicates from associated type bounds. if let Some((self_trait_ref, trait_items)) = is_trait { predicates.extend(trait_items.iter().flat_map(|trait_item_ref| { - let trait_item = tcx.hir().trait_item(trait_item_ref.id); - let bounds = match trait_item.kind { - hir::TraitItemKind::Type(ref bounds, _) => bounds, - _ => return Vec::new().into_iter() - }; - - let assoc_ty = - tcx.mk_projection(tcx.hir().local_def_id(trait_item.hir_id), - self_trait_ref.substs); - - let bounds = AstConv::compute_bounds( - &ItemCtxt::new(tcx, def_id), - assoc_ty, - bounds, - SizedByDefault::Yes, - trait_item.span, - ); - - bounds.predicates(tcx, assoc_ty).into_iter() + associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref) })) } @@ -2352,6 +2334,105 @@ fn explicit_predicates_of( result } +fn associated_item_predicates( + tcx: TyCtxt<'tcx>, + def_id: DefId, + self_trait_ref: ty::TraitRef<'tcx>, + trait_item_ref: &hir::TraitItemRef, +) -> Vec<(ty::Predicate<'tcx>, Span)> { + let trait_item = tcx.hir().trait_item(trait_item_ref.id); + let item_def_id = tcx.hir().local_def_id(trait_item_ref.id.hir_id); + let bounds = match trait_item.kind { + hir::TraitItemKind::Type(ref bounds, _) => bounds, + _ => return Vec::new() + }; + + let is_gat = !tcx.generics_of(item_def_id).params.is_empty(); + + let mut had_error = false; + + let mut unimplemented_error = |arg_kind: &str| { + if !had_error { + tcx.sess.struct_span_err( + trait_item.span, + &format!("{}-generic associated types are not yet implemented", arg_kind), + ) + .note("for more information, see https://github.com/rust-lang/rust/issues/44265") + .emit(); + had_error = true; + } + }; + + let mk_bound_param = |param: &ty::GenericParamDef, _: &_| { + match param.kind { + ty::GenericParamDefKind::Lifetime => { + tcx.mk_region(ty::RegionKind::ReLateBound( + ty::INNERMOST, + ty::BoundRegion::BrNamed(param.def_id, param.name) + )).into() + } + // FIXME(generic_associated_types): Use bound types and constants + // once they are handled by the trait system. + ty::GenericParamDefKind::Type { .. } => { + unimplemented_error("type"); + tcx.types.err.into() + } + ty::GenericParamDefKind::Const => { + unimplemented_error("const"); + tcx.consts.err.into() + } + } + }; + + let bound_substs = if is_gat { + // Given: + // + // trait X<'a, B, const C: usize> { + // type T<'d, E, const F: usize>: Default; + // } + // + // We need to create predicates on the trait: + // + // for<'d, E, const F: usize> + // >::T<'d, E, const F: usize>: Sized + Default + // + // We substitute escaping bound parameters for the generic + // arguments to the associated type which are then bound by + // the `Binder` around the the predicate. + // + // FIXME(generic_associated_types): Currently only lifetimes are handled. + self_trait_ref.substs.extend_to(tcx, item_def_id, mk_bound_param) + } else { + self_trait_ref.substs + }; + + let assoc_ty = tcx.mk_projection( + tcx.hir().local_def_id(trait_item.hir_id), + bound_substs, + ); + + let bounds = AstConv::compute_bounds( + &ItemCtxt::new(tcx, def_id), + assoc_ty, + bounds, + SizedByDefault::Yes, + trait_item.span, + ); + + let predicates = bounds.predicates(tcx, assoc_ty); + + if is_gat { + // We use shifts to get the regions that we're substituting to + // be bound by the binders in the `Predicate`s rather that + // escaping. + let shifted_in = ty::fold::shift_vars(tcx, &predicates, 1); + let substituted = shifted_in.subst(tcx, bound_substs); + ty::fold::shift_out_vars(tcx, &substituted, 1) + } else { + predicates + } +} + /// Converts a specific `GenericBound` from the AST into a set of /// predicates that apply to the self type. A vector is returned /// because this can be anywhere from zero predicates (`T: ?Sized` adds no