// Return the visibility of the type alias's least visible component type when substituted
fn substituted_alias_visibility(&self, item: &hir::Item, path: &hir::Path)
-> Option<ty::Visibility> {
- // We substitute type aliases only when determining impl publicity
- // FIXME: This will probably change and all type aliases will be substituted,
- // requires an amendment to RFC 136.
- if self.required_visibility != ty::Visibility::PrivateExternal {
- return None;
- }
// Type alias is considered public if the aliased type is
// public, even if the type alias itself is private. So, something
// like `type A = u8; pub fn f() -> A {...}` doesn't cause an error.
if let hir::ItemTy(ref ty, ref generics) = item.node {
- let mut check = SearchInterfaceForPrivateItemsVisitor {
- min_visibility: ty::Visibility::Public, ..*self
- };
+ let mut check = SearchInterfaceForPrivateItemsVisitor::new(self.tcx,
+ self.old_error_set);
check.visit_ty(ty);
// If a private type alias with default type parameters is used in public
// interface we must ensure, that the defaults are public if they are actually used.
use rustc_trans::back::link;
use rustc::middle::cstore;
use rustc::middle::privacy::AccessLevels;
+use rustc::middle::resolve_lifetime::DefRegion::*;
use rustc::hir::def::Def;
use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc::hir::fold::Folder;
use rustc::hir::print as pprust;
use rustc::ty::subst::{self, ParamSpace, VecPerParamSpace};
use rustc::ty;
}
}
+
+// Poor man's type parameter substitution at HIR level.
+// Used to replace private type aliases in public signatures with their aliased types.
+struct SubstAlias<'a, 'tcx: 'a> {
+ tcx: &'a ty::TyCtxt<'a, 'tcx, 'tcx>,
+ // Table type parameter definition -> substituted type
+ ty_substs: HashMap<Def, hir::Ty>,
+ // Table node id of lifetime parameter definition -> substituted lifetime
+ lt_substs: HashMap<ast::NodeId, hir::Lifetime>,
+}
+
+impl<'a, 'tcx: 'a, 'b: 'tcx> Folder for SubstAlias<'a, 'tcx> {
+ fn fold_ty(&mut self, ty: P<hir::Ty>) -> P<hir::Ty> {
+ if let hir::TyPath(..) = ty.node {
+ let def = self.tcx.expect_def(ty.id);
+ if let Some(new_ty) = self.ty_substs.get(&def).cloned() {
+ return P(new_ty);
+ }
+ }
+ hir::fold::noop_fold_ty(ty, self)
+ }
+ fn fold_lifetime(&mut self, lt: hir::Lifetime) -> hir::Lifetime {
+ let def = self.tcx.named_region_map.defs.get(<.id).cloned();
+ match def {
+ Some(DefEarlyBoundRegion(_, _, node_id)) |
+ Some(DefLateBoundRegion(_, node_id)) |
+ Some(DefFreeRegion(_, node_id)) => {
+ if let Some(lt) = self.lt_substs.get(&node_id).cloned() {
+ return lt;
+ }
+ }
+ _ => {}
+ }
+ hir::fold::noop_fold_lifetime(lt, self)
+ }
+}
+
impl Clean<Type> for hir::Ty {
fn clean(&self, cx: &DocContext) -> Type {
use rustc::hir::*;
FixedVector(box ty.clean(cx), n)
},
TyTup(ref tys) => Tuple(tys.clean(cx)),
- TyPath(None, ref p) => {
- resolve_type(cx, p.clean(cx), self.id)
+ TyPath(None, ref path) => {
+ if let Some(tcx) = cx.tcx_opt() {
+ // Substitute private type aliases
+ let def = tcx.expect_def(self.id);
+ if let Def::TyAlias(def_id) = def {
+ if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+ if !cx.access_levels.borrow().is_exported(def_id) {
+ let item = tcx.map.expect_item(node_id);
+ if let hir::ItemTy(ref ty, ref generics) = item.node {
+ let provided_params = &path.segments.last().unwrap().parameters;
+ let mut ty_substs = HashMap::new();
+ let mut lt_substs = HashMap::new();
+ for (i, ty_param) in generics.ty_params.iter().enumerate() {
+ let ty_param_def = tcx.expect_def(ty_param.id);
+ if let Some(ty) = provided_params.types().get(i).cloned()
+ .cloned() {
+ ty_substs.insert(ty_param_def, ty.unwrap());
+ } else if let Some(default) = ty_param.default.clone() {
+ ty_substs.insert(ty_param_def, default.unwrap());
+ }
+ }
+ for (i, lt_param) in generics.lifetimes.iter().enumerate() {
+ if let Some(lt) = provided_params.lifetimes().get(i)
+ .cloned()
+ .cloned() {
+ lt_substs.insert(lt_param.lifetime.id, lt);
+ }
+ }
+ let mut subst_alias = SubstAlias {
+ tcx: &tcx,
+ ty_substs: ty_substs,
+ lt_substs: lt_substs
+ };
+ return subst_alias.fold_ty(ty.clone()).clean(cx);
+ }
+ }
+ }
+ }
+ }
+ resolve_type(cx, path.clean(cx), self.id)
}
TyPath(Some(ref qself), ref p) => {
let mut segments: Vec<_> = p.segments.clone().into();
--- /dev/null
+// 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.
+
+type MyResultPriv<T> = Result<T, u16>;
+pub type MyResultPub<T> = Result<T, u64>;
+
+// @has private_type_alias/fn.get_result_priv.html '//pre' 'Result<u8, u16>'
+pub fn get_result_priv() -> MyResultPriv<u8> {
+ panic!();
+}
+
+// @has private_type_alias/fn.get_result_pub.html '//pre' 'MyResultPub<u32>'
+pub fn get_result_pub() -> MyResultPub<u32> {
+ panic!();
+}
+
+pub type PubRecursive = u16;
+type PrivRecursive3 = u8;
+type PrivRecursive2 = PubRecursive;
+type PrivRecursive1 = PrivRecursive3;
+
+// PrivRecursive1 is expanded twice and stops at u8
+// PrivRecursive2 is expanded once and stops at public type alias PubRecursive
+// @has private_type_alias/fn.get_result_recursive.html '//pre' '(u8, PubRecursive)'
+pub fn get_result_recursive() -> (PrivRecursive1, PrivRecursive2) {
+ panic!();
+}
+
+type MyLifetimePriv<'a> = &'a isize;
+
+// @has private_type_alias/fn.get_lifetime_priv.html '//pre' "&'static isize"
+pub fn get_lifetime_priv() -> MyLifetimePriv<'static> {
+ panic!();
+}