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() {}