Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Private trait's methods reachable through a public subtrait #28514

Closed
bluss opened this issue Sep 19, 2015 · 29 comments
Closed

Private trait's methods reachable through a public subtrait #28514

bluss opened this issue Sep 19, 2015 · 29 comments
Assignees
Labels
A-resolve Area: Name resolution A-visibility Area: Visibility / privacy T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@bluss
Copy link
Member

bluss commented Sep 19, 2015

I'm not 100% sure how the privacy rules should work.

A's methods should not be callable because the trait is private, but it's reachable though the trait C that inherits A, by calling C::a().

B's methods are reachable the same way, even if it's marked pub but not publically reachable.

pub use inner::C;

mod inner {
    trait A {
        fn a(&self) { }
    }

    pub trait B {
        fn b(&self) { }
    }

    pub trait C: A + B {
        fn c(&self) { }
    }

    impl A for i32 {}
    impl B for i32 {}
    impl C for i32 {}
}

fn main() {
    // A is private
    // B is pub, not reexported
    // C : A + B is pub, reexported

    // 0.a(); // can't call
    // 0.b(); // can't call
    0.c(); // ok

    C::a(&0); // can call
    C::b(&0); // can call
    C::c(&0); // ok
}

Playpen

@bluss
Copy link
Member Author

bluss commented Sep 19, 2015

cc @alexcrichton, because you've weighed in on other privacy issues

@alexcrichton
Copy link
Member

I would personally expect a privacy error to be generated. I'm also a little surprised about how resolution allows using a method without importing the trait as well, but that may perhaps be intended behavior.

cc @rust-lang/lang, @nrc

triage: I-nominated

@alexcrichton alexcrichton added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Sep 19, 2015
@bluss
Copy link
Member Author

bluss commented Sep 19, 2015

C::b being callable seems to suggest b is a method in the C trait, "inherited", but .b() not being callable as a method when C is in scope is a counterargument.

@nikomatsakis
Copy link
Contributor

I think the error here is that pub trait C: A + B ought to require that A is public.

@nrc
Copy link
Member

nrc commented Sep 22, 2015

public or accessible from all the places C is? If it is in another module, it could be public but we could still have this problem (with a more complex example). The alternative feels hard to check though.

@alexcrichton
Copy link
Member

I'd be fine so long as it was limited to "marked pub" because that's generally how the public/private check works in terms of what you can export.

@nikomatsakis
Copy link
Contributor

I am somewhat surprised, but this test case passes too. The difference here is that the type I32 is private, so I expect the impl to be in error.

mod inner {
    struct I32;

    trait A {
        fn a(&self) { }
    }

    pub trait B {
        fn b(&self) { }
    }

    pub trait C: A + B {
        fn c(&self) { }
    }

    impl A for I32 {}
    impl B for I32 {}
    impl C for I32 {} // <-- I expected an error here and on the impl of B
}

fn main() {
}

@pnkfelix
Copy link
Member

pnkfelix commented Oct 1, 2015

