Modify --explain to handle hidden code (# ...) and indented code blocks.

This commit is contained in:
kennytm 2017-06-20 15:53:03 +08:00
parent 4711982314
commit 2c89165814
No known key found for this signature in database
GPG key ID: FEF6C8051D0E013C
3 changed files with 87 additions and 6 deletions

View file

@ -355,14 +355,21 @@ fn handle_explain(code: &str,
};
match descriptions.find_description(&normalised) {
Some(ref description) => {
let mut is_in_code_block = false;
// Slice off the leading newline and print.
print!("{}", &(&description[1..]).split("\n").map(|x| {
format!("{}\n", if x.starts_with("```") {
"```"
for line in description[1..].lines() {
let indent_level = line.find(|c: char| !c.is_whitespace())
.unwrap_or_else(|| line.len());
let dedented_line = &line[indent_level..];
if dedented_line.starts_with("```") {
is_in_code_block = !is_in_code_block;
println!("{}", &line[..(indent_level+3)]);
} else if is_in_code_block && dedented_line.starts_with("# ") {
continue;
} else {
x
})
}).collect::<String>());
println!("{}", line);
}
}
}
None => {
early_error(output, &format!("no extended information for {}", code));

11
src/test/ui/explain.rs Normal file
View file

@ -0,0 +1,11 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --explain E0591

View file

@ -0,0 +1,63 @@
Per [RFC 401][rfc401], if you have a function declaration `foo`:
```
// For the purposes of this explanation, all of these
// different kinds of `fn` declarations are equivalent:
struct S;
fn foo(x: S) { /* ... */ }
extern "C" { fn foo(x: S); }
impl S { fn foo(self) { /* ... */ } }
```
the type of `foo` is **not** `fn(S)`, as one might expect.
Rather, it is a unique, zero-sized marker type written here as `typeof(foo)`.
However, `typeof(foo)` can be _coerced_ to a function pointer `fn(S)`,
so you rarely notice this:
```
let x: fn(S) = foo; // OK, coerces
```
The reason that this matter is that the type `fn(S)` is not specific to
any particular function: it's a function _pointer_. So calling `x()` results
in a virtual call, whereas `foo()` is statically dispatched, because the type
of `foo` tells us precisely what function is being called.
As noted above, coercions mean that most code doesn't have to be
concerned with this distinction. However, you can tell the difference
when using **transmute** to convert a fn item into a fn pointer.
This is sometimes done as part of an FFI:
```
extern "C" fn foo(userdata: Box<i32>) {
/* ... */
}
let f: extern "C" fn(*mut i32) = transmute(foo);
callback(f);
```
Here, transmute is being used to convert the types of the fn arguments.
This pattern is incorrect because, because the type of `foo` is a function
**item** (`typeof(foo)`), which is zero-sized, and the target type (`fn()`)
is a function pointer, which is not zero-sized.
This pattern should be rewritten. There are a few possible ways to do this:
- change the original fn declaration to match the expected signature,
and do the cast in the fn body (the prefered option)
- cast the fn item fo a fn pointer before calling transmute, as shown here:
```
let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_));
let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too
```
The same applies to transmutes to `*mut fn()`, which were observedin practice.
Note though that use of this type is generally incorrect.
The intention is typically to describe a function pointer, but just `fn()`
alone suffices for that. `*mut fn()` is a pointer to a fn pointer.
(Since these values are typically just passed to C code, however, this rarely
makes a difference in practice.)
[rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md