Rollup merge of #57649 - petrochenkov:privexist, r=arielb1
privacy: Account for associated existential types
Turns out they *can* be associated (but only in impls, not traits).
Fixes https://github.com/rust-lang/rust/issues/53546#issuecomment-454372879
r? @arielb1
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 698037e..dcbb9ff 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -13,7 +13,7 @@
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};
@@ -548,7 +548,7 @@
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 {
@@ -1343,11 +1343,11 @@
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);
}
@@ -1568,6 +1568,24 @@
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> {
@@ -1602,16 +1620,8 @@
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(..) => {
@@ -1657,9 +1667,8 @@
} 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);
}
}
}
diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.rs b/src/test/ui/privacy/private-in-public-assoc-ty.rs
index c6e86ed..81d2395 100644
--- a/src/test/ui/privacy/private-in-public-assoc-ty.rs
+++ b/src/test/ui/privacy/private-in-public-assoc-ty.rs
@@ -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;
@@ -23,10 +23,17 @@
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 }
}
}
diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.stderr b/src/test/ui/privacy/private-in-public-assoc-ty.stderr
index 6740277..0e5dab1 100644
--- a/src/test/ui/privacy/private-in-public-assoc-ty.stderr
+++ b/src/test/ui/privacy/private-in-public-assoc-ty.stderr
@@ -6,7 +6,7 @@
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 | | }
| |_____^
|
@@ -22,7 +22,7 @@
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 | | }
| |_____^
|
@@ -39,7 +39,7 @@
| ^^^^^^^^^^^^^^^^^^^ 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
@@ -47,6 +47,16 @@
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
-For more information about this error, try `rustc --explain E0446`.
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0445, E0446.
+For more information about an error, try `rustc --explain E0445`.
diff --git a/src/test/ui/privacy/private-in-public-existential.rs b/src/test/ui/privacy/private-in-public-existential.rs
index 95658f4..61c6130 100644
--- a/src/test/ui/privacy/private-in-public-existential.rs
+++ b/src/test/ui/privacy/private-in-public-existential.rs
@@ -12,4 +12,14 @@
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() {}