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

"source trait is private" error with writeln! only when println! isn't used #27669

Closed
gsingh93 opened this issue Aug 11, 2015 · 9 comments
Closed
Labels
E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.

Comments

@gsingh93
Copy link
Contributor

This error is related to #22050, not sure if it's a dupe. Some of the following code snippets rely on the term library (but the issue seems to be in Rust, not term).

The following builds fine:

fn foo() {
    let mut s = String::new();
    writeln!(s, "foo").unwrap();
}

This gives an error:

extern crate term;

fn foo() {
    let mut t = term::stdout().unwrap();
    writeln!(t, "foo").unwrap();
}

Output:

lib.rs:5:5: 5:23 error: source trait is private
lib.rs:5     writeln!(t, "foo").unwrap();

This is the error mentioned in #22050. Importing std::io::Write fixes the error. However, if println is used, we get no errors:

extern crate term;

fn foo() {
    let mut t = term::stdout().unwrap();
    writeln!(t, "foo").unwrap();
    println!("foo");
}
@gsingh93
Copy link
Contributor Author

Running rustc with --pretty=expanded on the second example gives this:

$ rustc -Z unstable-options --pretty=expanded src/lib.rs
#![feature(no_std)]
#![no_std]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std as std;
extern crate term;

fn foo() {
    let mut t = term::stdout().unwrap();
    t.write_fmt(::std::fmt::Arguments::new_v1({
                                                  static __STATIC_FMTSTR:
                                                         &'static [&'static str]
                                                         =
                                                      &["foo\n"];
                                                  __STATIC_FMTSTR
                                              },
                                              &match () {
                                                   () => [],
                                               })).unwrap();
}

Running it on the third example gives this:

$ rustc -Z unstable-options --pretty=expanded src/lib.rs
#![feature(no_std)]
#![no_std]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std as std;
extern crate term;

fn foo() {
    let mut t = term::stdout().unwrap();
    t.write_fmt(::std::fmt::Arguments::new_v1({
                                                  static __STATIC_FMTSTR:
                                                         &'static [&'static str]
                                                         =
                                                      &["foo\n"];
                                                  __STATIC_FMTSTR
                                              },
                                              &match () {
                                                   () => [],
                                               })).unwrap();
    ::std::io::_print(::std::fmt::Arguments::new_v1({
                                                        static __STATIC_FMTSTR:
                                                               &'static [&'static str]
                                                               =
                                                            &["foo\n"];
                                                        __STATIC_FMTSTR
                                                    },
                                                    &match () { () => [], }));
}

@gsingh93
Copy link
Contributor Author

My first example was incorrect, this code compiles:

use std::fmt::Write; // I had forgot this previously

fn foo() {
    let mut s = String::new();
    writeln!(s, "foo").unwrap();
}

Original issue is unchanged.

@steveklabnik steveklabnik added the A-trait-system Area: Trait system label Sep 3, 2015
@petrochenkov
Copy link
Contributor

This is fixed in #32073 & #31920

@alexcrichton alexcrichton added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label May 1, 2016
@petrochenkov petrochenkov removed the A-trait-system Area: Trait system label Feb 19, 2017
@petrochenkov petrochenkov added the E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. label Mar 1, 2017
@tbg
Copy link
Contributor

tbg commented Mar 12, 2017

@petrochenkov you mentioned above that this is fixed, what's left to do here then? Just tests?

@sfackler
Copy link
Member

Yep!

@tbg
Copy link
Contributor

tbg commented Mar 12, 2017

Ok. Consider it done.

@tbg
Copy link
Contributor

tbg commented Mar 12, 2017

So I thought the test that was needed was something that used an external crate, and then uses a trait without importing it from that crate. Steve already posted something using only the standard library and that seems to have made it into a test, but somehow it's not necessary any more to import the trait?

use std::thread;
// use std::any::TypeId; // <- actually compiles as-is

fn main() {
    let child = thread::spawn(|| {
    });
    child.join().unwrap_err().get_type_id();
}

The test is here (and indeed the TypeId trait isn't explicitly imported any more).

In the same vein, the originally failing example now compiles:

extern crate term;

fn main() {
    let mut t = term::stdout().unwrap();
    writeln!(t, "foo").unwrap();
}

so does

extern crate term;

fn foo(t: &mut std::io::Write) {
    t.flush().unwrap();
}

fn main() {
    let mut t = term::stdout().unwrap();
    foo(&mut t);
}

but then this one still errors even though to my untrained eye it looks exactly like the term example above.

//use std::fmt::Write; // intentional omission

fn main() {
    let mut s = String::new();
    writeln!(s, "foo").unwrap();
}
/*
error: no method named `write_fmt` found for type `std::string::String` in the current scope
 --> main.rs:5:5
  |
5 |     writeln!(s, "foo").unwrap();
  |     ^^^^^^^^^^^^^^^^^^
  |
  = help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
  = help: candidate #1: `use std::fmt::Write;`
  = note: this error originates in a macro outside of the current crate
*/

I'm obviously a bit confused, so whatever reading you can throw at me, please do.

Perhaps std is too special to be used to make the test case we want happen, but if even the original examples can't reproduce an error any more because something picks up the trait automatically, what's left here to test?

@petrochenkov
Copy link
Contributor

@tschottdorf
Actually, #32073 already contains the test, so this issue can be closed.

The difference between the term example and String::new() example is that term::stdout().unwrap() returns a trait object so the trait's methods should be usable on it even if the trait is not in scope.
String is not a trait object, it just implements Write, so Write needs to be in scope for s.write_fmt(...) to work.

@tbg
Copy link
Contributor

tbg commented Mar 12, 2017

Gotcha, thanks for the clarification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.
Projects
None yet
Development

No branches or pull requests

6 participants