Substitute type aliases before checking for privacy

This commit is contained in:
Vadim Petrochenkov 2015-11-27 01:48:26 +03:00
parent a745614f44
commit fcbd553f0f
5 changed files with 43 additions and 24 deletions

View file

@ -1460,13 +1460,38 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
old_error_set: &'a NodeSet,
}
impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
// Check if the type alias contain private types when substituted
fn is_public_type_alias(&self, item: &hir::Item, path: &hir::Path) -> bool {
// 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 {
tcx: self.tcx, is_quiet: self.is_quiet,
is_public: true, old_error_set: self.old_error_set,
};
check.visit_ty(ty);
let provided_params = path.segments.last().unwrap().parameters.types().len();
for ty_param in &generics.ty_params[provided_params..] {
if let Some(ref default_ty) = ty_param.default {
check.visit_ty(default_ty);
}
}
check.is_public
} else {
false
}
}
}
impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
fn visit_ty(&mut self, ty: &hir::Ty) {
if self.is_quiet && !self.is_public {
// We are in quiet mode and a private type is already found, no need to proceed
return
}
if let hir::TyPath(..) = ty.node {
if let hir::TyPath(_, ref path) = ty.node {
let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
match def {
def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {
@ -1482,12 +1507,7 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a,
// Non-local means public, local needs to be checked
if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
if let Some(ast_map::NodeItem(ref item)) = self.tcx.map.find(node_id) {
if let (&hir::ItemTy(..), true) = (&item.node, self.is_quiet) {
// Conservatively approximate the whole type alias as public without
// recursing into its components when determining impl publicity.
return
}
if item.vis != hir::Public {
if item.vis != hir::Public && !self.is_public_type_alias(item, path) {
if !self.is_quiet {
if self.old_error_set.contains(&ty.id) {
span_err!(self.tcx.sess, ty.span, E0446,

View file

@ -14,7 +14,7 @@ use std::os::windows::prelude::*;
use std::ptr;
use libc::{c_void, c_long};
pub type DWORD = u32;
type DWORD = u32;
type LPCWSTR = *const u16;
type LONG = c_long;
type LPDWORD = *mut DWORD;

View file

@ -1,16 +0,0 @@
// Copyright 2015 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.
// Checks for private types in public interfaces
type Foo = u8;
pub fn foo(f: Foo) {} //~ ERROR private type in public interface
fn main() {}

View file

@ -37,5 +37,11 @@ impl PubTrait for <Private<isize> as PrivTrait2>::Alias {
type Output = Private<isize>; //~ WARN private type in public interface
}
type PrivAliasPubType = u8;
pub fn f1(_: PrivAliasPubType) {} // Ok, not an error
type PrivAliasGeneric<T = Private<isize>> = T;
pub fn f2(_: PrivAliasGeneric<u8>) {} // Ok, not an error
#[rustc_error]
fn main() {} //~ ERROR compilation successful

View file

@ -121,3 +121,12 @@ impl<T: ParamTrait<Private<isize>>> //~ ERROR private type in public interface
ParamTrait<T> for Public<i8> {
fn foo() -> T { panic!() }
}
type PrivAliasPrivType = Private<isize>;
pub fn f1(_: PrivAliasPrivType) {} //~ ERROR private type in public interface
type PrivAliasGeneric<T = Private<isize>> = T;
pub fn f2(_: PrivAliasGeneric) {} //~ ERROR private type in public interface
type Result<T> = std::result::Result<T, Private<isize>>;
pub fn f3(_: Result<u8>) {} //~ ERROR private type in public interface