diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 69bdb68945d7..909855c1669f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -43,6 +43,7 @@ use rustc_const_math::ConstInt; use std::collections::BTreeMap; use syntax::{abi, ast}; +use syntax::ptr::P; use syntax::codemap::Spanned; use syntax::symbol::{Symbol, keywords}; use syntax_pos::{Span, DUMMY_SP}; @@ -873,22 +874,32 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut allow_defaults = false; let no_generics = hir::Generics::empty(); - let ast_generics = match node { - NodeTraitItem(item) => &item.generics, + let (ast_generics, opt_inputs) = match node { + NodeTraitItem(item) => { + match item.node { + TraitItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)), + _ => (&item.generics, None) + } + } - NodeImplItem(item) => &item.generics, + NodeImplItem(item) => { + match item.node { + ImplItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)), + _ => (&item.generics, None) + } + } NodeItem(item) => { match item.node { - ItemFn(.., ref generics, _) | - ItemImpl(_, _, _, ref generics, ..) => generics, + ItemFn(ref decl, .., ref generics, _) => (generics, Some(&decl.inputs)), + ItemImpl(_, _, _, ref generics, ..) => (generics, None), ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | ItemUnion(_, ref generics) => { allow_defaults = true; - generics + (generics, None) } ItemTrait(_, _, ref generics, ..) => { @@ -909,22 +920,22 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); allow_defaults = true; - generics + (generics, None) } - _ => &no_generics + _ => (&no_generics, None) } } NodeForeignItem(item) => { match item.node { - ForeignItemStatic(..) => &no_generics, - ForeignItemFn(_, _, ref generics) => generics, - ForeignItemType => &no_generics, + ForeignItemStatic(..) => (&no_generics, None), + ForeignItemFn(ref decl, _, ref generics) => (generics, Some(&decl.inputs)), + ForeignItemType => (&no_generics, None) } } - _ => &no_generics + _ => (&no_generics, None) }; let has_self = opt_self.is_some(); @@ -981,7 +992,24 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, synthetic: p.synthetic, } }); - let mut types: Vec<_> = opt_self.into_iter().chain(types).collect(); + + let fn_ins = opt_inputs.map(|tys| &tys[..]); + let univ_impl_trait_info = extract_universal_impl_trait_info(tcx, fn_ins); + let other_type_start = type_start + ast_generics.ty_params.len() as u32; + let mut types: Vec<_> = opt_self.into_iter() + .chain(types) + .chain(univ_impl_trait_info.iter().enumerate().map(|(i, info)| { + ty::TypeParameterDef { + index: other_type_start + i as u32, + name: keywords::Invalid.name() /* FIXME(chrisvittal) maybe make not Invalid */, + def_id: info.def_id, + has_default: false, + object_lifetime_default: rl::Set1::Empty, + pure_wrt_drop: false, + synthetic: Some(SyntheticTyParamKind::ImplTrait), + } + })) + .collect(); // provide junk type parameter defs - the only place that // cares about anything but the length is instantiation, @@ -1337,20 +1365,31 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); - let ast_generics = match node { - NodeTraitItem(item) => &item.generics, + let (ast_generics, opt_inputs) = match node { + NodeTraitItem(item) => { + match item.node { + TraitItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)), + _ => (&item.generics, None) + } + } - NodeImplItem(item) => &item.generics, + NodeImplItem(item) => { + match item.node { + ImplItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)), + _ => (&item.generics, None) + } + } NodeItem(item) => { match item.node { - ItemFn(.., ref generics, _) | + ItemFn(ref decl, .., ref generics, _) => (generics, Some(&decl.inputs)), + ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | ItemUnion(_, ref generics) => { - generics + (generics, None) } ItemTrait(_, _, ref generics, .., ref items) => { @@ -1358,18 +1397,18 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id, substs: Substs::identity_for_item(tcx, def_id) }, items)); - generics + (generics, None) } - _ => &no_generics + _ => (&no_generics, None) } } NodeForeignItem(item) => { match item.node { - ForeignItemStatic(..) => &no_generics, - ForeignItemFn(_, _, ref generics) => generics, - ForeignItemType => &no_generics, + ForeignItemStatic(..) => (&no_generics, None), + ForeignItemFn(ref decl, _, ref generics) => (generics, Some(&decl.inputs)), + ForeignItemType => (&no_generics, None), } } @@ -1387,7 +1426,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; } - _ => &no_generics + _ => (&no_generics, None) }; let generics = tcx.generics_of(def_id); @@ -1518,6 +1557,19 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, })) } + // Add predicates from impl Trait arguments + let fn_ins = opt_inputs.map(|tys| &tys[..]); + let univ_impl_trait_info = extract_universal_impl_trait_info(tcx, fn_ins); + for info in univ_impl_trait_info.iter() { + let name = keywords::Invalid.name(); + let param_ty = ty::ParamTy::new(index, name).to_ty(tcx); + index += 1; + let bounds = compute_bounds(&icx, param_ty, info.bounds, + SizedByDefault::Yes, + info.span); + predicates.extend(bounds.predicates(tcx, param_ty)); + } + // Subtle: before we store the predicates into the tcx, we // sort them so that predicates like `T: Foo` come // before uses of `U`. This avoids false ambiguity errors @@ -1678,3 +1730,48 @@ fn is_auto_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => bug!("is_auto_impl applied to non-local def-id {:?}", def_id) } } + +struct ImplTraitUniversalInfo<'hir> { + def_id: DefId, + span: Span, + bounds: &'hir [hir::TyParamBound], +} + +/// Take some possible list of arguments and return the DefIds of the ImplTraitUniversal +/// arguments +fn extract_universal_impl_trait_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + opt_inputs: Option<&'tcx [P]>) + -> Vec> +{ + // A visitor for simply collecting Universally quantified impl Trait arguments + struct ImplTraitUniversalVisitor<'tcx> { + items: Vec<&'tcx hir::Ty> + } + + impl<'tcx> Visitor<'tcx> for ImplTraitUniversalVisitor<'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &'tcx hir::Ty) { + if let hir::TyImplTraitUniversal(..) = ty.node { + self.items.push(ty); + } + intravisit::walk_ty(self, ty); + } + } + + let mut visitor = ImplTraitUniversalVisitor { items: Vec::new() }; + opt_inputs.map(|inputs| for t in inputs.iter() { + visitor.visit_ty(t); + }); + visitor.items.into_iter().map(|ty| if let hir::TyImplTraitUniversal(_, ref bounds) = ty.node { + ImplTraitUniversalInfo { + def_id: tcx.hir.local_def_id(ty.id), + span: ty.span, + bounds: bounds + } + } else { + span_bug!(ty.span, "this type should be a universally quantified impl trait. this is a bug") + }).collect() +}