(I'm inclined to think that the invocation C::a(&0) from the original example is still problematic, independently of the example @nikomatsakis gave above.)

@pnkfelix
Copy link
Member

pnkfelix commented Oct 1, 2015

(namely, if one changes @nikomatsakis example so that it says pub struct I32;, then we would still have the issue of whether 1. one can have the declaration of pub trait C: A { ... } and 2. whether one can call the methods from the private trait A on a type where only the public trait C is available for use.)

@nikomatsakis
Copy link
Contributor

The heart of this question is what a private trait means. After some discussion in the language team, we came to the following conclusions:

  • To be consistent with the rest of the rules, private types and traits should not appear in the where-clauses (or supertraits) of public traits. This would make pub trait B: A an error. I believe this is the in the spirit of the relevant RFC, I've not reviewed the precise wording.
  • Furthermore, if we ever were to relax this rule, we would want to define when you can call a method on a private trait. It might make sense to make that illegal outside of the module that defined the trait.

There is definitely concern that people are going to be relying on this kind of setup, though also concern that they may not be getting the guarantees that they think they are.

@nikomatsakis
Copy link
Contributor

triage: P-high

@bluss
Copy link
Member Author

bluss commented Oct 23, 2015

This variation shows how using a trait bound with C makes all the methods from A, B, C directly callable, while just use inner::C; (in the original report's code) only enables the methods from C and not A nor B.

fn use_c<T: C>(x: &T) {
    // A is private
    // B is pub, not reexported
    // C : A + B is pub, reexported

    x.a(); // can call
    x.b(); // can call
    x.c(); // ok

    C::a(x); // can call
    C::b(x); // can call
    C::c(x); // ok
}

a is still callable both ways in nightly — is so it's not limited to just UFCS?!

@bluss
Copy link
Member Author

bluss commented Oct 23, 2015

The last comment shows a regression in nightly. x.a() compiles in nightly, used to be a privacy error.

@nikomatsakis nikomatsakis added the regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. label Oct 23, 2015
@nikomatsakis
Copy link
Contributor

Unfortunately, the current assignee (@aturon) is out for a while, so someone else will have to look into this.

@arielb1 arielb1 changed the title Private trait's methods reachable through UFCS Private trait's methods reachable through a public supertrait Oct 23, 2015
@brson
Copy link
Contributor

brson commented Nov 18, 2015

Is this on beta/stable yet?

@bluss
Copy link
Member Author

bluss commented Nov 18, 2015

The regression mentioned in this comment seems to be fixed in nightly (and never reached beta). I think it was fixed in #29325

@bluss bluss removed the regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. label Nov 18, 2015
@aturon
Copy link
Member

aturon commented Jan 14, 2016

@petrochenkov Are you interested in taking this on?

@petrochenkov
Copy link
Contributor

@aturon
I'm very much interested in fixing the rest of privacy bugs and then laying the road to rust-lang/rfcs#1422, but the main problem is time now. It will be clear in the next few weeks how much resources I'll be able to spend on it.

@jseyfried
Copy link
Contributor

cc @nikomatsakis

@brson brson added the P-medium Medium priority label Jul 14, 2016
@brson
Copy link
Contributor

brson commented Jul 14, 2016

Triage: Moving this to P-medium since nobody is working on it. cc @rust-lang/lang @petrochenkov

@alexcrichton
Copy link
Member

also ping @jseyfried, if this is no longer an issue, could you provide a summary as to why as well? It'd be great to close out!

@jseyfried
Copy link
Contributor

jseyfried commented Jul 14, 2016

@alexcrichton I believe this issue can only happen if a public trait has a private parent, which is already a private_in_public future incompatiblity warning.

@alexcrichton alexcrichton removed the P-high High priority label Jul 14, 2016
@alexcrichton
Copy link
Member

Awesome! I @rust-lang/lang, thoughts about closing? (also applying a nomination for bringing it up)

@petrochenkov
Copy link
Contributor

petrochenkov commented Jul 14, 2016

I think this can be requalified to E-needtest and closed when #34206 lands. I should probably add this test to #34206 itself (EDIT: done).

@aturon aturon added E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. and removed I-nominated P-medium Medium priority labels Jul 14, 2016
@aturon
Copy link
Member

aturon commented Jul 14, 2016

Switching to needstest!

@bors bors closed this as completed in b052dd6 Aug 14, 2016
@petrochenkov
Copy link
Contributor

Reopening this since private_in_public was reverted to warn-by-default and is not going to become a hard error.

@petrochenkov petrochenkov reopened this Apr 11, 2017
@petrochenkov petrochenkov added A-visibility Area: Visibility / privacy and removed E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. labels Apr 11, 2017
@petrochenkov
Copy link
Contributor

Visibility of a trait item is inherited from its trait, so the fix is to check this trait visibility every time a trait item is named.

C::a(x); // ERROR, trait A is private / not accessible from here

@petrochenkov
Copy link
Contributor

petrochenkov commented Apr 11, 2017

C::b(&0);

is an orthogonal problem.
UFCS RFC says that UFCS works only with traits in scope, exactly like method calls, and B is not in scope, so this should supposedly be a method resolution error.

C::b(&0); // ERROR no method b in the current scope

EDIT: This interpretation incorrect, I didn't realize this is about C::b and not i32::b. C::b is OK.
C in this example is a trait object type, not a trait, and trait objects are special cased in associated item resolution, and items of their corresponding traits and super-traits are treated as inherent. That's why C::b doesn't require B to be in scope, because it's treated as inherent.

@petrochenkov petrochenkov added the A-resolve Area: Name resolution label Apr 11, 2017
arielb1 pushed a commit to arielb1/rust that referenced this issue Apr 25, 2017
Check privacy of trait items in all contexts

Fixes rust-lang#28514

This is a sufficiently rare scenario and it's currently guarded by `private_in_public` lint, so it shouldn't be a [breaking-change] in practice.
bors added a commit that referenced this issue Apr 25, 2017
Check privacy of trait items in all contexts

Fixes #28514

This is a sufficiently rare scenario and it's currently guarded by `private_in_public` lint, so it shouldn't be a [breaking-change] in practice.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-resolve Area: Name resolution A-visibility Area: Visibility / privacy T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

10 participants