auto merge of #15377 : alexcrichton/rust/rollup, r=alexcrichton
Closes #15276 (Guide: if) Closes #15280 (std::os - Add join_paths, make setenv non-utf8 capable) Closes #15314 (Guide: functions) Closes #15327 (Simplify PatIdent to contain an Ident rather than a Path) Closes #15340 (Guide: add mutable binding section) Closes #15342 (Fix ICE with nested macro_rules!-style macros) Closes #15350 (Remove duplicated slash in install script path) Closes #15351 (correct a few spelling mistakes in the tutorial) Closes #15352 (librustc: Have the kind checker check sub-bounds in trait casts.) Closes #15359 (Fix spelling errors.) Closes #15361 (Rename set_broadast() to set_broadcast().) Closes #15366 (Simplify creating a parser from a token tree) Closes #15367 (Add examples for StrVector methods) Closes #15372 (Vec::grow should use reserve_additional, Vec::reserve should check against capacity) Closes #15373 (Fix minor issues in the documentation of libtime.)
This commit is contained in:
commit
5d5c20647f
335
src/doc/guide.md
335
src/doc/guide.md
@ -515,9 +515,45 @@ let x: int = 5;
|
||||
```
|
||||
|
||||
If I asked you to read this out loud to the rest of the class, you'd say "`x`
|
||||
is a binding with the type `int` and the value `five`." Rust requires you to
|
||||
initialize the binding with a value before you're allowed to use it. If
|
||||
we try...
|
||||
is a binding with the type `int` and the value `five`."
|
||||
|
||||
By default, bindings are **immutable**. This code will not compile:
|
||||
|
||||
```{ignore}
|
||||
let x = 5i;
|
||||
x = 10i;
|
||||
```
|
||||
|
||||
It will give you this error:
|
||||
|
||||
```{ignore,notrust}
|
||||
error: re-assignment of immutable variable `x`
|
||||
x = 10i;
|
||||
^~~~~~~
|
||||
```
|
||||
|
||||
If you want a binding to be mutable, you can use `mut`:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5i;
|
||||
x = 10i;
|
||||
```
|
||||
|
||||
There is no single reason that bindings are immutable by default, but we can
|
||||
think about it through one of Rust's primary focuses: safety. If you forget to
|
||||
say `mut`, the compiler will catch it, and let you know that you have mutated
|
||||
something you may not have cared to mutate. If bindings were mutable by
|
||||
default, the compiler would not be able to tell you this. If you _did_ intend
|
||||
mutation, then the solution is quite easy: add `mut`.
|
||||
|
||||
There are other good reasons to avoid mutable state when possible, but they're
|
||||
out of the scope of this guide. In general, you can often avoid explicit
|
||||
mutation, and so it is preferable in Rust. That said, sometimes, mutation is
|
||||
what you need, so it's not verboten.
|
||||
|
||||
Let's get back to bindings. Rust variable bindings have one more aspect that
|
||||
differs from other languages: bindings are required to be initialized with a
|
||||
value before you're allowed to use it. If we try...
|
||||
|
||||
```{ignore}
|
||||
let x;
|
||||
@ -611,8 +647,301 @@ concept: `if`.
|
||||
|
||||
## If
|
||||
|
||||
Rust's take on `if` is not particularly complex, but it's much more like the
|
||||
`if` you'll find in a dynamically typed language than in a more traditional
|
||||
systems language. So let's talk about it, to make sure you grasp the nuances.
|
||||
|
||||
`if` is a specific form of a more general concept, the 'branch.' The name comes
|
||||
from a branch in a tree: a decision point, where depending on a choice,
|
||||
multiple paths can be taken.
|
||||
|
||||
In the case of `if`, there is one choice that leads down two paths:
|
||||
|
||||
```rust
|
||||
let x = 5i;
|
||||
|
||||
if x == 5i {
|
||||
println!("x is five!");
|
||||
}
|
||||
```
|
||||
|
||||
If we changed the value of `x` to something else, this line would not print.
|
||||
More specifically, if the expression after the `if` evaluates to `true`, then
|
||||
the block is executed. If it's `false`, then it is not.
|
||||
|
||||
If you want something to happen in the `false` case, use an `else`:
|
||||
|
||||
```
|
||||
let x = 5i;
|
||||
|
||||
if x == 5i {
|
||||
println!("x is five!");
|
||||
} else {
|
||||
println!("x is not five :(");
|
||||
}
|
||||
```
|
||||
|
||||
This is all pretty standard. However, you can also do this:
|
||||
|
||||
|
||||
```
|
||||
let x = 5i;
|
||||
|
||||
let y = if x == 5i {
|
||||
10i
|
||||
} else {
|
||||
15i
|
||||
};
|
||||
```
|
||||
|
||||
Which we can (and probably should) write like this:
|
||||
|
||||
```
|
||||
let x = 5i;
|
||||
|
||||
let y = if x == 5i { 10i } else { 15i };
|
||||
```
|
||||
|
||||
This reveals two interesting things about Rust: it is an expression-based
|
||||
language, and semicolons are different than in other 'curly brace and
|
||||
semicolon'-based languages. These two things are related.
|
||||
|
||||
### Expressions vs. Statements
|
||||
|
||||
Rust is primarily an expression based language. There are only two kinds of
|
||||
statements, and everything else is an expression.
|
||||
|
||||
So what's the difference? Expressions return a value, and statements do not.
|
||||
In many languages, `if` is a statement, and therefore, `let x = if ...` would
|
||||
make no sense. But in Rust, `if` is an expression, which means that it returns
|
||||
a value. We can then use this value to initialize the binding.
|
||||
|
||||
Speaking of which, bindings are a kind of the first of Rust's two statements.
|
||||
The proper name is a **declaration statement**. So far, `let` is the only kind
|
||||
of declaration statement we've seen. Let's talk about that some more.
|
||||
|
||||
In some languages, variable bindings can be written as expressions, not just
|
||||
statements. Like Ruby:
|
||||
|
||||
```{ruby}
|
||||
x = y = 5
|
||||
```
|
||||
|
||||
In Rust, however, using `let` to introduce a binding is _not_ an expression. The
|
||||
following will produce a compile-time error:
|
||||
|
||||
```{ignore}
|
||||
let x = (let y = 5i); // found `let` in ident position
|
||||
```
|
||||
|
||||
The compiler is telling us here that it was expecting to see the beginning of
|
||||
an expression, and a `let` can only begin a statement, not an expression.
|
||||
|
||||
However, re-assigning to a mutable binding is an expression:
|
||||
|
||||
```{rust}
|
||||
let mut x = 0i;
|
||||
let y = x = 5i;
|
||||
```
|
||||
|
||||
In this case, we have an assignment expression (`x = 5`) whose value is
|
||||
being used as part of a `let` declaration statement (`let y = ...`).
|
||||
|
||||
The second kind of statement in Rust is the **expression statement**. Its
|
||||
purpose is to turn any expression into a statement. In practical terms, Rust's
|
||||
grammar expects statements to follow other statements. This means that you use
|
||||
semicolons to separate expressions from each other. This means that Rust
|
||||
looks a lot like most other languages that require you to use semicolons
|
||||
at the end of every line, and you will see semicolons at the end of almost
|
||||
every line of Rust code you see.
|
||||
|
||||
What is this exception that makes us say 'almost?' You saw it already, in this
|
||||
code:
|
||||
|
||||
```
|
||||
let x = 5i;
|
||||
|
||||
let y: int = if x == 5i { 10i } else { 15i };
|
||||
```
|
||||
|
||||
Note that I've added the type annotation to `y`, to specify explicitly that I
|
||||
want `y` to be an integer.
|
||||
|
||||
This is not the same as this, which won't compile:
|
||||
|
||||
```{ignore}
|
||||
let x = 5i;
|
||||
|
||||
let y: int = if x == 5 { 10i; } else { 15i; };
|
||||
```
|
||||
|
||||
Note the semicolons after the 10 and 15. Rust will give us the following error:
|
||||
|
||||
```{ignore,notrust}
|
||||
error: mismatched types: expected `int` but found `()` (expected int but found ())
|
||||
```
|
||||
|
||||
We expected an integer, but we got `()`. `()` is pronounced 'unit', and is a
|
||||
special type in Rust's type system. `()` is different than `null` in other
|
||||
languages, because `()` is distinct from other types. For example, in C, `null`
|
||||
is a valid value for a variable of type `int`. In Rust, `()` is _not_ a valid
|
||||
value for a variable of type `int`. It's only a valid value for variables of
|
||||
the type `()`, which aren't very useful. Remember how we said statements don't
|
||||
return a value? Well, that's the purpose of unit in this case. The semicolon
|
||||
turns any expression into a statement by throwing away its value and returning
|
||||
unit instead.
|
||||
|
||||
There's one more time in which you won't see a semicolon at the end of a line
|
||||
of Rust code. For that, we'll need our next concept: functions.
|
||||
|
||||
## Functions
|
||||
|
||||
You've already seen one function so far, the `main` function:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
This is the simplest possible function declaration. As we mentioned before,
|
||||
`fn` says 'this is a function,' followed by the name, some parenthesis because
|
||||
this function takes no arguments, and then some curly braces to indicate the
|
||||
body. Here's a function named `foo`:
|
||||
|
||||
```{rust}
|
||||
fn foo() {
|
||||
}
|
||||
```
|
||||
|
||||
So, what about taking arguments? Here's a function that prints a number:
|
||||
|
||||
```{rust}
|
||||
fn print_number(x: int) {
|
||||
println!("x is: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Here's a complete program that uses `print_number`:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
print_number(5);
|
||||
}
|
||||
|
||||
fn print_number(x: int) {
|
||||
println!("x is: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, function arguments work very similar to `let` declarations:
|
||||
you add a type to the argument name, after a colon.
|
||||
|
||||
Here's a complete program that adds two numbers together and prints them:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
print_sum(5, 6);
|
||||
}
|
||||
|
||||
fn print_sum(x: int, y: int) {
|
||||
println!("sum is: {}", x + y);
|
||||
}
|
||||
```
|
||||
|
||||
You separate arguments with a comma, both when you call the function, as well
|
||||
as when you declare it.
|
||||
|
||||
Unlike `let`, you _must_ declare the types of function arguments. This does
|
||||
not work:
|
||||
|
||||
```{ignore}
|
||||
fn print_number(x, y) {
|
||||
println!("x is: {}", x + y);
|
||||
}
|
||||
```
|
||||
|
||||
You get this error:
|
||||
|
||||
```{ignore,notrust}
|
||||
hello.rs:5:18: 5:19 error: expected `:` but found `,`
|
||||
hello.rs:5 fn print_number(x, y) {
|
||||
```
|
||||
|
||||
This is a deliberate design decision. While full-program inference is possible,
|
||||
languages which have it, like Haskell, often suggest that documenting your
|
||||
types explicitly is a best-practice. We agree that forcing functions to declare
|
||||
types while allowing for inference inside of function bodies is a wonderful
|
||||
compromise between full inference and no inference.
|
||||
|
||||
What about returning a value? Here's a function that adds one to an integer:
|
||||
|
||||
```{rust}
|
||||
fn add_one(x: int) -> int {
|
||||
x + 1
|
||||
}
|
||||
```
|
||||
|
||||
Rust functions return exactly one value, and you declare the type after an
|
||||
'arrow', which is a dash (`-`) followed by a greater-than sign (`>`).
|
||||
|
||||
You'll note the lack of a semicolon here. If we added it in:
|
||||
|
||||
```{ignore}
|
||||
fn add_one(x: int) -> int {
|
||||
x + 1;
|
||||
}
|
||||
```
|
||||
|
||||
We would get an error:
|
||||
|
||||
```{ignore,notrust}
|
||||
note: consider removing this semicolon:
|
||||
x + 1;
|
||||
^
|
||||
error: not all control paths return a value
|
||||
fn add_one(x: int) -> int {
|
||||
x + 1;
|
||||
}
|
||||
```
|
||||
|
||||
Remember our earlier discussions about semicolons and `()`? Our function claims
|
||||
to return an `int`, but with a semicolon, it would return `()` instead. Rust
|
||||
realizes this probably isn't what we want, and suggests removing the semicolon.
|
||||
|
||||
This is very much like our `if` statement before: the result of the block
|
||||
(`{}`) is the value of the expression. Other expression-oriented languages,
|
||||
such as Ruby, work like this, but it's a bit unusual in the systems programming
|
||||
world. When people first learn about this, they usually assume that it
|
||||
introduces bugs. But because Rust's type system is so strong, and because unit
|
||||
is its own unique type, we have never seen an issue where adding or removing a
|
||||
semicolon in a return position would cause a bug.
|
||||
|
||||
But what about early returns? Rust does have a keyword for that, `return`:
|
||||
|
||||
```{rust}
|
||||
fn foo(x: int) -> int {
|
||||
if x < 5 { return x; }
|
||||
|
||||
x + 1
|
||||
}
|
||||
```
|
||||
|
||||
Using a `return` as the last line of a function works, but is considered poor
|
||||
style:
|
||||
|
||||
```{rust}
|
||||
fn foo(x: int) -> int {
|
||||
if x < 5 { return x; }
|
||||
|
||||
return x + 1;
|
||||
}
|
||||
```
|
||||
|
||||
There are some additional ways to define functions, but they involve features
|
||||
that we haven't learned about yet, so let's just leave it at that for now.
|
||||
|
||||
## Comments
|
||||
|
||||
return
|
||||
|
||||
comments
|
||||
|
@ -469,7 +469,7 @@ fn signum(x: int) -> int {
|
||||
|
||||
Rust's `match` construct is a generalized, cleaned-up version of C's
|
||||
`switch` construct. You provide it with a value and a number of
|
||||
*arms*, each labelled with a pattern, and the code compares the value
|
||||
*arms*, each labeled with a pattern, and the code compares the value
|
||||
against each pattern in order until one matches. The matching pattern
|
||||
executes its corresponding arm.
|
||||
|
||||
@ -2524,7 +2524,7 @@ of the components of types. By design, trait objects don't know the exact type
|
||||
of their contents and so the compiler cannot reason about those properties.
|
||||
|
||||
You can instruct the compiler, however, that the contents of a trait object must
|
||||
acribe to a particular bound with a trailing colon (`:`). These are examples of
|
||||
ascribe to a particular bound with a trailing colon (`:`). These are examples of
|
||||
valid types:
|
||||
|
||||
~~~rust
|
||||
@ -2579,7 +2579,7 @@ This is a silly way to compute the radius of a circle
|
||||
|
||||
In type-parameterized functions,
|
||||
methods of the supertrait may be called on values of subtrait-bound type parameters.
|
||||
Refering to the previous example of `trait Circle : Shape`:
|
||||
Referring to the previous example of `trait Circle : Shape`:
|
||||
|
||||
~~~
|
||||
# trait Shape { fn area(&self) -> f64; }
|
||||
|
@ -214,7 +214,7 @@ need_cmd uname
|
||||
need_cmd tr
|
||||
need_cmd sed
|
||||
|
||||
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
|
||||
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)"
|
||||
CFG_SELF="$0"
|
||||
CFG_ARGS="$@"
|
||||
|
||||
|
@ -185,7 +185,7 @@ impl<T: Share + Send> Drop for Arc<T> {
|
||||
// deletion of the data. Because it is marked `Release`, the
|
||||
// decreasing of the reference count synchronizes with this `Acquire`
|
||||
// fence. This means that use of the data happens before decreasing
|
||||
// the refernce count, which happens before this fence, which
|
||||
// the reference count, which happens before this fence, which
|
||||
// happens before the deletion of the data.
|
||||
//
|
||||
// As explained in the [Boost documentation][1],
|
||||
|
@ -160,9 +160,27 @@ pub fn from_chars(chs: &[char]) -> String {
|
||||
/// Methods for vectors of strings
|
||||
pub trait StrVector {
|
||||
/// Concatenate a vector of strings.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let first = "Restaurant at the End of the".to_string();
|
||||
/// let second = " Universe".to_string();
|
||||
/// let string_vec = vec![first, second];
|
||||
/// assert_eq!(string_vec.concat(), "Restaurant at the End of the Universe".to_string());
|
||||
/// ```
|
||||
fn concat(&self) -> String;
|
||||
|
||||
/// Concatenate a vector of strings, placing a given separator between each.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let first = "Roast".to_string();
|
||||
/// let second = "Sirloin Steak".to_string();
|
||||
/// let string_vec = vec![first, second];
|
||||
/// assert_eq!(string_vec.connect(", "), "Roast, Sirloin Steak".to_string());
|
||||
/// ```
|
||||
fn connect(&self, sep: &str) -> String;
|
||||
}
|
||||
|
||||
@ -172,7 +190,7 @@ impl<'a, S: Str> StrVector for &'a [S] {
|
||||
return String::new();
|
||||
}
|
||||
|
||||
// `len` calculation may overflow but push_str but will check boundaries
|
||||
// `len` calculation may overflow but push_str will check boundaries
|
||||
let len = self.iter().map(|s| s.as_slice().len()).sum();
|
||||
|
||||
let mut result = String::with_capacity(len);
|
||||
|
@ -253,8 +253,7 @@ impl<T: Clone> Vec<T> {
|
||||
/// assert_eq!(vec, vec!("hello", "world", "world"));
|
||||
/// ```
|
||||
pub fn grow(&mut self, n: uint, value: &T) {
|
||||
let new_len = self.len() + n;
|
||||
self.reserve(new_len);
|
||||
self.reserve_additional(n);
|
||||
let mut i: uint = 0u;
|
||||
|
||||
while i < n {
|
||||
@ -497,7 +496,7 @@ impl<T> Vec<T> {
|
||||
/// assert!(vec.capacity() >= 10);
|
||||
/// ```
|
||||
pub fn reserve(&mut self, capacity: uint) {
|
||||
if capacity >= self.len {
|
||||
if capacity > self.cap {
|
||||
self.reserve_exact(num::next_power_of_two(capacity))
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ use syntax::codemap::{Span, mk_sp};
|
||||
use syntax::ext::base;
|
||||
use syntax::ext::base::{ExtCtxt, MacExpr};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::parse;
|
||||
use syntax::parse::token;
|
||||
use syntax::parse::token::InternedString;
|
||||
use rustc::plugin::Registry;
|
||||
@ -135,11 +134,7 @@ struct Ident {
|
||||
|
||||
fn parse_tts(cx: &ExtCtxt,
|
||||
tts: &[ast::TokenTree]) -> (Gc<ast::Expr>, Option<Ident>) {
|
||||
let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
|
||||
cx.cfg(),
|
||||
tts.iter()
|
||||
.map(|x| (*x).clone())
|
||||
.collect());
|
||||
let p = &mut cx.new_parser_from_tts(tts);
|
||||
let ex = p.parse_expr();
|
||||
let id = if p.token == token::EOF {
|
||||
None
|
||||
|
@ -124,7 +124,7 @@ impl Drop for Stack {
|
||||
}
|
||||
|
||||
pub struct StackPool {
|
||||
// Ideally this would be some datastructure that preserved ordering on
|
||||
// Ideally this would be some data structure that preserved ordering on
|
||||
// Stack.min_size.
|
||||
stacks: Vec<Stack>,
|
||||
}
|
||||
|
@ -54,7 +54,6 @@ use syntax::codemap::{Span, mk_sp};
|
||||
use syntax::ext::base;
|
||||
use syntax::ext::base::{ExtCtxt, MacExpr};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::parse;
|
||||
use syntax::parse::token;
|
||||
use rustc::plugin::Registry;
|
||||
|
||||
@ -167,11 +166,7 @@ struct Ident {
|
||||
|
||||
fn parse_tts(cx: &ExtCtxt,
|
||||
tts: &[ast::TokenTree]) -> (Gc<ast::Expr>, Option<Ident>) {
|
||||
let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
|
||||
cx.cfg(),
|
||||
tts.iter()
|
||||
.map(|x| (*x).clone())
|
||||
.collect());
|
||||
let p = &mut cx.new_parser_from_tts(tts);
|
||||
let ex = p.parse_expr();
|
||||
let id = if p.token == token::EOF {
|
||||
None
|
||||
|
@ -288,7 +288,7 @@ pub fn mod_enabled(level: u32, module: &str) -> bool {
|
||||
unsafe { INIT.doit(init); }
|
||||
|
||||
// It's possible for many threads are in this function, only one of them
|
||||
// will peform the global initialization, but all of them will need to check
|
||||
// will perform the global initialization, but all of them will need to check
|
||||
// again to whether they should really be here or not. Hence, despite this
|
||||
// check being expanded manually in the logging macro, this function checks
|
||||
// the log level again.
|
||||
|
@ -877,7 +877,7 @@ pub fn write<T>(fd: sock_t,
|
||||
}
|
||||
|
||||
// Also as with read(), we use MSG_DONTWAIT to guard ourselves
|
||||
// against unforseen circumstances.
|
||||
// against unforeseen circumstances.
|
||||
let _guard = lock();
|
||||
let ptr = buf.slice_from(written).as_ptr();
|
||||
let len = buf.len() - written;
|
||||
|
@ -376,7 +376,7 @@ impl rtio::RtioPipe for UnixStream {
|
||||
if ret != 0 { return Ok(bytes_read as uint) }
|
||||
|
||||
// If our errno doesn't say that the I/O is pending, then we hit some
|
||||
// legitimate error and reeturn immediately.
|
||||
// legitimate error and return immediately.
|
||||
if os::errno() != libc::ERROR_IO_PENDING as uint {
|
||||
return Err(super::last_error())
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ use syntax::ast;
|
||||
use syntax::codemap;
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, DummyResult};
|
||||
use syntax::parse;
|
||||
use syntax::parse::token;
|
||||
use syntax::print::pprust;
|
||||
|
||||
@ -615,8 +614,7 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str,
|
||||
/// Looks for a single string literal and returns it.
|
||||
/// Otherwise, logs an error with cx.span_err and returns None.
|
||||
fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
|
||||
let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
|
||||
Vec::from_slice(tts));
|
||||
let mut parser = cx.new_parser_from_tts(tts);
|
||||
let entry = cx.expand_expr(parser.parse_expr());
|
||||
let regex = match entry.node {
|
||||
ast::ExprLit(lit) => {
|
||||
|
@ -31,7 +31,7 @@
|
||||
#![no_std]
|
||||
#![experimental]
|
||||
|
||||
// This library is definining the builtin functions, so it would be a shame for
|
||||
// This library defines the builtin functions, so it would be a shame for
|
||||
// LLVM to optimize these function calls to themselves!
|
||||
#![no_builtins]
|
||||
|
||||
|
@ -119,7 +119,7 @@ pub mod write {
|
||||
// get all hardware potential via VFP3 (hardware floating point)
|
||||
// and NEON (SIMD) instructions supported by LLVM.
|
||||
// Note that without those flags various linking errors might
|
||||
// arise as some of intrinsicts are converted into function calls
|
||||
// arise as some of intrinsics are converted into function calls
|
||||
// and nobody provides implementations those functions
|
||||
fn target_feature<'a>(sess: &'a Session) -> &'a str {
|
||||
match sess.targ_cfg.os {
|
||||
|
@ -902,12 +902,10 @@ impl LintPass for NonUppercasePatternStatics {
|
||||
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
|
||||
// Lint for constants that look like binding identifiers (#7526)
|
||||
match (&p.node, cx.tcx.def_map.borrow().find(&p.id)) {
|
||||
(&ast::PatIdent(_, ref path, _), Some(&def::DefStatic(_, false))) => {
|
||||
// last identifier alone is right choice for this lint.
|
||||
let ident = path.segments.last().unwrap().identifier;
|
||||
let s = token::get_ident(ident);
|
||||
(&ast::PatIdent(_, ref path1, _), Some(&def::DefStatic(_, false))) => {
|
||||
let s = token::get_ident(path1.node);
|
||||
if s.get().chars().any(|c| c.is_lowercase()) {
|
||||
cx.span_lint(NON_UPPERCASE_PATTERN_STATICS, path.span,
|
||||
cx.span_lint(NON_UPPERCASE_PATTERN_STATICS, path1.span,
|
||||
format!("static constant in pattern `{}` should have an uppercase \
|
||||
name such as `{}`",
|
||||
s.get(), s.get().chars().map(|c| c.to_uppercase())
|
||||
@ -931,15 +929,13 @@ impl LintPass for UppercaseVariables {
|
||||
|
||||
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
|
||||
match &p.node {
|
||||
&ast::PatIdent(_, ref path, _) => {
|
||||
&ast::PatIdent(_, ref path1, _) => {
|
||||
match cx.tcx.def_map.borrow().find(&p.id) {
|
||||
Some(&def::DefLocal(_, _)) | Some(&def::DefBinding(_, _)) |
|
||||
Some(&def::DefArg(_, _)) => {
|
||||
// last identifier alone is right choice for this lint.
|
||||
let ident = path.segments.last().unwrap().identifier;
|
||||
let s = token::get_ident(ident);
|
||||
let s = token::get_ident(path1.node);
|
||||
if s.get().len() > 0 && s.get().char_at(0).is_uppercase() {
|
||||
cx.span_lint(UPPERCASE_VARIABLES, path.span,
|
||||
cx.span_lint(UPPERCASE_VARIABLES, path1.span,
|
||||
"variable names should start with \
|
||||
a lowercase character");
|
||||
}
|
||||
@ -989,7 +985,7 @@ impl UnnecessaryParens {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
/// Expressions that syntatically contain an "exterior" struct
|
||||
/// Expressions that syntactically contain an "exterior" struct
|
||||
/// literal i.e. not surrounded by any parens or other
|
||||
/// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo
|
||||
/// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X {
|
||||
@ -1113,15 +1109,10 @@ impl UnusedMut {
|
||||
// avoid false warnings in match arms with multiple patterns
|
||||
let mut mutables = HashMap::new();
|
||||
for &p in pats.iter() {
|
||||
pat_util::pat_bindings(&cx.tcx.def_map, &*p, |mode, id, _, path| {
|
||||
pat_util::pat_bindings(&cx.tcx.def_map, &*p, |mode, id, _, path1| {
|
||||
let ident = path1.node;
|
||||
match mode {
|
||||
ast::BindByValue(ast::MutMutable) => {
|
||||
if path.segments.len() != 1 {
|
||||
cx.sess().span_bug(p.span,
|
||||
"mutable binding that doesn't consist \
|
||||
of exactly one segment");
|
||||
}
|
||||
let ident = path.segments.get(0).identifier;
|
||||
if !token::get_ident(ident).get().starts_with("_") {
|
||||
mutables.insert_or_update_with(ident.name as uint,
|
||||
vec!(id), |_, old| { old.push(id); });
|
||||
|
@ -809,9 +809,8 @@ fn encode_method_argument_names(ebml_w: &mut Encoder,
|
||||
for arg in decl.inputs.iter() {
|
||||
ebml_w.start_tag(tag_method_argument_name);
|
||||
match arg.pat.node {
|
||||
ast::PatIdent(_, ref name, _) => {
|
||||
let name = name.segments.last().unwrap().identifier;
|
||||
let name = token::get_ident(name);
|
||||
ast::PatIdent(_, ref path1, _) => {
|
||||
let name = token::get_ident(path1.node);
|
||||
ebml_w.writer.write(name.get().as_bytes());
|
||||
}
|
||||
_ => {}
|
||||
@ -1106,8 +1105,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
match ty.node {
|
||||
ast::TyPath(ref path, ref bounds, _) if path.segments
|
||||
.len() == 1 => {
|
||||
let ident = path.segments.last().unwrap().identifier;
|
||||
assert!(bounds.is_none());
|
||||
encode_impl_type_basename(ebml_w, ast_util::path_to_ident(path));
|
||||
encode_impl_type_basename(ebml_w, ident);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -66,9 +66,9 @@ pub fn gather_move_from_pat(bccx: &BorrowckCtxt,
|
||||
move_pat: &ast::Pat,
|
||||
cmt: mc::cmt) {
|
||||
let pat_span_path_opt = match move_pat.node {
|
||||
ast::PatIdent(_, ref path, _) => {
|
||||
Some(MoveSpanAndPath::with_span_and_path(move_pat.span,
|
||||
(*path).clone()))
|
||||
ast::PatIdent(_, ref path1, _) => {
|
||||
Some(MoveSpanAndPath{span: move_pat.span,
|
||||
ident: path1.node})
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
@ -56,19 +56,8 @@ impl MoveError {
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct MoveSpanAndPath {
|
||||
span: codemap::Span,
|
||||
path: ast::Path
|
||||
}
|
||||
|
||||
impl MoveSpanAndPath {
|
||||
pub fn with_span_and_path(span: codemap::Span,
|
||||
path: ast::Path)
|
||||
-> MoveSpanAndPath {
|
||||
MoveSpanAndPath {
|
||||
span: span,
|
||||
path: path,
|
||||
}
|
||||
}
|
||||
pub span: codemap::Span,
|
||||
pub ident: ast::Ident
|
||||
}
|
||||
|
||||
pub struct GroupedMoveErrors {
|
||||
@ -83,7 +72,7 @@ fn report_move_errors(bccx: &BorrowckCtxt, errors: &Vec<MoveError>) {
|
||||
let mut is_first_note = true;
|
||||
for move_to in error.move_to_places.iter() {
|
||||
note_move_destination(bccx, move_to.span,
|
||||
&move_to.path, is_first_note);
|
||||
&move_to.ident, is_first_note);
|
||||
is_first_note = false;
|
||||
}
|
||||
}
|
||||
@ -154,9 +143,9 @@ fn report_cannot_move_out_of(bccx: &BorrowckCtxt, move_from: mc::cmt) {
|
||||
|
||||
fn note_move_destination(bccx: &BorrowckCtxt,
|
||||
move_to_span: codemap::Span,
|
||||
pat_ident_path: &ast::Path,
|
||||
pat_ident: &ast::Ident,
|
||||
is_first_note: bool) {
|
||||
let pat_name = pprust::path_to_str(pat_ident_path);
|
||||
let pat_name = pprust::ident_to_str(pat_ident);
|
||||
if is_first_note {
|
||||
bccx.span_note(
|
||||
move_to_span,
|
||||
|
@ -247,6 +247,10 @@ impl<'a> Visitor<MarkSymbolVisitorContext> for MarkSymbolVisitor<'a> {
|
||||
ast::PatStruct(_, ref fields, _) => {
|
||||
self.handle_field_pattern_match(pat, fields.as_slice());
|
||||
}
|
||||
ast::PatIdent(_, _, _) => {
|
||||
// it might be the only use of a static:
|
||||
self.lookup_and_handle_definition(&pat.id)
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ use middle::freevars::freevar_entry;
|
||||
use middle::freevars;
|
||||
use middle::subst;
|
||||
use middle::ty;
|
||||
use middle::typeck::{MethodCall, NoAdjustment};
|
||||
use middle::typeck;
|
||||
use util::ppaux::{Repr, ty_to_str};
|
||||
use util::ppaux::UserString;
|
||||
@ -20,7 +21,7 @@ use util::ppaux::UserString;
|
||||
use syntax::ast::*;
|
||||
use syntax::attr;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::print::pprust::{expr_to_str,path_to_str};
|
||||
use syntax::print::pprust::{expr_to_str, ident_to_str};
|
||||
use syntax::{visit};
|
||||
use syntax::visit::Visitor;
|
||||
|
||||
@ -261,7 +262,15 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
|
||||
ExprCast(ref source, _) => {
|
||||
let source_ty = ty::expr_ty(cx.tcx, &**source);
|
||||
let target_ty = ty::expr_ty(cx.tcx, e);
|
||||
check_trait_cast(cx, source_ty, target_ty, source.span);
|
||||
let method_call = MethodCall {
|
||||
expr_id: e.id,
|
||||
adjustment: NoAdjustment,
|
||||
};
|
||||
check_trait_cast(cx,
|
||||
source_ty,
|
||||
target_ty,
|
||||
source.span,
|
||||
method_call);
|
||||
}
|
||||
ExprRepeat(ref element, ref count_expr) => {
|
||||
let count = ty::eval_repeat_count(cx.tcx, &**count_expr);
|
||||
@ -281,7 +290,15 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
|
||||
ty::AutoObject(..) => {
|
||||
let source_ty = ty::expr_ty(cx.tcx, e);
|
||||
let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
|
||||
check_trait_cast(cx, source_ty, target_ty, e.span);
|
||||
let method_call = MethodCall {
|
||||
expr_id: e.id,
|
||||
adjustment: typeck::AutoObject,
|
||||
};
|
||||
check_trait_cast(cx,
|
||||
source_ty,
|
||||
target_ty,
|
||||
e.span,
|
||||
method_call);
|
||||
}
|
||||
ty::AutoAddEnv(..) |
|
||||
ty::AutoDerefRef(..) => {}
|
||||
@ -364,15 +381,62 @@ fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) {
|
||||
fn check_type_parameter_bounds_in_vtable_result(
|
||||
cx: &mut Context,
|
||||
span: Span,
|
||||
vtable_res: &typeck::vtable_res) {
|
||||
for origins in vtable_res.iter() {
|
||||
for origin in origins.iter() {
|
||||
let (type_param_defs, substs) = match *origin {
|
||||
typeck::vtable_static(def_id, ref tys, _) => {
|
||||
let type_param_defs =
|
||||
ty::lookup_item_type(cx.tcx, def_id).generics
|
||||
.types
|
||||
.clone();
|
||||
(type_param_defs, (*tys).clone())
|
||||
}
|
||||
_ => {
|
||||
// Nothing to do here.
|
||||
continue
|
||||
}
|
||||
};
|
||||
for type_param_def in type_param_defs.iter() {
|
||||
let typ = substs.types.get(type_param_def.space,
|
||||
type_param_def.index);
|
||||
check_typaram_bounds(cx, span, *typ, type_param_def)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_cast(cx: &mut Context,
|
||||
source_ty: ty::t,
|
||||
target_ty: ty::t,
|
||||
span: Span,
|
||||
method_call: MethodCall) {
|
||||
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
|
||||
match ty::get(target_ty).sty {
|
||||
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => match ty::get(ty).sty {
|
||||
ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
|
||||
check_trait_cast_bounds(cx, span, source_ty, bounds);
|
||||
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
|
||||
match cx.tcx.vtable_map.borrow().find(&method_call) {
|
||||
None => {
|
||||
cx.tcx.sess.span_bug(span,
|
||||
"trait cast not in vtable \
|
||||
map?!")
|
||||
}
|
||||
Some(vtable_res) => {
|
||||
check_type_parameter_bounds_in_vtable_result(
|
||||
cx,
|
||||
span,
|
||||
vtable_res)
|
||||
}
|
||||
};
|
||||
check_trait_cast_bounds(cx, span, source_ty, bounds);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -627,7 +691,7 @@ fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
|
||||
fn check_pat(cx: &mut Context, pat: &Pat) {
|
||||
let var_name = match pat.node {
|
||||
PatWild => Some("_".to_string()),
|
||||
PatIdent(_, ref path, _) => Some(path_to_str(path).to_string()),
|
||||
PatIdent(_, ref path1, _) => Some(ident_to_str(&path1.node).to_string()),
|
||||
_ => None
|
||||
};
|
||||
|
||||
|
@ -367,9 +367,9 @@ fn visit_fn(ir: &mut IrMaps,
|
||||
for arg in decl.inputs.iter() {
|
||||
pat_util::pat_bindings(&ir.tcx.def_map,
|
||||
&*arg.pat,
|
||||
|_bm, arg_id, _x, path| {
|
||||
|_bm, arg_id, _x, path1| {
|
||||
debug!("adding argument {}", arg_id);
|
||||
let ident = ast_util::path_to_ident(path);
|
||||
let ident = path1.node;
|
||||
fn_maps.add_variable(Arg(arg_id, ident));
|
||||
})
|
||||
};
|
||||
@ -399,9 +399,9 @@ fn visit_fn(ir: &mut IrMaps,
|
||||
}
|
||||
|
||||
fn visit_local(ir: &mut IrMaps, local: &Local) {
|
||||
pat_util::pat_bindings(&ir.tcx.def_map, &*local.pat, |_, p_id, sp, path| {
|
||||
pat_util::pat_bindings(&ir.tcx.def_map, &*local.pat, |_, p_id, sp, path1| {
|
||||
debug!("adding local variable {}", p_id);
|
||||
let name = ast_util::path_to_ident(path);
|
||||
let name = path1.node;
|
||||
ir.add_live_node_for_node(p_id, VarDefNode(sp));
|
||||
ir.add_variable(Local(LocalInfo {
|
||||
id: p_id,
|
||||
@ -413,10 +413,10 @@ fn visit_local(ir: &mut IrMaps, local: &Local) {
|
||||
|
||||
fn visit_arm(ir: &mut IrMaps, arm: &Arm) {
|
||||
for pat in arm.pats.iter() {
|
||||
pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path| {
|
||||
pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| {
|
||||
debug!("adding local variable {} from match with bm {:?}",
|
||||
p_id, bm);
|
||||
let name = ast_util::path_to_ident(path);
|
||||
let name = path1.node;
|
||||
ir.add_live_node_for_node(p_id, VarDefNode(sp));
|
||||
ir.add_variable(Local(LocalInfo {
|
||||
id: p_id,
|
||||
@ -1522,10 +1522,10 @@ impl<'a> Liveness<'a> {
|
||||
for arg in decl.inputs.iter() {
|
||||
pat_util::pat_bindings(&self.ir.tcx.def_map,
|
||||
&*arg.pat,
|
||||
|_bm, p_id, sp, path| {
|
||||
|_bm, p_id, sp, path1| {
|
||||
let var = self.variable(p_id, sp);
|
||||
// Ignore unused self.
|
||||
let ident = ast_util::path_to_ident(path);
|
||||
let ident = path1.node;
|
||||
if ident.name != special_idents::self_.name {
|
||||
self.warn_about_unused(sp, p_id, entry_ln, var);
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
Some(adjustment) => {
|
||||
match *adjustment {
|
||||
ty::AutoObject(..) => {
|
||||
// Implicity cast a concrete object to trait object.
|
||||
// Implicitly cast a concrete object to trait object.
|
||||
// Result is an rvalue.
|
||||
let expr_ty = if_ok!(self.expr_ty_adjusted(expr));
|
||||
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
|
||||
|
@ -14,7 +14,7 @@ use middle::resolve;
|
||||
use std::collections::HashMap;
|
||||
use std::gc::{Gc, GC};
|
||||
use syntax::ast::*;
|
||||
use syntax::ast_util::{path_to_ident, walk_pat};
|
||||
use syntax::ast_util::{walk_pat};
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
|
||||
pub type PatIdMap = HashMap<Ident, NodeId>;
|
||||
@ -23,8 +23,8 @@ pub type PatIdMap = HashMap<Ident, NodeId>;
|
||||
// use the NodeId of their namesake in the first pattern.
|
||||
pub fn pat_id_map(dm: &resolve::DefMap, pat: &Pat) -> PatIdMap {
|
||||
let mut map = HashMap::new();
|
||||
pat_bindings(dm, pat, |_bm, p_id, _s, n| {
|
||||
map.insert(path_to_ident(n), p_id);
|
||||
pat_bindings(dm, pat, |_bm, p_id, _s, path1| {
|
||||
map.insert(path1.node, p_id);
|
||||
});
|
||||
map
|
||||
}
|
||||
@ -75,7 +75,7 @@ pub fn pat_is_binding_or_wild(dm: &resolve::DefMap, pat: &Pat) -> bool {
|
||||
/// `match foo() { Some(a) => (), None => () }`
|
||||
pub fn pat_bindings(dm: &resolve::DefMap,
|
||||
pat: &Pat,
|
||||
it: |BindingMode, NodeId, Span, &Path|) {
|
||||
it: |BindingMode, NodeId, Span, &SpannedIdent|) {
|
||||
walk_pat(pat, |p| {
|
||||
match p.node {
|
||||
PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => {
|
||||
@ -102,10 +102,10 @@ pub fn pat_contains_bindings(dm: &resolve::DefMap, pat: &Pat) -> bool {
|
||||
contains_bindings
|
||||
}
|
||||
|
||||
pub fn simple_identifier<'a>(pat: &'a Pat) -> Option<&'a Path> {
|
||||
pub fn simple_identifier<'a>(pat: &'a Pat) -> Option<&'a Ident> {
|
||||
match pat.node {
|
||||
PatIdent(BindByValue(_), ref path, None) => {
|
||||
Some(path)
|
||||
PatIdent(BindByValue(_), ref path1, None) => {
|
||||
Some(&path1.node)
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
|
@ -1267,7 +1267,7 @@ impl<'a> Visitor<()> for VisiblePrivateTypesVisitor<'a> {
|
||||
// error messages without (too many) false positives
|
||||
// (i.e. we could just return here to not check them at
|
||||
// all, or some worse estimation of whether an impl is
|
||||
// publically visible.
|
||||
// publicly visible.
|
||||
ast::ItemImpl(ref g, ref trait_ref, self_, ref methods) => {
|
||||
// `impl [... for] Private` is never visible.
|
||||
let self_contains_private;
|
||||
|
@ -23,11 +23,10 @@ use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
|
||||
use syntax::ast::*;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util::{local_def};
|
||||
use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method};
|
||||
use syntax::ast_util::{walk_pat, trait_method_to_ty_method};
|
||||
use syntax::ext::mtwt;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::parse::token;
|
||||
use syntax::print::pprust::path_to_str;
|
||||
use syntax::codemap::{Span, DUMMY_SP, Pos};
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::visit;
|
||||
@ -1247,7 +1246,7 @@ impl<'a> Resolver<'a> {
|
||||
// Create the module and add all methods.
|
||||
match ty.node {
|
||||
TyPath(ref path, _, _) if path.segments.len() == 1 => {
|
||||
let name = path_to_ident(path);
|
||||
let name = path.segments.last().unwrap().identifier;
|
||||
|
||||
let parent_opt = parent.module().children.borrow()
|
||||
.find_copy(&name.name);
|
||||
@ -4104,8 +4103,8 @@ impl<'a> Resolver<'a> {
|
||||
// user and one 'x' came from the macro.
|
||||
fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
|
||||
let mut result = HashMap::new();
|
||||
pat_bindings(&self.def_map, pat, |binding_mode, _id, sp, path| {
|
||||
let name = mtwt::resolve(path_to_ident(path));
|
||||
pat_bindings(&self.def_map, pat, |binding_mode, _id, sp, path1| {
|
||||
let name = mtwt::resolve(path1.node);
|
||||
result.insert(name,
|
||||
binding_info {span: sp,
|
||||
binding_mode: binding_mode});
|
||||
@ -4314,8 +4313,7 @@ impl<'a> Resolver<'a> {
|
||||
let pat_id = pattern.id;
|
||||
walk_pat(pattern, |pattern| {
|
||||
match pattern.node {
|
||||
PatIdent(binding_mode, ref path, _)
|
||||
if !path.global && path.segments.len() == 1 => {
|
||||
PatIdent(binding_mode, ref path1, _) => {
|
||||
|
||||
// The meaning of pat_ident with no type parameters
|
||||
// depends on whether an enum variant or unit-like struct
|
||||
@ -4326,7 +4324,7 @@ impl<'a> Resolver<'a> {
|
||||
// such a value is simply disallowed (since it's rarely
|
||||
// what you want).
|
||||
|
||||
let ident = path.segments.get(0).identifier;
|
||||
let ident = path1.node;
|
||||
let renamed = mtwt::resolve(ident);
|
||||
|
||||
match self.resolve_bare_identifier_pattern(ident) {
|
||||
@ -4416,57 +4414,12 @@ impl<'a> Resolver<'a> {
|
||||
format!("identifier `{}` is bound \
|
||||
more than once in the same \
|
||||
pattern",
|
||||
path_to_str(path)).as_slice());
|
||||
token::get_ident(ident)).as_slice());
|
||||
}
|
||||
// Else, not bound in the same pattern: do
|
||||
// nothing.
|
||||
}
|
||||
}
|
||||
|
||||
// Check the types in the path pattern.
|
||||
for ty in path.segments
|
||||
.iter()
|
||||
.flat_map(|seg| seg.types.iter()) {
|
||||
self.resolve_type(&**ty);
|
||||
}
|
||||
}
|
||||
|
||||
PatIdent(binding_mode, ref path, _) => {
|
||||
// This must be an enum variant, struct, or constant.
|
||||
match self.resolve_path(pat_id, path, ValueNS, false) {
|
||||
Some(def @ (DefVariant(..), _)) |
|
||||
Some(def @ (DefStruct(..), _)) => {
|
||||
self.record_def(pattern.id, def);
|
||||
}
|
||||
Some(def @ (DefStatic(..), _)) => {
|
||||
self.enforce_default_binding_mode(
|
||||
pattern,
|
||||
binding_mode,
|
||||
"a constant");
|
||||
self.record_def(pattern.id, def);
|
||||
}
|
||||
Some(_) => {
|
||||
self.resolve_error(
|
||||
path.span,
|
||||
format!("`{}` is not an enum variant or constant",
|
||||
token::get_ident(
|
||||
path.segments
|
||||
.last()
|
||||
.unwrap()
|
||||
.identifier)).as_slice())
|
||||
}
|
||||
None => {
|
||||
self.resolve_error(path.span,
|
||||
"unresolved enum variant");
|
||||
}
|
||||
}
|
||||
|
||||
// Check the types in the path pattern.
|
||||
for ty in path.segments
|
||||
.iter()
|
||||
.flat_map(|s| s.types.iter()) {
|
||||
self.resolve_type(&**ty);
|
||||
}
|
||||
}
|
||||
|
||||
PatEnum(ref path, _) => {
|
||||
@ -5202,8 +5155,8 @@ impl<'a> Resolver<'a> {
|
||||
in a static method. Maybe a \
|
||||
`self` argument is missing?");
|
||||
} else {
|
||||
let name = path_to_ident(path).name;
|
||||
let mut msg = match self.find_fallback_in_self_type(name) {
|
||||
let last_name = path.segments.last().unwrap().identifier.name;
|
||||
let mut msg = match self.find_fallback_in_self_type(last_name) {
|
||||
NoSuggestion => {
|
||||
// limit search to 5 to reduce the number
|
||||
// of stupid suggestions
|
||||
|
@ -484,7 +484,7 @@ impl <'l> DxrVisitor<'l> {
|
||||
{
|
||||
let qualname = self.analysis.ty_cx.map.path_to_str(item.id);
|
||||
|
||||
// If the variable is immutable, save the initialising expresion.
|
||||
// If the variable is immutable, save the initialising expression.
|
||||
let value = match mt {
|
||||
ast::MutMutable => String::from_str("<mutable>"),
|
||||
ast::MutImmutable => self.span.snippet(expr.span),
|
||||
@ -845,7 +845,7 @@ impl <'l> DxrVisitor<'l> {
|
||||
let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx, def_id);
|
||||
|
||||
// This incantation is required if the method referenced is a trait's
|
||||
// defailt implementation.
|
||||
// default implementation.
|
||||
let def_id = ty::method(&self.analysis.ty_cx, def_id).provided_source
|
||||
.unwrap_or(def_id);
|
||||
(Some(def_id), decl_id)
|
||||
@ -926,7 +926,7 @@ impl <'l> DxrVisitor<'l> {
|
||||
self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef));
|
||||
visit::walk_pat(self, p, e);
|
||||
}
|
||||
ast::PatIdent(bm, ref path, ref optional_subpattern) => {
|
||||
ast::PatIdent(bm, ref path1, ref optional_subpattern) => {
|
||||
let immut = match bm {
|
||||
// Even if the ref is mut, you can't change the ref, only
|
||||
// the data pointed at, so showing the initialising expression
|
||||
@ -940,7 +940,8 @@ impl <'l> DxrVisitor<'l> {
|
||||
}
|
||||
};
|
||||
// collect path for either visit_local or visit_arm
|
||||
self.collected_paths.push((p.id, path.clone(), immut, recorder::VarRef));
|
||||
let path = ast_util::ident_to_path(path1.span,path1.node);
|
||||
self.collected_paths.push((p.id, path, immut, recorder::VarRef));
|
||||
match *optional_subpattern {
|
||||
None => {}
|
||||
Some(subpattern) => self.visit_pat(&*subpattern, e),
|
||||
@ -1402,7 +1403,7 @@ pub fn process_crate(sess: &Session,
|
||||
info!("Writing output to {}", disp);
|
||||
}
|
||||
|
||||
// Create ouput file.
|
||||
// Create output file.
|
||||
let mut out_name = cratename.clone();
|
||||
out_name.push_str(".csv");
|
||||
root_path.push(out_name);
|
||||
|
@ -224,8 +224,6 @@ use std::rc::Rc;
|
||||
use std::gc::{Gc};
|
||||
use syntax::ast;
|
||||
use syntax::ast::Ident;
|
||||
use syntax::ast_util::path_to_ident;
|
||||
use syntax::ast_util;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token::InternedString;
|
||||
|
||||
@ -429,13 +427,13 @@ fn expand_nested_bindings<'a, 'b>(
|
||||
|
||||
m.iter().map(|br| {
|
||||
match br.pats.get(col).node {
|
||||
ast::PatIdent(_, ref path, Some(inner)) => {
|
||||
ast::PatIdent(_, ref path1, Some(inner)) => {
|
||||
let pats = Vec::from_slice(br.pats.slice(0u, col))
|
||||
.append((vec!(inner))
|
||||
.append(br.pats.slice(col + 1u, br.pats.len())).as_slice());
|
||||
|
||||
let mut bound_ptrs = br.bound_ptrs.clone();
|
||||
bound_ptrs.push((path_to_ident(path), val));
|
||||
bound_ptrs.push((path1.node, val));
|
||||
Match {
|
||||
pats: pats,
|
||||
data: &*br.data,
|
||||
@ -473,9 +471,9 @@ fn enter_match<'a, 'b>(
|
||||
let this = *br.pats.get(col);
|
||||
let mut bound_ptrs = br.bound_ptrs.clone();
|
||||
match this.node {
|
||||
ast::PatIdent(_, ref path, None) => {
|
||||
ast::PatIdent(_, ref path1, None) => {
|
||||
if pat_is_binding(dm, &*this) {
|
||||
bound_ptrs.push((path_to_ident(path), val));
|
||||
bound_ptrs.push((path1.node, val));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -1366,8 +1364,8 @@ fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> BindingsMap {
|
||||
let ccx = bcx.ccx();
|
||||
let tcx = bcx.tcx();
|
||||
let mut bindings_map = HashMap::new();
|
||||
pat_bindings(&tcx.def_map, &*pat, |bm, p_id, span, path| {
|
||||
let ident = path_to_ident(path);
|
||||
pat_bindings(&tcx.def_map, &*pat, |bm, p_id, span, path1| {
|
||||
let ident = path1.node;
|
||||
let variable_ty = node_id_type(bcx, p_id);
|
||||
let llvariable_ty = type_of::type_of(ccx, variable_ty);
|
||||
let tcx = bcx.tcx();
|
||||
@ -1520,10 +1518,10 @@ pub fn store_local<'a>(bcx: &'a Block<'a>,
|
||||
// In such cases, the more general path is unsafe, because
|
||||
// it assumes it is matching against a valid value.
|
||||
match simple_identifier(&*pat) {
|
||||
Some(path) => {
|
||||
Some(ident) => {
|
||||
let var_scope = cleanup::var_scope(tcx, local.id);
|
||||
return mk_binding_alloca(
|
||||
bcx, pat.id, path, BindLocal, var_scope, (),
|
||||
bcx, pat.id, ident, BindLocal, var_scope, (),
|
||||
|(), bcx, v, _| expr::trans_into(bcx, &*init_expr,
|
||||
expr::SaveIn(v)));
|
||||
}
|
||||
@ -1555,10 +1553,10 @@ pub fn store_local<'a>(bcx: &'a Block<'a>,
|
||||
// create dummy memory for the variables if we have no
|
||||
// value to store into them immediately
|
||||
let tcx = bcx.tcx();
|
||||
pat_bindings(&tcx.def_map, &*pat, |_, p_id, _, path| {
|
||||
pat_bindings(&tcx.def_map, &*pat, |_, p_id, _, path1| {
|
||||
let scope = cleanup::var_scope(tcx, p_id);
|
||||
bcx = mk_binding_alloca(
|
||||
bcx, p_id, path, BindLocal, scope, (),
|
||||
bcx, p_id, &path1.node, BindLocal, scope, (),
|
||||
|(), bcx, llval, ty| { zero_mem(bcx, llval, ty); bcx });
|
||||
});
|
||||
bcx
|
||||
@ -1586,7 +1584,7 @@ pub fn store_arg<'a>(mut bcx: &'a Block<'a>,
|
||||
let _icx = push_ctxt("match::store_arg");
|
||||
|
||||
match simple_identifier(&*pat) {
|
||||
Some(path) => {
|
||||
Some(ident) => {
|
||||
// Generate nicer LLVM for the common case of fn a pattern
|
||||
// like `x: T`
|
||||
let arg_ty = node_id_type(bcx, pat.id);
|
||||
@ -1601,7 +1599,7 @@ pub fn store_arg<'a>(mut bcx: &'a Block<'a>,
|
||||
bcx
|
||||
} else {
|
||||
mk_binding_alloca(
|
||||
bcx, pat.id, path, BindArgument, arg_scope, arg,
|
||||
bcx, pat.id, ident, BindArgument, arg_scope, arg,
|
||||
|arg, bcx, llval, _| arg.store_to(bcx, llval))
|
||||
}
|
||||
}
|
||||
@ -1619,17 +1617,16 @@ pub fn store_arg<'a>(mut bcx: &'a Block<'a>,
|
||||
|
||||
fn mk_binding_alloca<'a,A>(bcx: &'a Block<'a>,
|
||||
p_id: ast::NodeId,
|
||||
path: &ast::Path,
|
||||
ident: &ast::Ident,
|
||||
binding_mode: IrrefutablePatternBindingMode,
|
||||
cleanup_scope: cleanup::ScopeId,
|
||||
arg: A,
|
||||
populate: |A, &'a Block<'a>, ValueRef, ty::t| -> &'a Block<'a>)
|
||||
-> &'a Block<'a> {
|
||||
let var_ty = node_id_type(bcx, p_id);
|
||||
let ident = ast_util::path_to_ident(path);
|
||||
|
||||
// Allocate memory on stack for the binding.
|
||||
let llval = alloc_ty(bcx, var_ty, bcx.ident(ident).as_slice());
|
||||
let llval = alloc_ty(bcx, var_ty, bcx.ident(*ident).as_slice());
|
||||
|
||||
// Subtle: be sure that we *populate* the memory *before*
|
||||
// we schedule the cleanup.
|
||||
@ -1687,13 +1684,13 @@ fn bind_irrefutable_pat<'a>(
|
||||
let tcx = bcx.tcx();
|
||||
let ccx = bcx.ccx();
|
||||
match pat.node {
|
||||
ast::PatIdent(pat_binding_mode, ref path, inner) => {
|
||||
ast::PatIdent(pat_binding_mode, ref path1, inner) => {
|
||||
if pat_is_binding(&tcx.def_map, &*pat) {
|
||||
// Allocate the stack slot where the value of this
|
||||
// binding will live and place it into the appropriate
|
||||
// map.
|
||||
bcx = mk_binding_alloca(
|
||||
bcx, pat.id, path, binding_mode, cleanup_scope, (),
|
||||
bcx, pat.id, &path1.node, binding_mode, cleanup_scope, (),
|
||||
|(), bcx, llval, ty| {
|
||||
match pat_binding_mode {
|
||||
ast::BindByValue(_) => {
|
||||
|
@ -842,8 +842,8 @@ pub fn create_local_var_metadata(bcx: &Block, local: &ast::Local) {
|
||||
let cx = bcx.ccx();
|
||||
let def_map = &cx.tcx.def_map;
|
||||
|
||||
pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, path_ref| {
|
||||
let var_ident = ast_util::path_to_ident(path_ref);
|
||||
pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, path1| {
|
||||
let var_ident = path1.node;
|
||||
|
||||
let datum = match bcx.fcx.lllocals.borrow().find_copy(&node_id) {
|
||||
Some(datum) => datum,
|
||||
@ -890,8 +890,8 @@ pub fn create_captured_var_metadata(bcx: &Block,
|
||||
}
|
||||
Some(ast_map::NodeLocal(pat)) | Some(ast_map::NodeArg(pat)) => {
|
||||
match pat.node {
|
||||
ast::PatIdent(_, ref path, _) => {
|
||||
ast_util::path_to_ident(path)
|
||||
ast::PatIdent(_, ref path1, _) => {
|
||||
path1.node
|
||||
}
|
||||
_ => {
|
||||
cx.sess()
|
||||
@ -1007,7 +1007,7 @@ pub fn create_argument_metadata(bcx: &Block, arg: &ast::Arg) {
|
||||
let def_map = &cx.tcx.def_map;
|
||||
let scope_metadata = bcx.fcx.debug_context.get_ref(cx, arg.pat.span).fn_metadata;
|
||||
|
||||
pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, path_ref| {
|
||||
pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, path1| {
|
||||
let llarg = match bcx.fcx.llargs.borrow().find_copy(&node_id) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
@ -1022,8 +1022,6 @@ pub fn create_argument_metadata(bcx: &Block, arg: &ast::Arg) {
|
||||
Referenced variable location is not an alloca!");
|
||||
}
|
||||
|
||||
let argument_ident = ast_util::path_to_ident(path_ref);
|
||||
|
||||
let argument_index = {
|
||||
let counter = &fcx.debug_context.get_ref(cx, span).argument_counter;
|
||||
let argument_index = counter.get();
|
||||
@ -1032,7 +1030,7 @@ pub fn create_argument_metadata(bcx: &Block, arg: &ast::Arg) {
|
||||
};
|
||||
|
||||
declare_local(bcx,
|
||||
argument_ident,
|
||||
path1.node,
|
||||
llarg.ty,
|
||||
scope_metadata,
|
||||
DirectVariable { alloca: llarg.val },
|
||||
@ -3237,10 +3235,9 @@ fn populate_scope_map(cx: &CrateContext,
|
||||
// Push argument identifiers onto the stack so arguments integrate nicely
|
||||
// with variable shadowing.
|
||||
for &arg_pat in arg_pats.iter() {
|
||||
pat_util::pat_bindings(def_map, &*arg_pat, |_, _, _, path_ref| {
|
||||
let ident = ast_util::path_to_ident(path_ref);
|
||||
pat_util::pat_bindings(def_map, &*arg_pat, |_, _, _, path1| {
|
||||
scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
|
||||
ident: Some(ident) });
|
||||
ident: Some(path1.node) });
|
||||
})
|
||||
}
|
||||
|
||||
@ -3348,13 +3345,13 @@ fn populate_scope_map(cx: &CrateContext,
|
||||
// ast_util::walk_pat() here because we have to visit *all* nodes in
|
||||
// order to put them into the scope map. The above functions don't do that.
|
||||
match pat.node {
|
||||
ast::PatIdent(_, ref path_ref, ref sub_pat_opt) => {
|
||||
ast::PatIdent(_, ref path1, ref sub_pat_opt) => {
|
||||
|
||||
// Check if this is a binding. If so we need to put it on the
|
||||
// scope stack and maybe introduce an artificial scope
|
||||
if pat_util::pat_is_binding(def_map, &*pat) {
|
||||
|
||||
let ident = ast_util::path_to_ident(path_ref);
|
||||
let ident = path1.node;
|
||||
|
||||
// LLVM does not properly generate 'DW_AT_start_scope' fields
|
||||
// for variable DIEs. For this reason we have to introduce
|
||||
|
@ -2771,8 +2771,8 @@ pub fn local_var_name_str(cx: &ctxt, id: NodeId) -> InternedString {
|
||||
match cx.map.find(id) {
|
||||
Some(ast_map::NodeLocal(pat)) => {
|
||||
match pat.node {
|
||||
ast::PatIdent(_, ref path, _) => {
|
||||
token::get_ident(ast_util::path_to_ident(path))
|
||||
ast::PatIdent(_, ref path1, _) => {
|
||||
token::get_ident(path1.node)
|
||||
}
|
||||
_ => {
|
||||
cx.sess.bug(
|
||||
|
@ -485,7 +485,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
|
||||
demand::suptype(fcx, pat.span, expected, const_pty.ty);
|
||||
fcx.write_ty(pat.id, const_pty.ty);
|
||||
}
|
||||
ast::PatIdent(bm, ref name, sub) if pat_is_binding(&tcx.def_map, pat) => {
|
||||
ast::PatIdent(bm, ref path1, sub) if pat_is_binding(&tcx.def_map, pat) => {
|
||||
let typ = fcx.local_ty(pat.span, pat.id);
|
||||
|
||||
match bm {
|
||||
@ -507,7 +507,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
|
||||
}
|
||||
}
|
||||
|
||||
let canon_id = *pcx.map.get(&ast_util::path_to_ident(name));
|
||||
let canon_id = *pcx.map.get(&path1.node);
|
||||
if canon_id != pat.id {
|
||||
let ct = fcx.local_ty(pat.span, canon_id);
|
||||
demand::eqtype(fcx, pat.span, ct, typ);
|
||||
@ -521,8 +521,10 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
ast::PatIdent(_, ref path, _) => {
|
||||
check_pat_variant(pcx, pat, path, &Some(Vec::new()), expected);
|
||||
// it's not a binding, it's an enum in disguise:
|
||||
ast::PatIdent(_, ref path1, _) => {
|
||||
let path = ast_util::ident_to_path(path1.span,path1.node);
|
||||
check_pat_variant(pcx, pat, &path, &Some(Vec::new()), expected);
|
||||
}
|
||||
ast::PatEnum(ref path, ref subpats) => {
|
||||
check_pat_variant(pcx, pat, path, subpats, expected);
|
||||
|
@ -406,11 +406,11 @@ impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
|
||||
// Add pattern bindings.
|
||||
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
|
||||
match p.node {
|
||||
ast::PatIdent(_, ref path, _)
|
||||
ast::PatIdent(_, ref path1, _)
|
||||
if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => {
|
||||
self.assign(p.id, None);
|
||||
debug!("Pattern binding {} is assigned to {}",
|
||||
token::get_ident(path.segments.get(0).identifier),
|
||||
token::get_ident(path1.node),
|
||||
self.fcx.infcx().ty_to_str(
|
||||
self.fcx.inh.locals.borrow().get_copy(&p.id)));
|
||||
}
|
||||
|
@ -398,6 +398,9 @@ fn search_for_vtable(vcx: &VtableContext,
|
||||
// Resolve any sub bounds. Note that there still may be free
|
||||
// type variables in substs. This might still be OK: the
|
||||
// process of looking up bounds might constrain some of them.
|
||||
//
|
||||
// This does not check built-in traits because those are handled
|
||||
// later in the kind checking pass.
|
||||
let im_generics =
|
||||
ty::lookup_item_type(tcx, impl_did).generics;
|
||||
let subres = lookup_vtables(vcx,
|
||||
|
@ -93,7 +93,7 @@ pub struct UnificationTable<K,V> {
|
||||
|
||||
/**
|
||||
* At any time, users may snapshot a unification table. The changes
|
||||
* made during the snapshot may either be *commited* or *rolled back*.
|
||||
* made during the snapshot may either be *committed* or *rolled back*.
|
||||
*/
|
||||
pub struct Snapshot<K> {
|
||||
// Ensure that this snapshot is keyed to the table type.
|
||||
@ -152,7 +152,7 @@ impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
|
||||
|
||||
/**
|
||||
* Starts a new snapshot. Each snapshot must be either
|
||||
* rolled back or commited in a "LIFO" (stack) order.
|
||||
* rolled back or committed in a "LIFO" (stack) order.
|
||||
*/
|
||||
pub fn snapshot(&mut self) -> Snapshot<K> {
|
||||
let length = self.undo_log.len();
|
||||
@ -188,12 +188,12 @@ impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
|
||||
match self.undo_log.pop().unwrap() {
|
||||
OpenSnapshot => {
|
||||
// This indicates a failure to obey the stack discipline.
|
||||
tcx.sess.bug("Cannot rollback an uncommited snapshot");
|
||||
tcx.sess.bug("Cannot rollback an uncommitted snapshot");
|
||||
}
|
||||
|
||||
CommittedSnapshot => {
|
||||
// This occurs when there are nested snapshots and
|
||||
// the inner is commited but outer is rolled back.
|
||||
// the inner is committed but outer is rolled back.
|
||||
}
|
||||
|
||||
NewVar(i) => {
|
||||
|
@ -216,9 +216,9 @@ pub type vtable_res = VecPerParamSpace<vtable_param_res>;
|
||||
#[deriving(Clone)]
|
||||
pub enum vtable_origin {
|
||||
/*
|
||||
Statically known vtable. def_id gives the class or impl item
|
||||
Statically known vtable. def_id gives the impl item
|
||||
from whence comes the vtable, and tys are the type substs.
|
||||
vtable_res is the vtable itself
|
||||
vtable_res is the vtable itself.
|
||||
*/
|
||||
vtable_static(ast::DefId, subst::Substs, vtable_res),
|
||||
|
||||
|
@ -1583,8 +1583,6 @@ impl Clean<PathSegment> for ast::PathSegment {
|
||||
}
|
||||
|
||||
fn path_to_str(p: &ast::Path) -> String {
|
||||
use syntax::parse::token;
|
||||
|
||||
let mut s = String::new();
|
||||
let mut first = true;
|
||||
for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) {
|
||||
@ -1739,7 +1737,7 @@ pub struct ViewItem {
|
||||
|
||||
impl Clean<Vec<Item>> for ast::ViewItem {
|
||||
fn clean(&self) -> Vec<Item> {
|
||||
// We consider inlining the documentation of `pub use` statments, but we
|
||||
// We consider inlining the documentation of `pub use` statements, but we
|
||||
// forcefully don't inline if this is not public or if the
|
||||
// #[doc(no_inline)] attribute is present.
|
||||
let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
|
||||
@ -1953,7 +1951,7 @@ fn name_from_pat(p: &ast::Pat) -> String {
|
||||
match p.node {
|
||||
PatWild => "_".to_string(),
|
||||
PatWildMulti => "..".to_string(),
|
||||
PatIdent(_, ref p, _) => path_to_str(p),
|
||||
PatIdent(_, ref p, _) => token::get_ident(p.node).get().to_string(),
|
||||
PatEnum(ref p, _) => path_to_str(p),
|
||||
PatStruct(..) => fail!("tried to get argument name from pat_struct, \
|
||||
which is not allowed in function arguments"),
|
||||
|
@ -376,7 +376,7 @@ pub trait ToCStr {
|
||||
// (without forcing an additional & around &str). So we are instead
|
||||
// temporarily adding an instance for ~str and String, so that we can
|
||||
// take ToCStr as owned. When DST lands, the string instances should
|
||||
// be revisted, and arguments bound by ToCStr should be passed by
|
||||
// be revisited, and arguments bound by ToCStr should be passed by
|
||||
// reference.
|
||||
|
||||
impl<'a> ToCStr for &'a str {
|
||||
|
@ -97,7 +97,7 @@ extern {}
|
||||
|
||||
extern "C" {
|
||||
// iOS on armv7 uses SjLj exceptions and requires to link
|
||||
// agains corresponding routine (..._SjLj_...)
|
||||
// against corresponding routine (..._SjLj_...)
|
||||
#[cfg(not(target_os = "ios", target_arch = "arm"))]
|
||||
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
|
||||
-> _Unwind_Reason_Code;
|
||||
|
@ -170,7 +170,7 @@ impl Task {
|
||||
/// This function can be used as an emulated "try/catch" to interoperate
|
||||
/// with the rust runtime at the outermost boundary. It is not possible to
|
||||
/// use this function in a nested fashion (a try/catch inside of another
|
||||
/// try/catch). Invoking this funciton is quite cheap.
|
||||
/// try/catch). Invoking this function is quite cheap.
|
||||
///
|
||||
/// If the closure `f` succeeds, then the returned task can be used again
|
||||
/// for another invocation of `run`. If the closure `f` fails then `self`
|
||||
@ -276,7 +276,7 @@ impl Task {
|
||||
// 1. If TLD destruction fails, heap destruction will be attempted.
|
||||
// There is a test for this at fail-during-tld-destroy.rs. Sadly the
|
||||
// other way can't be tested due to point 2 above. Note that we must
|
||||
// immortalize the heap first becuase if any deallocations are
|
||||
// immortalize the heap first because if any deallocations are
|
||||
// attempted while TLD is being dropped it will attempt to free the
|
||||
// allocation from the wrong heap (because the current one has been
|
||||
// replaced).
|
||||
|
@ -243,7 +243,7 @@ mod imp {
|
||||
// EINVAL means |stack_size| is either too small or not a
|
||||
// multiple of the system page size. Because it's definitely
|
||||
// >= PTHREAD_STACK_MIN, it must be an alignment issue.
|
||||
// Round up to the neareast page and try again.
|
||||
// Round up to the nearest page and try again.
|
||||
let page_size = libc::sysconf(libc::_SC_PAGESIZE) as uint;
|
||||
let stack_size = (stack_size + page_size - 1) &
|
||||
(-(page_size as int - 1) as uint - 1);
|
||||
|
@ -234,7 +234,7 @@ impl ForbidUnwind {
|
||||
impl Drop for ForbidUnwind {
|
||||
fn drop(&mut self) {
|
||||
assert!(self.failing_before == task::failing(),
|
||||
"didnt want an unwind during: {}", self.msg);
|
||||
"didn't want an unwind during: {}", self.msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ impl StreamWatcher {
|
||||
// immediately as part of the call to alloc_cb. What this means is that
|
||||
// we must be ready for this to happen (by setting the data in the uv
|
||||
// handle). In theory this otherwise doesn't need to happen until after
|
||||
// the read is succesfully started.
|
||||
// the read is successfully started.
|
||||
unsafe { uvll::set_data_for_uv_handle(self.handle, &mut rcx) }
|
||||
|
||||
// Send off the read request, but don't block until we're sure that the
|
||||
|
@ -77,7 +77,7 @@ impl RtioTimer for TimerWatcher {
|
||||
fn sleep(&mut self, msecs: u64) {
|
||||
// As with all of the below functions, we must be extra careful when
|
||||
// destroying the previous action. If the previous action was a channel,
|
||||
// destroying it could invoke a context switch. For these situtations,
|
||||
// destroying it could invoke a context switch. For these situations,
|
||||
// we must temporarily un-home ourselves, then destroy the action, and
|
||||
// then re-home again.
|
||||
let missile = self.fire_homing_missile();
|
||||
|
@ -410,7 +410,7 @@ mod test {
|
||||
// colon after v4
|
||||
let none: Option<IpAddr> = FromStr::from_str("::127.0.0.1:");
|
||||
assert_eq!(None, none);
|
||||
// not enought groups
|
||||
// not enough groups
|
||||
let none: Option<IpAddr> = FromStr::from_str("1.2.3.4.5:127.0.0.1");
|
||||
assert_eq!(None, none);
|
||||
// too many groups
|
||||
|
@ -165,7 +165,7 @@ impl UdpSocket {
|
||||
|
||||
/// Sets the broadcast flag on or off
|
||||
#[experimental]
|
||||
pub fn set_broadast(&mut self, broadcast: bool) -> IoResult<()> {
|
||||
pub fn set_broadcast(&mut self, broadcast: bool) -> IoResult<()> {
|
||||
if broadcast {
|
||||
self.obj.hear_broadcasts()
|
||||
} else {
|
||||
@ -173,6 +173,12 @@ impl UdpSocket {
|
||||
}.map_err(IoError::from_rtio_error)
|
||||
}
|
||||
|
||||
/// Sets the broadcast flag on or off
|
||||
#[deprecated="renamed to `set_broadcast`"]
|
||||
pub fn set_broadast(&mut self, broadcast: bool) -> IoResult<()> {
|
||||
self.set_broadcast(broadcast)
|
||||
}
|
||||
|
||||
/// Sets the read/write timeout for this socket.
|
||||
///
|
||||
/// For more information, see `TcpStream::set_timeout`
|
||||
|
209
src/libstd/os.rs
209
src/libstd/os.rs
@ -45,7 +45,7 @@ use path::{Path, GenericPath, BytesContainer};
|
||||
use ptr::RawPtr;
|
||||
use ptr;
|
||||
use result::{Err, Ok, Result};
|
||||
use slice::{Vector, ImmutableVector, MutableVector};
|
||||
use slice::{Vector, ImmutableVector, MutableVector, ImmutableEqVector};
|
||||
use str::{Str, StrSlice, StrAllocating};
|
||||
use str;
|
||||
use string::String;
|
||||
@ -398,9 +398,9 @@ pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
|
||||
/// None => println!("{} is not defined in the environment.", key)
|
||||
/// }
|
||||
/// ```
|
||||
pub fn setenv(n: &str, v: &str) {
|
||||
pub fn setenv<T: BytesContainer>(n: &str, v: T) {
|
||||
#[cfg(unix)]
|
||||
fn _setenv(n: &str, v: &str) {
|
||||
fn _setenv(n: &str, v: &[u8]) {
|
||||
unsafe {
|
||||
with_env_lock(|| {
|
||||
n.with_c_str(|nbuf| {
|
||||
@ -413,18 +413,20 @@ pub fn setenv(n: &str, v: &str) {
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn _setenv(n: &str, v: &str) {
|
||||
fn _setenv(n: &str, v: &[u8]) {
|
||||
let n: Vec<u16> = n.utf16_units().collect();
|
||||
let n = n.append_one(0);
|
||||
let v: Vec<u16> = v.utf16_units().collect();
|
||||
let v: Vec<u16> = str::from_utf8(v).unwrap().utf16_units().collect();
|
||||
let v = v.append_one(0);
|
||||
|
||||
unsafe {
|
||||
with_env_lock(|| {
|
||||
libc::SetEnvironmentVariableW(n.as_ptr(), v.as_ptr());
|
||||
})
|
||||
}
|
||||
}
|
||||
_setenv(n, v)
|
||||
|
||||
_setenv(n, v.container_as_bytes())
|
||||
}
|
||||
|
||||
/// Remove a variable from the environment entirely.
|
||||
@ -453,77 +455,130 @@ pub fn unsetenv(n: &str) {
|
||||
_unsetenv(n);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
/// Parse a string or vector according to the platform's conventions
|
||||
/// for the `PATH` environment variable and return a Vec<Path>.
|
||||
/// Drops empty paths.
|
||||
/// Parses input according to platform conventions for the `PATH`
|
||||
/// environment variable.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use std::os;
|
||||
///
|
||||
/// let key = "PATH";
|
||||
/// match os::getenv(key) {
|
||||
/// match os::getenv_as_bytes(key) {
|
||||
/// Some(paths) => {
|
||||
/// for path in os::split_paths(paths).iter() {
|
||||
/// println!("'{}'", path.display());
|
||||
/// }
|
||||
/// }
|
||||
/// None => println!("{} is not defined in the environnement.", key)
|
||||
/// None => println!("{} is not defined in the environment.", key)
|
||||
/// }
|
||||
/// ```
|
||||
pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
|
||||
unparsed.container_as_bytes()
|
||||
.split(|b| *b == ':' as u8)
|
||||
.filter(|s| s.len() > 0)
|
||||
.map(Path::new)
|
||||
.collect()
|
||||
}
|
||||
#[cfg(unix)]
|
||||
fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
|
||||
unparsed.container_as_bytes()
|
||||
.split(|b| *b == b':')
|
||||
.map(Path::new)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
/// Parse a string or vector according to the platform's conventions
|
||||
/// for the `PATH` environment variable. Drops empty paths.
|
||||
pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
|
||||
// On Windows, the PATH environment variable is semicolon separated. Double
|
||||
// quotes are used as a way of introducing literal semicolons (since
|
||||
// c:\some;dir is a valid Windows path). Double quotes are not themselves
|
||||
// permitted in path names, so there is no way to escape a double quote.
|
||||
// Quoted regions can appear in arbitrary locations, so
|
||||
//
|
||||
// c:\foo;c:\som"e;di"r;c:\bar
|
||||
//
|
||||
// Should parse as [c:\foo, c:\some;dir, c:\bar].
|
||||
//
|
||||
// (The above is based on testing; there is no clear reference available
|
||||
// for the grammar.)
|
||||
#[cfg(windows)]
|
||||
fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
|
||||
// On Windows, the PATH environment variable is semicolon separated. Double
|
||||
// quotes are used as a way of introducing literal semicolons (since
|
||||
// c:\some;dir is a valid Windows path). Double quotes are not themselves
|
||||
// permitted in path names, so there is no way to escape a double quote.
|
||||
// Quoted regions can appear in arbitrary locations, so
|
||||
//
|
||||
// c:\foo;c:\som"e;di"r;c:\bar
|
||||
//
|
||||
// Should parse as [c:\foo, c:\some;dir, c:\bar].
|
||||
//
|
||||
// (The above is based on testing; there is no clear reference available
|
||||
// for the grammar.)
|
||||
|
||||
let mut parsed = Vec::new();
|
||||
let mut in_progress = Vec::new();
|
||||
let mut in_quote = false;
|
||||
let mut parsed = Vec::new();
|
||||
let mut in_progress = Vec::new();
|
||||
let mut in_quote = false;
|
||||
|
||||
for b in unparsed.container_as_bytes().iter() {
|
||||
match *b as char {
|
||||
';' if !in_quote => {
|
||||
// ignore zero-length path strings
|
||||
if in_progress.len() > 0 {
|
||||
for b in unparsed.container_as_bytes().iter() {
|
||||
match *b {
|
||||
b';' if !in_quote => {
|
||||
parsed.push(Path::new(in_progress.as_slice()));
|
||||
in_progress.truncate(0)
|
||||
}
|
||||
b'"' => {
|
||||
in_quote = !in_quote;
|
||||
}
|
||||
_ => {
|
||||
in_progress.push(*b);
|
||||
}
|
||||
in_progress.truncate(0)
|
||||
}
|
||||
'\"' => {
|
||||
in_quote = !in_quote;
|
||||
}
|
||||
_ => {
|
||||
in_progress.push(*b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if in_progress.len() > 0 {
|
||||
parsed.push(Path::new(in_progress));
|
||||
parsed
|
||||
}
|
||||
|
||||
parsed
|
||||
_split_paths(unparsed)
|
||||
}
|
||||
|
||||
/// Joins a collection of `Path`s appropriately for the `PATH`
|
||||
/// environment variable.
|
||||
///
|
||||
/// Returns a `Vec<u8>` on success, since `Path`s are not utf-8
|
||||
/// encoded on all platforms.
|
||||
///
|
||||
/// Returns an `Err` (containing an error message) if one of the input
|
||||
/// `Path`s contains an invalid character for constructing the `PATH`
|
||||
/// variable (a double quote on Windows or a colon on Unix).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::os;
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// let key = "PATH";
|
||||
/// let mut paths = os::getenv_as_bytes(key).map_or(Vec::new(), os::split_paths);
|
||||
/// paths.push(Path::new("/home/xyz/bin"));
|
||||
/// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
|
||||
/// ```
|
||||
pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
|
||||
#[cfg(windows)]
|
||||
fn _join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
|
||||
let mut joined = Vec::new();
|
||||
let sep = b';';
|
||||
|
||||
for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
|
||||
if i > 0 { joined.push(sep) }
|
||||
if path.contains(&b'"') {
|
||||
return Err("path segment contains `\"`");
|
||||
} else if path.contains(&sep) {
|
||||
joined.push(b'"');
|
||||
joined.push_all(path);
|
||||
joined.push(b'"');
|
||||
} else {
|
||||
joined.push_all(path);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(joined)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn _join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
|
||||
let mut joined = Vec::new();
|
||||
let sep = b':';
|
||||
|
||||
for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
|
||||
if i > 0 { joined.push(sep) }
|
||||
if path.contains(&sep) { return Err("path segment contains separator `:`") }
|
||||
joined.push_all(path);
|
||||
}
|
||||
|
||||
Ok(joined)
|
||||
}
|
||||
|
||||
_join_paths(paths)
|
||||
}
|
||||
|
||||
/// A low-level OS in-memory pipe.
|
||||
@ -1767,7 +1822,7 @@ mod tests {
|
||||
use c_str::ToCStr;
|
||||
use option;
|
||||
use os::{env, getcwd, getenv, make_absolute};
|
||||
use os::{split_paths, setenv, unsetenv};
|
||||
use os::{split_paths, join_paths, setenv, unsetenv};
|
||||
use os;
|
||||
use rand::Rng;
|
||||
use rand;
|
||||
@ -2032,11 +2087,11 @@ mod tests {
|
||||
parsed.iter().map(|s| Path::new(*s)).collect()
|
||||
}
|
||||
|
||||
assert!(check_parse("", []));
|
||||
assert!(check_parse(r#""""#, []));
|
||||
assert!(check_parse(";;", []));
|
||||
assert!(check_parse("", [""]));
|
||||
assert!(check_parse(r#""""#, [""]));
|
||||
assert!(check_parse(";;", ["", "", ""]));
|
||||
assert!(check_parse(r"c:\", [r"c:\"]));
|
||||
assert!(check_parse(r"c:\;", [r"c:\"]));
|
||||
assert!(check_parse(r"c:\;", [r"c:\", ""]));
|
||||
assert!(check_parse(r"c:\;c:\Program Files\",
|
||||
[r"c:\", r"c:\Program Files\"]));
|
||||
assert!(check_parse(r#"c:\;c:\"foo"\"#, [r"c:\", r"c:\foo\"]));
|
||||
@ -2052,12 +2107,44 @@ mod tests {
|
||||
parsed.iter().map(|s| Path::new(*s)).collect()
|
||||
}
|
||||
|
||||
assert!(check_parse("", []));
|
||||
assert!(check_parse("::", []));
|
||||
assert!(check_parse("", [""]));
|
||||
assert!(check_parse("::", ["", "", ""]));
|
||||
assert!(check_parse("/", ["/"]));
|
||||
assert!(check_parse("/:", ["/"]));
|
||||
assert!(check_parse("/:", ["/", ""]));
|
||||
assert!(check_parse("/:/usr/local", ["/", "/usr/local"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn join_paths_unix() {
|
||||
fn test_eq(input: &[&str], output: &str) -> bool {
|
||||
join_paths(input).unwrap().as_slice() == output.as_bytes()
|
||||
}
|
||||
|
||||
assert!(test_eq([], ""));
|
||||
assert!(test_eq(["/bin", "/usr/bin", "/usr/local/bin"],
|
||||
"/bin:/usr/bin:/usr/local/bin"));
|
||||
assert!(test_eq(["", "/bin", "", "", "/usr/bin", ""],
|
||||
":/bin:::/usr/bin:"));
|
||||
assert!(join_paths(["/te:st"]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn join_paths_windows() {
|
||||
fn test_eq(input: &[&str], output: &str) -> bool {
|
||||
join_paths(input).unwrap().as_slice() == output.as_bytes()
|
||||
}
|
||||
|
||||
assert!(test_eq([], ""));
|
||||
assert!(test_eq([r"c:\windows", r"c:\"],
|
||||
r"c:\windows;c:\"));
|
||||
assert!(test_eq(["", r"c:\windows", "", "", r"c:\", ""],
|
||||
r";c:\windows;;;c:\;"));
|
||||
assert!(test_eq([r"c:\te;st", r"c:\"],
|
||||
r#""c:\te;st";c:\"#));
|
||||
assert!(join_paths([r#"c:\te"st"#]).is_err());
|
||||
}
|
||||
|
||||
// More recursive_mkdir tests are in extra::tempfile
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ mod imp {
|
||||
}
|
||||
|
||||
// while it doesn't requires lock for work as everything is
|
||||
// local, it still displays much nicier backtraces when a
|
||||
// local, it still displays much nicer backtraces when a
|
||||
// couple of tasks fail simultaneously
|
||||
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
||||
let _g = unsafe { LOCK.lock() };
|
||||
|
@ -354,7 +354,7 @@ impl<T: Send> Packet<T> {
|
||||
}
|
||||
|
||||
// We woke ourselves up from select. Assert that the task should be
|
||||
// trashed and returne that we don't have any data.
|
||||
// trashed and returned that we don't have any data.
|
||||
n => {
|
||||
let t = unsafe { BlockedTask::cast_from_uint(n) };
|
||||
t.trash();
|
||||
|
@ -81,7 +81,7 @@ impl<T: Send> Packet<T> {
|
||||
|
||||
// This function should be used after newly created Packet
|
||||
// was wrapped with an Arc
|
||||
// In other case mutex data will be duplicated while clonning
|
||||
// In other case mutex data will be duplicated while cloning
|
||||
// and that could cause problems on platforms where it is
|
||||
// represented by opaque data structure
|
||||
pub fn postinit_lock(&mut self) {
|
||||
@ -140,7 +140,7 @@ impl<T: Send> Packet<T> {
|
||||
// See Port::drop for what's going on
|
||||
if self.port_dropped.load(atomics::SeqCst) { return Err(t) }
|
||||
|
||||
// Note that the multiple sender case is a little tricker
|
||||
// Note that the multiple sender case is a little trickier
|
||||
// semantically than the single sender case. The logic for
|
||||
// incrementing is "add and if disconnected store disconnected".
|
||||
// This could end up leading some senders to believe that there
|
||||
|
@ -215,7 +215,7 @@ impl StaticMutex {
|
||||
None => {}
|
||||
}
|
||||
|
||||
// After we've failed the fast path, then we delegate to the differnet
|
||||
// After we've failed the fast path, then we delegate to the different
|
||||
// locking protocols for green/native tasks. This will select two tasks
|
||||
// to continue further (one native, one green).
|
||||
let t: Box<Task> = Local::take();
|
||||
|
@ -293,8 +293,8 @@ pub enum Pat_ {
|
||||
// In the nullary enum case, the parser can't determine
|
||||
// which it is. The resolver determines this, and
|
||||
// records this pattern's NodeId in an auxiliary
|
||||
// set (of "pat_idents that refer to nullary enums")
|
||||
PatIdent(BindingMode, Path, Option<Gc<Pat>>),
|
||||
// set (of "PatIdents that refer to nullary enums")
|
||||
PatIdent(BindingMode, SpannedIdent, Option<Gc<Pat>>),
|
||||
PatEnum(Path, Option<Vec<Gc<Pat>>>), /* "none" means a * pattern where
|
||||
* we don't bind the fields to names */
|
||||
PatStruct(Path, Vec<FieldPat>, bool),
|
||||
@ -818,7 +818,7 @@ pub struct Arg {
|
||||
|
||||
impl Arg {
|
||||
pub fn new_self(span: Span, mutability: Mutability) -> Arg {
|
||||
let path = ast_util::ident_to_path(span, special_idents::self_);
|
||||
let path = Spanned{span:span,node:special_idents::self_};
|
||||
Arg {
|
||||
// HACK(eddyb) fake type for the self argument.
|
||||
ty: P(Ty {
|
||||
|
@ -33,12 +33,6 @@ pub fn path_name_i(idents: &[Ident]) -> String {
|
||||
}).collect::<Vec<String>>().connect("::")
|
||||
}
|
||||
|
||||
// totally scary function: ignores all but the last element, should have
|
||||
// a different name
|
||||
pub fn path_to_ident(path: &Path) -> Ident {
|
||||
path.segments.last().unwrap().identifier
|
||||
}
|
||||
|
||||
pub fn local_def(id: NodeId) -> DefId {
|
||||
ast::DefId { krate: LOCAL_CRATE, node: id }
|
||||
}
|
||||
@ -186,6 +180,8 @@ pub fn block_from_expr(e: Gc<Expr>) -> P<Block> {
|
||||
})
|
||||
}
|
||||
|
||||
// convert a span and an identifier to the corresponding
|
||||
// 1-segment path
|
||||
pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
|
||||
ast::Path {
|
||||
span: s,
|
||||
@ -202,7 +198,7 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
|
||||
|
||||
pub fn ident_to_pat(id: NodeId, s: Span, i: Ident) -> Gc<Pat> {
|
||||
box(GC) ast::Pat { id: id,
|
||||
node: PatIdent(BindByValue(MutImmutable), ident_to_path(s, i), None),
|
||||
node: PatIdent(BindByValue(MutImmutable), codemap::Spanned{span:s, node:i}, None),
|
||||
span: s }
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@ use ast;
|
||||
use codemap::Span;
|
||||
use ext::base;
|
||||
use ext::base::*;
|
||||
use parse;
|
||||
use parse::token::InternedString;
|
||||
use parse::token;
|
||||
|
||||
@ -48,12 +47,7 @@ static OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
|
||||
|
||||
pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||
-> Box<base::MacResult> {
|
||||
let mut p = parse::new_parser_from_tts(cx.parse_sess(),
|
||||
cx.cfg(),
|
||||
tts.iter()
|
||||
.map(|x| (*x).clone())
|
||||
.collect());
|
||||
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
let mut asm = InternedString::new("");
|
||||
let mut asm_str_style = None;
|
||||
let mut outputs = Vec::new();
|
||||
|
@ -15,6 +15,7 @@ use codemap::{CodeMap, Span, ExpnInfo};
|
||||
use ext;
|
||||
use ext::expand;
|
||||
use parse;
|
||||
use parse::parser;
|
||||
use parse::token;
|
||||
use parse::token::{InternedString, intern, str_to_ident};
|
||||
use util::small_vector::SmallVector;
|
||||
@ -433,6 +434,11 @@ impl<'a> ExtCtxt<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_parser_from_tts(&self, tts: &[ast::TokenTree])
|
||||
-> parser::Parser<'a> {
|
||||
parse::tts_to_parser(self.parse_sess, Vec::from_slice(tts), self.cfg())
|
||||
}
|
||||
|
||||
pub fn codemap(&self) -> &'a CodeMap { &self.parse_sess.span_diagnostic.cm }
|
||||
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
|
||||
pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
|
||||
@ -472,7 +478,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
}
|
||||
/// Emit `msg` attached to `sp`, and stop compilation immediately.
|
||||
///
|
||||
/// `span_err` should be strongly prefered where-ever possible:
|
||||
/// `span_err` should be strongly preferred where-ever possible:
|
||||
/// this should *only* be used when
|
||||
/// - continuing has a high risk of flow-on errors (e.g. errors in
|
||||
/// declaring a macro would cause all uses of that macro to
|
||||
@ -586,11 +592,7 @@ pub fn get_single_str_from_tts(cx: &ExtCtxt,
|
||||
pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
|
||||
sp: Span,
|
||||
tts: &[ast::TokenTree]) -> Option<Vec<Gc<ast::Expr>>> {
|
||||
let mut p = parse::new_parser_from_tts(cx.parse_sess(),
|
||||
cx.cfg(),
|
||||
tts.iter()
|
||||
.map(|x| (*x).clone())
|
||||
.collect());
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
let mut es = Vec::new();
|
||||
while p.token != token::EOF {
|
||||
es.push(cx.expand_expr(p.parse_expr()));
|
||||
|
@ -759,8 +759,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
span: Span,
|
||||
ident: ast::Ident,
|
||||
bm: ast::BindingMode) -> Gc<ast::Pat> {
|
||||
let path = self.path_ident(span, ident);
|
||||
let pat = ast::PatIdent(bm, path, None);
|
||||
let pat = ast::PatIdent(bm, Spanned{span: span, node: ident}, None);
|
||||
self.pat(span, pat)
|
||||
}
|
||||
fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<Gc<ast::Pat>> ) -> Gc<ast::Pat> {
|
||||
|
@ -24,17 +24,11 @@ use attr::*;
|
||||
use parse::attr::ParserAttr;
|
||||
use parse::token::InternedString;
|
||||
use parse::token;
|
||||
use parse;
|
||||
|
||||
|
||||
pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||
-> Box<base::MacResult> {
|
||||
let mut p = parse::new_parser_from_tts(cx.parse_sess(),
|
||||
cx.cfg(),
|
||||
tts.iter()
|
||||
.map(|x| (*x).clone())
|
||||
.collect());
|
||||
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
let mut cfgs = Vec::new();
|
||||
// parse `cfg!(meta_item, meta_item(x,y), meta_item="foo", ...)`
|
||||
while p.token != token::EOF {
|
||||
|
@ -834,7 +834,7 @@ impl<'a> MethodDef<'a> {
|
||||
generic `deriving`");
|
||||
}
|
||||
|
||||
// `ref` inside let matches is buggy. Causes havoc wih rusc.
|
||||
// `ref` inside let matches is buggy. Causes havoc with rusc.
|
||||
// let (variant_index, ref self_vec) = matches_so_far[0];
|
||||
let (variant, self_vec) = match matches_so_far.get(0) {
|
||||
&(_, v, ref s) => (v, s)
|
||||
@ -1049,7 +1049,7 @@ impl<'a> TraitDef<'a> {
|
||||
|
||||
fn create_subpatterns(&self,
|
||||
cx: &mut ExtCtxt,
|
||||
field_paths: Vec<ast::Path> ,
|
||||
field_paths: Vec<ast::SpannedIdent> ,
|
||||
mutbl: ast::Mutability)
|
||||
-> Vec<Gc<ast::Pat>> {
|
||||
field_paths.iter().map(|path| {
|
||||
@ -1095,15 +1095,10 @@ impl<'a> TraitDef<'a> {
|
||||
cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
|
||||
}
|
||||
};
|
||||
let path =
|
||||
cx.path_ident(sp,
|
||||
cx.ident_of(format!("{}_{}",
|
||||
prefix,
|
||||
i).as_slice()));
|
||||
paths.push(path.clone());
|
||||
let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
|
||||
paths.push(codemap::Spanned{span: sp, node: ident});
|
||||
let val = cx.expr(
|
||||
sp, ast::ExprParen(
|
||||
cx.expr_deref(sp, cx.expr_path(path))));
|
||||
sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
|
||||
ident_expr.push((sp, opt_id, val));
|
||||
}
|
||||
|
||||
@ -1145,15 +1140,11 @@ impl<'a> TraitDef<'a> {
|
||||
let mut ident_expr = Vec::new();
|
||||
for (i, va) in variant_args.iter().enumerate() {
|
||||
let sp = self.set_expn_info(cx, va.ty.span);
|
||||
let path =
|
||||
cx.path_ident(sp,
|
||||
cx.ident_of(format!("{}_{}",
|
||||
prefix,
|
||||
i).as_slice()));
|
||||
|
||||
paths.push(path.clone());
|
||||
let val = cx.expr(
|
||||
sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path))));
|
||||
let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
|
||||
let path1 = codemap::Spanned{span: sp, node: ident};
|
||||
paths.push(path1);
|
||||
let expr_path = cx.expr_path(cx.path_ident(sp, ident));
|
||||
let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
|
||||
ident_expr.push((sp, None, val));
|
||||
}
|
||||
|
||||
|
@ -705,22 +705,10 @@ impl Visitor<()> for NameFinderContext {
|
||||
// we found a pat_ident!
|
||||
ast::Pat {
|
||||
id: _,
|
||||
node: ast::PatIdent(_, ref path, ref inner),
|
||||
node: ast::PatIdent(_, ref path1, ref inner),
|
||||
span: _
|
||||
} => {
|
||||
match path {
|
||||
// a path of length one:
|
||||
&ast::Path {
|
||||
global: false,
|
||||
span: _,
|
||||
segments: ref segments
|
||||
} if segments.len() == 1 => {
|
||||
self.ident_accumulator.push(segments.get(0)
|
||||
.identifier)
|
||||
}
|
||||
// I believe these must be enums...
|
||||
_ => ()
|
||||
}
|
||||
self.ident_accumulator.push(path1.node);
|
||||
// visit optional subpattern of pat_ident:
|
||||
for subpat in inner.iter() {
|
||||
self.visit_pat(&**subpat, ())
|
||||
@ -1307,7 +1295,7 @@ mod test {
|
||||
}
|
||||
|
||||
// create a really evil test case where a $x appears inside a binding of $x
|
||||
// but *shouldnt* bind because it was inserted by a different macro....
|
||||
// but *shouldn't* bind because it was inserted by a different macro....
|
||||
// can't write this test case until we have macro-generating macros.
|
||||
|
||||
// FIXME #9383 : lambda var hygiene
|
||||
|
@ -16,7 +16,6 @@ use ext::base;
|
||||
use ext::build::AstBuilder;
|
||||
use parse::token::InternedString;
|
||||
use parse::token;
|
||||
use rsparse = parse;
|
||||
|
||||
use parse = fmt_macros;
|
||||
use std::collections::HashMap;
|
||||
@ -81,11 +80,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, allow_method: bool,
|
||||
let mut names = HashMap::<String, Gc<ast::Expr>>::new();
|
||||
let mut order = Vec::new();
|
||||
|
||||
let mut p = rsparse::new_parser_from_tts(ecx.parse_sess(),
|
||||
ecx.cfg(),
|
||||
tts.iter()
|
||||
.map(|x| (*x).clone())
|
||||
.collect());
|
||||
let mut p = ecx.new_parser_from_tts(tts);
|
||||
// Parse the leading function expression (maybe a block, maybe a path)
|
||||
let invocation = if allow_method {
|
||||
let e = p.parse_expr();
|
||||
|
@ -15,7 +15,6 @@ use ext::base;
|
||||
use ext::build::AstBuilder;
|
||||
use parse::token::*;
|
||||
use parse::token;
|
||||
use parse;
|
||||
|
||||
use std::gc::Gc;
|
||||
|
||||
@ -583,11 +582,7 @@ fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||
// it has to do with transition away from supporting old-style macros, so
|
||||
// try removing it when enough of them are gone.
|
||||
|
||||
let mut p = parse::new_parser_from_tts(cx.parse_sess(),
|
||||
cx.cfg(),
|
||||
tts.iter()
|
||||
.map(|x| (*x).clone())
|
||||
.collect());
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
p.quote_depth += 1u;
|
||||
|
||||
let cx_expr = p.parse_expr();
|
||||
|
@ -791,9 +791,10 @@ pub fn noop_fold_pat<T: Folder>(p: Gc<Pat>, folder: &mut T) -> Gc<Pat> {
|
||||
let node = match p.node {
|
||||
PatWild => PatWild,
|
||||
PatWildMulti => PatWildMulti,
|
||||
PatIdent(binding_mode, ref pth, ref sub) => {
|
||||
PatIdent(binding_mode, ref pth1, ref sub) => {
|
||||
PatIdent(binding_mode,
|
||||
folder.fold_path(pth),
|
||||
Spanned{span: folder.new_span(pth1.span),
|
||||
node: folder.fold_ident(pth1.node)},
|
||||
sub.map(|x| folder.fold_pat(x)))
|
||||
}
|
||||
PatLit(e) => PatLit(folder.fold_expr(e)),
|
||||
|
@ -594,23 +594,15 @@ mod test {
|
||||
#[test] fn parse_ident_pat () {
|
||||
let sess = new_parse_sess();
|
||||
let mut parser = string_to_parser(&sess, "b".to_string());
|
||||
assert!(parser.parse_pat() ==
|
||||
box(GC) ast::Pat{id: ast::DUMMY_NODE_ID,
|
||||
node: ast::PatIdent(
|
||||
ast::BindByValue(ast::MutImmutable),
|
||||
ast::Path {
|
||||
span:sp(0,1),
|
||||
global:false,
|
||||
segments: vec!(
|
||||
ast::PathSegment {
|
||||
identifier: str_to_ident("b"),
|
||||
lifetimes: Vec::new(),
|
||||
types: OwnedSlice::empty(),
|
||||
}
|
||||
),
|
||||
},
|
||||
None /* no idea */),
|
||||
span: sp(0,1)});
|
||||
assert!(parser.parse_pat()
|
||||
== box(GC) ast::Pat{
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::PatIdent(ast::BindByValue(ast::MutImmutable),
|
||||
Spanned{ span:sp(0, 1),
|
||||
node: str_to_ident("b")
|
||||
},
|
||||
None),
|
||||
span: sp(0,1)});
|
||||
parser_done(parser);
|
||||
}
|
||||
|
||||
@ -643,24 +635,15 @@ mod test {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::PatIdent(
|
||||
ast::BindByValue(ast::MutImmutable),
|
||||
ast::Path {
|
||||
span:sp(6,7),
|
||||
global:false,
|
||||
segments: vec!(
|
||||
ast::PathSegment {
|
||||
identifier:
|
||||
str_to_ident("b"),
|
||||
lifetimes: Vec::new(),
|
||||
types: OwnedSlice::empty(),
|
||||
}
|
||||
),
|
||||
},
|
||||
None // no idea
|
||||
),
|
||||
span: sp(6,7)
|
||||
},
|
||||
id: ast::DUMMY_NODE_ID
|
||||
}),
|
||||
Spanned{
|
||||
span: sp(6,7),
|
||||
node: str_to_ident("b")},
|
||||
None
|
||||
),
|
||||
span: sp(6,7)
|
||||
},
|
||||
id: ast::DUMMY_NODE_ID
|
||||
}),
|
||||
output: ast::P(ast::Ty{id: ast::DUMMY_NODE_ID,
|
||||
node: ast::TyNil,
|
||||
span:sp(15,15)}), // not sure
|
||||
|
@ -58,7 +58,7 @@ use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
|
||||
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
|
||||
use ast::Visibility;
|
||||
use ast;
|
||||
use ast_util::{as_prec, lit_is_str, operator_prec};
|
||||
use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
|
||||
use ast_util;
|
||||
use codemap::{Span, BytePos, Spanned, spanned, mk_sp};
|
||||
use codemap;
|
||||
@ -2854,8 +2854,7 @@ impl<'a> Parser<'a> {
|
||||
self.bump();
|
||||
self.parse_pat()
|
||||
} else {
|
||||
let fieldpath = ast_util::ident_to_path(self.last_span,
|
||||
fieldname);
|
||||
let fieldpath = codemap::Spanned{span:self.last_span, node: fieldname};
|
||||
box(GC) ast::Pat {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: PatIdent(bind_type, fieldpath, None),
|
||||
@ -2961,6 +2960,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// at this point, token != _, ~, &, &&, (, [
|
||||
|
||||
if (!is_ident_or_path(&self.token) && self.token != token::MOD_SEP)
|
||||
|| self.is_keyword(keywords::True)
|
||||
@ -3017,7 +3017,9 @@ impl<'a> Parser<'a> {
|
||||
let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);
|
||||
pat = PatRange(start, end);
|
||||
} else if is_plain_ident(&self.token) && !can_be_enum_or_struct {
|
||||
let name = self.parse_path(NoTypesAllowed).path;
|
||||
let id = self.parse_ident();
|
||||
let id_span = self.last_span;
|
||||
let pth1 = codemap::Spanned{span:id_span, node: id};
|
||||
if self.eat(&token::NOT) {
|
||||
// macro invocation
|
||||
let ket = token::close_delimiter_for(&self.token)
|
||||
@ -3028,7 +3030,7 @@ impl<'a> Parser<'a> {
|
||||
seq_sep_none(),
|
||||
|p| p.parse_token_tree());
|
||||
|
||||
let mac = MacInvocTT(name, tts, EMPTY_CTXT);
|
||||
let mac = MacInvocTT(ident_to_path(id_span,id), tts, EMPTY_CTXT);
|
||||
pat = ast::PatMac(codemap::Spanned {node: mac, span: self.span});
|
||||
} else {
|
||||
let sub = if self.eat(&token::AT) {
|
||||
@ -3038,7 +3040,7 @@ impl<'a> Parser<'a> {
|
||||
// or just foo
|
||||
None
|
||||
};
|
||||
pat = PatIdent(BindByValue(MutImmutable), name, sub);
|
||||
pat = PatIdent(BindByValue(MutImmutable), pth1, sub);
|
||||
}
|
||||
} else {
|
||||
// parse an enum pat
|
||||
@ -3084,8 +3086,11 @@ impl<'a> Parser<'a> {
|
||||
// or an identifier pattern, resolve
|
||||
// will sort it out:
|
||||
pat = PatIdent(BindByValue(MutImmutable),
|
||||
enum_path,
|
||||
None);
|
||||
codemap::Spanned{
|
||||
span: enum_path.span,
|
||||
node: enum_path.segments.get(0)
|
||||
.identifier},
|
||||
None);
|
||||
} else {
|
||||
pat = PatEnum(enum_path, Some(args));
|
||||
}
|
||||
@ -3115,7 +3120,7 @@ impl<'a> Parser<'a> {
|
||||
"expected identifier, found path");
|
||||
}
|
||||
// why a path here, and not just an identifier?
|
||||
let name = self.parse_path(NoTypesAllowed).path;
|
||||
let name = codemap::Spanned{span: self.last_span, node: self.parse_ident()};
|
||||
let sub = if self.eat(&token::AT) {
|
||||
Some(self.parse_pat())
|
||||
} else {
|
||||
@ -3243,7 +3248,7 @@ impl<'a> Parser<'a> {
|
||||
None => {
|
||||
// we only expect an ident if we didn't parse one
|
||||
// above.
|
||||
let ident_str = if id == token::special_idents::invalid {
|
||||
let ident_str = if id.name == token::special_idents::invalid.name {
|
||||
"identifier, "
|
||||
} else {
|
||||
""
|
||||
@ -3263,7 +3268,7 @@ impl<'a> Parser<'a> {
|
||||
);
|
||||
let hi = self.span.hi;
|
||||
|
||||
if id == token::special_idents::invalid {
|
||||
if id.name == token::special_idents::invalid.name {
|
||||
return box(GC) spanned(lo, hi, StmtMac(
|
||||
spanned(lo, hi, MacInvocTT(pth, tts, EMPTY_CTXT)), false));
|
||||
} else {
|
||||
|
@ -196,6 +196,10 @@ pub fn path_to_str(p: &ast::Path) -> String {
|
||||
to_str(|s| s.print_path(p, false))
|
||||
}
|
||||
|
||||
pub fn ident_to_str(id: &ast::Ident) -> String {
|
||||
to_str(|s| s.print_ident(*id))
|
||||
}
|
||||
|
||||
pub fn fun_to_str(decl: &ast::FnDecl, fn_style: ast::FnStyle, name: ast::Ident,
|
||||
opt_explicit_self: Option<ast::ExplicitSelf_>,
|
||||
generics: &ast::Generics) -> String {
|
||||
@ -1705,7 +1709,7 @@ impl<'a> State<'a> {
|
||||
match pat.node {
|
||||
ast::PatWild => try!(word(&mut self.s, "_")),
|
||||
ast::PatWildMulti => try!(word(&mut self.s, "..")),
|
||||
ast::PatIdent(binding_mode, ref path, sub) => {
|
||||
ast::PatIdent(binding_mode, ref path1, sub) => {
|
||||
match binding_mode {
|
||||
ast::BindByRef(mutbl) => {
|
||||
try!(self.word_nbsp("ref"));
|
||||
@ -1716,7 +1720,7 @@ impl<'a> State<'a> {
|
||||
try!(self.word_nbsp("mut"));
|
||||
}
|
||||
}
|
||||
try!(self.print_path(path, true));
|
||||
try!(self.print_ident(path1.node));
|
||||
match sub {
|
||||
Some(ref p) => {
|
||||
try!(word(&mut self.s, "@"));
|
||||
@ -2148,9 +2152,8 @@ impl<'a> State<'a> {
|
||||
ast::TyInfer => try!(self.print_pat(&*input.pat)),
|
||||
_ => {
|
||||
match input.pat.node {
|
||||
ast::PatIdent(_, ref path, _) if
|
||||
path.segments.len() == 1 &&
|
||||
path.segments.get(0).identifier.name ==
|
||||
ast::PatIdent(_, ref path1, _) if
|
||||
path1.node.name ==
|
||||
parse::token::special_idents::invalid.name => {
|
||||
// Do nothing.
|
||||
}
|
||||
|
@ -454,8 +454,8 @@ pub fn walk_pat<E: Clone, V: Visitor<E>>(visitor: &mut V, pattern: &Pat, env: E)
|
||||
PatRegion(ref subpattern) => {
|
||||
visitor.visit_pat(&**subpattern, env)
|
||||
}
|
||||
PatIdent(_, ref path, ref optional_subpattern) => {
|
||||
visitor.visit_path(path, pattern.id, env.clone());
|
||||
PatIdent(_, ref pth1, ref optional_subpattern) => {
|
||||
visitor.visit_ident(pth1.span, pth1.node, env.clone());
|
||||
match *optional_subpattern {
|
||||
None => {}
|
||||
Some(ref subpattern) => visitor.visit_pat(&**subpattern, env),
|
||||
|
@ -330,7 +330,7 @@ impl Tm {
|
||||
* Returns a time string formatted according to RFC 822.
|
||||
*
|
||||
* local: "Thu, 22 Mar 2012 07:53:18 PST"
|
||||
* utc: "Thu, 22 Mar 2012 14:53:18 UTC"
|
||||
* utc: "Thu, 22 Mar 2012 14:53:18 GMT"
|
||||
*/
|
||||
pub fn rfc822(&self) -> String {
|
||||
if self.tm_gmtoff == 0_i32 {
|
||||
@ -351,7 +351,8 @@ impl Tm {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a time string formatted according to ISO 8601.
|
||||
* Returns a time string formatted according to RFC 3999. RFC 3999 is
|
||||
* compatible with ISO 8601.
|
||||
*
|
||||
* local: "2012-02-22T07:53:18-07:00"
|
||||
* utc: "2012-02-22T14:53:18Z"
|
||||
|
34
src/test/compile-fail/issue-10536.rs
Normal file
34
src/test/compile-fail/issue-10536.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// We only want to assert that this doesn't ICE, we don't particularly care
|
||||
// about whether it nor it fails to compile.
|
||||
|
||||
// error-pattern:
|
||||
|
||||
#![feature(macro_rules)]
|
||||
|
||||
macro_rules! foo{
|
||||
() => {{
|
||||
macro_rules! bar{() => (())}
|
||||
1
|
||||
}}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
foo!();
|
||||
|
||||
assert!({one! two()});
|
||||
|
||||
// regardless of whether nested macro_rules works, the following should at
|
||||
// least throw a conventional error.
|
||||
assert!({one! two});
|
||||
}
|
||||
|
39
src/test/compile-fail/kindck-impl-type-params.rs
Normal file
39
src/test/compile-fail/kindck-impl-type-params.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
// Issue #14061: tests the interaction between generic implementation
|
||||
// parameter bounds and trait objects.
|
||||
|
||||
struct S<T>;
|
||||
|
||||
trait Gettable<T> {}
|
||||
|
||||
impl<T: Send + Copy> Gettable<T> for S<T> {}
|
||||
|
||||
fn f<T>(val: T) {
|
||||
let t: S<T> = S;
|
||||
let a = &t as &Gettable<T>;
|
||||
//~^ ERROR instantiating a type parameter with an incompatible type `T`
|
||||
let a: &Gettable<T> = &t;
|
||||
//~^ ERROR instantiating a type parameter with an incompatible type `T`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let t: S<&int> = S;
|
||||
let a = &t as &Gettable<&int>;
|
||||
//~^ ERROR instantiating a type parameter with an incompatible type `&int`
|
||||
let t: Box<S<String>> = box S;
|
||||
let a = t as Box<Gettable<String>>;
|
||||
//~^ ERROR instantiating a type parameter with an incompatible type
|
||||
let t: Box<S<String>> = box S;
|
||||
let a: Box<Gettable<String>> = t;
|
||||
//~^ ERROR instantiating a type parameter with an incompatible type
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user