rustc_privacy: visit Ty instead of HIR types in EmbargoVisitor.
This commit is contained in:
parent
9aaf26e7aa
commit
36d33d6b71
8 changed files with 227 additions and 167 deletions
|
|
@ -298,7 +298,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
|||
// Nothing to recurse on for these
|
||||
ast_map::NodeForeignItem(_) |
|
||||
ast_map::NodeVariant(_) |
|
||||
ast_map::NodeStructCtor(_) => {}
|
||||
ast_map::NodeStructCtor(_) |
|
||||
ast_map::NodeTy(_) => {}
|
||||
_ => {
|
||||
bug!("found unexpected thingy in worklist: {}",
|
||||
self.tcx.map.node_to_string(search_item))
|
||||
|
|
|
|||
|
|
@ -191,6 +191,10 @@ pub trait TypeVisitor<'tcx> : Sized {
|
|||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
|
||||
trait_ref.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
|
||||
r.super_visit_with(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1280,8 +1280,13 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
|
|||
}
|
||||
Some(ast_map::NodeExpr(expr)) => {
|
||||
// This is a convenience to allow closures to work.
|
||||
if let hir::ExprClosure(..) = expr.node {
|
||||
ParameterEnvironment::for_item(tcx, tcx.map.get_parent(id))
|
||||
if let hir::ExprClosure(.., ref body, _) = expr.node {
|
||||
let def_id = tcx.map.local_def_id(id);
|
||||
let base_def_id = tcx.closure_base_def_id(def_id);
|
||||
tcx.construct_parameter_environment(
|
||||
expr.span,
|
||||
base_def_id,
|
||||
tcx.region_maps.call_site_extent(id, body.id))
|
||||
} else {
|
||||
tcx.empty_parameter_environment()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -599,6 +599,10 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
|
|||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.substs.visit_with(visitor)
|
||||
}
|
||||
|
||||
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
visitor.visit_trait_ref(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialTraitRef<'tcx> {
|
||||
|
|
@ -766,6 +770,36 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
ty::Generics {
|
||||
parent: self.parent,
|
||||
parent_regions: self.parent_regions,
|
||||
parent_types: self.parent_types,
|
||||
regions: self.regions.fold_with(folder),
|
||||
types: self.types.fold_with(folder),
|
||||
has_self: self.has_self,
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.regions.visit_with(visitor) || self.types.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
ty::GenericPredicates {
|
||||
parent: self.parent,
|
||||
predicates: self.predicates.fold_with(folder),
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.predicates.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
|||
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
|
||||
use rustc::lint;
|
||||
use rustc::middle::privacy::{AccessLevel, AccessLevels};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
|
||||
use rustc::ty::fold::TypeVisitor;
|
||||
use rustc::util::nodemap::NodeSet;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
|
|
@ -62,40 +63,32 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
|
|||
}
|
||||
|
||||
struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
|
||||
item_def_id: DefId,
|
||||
ev: &'b mut EmbargoVisitor<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
|
||||
fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
|
||||
if let hir::TyPath(ref qpath) = ty.node {
|
||||
let def = match *qpath {
|
||||
hir::QPath::Resolved(_, ref path) => path.def,
|
||||
hir::QPath::TypeRelative(..) => self.tcx.tables().type_relative_path_defs[&ty.id]
|
||||
};
|
||||
match def {
|
||||
Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
|
||||
Some(AccessLevel::Public)
|
||||
}
|
||||
def => {
|
||||
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
|
||||
self.get(node_id)
|
||||
} else {
|
||||
Some(AccessLevel::Public)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn item_ty_level(&self, item_def_id: DefId) -> Option<AccessLevel> {
|
||||
let ty_def_id = match self.tcx.item_type(item_def_id).sty {
|
||||
ty::TyAdt(adt, _) => adt.did,
|
||||
ty::TyTrait(ref obj) => obj.principal.def_id(),
|
||||
ty::TyProjection(ref proj) => proj.trait_ref.def_id,
|
||||
_ => return Some(AccessLevel::Public)
|
||||
};
|
||||
if let Some(node_id) = self.tcx.map.as_local_node_id(ty_def_id) {
|
||||
self.get(node_id)
|
||||
} else {
|
||||
Some(AccessLevel::Public)
|
||||
}
|
||||
}
|
||||
|
||||
fn trait_level(&self, trait_ref: &hir::TraitRef) -> Option<AccessLevel> {
|
||||
let did = trait_ref.path.def.def_id();
|
||||
if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
|
||||
self.get(node_id)
|
||||
} else {
|
||||
Some(AccessLevel::Public)
|
||||
fn impl_trait_level(&self, impl_def_id: DefId) -> Option<AccessLevel> {
|
||||
if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) {
|
||||
if let Some(node_id) = self.tcx.map.as_local_node_id(trait_ref.def_id) {
|
||||
return self.get(node_id);
|
||||
}
|
||||
}
|
||||
Some(AccessLevel::Public)
|
||||
}
|
||||
|
||||
fn get(&self, id: ast::NodeId) -> Option<AccessLevel> {
|
||||
|
|
@ -115,8 +108,12 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn reach<'b>(&'b mut self) -> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
|
||||
ReachEverythingInTheInterfaceVisitor { ev: self }
|
||||
fn reach<'b>(&'b mut self, item_id: ast::NodeId)
|
||||
-> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
|
||||
ReachEverythingInTheInterfaceVisitor {
|
||||
item_def_id: self.tcx.map.local_def_id(item_id),
|
||||
ev: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -130,14 +127,13 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
|
|||
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
||||
let inherited_item_level = match item.node {
|
||||
// Impls inherit level from their types and traits
|
||||
hir::ItemImpl(.., None, ref ty, _) => {
|
||||
self.ty_level(&ty)
|
||||
hir::ItemImpl(..) => {
|
||||
let def_id = self.tcx.map.local_def_id(item.id);
|
||||
cmp::min(self.item_ty_level(def_id), self.impl_trait_level(def_id))
|
||||
}
|
||||
hir::ItemImpl(.., Some(ref trait_ref), ref ty, _) => {
|
||||
cmp::min(self.ty_level(&ty), self.trait_level(trait_ref))
|
||||
}
|
||||
hir::ItemDefaultImpl(_, ref trait_ref) => {
|
||||
self.trait_level(trait_ref)
|
||||
hir::ItemDefaultImpl(..) => {
|
||||
let def_id = self.tcx.map.local_def_id(item.id);
|
||||
self.impl_trait_level(def_id)
|
||||
}
|
||||
// Foreign mods inherit level from parents
|
||||
hir::ItemForeignMod(..) => {
|
||||
|
|
@ -209,22 +205,54 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
|
|||
hir::ItemMod(..) => {}
|
||||
// Reexports are handled in visit_mod
|
||||
hir::ItemUse(..) => {}
|
||||
// The interface is empty
|
||||
hir::ItemDefaultImpl(..) => {}
|
||||
// Visit everything
|
||||
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
|
||||
hir::ItemTrait(..) | hir::ItemTy(..) | hir::ItemImpl(.., Some(..), _, _) => {
|
||||
hir::ItemConst(..) | hir::ItemStatic(..) |
|
||||
hir::ItemFn(..) | hir::ItemTy(..) => {
|
||||
if item_level.is_some() {
|
||||
self.reach().visit_item(item);
|
||||
self.reach(item.id).generics().predicates().item_type();
|
||||
}
|
||||
}
|
||||
// Visit everything, but enum variants have their own levels
|
||||
hir::ItemEnum(ref def, ref generics) => {
|
||||
hir::ItemTrait(.., ref trait_items) => {
|
||||
if item_level.is_some() {
|
||||
self.reach().visit_generics(generics);
|
||||
self.reach(item.id).generics().predicates();
|
||||
|
||||
for trait_item in trait_items {
|
||||
let mut reach = self.reach(trait_item.id);
|
||||
reach.generics().predicates();
|
||||
|
||||
if let hir::TypeTraitItem(_, None) = trait_item.node {
|
||||
// No type to visit.
|
||||
} else {
|
||||
reach.item_type();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Visit everything except for private impl items
|
||||
hir::ItemImpl(.., ref trait_ref, _, ref impl_items) => {
|
||||
if item_level.is_some() {
|
||||
self.reach(item.id).generics().predicates().impl_trait_ref();
|
||||
|
||||
for impl_item in impl_items {
|
||||
let id = impl_item.id.node_id;
|
||||
if trait_ref.is_some() || self.get(id).is_some() {
|
||||
self.reach(id).generics().predicates().item_type();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Visit everything, but enum variants have their own levels
|
||||
hir::ItemEnum(ref def, _) => {
|
||||
if item_level.is_some() {
|
||||
self.reach(item.id).generics().predicates();
|
||||
}
|
||||
for variant in &def.variants {
|
||||
if self.get(variant.node.data.id()).is_some() {
|
||||
for field in variant.node.data.fields() {
|
||||
self.reach().visit_struct_field(field);
|
||||
self.reach(field.id).item_type();
|
||||
}
|
||||
// Corner case: if the variant is reachable, but its
|
||||
// enum is not, make the enum reachable as well.
|
||||
|
|
@ -236,32 +264,18 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
|
|||
hir::ItemForeignMod(ref foreign_mod) => {
|
||||
for foreign_item in &foreign_mod.items {
|
||||
if self.get(foreign_item.id).is_some() {
|
||||
self.reach().visit_foreign_item(foreign_item);
|
||||
self.reach(foreign_item.id).generics().predicates().item_type();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Visit everything except for private fields
|
||||
hir::ItemStruct(ref struct_def, ref generics) |
|
||||
hir::ItemUnion(ref struct_def, ref generics) => {
|
||||
hir::ItemStruct(ref struct_def, _) |
|
||||
hir::ItemUnion(ref struct_def, _) => {
|
||||
if item_level.is_some() {
|
||||
self.reach().visit_generics(generics);
|
||||
self.reach(item.id).generics().predicates();
|
||||
for field in struct_def.fields() {
|
||||
if self.get(field.id).is_some() {
|
||||
self.reach().visit_struct_field(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The interface is empty
|
||||
hir::ItemDefaultImpl(..) => {}
|
||||
// Visit everything except for private impl items
|
||||
hir::ItemImpl(.., ref generics, None, _, ref impl_item_refs) => {
|
||||
if item_level.is_some() {
|
||||
self.reach().visit_generics(generics);
|
||||
for impl_item_ref in impl_item_refs {
|
||||
if self.get(impl_item_ref.id.node_id).is_some() {
|
||||
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
|
||||
self.reach().visit_impl_item(impl_item);
|
||||
self.reach(field.id).item_type();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -306,87 +320,69 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
|
|||
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
|
||||
self.update(md.id, Some(AccessLevel::Public));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
|
||||
// Make the type hidden under a type alias reachable
|
||||
fn reach_aliased_type(&mut self, item: &'tcx hir::Item, segment: &'tcx hir::PathSegment) {
|
||||
if let hir::ItemTy(ref ty, ref generics) = item.node {
|
||||
// See `fn is_public_type_alias` for details
|
||||
self.visit_ty(ty);
|
||||
let provided_params = segment.parameters.types().len();
|
||||
for ty_param in &generics.ty_params[provided_params..] {
|
||||
if let Some(ref default_ty) = ty_param.default {
|
||||
self.visit_ty(default_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
|
||||
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
|
||||
// when we visit an impl, its methods and items are part of its "interface"
|
||||
let impl_item = self.ev.tcx.map.impl_item(item_id);
|
||||
self.visit_impl_item(impl_item)
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
|
||||
let def_and_segment = match ty.node {
|
||||
hir::TyPath(hir::QPath::Resolved(_, ref path)) => {
|
||||
Some((path.def, path.segments.last().unwrap()))
|
||||
}
|
||||
hir::TyPath(hir::QPath::TypeRelative(_, ref segment)) => {
|
||||
Some((self.ev.tcx.tables().type_relative_path_defs[&ty.id], &**segment))
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
if let Some((def, segment)) = def_and_segment {
|
||||
match def {
|
||||
Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) |
|
||||
Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id) => {
|
||||
if let Some(mut node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
|
||||
// Check the trait for associated types.
|
||||
if let hir::map::NodeTraitItem(_) = self.ev.tcx.map.get(node_id) {
|
||||
node_id = self.ev.tcx.map.get_parent(node_id);
|
||||
}
|
||||
|
||||
let item = self.ev.tcx.map.expect_item(node_id);
|
||||
if let Def::TyAlias(..) = def {
|
||||
// Type aliases are substituted. Associated type aliases are not
|
||||
// substituted yet, but ideally they should be.
|
||||
if self.ev.get(item.id).is_none() {
|
||||
self.reach_aliased_type(item, segment);
|
||||
}
|
||||
} else {
|
||||
self.ev.update(item.id, Some(AccessLevel::Reachable));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
if let hir::TyImplTrait(..) = ty.node {
|
||||
if self.get(ty.id).is_some() {
|
||||
// Reach the (potentially private) type and the API being exposed.
|
||||
self.reach(ty.id).item_type().predicates();
|
||||
}
|
||||
}
|
||||
|
||||
intravisit::walk_ty(self, ty);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
|
||||
let def_id = trait_ref.path.def.def_id();
|
||||
if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
|
||||
impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
|
||||
fn generics(&mut self) -> &mut Self {
|
||||
self.ev.tcx.item_generics(self.item_def_id).visit_with(self);
|
||||
self
|
||||
}
|
||||
|
||||
fn predicates(&mut self) -> &mut Self {
|
||||
self.ev.tcx.item_predicates(self.item_def_id).visit_with(self);
|
||||
self
|
||||
}
|
||||
|
||||
fn item_type(&mut self) -> &mut Self {
|
||||
self.ev.tcx.item_type(self.item_def_id).visit_with(self);
|
||||
self
|
||||
}
|
||||
|
||||
fn impl_trait_ref(&mut self) -> &mut Self {
|
||||
self.ev.tcx.impl_trait_ref(self.item_def_id).visit_with(self);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||
let ty_def_id = match ty.sty {
|
||||
ty::TyAdt(adt, _) => Some(adt.did),
|
||||
ty::TyTrait(ref obj) => Some(obj.principal.def_id()),
|
||||
ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
|
||||
ty::TyFnDef(def_id, ..) |
|
||||
ty::TyAnon(def_id, _) => Some(def_id),
|
||||
_ => None
|
||||
};
|
||||
|
||||
if let Some(def_id) = ty_def_id {
|
||||
if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
|
||||
self.ev.update(node_id, Some(AccessLevel::Reachable));
|
||||
}
|
||||
}
|
||||
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
|
||||
if let Some(node_id) = self.ev.tcx.map.as_local_node_id(trait_ref.def_id) {
|
||||
let item = self.ev.tcx.map.expect_item(node_id);
|
||||
self.ev.update(item.id, Some(AccessLevel::Reachable));
|
||||
}
|
||||
|
||||
intravisit::walk_trait_ref(self, trait_ref);
|
||||
trait_ref.super_visit_with(self)
|
||||
}
|
||||
|
||||
// Don't recurse into function bodies
|
||||
fn visit_block(&mut self, _: &hir::Block) {}
|
||||
// Don't recurse into expressions in array sizes or const initializers
|
||||
fn visit_expr(&mut self, _: &hir::Expr) {}
|
||||
// Don't recurse into patterns in function arguments
|
||||
fn visit_pat(&mut self, _: &hir::Pat) {}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -136,7 +136,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
|
|||
|
||||
fn visit_expr(&mut self, expr: &hir::Expr) {
|
||||
if let hir::ExprClosure(..) = expr.node {
|
||||
convert_closure(self.ccx, expr.id);
|
||||
let def_id = self.ccx.tcx.map.local_def_id(expr.id);
|
||||
generics_of_def_id(self.ccx, def_id);
|
||||
type_of_def_id(self.ccx, def_id);
|
||||
}
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
|
@ -570,40 +572,6 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
ccx.tcx.predicates.borrow_mut().insert(def_id, struct_predicates.clone());
|
||||
}
|
||||
|
||||
fn convert_closure<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
node_id: ast::NodeId)
|
||||
{
|
||||
let tcx = ccx.tcx;
|
||||
let def_id = tcx.map.local_def_id(node_id);
|
||||
let base_def_id = tcx.closure_base_def_id(def_id);
|
||||
let base_generics = generics_of_def_id(ccx, base_def_id);
|
||||
|
||||
// provide junk type parameter defs - the only place that
|
||||
// cares about anything but the length is instantiation,
|
||||
// and we don't do that for closures.
|
||||
let upvar_decls : Vec<_> = tcx.with_freevars(node_id, |fv| {
|
||||
fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
|
||||
index: (base_generics.count() as u32) + (i as u32),
|
||||
name: Symbol::intern("<upvar>"),
|
||||
def_id: def_id,
|
||||
default_def_id: base_def_id,
|
||||
default: None,
|
||||
object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
|
||||
pure_wrt_drop: false,
|
||||
}).collect()
|
||||
});
|
||||
tcx.generics.borrow_mut().insert(def_id, tcx.alloc_generics(ty::Generics {
|
||||
parent: Some(base_def_id),
|
||||
parent_regions: base_generics.parent_regions + (base_generics.regions.len() as u32),
|
||||
parent_types: base_generics.parent_types + (base_generics.types.len() as u32),
|
||||
regions: vec![],
|
||||
types: upvar_decls,
|
||||
has_self: base_generics.has_self,
|
||||
}));
|
||||
|
||||
type_of_def_id(ccx, def_id);
|
||||
}
|
||||
|
||||
fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
container: AssociatedItemContainer,
|
||||
id: ast::NodeId,
|
||||
|
|
@ -1320,6 +1288,9 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
let parent_id = tcx.map.get_parent(node_id);
|
||||
Some(tcx.map.local_def_id(parent_id))
|
||||
}
|
||||
NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
|
||||
Some(tcx.closure_base_def_id(def_id))
|
||||
}
|
||||
NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
|
||||
let mut parent_id = node_id;
|
||||
loop {
|
||||
|
|
@ -1437,7 +1408,24 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
let i = type_start + i as u32;
|
||||
get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults)
|
||||
});
|
||||
let types: Vec<_> = opt_self.into_iter().chain(types).collect();
|
||||
let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
|
||||
|
||||
// provide junk type parameter defs - the only place that
|
||||
// cares about anything but the length is instantiation,
|
||||
// and we don't do that for closures.
|
||||
if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node {
|
||||
tcx.with_freevars(node_id, |fv| {
|
||||
types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
|
||||
index: type_start + i as u32,
|
||||
name: Symbol::intern("<upvar>"),
|
||||
def_id: def_id,
|
||||
default_def_id: parent_def_id.unwrap(),
|
||||
default: None,
|
||||
object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
|
||||
pure_wrt_drop: false,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
// Debugging aid.
|
||||
if tcx.has_attr(def_id, "rustc_object_lifetime_default") {
|
||||
|
|
|
|||
15
src/test/run-pass/impl-trait/auxiliary/xcrate.rs
Normal file
15
src/test/run-pass/impl-trait/auxiliary/xcrate.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(conservative_impl_trait)]
|
||||
|
||||
pub fn fourway_add(a: i32) -> impl Fn(i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 {
|
||||
move |b| move |c| move |d| a + b + c + d
|
||||
}
|
||||
17
src/test/run-pass/impl-trait/xcrate.rs
Normal file
17
src/test/run-pass/impl-trait/xcrate.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:xcrate.rs
|
||||
|
||||
extern crate xcrate;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(xcrate::fourway_add(1)(2)(3)(4), 10);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue