Skip to content

Commit

Permalink
Rollup merge of rust-lang#57649 - petrochenkov:privexist, r=arielb1
Browse files Browse the repository at this point in the history
privacy: Account for associated existential types

Turns out they *can* be associated (but only in impls, not traits).
Fixes rust-lang#53546 (comment)

r? @arielb1
  • Loading branch information
Centril authored Jan 18, 2019
2 parents 67386f0 + d34b3e9 commit e8f2aec
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 23 deletions.
43 changes: 26 additions & 17 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ extern crate rustc_typeck;
extern crate syntax_pos;
extern crate rustc_data_structures;

use rustc::hir::{self, Node, PatKind};
use rustc::hir::{self, Node, PatKind, AssociatedItemKind};
use rustc::hir::def::Def;
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
Expand Down Expand Up @@ -548,7 +548,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
let mut reach = self.reach(trait_item_ref.id.node_id, item_level);
reach.generics().predicates();

if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
if trait_item_ref.kind == AssociatedItemKind::Type &&
!trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
Expand Down Expand Up @@ -1333,11 +1333,11 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item_ref.kind {
hir::AssociatedItemKind::Const => {
AssociatedItemKind::Const => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
hir::AssociatedItemKind::Method { has_self: false } => {
AssociatedItemKind::Method { has_self: false } => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
Expand Down Expand Up @@ -1558,6 +1558,24 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
in_assoc_ty: false,
}
}

fn check_trait_or_impl_item(&self, node_id: ast::NodeId, assoc_item_kind: AssociatedItemKind,
defaultness: hir::Defaultness, vis: ty::Visibility) {
let mut check = self.check(node_id, vis);

let (check_ty, is_assoc_ty) = match assoc_item_kind {
AssociatedItemKind::Const | AssociatedItemKind::Method { .. } => (true, false),
AssociatedItemKind::Type => (defaultness.has_value(), true),
// `ty()` for existential types is the underlying type,
// it's not a part of interface, so we skip it.
AssociatedItemKind::Existential => (false, true),
};
check.in_assoc_ty = is_assoc_ty;
check.generics().predicates();
if check_ty {
check.ty();
}
}
}

impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
Expand Down Expand Up @@ -1592,16 +1610,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
self.check(item.id, item_visibility).generics().predicates();

for trait_item_ref in trait_item_refs {
let mut check = self.check(trait_item_ref.id.node_id, item_visibility);
check.in_assoc_ty = trait_item_ref.kind == hir::AssociatedItemKind::Type;
check.generics().predicates();

if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
!trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
check.ty();
}
self.check_trait_or_impl_item(trait_item_ref.id.node_id, trait_item_ref.kind,
trait_item_ref.defaultness, item_visibility);
}
}
hir::ItemKind::TraitAlias(..) => {
Expand Down Expand Up @@ -1647,9 +1657,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
} else {
impl_vis
};
let mut check = self.check(impl_item.id, impl_item_vis);
check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type;
check.generics().predicates().ty();
self.check_trait_or_impl_item(impl_item_ref.id.node_id, impl_item_ref.kind,
impl_item_ref.defaultness, impl_item_vis);
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/test/ui/privacy/private-in-public-assoc-ty.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Private types and traits are not allowed in interfaces of associated types.
// This test also ensures that the checks are performed even inside private modules.

#![feature(associated_type_defaults)]
#![feature(associated_type_defaults, existential_type)]

mod m {
struct Priv;
Expand All @@ -23,10 +23,17 @@ mod m {

type Alias4 = Priv;
//~^ ERROR private type `m::Priv` in public interface

type Exist;
fn infer_exist() -> Self::Exist;
}
impl PubTr for u8 {
type Alias1 = Priv;
//~^ ERROR private type `m::Priv` in public interface

existential type Exist: PrivTr;
//~^ ERROR private trait `m::PrivTr` in public interface
fn infer_exist() -> Self::Exist { Priv }
}
}

Expand Down
20 changes: 15 additions & 5 deletions src/test/ui/privacy/private-in-public-assoc-ty.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ LL | | //~^ WARN private trait `m::PrivTr` in public interface
LL | | //~| WARN this was previously accepted
LL | | //~| WARN private type `m::Priv` in public interface
... |
LL | | //~^ ERROR private type `m::Priv` in public interface
LL | | fn infer_exist() -> Self::Exist;
LL | | }
| |_____^
|
Expand All @@ -22,7 +22,7 @@ LL | | //~^ WARN private trait `m::PrivTr` in public interface
LL | | //~| WARN this was previously accepted
LL | | //~| WARN private type `m::Priv` in public interface
... |
LL | | //~^ ERROR private type `m::Priv` in public interface
LL | | fn infer_exist() -> Self::Exist;
LL | | }
| |_____^
|
Expand All @@ -39,14 +39,24 @@ LL | type Alias4 = Priv;
| ^^^^^^^^^^^^^^^^^^^ can't leak private type

error[E0446]: private type `m::Priv` in public interface
--> $DIR/private-in-public-assoc-ty.rs:28:9
--> $DIR/private-in-public-assoc-ty.rs:31:9
|
LL | struct Priv;
| - `m::Priv` declared as private
...
LL | type Alias1 = Priv;
| ^^^^^^^^^^^^^^^^^^^ can't leak private type

error: aborting due to 2 previous errors
error[E0445]: private trait `m::PrivTr` in public interface
--> $DIR/private-in-public-assoc-ty.rs:34:9
|
LL | trait PrivTr {}
| - `m::PrivTr` declared as private
...
LL | existential type Exist: PrivTr;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0446`.
Some errors occurred: E0445, E0446.
For more information about an error, try `rustc --explain E0445`.
10 changes: 10 additions & 0 deletions src/test/ui/privacy/private-in-public-existential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,14 @@ fn check() -> Pub {
Priv
}

pub trait Trait {
type Pub: Default;
fn method() -> Self::Pub;
}

impl Trait for u8 {
existential type Pub: Default;
fn method() -> Self::Pub { Priv }
}

fn main() {}

0 comments on commit e8f2aec

Please sign in to comment.