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

More general on_unimplemented, with uses in Try #44191

Merged
merged 7 commits into from Sep 3, 2017

Conversation

arielb1
Copy link
Contributor

@arielb1 arielb1 commented Aug 30, 2017

Allow on_unimplemented directives to specify both the label and the primary message of the trait error, and allow them to be controlled by flags - currently only to be desugaring-sensitive.

e.g.

#[rustc_on_unimplemented(
    on(all(direct, from_desugaring="?"),
        message="the `?` operator can only be used in a \
        function that returns `Result` \
        (or another type that implements `{Try}`)",
        label="cannot use the `?` operator in a function that returns `{Self}`"),
)]

r? @nikomatsakis

@arielb1
Copy link
Contributor Author

arielb1 commented Aug 30, 2017

cc @estebank @rust-lang/docs are there any more things you want in on_unimplemented?

Position::ArgumentIs(_) => {
span_err!(tcx.sess, span, E0231,
"only named substitution \
parameters are allowed");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a note including all the possible valid named parameters?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's preexisting.

let item_def_id = tcx.hir.local_def_id(item.id);
// an error would be reported if this fails.
let _ = traits::OnUnimplementedDirective::of_item(
tcx, trait_def_id, item_def_id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't fit in <100?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it does. this just went through a few revisions.

@@ -4690,7 +4646,6 @@ register_diagnostics! {
E0224, // at least one non-builtin train is required for an object type
E0227, // ambiguous lifetime bound, explicit lifetime bound required
E0228, // explicit lifetime bound required
E0231, // only named substitution parameters are allowed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't these need to be commented out instead of deleted? I don't know.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to librustc/diagnostics, not deleted.

| ---------------------------
| |
| the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`)
| the trait `std::ops::Try` is not implemented for `()`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am worried that the error text is less prominent than the label, so moving the more relevant text to the error message makes it less useful for newbies. But this might just be an unfounded personal reaction.

Maybe adding an optional label attribute to rustc_on_unimplemented for text to be displayed in the label would be reasonable? (If I understood the code above correctly, the feature is already there, it just needs to be changed in the trait, right?)

--> $DIR/bad-annotation.rs:46:39
|
46 | #[rustc_on_unimplemented(message="x", message="y")]
| ^^^^^^^^^^^ expected value here
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we handle duplicated values with a special label pointing at the first one encountered?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't bother with precise error reporting here - this is an unstable feature that is going to be revised.

@arielb1
Copy link
Contributor Author

arielb1 commented Aug 31, 2017

addressed

@nikomatsakis
Copy link
Contributor

Ah, this is a neat idea! :) I like the idea of improving on_unimplemented further. (As an irrelevant aside, remind me to try and write-up some of my thoughts about end-user-customizable error reporting, which would supercede this sort of thing I think.)

Anyway, this seems good, but to truly handle the ? errors correctly, though, we would need to differentiate the two uses of Try that occur within the ? operator, as described in this comment. In particular, we want to distinguish between foo? where the type of foo does not implement Try and the error you are testing here, which arises from the Try::from_err() call.

Put another way, can you add the test case from #43984?

@arielb1
Copy link
Contributor Author

arielb1 commented Aug 31, 2017

The test case from #43984 is present, it's the other one that isn't

So the problem is basically to distinguish:

fn main() {
    Ok(4)?; //~ ERROR the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`)
}

fn foo() -> Result<(), ()> {
    ()?; //~ ERROR <want something else>
    Ok(())
}

@arielb1
Copy link
Contributor Author

arielb1 commented Aug 31, 2017

I think I can arrange that, but I need to go AFK.

@nikomatsakis
Copy link
Contributor

@arielb1 right, that is the two cases to distinguish. The test case I was referring to included:

fn source() -> u32 {
    3u32?
}

with the expected error message:

error[E0277]: the trait bound `u32: std::ops::Try` is not satisfied
  --> $DIR/try-unimplemented.rs:17:5
   |
17 |     3u32?
   |     ^^^^^ `?` cannot be applied to a value of type `u32`
   |
   = help: the trait `std::ops::Try` is not implemented for `u32`
   = note: required by `std::ops::Try::into_result`

I think it's a bit debatable what the "main part" of that error should be, but anyway.

@nikomatsakis
Copy link
Contributor

@arielb1 we could also do it in a follow-up, that'd be ok w/ me (and/or maybe @huntiep wants to hack on it, I don't know)

@arielb1
Copy link
Contributor Author

arielb1 commented Aug 31, 2017

Special Try case now done! We can iterate more on other special cases, but it should be fairly easy.

std::fs::File::open("foo")?;

// a non-`Try` type on a `Try` fn
Copy link
Contributor

@estebank estebank Aug 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a non-`Try` type on a non-`Try` fn

| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Try` is not implemented for `()`
|
= note: required by `try_trait_generic`

error: aborting due to 2 previous errors
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be neat to also add a custom error message for this case along the lines of

the `?` operator can only be applied to elements that implement the trait `std::ops::Try`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think now that we have this feature one of the docs guys should use it (or variants of it) in all the traits.

flags.push(("from_desugaring", None));
flags.push(("from_desugaring", Some(&*s)));
flags.push(("from_desugaring", Some(&*desugaring)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use .as_ref?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally use &*x instead of .as_ref().

@arielb1 arielb1 force-pushed the on-unimplemented-label branch 2 times, most recently from 264bc78 to 0738768 Compare August 31, 2017 19:53
@@ -21,7 +21,9 @@
(or another type that implements `{Try}`)")]
#[cfg_attr(not(stage0),
rustc_on_unimplemented(
on(all(direct, from_desugaring="?"),
on(all(
any(from_method="from_error", from_method="from_ok"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cute.

| in this macro invocation
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`

error: aborting due to previous error
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Aug 31, 2017

📌 Commit 0738768 has been approved by nikomatsakis

@estebank
Copy link
Contributor

estebank commented Sep 1, 2017

There's a bizarre error when running Doctest: bootstrap.RustBuild.program_config:

[00:02:13] ======================================================================
[00:02:13] FAIL: program_config (bootstrap.RustBuild)
[00:02:13] Doctest: bootstrap.RustBuild.program_config
[00:02:13] ----------------------------------------------------------------------
[00:02:13] Traceback (most recent call last):
[00:02:13]   File "/usr/lib/python2.7/doctest.py", line 2226, in runTest
[00:02:13]     raise self.failureException(self.format_failure(new.getvalue()))
[00:02:13] AssertionError: Failed doctest test for bootstrap.RustBuild.program_config
[00:02:13]   File "/checkout/src/bootstrap/bootstrap.py", line 519, in program_config
[00:02:13] 
[00:02:13] ----------------------------------------------------------------------
[00:02:13] File "/checkout/src/bootstrap/bootstrap.py", line 527, in bootstrap.RustBuild.program_config
[00:02:13] Failed example:
[00:02:13]     cargo_path.rstrip(".exe") == os.path.join("/tmp/rust",
[00:02:13]     "bin", "cargo")
[00:02:13] Expected:
[00:02:13]     True
[00:02:13] Got:
[00:02:13]     False

@shepmaster shepmaster added the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Sep 1, 2017
@frewsxcv
Copy link
Member

frewsxcv commented Sep 2, 2017

@estebank I'm pretty sure that error (which isn't actually a hard error) happens on all builds, regardless of whether the build is successful or not.

The actual error is in the Building stage1 compiler artifacts (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) section:

[00:18:17] error: variable does not need to be mutable
[00:18:17]    --> /checkout/src/libsyntax/attr.rs:598:65
[00:18:17]     |
[00:18:17] 598 | pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, mut eval: &mut F)
[00:18:17]     |                                                                 ^^^^^^^^
[00:18:17]     |
[00:18:17] note: lint level defined here
[00:18:17]    --> /checkout/src/libsyntax/lib.rs:21:9
[00:18:17]     |
[00:18:17] 21  | #![deny(warnings)]
[00:18:17]     |         ^^^^^^^^
[00:18:17]     = note: #[deny(unused_mut)] implied by #[deny(warnings)]
[00:18:17] 
[00:18:17] error: aborting due to previous error
[00:18:17] 
[00:18:17] error: Could not compile `syntax`.

@frewsxcv
Copy link
Member

frewsxcv commented Sep 2, 2017

@bors r-

@arielb1
Copy link
Contributor Author

arielb1 commented Sep 3, 2017

@bors r+

@bors
Copy link
Contributor

bors commented Sep 3, 2017

📌 Commit 291b4ed has been approved by arielb1

@arielb1
Copy link
Contributor Author

arielb1 commented Sep 3, 2017

@bors r-

@arielb1
Copy link
Contributor Author

arielb1 commented Sep 3, 2017

@bors r=nikomatsakis

@bors
Copy link
Contributor

bors commented Sep 3, 2017

📌 Commit 291b4ed has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Sep 3, 2017

⌛ Testing commit 291b4ed with merge c8642da...

bors added a commit that referenced this pull request Sep 3, 2017
More general `on_unimplemented`, with uses in `Try`

Allow `on_unimplemented` directives to specify both the label and the primary message of the trait error, and allow them to be controlled by flags - currently only to be desugaring-sensitive.

e.g.
```Rust
#[rustc_on_unimplemented(
    on(all(direct, from_desugaring="?"),
        message="the `?` operator can only be used in a \
        function that returns `Result` \
        (or another type that implements `{Try}`)",
        label="cannot use the `?` operator in a function that returns `{Self}`"),
)]
```

r? @nikomatsakis
@bors
Copy link
Contributor

bors commented Sep 3, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing c8642da to master...

@bors bors merged commit 291b4ed into rust-lang:master Sep 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants