serialize getopts collections test time rand \
log regex graphviz core rbml alloc \
unicode
-RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_driver rustc_trans rustc_back rustc_llvm
+RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
+ rustc_trans rustc_back rustc_llvm
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc regex_macros fmt_macros
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
TOOLS := compiletest rustdoc rustc
DEPS_graphviz := std
DEPS_syntax := std term serialize log fmt_macros arena libc
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
- rustc_typeck log syntax serialize rustc_llvm rustc_trans
+ rustc_typeck rustc_resolve log syntax serialize rustc_llvm rustc_trans
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
log syntax serialize rustc_llvm
DEPS_rustc_typeck := rustc syntax
DEPS_rustc_borrowck := rustc log graphviz syntax
+DEPS_rustc_resolve := rustc log syntax
DEPS_rustc := syntax flate arena serialize getopts rbml \
time log graphviz rustc_llvm rustc_back
DEPS_rustc_llvm := native:rustllvm libc std
$(filter-out rustc_trans, \
$(filter-out rustc_typeck, \
$(filter-out rustc_borrowck, \
+ $(filter-out rustc_resolve, \
$(filter-out rustc_driver, \
- $(filter-out syntax, $(CRATES)))))))
-COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_typeck rustc_driver syntax
+ $(filter-out syntax, $(CRATES))))))))
+COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \
+ rustc_typeck rustc_driver syntax
# This macro creates some simple definitions for each crate being built, just
# some munging of all of the parameters above.
$(foreach docname,$(DOCS),$(eval $(call DEF_DOC,$(docname))))
-# Localized documentation
-
-# FIXME: I (huonw) haven't actually been able to test properly, since
-# e.g. (by default) I'm doing an out-of-tree build (#12763), but even
-# adjusting for that, the files are too old(?) and are rejected by
-# po4a.
-#
-# As such, I've attempted to get it working as much as possible (and
-# switching from pandoc to rustdoc), but preserving the old behaviour
-# (e.g. only running on the guide)
-.PHONY: l10n-mds
-l10n-mds: $(D)/po4a.conf \
- $(foreach lang,$(L10N_LANG),$(D)/po/$(lang)/*.md.po)
- $(warning WARNING: localized documentation is experimental)
- po4a --copyright-holder="The Rust Project Developers" \
- --package-name="Rust" \
- --package-version="$(CFG_RELEASE)" \
- -M UTF-8 -L UTF-8 \
- $(D)/po4a.conf
-
-define DEF_L10N_DOC
-DOC_L10N_TARGETS += doc/l10n/$(1)/$(2).html
-doc/l10n/$(1)/$(2).html: l10n-mds $$(HTML_DEPS) $$(RUSTDOC_DEPS_$(2))
- @$$(call E, rustdoc: $$@)
- $$(RUSTDOC) $$(RUSTDOC_HTML_OPTS) $$(RUSTDOC_FLAGS_$(1)) doc/l10n/$(1)/$(2).md
-endef
-
-$(foreach lang,$(L10N_LANGS),$(eval $(call DEF_L10N_DOC,$(lang),guide)))
-
-
######################################################################
# Rustdoc (libstd/extra)
######################################################################
docs: $(DOC_TARGETS)
compiler-docs: $(COMPILER_DOC_TARGETS)
-
-docs-l10n: $(DOC_L10N_TARGETS)
-
-.PHONY: docs-l10n
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) coretest
TEST_DOC_CRATES = $(DOC_CRATES)
-TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_trans,$(HOST_CRATES))
+TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans,\
+ $(HOST_CRATES))
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
######################################################################
TEST_LOG_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
TEST_OK_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).ok
-TEST_RATCHET_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4)-metrics.json
-TEST_RATCHET_NOISE_PERCENT=10.0
-
-# Whether to ratchet or merely save benchmarks
-ifdef CFG_RATCHET_BENCH
-CRATE_TEST_EXTRA_ARGS= \
- --test $(TEST_BENCH) \
- --ratchet-metrics $(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4)) \
- --ratchet-noise-percent $(TEST_RATCHET_NOISE_PERCENT)
-else
-CRATE_TEST_EXTRA_ARGS= \
- --test $(TEST_BENCH) \
- --save-metrics $(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4))
-endif
-
# If we're sharding the testsuite between parallel testers,
# pass this argument along to the compiletest and crate test
# invocations.
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
$(Q)echo $(ALL_HS) \
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
- $(Q)find $(S)src -type f -perm +a+x \
+ $(Q)find $(S)src -type f -perm /a+x \
-not -name '*.rs' -and -not -name '*.py' \
-and -not -name '*.sh' \
| grep '^$(S)src/jemalloc' -v \
$$(Q)touch tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
$$(Q)$(CFG_ADB) pull $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log tmp/
$$(Q)$(CFG_ADB) shell rm $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
- $$(Q)$(CFG_ADB) pull $(CFG_ADB_TEST_DIR)/$$(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4)) tmp/
@if grep -q "result: ok" tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
then \
rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
$$(CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3)) \
--src-base $$(S)src/test/$$(CTEST_SRC_BASE_$(4))/ \
--build-base $(3)/test/$$(CTEST_BUILD_BASE_$(4))/ \
- --ratchet-metrics $(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4)) \
--mode $$(CTEST_MODE_$(4)) \
$$(CTEST_RUNTOOL_$(4))
stderr_out.as_slice());
ProcRes {
- status: process::ExitStatus(exitcode),
+ status: process::ProcessExit::ExitStatus(exitcode),
stdout: stdout_out,
stderr: stderr_out,
cmdline: cmdline
// FIXME (#9639): This needs to handle non-utf8 paths
let mut link_args = vec!("-L".to_string(),
aux_dir.as_str().unwrap().to_string());
- let llvm_args = vec!("--emit=bc,obj".to_string(),
+ let llvm_args = vec!("--emit=llvm-bc,obj".to_string(),
"--crate-type=lib".to_string());
link_args.extend(llvm_args.into_iter());
let args = make_compile_args(config,
document converter, is required to generate docs as HTML from Rust's
source code.
-[po4a](http://po4a.alioth.debian.org/) is required for generating translated
-docs from the master (English) docs.
-
-[GNU gettext](http://www.gnu.org/software/gettext/) is required for managing
-the translation data.
-
## Building
To generate all the docs, just run `make docs` from the root of the repository.
A nice quick reference (for non-pandoc markdown) is at:
- http://kramdown.gettalong.org/quickref.html
-
-## Notes for translators
-
-Notice: The procedure described below is a work in progress. We are working on
-translation system but the procedure contains some manual operations for now.
-
-To start the translation for a new language, see `po4a.conf` at first.
-
-To generate `.pot` and `.po` files, do something like:
-
-~~~~
-po4a --copyright-holder="The Rust Project Developers" \
- --package-name="Rust" \
- --package-version="0.13.0" \
- -M UTF-8 -L UTF-8 \
- src/doc/po4a.conf
-~~~~
-
-(the version number must be changed if it is not `0.13.0` now.)
-
-Now you can translate documents with `.po` files, commonly used with gettext. If
-you are not familiar with gettext-based translation, please read the online
-manual linked from http://www.gnu.org/software/gettext/ . We use UTF-8 as the
-file encoding of `.po` files.
-
-When you want to make a commit, do the command below before staging your
-change:
-
-~~~~
-for f in src/doc/po/**/*.po; do
- msgattrib --translated $f -o $f.strip
- if [ -e $f.strip ]; then
- mv $f.strip $f
- else
- rm $f
- fi
-done
-~~~~
-
-This removes untranslated entries from `.po` files to save disk space.
let f = Foo { x: y }; // -+ f goes into scope
// stuff // |
// |
-} // -+ f & y go out of scope
+} // -+ f and y go out of scope
```
Our `f` lives within the scope of `y`, so everything works. What if it didn't?
let y = &5i; // ---+ y goes into scope
let f = Foo { x: y }; // ---+ f goes into scope
x = &f.x; // | | error here
- } // ---+ f & y go out of scope
+ } // ---+ f and y go out of scope
// |
println!("{}", x); // |
} // -+ x goes out of scope
}
fn main() {
- let car = Car { name: "DeLorian".to_string() };
+ let car = Car { name: "DeLorean".to_string() };
for _ in range(0u, 4) {
Wheel { size: 360, owner: car };
}
fn main() {
- let car = Car { name: "DeLorian".to_string() };
+ let car = Car { name: "DeLorean".to_string() };
let car_owner = Rc::new(car);
If you're on Windows, please download either the [32-bit
installer](https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe)
-
or the [64-bit
installer](https://static.rust-lang.org/dist/rust-nightly-x86_64-pc-windows-gnu.exe)
and run it.
ErrorReason(String),
}
```
-Where a `StringResult` is either an `StringOK`, with the result of a computation, or an
+Where a `StringResult` is either a `StringOK`, with the result of a computation, or an
`ErrorReason` with a `String` explaining what caused the computation to fail. These kinds of
`enum`s are actually very useful and are even part of the standard library.
```
Notice that we need both the enum name and the variant name: `StringResult::StringOK`, but
-we didn't need to with `Ordering`, we just said `Greater` rather than `Ordering::Greater`.
+we didn't need to with `Ordering` – we just said `Greater` rather than `Ordering::Greater`.
There's a reason: the Rust prelude imports the variants of `Ordering` as well as the enum
itself. We can use the `use` keyword to do something similar with `StringResult`:
also cause name conflicts, so do this with caution. It's considered good style to rarely import
variants for this reason.
-As you can see `enum`s with values are quite a powerful tool for data representation,
-and can be even more useful when they're generic across types. But before we get to
-generics, let's talk about how to use them with pattern matching, a tool that will
+As you can see, `enum`s with values are quite a powerful tool for data representation,
+and can be even more useful when they're generic across types. Before we get to generics,
+though, let's talk about how to use them with pattern matching, a tool that will
let us deconstruct this sum type (the type theory term for enums) in a very elegant
way and avoid all these messy `if`/`else`s.
# Match
Often, a simple `if`/`else` isn't enough, because you have more than two
-possible options. And `else` conditions can get incredibly complicated. So
+possible options. Also, `else` conditions can get incredibly complicated, so
what's the solution?
Rust has a keyword, `match`, that allows you to replace complicated `if`/`else`
}
```
-`match` takes an expression, and then branches based on its value. Each 'arm' of
+`match` takes an expression and then branches based on its value. Each 'arm' of
the branch is of the form `val => expression`. When the value matches, that arm's
expression will be evaluated. It's called `match` because of the term 'pattern
-matching,' which `match` is an implementation of.
+matching', which `match` is an implementation of.
So what's the big advantage here? Well, there are a few. First of all, `match`
-enforces 'exhaustiveness checking.' Do you see that last arm, the one with the
+enforces 'exhaustiveness checking'. Do you see that last arm, the one with the
underscore (`_`)? If we remove that arm, Rust will give us an error:
```text
```
In other words, Rust is trying to tell us we forgot a value. Because `x` is an
-integer, Rust knows that it can have a number of different values. For example,
-`6i`. But without the `_`, there is no arm that could match, and so Rust refuses
-to compile. `_` is sort of like a catch-all arm. If none of the other arms match,
-the arm with `_` will. And since we have this catch-all arm, we now have an arm
-for every possible value of `x`, and so our program will now compile.
+integer, Rust knows that it can have a number of different values – for example,
+`6i`. Without the `_`, however, there is no arm that could match, and so Rust refuses
+to compile. `_` acts like a 'catch-all arm'. If none of the other arms match,
+the arm with `_` will, and since we have this catch-all arm, we now have an arm
+for every possible value of `x`, and so our program will compile successfully.
`match` statements also destructure enums, as well. Remember this code from the
section on enums?
```
That is how you can get and use the values contained in `enum`s.
-It can also allow us to treat errors or unexpected computations, for example, a
-function that is not guaranteed to be able to compute a result (an `int` here),
+It can also allow us to handle errors or unexpected computations; for example, a
+function that is not guaranteed to be able to compute a result (an `int` here)
could return an `OptionalInt`, and we would handle that value with a `match`.
As you can see, `enum` and `match` used together are quite useful!
-`match` is also an expression, which means we can use it on the right
-hand side of a `let` binding or directly where an expression is
-used. We could also implement the previous line like this:
+`match` is also an expression, which means we can use it on the right-hand
+side of a `let` binding or directly where an expression is used. We could
+also implement the previous line like this:
```{rust}
fn cmp(a: int, b: int) -> Ordering {
The `for` loop is used to loop a particular number of times. Rust's `for` loops
work a bit differently than in other systems languages, however. Rust's `for`
-loop doesn't look like this "C style" `for` loop:
+loop doesn't look like this "C-style" `for` loop:
```{c}
for (x = 0; x < 10; x++) {
and gives an iterator over those values. The upper bound is exclusive, though,
so our loop will print `0` through `9`, not `10`.
-Rust does not have the "C style" `for` loop on purpose. Manually controlling
+Rust does not have the "C-style" `for` loop on purpose. Manually controlling
each element of the loop is complicated and error prone, even for experienced C
developers.
while true {
```
-Rust has a dedicated keyword, `loop`, to handle this case:
+However, Rust has a dedicated keyword, `loop`, to handle this case:
```{rust,ignore}
loop {
`while true`, since we know that it will always loop. The details of what
that _means_ aren't super important to understand at this stage, but in
general, the more information we can give to the compiler, the better it
-can do with safety and code generation. So you should always prefer
+can do with safety and code generation, so you should always prefer
`loop` when you plan to loop infinitely.
## Ending iteration early
```
We had to keep a dedicated `mut` boolean variable binding, `done`, to know
-when we should skip out of the loop. Rust has two keywords to help us with
+when we should exit out of the loop. Rust has two keywords to help us with
modifying iteration: `break` and `continue`.
In this case, we can write the loop in a better way with `break`:
}
```
-We now loop forever with `loop`, and use `break` to break out early.
+We now loop forever with `loop` and use `break` to break out early.
`continue` is similar, but instead of ending the loop, goes to the next
-iteration: This will only print the odd numbers:
+iteration. This will only print the odd numbers:
```{rust}
for x in range(0i, 10i) {
Strings are an important concept for any programmer to master. Rust's string
handling system is a bit different from other languages, due to its systems
focus. Any time you have a data structure of variable size, things can get
-tricky, and strings are a re-sizable data structure. That said, Rust's strings
-also work differently than in some other systems languages, such as C.
+tricky, and strings are a re-sizable data structure. That being said, Rust's
+strings also work differently than in some other systems languages, such as C.
Let's dig into the details. A **string** is a sequence of Unicode scalar values
encoded as a stream of UTF-8 bytes. All strings are guaranteed to be
}
```
-We had to match each time, to see if we had a value or not. In this case,
-though, we _know_ that `x` has a `Value`. But `match` forces us to handle
+We had to match each time to see if we had a value or not. In this case,
+though, we _know_ that `x` has a `Value`, but `match` forces us to handle
the `missing` case. This is what we want 99% of the time, but sometimes, we
know better than the compiler.
Likewise, `read_line()` does not return a line of input. It _might_ return a
-line of input. It might also fail to do so. This could happen if our program
+line of input, though it might also fail to do so. This could happen if our program
isn't running in a terminal, but as part of a cron job, or some other context
where there's no standard input. Because of this, `read_line` returns a type
very similar to our `OptionalInt`: an `IoResult<T>`. We haven't talked about
`IoResult<T>` yet because it is the **generic** form of our `OptionalInt`.
-Until then, you can think of it as being the same thing, just for any type, not
-just `int`s.
+Until then, you can think of it as being the same thing, just for any type –
+not just `int`s.
Rust provides a method on these `IoResult<T>`s called `ok()`, which does the
-same thing as our `match` statement, but assuming that we have a valid value.
+same thing as our `match` statement but assumes that we have a valid value.
We then call `expect()` on the result, which will terminate our program if we
don't have a valid value. In this case, if we can't get input, our program
doesn't work, so we're okay with that. In most cases, we would want to handle
}
```
-Sometimes, this makes things more readable. Sometimes, less. Use your judgment
+Sometimes, this makes things more readable – sometimes, less. Use your judgement
here.
That's all you need to get basic input from the standard input! It's not too
that page, but the best part is the search bar. Right up at the top, there's
a box that you can enter in a search term. The search is pretty primitive
right now, but is getting better all the time. If you type 'random' in that
-box, the page will update to [this
-one](std/index.html?search=random). The very first
-result is a link to
-[std::rand::random](std/rand/fn.random.html). If we
+box, the page will update to [this one](std/index.html?search=random). The very
+first result is a link to [`std::rand::random`](std/rand/fn.random.html). If we
click on that result, we'll be taken to its documentation page.
This page shows us a few things: the type signature of the function, some
```
This says "please give me a random `int` value." We can change our code to use
-this hint...
+this hint:
```{rust,no_run}
use std::io;
}
```
-We use a `match` to either give us the `uint` inside of the `Option`, or we
+We use a `match` to either give us the `uint` inside of the `Option`, or else
print an error message and return. Let's give this a shot:
```bash
... actually, we didn't. See, when you get a line of input from `stdin()`,
you get all the input. Including the `\n` character from you pressing Enter.
-So, `from_str()` sees the string `"5\n"` and says "nope, that's not a number,
-there's non-number stuff in there!" Luckily for us, `&str`s have an easy
+Therefore, `from_str()` sees the string `"5\n"` and says "nope, that's not a
+number; there's non-number stuff in there!" Luckily for us, `&str`s have an easy
method we can use defined on them: `trim()`. One small modification, and our
code looks like this:
the number works, as well as guessing a number too small.
The Rust compiler helped us out quite a bit there! This technique is called
-"lean on the compiler," and it's often useful when working on some code. Let
+"lean on the compiler", and it's often useful when working on some code. Let
the error messages help guide you towards the correct types.
Now we've got most of the game working, but we can only make one guess. Let's
## Looping
-As we already discussed, the `loop` keyword gives us an infinite loop. So
-let's add that in:
+As we already discussed, the `loop` keyword gives us an infinite loop.
+Let's add that in:
```{rust,no_run}
use std::io;
Hello, world!
```
-Excellent! So, we already have a single crate here: our `src/main.rs` is a crate.
+Excellent! We already have a single crate here: our `src/main.rs` is a crate.
Everything in that file is in the crate root. A crate that generates an executable
defines a `main` function inside its root, as we've done here.
-Let's define a new module inside our crate. Edit `src/main.rs` to look
-like this:
+Let's define a new module inside our crate. Edit `src/main.rs` to look like this:
```
fn main() {
`snake_case` naming, like functions and variable bindings.
Inside the `hello` module, we've defined a `print_hello` function. This will
-also print out our hello world message. Modules allow you to split up your
+also print out our "hello world" message. Modules allow you to split up your
program into nice neat boxes of functionality, grouping common things together,
and keeping different things apart. It's kinda like having a set of shelves:
a place for everything and everything in its place.
You may have noticed an exclamation point in the `warn` attribute declaration.
The `!` in this attribute means that this attribute applies to the enclosing
-item, rather than to the item that follows the attribute. So this `warn`
+item, rather than to the item that follows the attribute. This `warn`
attribute declaration applies to the enclosing crate itself, rather than
to whatever item statement follows it:
Great. Rust's infrastructure supports tests in two sorts of places, and they're
for two kinds of tests: you include **unit test**s inside of the crate itself,
and you place **integration test**s inside a `tests` directory. "Unit tests"
-are small tests that test one focused unit, "integration tests" tests multiple
-units in integration. That said, this is a social convention, they're no different
-in syntax. Let's make a `tests` directory:
+are small tests that test one focused unit; "integration tests" test multiple
+units in integration. That being said, this is a social convention – they're no
+different in syntax. Let's make a `tests` directory:
```{bash,ignore}
$ mkdir tests
Now we're getting somewhere. Remember when we talked about naming our tests
with good names? This is why. Here, it says 'test foo' because we called our
-test 'foo.' If we had given it a good name, it'd be more clear which test
+test 'foo'. If we had given it a good name, it'd be more clear which test
failed, especially as we accumulate more tests.
```text
include `main` when it's _not_ true. So we use `not` to negate things:
`cfg(not(test))` will only compile our code when the `cfg(test)` is false.
-With this attribute we won't get the warning (even
+With this attribute, we won't get the warning (even
though `src/main.rs` gets recompiled this time):
```bash
Build failed, waiting for other jobs to finish...
Could not compile `testing`.
-To learn more, run the command again with --verbose.
+To learn more, run the command again with `--verbose`.
```
Rust can't find this function. That makes sense, as we didn't write it yet!
In order to share this code with our tests, we'll need to make a library crate.
This is also just good software design: as we mentioned before, it's a good idea
to put most of your functionality into a library crate, and have your executable
-crate use that library. This allows for code re-use.
+crate use that library. This allows for code reuse.
To do that, we'll need to make a new module. Make a new file, `src/lib.rs`,
and put this in it:
Great! One test passed. We've got an integration test showing that our public
method works, but maybe we want to test some of the internal logic as well.
While this function is simple, if it were more complicated, you can imagine
-we'd need more tests. So let's break it up into two helper functions, and
-write some unit tests to test those.
+we'd need more tests. Let's break it up into two helper functions and write
+some unit tests to test those.
Change your `src/lib.rs` to look like this:
```
We don't want a mutable reference to immutable data! This error message uses a
-term we haven't talked about yet, 'borrow.' We'll get to that in just a moment.
+term we haven't talked about yet, 'borrow'. We'll get to that in just a moment.
This simple example actually illustrates a lot of Rust's power: Rust has
prevented us, at compile time, from breaking our own rules. Because Rust's
fn foo(x: &int) -> &int { x }
{
- let x = 5i; // x is the owner of this integer, which is memory on the stack.
+ // x is the owner of the integer, which is memory on the stack.
+ let x = 5i;
- // privilege 2: you may lend that resource, to as many borrowers as you'd like
+ // privilege 2: you may lend that resource to as many borrowers as you like
let y = &x;
let z = &x;
}
{
- let mut x = 5i; // x is the owner of this integer, which is memory on the stack.
+ // x is the owner of this integer, which is memory on the stack.
+ let mut x = 5i;
- let y = &mut x; // privilege 3: you may lend that resource to a single borrower,
- // mutably
+ // privilege 3: you may lend that resource to a single borrower, mutably
+ let y = &mut x;
}
```
return something, and you've lent it to someone, they need to give it back to
you for you to give it back! If we didn't, then the owner could deallocate
the memory, and the person we've loaned it out to would have a pointer to
-invalid memory. This is called a 'dangling pointer.'
+invalid memory. This is called a 'dangling pointer'.
Let's re-examine the error that led us to talk about all of this, which was a
violation of the restrictions placed on owners who lend something out mutably.
```
The great thing about boxes is that we don't have to manually free this
-allocation! Instead, when `x` reaches the end of its lifetime -- in this case,
-when it goes out of scope at the end of the block -- Rust `free`s `x`. This
+allocation! Instead, when `x` reaches the end of its lifetime – in this case,
+when it goes out of scope at the end of the block – Rust `free`s `x`. This
isn't because Rust has a garbage collector (it doesn't). Instead, by tracking
the ownership and lifetime of a variable (with a little help from you, the
programmer), the compiler knows precisely when it is no longer used.
(immutably!), lasting as long as any of those places, and disappearing when it
is no longer referenced. For instance, in a graph-like data structure, a node
might be referenced from all of its neighbors. In this case, it is not possible
-for the compiler to determine ahead of time when the value can be freed -- it
+for the compiler to determine ahead of time when the value can be freed – it
needs a little run-time support.
Rust's **Rc** type provides shared ownership of a dynamically allocated value
that is automatically freed at the end of its last owner's lifetime. (`Rc`
-stands for 'reference counted,' referring to the way these library types are
+stands for 'reference counted', referring to the way these library types are
implemented.) This provides more flexibility than single-owner boxes, but has
some runtime overhead.
it two arguments: an integer, `5`, and our closure, `square`. This is just like
passing any other two variable bindings to a function, but if you've never
worked with closures before, it can seem a little complex. Just think: "I'm
-passing two variables, one is an int, and one is a function."
+passing two variables: one is an int, and one is a function."
Next, let's look at how `twice` is defined:
```
Since our closure is named `f`, we can call it just like we called our closures
-before. And we pass in our `x` argument to each one. Hence 'twice.'
+before, and we pass in our `x` argument to each one, hence the name `twice`.
If you do the math, `(5 * 5) + (5 * 5) == 50`, so that's the output we get.
```
if we wanted to. Convention says that the first generic parameter should be
-`T`, for 'type,' and that we use `E` for 'error.' Rust doesn't care, however.
+`T`, for 'type,' and that we use `E` for 'error'. Rust doesn't care, however.
The `Result<T, E>` type is intended to
be used to return the result of a computation, and to have the ability to
The names don't actually change to this, it's just for illustration. But
as you can see, there's no overhead of deciding which version to call here,
-hence 'statically dispatched.' The downside is that we have two copies of
+hence 'statically dispatched'. The downside is that we have two copies of
the same function, so our binary is a little bit larger.
# Tasks
}
```
-You can have the macros expanded like this: `rustc print.rs --pretty=expanded` – which will
+You can have the macros expanded like this: `rustc print.rs --pretty=expanded`, which will
give us this huge result:
```{rust,ignore}
you will have a firm grasp of basic Rust development. There's a whole lot more
out there, we've just covered the surface. There's tons of topics that you can
dig deeper into, and we've built specialized guides for many of them. To learn
-more, dig into the [full documentation
-index](index.html).
+more, dig into the [full documentation index](index.html).
Happy hacking!
+++ /dev/null
-# Add here a list of target languages; po4a will automatically
-# generates .po for them and build .md when translated, eg:
-# [po4a_langs] es fr it pt_BR
-[po4a_langs] ja
-[po4a_paths] doc/po/$master.pot $lang:src/doc/po/$lang/$master.po
-
-# Add here below all source documents to be translated
-[type: text] src/doc/complement-bugreport.md $lang:doc/l10n/$lang/complement-bugreport.md
-[type: text] src/doc/complement-design-faq.md $lang:doc/l10n/$lang/complement-design-faq.md
-[type: text] src/doc/complement-lang-faq.md $lang:doc/l10n/$lang/complement-lang-faq.md
-[type: text] src/doc/complement-project-faq.md $lang:doc/l10n/$lang/complement-project-faq.md
-[type: text] src/doc/guide-container.md $lang:doc/l10n/$lang/guide-container.md
-[type: text] src/doc/guide-ffi.md $lang:doc/l10n/$lang/guide-ffi.md
-[type: text] src/doc/guide-ownership.md $lang:doc/l10n/$lang/guide-ownership.md
-[type: text] src/doc/guide-macros.md $lang:doc/l10n/$lang/guide-macros.md
-[type: text] src/doc/guide-plugin.md $lang:doc/l10n/$lang/guide-plugin.md
-[type: text] src/doc/guide-pointers.md $lang:doc/l10n/$lang/guide-pointers.md
-[type: text] src/doc/guide-strings.md $lang:doc/l10n/$lang/guide-strings.md
-[type: text] src/doc/guide-tasks.md $lang:doc/l10n/$lang/guide-tasks.md
-[type: text] src/doc/guide-testing.md $lang:doc/l10n/$lang/guide-testing.md
-[type: text] src/doc/guide-unsafe.md $lang:doc/l10n/$lang/guide-unsafe.md
-[type: text] src/doc/guide-crates.md $lang:doc/l10n/$lang/guide-crates.md
-[type: text] src/doc/guide-error-handling.md $lang:doc/l10n/$lang/guide-error-handling.md
-[type: text] src/doc/guide.md $lang:doc/l10n/$lang/guide.md
-[type: text] src/doc/index.md $lang:doc/l10n/$lang/index.md
-[type: text] src/doc/intro.md $lang:doc/l10n/$lang/intro.md
-[type: text] src/doc/rust.md $lang:doc/l10n/$lang/rust.md
-[type: text] src/doc/rustdoc.md $lang:doc/l10n/$lang/rustdoc.md
syntax with a floating point literal ending in a period. `2.f64` would attempt
to call a method named `f64` on `2`.
-##### Boolean literals
+#### Boolean literals
The two values of the boolean type are written `true` and `false`.
```{.ebnf .gram}
extern_crate_decl : "extern" "crate" crate_name
-crate_name: ident | ( string_lit as ident )
+crate_name: ident | ( string_lit "as" ident )
```
An _`extern crate` declaration_ specifies a dependency on an external crate.
/**
- * Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+ * Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
* file at the top-level directory of this distribution and at
* http://rust-lang.org/COPYRIGHT.
* With elements taken from Bootstrap v3.0.2 (MIT licensed).
code {
padding: 0 2px;
color: #8D1A38;
- white-space: pre-wrap;
}
pre code {
padding: 0;
trap "rm -f $TMPFILE; exit" INT TERM EXIT
# Find out where to look for the pretty printer Python module
-RUSTC_SYSROOT=`rustc -Zprint-sysroot`
+RUSTC_SYSROOT=`rustc --print sysroot`
# Write the LLDB script to the tempfile
echo "command script import \"$RUSTC_SYSROOT/lib/rustlib/etc/lldb_rust_formatters.py\"" >> $TMPFILE
#![stable]
-//! Concurrency-enabled mechanisms for sharing mutable and/or immutable state
-//! between tasks.
+//! Threadsafe reference-counted boxes (the `Arc<T>` type).
+//!
+//! The `Arc<T>` type provides shared ownership of an immutable value. Destruction is
+//! deterministic, and will occur as soon as the last owner is gone. It is marked as `Send` because
+//! it uses atomic reference counting.
+//!
+//! If you do not need thread-safety, and just need shared ownership, consider the [`Rc<T>`
+//! type](../rc/struct.Rc.html). It is the same as `Arc<T>`, but does not use atomics, making it
+//! both thread-unsafe as well as significantly faster when updating the reference count.
+//!
+//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer to the box. A
+//! `Weak<T>` pointer can be upgraded to an `Arc<T>` pointer, but will return `None` if the value
+//! has already been dropped.
+//!
+//! For example, a tree with parent pointers can be represented by putting the nodes behind strong
+//! `Arc<T>` pointers, and then storing the parent pointers as `Weak<T>` pointers.
+//!
+//! # Examples
+//!
+//! Sharing some immutable data between tasks:
+//!
+//! ```
+//! use std::sync::Arc;
+//!
+//! let five = Arc::new(5i);
+//!
+//! for i in range(0u, 10) {
+//! let five = five.clone();
+//!
+//! spawn(move || {
+//! println!("{}", five);
+//! });
+//! }
+//! ```
+//!
+//! Sharing mutable data safely between tasks with a `Mutex`:
+//!
+//! ```
+//! use std::sync::Arc;
+//! use std::sync::Mutex;
+//!
+//! let five = Arc::new(Mutex::new(5i));
+//!
+//! for _ in range(0u, 10) {
+//! let five = five.clone();
+//!
+//! spawn(move || {
+//! let mut number = five.lock();
+//!
+//! number += 1;
+//!
+//! println!("{}", *number); // prints 6
+//! });
+//! }
+//! ```
use core::atomic;
use core::borrow::BorrowFrom;
///
/// # Example
///
-/// In this example, a large vector of floats is shared between several tasks.
-/// With simple pipes, without `Arc`, a copy would have to be made for each
-/// task.
+/// In this example, a large vector of floats is shared between several tasks. With simple pipes,
+/// without `Arc`, a copy would have to be made for each task.
///
/// ```rust
/// use std::sync::Arc;
/// A weak pointer to an `Arc`.
///
-/// Weak pointers will not keep the data inside of the `Arc` alive, and can be
-/// used to break cycles between `Arc` pointers.
+/// Weak pointers will not keep the data inside of the `Arc` alive, and can be used to break cycles
+/// between `Arc` pointers.
#[unsafe_no_drop_flag]
#[experimental = "Weak pointers may not belong in this module."]
pub struct Weak<T> {
}
impl<T: Sync + Send> Arc<T> {
- /// Creates an atomically reference counted wrapper.
+ /// Constructs a new `Arc<T>`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let five = Arc::new(5i);
+ /// ```
#[inline]
#[stable]
pub fn new(data: T) -> Arc<T> {
Arc { _ptr: unsafe { mem::transmute(x) } }
}
- /// Downgrades a strong pointer to a weak pointer.
+ /// Downgrades the `Arc<T>` to a `Weak<T>` reference.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let five = Arc::new(5i);
///
- /// Weak pointers will not keep the data alive. Once all strong references
- /// to the underlying data have been dropped, the data itself will be
- /// destroyed.
+ /// let weak_five = five.downgrade();
+ /// ```
#[experimental = "Weak pointers may not belong in this module."]
pub fn downgrade(&self) -> Weak<T> {
// See the clone() impl for why this is relaxed
impl<T> Arc<T> {
#[inline]
fn inner(&self) -> &ArcInner<T> {
- // This unsafety is ok because while this arc is alive we're guaranteed
- // that the inner pointer is valid. Furthermore, we know that the
- // `ArcInner` structure itself is `Sync` because the inner data is
- // `Sync` as well, so we're ok loaning out an immutable pointer to
- // these contents.
+ // This unsafety is ok because while this arc is alive we're guaranteed that the inner
+ // pointer is valid. Furthermore, we know that the `ArcInner` structure itself is `Sync`
+ // because the inner data is `Sync` as well, so we're ok loaning out an immutable pointer
+ // to these contents.
unsafe { &*self._ptr }
}
}
#[experimental]
pub fn strong_count<T>(this: &Arc<T>) -> uint { this.inner().strong.load(atomic::SeqCst) }
-#[unstable = "waiting on stability of Clone"]
+#[stable]
impl<T> Clone for Arc<T> {
- /// Duplicate an atomically reference counted wrapper.
+ /// Makes a clone of the `Arc<T>`.
+ ///
+ /// This increases the strong reference count.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let five = Arc::new(5i);
///
- /// The resulting two `Arc` objects will point to the same underlying data
- /// object. However, one of the `Arc` objects can be sent to another task,
- /// allowing them to share the underlying data.
+ /// five.clone();
+ /// ```
#[inline]
fn clone(&self) -> Arc<T> {
- // Using a relaxed ordering is alright here, as knowledge of the
- // original reference prevents other threads from erroneously deleting
- // the object.
+ // Using a relaxed ordering is alright here, as knowledge of the original reference
+ // prevents other threads from erroneously deleting the object.
//
- // As explained in the [Boost documentation][1], Increasing the
- // reference counter can always be done with memory_order_relaxed: New
- // references to an object can only be formed from an existing
- // reference, and passing an existing reference from one thread to
- // another must already provide any required synchronization.
+ // As explained in the [Boost documentation][1], Increasing the reference counter can
+ // always be done with memory_order_relaxed: New references to an object can only be formed
+ // from an existing reference, and passing an existing reference from one thread to another
+ // must already provide any required synchronization.
//
// [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
self.inner().strong.fetch_add(1, atomic::Relaxed);
}
impl<T: Send + Sync + Clone> Arc<T> {
- /// Acquires a mutable pointer to the inner contents by guaranteeing that
- /// the reference count is one (no sharing is possible).
+ /// Make a mutable reference from the given `Arc<T>`.
///
- /// This is also referred to as a copy-on-write operation because the inner
- /// data is cloned if the reference count is greater than one.
+ /// This is also referred to as a copy-on-write operation because the inner data is cloned if
+ /// the reference count is greater than one.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let mut five = Arc::new(5i);
+ ///
+ /// let mut_five = five.make_unique();
+ /// ```
#[inline]
#[experimental]
pub fn make_unique(&mut self) -> &mut T {
- // Note that we hold a strong reference, which also counts as
- // a weak reference, so we only clone if there is an
- // additional reference of either kind.
+ // Note that we hold a strong reference, which also counts as a weak reference, so we only
+ // clone if there is an additional reference of either kind.
if self.inner().strong.load(atomic::SeqCst) != 1 ||
self.inner().weak.load(atomic::SeqCst) != 1 {
*self = Arc::new((**self).clone())
}
- // This unsafety is ok because we're guaranteed that the pointer
- // returned is the *only* pointer that will ever be returned to T. Our
- // reference count is guaranteed to be 1 at this point, and we required
- // the Arc itself to be `mut`, so we're returning the only possible
- // reference to the inner data.
+ // This unsafety is ok because we're guaranteed that the pointer returned is the *only*
+ // pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at
+ // this point, and we required the Arc itself to be `mut`, so we're returning the only
+ // possible reference to the inner data.
let inner = unsafe { &mut *self._ptr };
&mut inner.data
}
#[unsafe_destructor]
#[experimental = "waiting on stability of Drop"]
impl<T: Sync + Send> Drop for Arc<T> {
+ /// Drops the `Arc<T>`.
+ ///
+ /// This will decrement the strong reference count. If the strong reference count becomes zero
+ /// and the only other references are `Weak<T>` ones, `drop`s the inner value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// {
+ /// let five = Arc::new(5i);
+ ///
+ /// // stuff
+ ///
+ /// drop(five); // explict drop
+ /// }
+ /// {
+ /// let five = Arc::new(5i);
+ ///
+ /// // stuff
+ ///
+ /// } // implicit drop
+ /// ```
fn drop(&mut self) {
- // This structure has #[unsafe_no_drop_flag], so this drop glue may run
- // more than once (but it is guaranteed to be zeroed after the first if
- // it's run more than once)
+ // This structure has #[unsafe_no_drop_flag], so this drop glue may run more than once (but
+ // it is guaranteed to be zeroed after the first if it's run more than once)
if self._ptr.is_null() { return }
- // Because `fetch_sub` is already atomic, we do not need to synchronize
- // with other threads unless we are going to delete the object. This
- // same logic applies to the below `fetch_sub` to the `weak` count.
+ // Because `fetch_sub` is already atomic, we do not need to synchronize with other threads
+ // unless we are going to delete the object. This same logic applies to the below
+ // `fetch_sub` to the `weak` count.
if self.inner().strong.fetch_sub(1, atomic::Release) != 1 { return }
- // This fence is needed to prevent reordering of use of the data and
- // 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 reference count, which happens before this fence, which
- // happens before the deletion of the data.
+ // This fence is needed to prevent reordering of use of the data and 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
+ // reference count, which happens before this fence, which happens before the deletion of
+ // the data.
//
// As explained in the [Boost documentation][1],
//
- // It is important to enforce any possible access to the object in
- // one thread (through an existing reference) to *happen before*
- // deleting the object in a different thread. This is achieved by a
- // "release" operation after dropping a reference (any access to the
- // object through this reference must obviously happened before),
- // and an "acquire" operation before deleting the object.
+ // > It is important to enforce any possible access to the object in one thread (through an
+ // > existing reference) to *happen before* deleting the object in a different thread. This
+ // > is achieved by a "release" operation after dropping a reference (any access to the
+ // > object through this reference must obviously happened before), and an "acquire"
+ // > operation before deleting the object.
//
// [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
atomic::fence(atomic::Acquire);
- // Destroy the data at this time, even though we may not free the box
- // allocation itself (there may still be weak pointers lying around).
+ // Destroy the data at this time, even though we may not free the box allocation itself
+ // (there may still be weak pointers lying around).
unsafe { drop(ptr::read(&self.inner().data)); }
if self.inner().weak.fetch_sub(1, atomic::Release) == 1 {
#[experimental = "Weak pointers may not belong in this module."]
impl<T: Sync + Send> Weak<T> {
- /// Attempts to upgrade this weak reference to a strong reference.
+ /// Upgrades a weak reference to a strong reference.
+ ///
+ /// Upgrades the `Weak<T>` reference to an `Arc<T>`, if possible.
+ ///
+ /// Returns `None` if there were no strong references and the data was destroyed.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
///
- /// This method will not upgrade this reference if the strong reference count has already
- /// reached 0, but if there are still other active strong references this function will return
- /// a new strong reference to the data.
+ /// let five = Arc::new(5i);
+ ///
+ /// let weak_five = five.downgrade();
+ ///
+ /// let strong_five: Option<Arc<_>> = weak_five.upgrade();
+ /// ```
pub fn upgrade(&self) -> Option<Arc<T>> {
- // We use a CAS loop to increment the strong count instead of a
- // fetch_add because once the count hits 0 is must never be above 0.
+ // We use a CAS loop to increment the strong count instead of a fetch_add because once the
+ // count hits 0 is must never be above 0.
let inner = self.inner();
loop {
let n = inner.strong.load(atomic::SeqCst);
#[experimental = "Weak pointers may not belong in this module."]
impl<T: Sync + Send> Clone for Weak<T> {
+ /// Makes a clone of the `Weak<T>`.
+ ///
+ /// This increases the weak reference count.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let weak_five = Arc::new(5i).downgrade();
+ ///
+ /// weak_five.clone();
+ /// ```
#[inline]
fn clone(&self) -> Weak<T> {
// See comments in Arc::clone() for why this is relaxed
#[unsafe_destructor]
#[experimental = "Weak pointers may not belong in this module."]
impl<T: Sync + Send> Drop for Weak<T> {
+ /// Drops the `Weak<T>`.
+ ///
+ /// This will decrement the weak reference count.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// {
+ /// let five = Arc::new(5i);
+ /// let weak_five = five.downgrade();
+ ///
+ /// // stuff
+ ///
+ /// drop(weak_five); // explict drop
+ /// }
+ /// {
+ /// let five = Arc::new(5i);
+ /// let weak_five = five.downgrade();
+ ///
+ /// // stuff
+ ///
+ /// } // implicit drop
+ /// ```
fn drop(&mut self) {
// see comments above for why this check is here
if self._ptr.is_null() { return }
- // If we find out that we were the last weak pointer, then its time to
- // deallocate the data entirely. See the discussion in Arc::drop() about
- // the memory orderings
+ // If we find out that we were the last weak pointer, then its time to deallocate the data
+ // entirely. See the discussion in Arc::drop() about the memory orderings
if self.inner().weak.fetch_sub(1, atomic::Release) == 1 {
atomic::fence(atomic::Acquire);
unsafe { deallocate(self._ptr as *mut u8, size_of::<ArcInner<T>>(),
#[unstable = "waiting on PartialEq"]
impl<T: PartialEq> PartialEq for Arc<T> {
+ /// Equality for two `Arc<T>`s.
+ ///
+ /// Two `Arc<T>`s are equal if their inner value are equal.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let five = Arc::new(5i);
+ ///
+ /// five == Arc::new(5i);
+ /// ```
fn eq(&self, other: &Arc<T>) -> bool { *(*self) == *(*other) }
+
+ /// Inequality for two `Arc<T>`s.
+ ///
+ /// Two `Arc<T>`s are unequal if their inner value are unequal.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let five = Arc::new(5i);
+ ///
+ /// five != Arc::new(5i);
+ /// ```
fn ne(&self, other: &Arc<T>) -> bool { *(*self) != *(*other) }
}
#[unstable = "waiting on PartialOrd"]
impl<T: PartialOrd> PartialOrd for Arc<T> {
+ /// Partial comparison for two `Arc<T>`s.
+ ///
+ /// The two are compared by calling `partial_cmp()` on their inner values.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let five = Arc::new(5i);
+ ///
+ /// five.partial_cmp(&Arc::new(5i));
+ /// ```
fn partial_cmp(&self, other: &Arc<T>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
+
+ /// Less-than comparison for two `Arc<T>`s.
+ ///
+ /// The two are compared by calling `<` on their inner values.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let five = Arc::new(5i);
+ ///
+ /// five < Arc::new(5i);
+ /// ```
fn lt(&self, other: &Arc<T>) -> bool { *(*self) < *(*other) }
+
+ /// 'Less-than or equal to' comparison for two `Arc<T>`s.
+ ///
+ /// The two are compared by calling `<=` on their inner values.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let five = Arc::new(5i);
+ ///
+ /// five <= Arc::new(5i);
+ /// ```
fn le(&self, other: &Arc<T>) -> bool { *(*self) <= *(*other) }
- fn ge(&self, other: &Arc<T>) -> bool { *(*self) >= *(*other) }
+
+ /// Greater-than comparison for two `Arc<T>`s.
+ ///
+ /// The two are compared by calling `>` on their inner values.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let five = Arc::new(5i);
+ ///
+ /// five > Arc::new(5i);
+ /// ```
fn gt(&self, other: &Arc<T>) -> bool { *(*self) > *(*other) }
+
+ /// 'Greater-than or equal to' comparison for two `Arc<T>`s.
+ ///
+ /// The two are compared by calling `>=` on their inner values.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Arc;
+ ///
+ /// let five = Arc::new(5i);
+ ///
+ /// five >= Arc::new(5i);
+ /// ```
+ fn ge(&self, other: &Arc<T>) -> bool { *(*self) >= *(*other) }
}
#[unstable = "waiting on Ord"]
impl<T: Ord> Ord for Arc<T> {
use core::raw::TraitObject;
use core::result::Result;
use core::result::Result::{Ok, Err};
+use core::ops::{Deref, DerefMut};
/// A value that represents the global exchange heap. This is the default
/// place that the `box` keyword allocates into when no place is supplied.
fn default() -> Box<[T]> { box [] }
}
-#[unstable]
+#[stable]
impl<T: Clone> Clone for Box<T> {
/// Returns a copy of the owned box.
#[inline]
}
}
+impl<Sized? T> Deref<T> for Box<T> {
+ fn deref(&self) -> &T { &**self }
+}
+
+impl<Sized? T> DerefMut<T> for Box<T> {
+ fn deref_mut(&mut self) -> &mut T { &mut **self }
+}
+
#[cfg(test)]
mod test {
#[test]
let s = format!("{}", b);
assert_eq!(s, "&Any");
}
+
+ #[test]
+ fn deref() {
+ fn homura<T: Deref<i32>>(_: T) { }
+ homura(box 765i32);
+ }
}
/// An immutable reference-counted pointer type.
///
-/// See the [module level documentation](../index.html) for more.
+/// See the [module level documentation](../index.html) for more details.
#[unsafe_no_drop_flag]
#[stable]
pub struct Rc<T> {
- // FIXME #12808: strange names to try to avoid interfering with
- // field accesses of the contained type via Deref
+ // FIXME #12808: strange names to try to avoid interfering with field accesses of the contained
+ // type via Deref
_ptr: *mut RcBox<T>,
_nosend: marker::NoSend,
_noshare: marker::NoSync
pub fn new(value: T) -> Rc<T> {
unsafe {
Rc {
- // there is an implicit weak pointer owned by all the
- // strong pointers, which ensures that the weak
- // destructor never frees the allocation while the
- // strong destructor is running, even if the weak
- // pointer is stored inside the strong one.
+ // there is an implicit weak pointer owned by all the strong pointers, which
+ // ensures that the weak destructor never frees the allocation while the strong
+ // destructor is running, even if the weak pointer is stored inside the strong one.
_ptr: transmute(box RcBox {
value: value,
strong: Cell::new(1),
if !is_unique(self) {
*self = Rc::new((**self).clone())
}
- // This unsafety is ok because we're guaranteed that the pointer
- // returned is the *only* pointer that will ever be returned to T. Our
- // reference count is guaranteed to be 1 at this point, and we required
- // the `Rc<T>` itself to be `mut`, so we're returning the only possible
- // reference to the inner value.
+ // This unsafety is ok because we're guaranteed that the pointer returned is the *only*
+ // pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at
+ // this point, and we required the `Rc<T>` itself to be `mut`, so we're returning the only
+ // possible reference to the inner value.
let inner = unsafe { &mut *self._ptr };
&mut inner.value
}
if self.strong() == 0 {
ptr::read(&**self); // destroy the contained object
- // remove the implicit "strong weak" pointer now
- // that we've destroyed the contents.
+ // remove the implicit "strong weak" pointer now that we've destroyed the
+ // contents.
self.dec_weak();
if self.weak() == 0 {
}
}
-#[unstable = "Clone is unstable."]
+#[stable]
impl<T> Clone for Rc<T> {
/// Makes a clone of the `Rc<T>`.
///
unsafe {
if !self._ptr.is_null() {
self.dec_weak();
- // the weak count starts at 1, and will only go to
- // zero if all the strong pointers have disappeared.
+ // the weak count starts at 1, and will only go to zero if all the strong pointers
+ // have disappeared.
if self.weak() == 0 {
deallocate(self._ptr as *mut u8, size_of::<RcBox<T>>(),
min_align_of::<RcBox<T>>())
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::prelude::*;
+use prelude::*;
use std::rand;
use std::rand::Rng;
use test::Bencher;
/// }
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
- pub fn iter<'a>(&'a self) -> Items<'a, T> {
+ pub fn iter(&self) -> Items<T> {
Items { iter: self.data.iter() }
}
/// assert_eq!(heap.top(), Some(&5i));
///
/// ```
- pub fn top<'a>(&'a self) -> Option<&'a T> {
- if self.is_empty() { None } else { Some(&self.data[0]) }
+ pub fn top(&self) -> Option<&T> {
+ self.data.get(0)
}
/// Returns the number of elements the queue can hold without reallocating.
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn push(&mut self, item: T) {
+ let old_len = self.len();
self.data.push(item);
- let new_len = self.len() - 1;
- self.siftup(0, new_len);
+ self.siftup(0, old_len);
}
/// Pushes an item onto a queue then pops the greatest item off the queue in
/// assert_eq!(heap.top(), Some(&3i));
/// ```
pub fn push_pop(&mut self, mut item: T) -> T {
- if !self.is_empty() && *self.top().unwrap() > item {
- swap(&mut item, &mut self.data[0]);
- self.siftdown(0);
+ match self.data.get_mut(0) {
+ None => return item,
+ Some(top) => if *top > item {
+ swap(&mut item, top);
+ } else {
+ return item;
+ },
}
+
+ self.siftdown(0);
item
}
/// println!("{}", x);
/// }
/// ```
- pub fn into_vec(self) -> Vec<T> { let BinaryHeap{data: v} = self; v }
+ pub fn into_vec(self) -> Vec<T> { self.data }
/// Consumes the `BinaryHeap` and returns a vector in sorted
/// (ascending) order.
/// let vec = heap.into_sorted_vec();
/// assert_eq!(vec, vec![1i, 2, 3, 4, 5, 6, 7]);
/// ```
- pub fn into_sorted_vec(self) -> Vec<T> {
- let mut q = self;
- let mut end = q.len();
+ pub fn into_sorted_vec(mut self) -> Vec<T> {
+ let mut end = self.len();
while end > 1 {
end -= 1;
- q.data.swap(0, end);
- q.siftdown_range(0, end)
+ self.data.swap(0, end);
+ self.siftdown_range(0, end)
}
- q.into_vec()
+ self.into_vec()
}
// The implementations of siftup and siftdown use unsafe blocks in
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn is_empty(&self) -> bool { self.len() == 0 }
+ /// Clears the queue, returning an iterator over the removed elements.
+ #[inline]
+ #[unstable = "matches collection reform specification, waiting for dust to settle"]
+ pub fn drain<'a>(&'a mut self) -> Drain<'a, T> {
+ Drain {
+ iter: self.data.drain(),
+ }
+ }
+
/// Drops all items from the queue.
#[unstable = "matches collection reform specification, waiting for dust to settle"]
- pub fn clear(&mut self) { self.data.truncate(0) }
+ pub fn clear(&mut self) { self.drain(); }
}
/// `BinaryHeap` iterator.
-pub struct Items <'a, T:'a> {
+pub struct Items<'a, T: 'a> {
iter: slice::Items<'a, T>,
}
impl<'a, T> Iterator<&'a T> for Items<'a, T> {
#[inline]
- fn next(&mut self) -> Option<(&'a T)> { self.iter.next() }
+ fn next(&mut self) -> Option<&'a T> { self.iter.next() }
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
impl<'a, T> DoubleEndedIterator<&'a T> for Items<'a, T> {
#[inline]
- fn next_back(&mut self) -> Option<(&'a T)> { self.iter.next_back() }
+ fn next_back(&mut self) -> Option<&'a T> { self.iter.next_back() }
}
impl<'a, T> ExactSizeIterator<&'a T> for Items<'a, T> {}
impl<T> ExactSizeIterator<T> for MoveItems<T> {}
+/// An iterator that drains a `BinaryHeap`.
+pub struct Drain<'a, T: 'a> {
+ iter: vec::Drain<'a, T>,
+}
+
+impl<'a, T: 'a> Iterator<T> for Drain<'a, T> {
+ #[inline]
+ fn next(&mut self) -> Option<T> { self.iter.next() }
+
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
+}
+
+impl<'a, T: 'a> DoubleEndedIterator<T> for Drain<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
+}
+
+impl<'a, T: 'a> ExactSizeIterator<T> for Drain<'a, T> {}
+
impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
fn from_iter<Iter: Iterator<T>>(iter: Iter) -> BinaryHeap<T> {
- let vec: Vec<T> = iter.collect();
- BinaryHeap::from_vec(vec)
+ BinaryHeap::from_vec(iter.collect())
}
}
#[cfg(test)]
mod tests {
- use std::prelude::*;
+ use prelude::*;
use super::BinaryHeap;
- use vec::Vec;
#[test]
fn test_iterator() {
#[test]
fn test_empty_pop() {
- let mut heap: BinaryHeap<int> = BinaryHeap::new();
+ let mut heap = BinaryHeap::<int>::new();
assert!(heap.pop().is_none());
}
#[test]
fn test_empty_top() {
- let empty: BinaryHeap<int> = BinaryHeap::new();
+ let empty = BinaryHeap::<int>::new();
assert!(empty.top().is_none());
}
#[test]
fn test_empty_replace() {
- let mut heap: BinaryHeap<int> = BinaryHeap::new();
- heap.replace(5).is_none();
+ let mut heap = BinaryHeap::<int>::new();
+ assert!(heap.replace(5).is_none());
}
#[test]
assert_eq!(q.pop().unwrap(), x);
}
}
+
+ #[test]
+ fn test_drain() {
+ let mut q: BinaryHeap<_> =
+ [9u, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
+
+ assert_eq!(q.drain().take(5).count(), 5);
+
+ assert!(q.is_empty());
+ }
}
}
}
+#[stable]
impl Clone for Bitv {
#[inline]
fn clone(&self) -> Bitv {
#[cfg(test)]
mod tests {
- use std::prelude::*;
- use std::iter::range_step;
+ use prelude::*;
+ use core::iter::range_step;
+ use core::u32;
use std::rand;
use std::rand::Rng;
- use std::u32;
use test::{Bencher, black_box};
use super::{Bitv, BitvSet, from_fn, from_bytes};
use bitv;
- use vec::Vec;
static BENCH_BITS : uint = 1 << 14;
#[test]
fn test_from_bytes() {
let bitv = from_bytes(&[0b10110110, 0b00000000, 0b11111111]);
- let str = format!("{}{}{}", "10110110", "00000000", "11111111");
+ let str = concat!("10110110", "00000000", "11111111");
assert_eq!(bitv.to_string(), str);
}
/// A vacant Entry.
pub struct VacantEntry<'a, K:'a, V:'a> {
key: K,
- stack: stack::SearchStack<'a, K, V, node::Edge, node::Leaf>,
+ stack: stack::SearchStack<'a, K, V, node::handle::Edge, node::handle::Leaf>,
}
/// An occupied Entry.
pub struct OccupiedEntry<'a, K:'a, V:'a> {
- stack: stack::SearchStack<'a, K, V, node::KV, node::LeafOrInternal>,
+ stack: stack::SearchStack<'a, K, V, node::handle::KV, node::handle::LeafOrInternal>,
}
impl<K: Ord, V> BTreeMap<K, V> {
use core::kinds::marker;
use core::mem;
use super::BTreeMap;
- use super::super::node::{mod, Node, Fit, Split, KV, Edge, Internal, Leaf, LeafOrInternal};
+ use super::super::node::{mod, Node, Fit, Split, Internal, Leaf};
+ use super::super::node::handle;
use vec::Vec;
/// A generic mutable reference, identical to `&mut` except for the fact that its lifetime
}
}
- type StackItem<K, V> = node::Handle<*mut Node<K, V>, Edge, Internal>;
+ type StackItem<K, V> = node::Handle<*mut Node<K, V>, handle::Edge, handle::Internal>;
type Stack<K, V> = Vec<StackItem<K, V>>;
/// A `PartialSearchStack` handles the construction of a search stack.
/// Pushes the requested child of the stack's current top on top of the stack. If the child
/// exists, then a new PartialSearchStack is yielded. Otherwise, a VacantSearchStack is
/// yielded.
- pub fn push(mut self, mut edge: node::Handle<IdRef<'id, Node<K, V>>, Edge, Internal>)
+ pub fn push(mut self, mut edge: node::Handle<IdRef<'id, Node<K, V>>,
+ handle::Edge,
+ handle::Internal>)
-> PartialSearchStack<'a, K, V> {
self.stack.push(edge.as_raw());
PartialSearchStack {
}
}
- impl<'a, K, V, NodeType> SearchStack<'a, K, V, KV, NodeType> {
+ impl<'a, K, V, NodeType> SearchStack<'a, K, V, handle::KV, NodeType> {
/// Gets a reference to the value the stack points to.
pub fn peek(&self) -> &V {
unsafe { self.top.from_raw().into_kv().1 }
}
}
- impl<'a, K, V> SearchStack<'a, K, V, KV, Leaf> {
+ impl<'a, K, V> SearchStack<'a, K, V, handle::KV, handle::Leaf> {
/// Removes the key and value in the top element of the stack, then handles underflows as
/// described in BTree's pop function.
fn remove_leaf(mut self) -> V {
}
}
- impl<'a, K, V> SearchStack<'a, K, V, KV, LeafOrInternal> {
+ impl<'a, K, V> SearchStack<'a, K, V, handle::KV, handle::LeafOrInternal> {
/// Removes the key and value in the top element of the stack, then handles underflows as
/// described in BTree's pop function.
pub fn remove(self) -> V {
/// leaves the tree in an inconsistent state that must be repaired by the caller by
/// removing the entry in question. Specifically the key-value pair and its successor will
/// become swapped.
- fn into_leaf(mut self) -> SearchStack<'a, K, V, KV, Leaf> {
+ fn into_leaf(mut self) -> SearchStack<'a, K, V, handle::KV, handle::Leaf> {
unsafe {
let mut top_raw = self.top;
let mut top = top_raw.from_raw_mut();
}
}
- impl<'a, K, V> SearchStack<'a, K, V, Edge, Leaf> {
+ impl<'a, K, V> SearchStack<'a, K, V, handle::Edge, handle::Leaf> {
/// Inserts the key and value into the top element in the stack, and if that node has to
/// split recursively inserts the split contents into the next element stack until
/// splits stop.
#[cfg(test)]
mod test {
- use std::prelude::*;
+ use prelude::*;
use super::{BTreeMap, Occupied, Vacant};
#[cfg(test)]
mod bench {
- use std::prelude::*;
+ use prelude::*;
use std::rand::{weak_rng, Rng};
use test::{Bencher, black_box};
/// Represents the result of a search for a key in a single node
pub enum SearchResult<NodeRef> {
/// The element was found at the given index
- Found(Handle<NodeRef, KV, LeafOrInternal>),
+ Found(Handle<NodeRef, handle::KV, handle::LeafOrInternal>),
/// The element wasn't found, but if it's anywhere, it must be beyond this edge
- GoDown(Handle<NodeRef, Edge, LeafOrInternal>),
+ GoDown(Handle<NodeRef, handle::Edge, handle::LeafOrInternal>),
}
/// A B-Tree Node. We keep keys/edges/values separate to optimize searching for keys.
}
// FIXME(gereeter) Write an efficient clone_from
+#[stable]
impl<K: Clone, V: Clone> Clone for Node<K, V> {
fn clone(&self) -> Node<K, V> {
let mut ret = if self.is_leaf() {
index: uint
}
-pub enum KV {}
-pub enum Edge {}
+pub mod handle {
+ // Handle types.
+ pub enum KV {}
+ pub enum Edge {}
-pub enum LeafOrInternal {}
-pub enum Leaf {}
-pub enum Internal {}
+ // Handle node types.
+ pub enum LeafOrInternal {}
+ pub enum Leaf {}
+ pub enum Internal {}
+}
impl<K: Ord, V> Node<K, V> {
/// Searches for the given key in the node. If it finds an exact match,
}
}
-impl<'a, K: 'a, V: 'a> Handle<&'a Node<K, V>, Edge, Internal> {
+impl<'a, K: 'a, V: 'a> Handle<&'a Node<K, V>, handle::Edge, handle::Internal> {
/// Turns the handle into a reference to the edge it points at. This is necessary because the
/// returned pointer has a larger lifetime than what would be returned by `edge` or `edge_mut`,
/// making it more suitable for moving down a chain of nodes.
}
}
-impl<'a, K: 'a, V: 'a> Handle<&'a mut Node<K, V>, Edge, Internal> {
+impl<'a, K: 'a, V: 'a> Handle<&'a mut Node<K, V>, handle::Edge, handle::Internal> {
/// Turns the handle into a mutable reference to the edge it points at. This is necessary
/// because the returned pointer has a larger lifetime than what would be returned by
/// `edge_mut`, making it more suitable for moving down a chain of nodes.
}
}
-impl<K, V, NodeRef: Deref<Node<K, V>>> Handle<NodeRef, Edge, Internal> {
+impl<K, V, NodeRef: Deref<Node<K, V>>> Handle<NodeRef, handle::Edge, handle::Internal> {
// This doesn't exist because there are no uses for it,
// but is fine to add, analagous to edge_mut.
//
}
pub enum ForceResult<NodeRef, Type> {
- Leaf(Handle<NodeRef, Type, Leaf>),
- Internal(Handle<NodeRef, Type, Internal>)
+ Leaf(Handle<NodeRef, Type, handle::Leaf>),
+ Internal(Handle<NodeRef, Type, handle::Internal>)
}
-impl<K, V, NodeRef: Deref<Node<K, V>>, Type> Handle<NodeRef, Type, LeafOrInternal> {
+impl<K, V, NodeRef: Deref<Node<K, V>>, Type> Handle<NodeRef, Type, handle::LeafOrInternal> {
/// Figure out whether this handle is pointing to something in a leaf node or to something in
/// an internal node, clarifying the type according to the result.
pub fn force(self) -> ForceResult<NodeRef, Type> {
}
}
-impl<K, V, NodeRef: DerefMut<Node<K, V>>> Handle<NodeRef, Edge, Leaf> {
+impl<K, V, NodeRef: DerefMut<Node<K, V>>> Handle<NodeRef, handle::Edge, handle::Leaf> {
/// Tries to insert this key-value pair at the given index in this leaf node
/// If the node is full, we have to split it.
///
}
}
-impl<K, V, NodeRef: DerefMut<Node<K, V>>> Handle<NodeRef, Edge, Internal> {
+impl<K, V, NodeRef: DerefMut<Node<K, V>>> Handle<NodeRef, handle::Edge, handle::Internal> {
/// Returns a mutable reference to the edge pointed-to by this handle. This should not be
/// confused with `node`, which references the parent node of what is returned here.
pub fn edge_mut(&mut self) -> &mut Node<K, V> {
}
}
-impl<K, V, NodeRef: DerefMut<Node<K, V>>, NodeType> Handle<NodeRef, Edge, NodeType> {
+impl<K, V, NodeRef: DerefMut<Node<K, V>>, NodeType> Handle<NodeRef, handle::Edge, NodeType> {
/// Gets the handle pointing to the key/value pair just to the left of the pointed-to edge.
/// This is unsafe because the handle might point to the first edge in the node, which has no
/// pair to its left.
- unsafe fn left_kv<'a>(&'a mut self) -> Handle<&'a mut Node<K, V>, KV, NodeType> {
+ unsafe fn left_kv<'a>(&'a mut self) -> Handle<&'a mut Node<K, V>, handle::KV, NodeType> {
Handle {
node: &mut *self.node,
index: self.index - 1
/// Gets the handle pointing to the key/value pair just to the right of the pointed-to edge.
/// This is unsafe because the handle might point to the last edge in the node, which has no
/// pair to its right.
- unsafe fn right_kv<'a>(&'a mut self) -> Handle<&'a mut Node<K, V>, KV, NodeType> {
+ unsafe fn right_kv<'a>(&'a mut self) -> Handle<&'a mut Node<K, V>, handle::KV, NodeType> {
Handle {
node: &mut *self.node,
index: self.index
}
}
-impl<'a, K: 'a, V: 'a, NodeType> Handle<&'a Node<K, V>, KV, NodeType> {
+impl<'a, K: 'a, V: 'a, NodeType> Handle<&'a Node<K, V>, handle::KV, NodeType> {
/// Turns the handle into references to the key and value it points at. This is necessary
/// because the returned pointers have larger lifetimes than what would be returned by `key`
/// or `val`.
}
}
-impl<'a, K: 'a, V: 'a, NodeType> Handle<&'a mut Node<K, V>, KV, NodeType> {
+impl<'a, K: 'a, V: 'a, NodeType> Handle<&'a mut Node<K, V>, handle::KV, NodeType> {
/// Turns the handle into mutable references to the key and value it points at. This is
/// necessary because the returned pointers have larger lifetimes than what would be returned
/// by `key_mut` or `val_mut`.
/// Convert this handle into one pointing at the edge immediately to the left of the key/value
/// pair pointed-to by this handle. This is useful because it returns a reference with larger
/// lifetime than `left_edge`.
- pub fn into_left_edge(self) -> Handle<&'a mut Node<K, V>, Edge, NodeType> {
+ pub fn into_left_edge(self) -> Handle<&'a mut Node<K, V>, handle::Edge, NodeType> {
Handle {
node: &mut *self.node,
index: self.index
}
}
-impl<'a, K: 'a, V: 'a, NodeRef: Deref<Node<K, V>> + 'a, NodeType> Handle<NodeRef, KV, NodeType> {
+impl<'a, K: 'a, V: 'a, NodeRef: Deref<Node<K, V>> + 'a, NodeType> Handle<NodeRef, handle::KV,
+ NodeType> {
// These are fine to include, but are currently unneeded.
//
// /// Returns a reference to the key pointed-to by this handle. This doesn't return a
// }
}
-impl<'a, K: 'a, V: 'a, NodeRef: DerefMut<Node<K, V>> + 'a, NodeType> Handle<NodeRef, KV, NodeType> {
+impl<'a, K: 'a, V: 'a, NodeRef: DerefMut<Node<K, V>> + 'a, NodeType> Handle<NodeRef, handle::KV,
+ NodeType> {
/// Returns a mutable reference to the key pointed-to by this handle. This doesn't return a
/// reference with a lifetime as large as `into_kv_mut`, but it also does not consume the
/// handle.
}
}
-impl<K, V, NodeRef: DerefMut<Node<K, V>>, NodeType> Handle<NodeRef, KV, NodeType> {
+impl<K, V, NodeRef: DerefMut<Node<K, V>>, NodeType> Handle<NodeRef, handle::KV, NodeType> {
/// Gets the handle pointing to the edge immediately to the left of the key/value pair pointed
/// to by this handle.
- pub fn left_edge<'a>(&'a mut self) -> Handle<&'a mut Node<K, V>, Edge, NodeType> {
+ pub fn left_edge<'a>(&'a mut self) -> Handle<&'a mut Node<K, V>, handle::Edge, NodeType> {
Handle {
node: &mut *self.node,
index: self.index
/// Gets the handle pointing to the edge immediately to the right of the key/value pair pointed
/// to by this handle.
- pub fn right_edge<'a>(&'a mut self) -> Handle<&'a mut Node<K, V>, Edge, NodeType> {
+ pub fn right_edge<'a>(&'a mut self) -> Handle<&'a mut Node<K, V>, handle::Edge, NodeType> {
Handle {
node: &mut *self.node,
index: self.index + 1
}
}
-impl<K, V, NodeRef: DerefMut<Node<K, V>>> Handle<NodeRef, KV, Leaf> {
+impl<K, V, NodeRef: DerefMut<Node<K, V>>> Handle<NodeRef, handle::KV, handle::Leaf> {
/// Removes the key/value pair at the handle's location.
///
/// # Panics (in debug build)
}
}
-impl<K, V, NodeRef: DerefMut<Node<K, V>>> Handle<NodeRef, KV, Internal> {
+impl<K, V, NodeRef: DerefMut<Node<K, V>>> Handle<NodeRef, handle::KV, handle::Internal> {
/// Steal! Stealing is roughly analogous to a binary tree rotation.
/// In this case, we're "rotating" right.
unsafe fn steal_rightward(&mut self) {
/// # Panics (in debug build)
///
/// Panics if the given index is out of bounds.
- pub fn kv_handle(&mut self, index: uint) -> Handle<&mut Node<K, V>, KV, LeafOrInternal> {
+ pub fn kv_handle(&mut self, index: uint) -> Handle<&mut Node<K, V>, handle::KV,
+ handle::LeafOrInternal> {
// Necessary for correctness, but in a private module
debug_assert!(index < self.len(), "kv_handle index out of bounds");
Handle {
#[cfg(test)]
mod test {
- use std::prelude::*;
+ use prelude::*;
use super::BTreeSet;
use std::hash;
}
}
+#[stable]
impl<A: Clone> Clone for DList<A> {
fn clone(&self) -> DList<A> {
self.iter().map(|x| x.clone()).collect()
#[cfg(test)]
mod tests {
- use std::prelude::*;
+ use prelude::*;
use std::rand;
use std::hash;
+ use std::task::spawn;
use test::Bencher;
use test;
use super::{DList, Node, ListInsertion};
- use vec::Vec;
pub fn check_links<T>(list: &DList<T>) {
let mut len = 0u;
#[cfg(test)]
mod test {
- use std::prelude::*;
use self::Foo::*;
- use std::mem;
+ use prelude::*;
+ use core::mem;
use super::{EnumSet, CLike};
#![allow(unknown_features)]
#![feature(macro_rules, default_type_params, phase, globs)]
-#![feature(unsafe_destructor, import_shadowing, slicing_syntax)]
+#![feature(unsafe_destructor, slicing_syntax)]
#![feature(unboxed_closures)]
#![no_std]
pub use core::kinds; // deriving(Copy)
pub use core::hash; // deriving(Hash)
}
+
+#[cfg(test)]
+mod prelude {
+ // from core.
+ pub use core::borrow::IntoCow;
+ pub use core::char::Char;
+ pub use core::clone::Clone;
+ pub use core::cmp::{PartialEq, Eq, Equiv, PartialOrd, Ord};
+ pub use core::cmp::Ordering::{Less, Equal, Greater};
+ pub use core::iter::range;
+ pub use core::iter::{FromIterator, Extend, IteratorExt};
+ pub use core::iter::{Iterator, DoubleEndedIterator, RandomAccessIterator};
+ pub use core::iter::{IteratorCloneExt, CloneIteratorExt, DoubleEndedIteratorExt};
+ pub use core::iter::{IteratorOrdExt, MutableDoubleEndedIterator, ExactSizeIterator};
+ pub use core::kinds::{Copy, Send, Sized, Sync};
+ pub use core::mem::drop;
+ pub use core::ops::{Drop, Fn, FnMut, FnOnce};
+ pub use core::option::Option;
+ pub use core::option::Option::{Some, None};
+ pub use core::ptr::RawPtr;
+ pub use core::result::Result;
+ pub use core::result::Result::{Ok, Err};
+
+ // in core and collections (may differ).
+ pub use slice::{PartialEqSliceExt, OrdSliceExt};
+ pub use slice::{AsSlice, SliceExt};
+ pub use str::{from_str, Str, StrPrelude};
+
+ // from other crates.
+ pub use alloc::boxed::Box;
+ pub use unicode::char::UnicodeChar;
+
+ // from collections.
+ pub use slice::{CloneSliceExt, VectorVector};
+ pub use str::{IntoMaybeOwned, UnicodeStrPrelude, StrAllocating, StrVector};
+ pub use string::{String, ToString};
+ pub use vec::Vec;
+}
ptr: *mut T
}
+#[stable]
impl<T: Clone> Clone for RingBuf<T> {
fn clone(&self) -> RingBuf<T> {
self.iter().map(|t| t.clone()).collect()
impl<T> RingBuf<T> {
/// Turn ptr into a slice
#[inline]
- unsafe fn buffer_as_slice(&self) -> &[T] {
+ unsafe fn buffer_as_slice<'a>(&'a self) -> &'a [T] {
+ mem::transmute(RawSlice { data: self.ptr as *const T, len: self.cap })
+ }
+
+ /// Turn ptr into a mut slice
+ #[inline]
+ unsafe fn buffer_as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
mem::transmute(RawSlice { data: self.ptr as *const T, len: self.cap })
}
}
}
+ /// Returns a pair of slices which contain, in order, the contents of the
+ /// `RingBuf`.
+ #[inline]
+ #[unstable = "matches collection reform specification, waiting for dust to settle"]
+ pub fn as_slices<'a>(&'a self) -> (&'a [T], &'a [T]) {
+ unsafe {
+ let contiguous = self.is_contiguous();
+ let buf = self.buffer_as_slice();
+ if contiguous {
+ let (empty, buf) = buf.split_at(0);
+ (buf[self.tail..self.head], empty)
+ } else {
+ let (mid, right) = buf.split_at(self.tail);
+ let (left, _) = mid.split_at(self.head);
+ (right, left)
+ }
+ }
+ }
+
+ /// Returns a pair of slices which contain, in order, the contents of the
+ /// `RingBuf`.
+ #[inline]
+ #[unstable = "matches collection reform specification, waiting for dust to settle"]
+ pub fn as_mut_slices<'a>(&'a mut self) -> (&'a mut [T], &'a mut [T]) {
+ unsafe {
+ let contiguous = self.is_contiguous();
+ let head = self.head;
+ let tail = self.tail;
+ let buf = self.buffer_as_mut_slice();
+
+ if contiguous {
+ let (empty, buf) = buf.split_at_mut(0);
+ (buf[mut tail..head], empty)
+ } else {
+ let (mid, right) = buf.split_at_mut(tail);
+ let (left, _) = mid.split_at_mut(head);
+
+ (right, left)
+ }
+ }
+ }
+
/// Returns the number of elements in the `RingBuf`.
///
/// # Examples
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn is_empty(&self) -> bool { self.len() == 0 }
+ /// Creates a draining iterator that clears the `RingBuf` and iterates over
+ /// the removed items from start to end.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::RingBuf;
+ ///
+ /// let mut v = RingBuf::new();
+ /// v.push_back(1i);
+ /// assert_eq!(v.drain().next(), Some(1));
+ /// assert!(v.is_empty());
+ /// ```
+ #[inline]
+ #[unstable = "matches collection reform specification, waiting for dust to settle"]
+ pub fn drain<'a>(&'a mut self) -> Drain<'a, T> {
+ Drain {
+ inner: self,
+ }
+ }
+
/// Clears the buffer, removing all values.
///
/// # Examples
/// assert!(v.is_empty());
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
+ #[inline]
pub fn clear(&mut self) {
- while self.pop_front().is_some() {}
- self.head = 0;
- self.tail = 0;
+ self.drain();
}
/// Provides a reference to the front element, or `None` if the sequence is
}
}
+ #[inline]
+ fn is_contiguous(&self) -> bool {
+ self.tail <= self.head
+ }
+
/// Inserts an element at position `i` within the ringbuf. Whichever
/// end is closer to the insertion point will be moved to make room,
/// and all the affected elements will be moved to new positions.
let distance_to_tail = i;
let distance_to_head = self.len() - i;
- let contiguous = self.tail <= self.head;
+ let contiguous = self.is_contiguous();
match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) {
(true, true, _) if i == 0 => {
}
}
-
impl<T> ExactSizeIterator<T> for MoveItems<T> {}
+/// A draining RingBuf iterator
+pub struct Drain<'a, T: 'a> {
+ inner: &'a mut RingBuf<T>,
+}
+
+#[unsafe_destructor]
+impl<'a, T: 'a> Drop for Drain<'a, T> {
+ fn drop(&mut self) {
+ for _ in *self {}
+ self.inner.head = 0;
+ self.inner.tail = 0;
+ }
+}
+
+impl<'a, T: 'a> Iterator<T> for Drain<'a, T> {
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ self.inner.pop_front()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let len = self.inner.len();
+ (len, Some(len))
+ }
+}
+
+impl<'a, T: 'a> DoubleEndedIterator<T> for Drain<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<T> {
+ self.inner.pop_back()
+ }
+}
+
+impl<'a, T: 'a> ExactSizeIterator<T> for Drain<'a, T> {}
+
impl<A: PartialEq> PartialEq for RingBuf<A> {
fn eq(&self, other: &RingBuf<A>) -> bool {
self.len() == other.len() &&
#[cfg(test)]
mod tests {
- use core::iter;
use self::Taggy::*;
use self::Taggypar::*;
- use std::cmp;
+ use prelude::*;
+ use core::cmp;
+ use core::iter;
use std::fmt::Show;
- use std::prelude::*;
use std::hash;
use test::Bencher;
use test;
use super::RingBuf;
- use vec::Vec;
#[test]
#[allow(deprecated)]
}
}
+ #[test]
+ fn test_drain() {
+
+ // Empty iter
+ {
+ let mut d: RingBuf<int> = RingBuf::new();
+
+ {
+ let mut iter = d.drain();
+
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ }
+
+ assert!(d.is_empty());
+ }
+
+ // simple iter
+ {
+ let mut d = RingBuf::new();
+ for i in range(0i, 5) {
+ d.push_back(i);
+ }
+
+ assert_eq!(d.drain().collect::<Vec<int>>(), [0, 1, 2, 3, 4]);
+ assert!(d.is_empty());
+ }
+
+ // wrapped iter
+ {
+ let mut d = RingBuf::new();
+ for i in range(0i, 5) {
+ d.push_back(i);
+ }
+ for i in range(6, 9) {
+ d.push_front(i);
+ }
+
+ assert_eq!(d.drain().collect::<Vec<int>>(), [8,7,6,0,1,2,3,4]);
+ assert!(d.is_empty());
+ }
+
+ // partially used
+ {
+ let mut d = RingBuf::new();
+ for i in range(0i, 5) {
+ d.push_back(i);
+ }
+ for i in range(6, 9) {
+ d.push_front(i);
+ }
+
+ {
+ let mut it = d.drain();
+ assert_eq!(it.size_hint(), (8, Some(8)));
+ assert_eq!(it.next(), Some(8));
+ assert_eq!(it.size_hint(), (7, Some(7)));
+ assert_eq!(it.next_back(), Some(4));
+ assert_eq!(it.size_hint(), (6, Some(6)));
+ assert_eq!(it.next(), Some(7));
+ assert_eq!(it.size_hint(), (5, Some(5)));
+ }
+ assert!(d.is_empty());
+ }
+ }
+
#[test]
fn test_from_iter() {
- use std::iter;
+ use core::iter;
let v = vec!(1i,2,3,4,5,6,7);
let deq: RingBuf<int> = v.iter().map(|&x| x).collect();
let u: Vec<int> = deq.iter().map(|&x| x).collect();
ring.pop_front();
assert_eq!(ring.front(), None);
}
+
+ #[test]
+ fn test_as_slices() {
+ let mut ring: RingBuf<int> = RingBuf::with_capacity(127);
+ let cap = ring.capacity() as int;
+ let first = cap/2;
+ let last = cap - first;
+ for i in range(0, first) {
+ ring.push_back(i);
+
+ let (left, right) = ring.as_slices();
+ let expected: Vec<_> = range(0, i+1).collect();
+ assert_eq!(left, expected);
+ assert_eq!(right, []);
+ }
+
+ for j in range(-last, 0) {
+ ring.push_front(j);
+ let (left, right) = ring.as_slices();
+ let expected_left: Vec<_> = range(-last, j+1).rev().collect();
+ let expected_right: Vec<_> = range(0, first).collect();
+ assert_eq!(left, expected_left);
+ assert_eq!(right, expected_right);
+ }
+
+ assert_eq!(ring.len() as int, cap);
+ assert_eq!(ring.capacity() as int, cap);
+ }
+
+ #[test]
+ fn test_as_mut_slices() {
+ let mut ring: RingBuf<int> = RingBuf::with_capacity(127);
+ let cap = ring.capacity() as int;
+ let first = cap/2;
+ let last = cap - first;
+ for i in range(0, first) {
+ ring.push_back(i);
+
+ let (left, right) = ring.as_mut_slices();
+ let expected: Vec<_> = range(0, i+1).collect();
+ assert_eq!(left, expected);
+ assert_eq!(right, []);
+ }
+
+ for j in range(-last, 0) {
+ ring.push_front(j);
+ let (left, right) = ring.as_mut_slices();
+ let expected_left: Vec<_> = range(-last, j+1).rev().collect();
+ let expected_right: Vec<_> = range(0, first).collect();
+ assert_eq!(left, expected_left);
+ assert_eq!(right, expected_right);
+ }
+
+ assert_eq!(ring.len() as int, cap);
+ assert_eq!(ring.capacity() as int, cap);
+ }
}
#[cfg(test)]
mod tests {
use std::boxed::Box;
- use std::cell::Cell;
- use std::default::Default;
- use std::mem;
- use std::prelude::*;
+ use prelude::*;
+ use core::cell::Cell;
+ use core::default::Default;
+ use core::mem;
use std::rand::{Rng, task_rng};
use std::rc::Rc;
- use std::rt;
- use slice::*;
-
- use vec::Vec;
+ use super::ElementSwaps;
fn square(n: uint) -> uint { n * n }
#[cfg(test)]
mod bench {
- use std::prelude::*;
+ use prelude::*;
+ use core::mem;
+ use core::ptr;
use std::rand::{weak_rng, Rng};
- use std::mem;
- use std::ptr;
use test::{Bencher, black_box};
- use vec::Vec;
-
#[bench]
fn iterator(b: &mut Bencher) {
// peculiar numbers to stop LLVM from optimising the summation
#![doc(primitive = "str")]
-use core::prelude::*;
-
-pub use self::MaybeOwned::*;
+use self::MaybeOwned::*;
use self::RecompositionState::*;
use self::DecompositionType::*;
use core::borrow::{BorrowFrom, Cow, ToOwned};
+use core::clone::Clone;
use core::default::Default;
use core::fmt;
use core::hash;
-use core::cmp;
-use core::iter::AdditiveIterator;
+use core::char::Char;
+use core::cmp::{mod, Eq, Equiv, Ord, Ordering, PartialEq, PartialOrd};
+use core::iter::{range, AdditiveIterator, Iterator, IteratorExt};
+use core::kinds::Sized;
+use core::option::Option::{mod, Some, None};
+use core::slice::{AsSlice, SliceExt};
use ring_buf::RingBuf;
use string::String;
#[cfg(test)]
mod tests {
- use std::iter::AdditiveIterator;
- use std::iter::range;
- use std::default::Default;
- use std::char::Char;
- use std::clone::Clone;
- use std::cmp::{Ord, PartialOrd, Equiv};
- use std::cmp::Ordering::{Equal, Greater, Less};
- use std::option::Option;
- use std::option::Option::{Some, None};
- use std::ptr::RawPtr;
- use std::iter::{Iterator, IteratorExt, DoubleEndedIteratorExt};
-
- use super::*;
- use std::slice::{AsSlice, SliceExt};
- use string::String;
- use vec::Vec;
- use slice::CloneSliceExt;
-
- use unicode::char::UnicodeChar;
+ use prelude::*;
+ use core::default::Default;
+ use core::iter::AdditiveIterator;
+ use super::{eq_slice, from_utf8, is_utf8, is_utf16, raw};
+ use super::truncate_utf16_at_nul;
+ use super::MaybeOwned::{Owned, Slice};
#[test]
fn test_eq_slice() {
#[test]
fn test_lev_distance() {
- use std::char::{ from_u32, MAX };
+ use core::char::{ from_u32, MAX };
// Test bytelength agnosticity
for c in range(0u32, MAX as u32)
.filter_map(|i| from_u32(i))
#[test]
fn test_graphemes() {
- use std::iter::order;
+ use core::iter::order;
// official Unicode test data
// from http://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt
let test_same: [(_, &[_]), .. 325] = [
#[test]
fn test_str_default() {
- use std::default::Default;
+ use core::default::Default;
fn t<S: Default + Str>() {
let s: S = Default::default();
assert_eq!(s.as_slice(), "");
#[cfg(test)]
mod bench {
+ use prelude::*;
use test::Bencher;
use test::black_box;
use super::*;
- use std::iter::{IteratorExt, DoubleEndedIteratorExt};
- use std::str::StrPrelude;
- use std::slice::SliceExt;
#[bench]
fn char_iterator(b: &mut Bencher) {
use slice::CloneSliceExt;
use str;
-use str::{CharRange, CowString, FromStr, StrAllocating, Owned};
+use str::{CharRange, CowString, FromStr, StrAllocating};
+use str::MaybeOwned::Owned;
use vec::{DerefVec, Vec, as_vec};
/// A growable string stored as a UTF-8 encoded buffer.
#[inline]
#[stable = "function just renamed from push_char"]
pub fn push(&mut self, ch: char) {
+ if (ch as u32) < 0x80 {
+ self.vec.push(ch as u8);
+ return;
+ }
+
let cur_len = self.len();
// This may use up to 4 bytes.
self.vec.reserve(4);
}
}
-#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot
-impl<'a> Add<String, String> for &'a str {
- fn add(self, mut other: String) -> String {
- other.push_str(self);
- other
- }
-}
-
impl ops::Slice<uint, str> for String {
#[inline]
fn as_slice_<'a>(&'a self) -> &'a str {
#[cfg(test)]
mod tests {
- use std::prelude::*;
+ use prelude::*;
use test::Bencher;
- use slice::CloneSliceExt;
- use str::{Str, StrPrelude};
use str;
- use super::{as_string, String, ToString};
- use vec::Vec;
+ use super::as_string;
#[test]
fn test_as_string() {
});
}
+ const REPETITIONS: u64 = 10_000;
+
+ #[bench]
+ fn bench_push_str_one_byte(b: &mut Bencher) {
+ b.bytes = REPETITIONS;
+ b.iter(|| {
+ let mut r = String::new();
+ for _ in range(0, REPETITIONS) {
+ r.push_str("a")
+ }
+ });
+ }
+
+ #[bench]
+ fn bench_push_char_one_byte(b: &mut Bencher) {
+ b.bytes = REPETITIONS;
+ b.iter(|| {
+ let mut r = String::new();
+ for _ in range(0, REPETITIONS) {
+ r.push('a')
+ }
+ });
+ }
+
+ #[bench]
+ fn bench_push_char_two_bytes(b: &mut Bencher) {
+ b.bytes = REPETITIONS * 2;
+ b.iter(|| {
+ let mut r = String::new();
+ for _ in range(0, REPETITIONS) {
+ r.push('â')
+ }
+ });
+ }
+
#[bench]
fn from_utf8_lossy_100_ascii(b: &mut Bencher) {
let s = b"Hello there, the quick brown fox jumped over the lazy dog! \
use core::fmt;
use core::hash::{mod, Hash};
use core::kinds::marker::{ContravariantLifetime, InvariantType};
-use core::kinds::Sized;
use core::mem;
use core::num::{Int, UnsignedInt};
use core::ops;
}
}
+ /// Resizes the `Vec` in-place so that `len()` is equal to `new_len`.
+ ///
+ /// Calls either `extend()` or `truncate()` depending on whether `new_len`
+ /// is larger than the current value of `len()` or not.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut vec = vec!["hello"];
+ /// vec.resize(3, "world");
+ /// assert_eq!(vec, vec!["hello", "world", "world"]);
+ ///
+ /// let mut vec = vec![1i, 2, 3, 4];
+ /// vec.resize(2, 0);
+ /// assert_eq!(vec, vec![1, 2]);
+ /// ```
+ #[unstable = "matches collection reform specification; waiting for dust to settle"]
+ pub fn resize(&mut self, new_len: uint, value: T) {
+ let len = self.len();
+
+ if new_len > len {
+ self.extend(repeat(value).take(new_len - len));
+ } else {
+ self.truncate(new_len);
+ }
+ }
+
/// Partitions a vector based on a predicate.
///
/// Clones the elements of the vector, partitioning them into two `Vec<T>`s
}
}
-#[unstable]
+#[stable]
impl<T:Clone> Clone for Vec<T> {
fn clone(&self) -> Vec<T> { self.as_slice().to_vec() }
}
}
+ /// Creates a draining iterator that clears the `Vec` and iterates over
+ /// the removed items from start to end.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = vec!["a".to_string(), "b".to_string()];
+ /// for s in v.drain() {
+ /// // s has type String, not &String
+ /// println!("{}", s);
+ /// }
+ /// assert!(v.is_empty());
+ /// ```
+ #[inline]
+ #[unstable = "matches collection reform specification, waiting for dust to settle"]
+ pub fn drain<'a>(&'a mut self) -> Drain<'a, T> {
+ unsafe {
+ let begin = self.ptr as *const T;
+ let end = if mem::size_of::<T>() == 0 {
+ (self.ptr as uint + self.len()) as *const T
+ } else {
+ self.ptr.offset(self.len() as int) as *const T
+ };
+ self.set_len(0);
+ Drain {
+ ptr: begin,
+ end: end,
+ marker: ContravariantLifetime,
+ }
+ }
+ }
+
/// Clears the vector, removing all values.
///
/// # Examples
}
}
-#[cfg(not(stage0))] // NOTE(stage0): Remove impl after a snapshot
-impl<'a, T: Clone> Add<Vec<T>, Vec<T>> for &'a [T] {
- #[inline]
- fn add(self, mut rhs: Vec<T>) -> Vec<T> {
- rhs.push_all(self);
- rhs
- }
-}
-
#[unsafe_destructor]
impl<T> Drop for Vec<T> {
fn drop(&mut self) {
}
impl<T> MoveItems<T> {
- #[inline]
/// Drops all items that have not yet been moved and returns the empty vector.
+ #[inline]
+ #[unstable]
pub fn into_inner(mut self) -> Vec<T> {
unsafe {
for _x in self { }
}
}
- /// Deprecated, use into_inner() instead
- #[deprecated = "renamed to into_inner()"]
+ /// Deprecated, use .into_inner() instead
+ #[deprecated = "use .into_inner() instead"]
pub fn unwrap(self) -> Vec<T> { self.into_inner() }
}
}
}
+/// An iterator that drains a vector.
+#[unsafe_no_drop_flag]
+pub struct Drain<'a, T> {
+ ptr: *const T,
+ end: *const T,
+ marker: ContravariantLifetime<'a>,
+}
+
+impl<'a, T> Iterator<T> for Drain<'a, T> {
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ unsafe {
+ if self.ptr == self.end {
+ None
+ } else {
+ if mem::size_of::<T>() == 0 {
+ // purposefully don't use 'ptr.offset' because for
+ // vectors with 0-size elements this would return the
+ // same pointer.
+ self.ptr = mem::transmute(self.ptr as uint + 1);
+
+ // Use a non-null pointer value
+ Some(ptr::read(mem::transmute(1u)))
+ } else {
+ let old = self.ptr;
+ self.ptr = self.ptr.offset(1);
+
+ Some(ptr::read(old))
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let diff = (self.end as uint) - (self.ptr as uint);
+ let size = mem::size_of::<T>();
+ let exact = diff / (if size == 0 {1} else {size});
+ (exact, Some(exact))
+ }
+}
+
+impl<'a, T> DoubleEndedIterator<T> for Drain<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<T> {
+ unsafe {
+ if self.end == self.ptr {
+ None
+ } else {
+ if mem::size_of::<T>() == 0 {
+ // See above for why 'ptr.offset' isn't used
+ self.end = mem::transmute(self.end as uint - 1);
+
+ // Use a non-null pointer value
+ Some(ptr::read(mem::transmute(1u)))
+ } else {
+ self.end = self.end.offset(-1);
+
+ Some(ptr::read(self.end))
+ }
+ }
+ }
+ }
+}
+
+impl<'a, T> ExactSizeIterator<T> for Drain<'a, T> {}
+
+#[unsafe_destructor]
+impl<'a, T> Drop for Drain<'a, T> {
+ fn drop(&mut self) {
+ // self.ptr == self.end == null if drop has already been called,
+ // so we can use #[unsafe_no_drop_flag].
+
+ // destroy the remaining elements
+ for _x in *self {}
+ }
+}
+
/// Converts an iterator of pairs into a pair of vectors.
///
/// Returns a tuple containing two vectors where the i-th element of the first vector contains the
#[cfg(test)]
mod tests {
- extern crate test;
-
- use std::prelude::*;
- use std::mem::size_of;
+ use prelude::*;
+ use core::mem::size_of;
use test::Bencher;
- use super::{as_vec, unzip, raw, Vec};
+ use super::{as_vec, unzip, raw};
struct DropCounter<'a> {
count: &'a mut int
assert!(vec2 == vec![(), (), ()]);
}
+ #[test]
+ fn test_drain_items() {
+ let mut vec = vec![1, 2, 3];
+ let mut vec2: Vec<i32> = vec![];
+ for i in vec.drain() {
+ vec2.push(i);
+ }
+ assert_eq!(vec, []);
+ assert_eq!(vec2, [ 1, 2, 3 ]);
+ }
+
+ #[test]
+ fn test_drain_items_reverse() {
+ let mut vec = vec![1, 2, 3];
+ let mut vec2: Vec<i32> = vec![];
+ for i in vec.drain().rev() {
+ vec2.push(i);
+ }
+ assert_eq!(vec, []);
+ assert_eq!(vec2, [ 3, 2, 1 ]);
+ }
+
+ #[test]
+ fn test_drain_items_zero_sized() {
+ let mut vec = vec![(), (), ()];
+ let mut vec2: Vec<()> = vec![];
+ for i in vec.drain() {
+ vec2.push(i);
+ }
+ assert_eq!(vec, []);
+ assert_eq!(vec2, [(), (), ()]);
+ }
+
#[test]
fn test_into_boxed_slice() {
let xs = vec![1u, 2, 3];
use core::iter;
use core::iter::{Enumerate, FilterMap, Map};
use core::mem::replace;
-use core::ops::FnOnce;
use {vec, slice};
use vec::Vec;
#[cfg(test)]
mod test_map {
- use std::prelude::*;
- use vec::Vec;
+ use prelude::*;
use core::hash::hash;
use super::VecMap;
#[cfg(test)]
mod bench {
- extern crate test;
- use self::test::Bencher;
+ use test::Bencher;
use super::VecMap;
use bench::{insert_rand_n, insert_seq_n, find_rand_n, find_seq_n};
macro_rules! array_impls {
($($N:expr)+) => {
$(
- #[unstable = "waiting for Clone to stabilize"]
+ #[stable]
impl<T:Copy> Clone for [T, ..$N] {
fn clone(&self) -> [T, ..$N] {
*self
20 21 22 23 24 25 26 27 28 29
30 31 32
}
-
+++ /dev/null
-// Copyright 2013 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.
-
-//! The boolean type
-
-#![doc(primitive = "bool")]
-#![unstable = "this module is purely for documentation and it will likely be \
- removed from the public api"]
-
Owned(T)
}
+#[stable]
impl<'a, T, Sized? B> Clone for Cow<'a, T, B> where B: ToOwned<T> {
fn clone(&self) -> Cow<'a, T, B> {
match *self {
use option::Option::{None, Some};
/// A mutable memory location that admits only `Copy` data.
-#[unstable = "likely to be renamed; otherwise stable"]
+#[stable]
pub struct Cell<T> {
value: UnsafeCell<T>,
noshare: marker::NoSync,
}
}
-#[unstable = "waiting for `Clone` trait to become stable"]
+#[stable]
impl<T:Copy> Clone for Cell<T> {
fn clone(&self) -> Cell<T> {
Cell::new(self.get())
}
/// A mutable memory location with dynamically checked borrow rules
-#[unstable = "likely to be renamed; otherwise stable"]
+#[stable]
pub struct RefCell<T> {
value: UnsafeCell<T>,
borrow: Cell<BorrowFlag>,
}
/// Consumes the `RefCell`, returning the wrapped value.
- #[unstable = "recently renamed per RFC 430"]
+ #[stable]
pub fn into_inner(self) -> T {
// Since this function takes `self` (the `RefCell`) by value, the
// compiler statically verifies that it is not currently borrowed.
/// immutable borrows can be taken out at the same time.
///
/// Returns `None` if the value is currently mutably borrowed.
- #[unstable = "may be renamed, depending on global conventions"]
+ #[unstable = "may be renamed or removed"]
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
match BorrowRef::new(&self.borrow) {
Some(b) => Some(Ref { _value: unsafe { &*self.value.get() }, _borrow: b }),
/// # Panics
///
/// Panics if the value is currently mutably borrowed.
- #[unstable]
+ #[stable]
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
match self.try_borrow() {
Some(ptr) => ptr,
/// cannot be borrowed while this borrow is active.
///
/// Returns `None` if the value is currently borrowed.
- #[unstable = "may be renamed, depending on global conventions"]
+ #[unstable = "may be renamed or removed"]
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
match BorrowRefMut::new(&self.borrow) {
Some(b) => Some(RefMut { _value: unsafe { &mut *self.value.get() }, _borrow: b }),
/// # Panics
///
/// Panics if the value is currently borrowed.
- #[unstable]
+ #[stable]
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
match self.try_borrow_mut() {
Some(ptr) => ptr,
}
}
-#[unstable = "waiting for `Clone` to become stable"]
+#[stable]
impl<T: Clone> Clone for RefCell<T> {
fn clone(&self) -> RefCell<T> {
RefCell::new(self.borrow().clone())
}
/// Wraps a borrowed reference to a value in a `RefCell` box.
-#[unstable]
+#[stable]
pub struct Ref<'b, T:'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
}
/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
-#[unstable]
+#[stable]
pub struct RefMut<'b, T:'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
/// is not recommended to access its fields directly, `get` should be used
/// instead.
#[lang="unsafe"]
-#[unstable = "this type may be renamed in the future"]
+#[stable]
pub struct UnsafeCell<T> {
/// Wrapped value
///
}
/// Gets a mutable pointer to the wrapped value.
- ///
- /// This function is unsafe as the pointer returned is an unsafe pointer and
- /// no guarantees are made about the aliasing of the pointers being handed
- /// out in this or other tasks.
#[inline]
- #[unstable = "conventions around acquiring an inner reference are still \
- under development"]
- pub unsafe fn get(&self) -> *mut T { &self.value as *const T as *mut T }
+ #[stable]
+ pub fn get(&self) -> *mut T { &self.value as *const T as *mut T }
/// Unwraps the value
///
/// This function is unsafe because there is no guarantee that this or other
/// tasks are currently inspecting the inner value.
#[inline]
- #[unstable = "conventions around the name `unwrap` are still under \
- development"]
+ #[stable]
pub unsafe fn into_inner(self) -> T { self.value }
/// Deprecated, use into_inner() instead
//! explicitly, by convention implementing the `Clone` trait and calling
//! the `clone` method.
-#![unstable]
+#![stable]
use kinds::Sized;
/// A common trait for cloning an object.
+#[stable]
pub trait Clone {
/// Returns a copy of the value.
+ #[stable]
fn clone(&self) -> Self;
/// Perform copy-assignment from `source`.
/// but can be overridden to reuse the resources of `a` to avoid unnecessary
/// allocations.
#[inline(always)]
- #[experimental = "this function is mostly unused"]
+ #[unstable = "this function rarely unused"]
fn clone_from(&mut self, source: &Self) {
*self = source.clone()
}
}
+#[stable]
impl<'a, Sized? T> Clone for &'a T {
/// Return a shallow copy of the reference.
#[inline]
macro_rules! clone_impl {
($t:ty) => {
+ #[stable]
impl Clone for $t {
/// Return a deep copy of the value.
#[inline]
extern_fn_clone! { A, B, C, D, E, F }
extern_fn_clone! { A, B, C, D, E, F, G }
extern_fn_clone! { A, B, C, D, E, F, G, H }
-
}
}
+#[stable]
impl Clone for SipState {
#[inline]
fn clone(&self) -> SipState {
#[cfg(test)]
mod tests {
use test::Bencher;
- use std::prelude::*;
+ use prelude::*;
use std::fmt;
- use str::Str;
- use string::String;
- use slice::{AsSlice, SliceExt};
- use vec::Vec;
-
use super::super::{Hash, Writer};
use super::{SipState, hash, hash_with_keys};
/// Both types must have the same size and alignment, and this guarantee
/// is enforced at compile-time.
///
- /// # Example
+ /// # Examples
///
/// ```rust
/// use std::mem;
/// integer, since the conversion would throw away aliasing information.
pub fn offset<T>(dst: *const T, offset: int) -> *const T;
- /// Copies data from one location to another.
- ///
- /// Copies `count` elements (not bytes) from `src` to `dst`. The source
+ /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
/// and destination may *not* overlap.
///
/// `copy_nonoverlapping_memory` is semantically equivalent to C's `memcpy`.
///
- /// # Example
+ /// # Safety
+ ///
+ /// Beyond requiring that both regions of memory be allocated, it is Undefined Behaviour
+ /// for source and destination to overlap. Care must also be taken with the ownership of
+ /// `src` and `dst`. This method semantically moves the values of `src` into `dst`.
+ /// However it does not drop the contents of `dst`, or prevent the contents of `src`
+ /// from being dropped or used.
+ ///
+ /// # Examples
///
/// A safe swap function:
///
/// }
/// }
/// ```
- ///
- /// # Safety Note
- ///
- /// If the source and destination overlap then the behavior of this
- /// function is undefined.
#[unstable]
pub fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint);
- /// Copies data from one location to another.
- ///
- /// Copies `count` elements (not bytes) from `src` to `dst`. The source
+ /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
/// and destination may overlap.
///
/// `copy_memory` is semantically equivalent to C's `memmove`.
///
- /// # Example
+ /// # Safety
+ ///
+ /// Care must be taken with the ownership of `src` and `dst`.
+ /// This method semantically moves the values of `src` into `dst`.
+ /// However it does not drop the contents of `dst`, or prevent the contents of `src`
+ /// from being dropped or used.
+ ///
+ /// # Examples
///
/// Efficiently create a Rust vector from an unsafe buffer:
///
}
// FIXME(#19839) Remove in favor of `#[deriving(Clone)]`
+#[stable]
impl<A, B, I, F> Clone for Map<A, B, I, F> where
I: Clone + Iterator<A>,
F: Clone + FnMut(A) -> B,
}
// FIXME(#19839) Remove in favor of `#[deriving(Clone)]`
+#[stable]
impl<A, I, P> Clone for Filter<A, I, P> where
I: Clone + Iterator<A>,
P: Clone + FnMut(&A) -> bool,
}
// FIXME(#19839) Remove in favor of `#[deriving(Clone)]`
+#[stable]
impl<A, B, I, F> Clone for FilterMap<A, B, I, F> where
I: Clone + Iterator<A>,
F: Clone + FnMut(A) -> Option<B>,
}
// FIXME(#19839) Remove in favor of `#[deriving(Clone)]`
+#[stable]
impl<A, I, P> Clone for SkipWhile<A, I, P> where
I: Clone + Iterator<A>,
P: Clone + FnMut(&A) -> bool,
}
// FIXME(#19839) Remove in favor of `#[deriving(Clone)]`
+#[stable]
impl<A, I, P> Clone for TakeWhile<A, I, P> where
I: Clone + Iterator<A>,
P: Clone + FnMut(&A) -> bool,
}
// FIXME(#19839) Remove in favor of `#[deriving(Clone)]`
+#[stable]
impl<A, B, I, St, F> Clone for Scan<A, B, I, St, F> where
I: Clone + Iterator<A>,
St: Clone,
}
// FIXME(#19839) Remove in favor of `#[deriving(Clone)]`
+#[stable]
impl<A, B, I, U, F> Clone for FlatMap<A, B, I, U, F> where
I: Clone + Iterator<A>,
U: Clone + Iterator<B>,
}
// FIXME(#19839) Remove in favor of `#[deriving(Clone)]`
+#[stable]
impl<A, I, F> Clone for Inspect<A, I, F> where
I: Clone + Iterator<A>,
F: Clone + FnMut(&A),
}
// FIXME(#19839) Remove in favor of `#[deriving(Clone)]`
+#[stable]
impl<A, St, F> Clone for Unfold<A, St, F> where
F: Clone + FnMut(&mut St) -> Option<A>,
St: Clone,
/// implemented using unsafe code. In that case, you may want to embed
/// some of the marker types below into your type.
pub mod marker {
- use super::Copy;
+ use super::{Copy,Sized};
+ use clone::Clone;
/// A marker type whose type parameter `T` is considered to be
/// covariant with respect to the type itself. This is (typically)
/// (for example, `S<&'static int>` is a subtype of `S<&'a int>`
/// for some lifetime `'a`, but not the other way around).
#[lang="covariant_type"]
- #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)]
- pub struct CovariantType<T>;
+ #[deriving(PartialEq, Eq, PartialOrd, Ord)]
+ pub struct CovariantType<Sized? T>;
- impl<T> Copy for CovariantType<T> {}
+ impl<Sized? T> Copy for CovariantType<T> {}
+ impl<Sized? T> Clone for CovariantType<T> {
+ fn clone(&self) -> CovariantType<T> { *self }
+ }
/// A marker type whose type parameter `T` is considered to be
/// contravariant with respect to the type itself. This is (typically)
/// function requires arguments of type `T`, it must also accept
/// arguments of type `U`, hence such a conversion is safe.
#[lang="contravariant_type"]
- #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)]
- pub struct ContravariantType<T>;
+ #[deriving(PartialEq, Eq, PartialOrd, Ord)]
+ pub struct ContravariantType<Sized? T>;
- impl<T> Copy for ContravariantType<T> {}
+ impl<Sized? T> Copy for ContravariantType<T> {}
+ impl<Sized? T> Clone for ContravariantType<T> {
+ fn clone(&self) -> ContravariantType<T> { *self }
+ }
/// A marker type whose type parameter `T` is considered to be
/// invariant with respect to the type itself. This is (typically)
/// never written, but in fact `Cell` uses unsafe code to achieve
/// interior mutability.
#[lang="invariant_type"]
- #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)]
- pub struct InvariantType<T>;
+ #[deriving(PartialEq, Eq, PartialOrd, Ord)]
+ pub struct InvariantType<Sized? T>;
- impl<T> Copy for InvariantType<T> {}
+ impl<Sized? T> Copy for InvariantType<T> {}
+ impl<Sized? T> Clone for InvariantType<T> {
+ fn clone(&self) -> InvariantType<T> { *self }
+ }
/// As `CovariantType`, but for lifetime parameters. Using
/// `CovariantLifetime<'a>` indicates that it is ok to substitute
/// and this pointer is itself stored in an inherently mutable
/// location (such as a `Cell`).
#[lang="invariant_lifetime"]
- #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)]
+ #[deriving(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct InvariantLifetime<'a>;
- impl<'a> Copy for InvariantLifetime<'a> {}
-
/// A type which is considered "not sendable", meaning that it cannot
/// be safely sent between tasks, even if it is owned. This is
/// typically embedded in other types, such as `Gc`, to ensure that
pub mod any;
pub mod atomic;
-pub mod bool;
pub mod borrow;
pub mod cell;
pub mod char;
pub mod simd;
pub mod slice;
pub mod str;
-pub mod tuple;
pub mod hash;
-// FIXME #15320: primitive documentation needs top-level modules, this
-// should be `core::tuple::unit`.
-#[path = "tuple/unit.rs"]
-pub mod unit;
pub mod fmt;
// note: does not need to be public
+mod tuple;
mod array;
#[doc(hidden)]
//! Operations and constants for architecture-sized signed integers (`int` type)
-#![unstable]
+#![stable]
#![doc(primitive = "int")]
#[cfg(target_word_size = "32")] int_module! { int, 32 }
#[cfg(target_word_size = "64")] int_module! { int, 64 }
-
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `Bounded::min_value` function.
-#[unstable]
+#[stable]
pub const MIN: $T = (-1 as $T) << (BITS - 1);
// FIXME(#9837): Compute MIN like this so the high bits that shouldn't exist are 0.
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `Bounded::max_value` function.
-#[unstable]
+#[stable]
pub const MAX: $T = !MIN;
) }
-
//! Operations and constants for architecture-sized unsigned integers (`uint` type)
-#![unstable]
+#![stable]
#![doc(primitive = "uint")]
uint_module! { uint, int, ::int::BITS }
-
#[unstable]
pub const BYTES : uint = ($bits / 8);
-#[unstable]
+#[stable]
pub const MIN: $T = 0 as $T;
-#[unstable]
+#[stable]
pub const MAX: $T = 0 as $T - 1 as $T;
) }
-
impl<'a, A> ExactSizeIterator<&'a A> for Iter<'a, A> {}
+#[stable]
impl<'a, A> Clone for Iter<'a, A> {
fn clone(&self) -> Iter<'a, A> {
Iter { inner: self.inner.clone() }
use cmp::Ordering;
use cmp::Ordering::{Less, Equal, Greater};
-pub use intrinsics::copy_memory;
+// FIXME #19649: instrinsic docs don't render, so these have no docs :(
+
+#[unstable]
pub use intrinsics::copy_nonoverlapping_memory;
+
+#[unstable]
+pub use intrinsics::copy_memory;
+
+#[experimental = "uncertain about naming and semantics"]
pub use intrinsics::set_memory;
-/// Create a null pointer.
+/// Creates a null raw pointer.
///
-/// # Example
+/// # Examples
///
/// ```
/// use std::ptr;
#[unstable = "may need a different name after pending changes to pointer types"]
pub fn null<T>() -> *const T { 0 as *const T }
-/// Create an unsafe mutable null pointer.
+/// Creates a null mutable raw pointer.
///
-/// # Example
+/// # Examples
///
/// ```
/// use std::ptr;
#[unstable = "may need a different name after pending changes to pointer types"]
pub fn null_mut<T>() -> *mut T { 0 as *mut T }
-/// Zeroes out `count * size_of::<T>` bytes of memory at `dst`
+/// Zeroes out `count * size_of::<T>` bytes of memory at `dst`. `count` may be `0`.
+///
+/// # Safety
+///
+/// Beyond accepting a raw pointer, this is unsafe because it will not drop the contents of `dst`,
+/// and may be used to create invalid instances of `T`.
#[inline]
#[experimental = "uncertain about naming and semantics"]
#[allow(experimental)]
set_memory(dst, 0, count);
}
-/// Swap the values at two mutable locations of the same type, without
-/// deinitialising either. They may overlap.
+/// Swaps the values at two mutable locations of the same type, without
+/// deinitialising either. They may overlap, unlike `mem::swap` which is otherwise
+/// equivalent.
+///
+/// # Safety
+///
+/// This is only unsafe because it accepts a raw pointer.
#[inline]
#[unstable]
pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
mem::forget(tmp);
}
-/// Replace the value at a mutable location with a new one, returning the old
-/// value, without deinitialising either.
+/// Replaces the value at `dest` with `src`, returning the old
+/// value, without dropping either.
+///
+/// # Safety
+///
+/// This is only unsafe because it accepts a raw pointer.
+/// Otherwise, this operation is identical to `mem::replace`.
#[inline]
#[unstable]
pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
src
}
-/// Reads the value from `*src` and returns it.
+/// Reads the value from `src` without dropping it. This leaves the
+/// memory in `src` unchanged.
+///
+/// # Safety
+///
+/// Beyond accepting a raw pointer, this is unsafe because it semantically
+/// moves the value out of `src` without preventing further usage of `src`.
+/// If `T` is not `Copy`, then care must be taken to ensure that the value at
+/// `src` is not used before the data is overwritten again (e.g. with `write`,
+/// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use
+/// because it will attempt to drop the value previously at `*src`.
#[inline(always)]
#[unstable]
pub unsafe fn read<T>(src: *const T) -> T {
tmp
}
-/// Reads the value from `*src` and nulls it out.
-/// This currently prevents destructors from executing.
+/// Reads the value from `src` and nulls it out without dropping it.
+///
+/// # Safety
+///
+/// This is unsafe for the same reasons that `read` is unsafe.
#[inline(always)]
#[experimental]
#[allow(experimental)]
tmp
}
-/// Unsafely overwrite a memory location with the given value without destroying
+/// Overwrites a memory location with the given value without reading or dropping
/// the old value.
///
-/// This operation is unsafe because it does not destroy the previous value
-/// contained at the location `dst`. This could leak allocations or resources,
-/// so care must be taken to previously deallocate the value at `dst`.
+/// # Safety
+///
+/// Beyond accepting a raw pointer, this operation is unsafe because it does
+/// not drop the contents of `dst`. This could leak allocations or resources,
+/// so care must be taken not to overwrite an object that should be dropped.
+///
+/// This is appropriate for initializing uninitialized memory, or overwritting memory
+/// that has previously been `read` from.
#[inline]
#[unstable]
pub unsafe fn write<T>(dst: *mut T, src: T) {
/// Methods on raw pointers
pub trait RawPtr<T> {
- /// Returns the null pointer.
+ /// Returns a null raw pointer.
fn null() -> Self;
- /// Returns true if the pointer is equal to the null pointer.
+ /// Returns true if the pointer is null.
fn is_null(&self) -> bool;
- /// Returns true if the pointer is not equal to the null pointer.
+ /// Returns true if the pointer is not null.
fn is_not_null(&self) -> bool { !self.is_null() }
- /// Returns the value of this pointer (ie, the address it points to)
+ /// Returns the address of the pointer.
fn to_uint(&self) -> uint;
/// Returns `None` if the pointer is null, or else returns a reference to the
/// value wrapped in `Some`.
///
- /// # Safety Notes
+ /// # Safety
///
/// While this method and its mutable counterpart are useful for null-safety,
/// it is important to note that this is still an unsafe operation because
/// the returned value could be pointing to invalid memory.
unsafe fn as_ref<'a>(&self) -> Option<&'a T>;
- /// Calculates the offset from a pointer. The offset *must* be in-bounds of
- /// the object, or one-byte-past-the-end. `count` is in units of T; e.g. a
+ /// Calculates the offset from a pointer. `count` is in units of T; e.g. a
/// `count` of 3 represents a pointer offset of `3 * sizeof::<T>()` bytes.
+ ///
+ /// # Safety
+ ///
+ /// The offset must be in-bounds of the object, or one-byte-past-the-end. Otherwise
+ /// `offset` invokes Undefined Behaviour, regardless of whether the pointer is used.
unsafe fn offset(self, count: int) -> Self;
}
/// Methods on mutable raw pointers
pub trait RawMutPtr<T>{
/// Returns `None` if the pointer is null, or else returns a mutable reference
- /// to the value wrapped in `Some`. As with `as_ref`, this is unsafe because
- /// it cannot verify the validity of the returned pointer.
+ /// to the value wrapped in `Some`.
+ ///
+ /// # Safety
+ ///
+ /// As with `as_ref`, this is unsafe because it cannot verify the validity
+ /// of the returned pointer.
unsafe fn as_mut<'a>(&self) -> Option<&'a mut T>;
}
}
}
+#[stable]
impl<T> Clone for *const T {
#[inline]
fn clone(&self) -> *const T {
}
}
+#[stable]
impl<T> Clone for *mut T {
#[inline]
fn clone(&self) -> *mut T {
#[inline]
fn ge(&self, other: &*mut T) -> bool { *self >= *other }
}
-
#![stable]
-use self::Result::*;
+use self::Result::{Ok, Err};
-use std::fmt::Show;
-use slice;
-use slice::AsSlice;
+use clone::Clone;
+use fmt::Show;
use iter::{Iterator, IteratorExt, DoubleEndedIterator, FromIterator, ExactSizeIterator};
-use option::Option;
-use option::Option::{None, Some};
use ops::{FnMut, FnOnce};
+use option::Option::{mod, None, Some};
+use slice::AsSlice;
+use slice;
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
///
#[stable]
pub enum Result<T, E> {
/// Contains the success value
+ #[stable]
Ok(T),
/// Contains the error value
+ #[stable]
Err(E)
}
// Type implementation
/////////////////////////////////////////////////////////////////////////////
+#[stable]
impl<T, E> Result<T, E> {
/////////////////////////////////////////////////////////////////////////
// Querying the contained values
!self.is_ok()
}
-
/////////////////////////////////////////////////////////////////////////
// Adapter for each variant
/////////////////////////////////////////////////////////////////////////
/// ```
#[inline]
#[stable]
- pub fn as_ref<'r>(&'r self) -> Result<&'r T, &'r E> {
+ pub fn as_ref(&self) -> Result<&T, &E> {
match *self {
Ok(ref x) => Ok(x),
Err(ref x) => Err(x),
/// assert_eq!(x.unwrap_err(), 0);
/// ```
#[inline]
- #[unstable = "waiting for mut conventions"]
- pub fn as_mut<'r>(&'r mut self) -> Result<&'r mut T, &'r mut E> {
+ #[stable]
+ pub fn as_mut(&mut self) -> Result<&mut T, &mut E> {
match *self {
Ok(ref mut x) => Ok(x),
Err(ref mut x) => Err(x),
/// ```
#[inline]
#[unstable = "waiting for mut conventions"]
- pub fn as_mut_slice<'r>(&'r mut self) -> &'r mut [T] {
+ pub fn as_mut_slice(&mut self) -> &mut [T] {
match *self {
Ok(ref mut x) => slice::mut_ref_slice(x),
Err(_) => {
/// assert!(sum == 10);
/// ```
#[inline]
- #[unstable = "waiting for unboxed closures"]
+ #[stable]
pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Result<U,E> {
match self {
- Ok(t) => Ok(op(t)),
- Err(e) => Err(e)
+ Ok(t) => Ok(op(t)),
+ Err(e) => Err(e)
}
}
/// assert_eq!(x.map_err(stringify), Err("error code: 13".to_string()));
/// ```
#[inline]
- #[unstable = "waiting for unboxed closures"]
+ #[stable]
pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T,F> {
match self {
- Ok(t) => Ok(t),
- Err(e) => Err(op(e))
+ Ok(t) => Ok(t),
+ Err(e) => Err(op(e))
}
}
-
/////////////////////////////////////////////////////////////////////////
// Iterator constructors
/////////////////////////////////////////////////////////////////////////
/// assert_eq!(x.iter().next(), None);
/// ```
#[inline]
- #[unstable = "waiting for iterator conventions"]
- pub fn iter<'r>(&'r self) -> Item<&'r T> {
- Item{opt: self.as_ref().ok()}
+ #[stable]
+ pub fn iter(&self) -> Iter<T> {
+ Iter { inner: self.as_ref().ok() }
}
/// Returns a mutable iterator over the possibly contained value.
/// assert_eq!(x.iter_mut().next(), None);
/// ```
#[inline]
- #[unstable = "waiting for iterator conventions"]
- pub fn iter_mut<'r>(&'r mut self) -> Item<&'r mut T> {
- Item{opt: self.as_mut().ok()}
+ #[stable]
+ pub fn iter_mut(&mut self) -> IterMut<T> {
+ IterMut { inner: self.as_mut().ok() }
}
/// Returns a consuming iterator over the possibly contained value.
/// assert_eq!(v, vec![]);
/// ```
#[inline]
- #[unstable = "waiting for iterator conventions"]
- pub fn into_iter(self) -> Item<T> {
- Item{opt: self.ok()}
+ #[stable]
+ pub fn into_iter(self) -> IntoIter<T> {
+ IntoIter { inner: self.ok() }
}
////////////////////////////////////////////////////////////////////////
/// assert_eq!(Err(3).and_then(sq).and_then(sq), Err(3));
/// ```
#[inline]
- #[unstable = "waiting for unboxed closures"]
+ #[stable]
pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> {
match self {
Ok(t) => op(t),
/// assert_eq!(Err(3).or_else(err).or_else(err), Err(3));
/// ```
#[inline]
- #[unstable = "waiting for unboxed closures"]
+ #[stable]
pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> {
match self {
Ok(t) => Ok(t),
/// assert_eq!(x.unwrap_or(optb), optb);
/// ```
#[inline]
- #[unstable = "waiting for conventions"]
+ #[stable]
pub fn unwrap_or(self, optb: T) -> T {
match self {
Ok(t) => t,
/// assert_eq!(Err("foo").unwrap_or_else(count), 3u);
/// ```
#[inline]
- #[unstable = "waiting for conventions"]
+ #[stable]
pub fn unwrap_or_else<F: FnOnce(E) -> T>(self, op: F) -> T {
match self {
Ok(t) => t,
}
}
+#[stable]
impl<T, E: Show> Result<T, E> {
/// Unwraps a result, yielding the content of an `Ok`.
///
/// x.unwrap(); // panics with `emergency failure`
/// ```
#[inline]
- #[unstable = "waiting for conventions"]
+ #[stable]
pub fn unwrap(self) -> T {
match self {
Ok(t) => t,
}
}
+#[stable]
impl<T: Show, E> Result<T, E> {
/// Unwraps a result, yielding the content of an `Err`.
///
/// assert_eq!(x.unwrap_err(), "emergency failure");
/// ```
#[inline]
- #[unstable = "waiting for conventions"]
+ #[stable]
pub fn unwrap_err(self) -> E {
match self {
Ok(t) =>
}
/////////////////////////////////////////////////////////////////////////////
-// The Result Iterator
+// The Result Iterators
/////////////////////////////////////////////////////////////////////////////
-/// A `Result` iterator that yields either one or zero elements
-///
-/// The `Item` iterator is returned by the `iter`, `iter_mut` and `into_iter`
-/// methods on `Result`.
-#[deriving(Clone)]
-#[unstable = "waiting for iterator conventions"]
-pub struct Item<T> {
- opt: Option<T>
-}
+/// An iterator over a reference to the `Ok` variant of a `Result`.
+#[stable]
+pub struct Iter<'a, T: 'a> { inner: Option<&'a T> }
-impl<T> Iterator<T> for Item<T> {
+impl<'a, T> Iterator<&'a T> for Iter<'a, T> {
#[inline]
- fn next(&mut self) -> Option<T> {
- self.opt.take()
+ fn next(&mut self) -> Option<&'a T> { self.inner.take() }
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let n = if self.inner.is_some() {1} else {0};
+ (n, Some(n))
}
+}
+
+impl<'a, T> DoubleEndedIterator<&'a T> for Iter<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a T> { self.inner.take() }
+}
+
+impl<'a, T> ExactSizeIterator<&'a T> for Iter<'a, T> {}
+
+impl<'a, T> Clone for Iter<'a, T> {
+ fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } }
+}
+
+/// An iterator over a mutable reference to the `Ok` variant of a `Result`.
+#[stable]
+pub struct IterMut<'a, T: 'a> { inner: Option<&'a mut T> }
+impl<'a, T> Iterator<&'a mut T> for IterMut<'a, T> {
+ #[inline]
+ fn next(&mut self) -> Option<&'a mut T> { self.inner.take() }
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
- match self.opt {
- Some(_) => (1, Some(1)),
- None => (0, Some(0)),
- }
+ let n = if self.inner.is_some() {1} else {0};
+ (n, Some(n))
}
}
-impl<A> DoubleEndedIterator<A> for Item<A> {
+impl<'a, T> DoubleEndedIterator<&'a mut T> for IterMut<'a, T> {
#[inline]
- fn next_back(&mut self) -> Option<A> {
- self.opt.take()
+ fn next_back(&mut self) -> Option<&'a mut T> { self.inner.take() }
+}
+
+impl<'a, T> ExactSizeIterator<&'a mut T> for IterMut<'a, T> {}
+
+/// An iterator over the value in a `Ok` variant of a `Result`.
+#[stable]
+pub struct IntoIter<T> { inner: Option<T> }
+
+impl<T> Iterator<T> for IntoIter<T> {
+ #[inline]
+ fn next(&mut self) -> Option<T> { self.inner.take() }
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let n = if self.inner.is_some() {1} else {0};
+ (n, Some(n))
}
}
-impl<A> ExactSizeIterator<A> for Item<A> {}
+impl<T> DoubleEndedIterator<T> for IntoIter<T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<T> { self.inner.take() }
+}
+
+impl<T> ExactSizeIterator<T> for IntoIter<T> {}
/////////////////////////////////////////////////////////////////////////////
// FromIterator
#[experimental = "needs review"]
impl<'a, T> ExactSizeIterator<&'a T> for Items<'a, T> {}
-#[experimental = "needs review"]
+#[stable]
impl<'a, T> Clone for Items<'a, T> {
fn clone(&self) -> Items<'a, T> { *self }
}
}
// FIXME(#19839) Remove in favor of `#[deriving(Clone)]`
+#[stable]
impl<'a, T, P> Clone for Splits<'a, T, P> where P: Clone + FnMut(&T) -> bool {
fn clone(&self) -> Splits<'a, T, P> {
Splits {
impl_int_slice! { u32, i32 }
impl_int_slice! { u64, i64 }
impl_int_slice! { uint, int }
-
--- /dev/null
+// 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.
+
+//! Operations on tuples
+//!
+//! To access a single element of a tuple one can use the following
+//! methods:
+//!
+//! * `valN` - returns a value of _N_-th element
+//! * `refN` - returns a reference to _N_-th element
+//! * `mutN` - returns a mutable reference to _N_-th element
+//!
+//! Indexing starts from zero, so `val0` returns first value, `val1`
+//! returns second value, and so on. In general, a tuple with _S_
+//! elements provides aforementioned methods suffixed with numbers
+//! from `0` to `S-1`. Traits which contain these methods are
+//! implemented for tuples with up to 12 elements.
+//!
+//! If every type inside a tuple implements one of the following
+//! traits, then a tuple itself also implements it.
+//!
+//! * `Clone`
+//! * `PartialEq`
+//! * `Eq`
+//! * `PartialOrd`
+//! * `Ord`
+//! * `Default`
+//!
+//! # Examples
+//!
+//! Using methods:
+//!
+//! ```
+//! #[allow(deprecated)]
+//! # fn main() {
+//! let pair = ("pi", 3.14f64);
+//! assert_eq!(pair.val0(), "pi");
+//! assert_eq!(pair.val1(), 3.14f64);
+//! # }
+//! ```
+//!
+//! Using traits implemented for tuples:
+//!
+//! ```
+//! use std::default::Default;
+//!
+//! let a = (1i, 2i);
+//! let b = (3i, 4i);
+//! assert!(a != b);
+//!
+//! let c = b.clone();
+//! assert!(b == c);
+//!
+//! let d : (u32, f32) = Default::default();
+//! assert_eq!(d, (0u32, 0.0f32));
+//! ```
+
+#![stable]
+
+#[unstable = "this is just a documentation module and should not be part \
+ of the public api"]
+
+use clone::Clone;
+use cmp::*;
+use default::Default;
+use option::Option;
+use option::Option::Some;
+
+// FIXME(#19630) Remove this work-around
+macro_rules! e {
+ ($e:expr) => { $e }
+}
+
+// macro for implementing n-ary tuple functions and operations
+macro_rules! tuple_impls {
+ ($(
+ $Tuple:ident {
+ $(($valN:ident, $refN:ident, $mutN:ident, $idx:tt) -> $T:ident)+
+ }
+ )+) => {
+ $(
+ #[allow(missing_docs)]
+ #[deprecated]
+ pub trait $Tuple<$($T),+> {
+ $(
+ #[deprecated = "use tuple indexing: `tuple.N`"]
+ fn $valN(self) -> $T;
+ #[deprecated = "use tuple indexing: `&tuple.N`"]
+ fn $refN<'a>(&'a self) -> &'a $T;
+ #[deprecated = "use tuple indexing: `&mut tuple.N`"]
+ fn $mutN<'a>(&'a mut self) -> &'a mut $T;
+ )+
+ }
+
+ impl<$($T),+> $Tuple<$($T),+> for ($($T,)+) {
+ $(
+ #[inline]
+ #[allow(unused_variables)]
+ #[deprecated = "use tuple indexing: `tuple.N`"]
+ fn $valN(self) -> $T {
+ e!(self.$idx)
+ }
+
+ #[inline]
+ #[allow(unused_variables)]
+ #[deprecated = "use tuple indexing: `&tuple.N`"]
+ fn $refN<'a>(&'a self) -> &'a $T {
+ e!(&self.$idx)
+ }
+
+ #[inline]
+ #[allow(unused_variables)]
+ #[deprecated = "use tuple indexing: &mut tuple.N"]
+ fn $mutN<'a>(&'a mut self) -> &'a mut $T {
+ e!(&mut self.$idx)
+ }
+ )+
+ }
+
+ #[stable]
+ impl<$($T:Clone),+> Clone for ($($T,)+) {
+ fn clone(&self) -> ($($T,)+) {
+ ($(e!(self.$idx.clone()),)+)
+ }
+ }
+
+ #[unstable = "waiting for PartialEq to stabilize"]
+ impl<$($T:PartialEq),+> PartialEq for ($($T,)+) {
+ #[inline]
+ fn eq(&self, other: &($($T,)+)) -> bool {
+ e!($(self.$idx == other.$idx)&&+)
+ }
+ #[inline]
+ fn ne(&self, other: &($($T,)+)) -> bool {
+ e!($(self.$idx != other.$idx)||+)
+ }
+ }
+
+ #[unstable = "waiting for Eq to stabilize"]
+ impl<$($T:Eq),+> Eq for ($($T,)+) {}
+
+ #[unstable = "waiting for PartialOrd to stabilize"]
+ impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+) {
+ #[inline]
+ fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
+ lexical_partial_cmp!($(self.$idx, other.$idx),+)
+ }
+ #[inline]
+ fn lt(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(lt, $(self.$idx, other.$idx),+)
+ }
+ #[inline]
+ fn le(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(le, $(self.$idx, other.$idx),+)
+ }
+ #[inline]
+ fn ge(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(ge, $(self.$idx, other.$idx),+)
+ }
+ #[inline]
+ fn gt(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(gt, $(self.$idx, other.$idx),+)
+ }
+ }
+
+ #[unstable = "waiting for Ord to stabilize"]
+ impl<$($T:Ord),+> Ord for ($($T,)+) {
+ #[inline]
+ fn cmp(&self, other: &($($T,)+)) -> Ordering {
+ lexical_cmp!($(self.$idx, other.$idx),+)
+ }
+ }
+
+ #[stable]
+ impl<$($T:Default),+> Default for ($($T,)+) {
+ #[stable]
+ #[inline]
+ fn default() -> ($($T,)+) {
+ ($({ let x: $T = Default::default(); x},)+)
+ }
+ }
+ )+
+ }
+}
+
+// Constructs an expression that performs a lexical ordering using method $rel.
+// The values are interleaved, so the macro invocation for
+// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, a1, b1, a2, b2,
+// a3, b3)` (and similarly for `lexical_cmp`)
+macro_rules! lexical_ord {
+ ($rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
+ if $a != $b { lexical_ord!($rel, $a, $b) }
+ else { lexical_ord!($rel, $($rest_a, $rest_b),+) }
+ };
+ ($rel: ident, $a:expr, $b:expr) => { ($a) . $rel (& $b) };
+}
+
+macro_rules! lexical_partial_cmp {
+ ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
+ match ($a).partial_cmp(&$b) {
+ Some(Equal) => lexical_partial_cmp!($($rest_a, $rest_b),+),
+ ordering => ordering
+ }
+ };
+ ($a:expr, $b:expr) => { ($a).partial_cmp(&$b) };
+}
+
+macro_rules! lexical_cmp {
+ ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
+ match ($a).cmp(&$b) {
+ Equal => lexical_cmp!($($rest_a, $rest_b),+),
+ ordering => ordering
+ }
+ };
+ ($a:expr, $b:expr) => { ($a).cmp(&$b) };
+}
+
+tuple_impls! {
+ Tuple1 {
+ (val0, ref0, mut0, 0) -> A
+ }
+ Tuple2 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ }
+ Tuple3 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ (val2, ref2, mut2, 2) -> C
+ }
+ Tuple4 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ (val2, ref2, mut2, 2) -> C
+ (val3, ref3, mut3, 3) -> D
+ }
+ Tuple5 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ (val2, ref2, mut2, 2) -> C
+ (val3, ref3, mut3, 3) -> D
+ (val4, ref4, mut4, 4) -> E
+ }
+ Tuple6 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ (val2, ref2, mut2, 2) -> C
+ (val3, ref3, mut3, 3) -> D
+ (val4, ref4, mut4, 4) -> E
+ (val5, ref5, mut5, 5) -> F
+ }
+ Tuple7 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ (val2, ref2, mut2, 2) -> C
+ (val3, ref3, mut3, 3) -> D
+ (val4, ref4, mut4, 4) -> E
+ (val5, ref5, mut5, 5) -> F
+ (val6, ref6, mut6, 6) -> G
+ }
+ Tuple8 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ (val2, ref2, mut2, 2) -> C
+ (val3, ref3, mut3, 3) -> D
+ (val4, ref4, mut4, 4) -> E
+ (val5, ref5, mut5, 5) -> F
+ (val6, ref6, mut6, 6) -> G
+ (val7, ref7, mut7, 7) -> H
+ }
+ Tuple9 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ (val2, ref2, mut2, 2) -> C
+ (val3, ref3, mut3, 3) -> D
+ (val4, ref4, mut4, 4) -> E
+ (val5, ref5, mut5, 5) -> F
+ (val6, ref6, mut6, 6) -> G
+ (val7, ref7, mut7, 7) -> H
+ (val8, ref8, mut8, 8) -> I
+ }
+ Tuple10 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ (val2, ref2, mut2, 2) -> C
+ (val3, ref3, mut3, 3) -> D
+ (val4, ref4, mut4, 4) -> E
+ (val5, ref5, mut5, 5) -> F
+ (val6, ref6, mut6, 6) -> G
+ (val7, ref7, mut7, 7) -> H
+ (val8, ref8, mut8, 8) -> I
+ (val9, ref9, mut9, 9) -> J
+ }
+ Tuple11 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ (val2, ref2, mut2, 2) -> C
+ (val3, ref3, mut3, 3) -> D
+ (val4, ref4, mut4, 4) -> E
+ (val5, ref5, mut5, 5) -> F
+ (val6, ref6, mut6, 6) -> G
+ (val7, ref7, mut7, 7) -> H
+ (val8, ref8, mut8, 8) -> I
+ (val9, ref9, mut9, 9) -> J
+ (val10, ref10, mut10, 10) -> K
+ }
+ Tuple12 {
+ (val0, ref0, mut0, 0) -> A
+ (val1, ref1, mut1, 1) -> B
+ (val2, ref2, mut2, 2) -> C
+ (val3, ref3, mut3, 3) -> D
+ (val4, ref4, mut4, 4) -> E
+ (val5, ref5, mut5, 5) -> F
+ (val6, ref6, mut6, 6) -> G
+ (val7, ref7, mut7, 7) -> H
+ (val8, ref8, mut8, 8) -> I
+ (val9, ref9, mut9, 9) -> J
+ (val10, ref10, mut10, 10) -> K
+ (val11, ref11, mut11, 11) -> L
+ }
+}
+++ /dev/null
-// 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.
-
-//! Operations on tuples
-//!
-//! To access a single element of a tuple one can use the following
-//! methods:
-//!
-//! * `valN` - returns a value of _N_-th element
-//! * `refN` - returns a reference to _N_-th element
-//! * `mutN` - returns a mutable reference to _N_-th element
-//!
-//! Indexing starts from zero, so `val0` returns first value, `val1`
-//! returns second value, and so on. In general, a tuple with _S_
-//! elements provides aforementioned methods suffixed with numbers
-//! from `0` to `S-1`. Traits which contain these methods are
-//! implemented for tuples with up to 12 elements.
-//!
-//! If every type inside a tuple implements one of the following
-//! traits, then a tuple itself also implements it.
-//!
-//! * `Clone`
-//! * `PartialEq`
-//! * `Eq`
-//! * `PartialOrd`
-//! * `Ord`
-//! * `Default`
-//!
-//! # Examples
-//!
-//! Using methods:
-//!
-//! ```
-//! #[allow(deprecated)]
-//! # fn main() {
-//! let pair = ("pi", 3.14f64);
-//! assert_eq!(pair.val0(), "pi");
-//! assert_eq!(pair.val1(), 3.14f64);
-//! # }
-//! ```
-//!
-//! Using traits implemented for tuples:
-//!
-//! ```
-//! use std::default::Default;
-//!
-//! let a = (1i, 2i);
-//! let b = (3i, 4i);
-//! assert!(a != b);
-//!
-//! let c = b.clone();
-//! assert!(b == c);
-//!
-//! let d : (u32, f32) = Default::default();
-//! assert_eq!(d, (0u32, 0.0f32));
-//! ```
-
-#![doc(primitive = "tuple")]
-#![stable]
-
-#[unstable = "this is just a documentation module and should not be part \
- of the public api"]
-pub use unit;
-
-use clone::Clone;
-use cmp::*;
-use default::Default;
-use option::Option;
-use option::Option::Some;
-
-// FIXME(#19630) Remove this work-around
-macro_rules! e {
- ($e:expr) => { $e }
-}
-
-// macro for implementing n-ary tuple functions and operations
-macro_rules! tuple_impls {
- ($(
- $Tuple:ident {
- $(($valN:ident, $refN:ident, $mutN:ident, $idx:tt) -> $T:ident)+
- }
- )+) => {
- $(
- #[allow(missing_docs)]
- #[deprecated]
- pub trait $Tuple<$($T),+> {
- $(
- #[deprecated = "use tuple indexing: `tuple.N`"]
- fn $valN(self) -> $T;
- #[deprecated = "use tuple indexing: `&tuple.N`"]
- fn $refN<'a>(&'a self) -> &'a $T;
- #[deprecated = "use tuple indexing: `&mut tuple.N`"]
- fn $mutN<'a>(&'a mut self) -> &'a mut $T;
- )+
- }
-
- impl<$($T),+> $Tuple<$($T),+> for ($($T,)+) {
- $(
- #[inline]
- #[allow(unused_variables)]
- #[deprecated = "use tuple indexing: `tuple.N`"]
- fn $valN(self) -> $T {
- e!(self.$idx)
- }
-
- #[inline]
- #[allow(unused_variables)]
- #[deprecated = "use tuple indexing: `&tuple.N`"]
- fn $refN<'a>(&'a self) -> &'a $T {
- e!(&self.$idx)
- }
-
- #[inline]
- #[allow(unused_variables)]
- #[deprecated = "use tuple indexing: &mut tuple.N"]
- fn $mutN<'a>(&'a mut self) -> &'a mut $T {
- e!(&mut self.$idx)
- }
- )+
- }
-
- #[unstable = "waiting for Clone to stabilize"]
- impl<$($T:Clone),+> Clone for ($($T,)+) {
- fn clone(&self) -> ($($T,)+) {
- ($(e!(self.$idx.clone()),)+)
- }
- }
-
- #[unstable = "waiting for PartialEq to stabilize"]
- impl<$($T:PartialEq),+> PartialEq for ($($T,)+) {
- #[inline]
- fn eq(&self, other: &($($T,)+)) -> bool {
- e!($(self.$idx == other.$idx)&&+)
- }
- #[inline]
- fn ne(&self, other: &($($T,)+)) -> bool {
- e!($(self.$idx != other.$idx)||+)
- }
- }
-
- #[unstable = "waiting for Eq to stabilize"]
- impl<$($T:Eq),+> Eq for ($($T,)+) {}
-
- #[unstable = "waiting for PartialOrd to stabilize"]
- impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+) {
- #[inline]
- fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
- lexical_partial_cmp!($(self.$idx, other.$idx),+)
- }
- #[inline]
- fn lt(&self, other: &($($T,)+)) -> bool {
- lexical_ord!(lt, $(self.$idx, other.$idx),+)
- }
- #[inline]
- fn le(&self, other: &($($T,)+)) -> bool {
- lexical_ord!(le, $(self.$idx, other.$idx),+)
- }
- #[inline]
- fn ge(&self, other: &($($T,)+)) -> bool {
- lexical_ord!(ge, $(self.$idx, other.$idx),+)
- }
- #[inline]
- fn gt(&self, other: &($($T,)+)) -> bool {
- lexical_ord!(gt, $(self.$idx, other.$idx),+)
- }
- }
-
- #[unstable = "waiting for Ord to stabilize"]
- impl<$($T:Ord),+> Ord for ($($T,)+) {
- #[inline]
- fn cmp(&self, other: &($($T,)+)) -> Ordering {
- lexical_cmp!($(self.$idx, other.$idx),+)
- }
- }
-
- #[stable]
- impl<$($T:Default),+> Default for ($($T,)+) {
- #[stable]
- #[inline]
- fn default() -> ($($T,)+) {
- ($({ let x: $T = Default::default(); x},)+)
- }
- }
- )+
- }
-}
-
-// Constructs an expression that performs a lexical ordering using method $rel.
-// The values are interleaved, so the macro invocation for
-// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, a1, b1, a2, b2,
-// a3, b3)` (and similarly for `lexical_cmp`)
-macro_rules! lexical_ord {
- ($rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
- if $a != $b { lexical_ord!($rel, $a, $b) }
- else { lexical_ord!($rel, $($rest_a, $rest_b),+) }
- };
- ($rel: ident, $a:expr, $b:expr) => { ($a) . $rel (& $b) };
-}
-
-macro_rules! lexical_partial_cmp {
- ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
- match ($a).partial_cmp(&$b) {
- Some(Equal) => lexical_partial_cmp!($($rest_a, $rest_b),+),
- ordering => ordering
- }
- };
- ($a:expr, $b:expr) => { ($a).partial_cmp(&$b) };
-}
-
-macro_rules! lexical_cmp {
- ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
- match ($a).cmp(&$b) {
- Equal => lexical_cmp!($($rest_a, $rest_b),+),
- ordering => ordering
- }
- };
- ($a:expr, $b:expr) => { ($a).cmp(&$b) };
-}
-
-tuple_impls! {
- Tuple1 {
- (val0, ref0, mut0, 0) -> A
- }
- Tuple2 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- }
- Tuple3 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- (val2, ref2, mut2, 2) -> C
- }
- Tuple4 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- (val2, ref2, mut2, 2) -> C
- (val3, ref3, mut3, 3) -> D
- }
- Tuple5 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- (val2, ref2, mut2, 2) -> C
- (val3, ref3, mut3, 3) -> D
- (val4, ref4, mut4, 4) -> E
- }
- Tuple6 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- (val2, ref2, mut2, 2) -> C
- (val3, ref3, mut3, 3) -> D
- (val4, ref4, mut4, 4) -> E
- (val5, ref5, mut5, 5) -> F
- }
- Tuple7 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- (val2, ref2, mut2, 2) -> C
- (val3, ref3, mut3, 3) -> D
- (val4, ref4, mut4, 4) -> E
- (val5, ref5, mut5, 5) -> F
- (val6, ref6, mut6, 6) -> G
- }
- Tuple8 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- (val2, ref2, mut2, 2) -> C
- (val3, ref3, mut3, 3) -> D
- (val4, ref4, mut4, 4) -> E
- (val5, ref5, mut5, 5) -> F
- (val6, ref6, mut6, 6) -> G
- (val7, ref7, mut7, 7) -> H
- }
- Tuple9 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- (val2, ref2, mut2, 2) -> C
- (val3, ref3, mut3, 3) -> D
- (val4, ref4, mut4, 4) -> E
- (val5, ref5, mut5, 5) -> F
- (val6, ref6, mut6, 6) -> G
- (val7, ref7, mut7, 7) -> H
- (val8, ref8, mut8, 8) -> I
- }
- Tuple10 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- (val2, ref2, mut2, 2) -> C
- (val3, ref3, mut3, 3) -> D
- (val4, ref4, mut4, 4) -> E
- (val5, ref5, mut5, 5) -> F
- (val6, ref6, mut6, 6) -> G
- (val7, ref7, mut7, 7) -> H
- (val8, ref8, mut8, 8) -> I
- (val9, ref9, mut9, 9) -> J
- }
- Tuple11 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- (val2, ref2, mut2, 2) -> C
- (val3, ref3, mut3, 3) -> D
- (val4, ref4, mut4, 4) -> E
- (val5, ref5, mut5, 5) -> F
- (val6, ref6, mut6, 6) -> G
- (val7, ref7, mut7, 7) -> H
- (val8, ref8, mut8, 8) -> I
- (val9, ref9, mut9, 9) -> J
- (val10, ref10, mut10, 10) -> K
- }
- Tuple12 {
- (val0, ref0, mut0, 0) -> A
- (val1, ref1, mut1, 1) -> B
- (val2, ref2, mut2, 2) -> C
- (val3, ref3, mut3, 3) -> D
- (val4, ref4, mut4, 4) -> E
- (val5, ref5, mut5, 5) -> F
- (val6, ref6, mut6, 6) -> G
- (val7, ref7, mut7, 7) -> H
- (val8, ref8, mut8, 8) -> I
- (val9, ref9, mut9, 9) -> J
- (val10, ref10, mut10, 10) -> K
- (val11, ref11, mut11, 11) -> L
- }
-}
-
+++ /dev/null
-// 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.
-
-#![doc(primitive = "unit")]
-#![unstable = "this module is purely for documentation and it will likely be \
- removed from the public api"]
-
-//! The `()` type, sometimes called "unit" or "nil".
-//!
-//! The `()` type has exactly one value `()`, and is used when there
-//! is no other meaningful value that could be returned. `()` is most
-//! commonly seen implicitly: functions without a `-> ...` implicitly
-//! have return type `()`, that is, these are equivalent:
-//!
-//! ```rust
-//! fn long() -> () {}
-//!
-//! fn short() {}
-//! ```
-//!
-//! The semicolon `;` can be used to discard the result of an
-//! expression at the end of a block, making the expression (and thus
-//! the block) evaluate to `()`. For example,
-//!
-//! ```rust
-//! fn returns_i64() -> i64 {
-//! 1i64
-//! }
-//! fn returns_unit() {
-//! 1i64;
-//! }
-//!
-//! let is_i64 = {
-//! returns_i64()
-//! };
-//! let is_unit = {
-//! returns_i64();
-//! };
-//! ```
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
-#![feature(macro_rules, globs, import_shadowing)]
+#![feature(macro_rules, globs)]
pub use self::Piece::*;
pub use self::Position::*;
pub use self::Alignment::*;
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(globs, phase)]
-#![feature(import_shadowing)]
#![feature(unboxed_closures)]
#![deny(missing_docs)]
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![feature(default_type_params, globs, import_shadowing, macro_rules, phase, quote)]
+#![feature(default_type_params, globs, macro_rules, phase, quote)]
#![feature(slicing_syntax, unsafe_destructor)]
#![feature(rustc_diagnostic_macros)]
#![feature(unboxed_closures)]
pub mod reachable;
pub mod region;
pub mod recursion_limit;
- pub mod resolve;
pub mod resolve_lifetime;
pub mod stability;
pub mod subst;
use lint::{Context, LintPass, LintArray};
use std::{cmp, slice};
-use std::collections::hash_map::{Occupied, Vacant};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::num::SignedInt;
use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
use syntax::{abi, ast, ast_map};
ast::ExprIf(ref cond, _, _) => (cond, "`if` condition", true),
ast::ExprWhile(ref cond, _, _) => (cond, "`while` condition", true),
ast::ExprMatch(ref head, _, source) => match source {
- ast::MatchNormal => (head, "`match` head expression", true),
- ast::MatchIfLetDesugar => (head, "`if let` head expression", true),
- ast::MatchWhileLetDesugar => (head, "`while let` head expression", true),
+ ast::MatchSource::Normal => (head, "`match` head expression", true),
+ ast::MatchSource::IfLetDesugar { .. } => (head, "`if let` head expression", true),
+ ast::MatchSource::WhileLetDesugar => (head, "`while let` head expression", true),
},
ast::ExprRet(Some(ref value)) => (value, "`return` value", false),
ast::ExprAssign(_, ref value) => (value, "assigned value", false),
use util::nodemap::FnvHashMap;
use std::rc::Rc;
-use std::collections::hash_map::{Occupied, Vacant};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax::ast;
use syntax::abi;
use syntax::attr;
use metadata::decoder;
use middle::def;
use middle::lang_items;
-use middle::resolve;
use middle::ty;
use rbml;
}
pub fn get_trait_item_name_and_kind(cstore: &cstore::CStore, def: ast::DefId)
- -> (ast::Name, resolve::TraitItemKind) {
+ -> (ast::Name, def::TraitItemKind) {
let cdata = cstore.get_crate_data(def.krate);
decoder::get_trait_item_name_and_kind(cstore.intr.clone(),
&*cdata,
parse_predicate_data};
use middle::def;
use middle::lang_items;
-use middle::resolve::{TraitItemKind, TypeTraitItemKind};
use middle::subst;
use middle::ty::{ImplContainer, TraitContainer};
use middle::ty::{mod, Ty};
pub fn get_trait_item_name_and_kind(intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId)
- -> (ast::Name, TraitItemKind) {
+ -> (ast::Name, def::TraitItemKind) {
let doc = lookup_item(id, cdata.data());
let name = item_name(&*intr, doc);
match item_sort(doc) {
'r' | 'p' => {
let explicit_self = get_explicit_self(doc);
- (name, TraitItemKind::from_explicit_self_category(explicit_self))
+ (name, def::TraitItemKind::from_explicit_self_category(explicit_self))
}
- 't' => (name, TypeTraitItemKind),
+ 't' => (name, def::TypeTraitItemKind),
c => {
panic!("get_trait_item_name_and_kind(): unknown trait item kind \
in metadata: `{}`", c)
use metadata::cstore;
use metadata::decoder;
use metadata::tyencode;
+use middle::def;
use middle::ty::{lookup_item_type};
use middle::ty::{mod, Ty};
use middle::stability;
-use middle;
use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
use serialize::Encodable;
pub struct EncodeParams<'a, 'tcx: 'a> {
pub diag: &'a SpanHandler,
pub tcx: &'a ty::ctxt<'tcx>,
- pub reexports2: &'a middle::resolve::ExportMap2,
+ pub reexports: &'a def::ExportMap,
pub item_symbols: &'a RefCell<NodeMap<String>>,
pub link_meta: &'a LinkMeta,
pub cstore: &'a cstore::CStore,
pub struct EncodeContext<'a, 'tcx: 'a> {
pub diag: &'a SpanHandler,
pub tcx: &'a ty::ctxt<'tcx>,
- pub reexports2: &'a middle::resolve::ExportMap2,
+ pub reexports: &'a def::ExportMap,
pub item_symbols: &'a RefCell<NodeMap<String>>,
pub link_meta: &'a LinkMeta,
pub cstore: &'a cstore::CStore,
}
fn encode_reexported_static_method(rbml_w: &mut Encoder,
- exp: &middle::resolve::Export2,
+ exp: &def::Export,
method_def_id: DefId,
method_name: ast::Name) {
debug!("(encode reexported static method) {}::{}",
fn encode_reexported_static_base_methods(ecx: &EncodeContext,
rbml_w: &mut Encoder,
- exp: &middle::resolve::Export2)
+ exp: &def::Export)
-> bool {
let impl_items = ecx.tcx.impl_items.borrow();
match ecx.tcx.inherent_impls.borrow().get(&exp.def_id) {
fn encode_reexported_static_trait_methods(ecx: &EncodeContext,
rbml_w: &mut Encoder,
- exp: &middle::resolve::Export2)
+ exp: &def::Export)
-> bool {
match ecx.tcx.trait_items_cache.borrow().get(&exp.def_id) {
Some(trait_items) => {
fn encode_reexported_static_methods(ecx: &EncodeContext,
rbml_w: &mut Encoder,
mod_path: PathElems,
- exp: &middle::resolve::Export2) {
+ exp: &def::Export) {
if let Some(ast_map::NodeItem(item)) = ecx.tcx.map.find(exp.def_id.node) {
- let original_name = token::get_ident(item.ident);
-
let path_differs = ecx.tcx.map.with_path(exp.def_id.node, |path| {
let (mut a, mut b) = (path, mod_path.clone());
loop {
// encoded metadata for static methods relative to Bar,
// but not yet for Foo.
//
- if path_differs || original_name.get() != exp.name {
+ if path_differs || item.ident.name != exp.name {
if !encode_reexported_static_base_methods(ecx, rbml_w, exp) {
if encode_reexported_static_trait_methods(ecx, rbml_w, exp) {
debug!("(encode reexported static methods) {} [trait]",
- original_name);
+ item.ident.name);
}
}
else {
debug!("(encode reexported static methods) {} [base]",
- original_name);
+ item.ident.name);
}
}
}
id: NodeId,
path: PathElems) {
debug!("(encoding info for module) encoding reexports for {}", id);
- match ecx.reexports2.get(&id) {
+ match ecx.reexports.get(&id) {
Some(ref exports) => {
debug!("(encoding info for module) found reexports for {}", id);
for exp in exports.iter() {
rbml_w.wr_str(def_to_string(exp.def_id).as_slice());
rbml_w.end_tag();
rbml_w.start_tag(tag_items_data_item_reexport_name);
- rbml_w.wr_str(exp.name.as_slice());
+ rbml_w.wr_str(exp.name.as_str());
rbml_w.end_tag();
rbml_w.end_tag();
encode_reexported_static_methods(ecx, rbml_w, path.clone(), exp);
if abi == abi::RustIntrinsic {
encode_inlined_item(ecx, rbml_w, IIForeignRef(nitem));
}
+ encode_attributes(rbml_w, &*nitem.attrs);
+ let stab = stability::lookup(ecx.tcx, ast_util::local_def(nitem.id));
+ encode_stability(rbml_w, stab);
encode_symbol(ecx, rbml_w, nitem.id);
}
ast::ForeignItemStatic(_, mutbl) => {
}
encode_bounds_and_type(rbml_w, ecx,
&lookup_item_type(ecx.tcx,local_def(nitem.id)));
+ encode_attributes(rbml_w, &*nitem.attrs);
+ let stab = stability::lookup(ecx.tcx, ast_util::local_def(nitem.id));
+ encode_stability(rbml_w, stab);
encode_symbol(ecx, rbml_w, nitem.id);
encode_name(rbml_w, nitem.ident.name);
}
item_symbols,
diag,
tcx,
- reexports2,
+ reexports,
cstore,
encode_inlined_item,
link_meta,
let ecx = EncodeContext {
diag: diag,
tcx: tcx,
- reexports2: reexports2,
+ reexports: reexports,
item_symbols: item_symbols,
link_meta: link_meta,
cstore: cstore,
use std::c_str::ToCStr;
use std::cmp;
-use std::collections::hash_map::{Occupied, Vacant};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{HashMap, HashSet};
use std::io::fs::PathExtensions;
use std::io;
None => {}
}
let pos = w.tell().unwrap();
- enc_sty(w, cx, &t.sty);
+
+ match t.sty {
+ ty::ty_bool => mywrite!(w, "b"),
+ ty::ty_char => mywrite!(w, "c"),
+ ty::ty_int(t) => {
+ match t {
+ ast::TyI => mywrite!(w, "i"),
+ ast::TyI8 => mywrite!(w, "MB"),
+ ast::TyI16 => mywrite!(w, "MW"),
+ ast::TyI32 => mywrite!(w, "ML"),
+ ast::TyI64 => mywrite!(w, "MD")
+ }
+ }
+ ty::ty_uint(t) => {
+ match t {
+ ast::TyU => mywrite!(w, "u"),
+ ast::TyU8 => mywrite!(w, "Mb"),
+ ast::TyU16 => mywrite!(w, "Mw"),
+ ast::TyU32 => mywrite!(w, "Ml"),
+ ast::TyU64 => mywrite!(w, "Md")
+ }
+ }
+ ty::ty_float(t) => {
+ match t {
+ ast::TyF32 => mywrite!(w, "Mf"),
+ ast::TyF64 => mywrite!(w, "MF"),
+ }
+ }
+ ty::ty_enum(def, ref substs) => {
+ mywrite!(w, "t[{}|", (cx.ds)(def));
+ enc_substs(w, cx, substs);
+ mywrite!(w, "]");
+ }
+ ty::ty_trait(box ty::TyTrait { ref principal,
+ ref bounds }) => {
+ mywrite!(w, "x[");
+ enc_trait_ref(w, cx, &principal.0);
+ enc_existential_bounds(w, cx, bounds);
+ mywrite!(w, "]");
+ }
+ ty::ty_tup(ref ts) => {
+ mywrite!(w, "T[");
+ for t in ts.iter() { enc_ty(w, cx, *t); }
+ mywrite!(w, "]");
+ }
+ ty::ty_uniq(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); }
+ ty::ty_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); }
+ ty::ty_rptr(r, mt) => {
+ mywrite!(w, "&");
+ enc_region(w, cx, r);
+ enc_mt(w, cx, mt);
+ }
+ ty::ty_vec(t, sz) => {
+ mywrite!(w, "V");
+ enc_ty(w, cx, t);
+ mywrite!(w, "/");
+ match sz {
+ Some(n) => mywrite!(w, "{}|", n),
+ None => mywrite!(w, "|"),
+ }
+ }
+ ty::ty_str => {
+ mywrite!(w, "v");
+ }
+ ty::ty_closure(ref f) => {
+ mywrite!(w, "f");
+ enc_closure_ty(w, cx, &**f);
+ }
+ ty::ty_bare_fn(ref f) => {
+ mywrite!(w, "F");
+ enc_bare_fn_ty(w, cx, f);
+ }
+ ty::ty_infer(_) => {
+ cx.diag.handler().bug("cannot encode inference variable types");
+ }
+ ty::ty_param(ParamTy {space, idx: id, def_id: did}) => {
+ mywrite!(w, "p{}|{}|{}|", (cx.ds)(did), id, space.to_uint())
+ }
+ ty::ty_struct(def, ref substs) => {
+ mywrite!(w, "a[{}|", (cx.ds)(def));
+ enc_substs(w, cx, substs);
+ mywrite!(w, "]");
+ }
+ ty::ty_unboxed_closure(def, region, ref substs) => {
+ mywrite!(w, "k[{}|", (cx.ds)(def));
+ enc_region(w, cx, region);
+ enc_substs(w, cx, substs);
+ mywrite!(w, "]");
+ }
+ ty::ty_err => {
+ mywrite!(w, "e");
+ }
+ ty::ty_open(_) => {
+ cx.diag.handler().bug("unexpected type in enc_sty (ty_open)");
+ }
+ }
+
let end = w.tell().unwrap();
let len = end - pos;
fn estimate_sz(u: u64) -> u64 {
}
}
-fn enc_sty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
- st: &ty::sty<'tcx>) {
- match *st {
- ty::ty_bool => mywrite!(w, "b"),
- ty::ty_char => mywrite!(w, "c"),
- ty::ty_int(t) => {
- match t {
- ast::TyI => mywrite!(w, "i"),
- ast::TyI8 => mywrite!(w, "MB"),
- ast::TyI16 => mywrite!(w, "MW"),
- ast::TyI32 => mywrite!(w, "ML"),
- ast::TyI64 => mywrite!(w, "MD")
- }
- }
- ty::ty_uint(t) => {
- match t {
- ast::TyU => mywrite!(w, "u"),
- ast::TyU8 => mywrite!(w, "Mb"),
- ast::TyU16 => mywrite!(w, "Mw"),
- ast::TyU32 => mywrite!(w, "Ml"),
- ast::TyU64 => mywrite!(w, "Md")
- }
- }
- ty::ty_float(t) => {
- match t {
- ast::TyF32 => mywrite!(w, "Mf"),
- ast::TyF64 => mywrite!(w, "MF"),
- }
- }
- ty::ty_enum(def, ref substs) => {
- mywrite!(w, "t[{}|", (cx.ds)(def));
- enc_substs(w, cx, substs);
- mywrite!(w, "]");
- }
- ty::ty_trait(box ty::TyTrait { ref principal,
- ref bounds }) => {
- mywrite!(w, "x[");
- enc_trait_ref(w, cx, &principal.0);
- enc_existential_bounds(w, cx, bounds);
- mywrite!(w, "]");
- }
- ty::ty_tup(ref ts) => {
- mywrite!(w, "T[");
- for t in ts.iter() { enc_ty(w, cx, *t); }
- mywrite!(w, "]");
- }
- ty::ty_uniq(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); }
- ty::ty_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); }
- ty::ty_rptr(r, mt) => {
- mywrite!(w, "&");
- enc_region(w, cx, r);
- enc_mt(w, cx, mt);
- }
- ty::ty_vec(t, sz) => {
- mywrite!(w, "V");
- enc_ty(w, cx, t);
- mywrite!(w, "/");
- match sz {
- Some(n) => mywrite!(w, "{}|", n),
- None => mywrite!(w, "|"),
- }
- }
- ty::ty_str => {
- mywrite!(w, "v");
- }
- ty::ty_closure(ref f) => {
- mywrite!(w, "f");
- enc_closure_ty(w, cx, &**f);
- }
- ty::ty_bare_fn(ref f) => {
- mywrite!(w, "F");
- enc_bare_fn_ty(w, cx, f);
- }
- ty::ty_infer(_) => {
- cx.diag.handler().bug("cannot encode inference variable types");
- }
- ty::ty_param(ParamTy {space, idx: id, def_id: did}) => {
- mywrite!(w, "p{}|{}|{}|", (cx.ds)(did), id, space.to_uint())
- }
- ty::ty_struct(def, ref substs) => {
- mywrite!(w, "a[{}|", (cx.ds)(def));
- enc_substs(w, cx, substs);
- mywrite!(w, "]");
- }
- ty::ty_unboxed_closure(def, region, ref substs) => {
- mywrite!(w, "k[{}|", (cx.ds)(def));
- enc_region(w, cx, region);
- enc_substs(w, cx, substs);
- mywrite!(w, "]");
- }
- ty::ty_err => {
- mywrite!(w, "e");
- }
- ty::ty_open(_) => {
- cx.diag.handler().bug("unexpected type in enc_sty (ty_open)");
- }
- }
-}
-
fn enc_unsafety(w: &mut SeekableMemWriter, p: ast::Unsafety) {
match p {
ast::Unsafety::Normal => mywrite!(w, "n"),
blk: &ast::Block) -> CFG {
construct::construct(tcx, blk)
}
+
+ pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
+ self.graph.depth_traverse(self.entry).any(|node| node.id == id)
+ }
}
use middle::mem_categorization::cmt;
use middle::pat_util::*;
use middle::ty::*;
-use middle::ty::{mod, Ty};
+use middle::ty;
use std::fmt;
use std::iter::AdditiveIterator;
use std::iter::range_inclusive;
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
NotUseful => {
match source {
- ast::MatchIfLetDesugar => {
+ ast::MatchSource::IfLetDesugar { .. } => {
if printed_if_let_err {
// we already printed an irrefutable if-let pattern error.
// We don't want two, that's just confusing.
}
},
- ast::MatchWhileLetDesugar => {
+ ast::MatchSource::WhileLetDesugar => {
// find the first arm pattern so we can use its span
let &(ref first_arm_pats, _) = &arms[0];
let first_pat = &first_arm_pats[0];
span_err!(cx.tcx.sess, span, E0165, "irrefutable while-let pattern");
},
- ast::MatchNormal => {
+ ast::MatchSource::Normal => {
span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern")
},
}
// recursively.
use session::Session;
-use middle::resolve;
-use middle::def::{DefStatic, DefConst};
+use middle::def::{DefStatic, DefConst, DefMap};
use syntax::ast;
use syntax::{ast_util, ast_map};
struct CheckCrateVisitor<'a, 'ast: 'a> {
sess: &'a Session,
- def_map: &'a resolve::DefMap,
+ def_map: &'a DefMap,
ast_map: &'a ast_map::Map<'ast>
}
pub fn check_crate<'ast>(sess: &Session,
krate: &ast::Crate,
- def_map: &resolve::DefMap,
+ def_map: &DefMap,
ast_map: &ast_map::Map<'ast>) {
let mut visitor = CheckCrateVisitor {
sess: sess,
root_it: &'a ast::Item,
sess: &'a Session,
ast_map: &'a ast_map::Map<'ast>,
- def_map: &'a resolve::DefMap,
+ def_map: &'a DefMap,
idstack: Vec<ast::NodeId>
}
// FIXME: Should use the dependency graph when it's available (#1356)
pub fn check_item_recursion<'a>(sess: &'a Session,
ast_map: &'a ast_map::Map,
- def_map: &'a resolve::DefMap,
+ def_map: &'a DefMap,
it: &'a ast::Item) {
let mut visitor = CheckItemRecursionVisitor {
use syntax::{ast_map, ast_util, codemap};
use std::rc::Rc;
-use std::collections::hash_map::Vacant;
+use std::collections::hash_map::Entry::Vacant;
//
// This pass classifies expressions by their constant-ness.
pub use self::Def::*;
pub use self::MethodProvenance::*;
+pub use self::TraitItemKind::*;
use middle::subst::ParamSpace;
+use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory};
+use util::nodemap::NodeMap;
use syntax::ast;
use syntax::ast_util::local_def;
+use std::cell::RefCell;
+
#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum Def {
DefFn(ast::DefId, bool /* is_ctor */),
DefMethod(ast::DefId /* method */, Option<ast::DefId> /* trait */, MethodProvenance),
}
+// Definition mapping
+pub type DefMap = RefCell<NodeMap<Def>>;
+// This is the replacement export map. It maps a module to all of the exports
+// within.
+pub type ExportMap = NodeMap<Vec<Export>>;
+
+#[deriving(Copy)]
+pub struct Export {
+ pub name: ast::Name, // The name of the target.
+ pub def_id: ast::DefId, // The definition of the target.
+}
+
#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum MethodProvenance {
FromTrait(ast::DefId),
}
}
+#[deriving(Clone, Copy, Eq, PartialEq)]
+pub enum TraitItemKind {
+ NonstaticMethodTraitItemKind,
+ StaticMethodTraitItemKind,
+ TypeTraitItemKind,
+}
+
+impl TraitItemKind {
+ pub fn from_explicit_self_category(explicit_self_category:
+ ExplicitSelfCategory)
+ -> TraitItemKind {
+ if explicit_self_category == StaticExplicitSelfCategory {
+ StaticMethodTraitItemKind
+ } else {
+ NonstaticMethodTraitItemKind
+ }
+ }
+}
+
impl Def {
pub fn def_id(&self) -> ast::DefId {
match *self {
}
}
}
-
use std::fmt::{Formatter, Error, Show};
use std::uint;
+use std::collections::BitvSet;
pub struct Graph<N,E> {
nodes: Vec<Node<N>> ,
}
}
}
+
+ pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E> {
+ DepthFirstTraversal {
+ graph: self,
+ stack: vec![start],
+ visited: BitvSet::new()
+ }
+ }
+}
+
+pub struct DepthFirstTraversal<'g, N:'g, E:'g> {
+ graph: &'g Graph<N, E>,
+ stack: Vec<NodeIndex>,
+ visited: BitvSet
+}
+
+impl<'g, N, E> Iterator<&'g N> for DepthFirstTraversal<'g, N, E> {
+ fn next(&mut self) -> Option<&'g N> {
+ while let Some(idx) = self.stack.pop() {
+ if !self.visited.insert(idx.node_id()) {
+ continue;
+ }
+ self.graph.each_outgoing_edge(idx, |_, e| -> bool {
+ if !self.visited.contains(&e.target().node_id()) {
+ self.stack.push(e.target());
+ }
+ true
+ });
+
+ return Some(self.graph.node_data(idx));
+ }
+
+ return None;
+ }
}
pub fn each_edge_index<F>(max_edge_index: EdgeIndex, mut f: F) where
b.repr(self.get_ref().infcx.tcx));
// Consider coercing the subtype to a DST
- let unsize = self.unpack_actual_value(a, |sty_a| {
- self.coerce_unsized(a, sty_a, b)
+ let unsize = self.unpack_actual_value(a, |a| {
+ self.coerce_unsized(a, b)
});
if unsize.is_ok() {
return unsize;
ty::ty_ptr(mt_b) => {
match mt_b.ty.sty {
ty::ty_str => {
- return self.unpack_actual_value(a, |sty_a| {
- self.coerce_unsafe_ptr(a, sty_a, b, ast::MutImmutable)
+ return self.unpack_actual_value(a, |a| {
+ self.coerce_unsafe_ptr(a, b, ast::MutImmutable)
});
}
ty::ty_trait(..) => {
- let result = self.unpack_actual_value(a, |sty_a| {
- self.coerce_unsafe_object(a, sty_a, b, mt_b.mutbl)
+ let result = self.unpack_actual_value(a, |a| {
+ self.coerce_unsafe_object(a, b, mt_b.mutbl)
});
match result {
}
_ => {
- return self.unpack_actual_value(a, |sty_a| {
- self.coerce_unsafe_ptr(a, sty_a, b, mt_b.mutbl)
+ return self.unpack_actual_value(a, |a| {
+ self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
});
}
};
ty::ty_rptr(_, mt_b) => {
match mt_b.ty.sty {
ty::ty_str => {
- return self.unpack_actual_value(a, |sty_a| {
- self.coerce_borrowed_pointer(a, sty_a, b, ast::MutImmutable)
+ return self.unpack_actual_value(a, |a| {
+ self.coerce_borrowed_pointer(a, b, ast::MutImmutable)
});
}
ty::ty_trait(..) => {
- let result = self.unpack_actual_value(a, |sty_a| {
- self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
+ let result = self.unpack_actual_value(a, |a| {
+ self.coerce_borrowed_object(a, b, mt_b.mutbl)
});
match result {
}
_ => {
- return self.unpack_actual_value(a, |sty_a| {
- self.coerce_borrowed_pointer(a, sty_a, b, mt_b.mutbl)
+ return self.unpack_actual_value(a, |a| {
+ self.coerce_borrowed_pointer(a, b, mt_b.mutbl)
});
}
};
store: ty::RegionTraitStore(..),
..
}) => {
- return self.unpack_actual_value(a, |sty_a| {
- self.coerce_borrowed_fn(a, sty_a, b)
+ return self.unpack_actual_value(a, |a| {
+ self.coerce_borrowed_fn(a, b)
});
}
_ => {}
}
- self.unpack_actual_value(a, |sty_a| {
- match *sty_a {
+ self.unpack_actual_value(a, |a| {
+ match a.sty {
ty::ty_bare_fn(ref a_f) => {
// Bare functions are coercible to any closure type.
//
}
pub fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
- F: FnOnce(&ty::sty<'tcx>) -> T,
+ F: FnOnce(Ty<'tcx>) -> T,
{
- f(&self.get_ref().infcx.shallow_resolve(a).sty)
+ f(self.get_ref().infcx.shallow_resolve(a))
}
// ~T -> &T or &mut T -> &T (including where T = [U] or str)
pub fn coerce_borrowed_pointer(&self,
a: Ty<'tcx>,
- sty_a: &ty::sty<'tcx>,
b: Ty<'tcx>,
mutbl_b: ast::Mutability)
-> CoerceResult<'tcx> {
- debug!("coerce_borrowed_pointer(a={}, sty_a={}, b={})",
- a.repr(self.get_ref().infcx.tcx), sty_a,
+ debug!("coerce_borrowed_pointer(a={}, b={})",
+ a.repr(self.get_ref().infcx.tcx),
b.repr(self.get_ref().infcx.tcx));
// If we have a parameter of type `&M T_a` and the value
let coercion = Coercion(self.get_ref().trace.clone());
let r_borrow = self.get_ref().infcx.next_region_var(coercion);
- let inner_ty = match *sty_a {
+ let inner_ty = match a.sty {
ty::ty_uniq(_) => return Err(ty::terr_mismatch),
ty::ty_rptr(_, mt_a) => mt_a.ty,
_ => {
// or &Concrete -> &Trait, etc.
fn coerce_unsized(&self,
a: Ty<'tcx>,
- sty_a: &ty::sty<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
- debug!("coerce_unsized(a={}, sty_a={}, b={})",
- a.repr(self.get_ref().infcx.tcx), sty_a,
+ debug!("coerce_unsized(a={}, b={})",
+ a.repr(self.get_ref().infcx.tcx),
b.repr(self.get_ref().infcx.tcx));
// Note, we want to avoid unnecessary unsizing. We don't want to coerce to
let sub = Sub(self.get_ref().clone());
- let sty_b = &b.sty;
- match (sty_a, sty_b) {
+ match (&a.sty, &b.sty) {
(&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
- self.unpack_actual_value(t_a, |sty_a| {
- match self.unsize_ty(t_a, sty_a, mt_b.ty) {
+ self.unpack_actual_value(t_a, |a| {
+ match self.unsize_ty(t_a, a, mt_b.ty) {
Some((ty, kind)) => {
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
return Err(ty::terr_mutability);
})
}
(&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
- self.unpack_actual_value(t_a, |sty_a| {
- match self.unsize_ty(t_a, sty_a, mt_b.ty) {
+ self.unpack_actual_value(t_a, |a| {
+ match self.unsize_ty(t_a, a, mt_b.ty) {
Some((ty, kind)) => {
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
return Err(ty::terr_mutability);
})
}
(&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
- self.unpack_actual_value(t_a, |sty_a| {
- match self.unsize_ty(t_a, sty_a, t_b) {
+ self.unpack_actual_value(t_a, |a| {
+ match self.unsize_ty(t_a, a, t_b) {
Some((ty, kind)) => {
let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
// E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
fn unsize_ty(&self,
ty_a: Ty<'tcx>,
- sty_a: &ty::sty<'tcx>,
+ a: Ty<'tcx>,
ty_b: Ty<'tcx>)
-> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> {
- debug!("unsize_ty(sty_a={}, ty_b={})", sty_a, ty_b.repr(self.get_ref().infcx.tcx));
+ debug!("unsize_ty(a={}, ty_b={})", a, ty_b.repr(self.get_ref().infcx.tcx));
let tcx = self.get_ref().infcx.tcx;
- self.unpack_actual_value(ty_b, |sty_b|
- match (sty_a, sty_b) {
+ self.unpack_actual_value(ty_b, |b|
+ match (&a.sty, &b.sty) {
(&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
let ty = ty::mk_vec(tcx, t_a, None);
Some((ty, ty::UnsizeLength(len)))
fn coerce_borrowed_object(&self,
a: Ty<'tcx>,
- sty_a: &ty::sty<'tcx>,
b: Ty<'tcx>,
b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
{
let tcx = self.get_ref().infcx.tcx;
- debug!("coerce_borrowed_object(a={}, sty_a={}, b={}, b_mutbl={})",
- a.repr(tcx), sty_a,
+ debug!("coerce_borrowed_object(a={}, b={}, b_mutbl={})",
+ a.repr(tcx),
b.repr(tcx), b_mutbl);
let coercion = Coercion(self.get_ref().trace.clone());
let r_a = self.get_ref().infcx.next_region_var(coercion);
- self.coerce_object(a, sty_a, b, b_mutbl,
+ self.coerce_object(a, b, b_mutbl,
|tr| ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr }),
|| AutoPtr(r_a, b_mutbl, None))
}
fn coerce_unsafe_object(&self,
a: Ty<'tcx>,
- sty_a: &ty::sty<'tcx>,
b: Ty<'tcx>,
b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
{
let tcx = self.get_ref().infcx.tcx;
- debug!("coerce_unsafe_object(a={}, sty_a={}, b={}, b_mutbl={})",
- a.repr(tcx), sty_a,
+ debug!("coerce_unsafe_object(a={}, b={}, b_mutbl={})",
+ a.repr(tcx),
b.repr(tcx), b_mutbl);
- self.coerce_object(a, sty_a, b, b_mutbl,
+ self.coerce_object(a, b, b_mutbl,
|tr| ty::mk_ptr(tcx, ty::mt{ mutbl: b_mutbl, ty: tr }),
|| AutoUnsafe(b_mutbl, None))
}
fn coerce_object<F, G>(&self,
a: Ty<'tcx>,
- sty_a: &ty::sty<'tcx>,
b: Ty<'tcx>,
b_mutbl: ast::Mutability,
mk_ty: F,
{
let tcx = self.get_ref().infcx.tcx;
- match *sty_a {
+ match a.sty {
ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty.sty {
ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl);
pub fn coerce_borrowed_fn(&self,
a: Ty<'tcx>,
- sty_a: &ty::sty<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
- debug!("coerce_borrowed_fn(a={}, sty_a={}, b={})",
- a.repr(self.get_ref().infcx.tcx), sty_a,
+ debug!("coerce_borrowed_fn(a={}, b={})",
+ a.repr(self.get_ref().infcx.tcx),
b.repr(self.get_ref().infcx.tcx));
- match *sty_a {
+ match a.sty {
ty::ty_bare_fn(ref f) => {
self.coerce_from_bare_fn(a, f, b)
}
/// `proc`.
fn coerce_from_bare_fn(&self, a: Ty<'tcx>, fn_ty_a: &ty::BareFnTy<'tcx>, b: Ty<'tcx>)
-> CoerceResult<'tcx> {
- self.unpack_actual_value(b, |sty_b| {
+ self.unpack_actual_value(b, |b| {
debug!("coerce_from_bare_fn(a={}, b={})",
a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
return self.subtype(a, b);
}
- let fn_ty_b = match *sty_b {
+ let fn_ty_b = match b.sty {
ty::ty_closure(ref f) => (*f).clone(),
_ => return self.subtype(a, b)
};
pub fn coerce_unsafe_ptr(&self,
a: Ty<'tcx>,
- sty_a: &ty::sty<'tcx>,
b: Ty<'tcx>,
mutbl_b: ast::Mutability)
-> CoerceResult<'tcx> {
- debug!("coerce_unsafe_ptr(a={}, sty_a={}, b={})",
- a.repr(self.get_ref().infcx.tcx), sty_a,
+ debug!("coerce_unsafe_ptr(a={}, b={})",
+ a.repr(self.get_ref().infcx.tcx),
b.repr(self.get_ref().infcx.tcx));
- let mt_a = match *sty_a {
+ let mt_a = match a.sty {
ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => mt,
_ => {
return self.subtype(a, b);
use middle::ty_fold;
use middle::ty_fold::TypeFoldable;
use middle::ty_fold::TypeFolder;
-use std::collections::hash_map;
+use std::collections::hash_map::{mod, Entry};
use super::InferCtxt;
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
}
match self.freshen_map.entry(key) {
- hash_map::Occupied(entry) => *entry.get(),
- hash_map::Vacant(entry) => {
+ Entry::Occupied(entry) => *entry.get(),
+ Entry::Vacant(entry) => {
let index = self.freshen_count;
self.freshen_count += 1;
let t = ty::mk_infer(self.infcx.tcx, freshener(index));
use util::nodemap::{FnvHashMap, FnvHashSet};
use util::ppaux::Repr;
-use std::collections::hash_map::Vacant;
+use std::collections::hash_map::Entry::Vacant;
use std::io::{mod, File};
use std::os;
use std::sync::atomic;
// except according to those terms.
use middle::def::*;
-use middle::resolve;
use middle::ty;
use util::nodemap::FnvHashMap;
// This is used because same-named variables in alternative patterns need to
// use the NodeId of their namesake in the first pattern.
-pub fn pat_id_map(dm: &resolve::DefMap, pat: &ast::Pat) -> PatIdMap {
+pub fn pat_id_map(dm: &DefMap, pat: &ast::Pat) -> PatIdMap {
let mut map = FnvHashMap::new();
pat_bindings(dm, pat, |_bm, p_id, _s, path1| {
map.insert(path1.node, p_id);
map
}
-pub fn pat_is_refutable(dm: &resolve::DefMap, pat: &ast::Pat) -> bool {
+pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
ast::PatLit(_) | ast::PatRange(_, _) => true,
ast::PatEnum(_, _) |
}
}
-pub fn pat_is_variant_or_struct(dm: &resolve::DefMap, pat: &ast::Pat) -> bool {
+pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
ast::PatEnum(_, _) |
ast::PatIdent(_, _, None) |
}
}
-pub fn pat_is_const(dm: &resolve::DefMap, pat: &ast::Pat) -> bool {
+pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
ast::PatIdent(_, _, None) | ast::PatEnum(..) => {
match dm.borrow().get(&pat.id) {
}
}
-pub fn pat_is_binding(dm: &resolve::DefMap, pat: &ast::Pat) -> bool {
+pub fn pat_is_binding(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
ast::PatIdent(..) => {
!pat_is_variant_or_struct(dm, pat) &&
}
}
-pub fn pat_is_binding_or_wild(dm: &resolve::DefMap, pat: &ast::Pat) -> bool {
+pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
ast::PatIdent(..) => pat_is_binding(dm, pat),
ast::PatWild(_) => true,
/// Call `it` on every "binding" in a pattern, e.g., on `a` in
/// `match foo() { Some(a) => (), None => () }`
-pub fn pat_bindings<I>(dm: &resolve::DefMap, pat: &ast::Pat, mut it: I) where
+pub fn pat_bindings<I>(dm: &DefMap, pat: &ast::Pat, mut it: I) where
I: FnMut(ast::BindingMode, ast::NodeId, Span, &ast::SpannedIdent),
{
walk_pat(pat, |p| {
/// Checks if the pattern contains any patterns that bind something to
/// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
-pub fn pat_contains_bindings(dm: &resolve::DefMap, pat: &ast::Pat) -> bool {
+pub fn pat_contains_bindings(dm: &DefMap, pat: &ast::Pat) -> bool {
let mut contains_bindings = false;
walk_pat(pat, |p| {
if pat_is_binding(dm, p) {
//! A pass that checks to make sure private fields and methods aren't used
//! outside their scopes. This pass will also generate a set of exported items
//! which are available for use externally when compiled as a library.
+pub use self::PrivateDep::*;
+pub use self::ImportUse::*;
+pub use self::LastPrivate::*;
use self::PrivacyResult::*;
use self::FieldName::*;
use std::mem::replace;
use metadata::csearch;
-use middle::{def, resolve};
+use middle::def;
use middle::ty::{mod, Ty};
use middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam, MethodTypeParam};
use middle::ty::{MethodStatic, MethodStaticUnboxedClosure, MethodObject, MethodTraitObject};
-use util::nodemap::{NodeMap, NodeSet};
+use util::nodemap::{DefIdSet, NodeMap, NodeSet};
use syntax::{ast, ast_map};
use syntax::ast_util::{is_local, local_def, PostExpansionMethod};
use syntax::parse::token;
use syntax::visit::{mod, Visitor};
-type Context<'a, 'tcx> = (&'a MethodMap<'tcx>, &'a resolve::ExportMap2);
+type Context<'a, 'tcx> = (&'a MethodMap<'tcx>, &'a def::ExportMap);
/// A set of AST nodes exported by the crate.
pub type ExportedItems = NodeSet;
+/// A set containing all exported definitions from external crates.
+/// The set does not contain any entries from local crates.
+pub type ExternalExports = DefIdSet;
+
/// A set of AST nodes that are fully public in the crate. This map is used for
/// documentation purposes (reexporting a private struct inlines the doc,
/// reexporting a public struct doesn't inline the doc).
pub type PublicItems = NodeSet;
+// FIXME: dox
+pub type LastPrivateMap = NodeMap<LastPrivate>;
+
+#[deriving(Copy, Show)]
+pub enum LastPrivate {
+ LastMod(PrivateDep),
+ // `use` directives (imports) can refer to two separate definitions in the
+ // type and value namespaces. We record here the last private node for each
+ // and whether the import is in fact used for each.
+ // If the Option<PrivateDep> fields are None, it means there is no definition
+ // in that namespace.
+ LastImport{value_priv: Option<PrivateDep>,
+ value_used: ImportUse,
+ type_priv: Option<PrivateDep>,
+ type_used: ImportUse},
+}
+
+#[deriving(Copy, Show)]
+pub enum PrivateDep {
+ AllPublic,
+ DependsOn(ast::DefId),
+}
+
+// How an import is used.
+#[deriving(Copy, PartialEq, Show)]
+pub enum ImportUse {
+ Unused, // The import is not used.
+ Used, // The import is used.
+}
+
+impl LastPrivate {
+ pub fn or(self, other: LastPrivate) -> LastPrivate {
+ match (self, other) {
+ (me, LastMod(AllPublic)) => me,
+ (_, other) => other,
+ }
+ }
+}
+
/// Result of a checking operation - None => no errors were found. Some => an
/// error and contains the span and message for reporting that error and
/// optionally the same for a note about the error.
struct EmbargoVisitor<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
- exp_map2: &'a resolve::ExportMap2,
+ export_map: &'a def::ExportMap,
// This flag is an indicator of whether the previous item in the
// hierarchical chain was exported or not. This is the indicator of whether
// This code is here instead of in visit_item so that the
// crate module gets processed as well.
if self.prev_exported {
- assert!(self.exp_map2.contains_key(&id), "wut {}", id);
- for export in self.exp_map2[id].iter() {
+ assert!(self.export_map.contains_key(&id), "wut {}", id);
+ for export in self.export_map[id].iter() {
if is_local(export.def_id) {
self.reexports.insert(export.def_id.node);
}
curitem: ast::NodeId,
in_foreign: bool,
parents: NodeMap<ast::NodeId>,
- external_exports: resolve::ExternalExports,
- last_private_map: resolve::LastPrivateMap,
+ external_exports: ExternalExports,
+ last_private_map: LastPrivateMap,
}
enum PrivacyResult {
};
match self.last_private_map[path_id] {
- resolve::LastMod(resolve::AllPublic) => {},
- resolve::LastMod(resolve::DependsOn(def)) => {
+ LastMod(AllPublic) => {},
+ LastMod(DependsOn(def)) => {
self.report_error(ck_public(def));
},
- resolve::LastImport{value_priv,
- value_used: check_value,
- type_priv,
- type_used: check_type} => {
+ LastImport { value_priv,
+ value_used: check_value,
+ type_priv,
+ type_used: check_type } => {
// This dance with found_error is because we don't want to report
// a privacy error twice for the same directive.
let found_error = match (type_priv, check_type) {
- (Some(resolve::DependsOn(def)), resolve::Used) => {
+ (Some(DependsOn(def)), Used) => {
!self.report_error(ck_public(def))
},
_ => false,
};
if !found_error {
match (value_priv, check_value) {
- (Some(resolve::DependsOn(def)), resolve::Used) => {
+ (Some(DependsOn(def)), Used) => {
self.report_error(ck_public(def));
},
_ => {},
// be illegal. We only report one error, even if it is
// illegal to import from both namespaces.
match (value_priv, check_value, type_priv, check_type) {
- (Some(p), resolve::Unused, None, _) |
- (None, _, Some(p), resolve::Unused) => {
+ (Some(p), Unused, None, _) |
+ (None, _, Some(p), Unused) => {
let p = match p {
- resolve::AllPublic => None,
- resolve::DependsOn(def) => ck_public(def),
+ AllPublic => None,
+ DependsOn(def) => ck_public(def),
};
if p.is_some() {
self.report_error(p);
}
},
- (Some(v), resolve::Unused, Some(t), resolve::Unused) => {
+ (Some(v), Unused, Some(t), Unused) => {
let v = match v {
- resolve::AllPublic => None,
- resolve::DependsOn(def) => ck_public(def),
+ AllPublic => None,
+ DependsOn(def) => ck_public(def),
};
let t = match t {
- resolve::AllPublic => None,
- resolve::DependsOn(def) => ck_public(def),
+ AllPublic => None,
+ DependsOn(def) => ck_public(def),
};
if let (Some(_), Some(t)) = (v, t) {
self.report_error(Some(t));
}
fn check_ty_param_bound(&self,
- span: Span,
ty_param_bound: &ast::TyParamBound) {
if let ast::TraitTyParamBound(ref trait_ref) = *ty_param_bound {
if !self.tcx.sess.features.borrow().visible_private_types &&
self.path_is_private_type(trait_ref.trait_ref.ref_id) {
+ let span = trait_ref.trait_ref.path.span;
self.tcx.sess.span_err(span,
- "private type in exported type \
+ "private trait in exported type \
parameter bound");
}
}
}
for bound in bounds.iter() {
- self.check_ty_param_bound(item.span, bound)
+ self.check_ty_param_bound(bound)
}
}
fn visit_generics(&mut self, generics: &ast::Generics) {
for ty_param in generics.ty_params.iter() {
for bound in ty_param.bounds.iter() {
- self.check_ty_param_bound(ty_param.span, bound)
+ self.check_ty_param_bound(bound)
}
}
for predicate in generics.where_clause.predicates.iter() {
match predicate {
&ast::WherePredicate::BoundPredicate(ref bound_pred) => {
for bound in bound_pred.bounds.iter() {
- self.check_ty_param_bound(bound_pred.span, bound)
+ self.check_ty_param_bound(bound)
}
}
+ &ast::WherePredicate::RegionPredicate(_) => {}
&ast::WherePredicate::EqPredicate(ref eq_pred) => {
self.visit_ty(&*eq_pred.ty);
}
}
pub fn check_crate(tcx: &ty::ctxt,
- exp_map2: &resolve::ExportMap2,
- external_exports: resolve::ExternalExports,
- last_private_map: resolve::LastPrivateMap)
+ export_map: &def::ExportMap,
+ external_exports: ExternalExports,
+ last_private_map: LastPrivateMap)
-> (ExportedItems, PublicItems) {
let krate = tcx.map.krate();
exported_items: NodeSet::new(),
public_items: NodeSet::new(),
reexports: NodeSet::new(),
- exp_map2: exp_map2,
+ export_map: export_map,
prev_exported: true,
prev_public: true,
};
+++ /dev/null
-// Copyright 2012-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.
-
-#![allow(non_camel_case_types)]
-
-pub use self::PrivateDep::*;
-pub use self::ImportUse::*;
-pub use self::TraitItemKind::*;
-pub use self::LastPrivate::*;
-use self::PatternBindingMode::*;
-use self::Namespace::*;
-use self::NamespaceError::*;
-use self::NamespaceResult::*;
-use self::NameDefinition::*;
-use self::ImportDirectiveSubclass::*;
-use self::ReducedGraphParent::*;
-use self::ResolveResult::*;
-use self::FallbackSuggestion::*;
-use self::TypeParameters::*;
-use self::RibKind::*;
-use self::MethodSort::*;
-use self::UseLexicalScopeFlag::*;
-use self::ModulePrefixResult::*;
-use self::NameSearchType::*;
-use self::BareIdentifierPatternResolution::*;
-use self::DuplicateCheckingMode::*;
-use self::ParentLink::*;
-use self::ModuleKind::*;
-use self::TraitReferenceType::*;
-use self::FallbackChecks::*;
-
-use session::Session;
-use lint;
-use metadata::csearch;
-use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
-use middle::def::*;
-use middle::lang_items::LanguageItems;
-use middle::pat_util::pat_bindings;
-use middle::subst::{ParamSpace, FnSpace, TypeSpace};
-use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory};
-use middle::ty::{CaptureModeMap, Freevar, FreevarMap};
-use util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap};
-
-use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
-use syntax::ast::{DeclItem, DefId, Expr, ExprAgain, ExprBreak, ExprField};
-use syntax::ast::{ExprClosure, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall};
-use syntax::ast::{ExprPath, ExprStruct, FnDecl};
-use syntax::ast::{ForeignItem, ForeignItemFn, ForeignItemStatic, Generics};
-use syntax::ast::{Ident, ImplItem, Item, ItemEnum, ItemFn, ItemForeignMod};
-use syntax::ast::{ItemImpl, ItemMac, ItemMod, ItemStatic, ItemStruct};
-use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, ItemConst};
-use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId};
-use syntax::ast::{Pat, PatEnum, PatIdent, PatLit};
-use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod};
-use syntax::ast::{PolyTraitRef, PrimTy, Public, SelfExplicit, SelfStatic};
-use syntax::ast::{RegionTyParamBound, StmtDecl, StructField};
-use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound};
-use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32};
-use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt, TyObjectSum};
-use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyPolyTraitRef, TyQPath};
-use syntax::ast::{TyRptr, TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint};
-use syntax::ast::{TypeImplItem, UnnamedField};
-use syntax::ast::{Variant, ViewItem, ViewItemExternCrate};
-use syntax::ast::{ViewItemUse, ViewPathGlob, ViewPathList, ViewPathSimple};
-use syntax::ast::{Visibility};
-use syntax::ast;
-use syntax::ast_util::{mod, PostExpansionMethod, local_def, walk_pat};
-use syntax::attr::AttrMetaMethods;
-use syntax::ext::mtwt;
-use syntax::parse::token::{mod, special_names, special_idents};
-use syntax::codemap::{Span, DUMMY_SP, Pos};
-use syntax::owned_slice::OwnedSlice;
-use syntax::visit::{mod, Visitor};
-
-use std::collections::{HashMap, HashSet};
-use std::collections::hash_map::{Occupied, Vacant};
-use std::cell::{Cell, RefCell};
-use std::mem::replace;
-use std::rc::{Rc, Weak};
-use std::uint;
-
-// Definition mapping
-pub type DefMap = RefCell<NodeMap<Def>>;
-
-#[deriving(Copy)]
-struct binding_info {
- span: Span,
- binding_mode: BindingMode,
-}
-
-// Map from the name in a pattern to its binding mode.
-type BindingMap = HashMap<Name,binding_info>;
-
-// Trait method resolution
-pub type TraitMap = NodeMap<Vec<DefId> >;
-
-// This is the replacement export map. It maps a module to all of the exports
-// within.
-pub type ExportMap2 = NodeMap<Vec<Export2>>;
-
-pub struct Export2 {
- pub name: String, // The name of the target.
- pub def_id: DefId, // The definition of the target.
-}
-
-// This set contains all exported definitions from external crates. The set does
-// not contain any entries from local crates.
-pub type ExternalExports = DefIdSet;
-
-// FIXME: dox
-pub type LastPrivateMap = NodeMap<LastPrivate>;
-
-#[deriving(Copy, Show)]
-pub enum LastPrivate {
- LastMod(PrivateDep),
- // `use` directives (imports) can refer to two separate definitions in the
- // type and value namespaces. We record here the last private node for each
- // and whether the import is in fact used for each.
- // If the Option<PrivateDep> fields are None, it means there is no definition
- // in that namespace.
- LastImport{value_priv: Option<PrivateDep>,
- value_used: ImportUse,
- type_priv: Option<PrivateDep>,
- type_used: ImportUse},
-}
-
-#[deriving(Copy, Show)]
-pub enum PrivateDep {
- AllPublic,
- DependsOn(DefId),
-}
-
-// How an import is used.
-#[deriving(Copy, PartialEq, Show)]
-pub enum ImportUse {
- Unused, // The import is not used.
- Used, // The import is used.
-}
-
-impl LastPrivate {
- fn or(self, other: LastPrivate) -> LastPrivate {
- match (self, other) {
- (me, LastMod(AllPublic)) => me,
- (_, other) => other,
- }
- }
-}
-
-#[deriving(Copy, PartialEq)]
-enum PatternBindingMode {
- RefutableMode,
- LocalIrrefutableMode,
- ArgumentIrrefutableMode,
-}
-
-#[deriving(Copy, PartialEq, Eq, Hash, Show)]
-enum Namespace {
- TypeNS,
- ValueNS
-}
-
-#[deriving(Copy, PartialEq)]
-enum NamespaceError {
- NoError,
- ModuleError,
- TypeError,
- ValueError
-}
-
-/// A NamespaceResult represents the result of resolving an import in
-/// a particular namespace. The result is either definitely-resolved,
-/// definitely- unresolved, or unknown.
-#[deriving(Clone)]
-enum NamespaceResult {
- /// Means that resolve hasn't gathered enough information yet to determine
- /// whether the name is bound in this namespace. (That is, it hasn't
- /// resolved all `use` directives yet.)
- UnknownResult,
- /// Means that resolve has determined that the name is definitely
- /// not bound in the namespace.
- UnboundResult,
- /// Means that resolve has determined that the name is bound in the Module
- /// argument, and specified by the NameBindings argument.
- BoundResult(Rc<Module>, Rc<NameBindings>)
-}
-
-impl NamespaceResult {
- fn is_unknown(&self) -> bool {
- match *self {
- UnknownResult => true,
- _ => false
- }
- }
- fn is_unbound(&self) -> bool {
- match *self {
- UnboundResult => true,
- _ => false
- }
- }
-}
-
-enum NameDefinition {
- NoNameDefinition, //< The name was unbound.
- ChildNameDefinition(Def, LastPrivate), //< The name identifies an immediate child.
- ImportNameDefinition(Def, LastPrivate) //< The name identifies an import.
-}
-
-impl<'a, 'v> Visitor<'v> for Resolver<'a> {
- fn visit_item(&mut self, item: &Item) {
- self.resolve_item(item);
- }
- fn visit_arm(&mut self, arm: &Arm) {
- self.resolve_arm(arm);
- }
- fn visit_block(&mut self, block: &Block) {
- self.resolve_block(block);
- }
- fn visit_expr(&mut self, expr: &Expr) {
- self.resolve_expr(expr);
- }
- fn visit_local(&mut self, local: &Local) {
- self.resolve_local(local);
- }
- fn visit_ty(&mut self, ty: &Ty) {
- self.resolve_type(ty);
- }
-}
-
-/// Contains data for specific types of import directives.
-#[deriving(Copy)]
-enum ImportDirectiveSubclass {
- SingleImport(Name /* target */, Name /* source */),
- GlobImport
-}
-
-/// The context that we thread through while building the reduced graph.
-#[deriving(Clone)]
-enum ReducedGraphParent {
- ModuleReducedGraphParent(Rc<Module>)
-}
-
-impl ReducedGraphParent {
- fn module(&self) -> Rc<Module> {
- match *self {
- ModuleReducedGraphParent(ref m) => {
- m.clone()
- }
- }
- }
-}
-
-type ErrorMessage = Option<(Span, String)>;
-
-enum ResolveResult<T> {
- Failed(ErrorMessage), // Failed to resolve the name, optional helpful error message.
- Indeterminate, // Couldn't determine due to unresolved globs.
- Success(T) // Successfully resolved the import.
-}
-
-impl<T> ResolveResult<T> {
- fn indeterminate(&self) -> bool {
- match *self { Indeterminate => true, _ => false }
- }
-}
-
-enum FallbackSuggestion {
- NoSuggestion,
- Field,
- Method,
- TraitItem,
- StaticMethod(String),
- TraitMethod(String),
-}
-
-#[deriving(Copy)]
-enum TypeParameters<'a> {
- NoTypeParameters,
- HasTypeParameters(
- // Type parameters.
- &'a Generics,
-
- // Identifies the things that these parameters
- // were declared on (type, fn, etc)
- ParamSpace,
-
- // ID of the enclosing item.
- NodeId,
-
- // The kind of the rib used for type parameters.
- RibKind)
-}
-
-// The rib kind controls the translation of local
-// definitions (`DefLocal`) to upvars (`DefUpvar`).
-#[deriving(Copy, Show)]
-enum RibKind {
- // No translation needs to be applied.
- NormalRibKind,
-
- // We passed through a closure scope at the given node ID.
- // Translate upvars as appropriate.
- ClosureRibKind(NodeId /* func id */, NodeId /* body id if proc or unboxed */),
-
- // We passed through an impl or trait and are now in one of its
- // methods. Allow references to ty params that impl or trait
- // binds. Disallow any other upvars (including other ty params that are
- // upvars).
- // parent; method itself
- MethodRibKind(NodeId, MethodSort),
-
- // We passed through an item scope. Disallow upvars.
- ItemRibKind,
-
- // We're in a constant item. Can't refer to dynamic stuff.
- ConstantItemRibKind
-}
-
-// Methods can be required or provided. RequiredMethod methods only occur in traits.
-#[deriving(Copy, Show)]
-enum MethodSort {
- RequiredMethod,
- ProvidedMethod(NodeId)
-}
-
-#[deriving(Copy)]
-enum UseLexicalScopeFlag {
- DontUseLexicalScope,
- UseLexicalScope
-}
-
-enum ModulePrefixResult {
- NoPrefixFound,
- PrefixFound(Rc<Module>, uint)
-}
-
-#[deriving(Clone, Copy, Eq, PartialEq)]
-pub enum TraitItemKind {
- NonstaticMethodTraitItemKind,
- StaticMethodTraitItemKind,
- TypeTraitItemKind,
-}
-
-impl TraitItemKind {
- pub fn from_explicit_self_category(explicit_self_category:
- ExplicitSelfCategory)
- -> TraitItemKind {
- if explicit_self_category == StaticExplicitSelfCategory {
- StaticMethodTraitItemKind
- } else {
- NonstaticMethodTraitItemKind
- }
- }
-}
-
-#[deriving(Copy, PartialEq)]
-enum NameSearchType {
- /// We're doing a name search in order to resolve a `use` directive.
- ImportSearch,
-
- /// We're doing a name search in order to resolve a path type, a path
- /// expression, or a path pattern.
- PathSearch,
-}
-
-#[deriving(Copy)]
-enum BareIdentifierPatternResolution {
- FoundStructOrEnumVariant(Def, LastPrivate),
- FoundConst(Def, LastPrivate),
- BareIdentifierPatternUnresolved
-}
-
-// Specifies how duplicates should be handled when adding a child item if
-// another item exists with the same name in some namespace.
-#[deriving(Copy, PartialEq)]
-enum DuplicateCheckingMode {
- ForbidDuplicateModules,
- ForbidDuplicateTypesAndModules,
- ForbidDuplicateValues,
- ForbidDuplicateTypesAndValues,
- OverwriteDuplicates
-}
-
-/// One local scope.
-#[deriving(Show)]
-struct Rib {
- bindings: HashMap<Name, DefLike>,
- kind: RibKind,
-}
-
-impl Rib {
- fn new(kind: RibKind) -> Rib {
- Rib {
- bindings: HashMap::new(),
- kind: kind
- }
- }
-}
-
-/// One import directive.
-struct ImportDirective {
- module_path: Vec<Name>,
- subclass: ImportDirectiveSubclass,
- span: Span,
- id: NodeId,
- is_public: bool, // see note in ImportResolution about how to use this
- shadowable: bool,
-}
-
-impl ImportDirective {
- fn new(module_path: Vec<Name> ,
- subclass: ImportDirectiveSubclass,
- span: Span,
- id: NodeId,
- is_public: bool,
- shadowable: bool)
- -> ImportDirective {
- ImportDirective {
- module_path: module_path,
- subclass: subclass,
- span: span,
- id: id,
- is_public: is_public,
- shadowable: shadowable,
- }
- }
-}
-
-/// The item that an import resolves to.
-#[deriving(Clone)]
-struct Target {
- target_module: Rc<Module>,
- bindings: Rc<NameBindings>,
- shadowable: bool,
-}
-
-impl Target {
- fn new(target_module: Rc<Module>,
- bindings: Rc<NameBindings>,
- shadowable: bool)
- -> Target {
- Target {
- target_module: target_module,
- bindings: bindings,
- shadowable: shadowable,
- }
- }
-}
-
-/// An ImportResolution represents a particular `use` directive.
-struct ImportResolution {
- /// Whether this resolution came from a `use` or a `pub use`. Note that this
- /// should *not* be used whenever resolution is being performed, this is
- /// only looked at for glob imports statements currently. Privacy testing
- /// occurs during a later phase of compilation.
- is_public: bool,
-
- // The number of outstanding references to this name. When this reaches
- // zero, outside modules can count on the targets being correct. Before
- // then, all bets are off; future imports could override this name.
- outstanding_references: uint,
-
- /// The value that this `use` directive names, if there is one.
- value_target: Option<Target>,
- /// The source node of the `use` directive leading to the value target
- /// being non-none
- value_id: NodeId,
-
- /// The type that this `use` directive names, if there is one.
- type_target: Option<Target>,
- /// The source node of the `use` directive leading to the type target
- /// being non-none
- type_id: NodeId,
-}
-
-impl ImportResolution {
- fn new(id: NodeId, is_public: bool) -> ImportResolution {
- ImportResolution {
- type_id: id,
- value_id: id,
- outstanding_references: 0,
- value_target: None,
- type_target: None,
- is_public: is_public,
- }
- }
-
- fn target_for_namespace(&self, namespace: Namespace)
- -> Option<Target> {
- match namespace {
- TypeNS => self.type_target.clone(),
- ValueNS => self.value_target.clone(),
- }
- }
-
- fn id(&self, namespace: Namespace) -> NodeId {
- match namespace {
- TypeNS => self.type_id,
- ValueNS => self.value_id,
- }
- }
-}
-
-/// The link from a module up to its nearest parent node.
-#[deriving(Clone)]
-enum ParentLink {
- NoParentLink,
- ModuleParentLink(Weak<Module>, Name),
- BlockParentLink(Weak<Module>, NodeId)
-}
-
-/// The type of module this is.
-#[deriving(Copy, PartialEq)]
-enum ModuleKind {
- NormalModuleKind,
- TraitModuleKind,
- ImplModuleKind,
- EnumModuleKind,
- AnonymousModuleKind,
-}
-
-/// One node in the tree of modules.
-struct Module {
- parent_link: ParentLink,
- def_id: Cell<Option<DefId>>,
- kind: Cell<ModuleKind>,
- is_public: bool,
-
- children: RefCell<HashMap<Name, Rc<NameBindings>>>,
- imports: RefCell<Vec<ImportDirective>>,
-
- // The external module children of this node that were declared with
- // `extern crate`.
- external_module_children: RefCell<HashMap<Name, Rc<Module>>>,
-
- // The anonymous children of this node. Anonymous children are pseudo-
- // modules that are implicitly created around items contained within
- // blocks.
- //
- // For example, if we have this:
- //
- // fn f() {
- // fn g() {
- // ...
- // }
- // }
- //
- // There will be an anonymous module created around `g` with the ID of the
- // entry block for `f`.
- anonymous_children: RefCell<NodeMap<Rc<Module>>>,
-
- // The status of resolving each import in this module.
- import_resolutions: RefCell<HashMap<Name, ImportResolution>>,
-
- // The number of unresolved globs that this module exports.
- glob_count: Cell<uint>,
-
- // The index of the import we're resolving.
- resolved_import_count: Cell<uint>,
-
- // Whether this module is populated. If not populated, any attempt to
- // access the children must be preceded with a
- // `populate_module_if_necessary` call.
- populated: Cell<bool>,
-}
-
-impl Module {
- fn new(parent_link: ParentLink,
- def_id: Option<DefId>,
- kind: ModuleKind,
- external: bool,
- is_public: bool)
- -> Module {
- Module {
- parent_link: parent_link,
- def_id: Cell::new(def_id),
- kind: Cell::new(kind),
- is_public: is_public,
- children: RefCell::new(HashMap::new()),
- imports: RefCell::new(Vec::new()),
- external_module_children: RefCell::new(HashMap::new()),
- anonymous_children: RefCell::new(NodeMap::new()),
- import_resolutions: RefCell::new(HashMap::new()),
- glob_count: Cell::new(0),
- resolved_import_count: Cell::new(0),
- populated: Cell::new(!external),
- }
- }
-
- fn all_imports_resolved(&self) -> bool {
- self.imports.borrow().len() == self.resolved_import_count.get()
- }
-}
-
-bitflags! {
- #[deriving(Show)]
- flags DefModifiers: u8 {
- const PUBLIC = 0b0000_0001,
- const IMPORTABLE = 0b0000_0010,
- }
-}
-
-// Records a possibly-private type definition.
-#[deriving(Clone)]
-struct TypeNsDef {
- modifiers: DefModifiers, // see note in ImportResolution about how to use this
- module_def: Option<Rc<Module>>,
- type_def: Option<Def>,
- type_span: Option<Span>
-}
-
-// Records a possibly-private value definition.
-#[deriving(Clone, Copy, Show)]
-struct ValueNsDef {
- modifiers: DefModifiers, // see note in ImportResolution about how to use this
- def: Def,
- value_span: Option<Span>,
-}
-
-// Records the definitions (at most one for each namespace) that a name is
-// bound to.
-struct NameBindings {
- type_def: RefCell<Option<TypeNsDef>>, //< Meaning in type namespace.
- value_def: RefCell<Option<ValueNsDef>>, //< Meaning in value namespace.
-}
-
-/// Ways in which a trait can be referenced
-#[deriving(Copy)]
-enum TraitReferenceType {
- TraitImplementation, // impl SomeTrait for T { ... }
- TraitDerivation, // trait T : SomeTrait { ... }
- TraitBoundingTypeParameter, // fn f<T:SomeTrait>() { ... }
- TraitObject, // Box<for<'a> SomeTrait>
- TraitQPath, // <T as SomeTrait>::
-}
-
-impl NameBindings {
- fn new() -> NameBindings {
- NameBindings {
- type_def: RefCell::new(None),
- value_def: RefCell::new(None),
- }
- }
-
- /// Creates a new module in this set of name bindings.
- fn define_module(&self,
- parent_link: ParentLink,
- def_id: Option<DefId>,
- kind: ModuleKind,
- external: bool,
- is_public: bool,
- sp: Span) {
- // Merges the module with the existing type def or creates a new one.
- let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
- let module_ = Rc::new(Module::new(parent_link,
- def_id,
- kind,
- external,
- is_public));
- let type_def = self.type_def.borrow().clone();
- match type_def {
- None => {
- *self.type_def.borrow_mut() = Some(TypeNsDef {
- modifiers: modifiers,
- module_def: Some(module_),
- type_def: None,
- type_span: Some(sp)
- });
- }
- Some(type_def) => {
- *self.type_def.borrow_mut() = Some(TypeNsDef {
- modifiers: modifiers,
- module_def: Some(module_),
- type_span: Some(sp),
- type_def: type_def.type_def
- });
- }
- }
- }
-
- /// Sets the kind of the module, creating a new one if necessary.
- fn set_module_kind(&self,
- parent_link: ParentLink,
- def_id: Option<DefId>,
- kind: ModuleKind,
- external: bool,
- is_public: bool,
- _sp: Span) {
- let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
- let type_def = self.type_def.borrow().clone();
- match type_def {
- None => {
- let module = Module::new(parent_link,
- def_id,
- kind,
- external,
- is_public);
- *self.type_def.borrow_mut() = Some(TypeNsDef {
- modifiers: modifiers,
- module_def: Some(Rc::new(module)),
- type_def: None,
- type_span: None,
- });
- }
- Some(type_def) => {
- match type_def.module_def {
- None => {
- let module = Module::new(parent_link,
- def_id,
- kind,
- external,
- is_public);
- *self.type_def.borrow_mut() = Some(TypeNsDef {
- modifiers: modifiers,
- module_def: Some(Rc::new(module)),
- type_def: type_def.type_def,
- type_span: None,
- });
- }
- Some(module_def) => module_def.kind.set(kind),
- }
- }
- }
- }
-
- /// Records a type definition.
- fn define_type(&self, def: Def, sp: Span, modifiers: DefModifiers) {
- debug!("defining type for def {} with modifiers {}", def, modifiers);
- // Merges the type with the existing type def or creates a new one.
- let type_def = self.type_def.borrow().clone();
- match type_def {
- None => {
- *self.type_def.borrow_mut() = Some(TypeNsDef {
- module_def: None,
- type_def: Some(def),
- type_span: Some(sp),
- modifiers: modifiers,
- });
- }
- Some(type_def) => {
- *self.type_def.borrow_mut() = Some(TypeNsDef {
- module_def: type_def.module_def,
- type_def: Some(def),
- type_span: Some(sp),
- modifiers: modifiers,
- });
- }
- }
- }
-
- /// Records a value definition.
- fn define_value(&self, def: Def, sp: Span, modifiers: DefModifiers) {
- debug!("defining value for def {} with modifiers {}", def, modifiers);
- *self.value_def.borrow_mut() = Some(ValueNsDef {
- def: def,
- value_span: Some(sp),
- modifiers: modifiers,
- });
- }
-
- /// Returns the module node if applicable.
- fn get_module_if_available(&self) -> Option<Rc<Module>> {
- match *self.type_def.borrow() {
- Some(ref type_def) => type_def.module_def.clone(),
- None => None
- }
- }
-
- /// Returns the module node. Panics if this node does not have a module
- /// definition.
- fn get_module(&self) -> Rc<Module> {
- match self.get_module_if_available() {
- None => {
- panic!("get_module called on a node with no module \
- definition!")
- }
- Some(module_def) => module_def
- }
- }
-
- fn defined_in_namespace(&self, namespace: Namespace) -> bool {
- match namespace {
- TypeNS => return self.type_def.borrow().is_some(),
- ValueNS => return self.value_def.borrow().is_some()
- }
- }
-
- fn defined_in_public_namespace(&self, namespace: Namespace) -> bool {
- self.defined_in_namespace_with(namespace, PUBLIC)
- }
-
- fn defined_in_namespace_with(&self, namespace: Namespace, modifiers: DefModifiers) -> bool {
- match namespace {
- TypeNS => match *self.type_def.borrow() {
- Some(ref def) => def.modifiers.contains(modifiers), None => false
- },
- ValueNS => match *self.value_def.borrow() {
- Some(ref def) => def.modifiers.contains(modifiers), None => false
- }
- }
- }
-
- fn def_for_namespace(&self, namespace: Namespace) -> Option<Def> {
- match namespace {
- TypeNS => {
- match *self.type_def.borrow() {
- None => None,
- Some(ref type_def) => {
- match type_def.type_def {
- Some(type_def) => Some(type_def),
- None => {
- match type_def.module_def {
- Some(ref module) => {
- match module.def_id.get() {
- Some(did) => Some(DefMod(did)),
- None => None,
- }
- }
- None => None,
- }
- }
- }
- }
- }
- }
- ValueNS => {
- match *self.value_def.borrow() {
- None => None,
- Some(value_def) => Some(value_def.def)
- }
- }
- }
- }
-
- fn span_for_namespace(&self, namespace: Namespace) -> Option<Span> {
- if self.defined_in_namespace(namespace) {
- match namespace {
- TypeNS => {
- match *self.type_def.borrow() {
- None => None,
- Some(ref type_def) => type_def.type_span
- }
- }
- ValueNS => {
- match *self.value_def.borrow() {
- None => None,
- Some(ref value_def) => value_def.value_span
- }
- }
- }
- } else {
- None
- }
- }
-}
-
-/// Interns the names of the primitive types.
-struct PrimitiveTypeTable {
- primitive_types: HashMap<Name, PrimTy>,
-}
-
-impl PrimitiveTypeTable {
- fn new() -> PrimitiveTypeTable {
- let mut table = PrimitiveTypeTable {
- primitive_types: HashMap::new()
- };
-
- table.intern("bool", TyBool);
- table.intern("char", TyChar);
- table.intern("f32", TyFloat(TyF32));
- table.intern("f64", TyFloat(TyF64));
- table.intern("int", TyInt(TyI));
- table.intern("i8", TyInt(TyI8));
- table.intern("i16", TyInt(TyI16));
- table.intern("i32", TyInt(TyI32));
- table.intern("i64", TyInt(TyI64));
- table.intern("str", TyStr);
- table.intern("uint", TyUint(TyU));
- table.intern("u8", TyUint(TyU8));
- table.intern("u16", TyUint(TyU16));
- table.intern("u32", TyUint(TyU32));
- table.intern("u64", TyUint(TyU64));
-
- table
- }
-
- fn intern(&mut self, string: &str, primitive_type: PrimTy) {
- self.primitive_types.insert(token::intern(string), primitive_type);
- }
-}
-
-
-fn namespace_error_to_string(ns: NamespaceError) -> &'static str {
- match ns {
- NoError => "",
- ModuleError | TypeError => "type or module",
- ValueError => "value",
- }
-}
-
-/// The main resolver class.
-struct Resolver<'a> {
- session: &'a Session,
-
- graph_root: NameBindings,
-
- trait_item_map: FnvHashMap<(Name, DefId), TraitItemKind>,
-
- structs: FnvHashMap<DefId, Vec<Name>>,
-
- // The number of imports that are currently unresolved.
- unresolved_imports: uint,
-
- // The module that represents the current item scope.
- current_module: Rc<Module>,
-
- // The current set of local scopes, for values.
- // FIXME #4948: Reuse ribs to avoid allocation.
- value_ribs: Vec<Rib>,
-
- // The current set of local scopes, for types.
- type_ribs: Vec<Rib>,
-
- // The current set of local scopes, for labels.
- label_ribs: Vec<Rib>,
-
- // The trait that the current context can refer to.
- current_trait_ref: Option<(DefId, TraitRef)>,
-
- // The current self type if inside an impl (used for better errors).
- current_self_type: Option<Ty>,
-
- // The ident for the keyword "self".
- self_name: Name,
- // The ident for the non-keyword "Self".
- type_self_name: Name,
-
- // The idents for the primitive types.
- primitive_type_table: PrimitiveTypeTable,
-
- def_map: DefMap,
- freevars: RefCell<FreevarMap>,
- freevars_seen: RefCell<NodeMap<NodeSet>>,
- capture_mode_map: CaptureModeMap,
- export_map2: ExportMap2,
- trait_map: TraitMap,
- external_exports: ExternalExports,
- last_private: LastPrivateMap,
-
- // Whether or not to print error messages. Can be set to true
- // when getting additional info for error message suggestions,
- // so as to avoid printing duplicate errors
- emit_errors: bool,
-
- used_imports: HashSet<(NodeId, Namespace)>,
- used_crates: HashSet<CrateNum>,
-}
-
-struct BuildReducedGraphVisitor<'a, 'b:'a> {
- resolver: &'a mut Resolver<'b>,
- parent: ReducedGraphParent
-}
-
-impl<'a, 'b, 'v> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b> {
-
- fn visit_item(&mut self, item: &Item) {
- let p = self.resolver.build_reduced_graph_for_item(item, self.parent.clone());
- let old_parent = replace(&mut self.parent, p);
- visit::walk_item(self, item);
- self.parent = old_parent;
- }
-
- fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
- let parent = self.parent.clone();
- self.resolver.build_reduced_graph_for_foreign_item(foreign_item,
- parent.clone(),
- |r| {
- let mut v = BuildReducedGraphVisitor {
- resolver: r,
- parent: parent.clone()
- };
- visit::walk_foreign_item(&mut v, foreign_item);
- })
- }
-
- fn visit_view_item(&mut self, view_item: &ViewItem) {
- self.resolver.build_reduced_graph_for_view_item(view_item, self.parent.clone());
- }
-
- fn visit_block(&mut self, block: &Block) {
- let np = self.resolver.build_reduced_graph_for_block(block, self.parent.clone());
- let old_parent = replace(&mut self.parent, np);
- visit::walk_block(self, block);
- self.parent = old_parent;
- }
-
-}
-
-struct UnusedImportCheckVisitor<'a, 'b:'a> {
- resolver: &'a mut Resolver<'b>
-}
-
-impl<'a, 'b, 'v> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b> {
- fn visit_view_item(&mut self, vi: &ViewItem) {
- self.resolver.check_for_item_unused_imports(vi);
- visit::walk_view_item(self, vi);
- }
-}
-
-#[deriving(PartialEq)]
-enum FallbackChecks {
- Everything,
- OnlyTraitAndStatics
-}
-
-
-impl<'a> Resolver<'a> {
- fn new(session: &'a Session, crate_span: Span) -> Resolver<'a> {
- let graph_root = NameBindings::new();
-
- graph_root.define_module(NoParentLink,
- Some(DefId { krate: 0, node: 0 }),
- NormalModuleKind,
- false,
- true,
- crate_span);
-
- let current_module = graph_root.get_module();
-
- Resolver {
- session: session,
-
- // The outermost module has def ID 0; this is not reflected in the
- // AST.
-
- graph_root: graph_root,
-
- trait_item_map: FnvHashMap::new(),
- structs: FnvHashMap::new(),
-
- unresolved_imports: 0,
-
- current_module: current_module,
- value_ribs: Vec::new(),
- type_ribs: Vec::new(),
- label_ribs: Vec::new(),
-
- current_trait_ref: None,
- current_self_type: None,
-
- self_name: special_names::self_,
- type_self_name: special_names::type_self,
-
- primitive_type_table: PrimitiveTypeTable::new(),
-
- def_map: RefCell::new(NodeMap::new()),
- freevars: RefCell::new(NodeMap::new()),
- freevars_seen: RefCell::new(NodeMap::new()),
- capture_mode_map: NodeMap::new(),
- export_map2: NodeMap::new(),
- trait_map: NodeMap::new(),
- used_imports: HashSet::new(),
- used_crates: HashSet::new(),
- external_exports: DefIdSet::new(),
- last_private: NodeMap::new(),
-
- emit_errors: true,
- }
- }
- /// The main name resolution procedure.
- fn resolve(&mut self, krate: &ast::Crate) {
- self.build_reduced_graph(krate);
- self.session.abort_if_errors();
-
- self.resolve_imports();
- self.session.abort_if_errors();
-
- self.record_exports();
- self.session.abort_if_errors();
-
- self.resolve_crate(krate);
- self.session.abort_if_errors();
-
- self.check_for_unused_imports(krate);
- }
-
- //
- // Reduced graph building
- //
- // Here we build the "reduced graph": the graph of the module tree without
- // any imports resolved.
- //
-
- /// Constructs the reduced graph for the entire crate.
- fn build_reduced_graph(&mut self, krate: &ast::Crate) {
- let parent = ModuleReducedGraphParent(self.graph_root.get_module());
- let mut visitor = BuildReducedGraphVisitor {
- resolver: self,
- parent: parent
- };
- visit::walk_crate(&mut visitor, krate);
- }
-
- /// Adds a new child item to the module definition of the parent node and
- /// returns its corresponding name bindings as well as the current parent.
- /// Or, if we're inside a block, creates (or reuses) an anonymous module
- /// corresponding to the innermost block ID and returns the name bindings
- /// as well as the newly-created parent.
- ///
- /// # Panics
- ///
- /// Panics if this node does not have a module definition and we are not inside
- /// a block.
- fn add_child(&self,
- name: Name,
- reduced_graph_parent: ReducedGraphParent,
- duplicate_checking_mode: DuplicateCheckingMode,
- // For printing errors
- sp: Span)
- -> Rc<NameBindings> {
- // If this is the immediate descendant of a module, then we add the
- // child name directly. Otherwise, we create or reuse an anonymous
- // module and add the child to that.
-
- let module_ = reduced_graph_parent.module();
-
- self.check_for_conflicts_between_external_crates_and_items(&*module_,
- name,
- sp);
-
- // Add or reuse the child.
- let child = module_.children.borrow().get(&name).cloned();
- match child {
- None => {
- let child = Rc::new(NameBindings::new());
- module_.children.borrow_mut().insert(name, child.clone());
- child
- }
- Some(child) => {
- // Enforce the duplicate checking mode:
- //
- // * If we're requesting duplicate module checking, check that
- // there isn't a module in the module with the same name.
- //
- // * If we're requesting duplicate type checking, check that
- // there isn't a type in the module with the same name.
- //
- // * If we're requesting duplicate value checking, check that
- // there isn't a value in the module with the same name.
- //
- // * If we're requesting duplicate type checking and duplicate
- // value checking, check that there isn't a duplicate type
- // and a duplicate value with the same name.
- //
- // * If no duplicate checking was requested at all, do
- // nothing.
-
- let mut duplicate_type = NoError;
- let ns = match duplicate_checking_mode {
- ForbidDuplicateModules => {
- if child.get_module_if_available().is_some() {
- duplicate_type = ModuleError;
- }
- Some(TypeNS)
- }
- ForbidDuplicateTypesAndModules => {
- match child.def_for_namespace(TypeNS) {
- None => {}
- Some(_) if child.get_module_if_available()
- .map(|m| m.kind.get()) ==
- Some(ImplModuleKind) => {}
- Some(_) => duplicate_type = TypeError
- }
- Some(TypeNS)
- }
- ForbidDuplicateValues => {
- if child.defined_in_namespace(ValueNS) {
- duplicate_type = ValueError;
- }
- Some(ValueNS)
- }
- ForbidDuplicateTypesAndValues => {
- let mut n = None;
- match child.def_for_namespace(TypeNS) {
- Some(DefMod(_)) | None => {}
- Some(_) => {
- n = Some(TypeNS);
- duplicate_type = TypeError;
- }
- };
- if child.defined_in_namespace(ValueNS) {
- duplicate_type = ValueError;
- n = Some(ValueNS);
- }
- n
- }
- OverwriteDuplicates => None
- };
- if duplicate_type != NoError {
- // Return an error here by looking up the namespace that
- // had the duplicate.
- let ns = ns.unwrap();
- self.resolve_error(sp,
- format!("duplicate definition of {} `{}`",
- namespace_error_to_string(duplicate_type),
- token::get_name(name)).as_slice());
- {
- let r = child.span_for_namespace(ns);
- for sp in r.iter() {
- self.session.span_note(*sp,
- format!("first definition of {} `{}` here",
- namespace_error_to_string(duplicate_type),
- token::get_name(name)).as_slice());
- }
- }
- }
- child
- }
- }
- }
-
- fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
- // If the block has view items, we need an anonymous module.
- if block.view_items.len() > 0 {
- return true;
- }
-
- // Check each statement.
- for statement in block.stmts.iter() {
- match statement.node {
- StmtDecl(ref declaration, _) => {
- match declaration.node {
- DeclItem(_) => {
- return true;
- }
- _ => {
- // Keep searching.
- }
- }
- }
- _ => {
- // Keep searching.
- }
- }
- }
-
- // If we found neither view items nor items, we don't need to create
- // an anonymous module.
-
- return false;
- }
-
- fn get_parent_link(&mut self, parent: ReducedGraphParent, name: Name)
- -> ParentLink {
- match parent {
- ModuleReducedGraphParent(module_) => {
- return ModuleParentLink(module_.downgrade(), name);
- }
- }
- }
-
- /// Constructs the reduced graph for one item.
- fn build_reduced_graph_for_item(&mut self,
- item: &Item,
- parent: ReducedGraphParent)
- -> ReducedGraphParent
- {
- let name = item.ident.name;
- let sp = item.span;
- let is_public = item.vis == ast::Public;
- let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
-
- match item.node {
- ItemMod(..) => {
- let name_bindings =
- self.add_child(name, parent.clone(), ForbidDuplicateModules, sp);
-
- let parent_link = self.get_parent_link(parent, name);
- let def_id = DefId { krate: 0, node: item.id };
- name_bindings.define_module(parent_link,
- Some(def_id),
- NormalModuleKind,
- false,
- item.vis == ast::Public,
- sp);
-
- ModuleReducedGraphParent(name_bindings.get_module())
- }
-
- ItemForeignMod(..) => parent,
-
- // These items live in the value namespace.
- ItemStatic(_, m, _) => {
- let name_bindings =
- self.add_child(name, parent.clone(), ForbidDuplicateValues, sp);
- let mutbl = m == ast::MutMutable;
-
- name_bindings.define_value
- (DefStatic(local_def(item.id), mutbl), sp, modifiers);
- parent
- }
- ItemConst(_, _) => {
- self.add_child(name, parent.clone(), ForbidDuplicateValues, sp)
- .define_value(DefConst(local_def(item.id)),
- sp, modifiers);
- parent
- }
- ItemFn(_, _, _, _, _) => {
- let name_bindings =
- self.add_child(name, parent.clone(), ForbidDuplicateValues, sp);
-
- let def = DefFn(local_def(item.id), false);
- name_bindings.define_value(def, sp, modifiers);
- parent
- }
-
- // These items live in the type namespace.
- ItemTy(..) => {
- let name_bindings =
- self.add_child(name,
- parent.clone(),
- ForbidDuplicateTypesAndModules,
- sp);
-
- name_bindings.define_type
- (DefTy(local_def(item.id), false), sp, modifiers);
- parent
- }
-
- ItemEnum(ref enum_definition, _) => {
- let name_bindings =
- self.add_child(name,
- parent.clone(),
- ForbidDuplicateTypesAndModules,
- sp);
-
- name_bindings.define_type
- (DefTy(local_def(item.id), true), sp, modifiers);
-
- let parent_link = self.get_parent_link(parent.clone(), name);
- // We want to make sure the module type is EnumModuleKind
- // even if there's already an ImplModuleKind module defined,
- // since that's how we prevent duplicate enum definitions
- name_bindings.set_module_kind(parent_link,
- Some(local_def(item.id)),
- EnumModuleKind,
- false,
- is_public,
- sp);
-
- for variant in (*enum_definition).variants.iter() {
- self.build_reduced_graph_for_variant(
- &**variant,
- local_def(item.id),
- ModuleReducedGraphParent(name_bindings.get_module()));
- }
- parent
- }
-
- // These items live in both the type and value namespaces.
- ItemStruct(ref struct_def, _) => {
- // Adding to both Type and Value namespaces or just Type?
- let (forbid, ctor_id) = match struct_def.ctor_id {
- Some(ctor_id) => (ForbidDuplicateTypesAndValues, Some(ctor_id)),
- None => (ForbidDuplicateTypesAndModules, None)
- };
-
- let name_bindings = self.add_child(name, parent.clone(), forbid, sp);
-
- // Define a name in the type namespace.
- name_bindings.define_type(DefTy(local_def(item.id), false), sp, modifiers);
-
- // If this is a newtype or unit-like struct, define a name
- // in the value namespace as well
- match ctor_id {
- Some(cid) => {
- name_bindings.define_value(DefStruct(local_def(cid)),
- sp, modifiers);
- }
- None => {}
- }
-
- // Record the def ID and fields of this struct.
- let named_fields = struct_def.fields.iter().filter_map(|f| {
- match f.node.kind {
- NamedField(ident, _) => Some(ident.name),
- UnnamedField(_) => None
- }
- }).collect();
- self.structs.insert(local_def(item.id), named_fields);
-
- parent
- }
-
- ItemImpl(_, _, None, ref ty, ref impl_items) => {
- // If this implements an anonymous trait, then add all the
- // methods within to a new module, if the type was defined
- // within this module.
-
- let mod_name = match ty.node {
- TyPath(ref path, _) if path.segments.len() == 1 => {
- // FIXME(18446) we should distinguish between the name of
- // a trait and the name of an impl of that trait.
- Some(path.segments.last().unwrap().identifier.name)
- }
- TyObjectSum(ref lhs_ty, _) => {
- match lhs_ty.node {
- TyPath(ref path, _) if path.segments.len() == 1 => {
- Some(path.segments.last().unwrap().identifier.name)
- }
- _ => {
- None
- }
- }
- }
- _ => {
- None
- }
- };
-
- match mod_name {
- None => {
- self.resolve_error(ty.span,
- "inherent implementations may \
- only be implemented in the same \
- module as the type they are \
- implemented for")
- }
- Some(mod_name) => {
- // Create the module and add all methods.
- let parent_opt = parent.module().children.borrow()
- .get(&mod_name).cloned();
- let new_parent = match parent_opt {
- // It already exists
- Some(ref child) if child.get_module_if_available()
- .is_some() &&
- (child.get_module().kind.get() == ImplModuleKind ||
- child.get_module().kind.get() == TraitModuleKind) => {
- ModuleReducedGraphParent(child.get_module())
- }
- Some(ref child) if child.get_module_if_available()
- .is_some() &&
- child.get_module().kind.get() ==
- EnumModuleKind => {
- ModuleReducedGraphParent(child.get_module())
- }
- // Create the module
- _ => {
- let name_bindings =
- self.add_child(mod_name,
- parent.clone(),
- ForbidDuplicateModules,
- sp);
-
- let parent_link =
- self.get_parent_link(parent.clone(), name);
- let def_id = local_def(item.id);
- let ns = TypeNS;
- let is_public =
- !name_bindings.defined_in_namespace(ns) ||
- name_bindings.defined_in_public_namespace(ns);
-
- name_bindings.define_module(parent_link,
- Some(def_id),
- ImplModuleKind,
- false,
- is_public,
- sp);
-
- ModuleReducedGraphParent(
- name_bindings.get_module())
- }
- };
-
- // For each implementation item...
- for impl_item in impl_items.iter() {
- match *impl_item {
- MethodImplItem(ref method) => {
- // Add the method to the module.
- let name = method.pe_ident().name;
- let method_name_bindings =
- self.add_child(name,
- new_parent.clone(),
- ForbidDuplicateValues,
- method.span);
- let def = match method.pe_explicit_self()
- .node {
- SelfStatic => {
- // Static methods become
- // `DefStaticMethod`s.
- DefStaticMethod(local_def(method.id),
- FromImpl(local_def(item.id)))
- }
- _ => {
- // Non-static methods become
- // `DefMethod`s.
- DefMethod(local_def(method.id),
- None,
- FromImpl(local_def(item.id)))
- }
- };
-
- // NB: not IMPORTABLE
- let modifiers = if method.pe_vis() == ast::Public {
- PUBLIC
- } else {
- DefModifiers::empty()
- };
- method_name_bindings.define_value(
- def,
- method.span,
- modifiers);
- }
- TypeImplItem(ref typedef) => {
- // Add the typedef to the module.
- let name = typedef.ident.name;
- let typedef_name_bindings =
- self.add_child(
- name,
- new_parent.clone(),
- ForbidDuplicateTypesAndModules,
- typedef.span);
- let def = DefAssociatedTy(local_def(
- typedef.id));
- // NB: not IMPORTABLE
- let modifiers = if typedef.vis == ast::Public {
- PUBLIC
- } else {
- DefModifiers::empty()
- };
- typedef_name_bindings.define_type(
- def,
- typedef.span,
- modifiers);
- }
- }
- }
- }
- }
-
- parent
- }
-
- ItemImpl(_, _, Some(_), _, _) => parent,
-
- ItemTrait(_, _, _, _, ref items) => {
- let name_bindings =
- self.add_child(name,
- parent.clone(),
- ForbidDuplicateTypesAndModules,
- sp);
-
- // Add all the items within to a new module.
- let parent_link = self.get_parent_link(parent.clone(), name);
- name_bindings.define_module(parent_link,
- Some(local_def(item.id)),
- TraitModuleKind,
- false,
- item.vis == ast::Public,
- sp);
- let module_parent = ModuleReducedGraphParent(name_bindings.
- get_module());
-
- let def_id = local_def(item.id);
-
- // Add the names of all the items to the trait info.
- for trait_item in items.iter() {
- let (name, kind) = match *trait_item {
- ast::RequiredMethod(_) |
- ast::ProvidedMethod(_) => {
- let ty_m = ast_util::trait_item_to_ty_method(trait_item);
-
- let name = ty_m.ident.name;
-
- // Add it as a name in the trait module.
- let (def, static_flag) = match ty_m.explicit_self
- .node {
- SelfStatic => {
- // Static methods become `DefStaticMethod`s.
- (DefStaticMethod(
- local_def(ty_m.id),
- FromTrait(local_def(item.id))),
- StaticMethodTraitItemKind)
- }
- _ => {
- // Non-static methods become `DefMethod`s.
- (DefMethod(local_def(ty_m.id),
- Some(local_def(item.id)),
- FromTrait(local_def(item.id))),
- NonstaticMethodTraitItemKind)
- }
- };
-
- let method_name_bindings =
- self.add_child(name,
- module_parent.clone(),
- ForbidDuplicateTypesAndValues,
- ty_m.span);
- // NB: not IMPORTABLE
- method_name_bindings.define_value(def,
- ty_m.span,
- PUBLIC);
-
- (name, static_flag)
- }
- ast::TypeTraitItem(ref associated_type) => {
- let def = DefAssociatedTy(local_def(
- associated_type.ty_param.id));
-
- let name_bindings =
- self.add_child(associated_type.ty_param.ident.name,
- module_parent.clone(),
- ForbidDuplicateTypesAndValues,
- associated_type.ty_param.span);
- // NB: not IMPORTABLE
- name_bindings.define_type(def,
- associated_type.ty_param.span,
- PUBLIC);
-
- (associated_type.ty_param.ident.name, TypeTraitItemKind)
- }
- };
-
- self.trait_item_map.insert((name, def_id), kind);
- }
-
- name_bindings.define_type(DefTrait(def_id), sp, modifiers);
- parent
- }
- ItemMac(..) => parent
- }
- }
-
- // Constructs the reduced graph for one variant. Variants exist in the
- // type and value namespaces.
- fn build_reduced_graph_for_variant(&mut self,
- variant: &Variant,
- item_id: DefId,
- parent: ReducedGraphParent) {
- let name = variant.node.name.name;
- let is_exported = match variant.node.kind {
- TupleVariantKind(_) => false,
- StructVariantKind(_) => {
- // Not adding fields for variants as they are not accessed with a self receiver
- self.structs.insert(local_def(variant.node.id), Vec::new());
- true
- }
- };
-
- let child = self.add_child(name, parent,
- ForbidDuplicateTypesAndValues,
- variant.span);
- // variants are always treated as importable to allow them to be glob
- // used
- child.define_value(DefVariant(item_id,
- local_def(variant.node.id), is_exported),
- variant.span, PUBLIC | IMPORTABLE);
- child.define_type(DefVariant(item_id,
- local_def(variant.node.id), is_exported),
- variant.span, PUBLIC | IMPORTABLE);
- }
-
- /// Constructs the reduced graph for one 'view item'. View items consist
- /// of imports and use directives.
- fn build_reduced_graph_for_view_item(&mut self, view_item: &ViewItem,
- parent: ReducedGraphParent) {
- match view_item.node {
- ViewItemUse(ref view_path) => {
- // Extract and intern the module part of the path. For
- // globs and lists, the path is found directly in the AST;
- // for simple paths we have to munge the path a little.
- let module_path = match view_path.node {
- ViewPathSimple(_, ref full_path, _) => {
- full_path.segments
- .init()
- .iter().map(|ident| ident.identifier.name)
- .collect()
- }
-
- ViewPathGlob(ref module_ident_path, _) |
- ViewPathList(ref module_ident_path, _, _) => {
- module_ident_path.segments
- .iter().map(|ident| ident.identifier.name).collect()
- }
- };
-
- // Build up the import directives.
- let module_ = parent.module();
- let is_public = view_item.vis == ast::Public;
- let shadowable =
- view_item.attrs
- .iter()
- .any(|attr| {
- attr.name() == token::get_name(
- special_idents::prelude_import.name)
- });
-
- match view_path.node {
- ViewPathSimple(binding, ref full_path, id) => {
- let source_name =
- full_path.segments.last().unwrap().identifier.name;
- if token::get_name(source_name).get() == "mod" {
- self.resolve_error(view_path.span,
- "`mod` imports are only allowed within a { } list");
- }
-
- let subclass = SingleImport(binding.name,
- source_name);
- self.build_import_directive(&*module_,
- module_path,
- subclass,
- view_path.span,
- id,
- is_public,
- shadowable);
- }
- ViewPathList(_, ref source_items, _) => {
- // Make sure there's at most one `mod` import in the list.
- let mod_spans = source_items.iter().filter_map(|item| match item.node {
- PathListMod { .. } => Some(item.span),
- _ => None
- }).collect::<Vec<Span>>();
- if mod_spans.len() > 1 {
- self.resolve_error(mod_spans[0],
- "`mod` import can only appear once in the list");
- for other_span in mod_spans.iter().skip(1) {
- self.session.span_note(*other_span,
- "another `mod` import appears here");
- }
- }
-
- for source_item in source_items.iter() {
- let (module_path, name) = match source_item.node {
- PathListIdent { name, .. } =>
- (module_path.clone(), name.name),
- PathListMod { .. } => {
- let name = match module_path.last() {
- Some(name) => *name,
- None => {
- self.resolve_error(source_item.span,
- "`mod` import can only appear in an import list \
- with a non-empty prefix");
- continue;
- }
- };
- let module_path = module_path.init();
- (module_path.to_vec(), name)
- }
- };
- self.build_import_directive(
- &*module_,
- module_path,
- SingleImport(name, name),
- source_item.span,
- source_item.node.id(),
- is_public,
- shadowable);
- }
- }
- ViewPathGlob(_, id) => {
- self.build_import_directive(&*module_,
- module_path,
- GlobImport,
- view_path.span,
- id,
- is_public,
- shadowable);
- }
- }
- }
-
- ViewItemExternCrate(name, _, node_id) => {
- // n.b. we don't need to look at the path option here, because cstore already did
- for &crate_id in self.session.cstore
- .find_extern_mod_stmt_cnum(node_id).iter() {
- let def_id = DefId { krate: crate_id, node: 0 };
- self.external_exports.insert(def_id);
- let parent_link =
- ModuleParentLink(parent.module().downgrade(), name.name);
- let external_module = Rc::new(Module::new(parent_link,
- Some(def_id),
- NormalModuleKind,
- false,
- true));
- debug!("(build reduced graph for item) found extern `{}`",
- self.module_to_string(&*external_module));
- self.check_for_conflicts_between_external_crates(
- &*parent.module(),
- name.name,
- view_item.span);
- parent.module().external_module_children.borrow_mut()
- .insert(name.name, external_module.clone());
- self.build_reduced_graph_for_external_crate(external_module);
- }
- }
- }
- }
-
- /// Constructs the reduced graph for one foreign item.
- fn build_reduced_graph_for_foreign_item<F>(&mut self,
- foreign_item: &ForeignItem,
- parent: ReducedGraphParent,
- f: F) where
- F: FnOnce(&mut Resolver),
- {
- let name = foreign_item.ident.name;
- let is_public = foreign_item.vis == ast::Public;
- let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
- let name_bindings =
- self.add_child(name, parent, ForbidDuplicateValues,
- foreign_item.span);
-
- match foreign_item.node {
- ForeignItemFn(_, ref generics) => {
- let def = DefFn(local_def(foreign_item.id), false);
- name_bindings.define_value(def, foreign_item.span, modifiers);
-
- self.with_type_parameter_rib(
- HasTypeParameters(generics,
- FnSpace,
- foreign_item.id,
- NormalRibKind),
- f);
- }
- ForeignItemStatic(_, m) => {
- let def = DefStatic(local_def(foreign_item.id), m);
- name_bindings.define_value(def, foreign_item.span, modifiers);
-
- f(self)
- }
- }
- }
-
- fn build_reduced_graph_for_block(&mut self,
- block: &Block,
- parent: ReducedGraphParent)
- -> ReducedGraphParent
- {
- if self.block_needs_anonymous_module(block) {
- let block_id = block.id;
-
- debug!("(building reduced graph for block) creating a new \
- anonymous module for block {}",
- block_id);
-
- let parent_module = parent.module();
- let new_module = Rc::new(Module::new(
- BlockParentLink(parent_module.downgrade(), block_id),
- None,
- AnonymousModuleKind,
- false,
- false));
- parent_module.anonymous_children.borrow_mut()
- .insert(block_id, new_module.clone());
- ModuleReducedGraphParent(new_module)
- } else {
- parent
- }
- }
-
- fn handle_external_def(&mut self,
- def: Def,
- vis: Visibility,
- child_name_bindings: &NameBindings,
- final_ident: &str,
- name: Name,
- new_parent: ReducedGraphParent) {
- debug!("(building reduced graph for \
- external crate) building external def, priv {}",
- vis);
- let is_public = vis == ast::Public;
- let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
- let is_exported = is_public && match new_parent {
- ModuleReducedGraphParent(ref module) => {
- match module.def_id.get() {
- None => true,
- Some(did) => self.external_exports.contains(&did)
- }
- }
- };
- if is_exported {
- self.external_exports.insert(def.def_id());
- }
-
- let kind = match def {
- DefTy(_, true) => EnumModuleKind,
- DefStruct(..) | DefTy(..) => ImplModuleKind,
- _ => NormalModuleKind
- };
-
- match def {
- DefMod(def_id) | DefForeignMod(def_id) | DefStruct(def_id) |
- DefTy(def_id, _) => {
- let type_def = child_name_bindings.type_def.borrow().clone();
- match type_def {
- Some(TypeNsDef { module_def: Some(module_def), .. }) => {
- debug!("(building reduced graph for external crate) \
- already created module");
- module_def.def_id.set(Some(def_id));
- }
- Some(_) | None => {
- debug!("(building reduced graph for \
- external crate) building module \
- {}", final_ident);
- let parent_link = self.get_parent_link(new_parent.clone(), name);
-
- child_name_bindings.define_module(parent_link,
- Some(def_id),
- kind,
- true,
- is_public,
- DUMMY_SP);
- }
- }
- }
- _ => {}
- }
-
- match def {
- DefMod(_) | DefForeignMod(_) => {}
- DefVariant(_, variant_id, is_struct) => {
- debug!("(building reduced graph for external crate) building \
- variant {}",
- final_ident);
- // variants are always treated as importable to allow them to be
- // glob used
- let modifiers = PUBLIC | IMPORTABLE;
- if is_struct {
- child_name_bindings.define_type(def, DUMMY_SP, modifiers);
- // Not adding fields for variants as they are not accessed with a self receiver
- self.structs.insert(variant_id, Vec::new());
- } else {
- child_name_bindings.define_value(def, DUMMY_SP, modifiers);
- }
- }
- DefFn(ctor_id, true) => {
- child_name_bindings.define_value(
- csearch::get_tuple_struct_definition_if_ctor(&self.session.cstore, ctor_id)
- .map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, modifiers);
- }
- DefFn(..) | DefStaticMethod(..) | DefStatic(..) | DefConst(..) | DefMethod(..) => {
- debug!("(building reduced graph for external \
- crate) building value (fn/static) {}", final_ident);
- // impl methods have already been defined with the correct importability modifier
- let mut modifiers = match *child_name_bindings.value_def.borrow() {
- Some(ref def) => (modifiers & !IMPORTABLE) | (def.modifiers & IMPORTABLE),
- None => modifiers
- };
- if new_parent.module().kind.get() != NormalModuleKind {
- modifiers = modifiers & !IMPORTABLE;
- }
- child_name_bindings.define_value(def, DUMMY_SP, modifiers);
- }
- DefTrait(def_id) => {
- debug!("(building reduced graph for external \
- crate) building type {}", final_ident);
-
- // If this is a trait, add all the trait item names to the trait
- // info.
-
- let trait_item_def_ids =
- csearch::get_trait_item_def_ids(&self.session.cstore, def_id);
- for trait_item_def_id in trait_item_def_ids.iter() {
- let (trait_item_name, trait_item_kind) =
- csearch::get_trait_item_name_and_kind(
- &self.session.cstore,
- trait_item_def_id.def_id());
-
- debug!("(building reduced graph for external crate) ... \
- adding trait item '{}'",
- token::get_name(trait_item_name));
-
- self.trait_item_map.insert((trait_item_name, def_id), trait_item_kind);
-
- if is_exported {
- self.external_exports
- .insert(trait_item_def_id.def_id());
- }
- }
-
- child_name_bindings.define_type(def, DUMMY_SP, modifiers);
-
- // Define a module if necessary.
- let parent_link = self.get_parent_link(new_parent, name);
- child_name_bindings.set_module_kind(parent_link,
- Some(def_id),
- TraitModuleKind,
- true,
- is_public,
- DUMMY_SP)
- }
- DefTy(..) | DefAssociatedTy(..) | DefAssociatedPath(..) => {
- debug!("(building reduced graph for external \
- crate) building type {}", final_ident);
-
- child_name_bindings.define_type(def, DUMMY_SP, modifiers);
- }
- DefStruct(def_id) => {
- debug!("(building reduced graph for external \
- crate) building type and value for {}",
- final_ident);
- child_name_bindings.define_type(def, DUMMY_SP, modifiers);
- let fields = csearch::get_struct_fields(&self.session.cstore, def_id).iter().map(|f| {
- f.name
- }).collect::<Vec<_>>();
-
- if fields.len() == 0 {
- child_name_bindings.define_value(def, DUMMY_SP, modifiers);
- }
-
- // Record the def ID and fields of this struct.
- self.structs.insert(def_id, fields);
- }
- DefLocal(..) | DefPrimTy(..) | DefTyParam(..) |
- DefUse(..) | DefUpvar(..) | DefRegion(..) |
- DefTyParamBinder(..) | DefLabel(..) | DefSelfTy(..) => {
- panic!("didn't expect `{}`", def);
- }
- }
- }
-
- /// Builds the reduced graph for a single item in an external crate.
- fn build_reduced_graph_for_external_crate_def(&mut self,
- root: Rc<Module>,
- def_like: DefLike,
- name: Name,
- visibility: Visibility) {
- match def_like {
- DlDef(def) => {
- // Add the new child item, if necessary.
- match def {
- DefForeignMod(def_id) => {
- // Foreign modules have no names. Recur and populate
- // eagerly.
- csearch::each_child_of_item(&self.session.cstore,
- def_id,
- |def_like,
- child_name,
- vis| {
- self.build_reduced_graph_for_external_crate_def(
- root.clone(),
- def_like,
- child_name,
- vis)
- });
- }
- _ => {
- let child_name_bindings =
- self.add_child(name,
- ModuleReducedGraphParent(root.clone()),
- OverwriteDuplicates,
- DUMMY_SP);
-
- self.handle_external_def(def,
- visibility,
- &*child_name_bindings,
- token::get_name(name).get(),
- name,
- ModuleReducedGraphParent(root));
- }
- }
- }
- DlImpl(def) => {
- match csearch::get_type_name_if_impl(&self.session.cstore, def) {
- None => {}
- Some(final_name) => {
- let methods_opt =
- csearch::get_methods_if_impl(&self.session.cstore, def);
- match methods_opt {
- Some(ref methods) if
- methods.len() >= 1 => {
- debug!("(building reduced graph for \
- external crate) processing \
- static methods for type name {}",
- token::get_name(final_name));
-
- let child_name_bindings =
- self.add_child(
- final_name,
- ModuleReducedGraphParent(root.clone()),
- OverwriteDuplicates,
- DUMMY_SP);
-
- // Process the static methods. First,
- // create the module.
- let type_module;
- let type_def = child_name_bindings.type_def.borrow().clone();
- match type_def {
- Some(TypeNsDef {
- module_def: Some(module_def),
- ..
- }) => {
- // We already have a module. This
- // is OK.
- type_module = module_def;
-
- // Mark it as an impl module if
- // necessary.
- type_module.kind.set(ImplModuleKind);
- }
- Some(_) | None => {
- let parent_link =
- self.get_parent_link(ModuleReducedGraphParent(root),
- final_name);
- child_name_bindings.define_module(
- parent_link,
- Some(def),
- ImplModuleKind,
- true,
- true,
- DUMMY_SP);
- type_module =
- child_name_bindings.
- get_module();
- }
- }
-
- // Add each static method to the module.
- let new_parent =
- ModuleReducedGraphParent(type_module);
- for method_info in methods.iter() {
- let name = method_info.name;
- debug!("(building reduced graph for \
- external crate) creating \
- static method '{}'",
- token::get_name(name));
-
- let method_name_bindings =
- self.add_child(name,
- new_parent.clone(),
- OverwriteDuplicates,
- DUMMY_SP);
- let def = DefFn(method_info.def_id, false);
-
- // NB: not IMPORTABLE
- let modifiers = if visibility == ast::Public {
- PUBLIC
- } else {
- DefModifiers::empty()
- };
- method_name_bindings.define_value(
- def, DUMMY_SP, modifiers);
- }
- }
-
- // Otherwise, do nothing.
- Some(_) | None => {}
- }
- }
- }
- }
- DlField => {
- debug!("(building reduced graph for external crate) \
- ignoring field");
- }
- }
- }
-
- /// Builds the reduced graph rooted at the given external module.
- fn populate_external_module(&mut self, module: Rc<Module>) {
- debug!("(populating external module) attempting to populate {}",
- self.module_to_string(&*module));
-
- let def_id = match module.def_id.get() {
- None => {
- debug!("(populating external module) ... no def ID!");
- return
- }
- Some(def_id) => def_id,
- };
-
- csearch::each_child_of_item(&self.session.cstore,
- def_id,
- |def_like, child_name, visibility| {
- debug!("(populating external module) ... found ident: {}",
- token::get_name(child_name));
- self.build_reduced_graph_for_external_crate_def(module.clone(),
- def_like,
- child_name,
- visibility)
- });
- module.populated.set(true)
- }
-
- /// Ensures that the reduced graph rooted at the given external module
- /// is built, building it if it is not.
- fn populate_module_if_necessary(&mut self, module: &Rc<Module>) {
- if !module.populated.get() {
- self.populate_external_module(module.clone())
- }
- assert!(module.populated.get())
- }
-
- /// Builds the reduced graph rooted at the 'use' directive for an external
- /// crate.
- fn build_reduced_graph_for_external_crate(&mut self, root: Rc<Module>) {
- csearch::each_top_level_item_of_crate(&self.session.cstore,
- root.def_id
- .get()
- .unwrap()
- .krate,
- |def_like, name, visibility| {
- self.build_reduced_graph_for_external_crate_def(root.clone(),
- def_like,
- name,
- visibility)
- });
- }
-
- /// Creates and adds an import directive to the given module.
- fn build_import_directive(&mut self,
- module_: &Module,
- module_path: Vec<Name>,
- subclass: ImportDirectiveSubclass,
- span: Span,
- id: NodeId,
- is_public: bool,
- shadowable: bool) {
- module_.imports.borrow_mut().push(ImportDirective::new(module_path,
- subclass,
- span,
- id,
- is_public,
- shadowable));
- self.unresolved_imports += 1;
- // Bump the reference count on the name. Or, if this is a glob, set
- // the appropriate flag.
-
- match subclass {
- SingleImport(target, _) => {
- debug!("(building import directive) building import \
- directive: {}::{}",
- self.names_to_string(module_.imports.borrow().last().unwrap()
- .module_path.as_slice()),
- token::get_name(target));
-
- let mut import_resolutions = module_.import_resolutions
- .borrow_mut();
- match import_resolutions.get_mut(&target) {
- Some(resolution) => {
- debug!("(building import directive) bumping \
- reference");
- resolution.outstanding_references += 1;
-
- // the source of this name is different now
- resolution.type_id = id;
- resolution.value_id = id;
- resolution.is_public = is_public;
- return;
- }
- None => {}
- }
- debug!("(building import directive) creating new");
- let mut resolution = ImportResolution::new(id, is_public);
- resolution.outstanding_references = 1;
- import_resolutions.insert(target, resolution);
- }
- GlobImport => {
- // Set the glob flag. This tells us that we don't know the
- // module's exports ahead of time.
-
- module_.glob_count.set(module_.glob_count.get() + 1);
- }
- }
- }
-
- // Import resolution
- //
- // This is a fixed-point algorithm. We resolve imports until our efforts
- // are stymied by an unresolved import; then we bail out of the current
- // module and continue. We terminate successfully once no more imports
- // remain or unsuccessfully when no forward progress in resolving imports
- // is made.
-
- /// Resolves all imports for the crate. This method performs the fixed-
- /// point iteration.
- fn resolve_imports(&mut self) {
- let mut i = 0u;
- let mut prev_unresolved_imports = 0;
- loop {
- debug!("(resolving imports) iteration {}, {} imports left",
- i, self.unresolved_imports);
-
- let module_root = self.graph_root.get_module();
- self.resolve_imports_for_module_subtree(module_root.clone());
-
- if self.unresolved_imports == 0 {
- debug!("(resolving imports) success");
- break;
- }
-
- if self.unresolved_imports == prev_unresolved_imports {
- self.report_unresolved_imports(module_root);
- break;
- }
-
- i += 1;
- prev_unresolved_imports = self.unresolved_imports;
- }
- }
-
- /// Attempts to resolve imports for the given module and all of its
- /// submodules.
- fn resolve_imports_for_module_subtree(&mut self, module_: Rc<Module>) {
- debug!("(resolving imports for module subtree) resolving {}",
- self.module_to_string(&*module_));
- let orig_module = replace(&mut self.current_module, module_.clone());
- self.resolve_imports_for_module(module_.clone());
- self.current_module = orig_module;
-
- self.populate_module_if_necessary(&module_);
- for (_, child_node) in module_.children.borrow().iter() {
- match child_node.get_module_if_available() {
- None => {
- // Nothing to do.
- }
- Some(child_module) => {
- self.resolve_imports_for_module_subtree(child_module);
- }
- }
- }
-
- for (_, child_module) in module_.anonymous_children.borrow().iter() {
- self.resolve_imports_for_module_subtree(child_module.clone());
- }
- }
-
- /// Attempts to resolve imports for the given module only.
- fn resolve_imports_for_module(&mut self, module: Rc<Module>) {
- if module.all_imports_resolved() {
- debug!("(resolving imports for module) all imports resolved for \
- {}",
- self.module_to_string(&*module));
- return;
- }
-
- let imports = module.imports.borrow();
- let import_count = imports.len();
- while module.resolved_import_count.get() < import_count {
- let import_index = module.resolved_import_count.get();
- let import_directive = &(*imports)[import_index];
- match self.resolve_import_for_module(module.clone(),
- import_directive) {
- Failed(err) => {
- let (span, help) = match err {
- Some((span, msg)) => (span, format!(". {}", msg)),
- None => (import_directive.span, String::new())
- };
- let msg = format!("unresolved import `{}`{}",
- self.import_path_to_string(
- import_directive.module_path
- .as_slice(),
- import_directive.subclass),
- help);
- self.resolve_error(span, msg.as_slice());
- }
- Indeterminate => break, // Bail out. We'll come around next time.
- Success(()) => () // Good. Continue.
- }
-
- module.resolved_import_count
- .set(module.resolved_import_count.get() + 1);
- }
- }
-
- fn names_to_string(&self, names: &[Name]) -> String {
- let mut first = true;
- let mut result = String::new();
- for name in names.iter() {
- if first {
- first = false
- } else {
- result.push_str("::")
- }
- result.push_str(token::get_name(*name).get());
- };
- result
- }
-
- fn path_names_to_string(&self, path: &Path) -> String {
- let names: Vec<ast::Name> = path.segments
- .iter()
- .map(|seg| seg.identifier.name)
- .collect();
- self.names_to_string(names.as_slice())
- }
-
- fn import_directive_subclass_to_string(&mut self,
- subclass: ImportDirectiveSubclass)
- -> String {
- match subclass {
- SingleImport(_, source) => {
- token::get_name(source).get().to_string()
- }
- GlobImport => "*".to_string()
- }
- }
-
- fn import_path_to_string(&mut self,
- names: &[Name],
- subclass: ImportDirectiveSubclass)
- -> String {
- if names.is_empty() {
- self.import_directive_subclass_to_string(subclass)
- } else {
- (format!("{}::{}",
- self.names_to_string(names),
- self.import_directive_subclass_to_string(
- subclass))).to_string()
- }
- }
-
- /// Attempts to resolve the given import. The return value indicates
- /// failure if we're certain the name does not exist, indeterminate if we
- /// don't know whether the name exists at the moment due to other
- /// currently-unresolved imports, or success if we know the name exists.
- /// If successful, the resolved bindings are written into the module.
- fn resolve_import_for_module(&mut self,
- module_: Rc<Module>,
- import_directive: &ImportDirective)
- -> ResolveResult<()> {
- let mut resolution_result = Failed(None);
- let module_path = &import_directive.module_path;
-
- debug!("(resolving import for module) resolving import `{}::...` in \
- `{}`",
- self.names_to_string(module_path.as_slice()),
- self.module_to_string(&*module_));
-
- // First, resolve the module path for the directive, if necessary.
- let container = if module_path.len() == 0 {
- // Use the crate root.
- Some((self.graph_root.get_module(), LastMod(AllPublic)))
- } else {
- match self.resolve_module_path(module_.clone(),
- module_path.as_slice(),
- DontUseLexicalScope,
- import_directive.span,
- ImportSearch) {
- Failed(err) => {
- resolution_result = Failed(err);
- None
- },
- Indeterminate => {
- resolution_result = Indeterminate;
- None
- }
- Success(container) => Some(container),
- }
- };
-
- match container {
- None => {}
- Some((containing_module, lp)) => {
- // We found the module that the target is contained
- // within. Attempt to resolve the import within it.
-
- match import_directive.subclass {
- SingleImport(target, source) => {
- resolution_result =
- self.resolve_single_import(&*module_,
- containing_module,
- target,
- source,
- import_directive,
- lp);
- }
- GlobImport => {
- resolution_result =
- self.resolve_glob_import(&*module_,
- containing_module,
- import_directive,
- lp);
- }
- }
- }
- }
-
- // Decrement the count of unresolved imports.
- match resolution_result {
- Success(()) => {
- assert!(self.unresolved_imports >= 1);
- self.unresolved_imports -= 1;
- }
- _ => {
- // Nothing to do here; just return the error.
- }
- }
-
- // Decrement the count of unresolved globs if necessary. But only if
- // the resolution result is indeterminate -- otherwise we'll stop
- // processing imports here. (See the loop in
- // resolve_imports_for_module.)
-
- if !resolution_result.indeterminate() {
- match import_directive.subclass {
- GlobImport => {
- assert!(module_.glob_count.get() >= 1);
- module_.glob_count.set(module_.glob_count.get() - 1);
- }
- SingleImport(..) => {
- // Ignore.
- }
- }
- }
-
- return resolution_result;
- }
-
- fn create_name_bindings_from_module(module: Rc<Module>) -> NameBindings {
- NameBindings {
- type_def: RefCell::new(Some(TypeNsDef {
- modifiers: IMPORTABLE,
- module_def: Some(module),
- type_def: None,
- type_span: None
- })),
- value_def: RefCell::new(None),
- }
- }
-
- fn resolve_single_import(&mut self,
- module_: &Module,
- containing_module: Rc<Module>,
- target: Name,
- source: Name,
- directive: &ImportDirective,
- lp: LastPrivate)
- -> ResolveResult<()> {
- debug!("(resolving single import) resolving `{}` = `{}::{}` from \
- `{}` id {}, last private {}",
- token::get_name(target),
- self.module_to_string(&*containing_module),
- token::get_name(source),
- self.module_to_string(module_),
- directive.id,
- lp);
-
- let lp = match lp {
- LastMod(lp) => lp,
- LastImport {..} => {
- self.session
- .span_bug(directive.span,
- "not expecting Import here, must be LastMod")
- }
- };
-
- // We need to resolve both namespaces for this to succeed.
- //
-
- let mut value_result = UnknownResult;
- let mut type_result = UnknownResult;
-
- // Search for direct children of the containing module.
- self.populate_module_if_necessary(&containing_module);
-
- match containing_module.children.borrow().get(&source) {
- None => {
- // Continue.
- }
- Some(ref child_name_bindings) => {
- if child_name_bindings.defined_in_namespace(ValueNS) {
- debug!("(resolving single import) found value binding");
- value_result = BoundResult(containing_module.clone(),
- (*child_name_bindings).clone());
- }
- if child_name_bindings.defined_in_namespace(TypeNS) {
- debug!("(resolving single import) found type binding");
- type_result = BoundResult(containing_module.clone(),
- (*child_name_bindings).clone());
- }
- }
- }
-
- // Unless we managed to find a result in both namespaces (unlikely),
- // search imports as well.
- let mut value_used_reexport = false;
- let mut type_used_reexport = false;
- match (value_result.clone(), type_result.clone()) {
- (BoundResult(..), BoundResult(..)) => {} // Continue.
- _ => {
- // If there is an unresolved glob at this point in the
- // containing module, bail out. We don't know enough to be
- // able to resolve this import.
-
- if containing_module.glob_count.get() > 0 {
- debug!("(resolving single import) unresolved glob; \
- bailing out");
- return Indeterminate;
- }
-
- // Now search the exported imports within the containing module.
- match containing_module.import_resolutions.borrow().get(&source) {
- None => {
- debug!("(resolving single import) no import");
- // The containing module definitely doesn't have an
- // exported import with the name in question. We can
- // therefore accurately report that the names are
- // unbound.
-
- if value_result.is_unknown() {
- value_result = UnboundResult;
- }
- if type_result.is_unknown() {
- type_result = UnboundResult;
- }
- }
- Some(import_resolution)
- if import_resolution.outstanding_references == 0 => {
-
- fn get_binding(this: &mut Resolver,
- import_resolution: &ImportResolution,
- namespace: Namespace)
- -> NamespaceResult {
-
- // Import resolutions must be declared with "pub"
- // in order to be exported.
- if !import_resolution.is_public {
- return UnboundResult;
- }
-
- match import_resolution.
- target_for_namespace(namespace) {
- None => {
- return UnboundResult;
- }
- Some(Target {
- target_module,
- bindings,
- shadowable: _
- }) => {
- debug!("(resolving single import) found \
- import in ns {}", namespace);
- let id = import_resolution.id(namespace);
- // track used imports and extern crates as well
- this.used_imports.insert((id, namespace));
- match target_module.def_id.get() {
- Some(DefId{krate: kid, ..}) => {
- this.used_crates.insert(kid);
- },
- _ => {}
- }
- return BoundResult(target_module, bindings);
- }
- }
- }
-
- // The name is an import which has been fully
- // resolved. We can, therefore, just follow it.
- if value_result.is_unknown() {
- value_result = get_binding(self, import_resolution,
- ValueNS);
- value_used_reexport = import_resolution.is_public;
- }
- if type_result.is_unknown() {
- type_result = get_binding(self, import_resolution,
- TypeNS);
- type_used_reexport = import_resolution.is_public;
- }
-
- }
- Some(_) => {
- // If containing_module is the same module whose import we are resolving
- // and there it has an unresolved import with the same name as `source`,
- // then the user is actually trying to import an item that is declared
- // in the same scope
- //
- // e.g
- // use self::submodule;
- // pub mod submodule;
- //
- // In this case we continue as if we resolved the import and let the
- // check_for_conflicts_between_imports_and_items call below handle
- // the conflict
- match (module_.def_id.get(), containing_module.def_id.get()) {
- (Some(id1), Some(id2)) if id1 == id2 => {
- if value_result.is_unknown() {
- value_result = UnboundResult;
- }
- if type_result.is_unknown() {
- type_result = UnboundResult;
- }
- }
- _ => {
- // The import is unresolved. Bail out.
- debug!("(resolving single import) unresolved import; \
- bailing out");
- return Indeterminate;
- }
- }
- }
- }
- }
- }
-
- // If we didn't find a result in the type namespace, search the
- // external modules.
- let mut value_used_public = false;
- let mut type_used_public = false;
- match type_result {
- BoundResult(..) => {}
- _ => {
- match containing_module.external_module_children.borrow_mut()
- .get(&source).cloned() {
- None => {} // Continue.
- Some(module) => {
- debug!("(resolving single import) found external \
- module");
- // track the module as used.
- match module.def_id.get() {
- Some(DefId{krate: kid, ..}) => { self.used_crates.insert(kid); },
- _ => {}
- }
- let name_bindings =
- Rc::new(Resolver::create_name_bindings_from_module(
- module));
- type_result = BoundResult(containing_module.clone(),
- name_bindings);
- type_used_public = true;
- }
- }
- }
- }
-
- // We've successfully resolved the import. Write the results in.
- let mut import_resolutions = module_.import_resolutions.borrow_mut();
- let import_resolution = &mut (*import_resolutions)[target];
-
- match value_result {
- BoundResult(ref target_module, ref name_bindings) => {
- debug!("(resolving single import) found value target: {}",
- { name_bindings.value_def.borrow().clone().unwrap().def });
- self.check_for_conflicting_import(
- &import_resolution.value_target,
- directive.span,
- target,
- ValueNS);
-
- self.check_that_import_is_importable(
- &**name_bindings,
- directive.span,
- target,
- ValueNS);
-
- import_resolution.value_target =
- Some(Target::new(target_module.clone(),
- name_bindings.clone(),
- directive.shadowable));
- import_resolution.value_id = directive.id;
- import_resolution.is_public = directive.is_public;
- value_used_public = name_bindings.defined_in_public_namespace(ValueNS);
- }
- UnboundResult => { /* Continue. */ }
- UnknownResult => {
- panic!("value result should be known at this point");
- }
- }
- match type_result {
- BoundResult(ref target_module, ref name_bindings) => {
- debug!("(resolving single import) found type target: {}",
- { name_bindings.type_def.borrow().clone().unwrap().type_def });
- self.check_for_conflicting_import(
- &import_resolution.type_target,
- directive.span,
- target,
- TypeNS);
-
- self.check_that_import_is_importable(
- &**name_bindings,
- directive.span,
- target,
- TypeNS);
-
- import_resolution.type_target =
- Some(Target::new(target_module.clone(),
- name_bindings.clone(),
- directive.shadowable));
- import_resolution.type_id = directive.id;
- import_resolution.is_public = directive.is_public;
- type_used_public = name_bindings.defined_in_public_namespace(TypeNS);
- }
- UnboundResult => { /* Continue. */ }
- UnknownResult => {
- panic!("type result should be known at this point");
- }
- }
-
- self.check_for_conflicts_between_imports_and_items(
- module_,
- import_resolution,
- directive.span,
- target);
-
- if value_result.is_unbound() && type_result.is_unbound() {
- let msg = format!("There is no `{}` in `{}`",
- token::get_name(source),
- self.module_to_string(&*containing_module));
- return Failed(Some((directive.span, msg)));
- }
- let value_used_public = value_used_reexport || value_used_public;
- let type_used_public = type_used_reexport || type_used_public;
-
- assert!(import_resolution.outstanding_references >= 1);
- import_resolution.outstanding_references -= 1;
-
- // record what this import resolves to for later uses in documentation,
- // this may resolve to either a value or a type, but for documentation
- // purposes it's good enough to just favor one over the other.
- let value_private = match import_resolution.value_target {
- Some(ref target) => {
- let def = target.bindings.def_for_namespace(ValueNS).unwrap();
- self.def_map.borrow_mut().insert(directive.id, def);
- let did = def.def_id();
- if value_used_public {Some(lp)} else {Some(DependsOn(did))}
- },
- // AllPublic here and below is a dummy value, it should never be used because
- // _exists is false.
- None => None,
- };
- let type_private = match import_resolution.type_target {
- Some(ref target) => {
- let def = target.bindings.def_for_namespace(TypeNS).unwrap();
- self.def_map.borrow_mut().insert(directive.id, def);
- let did = def.def_id();
- if type_used_public {Some(lp)} else {Some(DependsOn(did))}
- },
- None => None,
- };
-
- self.last_private.insert(directive.id, LastImport{value_priv: value_private,
- value_used: Used,
- type_priv: type_private,
- type_used: Used});
-
- debug!("(resolving single import) successfully resolved import");
- return Success(());
- }
-
- // Resolves a glob import. Note that this function cannot panic; it either
- // succeeds or bails out (as importing * from an empty module or a module
- // that exports nothing is valid).
- fn resolve_glob_import(&mut self,
- module_: &Module,
- containing_module: Rc<Module>,
- import_directive: &ImportDirective,
- lp: LastPrivate)
- -> ResolveResult<()> {
- let id = import_directive.id;
- let is_public = import_directive.is_public;
-
- // This function works in a highly imperative manner; it eagerly adds
- // everything it can to the list of import resolutions of the module
- // node.
- debug!("(resolving glob import) resolving glob import {}", id);
-
- // We must bail out if the node has unresolved imports of any kind
- // (including globs).
- if !(*containing_module).all_imports_resolved() {
- debug!("(resolving glob import) target module has unresolved \
- imports; bailing out");
- return Indeterminate;
- }
-
- assert_eq!(containing_module.glob_count.get(), 0);
-
- // Add all resolved imports from the containing module.
- let import_resolutions = containing_module.import_resolutions
- .borrow();
- for (ident, target_import_resolution) in import_resolutions.iter() {
- debug!("(resolving glob import) writing module resolution \
- {} into `{}`",
- target_import_resolution.type_target.is_none(),
- self.module_to_string(module_));
-
- if !target_import_resolution.is_public {
- debug!("(resolving glob import) nevermind, just kidding");
- continue
- }
-
- // Here we merge two import resolutions.
- let mut import_resolutions = module_.import_resolutions.borrow_mut();
- match import_resolutions.get_mut(ident) {
- Some(dest_import_resolution) => {
- // Merge the two import resolutions at a finer-grained
- // level.
-
- match target_import_resolution.value_target {
- None => {
- // Continue.
- }
- Some(ref value_target) => {
- dest_import_resolution.value_target =
- Some(value_target.clone());
- }
- }
- match target_import_resolution.type_target {
- None => {
- // Continue.
- }
- Some(ref type_target) => {
- dest_import_resolution.type_target =
- Some(type_target.clone());
- }
- }
- dest_import_resolution.is_public = is_public;
- continue;
- }
- None => {}
- }
-
- // Simple: just copy the old import resolution.
- let mut new_import_resolution = ImportResolution::new(id, is_public);
- new_import_resolution.value_target =
- target_import_resolution.value_target.clone();
- new_import_resolution.type_target =
- target_import_resolution.type_target.clone();
-
- import_resolutions.insert(*ident, new_import_resolution);
- }
-
- // Add all children from the containing module.
- self.populate_module_if_necessary(&containing_module);
-
- for (&name, name_bindings) in containing_module.children
- .borrow().iter() {
- self.merge_import_resolution(module_,
- containing_module.clone(),
- import_directive,
- name,
- name_bindings.clone());
-
- }
-
- // Add external module children from the containing module.
- for (&name, module) in containing_module.external_module_children
- .borrow().iter() {
- let name_bindings =
- Rc::new(Resolver::create_name_bindings_from_module(module.clone()));
- self.merge_import_resolution(module_,
- containing_module.clone(),
- import_directive,
- name,
- name_bindings);
- }
-
- // Record the destination of this import
- match containing_module.def_id.get() {
- Some(did) => {
- self.def_map.borrow_mut().insert(id, DefMod(did));
- self.last_private.insert(id, lp);
- }
- None => {}
- }
-
- debug!("(resolving glob import) successfully resolved import");
- return Success(());
- }
-
- fn merge_import_resolution(&mut self,
- module_: &Module,
- containing_module: Rc<Module>,
- import_directive: &ImportDirective,
- name: Name,
- name_bindings: Rc<NameBindings>) {
- let id = import_directive.id;
- let is_public = import_directive.is_public;
-
- let mut import_resolutions = module_.import_resolutions.borrow_mut();
- let dest_import_resolution = match import_resolutions.entry(name) {
- Occupied(entry) => entry.into_mut(),
- Vacant(entry) => {
- // Create a new import resolution from this child.
- entry.set(ImportResolution::new(id, is_public))
- }
- };
-
- debug!("(resolving glob import) writing resolution `{}` in `{}` \
- to `{}`",
- token::get_name(name).get().to_string(),
- self.module_to_string(&*containing_module),
- self.module_to_string(module_));
-
- // Merge the child item into the import resolution.
- if name_bindings.defined_in_namespace_with(ValueNS, IMPORTABLE | PUBLIC) {
- debug!("(resolving glob import) ... for value target");
- dest_import_resolution.value_target =
- Some(Target::new(containing_module.clone(),
- name_bindings.clone(),
- import_directive.shadowable));
- dest_import_resolution.value_id = id;
- }
- if name_bindings.defined_in_namespace_with(TypeNS, IMPORTABLE | PUBLIC) {
- debug!("(resolving glob import) ... for type target");
- dest_import_resolution.type_target =
- Some(Target::new(containing_module,
- name_bindings.clone(),
- import_directive.shadowable));
- dest_import_resolution.type_id = id;
- }
- dest_import_resolution.is_public = is_public;
-
- self.check_for_conflicts_between_imports_and_items(
- module_,
- dest_import_resolution,
- import_directive.span,
- name);
- }
-
- /// Checks that imported names and items don't have the same name.
- fn check_for_conflicting_import(&mut self,
- target: &Option<Target>,
- import_span: Span,
- name: Name,
- namespace: Namespace) {
- if self.session.features.borrow().import_shadowing {
- return
- }
-
- match *target {
- Some(ref target) if !target.shadowable => {
- let msg = format!("a {} named `{}` has already been imported \
- in this module",
- match namespace {
- TypeNS => "type",
- ValueNS => "value",
- },
- token::get_name(name).get());
- self.session.span_err(import_span, msg.as_slice());
- }
- Some(_) | None => {}
- }
- }
-
- /// Checks that an import is actually importable
- fn check_that_import_is_importable(&mut self,
- name_bindings: &NameBindings,
- import_span: Span,
- name: Name,
- namespace: Namespace) {
- if !name_bindings.defined_in_namespace_with(namespace, IMPORTABLE) {
- let msg = format!("`{}` is not directly importable",
- token::get_name(name));
- self.session.span_err(import_span, msg.as_slice());
- }
- }
-
- /// Checks that imported names and items don't have the same name.
- fn check_for_conflicts_between_imports_and_items(&mut self,
- module: &Module,
- import_resolution:
- &ImportResolution,
- import_span: Span,
- name: Name) {
- if self.session.features.borrow().import_shadowing {
- return
- }
-
- // First, check for conflicts between imports and `extern crate`s.
- if module.external_module_children
- .borrow()
- .contains_key(&name) {
- match import_resolution.type_target {
- Some(ref target) if !target.shadowable => {
- let msg = format!("import `{0}` conflicts with imported \
- crate in this module \
- (maybe you meant `use {0}::*`?)",
- token::get_name(name).get());
- self.session.span_err(import_span, msg.as_slice());
- }
- Some(_) | None => {}
- }
- }
-
- // Check for item conflicts.
- let children = module.children.borrow();
- let name_bindings = match children.get(&name) {
- None => {
- // There can't be any conflicts.
- return
- }
- Some(ref name_bindings) => (*name_bindings).clone(),
- };
-
- match import_resolution.value_target {
- Some(ref target) if !target.shadowable => {
- if let Some(ref value) = *name_bindings.value_def.borrow() {
- let msg = format!("import `{}` conflicts with value \
- in this module",
- token::get_name(name).get());
- self.session.span_err(import_span, msg.as_slice());
- if let Some(span) = value.value_span {
- self.session.span_note(span,
- "conflicting value here");
- }
- }
- }
- Some(_) | None => {}
- }
-
- match import_resolution.type_target {
- Some(ref target) if !target.shadowable => {
- if let Some(ref ty) = *name_bindings.type_def.borrow() {
- match ty.module_def {
- None => {
- let msg = format!("import `{}` conflicts with type in \
- this module",
- token::get_name(name).get());
- self.session.span_err(import_span, msg.as_slice());
- if let Some(span) = ty.type_span {
- self.session.span_note(span,
- "note conflicting type here")
- }
- }
- Some(ref module_def) => {
- match module_def.kind.get() {
- ImplModuleKind => {
- if let Some(span) = ty.type_span {
- let msg = format!("inherent implementations \
- are only allowed on types \
- defined in the current module");
- self.session.span_err(span, msg.as_slice());
- self.session.span_note(import_span,
- "import from other module here")
- }
- }
- _ => {
- let msg = format!("import `{}` conflicts with existing \
- submodule",
- token::get_name(name).get());
- self.session.span_err(import_span, msg.as_slice());
- if let Some(span) = ty.type_span {
- self.session.span_note(span,
- "note conflicting module here")
- }
- }
- }
- }
- }
- }
- }
- Some(_) | None => {}
- }
- }
-
- /// Checks that the names of external crates don't collide with other
- /// external crates.
- fn check_for_conflicts_between_external_crates(&self,
- module: &Module,
- name: Name,
- span: Span) {
- if self.session.features.borrow().import_shadowing {
- return
- }
-
- if module.external_module_children.borrow().contains_key(&name) {
- self.session
- .span_err(span,
- format!("an external crate named `{}` has already \
- been imported into this module",
- token::get_name(name).get()).as_slice());
- }
- }
-
- /// Checks that the names of items don't collide with external crates.
- fn check_for_conflicts_between_external_crates_and_items(&self,
- module: &Module,
- name: Name,
- span: Span) {
- if self.session.features.borrow().import_shadowing {
- return
- }
-
- if module.external_module_children.borrow().contains_key(&name) {
- self.session
- .span_err(span,
- format!("the name `{}` conflicts with an external \
- crate that has been imported into this \
- module",
- token::get_name(name).get()).as_slice());
- }
- }
-
- /// Resolves the given module path from the given root `module_`.
- fn resolve_module_path_from_root(&mut self,
- module_: Rc<Module>,
- module_path: &[Name],
- index: uint,
- span: Span,
- name_search_type: NameSearchType,
- lp: LastPrivate)
- -> ResolveResult<(Rc<Module>, LastPrivate)> {
- fn search_parent_externals(needle: Name, module: &Rc<Module>)
- -> Option<Rc<Module>> {
- module.external_module_children.borrow()
- .get(&needle).cloned()
- .map(|_| module.clone())
- .or_else(|| {
- match module.parent_link.clone() {
- ModuleParentLink(parent, _) => {
- search_parent_externals(needle,
- &parent.upgrade().unwrap())
- }
- _ => None
- }
- })
- }
-
- let mut search_module = module_;
- let mut index = index;
- let module_path_len = module_path.len();
- let mut closest_private = lp;
-
- // Resolve the module part of the path. This does not involve looking
- // upward though scope chains; we simply resolve names directly in
- // modules as we go.
- while index < module_path_len {
- let name = module_path[index];
- match self.resolve_name_in_module(search_module.clone(),
- name,
- TypeNS,
- name_search_type,
- false) {
- Failed(None) => {
- let segment_name = token::get_name(name);
- let module_name = self.module_to_string(&*search_module);
- let mut span = span;
- let msg = if "???" == module_name.as_slice() {
- span.hi = span.lo + Pos::from_uint(segment_name.get().len());
-
- match search_parent_externals(name,
- &self.current_module) {
- Some(module) => {
- let path_str = self.names_to_string(module_path);
- let target_mod_str = self.module_to_string(&*module);
- let current_mod_str =
- self.module_to_string(&*self.current_module);
-
- let prefix = if target_mod_str == current_mod_str {
- "self::".to_string()
- } else {
- format!("{}::", target_mod_str)
- };
-
- format!("Did you mean `{}{}`?", prefix, path_str)
- },
- None => format!("Maybe a missing `extern crate {}`?",
- segment_name),
- }
- } else {
- format!("Could not find `{}` in `{}`",
- segment_name,
- module_name)
- };
-
- return Failed(Some((span, msg)));
- }
- Failed(err) => return Failed(err),
- Indeterminate => {
- debug!("(resolving module path for import) module \
- resolution is indeterminate: {}",
- token::get_name(name));
- return Indeterminate;
- }
- Success((target, used_proxy)) => {
- // Check to see whether there are type bindings, and, if
- // so, whether there is a module within.
- match *target.bindings.type_def.borrow() {
- Some(ref type_def) => {
- match type_def.module_def {
- None => {
- let msg = format!("Not a module `{}`",
- token::get_name(name));
-
- return Failed(Some((span, msg)));
- }
- Some(ref module_def) => {
- search_module = module_def.clone();
-
- // track extern crates for unused_extern_crate lint
- if let Some(did) = module_def.def_id.get() {
- self.used_crates.insert(did.krate);
- }
-
- // Keep track of the closest
- // private module used when
- // resolving this import chain.
- if !used_proxy && !search_module.is_public {
- if let Some(did) = search_module.def_id.get() {
- closest_private = LastMod(DependsOn(did));
- }
- }
- }
- }
- }
- None => {
- // There are no type bindings at all.
- let msg = format!("Not a module `{}`",
- token::get_name(name));
- return Failed(Some((span, msg)));
- }
- }
- }
- }
-
- index += 1;
- }
-
- return Success((search_module, closest_private));
- }
-
- /// Attempts to resolve the module part of an import directive or path
- /// rooted at the given module.
- ///
- /// On success, returns the resolved module, and the closest *private*
- /// module found to the destination when resolving this path.
- fn resolve_module_path(&mut self,
- module_: Rc<Module>,
- module_path: &[Name],
- use_lexical_scope: UseLexicalScopeFlag,
- span: Span,
- name_search_type: NameSearchType)
- -> ResolveResult<(Rc<Module>, LastPrivate)> {
- let module_path_len = module_path.len();
- assert!(module_path_len > 0);
-
- debug!("(resolving module path for import) processing `{}` rooted at `{}`",
- self.names_to_string(module_path),
- self.module_to_string(&*module_));
-
- // Resolve the module prefix, if any.
- let module_prefix_result = self.resolve_module_prefix(module_.clone(),
- module_path);
-
- let search_module;
- let start_index;
- let last_private;
- match module_prefix_result {
- Failed(None) => {
- let mpath = self.names_to_string(module_path);
- let mpath = mpath.as_slice();
- match mpath.rfind(':') {
- Some(idx) => {
- let msg = format!("Could not find `{}` in `{}`",
- // idx +- 1 to account for the
- // colons on either side
- mpath.slice_from(idx + 1),
- mpath.slice_to(idx - 1));
- return Failed(Some((span, msg)));
- },
- None => {
- return Failed(None)
- }
- }
- }
- Failed(err) => return Failed(err),
- Indeterminate => {
- debug!("(resolving module path for import) indeterminate; \
- bailing");
- return Indeterminate;
- }
- Success(NoPrefixFound) => {
- // There was no prefix, so we're considering the first element
- // of the path. How we handle this depends on whether we were
- // instructed to use lexical scope or not.
- match use_lexical_scope {
- DontUseLexicalScope => {
- // This is a crate-relative path. We will start the
- // resolution process at index zero.
- search_module = self.graph_root.get_module();
- start_index = 0;
- last_private = LastMod(AllPublic);
- }
- UseLexicalScope => {
- // This is not a crate-relative path. We resolve the
- // first component of the path in the current lexical
- // scope and then proceed to resolve below that.
- match self.resolve_module_in_lexical_scope(module_,
- module_path[0]) {
- Failed(err) => return Failed(err),
- Indeterminate => {
- debug!("(resolving module path for import) \
- indeterminate; bailing");
- return Indeterminate;
- }
- Success(containing_module) => {
- search_module = containing_module;
- start_index = 1;
- last_private = LastMod(AllPublic);
- }
- }
- }
- }
- }
- Success(PrefixFound(ref containing_module, index)) => {
- search_module = containing_module.clone();
- start_index = index;
- last_private = LastMod(DependsOn(containing_module.def_id
- .get()
- .unwrap()));
- }
- }
-
- self.resolve_module_path_from_root(search_module,
- module_path,
- start_index,
- span,
- name_search_type,
- last_private)
- }
-
- /// Invariant: This must only be called during main resolution, not during
- /// import resolution.
- fn resolve_item_in_lexical_scope(&mut self,
- module_: Rc<Module>,
- name: Name,
- namespace: Namespace)
- -> ResolveResult<(Target, bool)> {
- debug!("(resolving item in lexical scope) resolving `{}` in \
- namespace {} in `{}`",
- token::get_name(name),
- namespace,
- self.module_to_string(&*module_));
-
- // The current module node is handled specially. First, check for
- // its immediate children.
- self.populate_module_if_necessary(&module_);
-
- match module_.children.borrow().get(&name) {
- Some(name_bindings)
- if name_bindings.defined_in_namespace(namespace) => {
- debug!("top name bindings succeeded");
- return Success((Target::new(module_.clone(),
- name_bindings.clone(),
- false),
- false));
- }
- Some(_) | None => { /* Not found; continue. */ }
- }
-
- // Now check for its import directives. We don't have to have resolved
- // all its imports in the usual way; this is because chains of
- // adjacent import statements are processed as though they mutated the
- // current scope.
- if let Some(import_resolution) = module_.import_resolutions.borrow().get(&name) {
- match (*import_resolution).target_for_namespace(namespace) {
- None => {
- // Not found; continue.
- debug!("(resolving item in lexical scope) found \
- import resolution, but not in namespace {}",
- namespace);
- }
- Some(target) => {
- debug!("(resolving item in lexical scope) using \
- import resolution");
- // track used imports and extern crates as well
- self.used_imports.insert((import_resolution.id(namespace), namespace));
- if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
- self.used_crates.insert(kid);
- }
- return Success((target, false));
- }
- }
- }
-
- // Search for external modules.
- if namespace == TypeNS {
- if let Some(module) = module_.external_module_children.borrow().get(&name).cloned() {
- let name_bindings =
- Rc::new(Resolver::create_name_bindings_from_module(module));
- debug!("lower name bindings succeeded");
- return Success((Target::new(module_, name_bindings, false),
- false));
- }
- }
-
- // Finally, proceed up the scope chain looking for parent modules.
- let mut search_module = module_;
- loop {
- // Go to the next parent.
- match search_module.parent_link.clone() {
- NoParentLink => {
- // No more parents. This module was unresolved.
- debug!("(resolving item in lexical scope) unresolved \
- module");
- return Failed(None);
- }
- ModuleParentLink(parent_module_node, _) => {
- match search_module.kind.get() {
- NormalModuleKind => {
- // We stop the search here.
- debug!("(resolving item in lexical \
- scope) unresolved module: not \
- searching through module \
- parents");
- return Failed(None);
- }
- TraitModuleKind |
- ImplModuleKind |
- EnumModuleKind |
- AnonymousModuleKind => {
- search_module = parent_module_node.upgrade().unwrap();
- }
- }
- }
- BlockParentLink(ref parent_module_node, _) => {
- search_module = parent_module_node.upgrade().unwrap();
- }
- }
-
- // Resolve the name in the parent module.
- match self.resolve_name_in_module(search_module.clone(),
- name,
- namespace,
- PathSearch,
- true) {
- Failed(Some((span, msg))) =>
- self.resolve_error(span, format!("failed to resolve. {}",
- msg)),
- Failed(None) => (), // Continue up the search chain.
- Indeterminate => {
- // We couldn't see through the higher scope because of an
- // unresolved import higher up. Bail.
-
- debug!("(resolving item in lexical scope) indeterminate \
- higher scope; bailing");
- return Indeterminate;
- }
- Success((target, used_reexport)) => {
- // We found the module.
- debug!("(resolving item in lexical scope) found name \
- in module, done");
- return Success((target, used_reexport));
- }
- }
- }
- }
-
- /// Resolves a module name in the current lexical scope.
- fn resolve_module_in_lexical_scope(&mut self,
- module_: Rc<Module>,
- name: Name)
- -> ResolveResult<Rc<Module>> {
- // If this module is an anonymous module, resolve the item in the
- // lexical scope. Otherwise, resolve the item from the crate root.
- let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS);
- match resolve_result {
- Success((target, _)) => {
- let bindings = &*target.bindings;
- match *bindings.type_def.borrow() {
- Some(ref type_def) => {
- match type_def.module_def {
- None => {
- debug!("!!! (resolving module in lexical \
- scope) module wasn't actually a \
- module!");
- return Failed(None);
- }
- Some(ref module_def) => {
- return Success(module_def.clone());
- }
- }
- }
- None => {
- debug!("!!! (resolving module in lexical scope) module
- wasn't actually a module!");
- return Failed(None);
- }
- }
- }
- Indeterminate => {
- debug!("(resolving module in lexical scope) indeterminate; \
- bailing");
- return Indeterminate;
- }
- Failed(err) => {
- debug!("(resolving module in lexical scope) failed to resolve");
- return Failed(err);
- }
- }
- }
-
- /// Returns the nearest normal module parent of the given module.
- fn get_nearest_normal_module_parent(&mut self, module_: Rc<Module>)
- -> Option<Rc<Module>> {
- let mut module_ = module_;
- loop {
- match module_.parent_link.clone() {
- NoParentLink => return None,
- ModuleParentLink(new_module, _) |
- BlockParentLink(new_module, _) => {
- let new_module = new_module.upgrade().unwrap();
- match new_module.kind.get() {
- NormalModuleKind => return Some(new_module),
- TraitModuleKind |
- ImplModuleKind |
- EnumModuleKind |
- AnonymousModuleKind => module_ = new_module,
- }
- }
- }
- }
- }
-
- /// Returns the nearest normal module parent of the given module, or the
- /// module itself if it is a normal module.
- fn get_nearest_normal_module_parent_or_self(&mut self, module_: Rc<Module>)
- -> Rc<Module> {
- match module_.kind.get() {
- NormalModuleKind => return module_,
- TraitModuleKind |
- ImplModuleKind |
- EnumModuleKind |
- AnonymousModuleKind => {
- match self.get_nearest_normal_module_parent(module_.clone()) {
- None => module_,
- Some(new_module) => new_module
- }
- }
- }
- }
-
- /// Resolves a "module prefix". A module prefix is one or both of (a) `self::`;
- /// (b) some chain of `super::`.
- /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) *
- fn resolve_module_prefix(&mut self,
- module_: Rc<Module>,
- module_path: &[Name])
- -> ResolveResult<ModulePrefixResult> {
- // Start at the current module if we see `self` or `super`, or at the
- // top of the crate otherwise.
- let mut containing_module;
- let mut i;
- let first_module_path_string = token::get_name(module_path[0]);
- if "self" == first_module_path_string.get() {
- containing_module =
- self.get_nearest_normal_module_parent_or_self(module_);
- i = 1;
- } else if "super" == first_module_path_string.get() {
- containing_module =
- self.get_nearest_normal_module_parent_or_self(module_);
- i = 0; // We'll handle `super` below.
- } else {
- return Success(NoPrefixFound);
- }
-
- // Now loop through all the `super`s we find.
- while i < module_path.len() {
- let string = token::get_name(module_path[i]);
- if "super" != string.get() {
- break
- }
- debug!("(resolving module prefix) resolving `super` at {}",
- self.module_to_string(&*containing_module));
- match self.get_nearest_normal_module_parent(containing_module) {
- None => return Failed(None),
- Some(new_module) => {
- containing_module = new_module;
- i += 1;
- }
- }
- }
-
- debug!("(resolving module prefix) finished resolving prefix at {}",
- self.module_to_string(&*containing_module));
-
- return Success(PrefixFound(containing_module, i));
- }
-
- /// Attempts to resolve the supplied name in the given module for the
- /// given namespace. If successful, returns the target corresponding to
- /// the name.
- ///
- /// The boolean returned on success is an indicator of whether this lookup
- /// passed through a public re-export proxy.
- fn resolve_name_in_module(&mut self,
- module_: Rc<Module>,
- name: Name,
- namespace: Namespace,
- name_search_type: NameSearchType,
- allow_private_imports: bool)
- -> ResolveResult<(Target, bool)> {
- debug!("(resolving name in module) resolving `{}` in `{}`",
- token::get_name(name).get(),
- self.module_to_string(&*module_));
-
- // First, check the direct children of the module.
- self.populate_module_if_necessary(&module_);
-
- match module_.children.borrow().get(&name) {
- Some(name_bindings)
- if name_bindings.defined_in_namespace(namespace) => {
- debug!("(resolving name in module) found node as child");
- return Success((Target::new(module_.clone(),
- name_bindings.clone(),
- false),
- false));
- }
- Some(_) | None => {
- // Continue.
- }
- }
-
- // Next, check the module's imports if necessary.
-
- // If this is a search of all imports, we should be done with glob
- // resolution at this point.
- if name_search_type == PathSearch {
- assert_eq!(module_.glob_count.get(), 0);
- }
-
- // Check the list of resolved imports.
- match module_.import_resolutions.borrow().get(&name) {
- Some(import_resolution) if allow_private_imports ||
- import_resolution.is_public => {
-
- if import_resolution.is_public &&
- import_resolution.outstanding_references != 0 {
- debug!("(resolving name in module) import \
- unresolved; bailing out");
- return Indeterminate;
- }
- match import_resolution.target_for_namespace(namespace) {
- None => {
- debug!("(resolving name in module) name found, \
- but not in namespace {}",
- namespace);
- }
- Some(target) => {
- debug!("(resolving name in module) resolved to \
- import");
- // track used imports and extern crates as well
- self.used_imports.insert((import_resolution.id(namespace), namespace));
- if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
- self.used_crates.insert(kid);
- }
- return Success((target, true));
- }
- }
- }
- Some(..) | None => {} // Continue.
- }
-
- // Finally, search through external children.
- if namespace == TypeNS {
- if let Some(module) = module_.external_module_children.borrow().get(&name).cloned() {
- let name_bindings =
- Rc::new(Resolver::create_name_bindings_from_module(module));
- return Success((Target::new(module_, name_bindings, false),
- false));
- }
- }
-
- // We're out of luck.
- debug!("(resolving name in module) failed to resolve `{}`",
- token::get_name(name).get());
- return Failed(None);
- }
-
- fn report_unresolved_imports(&mut self, module_: Rc<Module>) {
- let index = module_.resolved_import_count.get();
- let imports = module_.imports.borrow();
- let import_count = imports.len();
- if index != import_count {
- let sn = self.session
- .codemap()
- .span_to_snippet((*imports)[index].span)
- .unwrap();
- if sn.contains("::") {
- self.resolve_error((*imports)[index].span,
- "unresolved import");
- } else {
- let err = format!("unresolved import (maybe you meant `{}::*`?)",
- sn.slice(0, sn.len()));
- self.resolve_error((*imports)[index].span, err.as_slice());
- }
- }
-
- // Descend into children and anonymous children.
- self.populate_module_if_necessary(&module_);
-
- for (_, child_node) in module_.children.borrow().iter() {
- match child_node.get_module_if_available() {
- None => {
- // Continue.
- }
- Some(child_module) => {
- self.report_unresolved_imports(child_module);
- }
- }
- }
-
- for (_, module_) in module_.anonymous_children.borrow().iter() {
- self.report_unresolved_imports(module_.clone());
- }
- }
-
- // Export recording
- //
- // This pass simply determines what all "export" keywords refer to and
- // writes the results into the export map.
- //
- // FIXME #4953 This pass will be removed once exports change to per-item.
- // Then this operation can simply be performed as part of item (or import)
- // processing.
-
- fn record_exports(&mut self) {
- let root_module = self.graph_root.get_module();
- self.record_exports_for_module_subtree(root_module);
- }
-
- fn record_exports_for_module_subtree(&mut self,
- module_: Rc<Module>) {
- // If this isn't a local krate, then bail out. We don't need to record
- // exports for nonlocal crates.
-
- match module_.def_id.get() {
- Some(def_id) if def_id.krate == LOCAL_CRATE => {
- // OK. Continue.
- debug!("(recording exports for module subtree) recording \
- exports for local module `{}`",
- self.module_to_string(&*module_));
- }
- None => {
- // Record exports for the root module.
- debug!("(recording exports for module subtree) recording \
- exports for root module `{}`",
- self.module_to_string(&*module_));
- }
- Some(_) => {
- // Bail out.
- debug!("(recording exports for module subtree) not recording \
- exports for `{}`",
- self.module_to_string(&*module_));
- return;
- }
- }
-
- self.record_exports_for_module(&*module_);
- self.populate_module_if_necessary(&module_);
-
- for (_, child_name_bindings) in module_.children.borrow().iter() {
- match child_name_bindings.get_module_if_available() {
- None => {
- // Nothing to do.
- }
- Some(child_module) => {
- self.record_exports_for_module_subtree(child_module);
- }
- }
- }
-
- for (_, child_module) in module_.anonymous_children.borrow().iter() {
- self.record_exports_for_module_subtree(child_module.clone());
- }
- }
-
- fn record_exports_for_module(&mut self, module_: &Module) {
- let mut exports2 = Vec::new();
-
- self.add_exports_for_module(&mut exports2, module_);
- match module_.def_id.get() {
- Some(def_id) => {
- self.export_map2.insert(def_id.node, exports2);
- debug!("(computing exports) writing exports for {} (some)",
- def_id.node);
- }
- None => {}
- }
- }
-
- fn add_exports_of_namebindings(&mut self,
- exports2: &mut Vec<Export2> ,
- name: Name,
- namebindings: &NameBindings,
- ns: Namespace) {
- match namebindings.def_for_namespace(ns) {
- Some(d) => {
- let name = token::get_name(name);
- debug!("(computing exports) YES: export '{}' => {}",
- name, d.def_id());
- exports2.push(Export2 {
- name: name.get().to_string(),
- def_id: d.def_id()
- });
- }
- d_opt => {
- debug!("(computing exports) NO: {}", d_opt);
- }
- }
- }
-
- fn add_exports_for_module(&mut self,
- exports2: &mut Vec<Export2> ,
- module_: &Module) {
- for (name, importresolution) in module_.import_resolutions.borrow().iter() {
- if !importresolution.is_public {
- continue
- }
- let xs = [TypeNS, ValueNS];
- for &ns in xs.iter() {
- match importresolution.target_for_namespace(ns) {
- Some(target) => {
- debug!("(computing exports) maybe export '{}'",
- token::get_name(*name));
- self.add_exports_of_namebindings(exports2,
- *name,
- &*target.bindings,
- ns)
- }
- _ => ()
- }
- }
- }
- }
-
- // AST resolution
- //
- // We maintain a list of value ribs and type ribs.
- //
- // Simultaneously, we keep track of the current position in the module
- // graph in the `current_module` pointer. When we go to resolve a name in
- // the value or type namespaces, we first look through all the ribs and
- // then query the module graph. When we resolve a name in the module
- // namespace, we can skip all the ribs (since nested modules are not
- // allowed within blocks in Rust) and jump straight to the current module
- // graph node.
- //
- // Named implementations are handled separately. When we find a method
- // call, we consult the module node to find all of the implementations in
- // scope. This information is lazily cached in the module node. We then
- // generate a fake "implementation scope" containing all the
- // implementations thus found, for compatibility with old resolve pass.
-
- fn with_scope<F>(&mut self, name: Option<Name>, f: F) where
- F: FnOnce(&mut Resolver),
- {
- let orig_module = self.current_module.clone();
-
- // Move down in the graph.
- match name {
- None => {
- // Nothing to do.
- }
- Some(name) => {
- self.populate_module_if_necessary(&orig_module);
-
- match orig_module.children.borrow().get(&name) {
- None => {
- debug!("!!! (with scope) didn't find `{}` in `{}`",
- token::get_name(name),
- self.module_to_string(&*orig_module));
- }
- Some(name_bindings) => {
- match (*name_bindings).get_module_if_available() {
- None => {
- debug!("!!! (with scope) didn't find module \
- for `{}` in `{}`",
- token::get_name(name),
- self.module_to_string(&*orig_module));
- }
- Some(module_) => {
- self.current_module = module_;
- }
- }
- }
- }
- }
- }
-
- f(self);
-
- self.current_module = orig_module;
- }
-
- /// Wraps the given definition in the appropriate number of `DefUpvar`
- /// wrappers.
- fn upvarify(&self,
- ribs: &[Rib],
- def_like: DefLike,
- span: Span)
- -> Option<DefLike> {
- match def_like {
- DlDef(d @ DefUpvar(..)) => {
- self.session.span_bug(span,
- format!("unexpected {} in bindings", d).as_slice())
- }
- DlDef(d @ DefLocal(_)) => {
- let node_id = d.def_id().node;
- let mut def = d;
- let mut last_proc_body_id = ast::DUMMY_NODE_ID;
- for rib in ribs.iter() {
- match rib.kind {
- NormalRibKind => {
- // Nothing to do. Continue.
- }
- ClosureRibKind(function_id, maybe_proc_body) => {
- let prev_def = def;
- if maybe_proc_body != ast::DUMMY_NODE_ID {
- last_proc_body_id = maybe_proc_body;
- }
- def = DefUpvar(node_id, function_id, last_proc_body_id);
-
- let mut seen = self.freevars_seen.borrow_mut();
- let seen = match seen.entry(function_id) {
- Occupied(v) => v.into_mut(),
- Vacant(v) => v.set(NodeSet::new()),
- };
- if seen.contains(&node_id) {
- continue;
- }
- match self.freevars.borrow_mut().entry(function_id) {
- Occupied(v) => v.into_mut(),
- Vacant(v) => v.set(vec![]),
- }.push(Freevar { def: prev_def, span: span });
- seen.insert(node_id);
- }
- MethodRibKind(item_id, _) => {
- // If the def is a ty param, and came from the parent
- // item, it's ok
- match def {
- DefTyParam(_, did, _) if {
- self.def_map.borrow().get(&did.node).cloned()
- == Some(DefTyParamBinder(item_id))
- } => {} // ok
- DefSelfTy(did) if did == item_id => {} // ok
- _ => {
- // This was an attempt to access an upvar inside a
- // named function item. This is not allowed, so we
- // report an error.
-
- self.resolve_error(
- span,
- "can't capture dynamic environment in a fn item; \
- use the || { ... } closure form instead");
-
- return None;
- }
- }
- }
- ItemRibKind => {
- // This was an attempt to access an upvar inside a
- // named function item. This is not allowed, so we
- // report an error.
-
- self.resolve_error(
- span,
- "can't capture dynamic environment in a fn item; \
- use the || { ... } closure form instead");
-
- return None;
- }
- ConstantItemRibKind => {
- // Still doesn't deal with upvars
- self.resolve_error(span,
- "attempt to use a non-constant \
- value in a constant");
-
- }
- }
- }
- Some(DlDef(def))
- }
- DlDef(def @ DefTyParam(..)) |
- DlDef(def @ DefSelfTy(..)) => {
- for rib in ribs.iter() {
- match rib.kind {
- NormalRibKind | ClosureRibKind(..) => {
- // Nothing to do. Continue.
- }
- MethodRibKind(item_id, _) => {
- // If the def is a ty param, and came from the parent
- // item, it's ok
- match def {
- DefTyParam(_, did, _) if {
- self.def_map.borrow().get(&did.node).cloned()
- == Some(DefTyParamBinder(item_id))
- } => {} // ok
- DefSelfTy(did) if did == item_id => {} // ok
-
- _ => {
- // This was an attempt to use a type parameter outside
- // its scope.
-
- self.resolve_error(span,
- "can't use type parameters from \
- outer function; try using a local \
- type parameter instead");
-
- return None;
- }
- }
- }
- ItemRibKind => {
- // This was an attempt to use a type parameter outside
- // its scope.
-
- self.resolve_error(span,
- "can't use type parameters from \
- outer function; try using a local \
- type parameter instead");
-
- return None;
- }
- ConstantItemRibKind => {
- // see #9186
- self.resolve_error(span,
- "cannot use an outer type \
- parameter in this context");
-
- }
- }
- }
- Some(DlDef(def))
- }
- _ => Some(def_like)
- }
- }
-
- fn search_ribs(&self,
- ribs: &[Rib],
- name: Name,
- span: Span)
- -> Option<DefLike> {
- // FIXME #4950: Try caching?
-
- for (i, rib) in ribs.iter().enumerate().rev() {
- match rib.bindings.get(&name).cloned() {
- Some(def_like) => {
- return self.upvarify(ribs[i + 1..], def_like, span);
- }
- None => {
- // Continue.
- }
- }
- }
-
- None
- }
-
- fn resolve_crate(&mut self, krate: &ast::Crate) {
- debug!("(resolving crate) starting");
-
- visit::walk_crate(self, krate);
- }
-
- fn resolve_item(&mut self, item: &Item) {
- let name = item.ident.name;
-
- debug!("(resolving item) resolving {}",
- token::get_name(name));
-
- match item.node {
-
- // enum item: resolve all the variants' discrs,
- // then resolve the ty params
- ItemEnum(ref enum_def, ref generics) => {
- for variant in (*enum_def).variants.iter() {
- for dis_expr in variant.node.disr_expr.iter() {
- // resolve the discriminator expr
- // as a constant
- self.with_constant_rib(|this| {
- this.resolve_expr(&**dis_expr);
- });
- }
- }
-
- // n.b. the discr expr gets visited twice.
- // but maybe it's okay since the first time will signal an
- // error if there is one? -- tjc
- self.with_type_parameter_rib(HasTypeParameters(generics,
- TypeSpace,
- item.id,
- ItemRibKind),
- |this| {
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
- visit::walk_item(this, item);
- });
- }
-
- ItemTy(_, ref generics) => {
- self.with_type_parameter_rib(HasTypeParameters(generics,
- TypeSpace,
- item.id,
- ItemRibKind),
- |this| {
- this.resolve_type_parameters(&generics.ty_params);
- visit::walk_item(this, item);
- });
- }
-
- ItemImpl(_,
- ref generics,
- ref implemented_traits,
- ref self_type,
- ref impl_items) => {
- self.resolve_implementation(item.id,
- generics,
- implemented_traits,
- &**self_type,
- impl_items.as_slice());
- }
-
- ItemTrait(_, ref generics, ref unbound, ref bounds, ref trait_items) => {
- // Create a new rib for the self type.
- let mut self_type_rib = Rib::new(ItemRibKind);
-
- // plain insert (no renaming, types are not currently hygienic....)
- let name = self.type_self_name;
- self_type_rib.bindings.insert(name, DlDef(DefSelfTy(item.id)));
- self.type_ribs.push(self_type_rib);
-
- // Create a new rib for the trait-wide type parameters.
- self.with_type_parameter_rib(HasTypeParameters(generics,
- TypeSpace,
- item.id,
- NormalRibKind),
- |this| {
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
-
- this.resolve_type_parameter_bounds(item.id, bounds,
- TraitDerivation);
-
- match *unbound {
- Some(ref tpb) => {
- this.resolve_trait_reference(item.id, tpb, TraitDerivation);
- }
- None => {}
- }
-
- for trait_item in (*trait_items).iter() {
- // Create a new rib for the trait_item-specific type
- // parameters.
- //
- // FIXME #4951: Do we need a node ID here?
-
- match *trait_item {
- ast::RequiredMethod(ref ty_m) => {
- this.with_type_parameter_rib
- (HasTypeParameters(&ty_m.generics,
- FnSpace,
- item.id,
- MethodRibKind(item.id, RequiredMethod)),
- |this| {
-
- // Resolve the method-specific type
- // parameters.
- this.resolve_type_parameters(
- &ty_m.generics.ty_params);
- this.resolve_where_clause(&ty_m.generics
- .where_clause);
-
- for argument in ty_m.decl.inputs.iter() {
- this.resolve_type(&*argument.ty);
- }
-
- if let SelfExplicit(ref typ, _) = ty_m.explicit_self.node {
- this.resolve_type(&**typ)
- }
-
- if let ast::Return(ref ret_ty) = ty_m.decl.output {
- this.resolve_type(&**ret_ty);
- }
- });
- }
- ast::ProvidedMethod(ref m) => {
- this.resolve_method(MethodRibKind(item.id,
- ProvidedMethod(m.id)),
- &**m)
- }
- ast::TypeTraitItem(ref data) => {
- this.resolve_type_parameter(&data.ty_param);
- visit::walk_trait_item(this, trait_item);
- }
- }
- }
- });
-
- self.type_ribs.pop();
- }
-
- ItemStruct(ref struct_def, ref generics) => {
- self.resolve_struct(item.id,
- generics,
- struct_def.fields.as_slice());
- }
-
- ItemMod(ref module_) => {
- self.with_scope(Some(name), |this| {
- this.resolve_module(module_, item.span, name,
- item.id);
- });
- }
-
- ItemForeignMod(ref foreign_module) => {
- self.with_scope(Some(name), |this| {
- for foreign_item in foreign_module.items.iter() {
- match foreign_item.node {
- ForeignItemFn(_, ref generics) => {
- this.with_type_parameter_rib(
- HasTypeParameters(
- generics, FnSpace, foreign_item.id,
- ItemRibKind),
- |this| visit::walk_foreign_item(this,
- &**foreign_item));
- }
- ForeignItemStatic(..) => {
- visit::walk_foreign_item(this,
- &**foreign_item);
- }
- }
- }
- });
- }
-
- ItemFn(ref fn_decl, _, _, ref generics, ref block) => {
- self.resolve_function(ItemRibKind,
- Some(&**fn_decl),
- HasTypeParameters
- (generics,
- FnSpace,
- item.id,
- ItemRibKind),
- &**block);
- }
-
- ItemConst(..) | ItemStatic(..) => {
- self.with_constant_rib(|this| {
- visit::walk_item(this, item);
- });
- }
-
- ItemMac(..) => {
- // do nothing, these are just around to be encoded
- }
- }
- }
-
- fn with_type_parameter_rib<F>(&mut self, type_parameters: TypeParameters, f: F) where
- F: FnOnce(&mut Resolver),
- {
- match type_parameters {
- HasTypeParameters(generics, space, node_id, rib_kind) => {
- let mut function_type_rib = Rib::new(rib_kind);
- let mut seen_bindings = HashSet::new();
- for (index, type_parameter) in generics.ty_params.iter().enumerate() {
- let name = type_parameter.ident.name;
- debug!("with_type_parameter_rib: {} {}", node_id,
- type_parameter.id);
-
- if seen_bindings.contains(&name) {
- self.resolve_error(type_parameter.span,
- format!("the name `{}` is already \
- used for a type \
- parameter in this type \
- parameter list",
- token::get_name(
- name)).as_slice())
- }
- seen_bindings.insert(name);
-
- let def_like = DlDef(DefTyParam(space,
- local_def(type_parameter.id),
- index));
- // Associate this type parameter with
- // the item that bound it
- self.record_def(type_parameter.id,
- (DefTyParamBinder(node_id), LastMod(AllPublic)));
- // plain insert (no renaming)
- function_type_rib.bindings.insert(name, def_like);
- }
- self.type_ribs.push(function_type_rib);
- }
-
- NoTypeParameters => {
- // Nothing to do.
- }
- }
-
- f(self);
-
- match type_parameters {
- HasTypeParameters(..) => { self.type_ribs.pop(); }
- NoTypeParameters => { }
- }
- }
-
- fn with_label_rib<F>(&mut self, f: F) where
- F: FnOnce(&mut Resolver),
- {
- self.label_ribs.push(Rib::new(NormalRibKind));
- f(self);
- self.label_ribs.pop();
- }
-
- fn with_constant_rib<F>(&mut self, f: F) where
- F: FnOnce(&mut Resolver),
- {
- self.value_ribs.push(Rib::new(ConstantItemRibKind));
- self.type_ribs.push(Rib::new(ConstantItemRibKind));
- f(self);
- self.type_ribs.pop();
- self.value_ribs.pop();
- }
-
- fn resolve_function(&mut self,
- rib_kind: RibKind,
- optional_declaration: Option<&FnDecl>,
- type_parameters: TypeParameters,
- block: &Block) {
- // Create a value rib for the function.
- let function_value_rib = Rib::new(rib_kind);
- self.value_ribs.push(function_value_rib);
-
- // Create a label rib for the function.
- let function_label_rib = Rib::new(rib_kind);
- self.label_ribs.push(function_label_rib);
-
- // If this function has type parameters, add them now.
- self.with_type_parameter_rib(type_parameters, |this| {
- // Resolve the type parameters.
- match type_parameters {
- NoTypeParameters => {
- // Continue.
- }
- HasTypeParameters(ref generics, _, _, _) => {
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
- }
- }
-
- // Add each argument to the rib.
- match optional_declaration {
- None => {
- // Nothing to do.
- }
- Some(declaration) => {
- let mut bindings_list = HashMap::new();
- for argument in declaration.inputs.iter() {
- this.resolve_pattern(&*argument.pat,
- ArgumentIrrefutableMode,
- &mut bindings_list);
-
- this.resolve_type(&*argument.ty);
-
- debug!("(resolving function) recorded argument");
- }
-
- if let ast::Return(ref ret_ty) = declaration.output {
- this.resolve_type(&**ret_ty);
- }
- }
- }
-
- // Resolve the function body.
- this.resolve_block(&*block);
-
- debug!("(resolving function) leaving function");
- });
-
- self.label_ribs.pop();
- self.value_ribs.pop();
- }
-
- fn resolve_type_parameters(&mut self,
- type_parameters: &OwnedSlice<TyParam>) {
- for type_parameter in type_parameters.iter() {
- self.resolve_type_parameter(type_parameter);
- }
- }
-
- fn resolve_type_parameter(&mut self,
- type_parameter: &TyParam) {
- for bound in type_parameter.bounds.iter() {
- self.resolve_type_parameter_bound(type_parameter.id, bound,
- TraitBoundingTypeParameter);
- }
- match &type_parameter.unbound {
- &Some(ref unbound) =>
- self.resolve_trait_reference(
- type_parameter.id, unbound, TraitBoundingTypeParameter),
- &None => {}
- }
- match type_parameter.default {
- Some(ref ty) => self.resolve_type(&**ty),
- None => {}
- }
- }
-
- fn resolve_type_parameter_bounds(&mut self,
- id: NodeId,
- type_parameter_bounds: &OwnedSlice<TyParamBound>,
- reference_type: TraitReferenceType) {
- for type_parameter_bound in type_parameter_bounds.iter() {
- self.resolve_type_parameter_bound(id, type_parameter_bound,
- reference_type);
- }
- }
-
- fn resolve_type_parameter_bound(&mut self,
- id: NodeId,
- type_parameter_bound: &TyParamBound,
- reference_type: TraitReferenceType) {
- match *type_parameter_bound {
- TraitTyParamBound(ref tref) => {
- self.resolve_poly_trait_reference(id, tref, reference_type)
- }
- RegionTyParamBound(..) => {}
- }
- }
-
- fn resolve_poly_trait_reference(&mut self,
- id: NodeId,
- poly_trait_reference: &PolyTraitRef,
- reference_type: TraitReferenceType) {
- self.resolve_trait_reference(id, &poly_trait_reference.trait_ref, reference_type)
- }
-
- fn resolve_trait_reference(&mut self,
- id: NodeId,
- trait_reference: &TraitRef,
- reference_type: TraitReferenceType) {
- match self.resolve_path(id, &trait_reference.path, TypeNS, true) {
- None => {
- let path_str = self.path_names_to_string(&trait_reference.path);
- let usage_str = match reference_type {
- TraitBoundingTypeParameter => "bound type parameter with",
- TraitImplementation => "implement",
- TraitDerivation => "derive",
- TraitObject => "reference",
- TraitQPath => "extract an associated type from",
- };
-
- let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
- self.resolve_error(trait_reference.path.span, msg.as_slice());
- }
- Some(def) => {
- match def {
- (DefTrait(_), _) => {
- debug!("(resolving trait) found trait def: {}", def);
- self.record_def(trait_reference.ref_id, def);
- }
- (def, _) => {
- self.resolve_error(trait_reference.path.span,
- format!("`{}` is not a trait",
- self.path_names_to_string(
- &trait_reference.path)));
-
- // If it's a typedef, give a note
- if let DefTy(..) = def {
- self.session.span_note(
- trait_reference.path.span,
- format!("`type` aliases cannot be used for traits")
- .as_slice());
- }
- }
- }
- }
- }
- }
-
- fn resolve_where_clause(&mut self, where_clause: &ast::WhereClause) {
- for predicate in where_clause.predicates.iter() {
- match predicate {
- &ast::WherePredicate::BoundPredicate(ref bound_pred) => {
- match self.resolve_identifier(bound_pred.ident,
- TypeNS,
- true,
- bound_pred.span) {
- Some((def @ DefTyParam(..), last_private)) => {
- self.record_def(bound_pred.id, (def, last_private));
- }
- _ => {
- self.resolve_error(
- bound_pred.span,
- format!("undeclared type parameter `{}`",
- token::get_ident(
- bound_pred.ident)).as_slice());
- }
- }
-
- for bound in bound_pred.bounds.iter() {
- self.resolve_type_parameter_bound(bound_pred.id, bound,
- TraitBoundingTypeParameter);
- }
- }
- &ast::WherePredicate::EqPredicate(ref eq_pred) => {
- match self.resolve_path(eq_pred.id, &eq_pred.path, TypeNS, true) {
- Some((def @ DefTyParam(..), last_private)) => {
- self.record_def(eq_pred.id, (def, last_private));
- }
- _ => {
- self.resolve_error(eq_pred.path.span,
- "undeclared associated type");
- }
- }
-
- self.resolve_type(&*eq_pred.ty);
- }
- }
- }
- }
-
- fn resolve_struct(&mut self,
- id: NodeId,
- generics: &Generics,
- fields: &[StructField]) {
- // If applicable, create a rib for the type parameters.
- self.with_type_parameter_rib(HasTypeParameters(generics,
- TypeSpace,
- id,
- ItemRibKind),
- |this| {
- // Resolve the type parameters.
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
-
- // Resolve fields.
- for field in fields.iter() {
- this.resolve_type(&*field.node.ty);
- }
- });
- }
-
- // Does this really need to take a RibKind or is it always going
- // to be NormalRibKind?
- fn resolve_method(&mut self,
- rib_kind: RibKind,
- method: &ast::Method) {
- let method_generics = method.pe_generics();
- let type_parameters = HasTypeParameters(method_generics,
- FnSpace,
- method.id,
- rib_kind);
-
- if let SelfExplicit(ref typ, _) = method.pe_explicit_self().node {
- self.resolve_type(&**typ);
- }
-
- self.resolve_function(rib_kind,
- Some(method.pe_fn_decl()),
- type_parameters,
- method.pe_body());
- }
-
- fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T where
- F: FnOnce(&mut Resolver) -> T,
- {
- // Handle nested impls (inside fn bodies)
- let previous_value = replace(&mut self.current_self_type, Some(self_type.clone()));
- let result = f(self);
- self.current_self_type = previous_value;
- result
- }
-
- fn with_optional_trait_ref<T, F>(&mut self, id: NodeId,
- opt_trait_ref: &Option<TraitRef>,
- f: F) -> T where
- F: FnOnce(&mut Resolver) -> T,
- {
- let new_val = match *opt_trait_ref {
- Some(ref trait_ref) => {
- self.resolve_trait_reference(id, trait_ref, TraitImplementation);
-
- match self.def_map.borrow().get(&trait_ref.ref_id) {
- Some(def) => {
- let did = def.def_id();
- Some((did, trait_ref.clone()))
- }
- None => None
- }
- }
- None => None
- };
- let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
- let result = f(self);
- self.current_trait_ref = original_trait_ref;
- result
- }
-
- fn resolve_implementation(&mut self,
- id: NodeId,
- generics: &Generics,
- opt_trait_reference: &Option<TraitRef>,
- self_type: &Ty,
- impl_items: &[ImplItem]) {
- // If applicable, create a rib for the type parameters.
- self.with_type_parameter_rib(HasTypeParameters(generics,
- TypeSpace,
- id,
- NormalRibKind),
- |this| {
- // Resolve the type parameters.
- this.resolve_type_parameters(&generics.ty_params);
- this.resolve_where_clause(&generics.where_clause);
-
- // Resolve the trait reference, if necessary.
- this.with_optional_trait_ref(id, opt_trait_reference, |this| {
- // Resolve the self type.
- this.resolve_type(self_type);
-
- this.with_current_self_type(self_type, |this| {
- for impl_item in impl_items.iter() {
- match *impl_item {
- MethodImplItem(ref method) => {
- // If this is a trait impl, ensure the method
- // exists in trait
- this.check_trait_item(method.pe_ident().name,
- method.span);
-
- // We also need a new scope for the method-
- // specific type parameters.
- this.resolve_method(
- MethodRibKind(id, ProvidedMethod(method.id)),
- &**method);
- }
- TypeImplItem(ref typedef) => {
- // If this is a trait impl, ensure the method
- // exists in trait
- this.check_trait_item(typedef.ident.name,
- typedef.span);
-
- this.resolve_type(&*typedef.typ);
- }
- }
- }
- });
- });
- });
-
- // Check that the current type is indeed a type, if we have an anonymous impl
- if opt_trait_reference.is_none() {
- match self_type.node {
- // TyPath is the only thing that we handled in `build_reduced_graph_for_item`,
- // where we created a module with the name of the type in order to implement
- // an anonymous trait. In the case that the path does not resolve to an actual
- // type, the result will be that the type name resolves to a module but not
- // a type (shadowing any imported modules or types with this name), leading
- // to weird user-visible bugs. So we ward this off here. See #15060.
- TyPath(ref path, path_id) => {
- match self.def_map.borrow().get(&path_id) {
- // FIXME: should we catch other options and give more precise errors?
- Some(&DefMod(_)) => {
- self.resolve_error(path.span, "inherent implementations are not \
- allowed for types not defined in \
- the current module");
- }
- _ => {}
- }
- }
- _ => { }
- }
- }
- }
-
- fn check_trait_item(&self, name: Name, span: Span) {
- // If there is a TraitRef in scope for an impl, then the method must be in the trait.
- for &(did, ref trait_ref) in self.current_trait_ref.iter() {
- if self.trait_item_map.get(&(name, did)).is_none() {
- let path_str = self.path_names_to_string(&trait_ref.path);
- self.resolve_error(span,
- format!("method `{}` is not a member of trait `{}`",
- token::get_name(name),
- path_str).as_slice());
- }
- }
- }
-
- fn resolve_module(&mut self, module: &Mod, _span: Span,
- _name: Name, id: NodeId) {
- // Write the implementations in scope into the module metadata.
- debug!("(resolving module) resolving module ID {}", id);
- visit::walk_mod(self, module);
- }
-
- fn resolve_local(&mut self, local: &Local) {
- // Resolve the type.
- self.resolve_type(&*local.ty);
-
- // Resolve the initializer, if necessary.
- match local.init {
- None => {
- // Nothing to do.
- }
- Some(ref initializer) => {
- self.resolve_expr(&**initializer);
- }
- }
-
- // Resolve the pattern.
- let mut bindings_list = HashMap::new();
- self.resolve_pattern(&*local.pat,
- LocalIrrefutableMode,
- &mut bindings_list);
- }
-
- // build a map from pattern identifiers to binding-info's.
- // this is done hygienically. This could arise for a macro
- // that expands into an or-pattern where one 'x' was from the
- // 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, path1| {
- let name = mtwt::resolve(path1.node);
- result.insert(name,
- binding_info {span: sp,
- binding_mode: binding_mode});
- });
- return result;
- }
-
- // check that all of the arms in an or-pattern have exactly the
- // same set of bindings, with the same binding modes for each.
- fn check_consistent_bindings(&mut self, arm: &Arm) {
- if arm.pats.len() == 0 {
- return
- }
- let map_0 = self.binding_mode_map(&*arm.pats[0]);
- for (i, p) in arm.pats.iter().enumerate() {
- let map_i = self.binding_mode_map(&**p);
-
- for (&key, &binding_0) in map_0.iter() {
- match map_i.get(&key) {
- None => {
- self.resolve_error(
- p.span,
- format!("variable `{}` from pattern #1 is \
- not bound in pattern #{}",
- token::get_name(key),
- i + 1).as_slice());
- }
- Some(binding_i) => {
- if binding_0.binding_mode != binding_i.binding_mode {
- self.resolve_error(
- binding_i.span,
- format!("variable `{}` is bound with different \
- mode in pattern #{} than in pattern #1",
- token::get_name(key),
- i + 1).as_slice());
- }
- }
- }
- }
-
- for (&key, &binding) in map_i.iter() {
- if !map_0.contains_key(&key) {
- self.resolve_error(
- binding.span,
- format!("variable `{}` from pattern {}{} is \
- not bound in pattern {}1",
- token::get_name(key),
- "#", i + 1, "#").as_slice());
- }
- }
- }
- }
-
- fn resolve_arm(&mut self, arm: &Arm) {
- self.value_ribs.push(Rib::new(NormalRibKind));
-
- let mut bindings_list = HashMap::new();
- for pattern in arm.pats.iter() {
- self.resolve_pattern(&**pattern, RefutableMode, &mut bindings_list);
- }
-
- // This has to happen *after* we determine which
- // pat_idents are variants
- self.check_consistent_bindings(arm);
-
- visit::walk_expr_opt(self, &arm.guard);
- self.resolve_expr(&*arm.body);
-
- self.value_ribs.pop();
- }
-
- fn resolve_block(&mut self, block: &Block) {
- debug!("(resolving block) entering block");
- self.value_ribs.push(Rib::new(NormalRibKind));
-
- // Move down in the graph, if there's an anonymous module rooted here.
- let orig_module = self.current_module.clone();
- match orig_module.anonymous_children.borrow().get(&block.id) {
- None => { /* Nothing to do. */ }
- Some(anonymous_module) => {
- debug!("(resolving block) found anonymous module, moving \
- down");
- self.current_module = anonymous_module.clone();
- }
- }
-
- // Descend into the block.
- visit::walk_block(self, block);
-
- // Move back up.
- self.current_module = orig_module;
-
- self.value_ribs.pop();
- debug!("(resolving block) leaving block");
- }
-
- fn resolve_type(&mut self, ty: &Ty) {
- match ty.node {
- // Like path expressions, the interpretation of path types depends
- // on whether the path has multiple elements in it or not.
-
- TyPath(ref path, path_id) => {
- // This is a path in the type namespace. Walk through scopes
- // looking for it.
- let mut result_def = None;
-
- // First, check to see whether the name is a primitive type.
- if path.segments.len() == 1 {
- let id = path.segments.last().unwrap().identifier;
-
- match self.primitive_type_table
- .primitive_types
- .get(&id.name) {
-
- Some(&primitive_type) => {
- result_def =
- Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
-
- if path.segments[0].parameters.has_lifetimes() {
- span_err!(self.session, path.span, E0157,
- "lifetime parameters are not allowed on this type");
- } else if !path.segments[0].parameters.is_empty() {
- span_err!(self.session, path.span, E0153,
- "type parameters are not allowed on this type");
- }
- }
- None => {
- // Continue.
- }
- }
- }
-
- match result_def {
- None => {
- match self.resolve_path(ty.id, path, TypeNS, true) {
- Some(def) => {
- debug!("(resolving type) resolved `{}` to \
- type {}",
- token::get_ident(path.segments
- .last().unwrap()
- .identifier),
- def);
- result_def = Some(def);
- }
- None => {
- result_def = None;
- }
- }
- }
- Some(_) => {} // Continue.
- }
-
- match result_def {
- Some(def) => {
- // Write the result into the def map.
- debug!("(resolving type) writing resolution for `{}` \
- (id {})",
- self.path_names_to_string(path),
- path_id);
- self.record_def(path_id, def);
- }
- None => {
- let msg = format!("use of undeclared type name `{}`",
- self.path_names_to_string(path));
- self.resolve_error(ty.span, msg.as_slice());
- }
- }
- }
-
- TyObjectSum(ref ty, ref bound_vec) => {
- self.resolve_type(&**ty);
- self.resolve_type_parameter_bounds(ty.id, bound_vec,
- TraitBoundingTypeParameter);
- }
-
- TyQPath(ref qpath) => {
- self.resolve_type(&*qpath.self_type);
- self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath);
- }
-
- TyClosure(ref c) => {
- self.resolve_type_parameter_bounds(
- ty.id,
- &c.bounds,
- TraitBoundingTypeParameter);
- visit::walk_ty(self, ty);
- }
-
- TyPolyTraitRef(ref bounds) => {
- self.resolve_type_parameter_bounds(
- ty.id,
- bounds,
- TraitObject);
- visit::walk_ty(self, ty);
- }
- _ => {
- // Just resolve embedded types.
- visit::walk_ty(self, ty);
- }
- }
- }
-
- fn resolve_pattern(&mut self,
- pattern: &Pat,
- mode: PatternBindingMode,
- // Maps idents to the node ID for the (outermost)
- // pattern that binds them
- bindings_list: &mut HashMap<Name, NodeId>) {
- let pat_id = pattern.id;
- walk_pat(pattern, |pattern| {
- match pattern.node {
- PatIdent(binding_mode, ref path1, _) => {
-
- // The meaning of pat_ident with no type parameters
- // depends on whether an enum variant or unit-like struct
- // with that name is in scope. The probing lookup has to
- // be careful not to emit spurious errors. Only matching
- // patterns (match) can match nullary variants or
- // unit-like structs. For binding patterns (let), matching
- // such a value is simply disallowed (since it's rarely
- // what you want).
-
- let ident = path1.node;
- let renamed = mtwt::resolve(ident);
-
- match self.resolve_bare_identifier_pattern(ident.name, pattern.span) {
- FoundStructOrEnumVariant(ref def, lp)
- if mode == RefutableMode => {
- debug!("(resolving pattern) resolving `{}` to \
- struct or enum variant",
- token::get_name(renamed));
-
- self.enforce_default_binding_mode(
- pattern,
- binding_mode,
- "an enum variant");
- self.record_def(pattern.id, (def.clone(), lp));
- }
- FoundStructOrEnumVariant(..) => {
- self.resolve_error(
- pattern.span,
- format!("declaration of `{}` shadows an enum \
- variant or unit-like struct in \
- scope",
- token::get_name(renamed)).as_slice());
- }
- FoundConst(ref def, lp) if mode == RefutableMode => {
- debug!("(resolving pattern) resolving `{}` to \
- constant",
- token::get_name(renamed));
-
- self.enforce_default_binding_mode(
- pattern,
- binding_mode,
- "a constant");
- self.record_def(pattern.id, (def.clone(), lp));
- }
- FoundConst(..) => {
- self.resolve_error(pattern.span,
- "only irrefutable patterns \
- allowed here");
- }
- BareIdentifierPatternUnresolved => {
- debug!("(resolving pattern) binding `{}`",
- token::get_name(renamed));
-
- let def = DefLocal(pattern.id);
-
- // Record the definition so that later passes
- // will be able to distinguish variants from
- // locals in patterns.
-
- self.record_def(pattern.id, (def, LastMod(AllPublic)));
-
- // Add the binding to the local ribs, if it
- // doesn't already exist in the bindings list. (We
- // must not add it if it's in the bindings list
- // because that breaks the assumptions later
- // passes make about or-patterns.)
- if !bindings_list.contains_key(&renamed) {
- let this = &mut *self;
- let last_rib = this.value_ribs.last_mut().unwrap();
- last_rib.bindings.insert(renamed, DlDef(def));
- bindings_list.insert(renamed, pat_id);
- } else if mode == ArgumentIrrefutableMode &&
- bindings_list.contains_key(&renamed) {
- // Forbid duplicate bindings in the same
- // parameter list.
- self.resolve_error(pattern.span,
- format!("identifier `{}` \
- is bound more \
- than once in \
- this parameter \
- list",
- token::get_ident(
- ident))
- .as_slice())
- } else if bindings_list.get(&renamed) ==
- Some(&pat_id) {
- // Then this is a duplicate variable in the
- // same disjunction, which is an error.
- self.resolve_error(pattern.span,
- format!("identifier `{}` is bound \
- more than once in the same \
- pattern",
- token::get_ident(ident)).as_slice());
- }
- // Else, not bound in the same pattern: do
- // nothing.
- }
- }
- }
-
- PatEnum(ref path, _) => {
- // This must be an enum variant, struct or const.
- match self.resolve_path(pat_id, path, ValueNS, false) {
- Some(def @ (DefVariant(..), _)) |
- Some(def @ (DefStruct(..), _)) |
- Some(def @ (DefConst(..), _)) => {
- self.record_def(pattern.id, def);
- }
- Some((DefStatic(..), _)) => {
- self.resolve_error(path.span,
- "static variables cannot be \
- referenced in a pattern, \
- use a `const` instead");
- }
- Some(_) => {
- self.resolve_error(path.span,
- format!("`{}` is not an enum variant, struct or const",
- token::get_ident(
- path.segments
- .last()
- .unwrap()
- .identifier)).as_slice());
- }
- None => {
- self.resolve_error(path.span,
- format!("unresolved enum variant, struct or const `{}`",
- token::get_ident(
- path.segments
- .last()
- .unwrap()
- .identifier)).as_slice());
- }
- }
-
- // Check the types in the path pattern.
- for ty in path.segments
- .iter()
- .flat_map(|s| s.parameters.types().into_iter()) {
- self.resolve_type(&**ty);
- }
- }
-
- PatLit(ref expr) => {
- self.resolve_expr(&**expr);
- }
-
- PatRange(ref first_expr, ref last_expr) => {
- self.resolve_expr(&**first_expr);
- self.resolve_expr(&**last_expr);
- }
-
- PatStruct(ref path, _, _) => {
- match self.resolve_path(pat_id, path, TypeNS, false) {
- Some(definition) => {
- self.record_def(pattern.id, definition);
- }
- result => {
- debug!("(resolving pattern) didn't find struct \
- def: {}", result);
- let msg = format!("`{}` does not name a structure",
- self.path_names_to_string(path));
- self.resolve_error(path.span, msg.as_slice());
- }
- }
- }
-
- _ => {
- // Nothing to do.
- }
- }
- true
- });
- }
-
- fn resolve_bare_identifier_pattern(&mut self, name: Name, span: Span)
- -> BareIdentifierPatternResolution {
- let module = self.current_module.clone();
- match self.resolve_item_in_lexical_scope(module,
- name,
- ValueNS) {
- Success((target, _)) => {
- debug!("(resolve bare identifier pattern) succeeded in \
- finding {} at {}",
- token::get_name(name),
- target.bindings.value_def.borrow());
- match *target.bindings.value_def.borrow() {
- None => {
- panic!("resolved name in the value namespace to a \
- set of name bindings with no def?!");
- }
- Some(def) => {
- // For the two success cases, this lookup can be
- // considered as not having a private component because
- // the lookup happened only within the current module.
- match def.def {
- def @ DefVariant(..) | def @ DefStruct(..) => {
- return FoundStructOrEnumVariant(def, LastMod(AllPublic));
- }
- def @ DefConst(..) => {
- return FoundConst(def, LastMod(AllPublic));
- }
- DefStatic(..) => {
- self.resolve_error(span,
- "static variables cannot be \
- referenced in a pattern, \
- use a `const` instead");
- return BareIdentifierPatternUnresolved;
- }
- _ => {
- return BareIdentifierPatternUnresolved;
- }
- }
- }
- }
- }
-
- Indeterminate => {
- panic!("unexpected indeterminate result");
- }
- Failed(err) => {
- match err {
- Some((span, msg)) => {
- self.resolve_error(span, format!("failed to resolve: {}",
- msg));
- }
- None => ()
- }
-
- debug!("(resolve bare identifier pattern) failed to find {}",
- token::get_name(name));
- return BareIdentifierPatternUnresolved;
- }
- }
- }
-
- /// If `check_ribs` is true, checks the local definitions first; i.e.
- /// doesn't skip straight to the containing module.
- fn resolve_path(&mut self,
- id: NodeId,
- path: &Path,
- namespace: Namespace,
- check_ribs: bool) -> Option<(Def, LastPrivate)> {
- // First, resolve the types and associated type bindings.
- for ty in path.segments.iter().flat_map(|s| s.parameters.types().into_iter()) {
- self.resolve_type(&**ty);
- }
- for binding in path.segments.iter().flat_map(|s| s.parameters.bindings().into_iter()) {
- self.resolve_type(&*binding.ty);
- }
-
- // A special case for sugared associated type paths `T::A` where `T` is
- // a type parameter and `A` is an associated type on some bound of `T`.
- if namespace == TypeNS && path.segments.len() == 2 {
- match self.resolve_identifier(path.segments[0].identifier,
- TypeNS,
- true,
- path.span) {
- Some((def, last_private)) => {
- match def {
- DefTyParam(_, did, _) => {
- let def = DefAssociatedPath(TyParamProvenance::FromParam(did),
- path.segments.last()
- .unwrap().identifier);
- return Some((def, last_private));
- }
- DefSelfTy(nid) => {
- let def = DefAssociatedPath(TyParamProvenance::FromSelf(local_def(nid)),
- path.segments.last()
- .unwrap().identifier);
- return Some((def, last_private));
- }
- _ => {}
- }
- }
- _ => {}
- }
- }
-
- if path.global {
- return self.resolve_crate_relative_path(path, namespace);
- }
-
- // Try to find a path to an item in a module.
- let unqualified_def =
- self.resolve_identifier(path.segments
- .last().unwrap()
- .identifier,
- namespace,
- check_ribs,
- path.span);
-
- if path.segments.len() > 1 {
- let def = self.resolve_module_relative_path(path, namespace);
- match (def, unqualified_def) {
- (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => {
- self.session
- .add_lint(lint::builtin::UNUSED_QUALIFICATIONS,
- id,
- path.span,
- "unnecessary qualification".to_string());
- }
- _ => ()
- }
-
- return def;
- }
-
- return unqualified_def;
- }
-
- // resolve a single identifier (used as a varref)
- fn resolve_identifier(&mut self,
- identifier: Ident,
- namespace: Namespace,
- check_ribs: bool,
- span: Span)
- -> Option<(Def, LastPrivate)> {
- if check_ribs {
- match self.resolve_identifier_in_local_ribs(identifier,
- namespace,
- span) {
- Some(def) => {
- return Some((def, LastMod(AllPublic)));
- }
- None => {
- // Continue.
- }
- }
- }
-
- return self.resolve_item_by_name_in_lexical_scope(identifier.name, namespace);
- }
-
- // FIXME #4952: Merge me with resolve_name_in_module?
- fn resolve_definition_of_name_in_module(&mut self,
- containing_module: Rc<Module>,
- name: Name,
- namespace: Namespace)
- -> NameDefinition {
- // First, search children.
- self.populate_module_if_necessary(&containing_module);
-
- match containing_module.children.borrow().get(&name) {
- Some(child_name_bindings) => {
- match child_name_bindings.def_for_namespace(namespace) {
- Some(def) => {
- // Found it. Stop the search here.
- let p = child_name_bindings.defined_in_public_namespace(
- namespace);
- let lp = if p {LastMod(AllPublic)} else {
- LastMod(DependsOn(def.def_id()))
- };
- return ChildNameDefinition(def, lp);
- }
- None => {}
- }
- }
- None => {}
- }
-
- // Next, search import resolutions.
- match containing_module.import_resolutions.borrow().get(&name) {
- Some(import_resolution) if import_resolution.is_public => {
- if let Some(target) = (*import_resolution).target_for_namespace(namespace) {
- match target.bindings.def_for_namespace(namespace) {
- Some(def) => {
- // Found it.
- let id = import_resolution.id(namespace);
- // track imports and extern crates as well
- self.used_imports.insert((id, namespace));
- match target.target_module.def_id.get() {
- Some(DefId{krate: kid, ..}) => {
- self.used_crates.insert(kid);
- },
- _ => {}
- }
- return ImportNameDefinition(def, LastMod(AllPublic));
- }
- None => {
- // This can happen with external impls, due to
- // the imperfect way we read the metadata.
- }
- }
- }
- }
- Some(..) | None => {} // Continue.
- }
-
- // Finally, search through external children.
- if namespace == TypeNS {
- if let Some(module) = containing_module.external_module_children.borrow()
- .get(&name).cloned() {
- if let Some(def_id) = module.def_id.get() {
- // track used crates
- self.used_crates.insert(def_id.krate);
- let lp = if module.is_public {LastMod(AllPublic)} else {
- LastMod(DependsOn(def_id))
- };
- return ChildNameDefinition(DefMod(def_id), lp);
- }
- }
- }
-
- return NoNameDefinition;
- }
-
- // resolve a "module-relative" path, e.g. a::b::c
- fn resolve_module_relative_path(&mut self,
- path: &Path,
- namespace: Namespace)
- -> Option<(Def, LastPrivate)> {
- let module_path = path.segments.init().iter()
- .map(|ps| ps.identifier.name)
- .collect::<Vec<_>>();
-
- let containing_module;
- let last_private;
- let module = self.current_module.clone();
- match self.resolve_module_path(module,
- module_path.as_slice(),
- UseLexicalScope,
- path.span,
- PathSearch) {
- Failed(err) => {
- let (span, msg) = match err {
- Some((span, msg)) => (span, msg),
- None => {
- let msg = format!("Use of undeclared type or module `{}`",
- self.names_to_string(module_path.as_slice()));
- (path.span, msg)
- }
- };
-
- self.resolve_error(span, format!("failed to resolve. {}",
- msg.as_slice()));
- return None;
- }
- Indeterminate => panic!("indeterminate unexpected"),
- Success((resulting_module, resulting_last_private)) => {
- containing_module = resulting_module;
- last_private = resulting_last_private;
- }
- }
-
- let name = path.segments.last().unwrap().identifier.name;
- let def = match self.resolve_definition_of_name_in_module(containing_module.clone(),
- name,
- namespace) {
- NoNameDefinition => {
- // We failed to resolve the name. Report an error.
- return None;
- }
- ChildNameDefinition(def, lp) | ImportNameDefinition(def, lp) => {
- (def, last_private.or(lp))
- }
- };
- if let Some(DefId{krate: kid, ..}) = containing_module.def_id.get() {
- self.used_crates.insert(kid);
- }
- return Some(def);
- }
-
- /// Invariant: This must be called only during main resolution, not during
- /// import resolution.
- fn resolve_crate_relative_path(&mut self,
- path: &Path,
- namespace: Namespace)
- -> Option<(Def, LastPrivate)> {
- let module_path = path.segments.init().iter()
- .map(|ps| ps.identifier.name)
- .collect::<Vec<_>>();
-
- let root_module = self.graph_root.get_module();
-
- let containing_module;
- let last_private;
- match self.resolve_module_path_from_root(root_module,
- module_path.as_slice(),
- 0,
- path.span,
- PathSearch,
- LastMod(AllPublic)) {
- Failed(err) => {
- let (span, msg) = match err {
- Some((span, msg)) => (span, msg),
- None => {
- let msg = format!("Use of undeclared module `::{}`",
- self.names_to_string(module_path.as_slice()));
- (path.span, msg)
- }
- };
-
- self.resolve_error(span, format!("failed to resolve. {}",
- msg.as_slice()));
- return None;
- }
-
- Indeterminate => {
- panic!("indeterminate unexpected");
- }
-
- Success((resulting_module, resulting_last_private)) => {
- containing_module = resulting_module;
- last_private = resulting_last_private;
- }
- }
-
- let name = path.segments.last().unwrap().identifier.name;
- match self.resolve_definition_of_name_in_module(containing_module,
- name,
- namespace) {
- NoNameDefinition => {
- // We failed to resolve the name. Report an error.
- return None;
- }
- ChildNameDefinition(def, lp) | ImportNameDefinition(def, lp) => {
- return Some((def, last_private.or(lp)));
- }
- }
- }
-
- fn resolve_identifier_in_local_ribs(&mut self,
- ident: Ident,
- namespace: Namespace,
- span: Span)
- -> Option<Def> {
- // Check the local set of ribs.
- let search_result = match namespace {
- ValueNS => {
- let renamed = mtwt::resolve(ident);
- self.search_ribs(self.value_ribs.as_slice(), renamed, span)
- }
- TypeNS => {
- let name = ident.name;
- self.search_ribs(self.type_ribs.as_slice(), name, span)
- }
- };
-
- match search_result {
- Some(DlDef(def)) => {
- debug!("(resolving path in local ribs) resolved `{}` to \
- local: {}",
- token::get_ident(ident),
- def);
- return Some(def);
- }
- Some(DlField) | Some(DlImpl(_)) | None => {
- return None;
- }
- }
- }
-
- fn resolve_item_by_name_in_lexical_scope(&mut self,
- name: Name,
- namespace: Namespace)
- -> Option<(Def, LastPrivate)> {
- // Check the items.
- let module = self.current_module.clone();
- match self.resolve_item_in_lexical_scope(module,
- name,
- namespace) {
- Success((target, _)) => {
- match (*target.bindings).def_for_namespace(namespace) {
- None => {
- // This can happen if we were looking for a type and
- // found a module instead. Modules don't have defs.
- debug!("(resolving item path by identifier in lexical \
- scope) failed to resolve {} after success...",
- token::get_name(name));
- return None;
- }
- Some(def) => {
- debug!("(resolving item path in lexical scope) \
- resolved `{}` to item",
- token::get_name(name));
- // This lookup is "all public" because it only searched
- // for one identifier in the current module (couldn't
- // have passed through reexports or anything like that.
- return Some((def, LastMod(AllPublic)));
- }
- }
- }
- Indeterminate => {
- panic!("unexpected indeterminate result");
- }
- Failed(err) => {
- match err {
- Some((span, msg)) =>
- self.resolve_error(span, format!("failed to resolve. {}", msg)),
- None => ()
- }
-
- debug!("(resolving item path by identifier in lexical scope) \
- failed to resolve {}", token::get_name(name));
- return None;
- }
- }
- }
-
- fn with_no_errors<T, F>(&mut self, f: F) -> T where
- F: FnOnce(&mut Resolver) -> T,
- {
- self.emit_errors = false;
- let rs = f(self);
- self.emit_errors = true;
- rs
- }
-
- fn resolve_error<T: Str>(&self, span: Span, s: T) {
- if self.emit_errors {
- self.session.span_err(span, s.as_slice());
- }
- }
-
- fn find_fallback_in_self_type(&mut self, name: Name) -> FallbackSuggestion {
- fn extract_path_and_node_id(t: &Ty, allow: FallbackChecks)
- -> Option<(Path, NodeId, FallbackChecks)> {
- match t.node {
- TyPath(ref path, node_id) => Some((path.clone(), node_id, allow)),
- TyPtr(ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, OnlyTraitAndStatics),
- TyRptr(_, ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, allow),
- // This doesn't handle the remaining `Ty` variants as they are not
- // that commonly the self_type, it might be interesting to provide
- // support for those in future.
- _ => None,
- }
- }
-
- fn get_module(this: &mut Resolver, span: Span, name_path: &[ast::Name])
- -> Option<Rc<Module>> {
- let root = this.current_module.clone();
- let last_name = name_path.last().unwrap();
-
- if name_path.len() == 1 {
- match this.primitive_type_table.primitive_types.get(last_name) {
- Some(_) => None,
- None => {
- match this.current_module.children.borrow().get(last_name) {
- Some(child) => child.get_module_if_available(),
- None => None
- }
- }
- }
- } else {
- match this.resolve_module_path(root,
- name_path.as_slice(),
- UseLexicalScope,
- span,
- PathSearch) {
- Success((module, _)) => Some(module),
- _ => None
- }
- }
- }
-
- let (path, node_id, allowed) = match self.current_self_type {
- Some(ref ty) => match extract_path_and_node_id(ty, Everything) {
- Some(x) => x,
- None => return NoSuggestion,
- },
- None => return NoSuggestion,
- };
-
- if allowed == Everything {
- // Look for a field with the same name in the current self_type.
- match self.def_map.borrow().get(&node_id) {
- Some(&DefTy(did, _))
- | Some(&DefStruct(did))
- | Some(&DefVariant(_, did, _)) => match self.structs.get(&did) {
- None => {}
- Some(fields) => {
- if fields.iter().any(|&field_name| name == field_name) {
- return Field;
- }
- }
- },
- _ => {} // Self type didn't resolve properly
- }
- }
-
- let name_path = path.segments.iter().map(|seg| seg.identifier.name).collect::<Vec<_>>();
-
- // Look for a method in the current self type's impl module.
- match get_module(self, path.span, name_path.as_slice()) {
- Some(module) => match module.children.borrow().get(&name) {
- Some(binding) => {
- let p_str = self.path_names_to_string(&path);
- match binding.def_for_namespace(ValueNS) {
- Some(DefStaticMethod(_, provenance)) => {
- match provenance {
- FromImpl(_) => return StaticMethod(p_str),
- FromTrait(_) => unreachable!()
- }
- }
- Some(DefMethod(_, None, _)) if allowed == Everything => return Method,
- Some(DefMethod(_, Some(_), _)) => return TraitItem,
- _ => ()
- }
- }
- None => {}
- },
- None => {}
- }
-
- // Look for a method in the current trait.
- match self.current_trait_ref {
- Some((did, ref trait_ref)) => {
- let path_str = self.path_names_to_string(&trait_ref.path);
-
- match self.trait_item_map.get(&(name, did)) {
- Some(&StaticMethodTraitItemKind) => {
- return TraitMethod(path_str)
- }
- Some(_) => return TraitItem,
- None => {}
- }
- }
- None => {}
- }
-
- NoSuggestion
- }
-
- fn find_best_match_for_name(&mut self, name: &str, max_distance: uint)
- -> Option<String> {
- let this = &mut *self;
-
- let mut maybes: Vec<token::InternedString> = Vec::new();
- let mut values: Vec<uint> = Vec::new();
-
- for rib in this.value_ribs.iter().rev() {
- for (&k, _) in rib.bindings.iter() {
- maybes.push(token::get_name(k));
- values.push(uint::MAX);
- }
- }
-
- let mut smallest = 0;
- for (i, other) in maybes.iter().enumerate() {
- values[i] = name.lev_distance(other.get());
-
- if values[i] <= values[smallest] {
- smallest = i;
- }
- }
-
- if values.len() > 0 &&
- values[smallest] != uint::MAX &&
- values[smallest] < name.len() + 2 &&
- values[smallest] <= max_distance &&
- name != maybes[smallest].get() {
-
- Some(maybes[smallest].get().to_string())
-
- } else {
- None
- }
- }
-
- fn resolve_expr(&mut self, expr: &Expr) {
- // First, record candidate traits for this expression if it could
- // result in the invocation of a method call.
-
- self.record_candidate_traits_for_expr_if_necessary(expr);
-
- // Next, resolve the node.
- match expr.node {
- // The interpretation of paths depends on whether the path has
- // multiple elements in it or not.
-
- ExprPath(ref path) => {
- // This is a local path in the value namespace. Walk through
- // scopes looking for it.
-
- let path_name = self.path_names_to_string(path);
-
- match self.resolve_path(expr.id, path, ValueNS, true) {
- // Check if struct variant
- Some((DefVariant(_, _, true), _)) => {
- self.resolve_error(expr.span,
- format!("`{}` is a struct variant name, but \
- this expression \
- uses it like a function name",
- path_name).as_slice());
-
- self.session.span_help(expr.span,
- format!("Did you mean to write: \
- `{} {{ /* fields */ }}`?",
- path_name).as_slice());
- }
- Some(def) => {
- // Write the result into the def map.
- debug!("(resolving expr) resolved `{}`",
- path_name);
-
- self.record_def(expr.id, def);
- }
- None => {
- // Be helpful if the name refers to a struct
- // (The pattern matching def_tys where the id is in self.structs
- // matches on regular structs while excluding tuple- and enum-like
- // structs, which wouldn't result in this error.)
- match self.with_no_errors(|this|
- this.resolve_path(expr.id, path, TypeNS, false)) {
- Some((DefTy(struct_id, _), _))
- if self.structs.contains_key(&struct_id) => {
- self.resolve_error(expr.span,
- format!("`{}` is a structure name, but \
- this expression \
- uses it like a function name",
- path_name).as_slice());
-
- self.session.span_help(expr.span,
- format!("Did you mean to write: \
- `{} {{ /* fields */ }}`?",
- path_name).as_slice());
-
- }
- _ => {
- let mut method_scope = false;
- self.value_ribs.iter().rev().all(|rib| {
- let res = match *rib {
- Rib { bindings: _, kind: MethodRibKind(_, _) } => true,
- Rib { bindings: _, kind: ItemRibKind } => false,
- _ => return true, // Keep advancing
- };
-
- method_scope = res;
- false // Stop advancing
- });
-
- if method_scope && token::get_name(self.self_name).get()
- == path_name {
- self.resolve_error(
- expr.span,
- "`self` is not available \
- in a static method. Maybe a \
- `self` argument is missing?");
- } else {
- 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
- self.find_best_match_for_name(path_name.as_slice(), 5)
- .map_or("".to_string(),
- |x| format!("`{}`", x))
- }
- Field =>
- format!("`self.{}`", path_name),
- Method
- | TraitItem =>
- format!("to call `self.{}`", path_name),
- TraitMethod(path_str)
- | StaticMethod(path_str) =>
- format!("to call `{}::{}`", path_str, path_name)
- };
-
- if msg.len() > 0 {
- msg = format!(". Did you mean {}?", msg)
- }
-
- self.resolve_error(
- expr.span,
- format!("unresolved name `{}`{}",
- path_name,
- msg).as_slice());
- }
- }
- }
- }
- }
-
- visit::walk_expr(self, expr);
- }
-
- ExprClosure(capture_clause, _, ref fn_decl, ref block) => {
- self.capture_mode_map.insert(expr.id, capture_clause);
- self.resolve_function(ClosureRibKind(expr.id, ast::DUMMY_NODE_ID),
- Some(&**fn_decl), NoTypeParameters,
- &**block);
- }
-
- ExprStruct(ref path, _, _) => {
- // Resolve the path to the structure it goes to. We don't
- // check to ensure that the path is actually a structure; that
- // is checked later during typeck.
- match self.resolve_path(expr.id, path, TypeNS, false) {
- Some(definition) => self.record_def(expr.id, definition),
- result => {
- debug!("(resolving expression) didn't find struct \
- def: {}", result);
- let msg = format!("`{}` does not name a structure",
- self.path_names_to_string(path));
- self.resolve_error(path.span, msg.as_slice());
- }
- }
-
- visit::walk_expr(self, expr);
- }
-
- ExprLoop(_, Some(label)) | ExprWhile(_, _, Some(label)) => {
- self.with_label_rib(|this| {
- let def_like = DlDef(DefLabel(expr.id));
-
- {
- let rib = this.label_ribs.last_mut().unwrap();
- let renamed = mtwt::resolve(label);
- rib.bindings.insert(renamed, def_like);
- }
-
- visit::walk_expr(this, expr);
- })
- }
-
- ExprForLoop(ref pattern, ref head, ref body, optional_label) => {
- self.resolve_expr(&**head);
-
- self.value_ribs.push(Rib::new(NormalRibKind));
-
- self.resolve_pattern(&**pattern,
- LocalIrrefutableMode,
- &mut HashMap::new());
-
- match optional_label {
- None => {}
- Some(label) => {
- self.label_ribs
- .push(Rib::new(NormalRibKind));
- let def_like = DlDef(DefLabel(expr.id));
-
- {
- let rib = self.label_ribs.last_mut().unwrap();
- let renamed = mtwt::resolve(label);
- rib.bindings.insert(renamed, def_like);
- }
- }
- }
-
- self.resolve_block(&**body);
-
- if optional_label.is_some() {
- drop(self.label_ribs.pop())
- }
-
- self.value_ribs.pop();
- }
-
- ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
- let renamed = mtwt::resolve(label);
- match self.search_ribs(self.label_ribs.as_slice(),
- renamed, expr.span) {
- None => {
- self.resolve_error(
- expr.span,
- format!("use of undeclared label `{}`",
- token::get_ident(label)).as_slice())
- }
- Some(DlDef(def @ DefLabel(_))) => {
- // Since this def is a label, it is never read.
- self.record_def(expr.id, (def, LastMod(AllPublic)))
- }
- Some(_) => {
- self.session.span_bug(expr.span,
- "label wasn't mapped to a \
- label def!")
- }
- }
- }
-
- _ => {
- visit::walk_expr(self, expr);
- }
- }
- }
-
- fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
- match expr.node {
- ExprField(_, ident) => {
- // FIXME(#6890): Even though you can't treat a method like a
- // field, we need to add any trait methods we find that match
- // the field name so that we can do some nice error reporting
- // later on in typeck.
- let traits = self.search_for_traits_containing_method(ident.node.name);
- self.trait_map.insert(expr.id, traits);
- }
- ExprMethodCall(ident, _, _) => {
- debug!("(recording candidate traits for expr) recording \
- traits for {}",
- expr.id);
- let traits = self.search_for_traits_containing_method(ident.node.name);
- self.trait_map.insert(expr.id, traits);
- }
- _ => {
- // Nothing to do.
- }
- }
- }
-
- fn search_for_traits_containing_method(&mut self, name: Name) -> Vec<DefId> {
- debug!("(searching for traits containing method) looking for '{}'",
- token::get_name(name));
-
- fn add_trait_info(found_traits: &mut Vec<DefId>,
- trait_def_id: DefId,
- name: Name) {
- debug!("(adding trait info) found trait {}:{} for method '{}'",
- trait_def_id.krate,
- trait_def_id.node,
- token::get_name(name));
- found_traits.push(trait_def_id);
- }
-
- let mut found_traits = Vec::new();
- let mut search_module = self.current_module.clone();
- loop {
- // Look for the current trait.
- match self.current_trait_ref {
- Some((trait_def_id, _)) => {
- if self.trait_item_map.contains_key(&(name, trait_def_id)) {
- add_trait_info(&mut found_traits, trait_def_id, name);
- }
- }
- None => {} // Nothing to do.
- }
-
- // Look for trait children.
- self.populate_module_if_necessary(&search_module);
-
- {
- for (_, child_names) in search_module.children.borrow().iter() {
- let def = match child_names.def_for_namespace(TypeNS) {
- Some(def) => def,
- None => continue
- };
- let trait_def_id = match def {
- DefTrait(trait_def_id) => trait_def_id,
- _ => continue,
- };
- if self.trait_item_map.contains_key(&(name, trait_def_id)) {
- add_trait_info(&mut found_traits, trait_def_id, name);
- }
- }
- }
-
- // Look for imports.
- for (_, import) in search_module.import_resolutions.borrow().iter() {
- let target = match import.target_for_namespace(TypeNS) {
- None => continue,
- Some(target) => target,
- };
- let did = match target.bindings.def_for_namespace(TypeNS) {
- Some(DefTrait(trait_def_id)) => trait_def_id,
- Some(..) | None => continue,
- };
- if self.trait_item_map.contains_key(&(name, did)) {
- add_trait_info(&mut found_traits, did, name);
- self.used_imports.insert((import.type_id, TypeNS));
- if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
- self.used_crates.insert(kid);
- }
- }
- }
-
- match search_module.parent_link.clone() {
- NoParentLink | ModuleParentLink(..) => break,
- BlockParentLink(parent_module, _) => {
- search_module = parent_module.upgrade().unwrap();
- }
- }
- }
-
- found_traits
- }
-
- fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) {
- debug!("(recording def) recording {} for {}, last private {}",
- def, node_id, lp);
- assert!(match lp {LastImport{..} => false, _ => true},
- "Import should only be used for `use` directives");
- self.last_private.insert(node_id, lp);
-
- match self.def_map.borrow_mut().entry(node_id) {
- // Resolve appears to "resolve" the same ID multiple
- // times, so here is a sanity check it at least comes to
- // the same conclusion! - nmatsakis
- Occupied(entry) => if def != *entry.get() {
- self.session
- .bug(format!("node_id {} resolved first to {} and \
- then {}",
- node_id,
- *entry.get(),
- def).as_slice());
- },
- Vacant(entry) => { entry.set(def); },
- }
- }
-
- fn enforce_default_binding_mode(&mut self,
- pat: &Pat,
- pat_binding_mode: BindingMode,
- descr: &str) {
- match pat_binding_mode {
- BindByValue(_) => {}
- BindByRef(..) => {
- self.resolve_error(pat.span,
- format!("cannot use `ref` binding mode \
- with {}",
- descr).as_slice());
- }
- }
- }
-
- //
- // Unused import checking
- //
- // Although this is mostly a lint pass, it lives in here because it depends on
- // resolve data structures and because it finalises the privacy information for
- // `use` directives.
- //
-
- fn check_for_unused_imports(&mut self, krate: &ast::Crate) {
- let mut visitor = UnusedImportCheckVisitor{ resolver: self };
- visit::walk_crate(&mut visitor, krate);
- }
-
- fn check_for_item_unused_imports(&mut self, vi: &ViewItem) {
- // Ignore is_public import statements because there's no way to be sure
- // whether they're used or not. Also ignore imports with a dummy span
- // because this means that they were generated in some fashion by the
- // compiler and we don't need to consider them.
- if vi.vis == Public { return }
- if vi.span == DUMMY_SP { return }
-
- match vi.node {
- ViewItemExternCrate(_, _, id) => {
- if let Some(crate_num) = self.session.cstore.find_extern_mod_stmt_cnum(id) {
- if !self.used_crates.contains(&crate_num) {
- self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATES,
- id,
- vi.span,
- "unused extern crate".to_string());
- }
- }
- },
- ViewItemUse(ref p) => {
- match p.node {
- ViewPathSimple(_, _, id) => self.finalize_import(id, p.span),
-
- ViewPathList(_, ref list, _) => {
- for i in list.iter() {
- self.finalize_import(i.node.id(), i.span);
- }
- },
- ViewPathGlob(_, id) => {
- if !self.used_imports.contains(&(id, TypeNS)) &&
- !self.used_imports.contains(&(id, ValueNS)) {
- self.session
- .add_lint(lint::builtin::UNUSED_IMPORTS,
- id,
- p.span,
- "unused import".to_string());
- }
- },
- }
- }
- }
- }
-
- // We have information about whether `use` (import) directives are actually used now.
- // If an import is not used at all, we signal a lint error. If an import is only used
- // for a single namespace, we remove the other namespace from the recorded privacy
- // information. That means in privacy.rs, we will only check imports and namespaces
- // which are used. In particular, this means that if an import could name either a
- // public or private item, we will check the correct thing, dependent on how the import
- // is used.
- fn finalize_import(&mut self, id: NodeId, span: Span) {
- debug!("finalizing import uses for {}",
- self.session.codemap().span_to_snippet(span));
-
- if !self.used_imports.contains(&(id, TypeNS)) &&
- !self.used_imports.contains(&(id, ValueNS)) {
- self.session.add_lint(lint::builtin::UNUSED_IMPORTS,
- id,
- span,
- "unused import".to_string());
- }
-
- let (v_priv, t_priv) = match self.last_private.get(&id) {
- Some(&LastImport {
- value_priv: v,
- value_used: _,
- type_priv: t,
- type_used: _
- }) => (v, t),
- Some(_) => {
- panic!("we should only have LastImport for `use` directives")
- }
- _ => return,
- };
-
- let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
- Used
- } else {
- Unused
- };
- let t_used = if self.used_imports.contains(&(id, TypeNS)) {
- Used
- } else {
- Unused
- };
-
- match (v_priv, t_priv) {
- // Since some items may be both in the value _and_ type namespaces (e.g., structs)
- // we might have two LastPrivates pointing at the same thing. There is no point
- // checking both, so lets not check the value one.
- (Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused,
- _ => {},
- }
-
- self.last_private.insert(id, LastImport{value_priv: v_priv,
- value_used: v_used,
- type_priv: t_priv,
- type_used: t_used});
- }
-
- //
- // Diagnostics
- //
- // Diagnostics are not particularly efficient, because they're rarely
- // hit.
- //
-
- /// A somewhat inefficient routine to obtain the name of a module.
- fn module_to_string(&self, module: &Module) -> String {
- let mut names = Vec::new();
-
- fn collect_mod(names: &mut Vec<ast::Name>, module: &Module) {
- match module.parent_link {
- NoParentLink => {}
- ModuleParentLink(ref module, name) => {
- names.push(name);
- collect_mod(names, &*module.upgrade().unwrap());
- }
- BlockParentLink(ref module, _) => {
- // danger, shouldn't be ident?
- names.push(special_idents::opaque.name);
- collect_mod(names, &*module.upgrade().unwrap());
- }
- }
- }
- collect_mod(&mut names, module);
-
- if names.len() == 0 {
- return "???".to_string();
- }
- self.names_to_string(names.into_iter().rev()
- .collect::<Vec<ast::Name>>()
- .as_slice())
- }
-
- #[allow(dead_code)] // useful for debugging
- fn dump_module(&mut self, module_: Rc<Module>) {
- debug!("Dump of module `{}`:", self.module_to_string(&*module_));
-
- debug!("Children:");
- self.populate_module_if_necessary(&module_);
- for (&name, _) in module_.children.borrow().iter() {
- debug!("* {}", token::get_name(name));
- }
-
- debug!("Import resolutions:");
- let import_resolutions = module_.import_resolutions.borrow();
- for (&name, import_resolution) in import_resolutions.iter() {
- let value_repr;
- match import_resolution.target_for_namespace(ValueNS) {
- None => { value_repr = "".to_string(); }
- Some(_) => {
- value_repr = " value:?".to_string();
- // FIXME #4954
- }
- }
-
- let type_repr;
- match import_resolution.target_for_namespace(TypeNS) {
- None => { type_repr = "".to_string(); }
- Some(_) => {
- type_repr = " type:?".to_string();
- // FIXME #4954
- }
- }
-
- debug!("* {}:{}{}", token::get_name(name), value_repr, type_repr);
- }
- }
-}
-
-pub struct CrateMap {
- pub def_map: DefMap,
- pub freevars: RefCell<FreevarMap>,
- pub capture_mode_map: RefCell<CaptureModeMap>,
- pub exp_map2: ExportMap2,
- pub trait_map: TraitMap,
- pub external_exports: ExternalExports,
- pub last_private_map: LastPrivateMap,
-}
-
-/// Entry point to crate resolution.
-pub fn resolve_crate(session: &Session,
- _: &LanguageItems,
- krate: &Crate)
- -> CrateMap {
- let mut resolver = Resolver::new(session, krate.span);
- resolver.resolve(krate);
- CrateMap {
- def_map: resolver.def_map,
- freevars: resolver.freevars,
- capture_mode_map: RefCell::new(resolver.capture_mode_map),
- exp_map2: resolver.export_map2,
- trait_map: resolver.trait_map,
- external_exports: resolver.external_exports,
- last_private_map: resolver.last_private,
- }
-}
use self::ScopeChain::*;
use session::Session;
-use middle::def;
+use middle::def::{mod, DefMap};
use middle::region;
-use middle::resolve::DefMap;
use middle::subst;
use middle::ty;
use std::fmt;
}
for predicate in generics.where_clause.predicates.iter() {
match predicate {
- &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ident,
+ &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ref bounded_ty,
ref bounds,
- span,
.. }) => {
- self.visit_ident(span, ident);
+ self.visit_ty(&**bounded_ty);
visit::walk_ty_param_bounds_helper(self, bounds);
}
+ &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
+ ref bounds,
+ .. }) => {
+
+ self.visit_lifetime_ref(lifetime);
+ for bound in bounds.iter() {
+ self.visit_lifetime_ref(bound);
+ }
+ }
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ id,
ref path,
ref ty,
}
for predicate in generics.where_clause.predicates.iter() {
match predicate {
- &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounds, ..}) => {
+ &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounds,
+ ref bounded_ty,
+ ..}) => {
+ collector.visit_ty(&**bounded_ty);
visit::walk_ty_param_bounds_helper(&mut collector, bounds);
}
+ &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
+ ref bounds,
+ ..}) => {
+ collector.visit_lifetime_ref(lifetime);
+
+ for bound in bounds.iter() {
+ collector.visit_lifetime_ref(bound);
+ }
+ }
&ast::WherePredicate::EqPredicate(_) => unimplemented!()
}
}
impl Annotator {
// Determine the stability for a node based on its attributes and inherited
// stability. The stability is recorded in the index and used as the parent.
- fn annotate<F>(&mut self, id: NodeId, attrs: &Vec<Attribute>, f: F) where
+ fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
+ attrs: &Vec<Attribute>, f: F) where
F: FnOnce(&mut Annotator),
{
match attr::find_stability(attrs.as_slice()) {
}
}
None => {
- self.parent.clone().map(|stab| self.index.local.insert(id, stab));
+ if use_parent {
+ self.parent.clone().map(|stab| self.index.local.insert(id, stab));
+ }
f(self);
}
}
impl<'v> Visitor<'v> for Annotator {
fn visit_item(&mut self, i: &Item) {
- self.annotate(i.id, &i.attrs, |v| visit::walk_item(v, i));
+ // FIXME (#18969): the following is a hack around the fact
+ // that we cannot currently annotate the stability of
+ // `deriving`. Basically, we do *not* allow stability
+ // inheritance on trait implementations, so that derived
+ // implementations appear to be unannotated. This then allows
+ // derived implementations to be automatically tagged with the
+ // stability of the trait. This is WRONG, but expedient to get
+ // libstd stabilized for the 1.0 release.
+ let use_parent = match i.node {
+ ast::ItemImpl(_, _, Some(_), _, _) => false,
+ _ => true,
+ };
+
+ self.annotate(i.id, use_parent, &i.attrs, |v| visit::walk_item(v, i));
if let ast::ItemStruct(ref sd, _) = i.node {
sd.ctor_id.map(|id| {
- self.annotate(id, &i.attrs, |_| {})
+ self.annotate(id, true, &i.attrs, |_| {})
});
}
}
_: &'v Block, _: Span, _: NodeId) {
if let FkMethod(_, _, meth) = fk {
// Methods are not already annotated, so we annotate it
- self.annotate(meth.id, &meth.attrs, |_| {});
+ self.annotate(meth.id, true, &meth.attrs, |_| {});
}
// Items defined in a function body have no reason to have
// a stability attribute, so we don't recurse.
TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs),
};
- self.annotate(id, attrs, |v| visit::walk_trait_item(v, t));
+ self.annotate(id, true, attrs, |v| visit::walk_trait_item(v, t));
}
fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
- self.annotate(var.node.id, &var.node.attrs, |v| visit::walk_variant(v, var, g))
+ self.annotate(var.node.id, true, &var.node.attrs,
+ |v| visit::walk_variant(v, var, g))
}
fn visit_struct_field(&mut self, s: &StructField) {
- self.annotate(s.node.id, &s.node.attrs, |v| visit::walk_struct_field(v, s));
+ self.annotate(s.node.id, true, &s.node.attrs,
+ |v| visit::walk_struct_field(v, s));
+ }
+
+ fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
+ self.annotate(i.id, &i.attrs, |_| {});
}
}
},
parent: None
};
- annotator.annotate(ast::CRATE_NODE_ID, &krate.attrs, |v| visit::walk_crate(v, krate));
+ annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs,
+ |v| visit::walk_crate(v, krate));
annotator.index
}
}
match ty::trait_item_of_item(tcx, id) {
Some(ty::MethodTraitItemId(trait_method_id))
if trait_method_id != id => {
- lookup(tcx, trait_method_id)
- }
- _ if is_local(id) => {
- tcx.stability.borrow().local.get(&id.node).cloned()
- }
- _ => {
- let stab = csearch::get_stability(&tcx.sess.cstore, id);
- let mut index = tcx.stability.borrow_mut();
- (*index).extern_cache.insert(id, stab.clone());
- stab
+ return lookup(tcx, trait_method_id)
}
+ _ => {}
}
+
+ let item_stab = if is_local(id) {
+ tcx.stability.borrow().local.get(&id.node).cloned()
+ } else {
+ let stab = csearch::get_stability(&tcx.sess.cstore, id);
+ let mut index = tcx.stability.borrow_mut();
+ (*index).extern_cache.insert(id, stab.clone());
+ stab
+ };
+
+ item_stab.or_else(|| {
+ if let Some(trait_id) = ty::trait_id_of_impl(tcx, id) {
+ // FIXME (#18969): for the time being, simply use the
+ // stability of the trait to determine the stability of any
+ // unmarked impls for it. See FIXME above for more details.
+
+ lookup(tcx, trait_id)
+ } else {
+ None
+ }
+ })
}
use middle::mem_categorization::Typer;
use middle::ty::{mod, Ty};
use std::collections::HashSet;
-use std::collections::hash_map::{Occupied, Vacant};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::default::Default;
use std::rc::Rc;
use syntax::ast;
use metadata::csearch;
use middle;
use middle::const_eval;
-use middle::def;
+use middle::def::{mod, DefMap, ExportMap};
use middle::dependency_format;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem};
use middle::lang_items::{FnOnceTraitLangItem, TyDescStructLangItem};
use middle::mem_categorization as mc;
use middle::region;
-use middle::resolve;
use middle::resolve_lifetime;
use middle::infer;
use middle::stability;
use std::ops;
use std::rc::Rc;
use collections::enum_set::{EnumSet, CLike};
-use std::collections::hash_map::{HashMap, Occupied, Vacant};
+use std::collections::hash_map::HashMap;
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax::abi;
use syntax::ast::{CrateNum, DefId, DUMMY_NODE_ID, Ident, ItemTrait, LOCAL_CRATE};
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
/// The complete set of all analyses described in this module. This is
/// produced by the driver and fed to trans and later passes.
pub struct CrateAnalysis<'tcx> {
- pub exp_map2: middle::resolve::ExportMap2,
+ pub export_map: ExportMap,
pub exported_items: middle::privacy::ExportedItems,
pub public_items: middle::privacy::PublicItems,
pub ty_cx: ty::ctxt<'tcx>,
// queried from a HashSet.
interner: RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>,
pub sess: Session,
- pub def_map: resolve::DefMap,
+ pub def_map: DefMap,
pub named_region_map: resolve_lifetime::NamedRegionMap,
pub fn mk_ctxt<'tcx>(s: Session,
type_arena: &'tcx TypedArena<TyS<'tcx>>,
- dm: resolve::DefMap,
+ dm: DefMap,
named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map<'tcx>,
freevars: RefCell<FreevarMap>,
pub type CaptureModeMap = NodeMap<ast::CaptureClause>;
+// Trait method resolution
+pub type TraitMap = NodeMap<Vec<DefId>>;
+
pub fn with_freevars<T, F>(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where
F: FnOnce(&[Freevar]) -> T,
{
super_fold_trait_ref(self, t)
}
- fn fold_sty(&mut self, sty: &ty::sty<'tcx>) -> ty::sty<'tcx> {
- super_fold_sty(self, sty)
- }
-
fn fold_substs(&mut self,
substs: &subst::Substs<'tcx>)
-> subst::Substs<'tcx> {
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::sty<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::sty<'tcx> {
- folder.fold_sty(self)
- }
-}
-
impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitRef<'tcx> {
folder.fold_trait_ref(self)
// They should invoke `foo.fold_with()` to do recursive folding.
pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
- t: Ty<'tcx>)
+ ty: Ty<'tcx>)
-> Ty<'tcx> {
- let sty = t.sty.fold_with(this);
+ let sty = match ty.sty {
+ ty::ty_uniq(typ) => {
+ ty::ty_uniq(typ.fold_with(this))
+ }
+ ty::ty_ptr(ref tm) => {
+ ty::ty_ptr(tm.fold_with(this))
+ }
+ ty::ty_vec(typ, sz) => {
+ ty::ty_vec(typ.fold_with(this), sz)
+ }
+ ty::ty_open(typ) => {
+ ty::ty_open(typ.fold_with(this))
+ }
+ ty::ty_enum(tid, ref substs) => {
+ ty::ty_enum(tid, substs.fold_with(this))
+ }
+ ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
+ ty::ty_trait(box ty::TyTrait {
+ principal: (*principal).fold_with(this),
+ bounds: bounds.fold_with(this),
+ })
+ }
+ ty::ty_tup(ref ts) => {
+ ty::ty_tup(ts.fold_with(this))
+ }
+ ty::ty_bare_fn(ref f) => {
+ ty::ty_bare_fn(f.fold_with(this))
+ }
+ ty::ty_closure(ref f) => {
+ ty::ty_closure(box f.fold_with(this))
+ }
+ ty::ty_rptr(r, ref tm) => {
+ ty::ty_rptr(r.fold_with(this), tm.fold_with(this))
+ }
+ ty::ty_struct(did, ref substs) => {
+ ty::ty_struct(did, substs.fold_with(this))
+ }
+ ty::ty_unboxed_closure(did, ref region, ref substs) => {
+ ty::ty_unboxed_closure(did, region.fold_with(this), substs.fold_with(this))
+ }
+ ty::ty_bool | ty::ty_char | ty::ty_str |
+ ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
+ ty::ty_err | ty::ty_infer(_) |
+ ty::ty_param(..) => {
+ ty.sty.clone()
+ }
+ };
ty::mk_t(this.tcx(), sty)
}
mutbl: mt.mutbl}
}
-pub fn super_fold_sty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
- sty: &ty::sty<'tcx>)
- -> ty::sty<'tcx> {
- match *sty {
- ty::ty_uniq(typ) => {
- ty::ty_uniq(typ.fold_with(this))
- }
- ty::ty_ptr(ref tm) => {
- ty::ty_ptr(tm.fold_with(this))
- }
- ty::ty_vec(typ, sz) => {
- ty::ty_vec(typ.fold_with(this), sz)
- }
- ty::ty_open(typ) => {
- ty::ty_open(typ.fold_with(this))
- }
- ty::ty_enum(tid, ref substs) => {
- ty::ty_enum(tid, substs.fold_with(this))
- }
- ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
- ty::ty_trait(box ty::TyTrait {
- principal: (*principal).fold_with(this),
- bounds: bounds.fold_with(this),
- })
- }
- ty::ty_tup(ref ts) => {
- ty::ty_tup(ts.fold_with(this))
- }
- ty::ty_bare_fn(ref f) => {
- ty::ty_bare_fn(f.fold_with(this))
- }
- ty::ty_closure(ref f) => {
- ty::ty_closure(box f.fold_with(this))
- }
- ty::ty_rptr(r, ref tm) => {
- ty::ty_rptr(r.fold_with(this), tm.fold_with(this))
- }
- ty::ty_struct(did, ref substs) => {
- ty::ty_struct(did, substs.fold_with(this))
- }
- ty::ty_unboxed_closure(did, ref region, ref substs) => {
- ty::ty_unboxed_closure(did, region.fold_with(this), substs.fold_with(this))
- }
- ty::ty_bool | ty::ty_char | ty::ty_str |
- ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
- ty::ty_err | ty::ty_infer(_) |
- ty::ty_param(..) => {
- (*sty).clone()
- }
- }
-}
-
pub fn super_fold_trait_store<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
trait_store: ty::TraitStore)
-> ty::TraitStore {
pub use self::OutputType::*;
pub use self::DebugInfoLevel::*;
-use session::{early_error, early_warn, Session};
+use session::{early_error, Session};
use rustc_back::target::Target;
use lint;
use syntax::parse::token::InternedString;
use std::collections::HashMap;
-use std::collections::hash_map::{Occupied, Vacant};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use getopts::{optopt, optmulti, optflag, optflagopt};
use getopts;
use std::cell::{RefCell};
OutputTypeLlvmAssembly,
OutputTypeObject,
OutputTypeExe,
+ OutputTypeDepInfo,
}
#[deriving(Clone)]
pub debugging_opts: u64,
/// Whether to write dependency files. It's (enabled, optional filename).
pub write_dependency_info: (bool, Option<Path>),
- /// Crate id-related things to maybe print. It's (crate_name, crate_file_name).
- pub print_metas: (bool, bool),
+ pub prints: Vec<PrintRequest>,
pub cg: CodegenOptions,
pub color: ColorConfig,
pub externs: HashMap<String, Vec<String>>,
pub alt_std_name: Option<String>
}
+#[deriving(Clone, PartialEq, Eq)]
+#[allow(missing_copy_implementations)]
+pub enum PrintRequest {
+ FileNames,
+ Sysroot,
+ CrateName,
+}
+
pub enum Input {
/// Load source from file
File(Path),
OutputTypeAssembly => base.with_extension("s"),
OutputTypeLlvmAssembly => base.with_extension("ll"),
OutputTypeObject => base.with_extension("o"),
+ OutputTypeDepInfo => base.with_extension("d"),
OutputTypeExe => base,
}
}
no_analysis: false,
debugging_opts: 0,
write_dependency_info: (false, None),
- print_metas: (false, false),
+ prints: Vec::new(),
cg: basic_codegen_options(),
color: Auto,
externs: HashMap::new(),
FLOWGRAPH_PRINT_MOVES,
FLOWGRAPH_PRINT_ASSIGNS,
FLOWGRAPH_PRINT_ALL,
- PRINT_SYSROOT,
- PRINT_REGION_GRAPH
+ PRINT_REGION_GRAPH,
+ PARSE_ONLY,
+ NO_TRANS,
+ NO_ANALYSIS
]
0
}
--pretty flowgraph output", FLOWGRAPH_PRINT_ASSIGNS),
("flowgraph-print-all", "Include all dataflow analysis data in \
--pretty flowgraph output", FLOWGRAPH_PRINT_ALL),
- ("print-sysroot", "Print the sysroot as used by this rustc invocation",
- PRINT_SYSROOT),
("print-region-graph", "Prints region inference graph. \
Use with RUST_REGION_GRAPH=help for more info",
- PRINT_REGION_GRAPH)]
+ PRINT_REGION_GRAPH),
+ ("parse-only", "Parse only; do not compile, assemble, or link", PARSE_ONLY),
+ ("no-trans", "Run all passes except translation; no output", NO_TRANS),
+ ("no-analysis", "Parse and expand the source, but run no analysis and",
+ NO_TRANS),
+ ]
}
#[deriving(Clone)]
pub const parse_uint: Option<&'static str> = Some("a number");
pub const parse_passes: Option<&'static str> =
Some("a space-separated list of passes, or `all`");
+ pub const parse_opt_uint: Option<&'static str> =
+ Some("a number");
}
mod cgsetters {
}
}
+ fn parse_opt_uint(slot: &mut Option<uint>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => { *slot = from_str(s); slot.is_some() }
+ None => { *slot = None; true }
+ }
+ }
+
fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
match v {
Some("all") => {
"print remarks for these optimization passes (space separated, or \"all\")"),
no_stack_check: bool = (false, parse_bool,
"disable checks for stack exhaustion (a memory-safety hazard!)"),
+ debuginfo: Option<uint> = (None, parse_opt_uint,
+ "debug info emission level, 0 = no debug info, 1 = line tables only, \
+ 2 = full debug info with variable and type information"),
+ opt_level: Option<uint> = (None, parse_opt_uint,
+ "Optimize with possible levels 0-3"),
}
pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions
}
}
-// rustc command line options
-pub fn optgroups() -> Vec<getopts::OptGroup> {
- vec!(
+pub fn short_optgroups() -> Vec<getopts::OptGroup> {
+ vec![
optflag("h", "help", "Display this message"),
optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
optmulti("L", "", "Add a directory to the library search path", "PATH"),
assumed.", "NAME[:KIND]"),
optmulti("", "crate-type", "Comma separated list of types of crates
for the compiler to emit",
- "[bin|lib|rlib|dylib|staticlib]"),
- optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
- "[asm|bc|ir|obj|link]"),
+ "[bin|lib|rlib|dylib|staticlib|dep-info]"),
optopt("", "crate-name", "Specify the name of the crate being built",
"NAME"),
- optflag("", "print-crate-name", "Output the crate name and exit"),
- optflag("", "print-file-name", "Output the file(s) that would be written if compilation \
- continued and exit"),
- optflag("", "crate-file-name", "deprecated in favor of --print-file-name"),
+ optmulti("", "emit", "Comma separated list of types of output for \
+ the compiler to emit",
+ "[asm|llvm-bc|llvm-ir|obj|link]"),
+ optmulti("", "print", "Comma separated list of compiler information to \
+ print on stdout",
+ "[crate-name|output-file-names|sysroot]"),
optflag("g", "", "Equivalent to --debuginfo=2"),
+ optflag("O", "", "Equivalent to --opt-level=2"),
+ optopt("o", "", "Write output to <filename>", "FILENAME"),
+ optopt("", "out-dir", "Write output to compiler-chosen filename \
+ in <dir>", "DIR"),
+ optopt("", "explain", "Provide a detailed explanation of an error \
+ message", "OPT"),
+ optflag("", "test", "Build a test harness"),
+ optopt("", "target", "Target triple cpu-manufacturer-kernel[-os] \
+ to compile for (see chapter 3.4 of \
+ http://www.sourceware.org/autobook/
+ for details)",
+ "TRIPLE"),
+ optmulti("W", "warn", "Set lint warnings", "OPT"),
+ optmulti("A", "allow", "Set lint allowed", "OPT"),
+ optmulti("D", "deny", "Set lint denied", "OPT"),
+ optmulti("F", "forbid", "Set lint forbidden", "OPT"),
+ optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
+ optflag("V", "version", "Print version info and exit"),
+ optflag("v", "verbose", "Use verbose output"),
+ ]
+}
+
+// rustc command line options
+pub fn optgroups() -> Vec<getopts::OptGroup> {
+ let mut opts = short_optgroups();
+ opts.push_all(&[
+ optmulti("", "extern", "Specify where an external rust library is \
+ located",
+ "NAME=PATH"),
+ optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
+ optopt("", "sysroot", "Override the system root", "PATH"),
+ optmulti("Z", "", "Set internal debugging options", "FLAG"),
+ optopt("", "color", "Configure coloring of output:
+ auto = colorize, if output goes to a tty (default);
+ always = always colorize output;
+ never = never colorize output", "auto|always|never"),
+
+ // DEPRECATED
+ optflag("", "print-crate-name", "Output the crate name and exit"),
+ optflag("", "print-file-name", "Output the file(s) that would be \
+ written if compilation \
+ continued and exit"),
optopt("", "debuginfo", "Emit DWARF debug info to the objects created:
0 = no debug info,
1 = line-tables only (for stacktraces and breakpoints),
- 2 = full debug info with variable and type information (same as -g)", "LEVEL"),
+ 2 = full debug info with variable and type information \
+ (same as -g)", "LEVEL"),
optflag("", "no-trans", "Run all passes except translation; no output"),
- optflag("", "no-analysis",
- "Parse and expand the source, but run no analysis and produce no output"),
- optflag("O", "", "Equivalent to --opt-level=2"),
- optopt("o", "", "Write output to <filename>", "FILENAME"),
- optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
- optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
- optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
- optopt("", "explain", "Provide a detailed explanation of an error message", "OPT"),
+ optflag("", "no-analysis", "Parse and expand the source, but run no \
+ analysis and produce no output"),
+ optflag("", "parse-only", "Parse only; do not compile, assemble, \
+ or link"),
optflagopt("", "pretty",
"Pretty-print the input instead of compiling;
valid types are: `normal` (un-annotated source),
optflagopt("", "dep-info",
"Output dependency info to <filename> after compiling, \
in a format suitable for use by Makefiles", "FILENAME"),
- optopt("", "sysroot", "Override the system root", "PATH"),
- optflag("", "test", "Build a test harness"),
- optopt("", "target", "Target triple cpu-manufacturer-kernel[-os]
- to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
- for details)", "TRIPLE"),
- optmulti("W", "warn", "Set lint warnings", "OPT"),
- optmulti("A", "allow", "Set lint allowed", "OPT"),
- optmulti("D", "deny", "Set lint denied", "OPT"),
- optmulti("F", "forbid", "Set lint forbidden", "OPT"),
- optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
- optmulti("Z", "", "Set internal debugging options", "FLAG"),
- optflagopt("v", "version", "Print version info and exit", "verbose"),
- optopt("", "color", "Configure coloring of output:
- auto = colorize, if output goes to a tty (default);
- always = always colorize output;
- never = never colorize output", "auto|always|never"),
- optmulti("", "extern", "Specify where an external rust library is located",
- "NAME=PATH"),
- )
+ ]);
+ opts
}
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
.unwrap_or_else(|e| early_error(e.as_slice()));
- let parse_only = matches.opt_present("parse-only");
- let no_trans = matches.opt_present("no-trans");
- let no_analysis = matches.opt_present("no-analysis");
-
let mut lint_opts = vec!();
let mut describe_lints = false;
debugging_opts |= this_bit;
}
+ let parse_only = if matches.opt_present("parse-only") {
+ // FIXME(acrichto) uncomment deprecation warning
+ // early_warn("--parse-only is deprecated in favor of -Z parse-only");
+ true
+ } else {
+ debugging_opts & PARSE_ONLY != 0
+ };
+ let no_trans = if matches.opt_present("no-trans") {
+ // FIXME(acrichto) uncomment deprecation warning
+ // early_warn("--no-trans is deprecated in favor of -Z no-trans");
+ true
+ } else {
+ debugging_opts & NO_TRANS != 0
+ };
+ let no_analysis = if matches.opt_present("no-analysis") {
+ // FIXME(acrichto) uncomment deprecation warning
+ // early_warn("--no-analysis is deprecated in favor of -Z no-analysis");
+ true
+ } else {
+ debugging_opts & NO_ANALYSIS != 0
+ };
+
if debugging_opts & DEBUG_LLVM != 0 {
unsafe { llvm::LLVMSetDebug(1); }
}
for unparsed_output_type in unparsed_output_types.iter() {
for part in unparsed_output_type.split(',') {
let output_type = match part.as_slice() {
- "asm" => OutputTypeAssembly,
- "ir" => OutputTypeLlvmAssembly,
- "bc" => OutputTypeBitcode,
- "obj" => OutputTypeObject,
+ "asm" => OutputTypeAssembly,
+ "llvm-ir" => OutputTypeLlvmAssembly,
+ "llvm-bc" => OutputTypeBitcode,
+ "obj" => OutputTypeObject,
"link" => OutputTypeExe,
+ "dep-info" => OutputTypeDepInfo,
_ => {
early_error(format!("unknown emission type: `{}`",
part).as_slice())
output_types.push(OutputTypeExe);
}
+ let cg = build_codegen_options(matches);
+
let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
let target = matches.opt_str("target").unwrap_or(
host_triple().to_string());
if matches.opt_present("opt-level") {
early_error("-O and --opt-level both provided");
}
+ if cg.opt_level.is_some() {
+ early_error("-O and -C opt-level both provided");
+ }
Default
} else if matches.opt_present("opt-level") {
+ // FIXME(acrichto) uncomment deprecation warning
+ // early_warn("--opt-level=N is deprecated in favor of -C opt-level=N");
match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
None |
Some("0") => No,
}
}
} else {
- No
+ match cg.opt_level {
+ None => No,
+ Some(0) => No,
+ Some(1) => Less,
+ Some(2) => Default,
+ Some(3) => Aggressive,
+ Some(arg) => {
+ early_error(format!("optimization level needs to be \
+ between 0-3 (instead was `{}`)",
+ arg).as_slice());
+ }
+ }
}
};
let gc = debugging_opts & GC != 0;
if matches.opt_present("debuginfo") {
early_error("-g and --debuginfo both provided");
}
+ if cg.debuginfo.is_some() {
+ early_error("-g and -C debuginfo both provided");
+ }
FullDebugInfo
} else if matches.opt_present("debuginfo") {
+ // FIXME(acrichto) uncomment deprecation warning
+ // early_warn("--debuginfo=N is deprecated in favor of -C debuginfo=N");
match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
Some("0") => NoDebugInfo,
Some("1") => LimitedDebugInfo,
}
}
} else {
- NoDebugInfo
+ match cg.debuginfo {
+ None | Some(0) => NoDebugInfo,
+ Some(1) => LimitedDebugInfo,
+ Some(2) => FullDebugInfo,
+ Some(arg) => {
+ early_error(format!("debug info level needs to be between \
+ 0-2 (instead was `{}`)",
+ arg).as_slice());
+ }
+ }
};
let addl_lib_search_paths = matches.opt_strs("L").iter().map(|s| {
let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
let test = matches.opt_present("test");
- let write_dependency_info = (matches.opt_present("dep-info"),
- matches.opt_str("dep-info")
- .map(|p| Path::new(p)));
-
- let print_metas = (matches.opt_present("print-crate-name"),
- matches.opt_present("print-file-name") ||
- matches.opt_present("crate-file-name"));
- if matches.opt_present("crate-file-name") {
- early_warn("the --crate-file-name argument has been renamed to \
- --print-file-name");
+ let write_dependency_info = if matches.opt_present("dep-info") {
+ // FIXME(acrichto) uncomment deprecation warning
+ // early_warn("--dep-info has been deprecated in favor of --emit");
+ (true, matches.opt_str("dep-info").map(|p| Path::new(p)))
+ } else {
+ (output_types.contains(&OutputTypeDepInfo), None)
+ };
+
+ let mut prints = matches.opt_strs("print").into_iter().map(|s| {
+ match s.as_slice() {
+ "crate-name" => PrintRequest::CrateName,
+ "file-names" => PrintRequest::FileNames,
+ "sysroot" => PrintRequest::Sysroot,
+ req => {
+ early_error(format!("unknown print request `{}`", req).as_slice())
+ }
+ }
+ }).collect::<Vec<_>>();
+ if matches.opt_present("print-crate-name") {
+ // FIXME(acrichto) uncomment deprecation warning
+ // early_warn("--print-crate-name has been deprecated in favor of \
+ // --print crate-name");
+ prints.push(PrintRequest::CrateName);
+ }
+ if matches.opt_present("print-file-name") {
+ // FIXME(acrichto) uncomment deprecation warning
+ // early_warn("--print-file-name has been deprecated in favor of \
+ // --print file-names");
+ prints.push(PrintRequest::FileNames);
}
- let cg = build_codegen_options(matches);
if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
- early_warn("-C remark will not show source locations without --debuginfo");
+ // FIXME(acrichto) uncomment deprecation warning
+ // early_warn("-C remark will not show source locations without \
+ // --debuginfo");
}
let color = match matches.opt_str("color").as_ref().map(|s| s.as_slice()) {
no_analysis: no_analysis,
debugging_opts: debugging_opts,
write_dependency_info: write_dependency_info,
- print_metas: print_metas,
+ prints: prints,
cg: cg,
color: color,
externs: externs,
ast::ExprMethodCall(..) => {
explain_span(cx, "method call", expr.span)
},
- ast::ExprMatch(_, _, ast::MatchIfLetDesugar) => explain_span(cx, "if let", expr.span),
- ast::ExprMatch(_, _, ast::MatchWhileLetDesugar) => {
+ ast::ExprMatch(_, _, ast::MatchSource::IfLetDesugar { .. }) =>
+ explain_span(cx, "if let", expr.span),
+ ast::ExprMatch(_, _, ast::MatchSource::WhileLetDesugar) => {
explain_span(cx, "while let", expr.span)
},
ast::ExprMatch(..) => explain_span(cx, "match", expr.span),
ty_vec(t, sz) => {
let inner_str = ty_to_string(cx, t);
match sz {
- Some(n) => format!("[{}, ..{}]", inner_str, n),
+ Some(n) => format!("[{}; {}]", inner_str, n),
None => format!("[{}]", inner_str),
}
}
if cx.lang_items.fn_trait_kind(did).is_some() {
format!("{}({}){}",
base,
- strs[0][1 .. strs[0].len() - (strs[0].ends_with(",)") as uint+1)],
+ if strs[0].starts_with("(") && strs[0].ends_with(",)") {
+ strs[0][1 .. strs[0].len() - 2] // Remove '(' and ',)'
+ } else {
+ strs[0][]
+ },
if &*strs[1] == "()" { String::new() } else { format!(" -> {}", strs[1]) })
} else if strs.len() > 0 {
format!("{}<{}>", base, strs.connect(", "))
pub use self::MoveKind::*;
use borrowck::*;
-use borrowck::LoanPathKind::{LpVar, LpUpvar, LpDowncast, LpExtend};
-use borrowck::LoanPathElem::{LpInterior};
use rustc::middle::cfg;
use rustc::middle::dataflow::DataFlowContext;
use rustc::middle::dataflow::BitwiseOperator;
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![feature(default_type_params, globs, import_shadowing, macro_rules, phase, quote)]
+#![feature(default_type_params, globs, macro_rules, phase, quote)]
#![feature(slicing_syntax, unsafe_destructor)]
#![feature(rustc_diagnostic_macros)]
#![feature(unboxed_closures)]
use rustc::plugin;
use rustc::util::common::time;
use rustc_borrowck as borrowck;
+use rustc_resolve as resolve;
use rustc_trans::back::link;
use rustc_trans::back::write;
use rustc_trans::save;
let lang_items = time(time_passes, "language item collection", (), |_|
middle::lang_items::collect_language_items(krate, &sess));
- let middle::resolve::CrateMap {
+ let resolve::CrateMap {
def_map,
freevars,
capture_mode_map,
- exp_map2,
+ export_map,
trait_map,
external_exports,
last_private_map
} =
- time(time_passes, "resolution", (), |_|
- middle::resolve::resolve_crate(&sess, &lang_items, krate));
+ time(time_passes, "resolution", (),
+ |_| resolve::resolve_crate(&sess, &lang_items, krate));
// Discard MTWT tables that aren't required past resolution.
syntax::ext::mtwt::clear_tables();
let maps = (external_exports, last_private_map);
let (exported_items, public_items) =
time(time_passes, "privacy checking", maps, |(a, b)|
- middle::privacy::check_crate(&ty_cx, &exp_map2, a, b));
+ middle::privacy::check_crate(&ty_cx, &export_map, a, b));
time(time_passes, "intrinsic checking", (), |_|
middle::intrinsicck::check_crate(&ty_cx));
lint::check_crate(&ty_cx, &exported_items));
ty::CrateAnalysis {
- exp_map2: exp_map2,
+ export_map: export_map,
ty_cx: ty_cx,
exported_items: exported_items,
public_items: public_items,
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![feature(default_type_params, globs, import_shadowing, macro_rules, phase, quote)]
+#![feature(default_type_params, globs, macro_rules, phase, quote)]
#![feature(slicing_syntax, unsafe_destructor)]
#![feature(rustc_diagnostic_macros)]
#![feature(unboxed_closures)]
extern crate rustc;
extern crate rustc_back;
extern crate rustc_borrowck;
+extern crate rustc_resolve;
extern crate rustc_trans;
extern crate rustc_typeck;
#[phase(plugin, link)] extern crate log;
use rustc_trans::back::link;
use rustc::session::{config, Session, build_session};
-use rustc::session::config::Input;
+use rustc::session::config::{Input, PrintRequest};
use rustc::lint::Lint;
use rustc::lint;
use rustc::metadata;
}
let sopts = config::build_session_options(&matches);
+ let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
+ let ofile = matches.opt_str("o").map(|o| Path::new(o));
let (input, input_file_path) = match matches.free.len() {
0u => {
if sopts.describe_lints {
describe_lints(&ls, false);
return;
}
-
let sess = build_session(sopts, None, descriptions);
- if sess.debugging_opt(config::PRINT_SYSROOT) {
- println!("{}", sess.sysroot().display());
+ if print_crate_info(&sess, None, &odir, &ofile) {
return;
}
-
early_error("no input filename given");
}
1u => {
let sess = build_session(sopts, input_file_path, descriptions);
let cfg = config::build_configuration(&sess);
- let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
- let ofile = matches.opt_str("o").map(|o| Path::new(o));
+ if print_crate_info(&sess, Some(&input), &odir, &ofile) {
+ return
+ }
let pretty = matches.opt_default("pretty", "normal").map(|a| {
pretty::parse_pretty(&sess, a.as_slice())
});
- match pretty {
+ match pretty.into_iter().next() {
Some((ppm, opt_uii)) => {
pretty::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile);
return;
return;
}
- if print_crate_info(&sess, &input, &odir, &ofile) {
- return;
- }
-
driver::compile_input(sess, cfg, &input, &odir, &ofile, None);
}
/// Prints version information and returns None on success or an error
/// message on panic.
-pub fn version(binary: &str, matches: &getopts::Matches) -> Option<String> {
- let verbose = match matches.opt_str("version").as_ref().map(|s| s.as_slice()) {
- None => false,
- Some("verbose") => true,
- Some(s) => return Some(format!("Unrecognized argument: {}", s))
- };
+pub fn version(binary: &str, matches: &getopts::Matches) {
+ let verbose = matches.opt_present("verbose");
println!("{} {}", binary, option_env!("CFG_VERSION").unwrap_or("unknown version"));
if verbose {
println!("host: {}", config::host_triple());
println!("release: {}", unw(release_str()));
}
- None
}
-fn usage() {
+fn usage(verbose: bool) {
+ let groups = if verbose {
+ config::optgroups()
+ } else {
+ config::short_optgroups()
+ };
let message = format!("Usage: rustc [OPTIONS] INPUT");
+ let extra_help = if verbose {
+ ""
+ } else {
+ "\n --help -v Print the full set of options rustc accepts"
+ };
println!("{}\n\
Additional help:
-C help Print codegen options
-W help Print 'lint' options and default settings
- -Z help Print internal options for debugging rustc\n",
- getopts::usage(message.as_slice(),
- config::optgroups().as_slice()));
+ -Z help Print internal options for debugging rustc{}\n",
+ getopts::usage(message.as_slice(), groups.as_slice()),
+ extra_help);
}
fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) {
let _binary = args.remove(0).unwrap();
if args.is_empty() {
- usage();
+ usage(false);
return None;
}
};
if matches.opt_present("h") || matches.opt_present("help") {
- usage();
+ usage(matches.opt_present("verbose"));
return None;
}
}
if matches.opt_present("version") {
- match version("rustc", &matches) {
- Some(err) => early_error(err.as_slice()),
- None => return None
- }
+ version("rustc", &matches);
+ return None;
}
Some(matches)
}
fn print_crate_info(sess: &Session,
- input: &Input,
+ input: Option<&Input>,
odir: &Option<Path>,
ofile: &Option<Path>)
-> bool {
- let (crate_name, crate_file_name) = sess.opts.print_metas;
- // these nasty nested conditions are to avoid doing extra work
- if crate_name || crate_file_name {
- let attrs = parse_crate_attrs(sess, input);
- let t_outputs = driver::build_output_filenames(input,
- odir,
- ofile,
- attrs.as_slice(),
- sess);
- let id = link::find_crate_name(Some(sess), attrs.as_slice(), input);
-
- if crate_name {
- println!("{}", id);
- }
- if crate_file_name {
- let crate_types = driver::collect_crate_types(sess, attrs.as_slice());
- let metadata = driver::collect_crate_metadata(sess, attrs.as_slice());
- *sess.crate_metadata.borrow_mut() = metadata;
- for &style in crate_types.iter() {
- let fname = link::filename_for_input(sess, style, id.as_slice(),
- &t_outputs.with_extension(""));
- println!("{}", fname.filename_display());
+ if sess.opts.prints.len() == 0 { return false }
+
+ let attrs = input.map(|input| parse_crate_attrs(sess, input));
+ for req in sess.opts.prints.iter() {
+ match *req {
+ PrintRequest::Sysroot => println!("{}", sess.sysroot().display()),
+ PrintRequest::FileNames |
+ PrintRequest::CrateName => {
+ let input = match input {
+ Some(input) => input,
+ None => early_error("no input file provided"),
+ };
+ let attrs = attrs.as_ref().unwrap().as_slice();
+ let t_outputs = driver::build_output_filenames(input,
+ odir,
+ ofile,
+ attrs,
+ sess);
+ let id = link::find_crate_name(Some(sess), attrs.as_slice(),
+ input);
+ if *req == PrintRequest::CrateName {
+ println!("{}", id);
+ continue
+ }
+ let crate_types = driver::collect_crate_types(sess, attrs);
+ let metadata = driver::collect_crate_metadata(sess, attrs);
+ *sess.crate_metadata.borrow_mut() = metadata;
+ for &style in crate_types.iter() {
+ let fname = link::filename_for_input(sess, style,
+ id.as_slice(),
+ &t_outputs.with_extension(""));
+ println!("{}", fname.filename_display());
+ }
}
}
-
- true
- } else {
- false
}
+ return true;
}
fn parse_crate_attrs(sess: &Session, input: &Input) ->
/// The diagnostic emitter yielded to the procedure should be used for reporting
/// errors of the compiler.
pub fn monitor<F:FnOnce()+Send>(f: F) {
- static STACK_SIZE: uint = 32000000; // 32MB
+ static STACK_SIZE: uint = 8 * 1024 * 1024; // 8MB
let (tx, rx) = channel();
let w = io::ChanWriter::new(tx);
use diagnostic;
use diagnostic::Emitter;
use driver;
+use rustc_resolve as resolve;
use rustc_typeck::middle::lang_items;
use rustc_typeck::middle::region::{mod, CodeExtent};
-use rustc_typeck::middle::resolve;
use rustc_typeck::middle::resolve_lifetime;
use rustc_typeck::middle::stability;
use rustc_typeck::middle::subst;
--- /dev/null
+// Copyright 2012-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.
+
+
+//
+// Unused import checking
+//
+// Although this is mostly a lint pass, it lives in here because it depends on
+// resolve data structures and because it finalises the privacy information for
+// `use` directives.
+//
+
+use Resolver;
+use Namespace::{TypeNS, ValueNS};
+
+use rustc::lint;
+use rustc::middle::privacy::{DependsOn, LastImport, Used, Unused};
+use syntax::ast;
+use syntax::ast::{ViewItem, ViewItemExternCrate, ViewItemUse};
+use syntax::ast::{ViewPathGlob, ViewPathList, ViewPathSimple};
+use syntax::codemap::{Span, DUMMY_SP};
+use syntax::visit::{mod, Visitor};
+
+struct UnusedImportCheckVisitor<'a, 'b:'a> {
+ resolver: &'a mut Resolver<'b>
+}
+
+// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
+impl<'a, 'b> Deref<Resolver<'b>> for UnusedImportCheckVisitor<'a, 'b> {
+ fn deref<'c>(&'c self) -> &'c Resolver<'b> {
+ &*self.resolver
+ }
+}
+
+impl<'a, 'b> DerefMut<Resolver<'b>> for UnusedImportCheckVisitor<'a, 'b> {
+ fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> {
+ &mut *self.resolver
+ }
+}
+
+impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
+ // We have information about whether `use` (import) directives are actually used now.
+ // If an import is not used at all, we signal a lint error. If an import is only used
+ // for a single namespace, we remove the other namespace from the recorded privacy
+ // information. That means in privacy.rs, we will only check imports and namespaces
+ // which are used. In particular, this means that if an import could name either a
+ // public or private item, we will check the correct thing, dependent on how the import
+ // is used.
+ fn finalize_import(&mut self, id: ast::NodeId, span: Span) {
+ debug!("finalizing import uses for {}",
+ self.session.codemap().span_to_snippet(span));
+
+ if !self.used_imports.contains(&(id, TypeNS)) &&
+ !self.used_imports.contains(&(id, ValueNS)) {
+ self.session.add_lint(lint::builtin::UNUSED_IMPORTS,
+ id,
+ span,
+ "unused import".to_string());
+ }
+
+ let (v_priv, t_priv) = match self.last_private.get(&id) {
+ Some(&LastImport {
+ value_priv: v,
+ value_used: _,
+ type_priv: t,
+ type_used: _
+ }) => (v, t),
+ Some(_) => {
+ panic!("we should only have LastImport for `use` directives")
+ }
+ _ => return,
+ };
+
+ let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
+ Used
+ } else {
+ Unused
+ };
+ let t_used = if self.used_imports.contains(&(id, TypeNS)) {
+ Used
+ } else {
+ Unused
+ };
+
+ match (v_priv, t_priv) {
+ // Since some items may be both in the value _and_ type namespaces (e.g., structs)
+ // we might have two LastPrivates pointing at the same thing. There is no point
+ // checking both, so lets not check the value one.
+ (Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused,
+ _ => {},
+ }
+
+ self.last_private.insert(id, LastImport{value_priv: v_priv,
+ value_used: v_used,
+ type_priv: t_priv,
+ type_used: t_used});
+ }
+}
+
+impl<'a, 'b, 'v> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b> {
+ fn visit_view_item(&mut self, vi: &ViewItem) {
+ // Ignore is_public import statements because there's no way to be sure
+ // whether they're used or not. Also ignore imports with a dummy span
+ // because this means that they were generated in some fashion by the
+ // compiler and we don't need to consider them.
+ if vi.vis == ast::Public || vi.span == DUMMY_SP {
+ visit::walk_view_item(self, vi);
+ return;
+ }
+
+ match vi.node {
+ ViewItemExternCrate(_, _, id) => {
+ if let Some(crate_num) = self.session.cstore.find_extern_mod_stmt_cnum(id) {
+ if !self.used_crates.contains(&crate_num) {
+ self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATES,
+ id,
+ vi.span,
+ "unused extern crate".to_string());
+ }
+ }
+ },
+ ViewItemUse(ref p) => {
+ match p.node {
+ ViewPathSimple(_, _, id) => {
+ self.finalize_import(id, p.span)
+ }
+
+ ViewPathList(_, ref list, _) => {
+ for i in list.iter() {
+ self.finalize_import(i.node.id(), i.span);
+ }
+ }
+ ViewPathGlob(_, id) => {
+ if !self.used_imports.contains(&(id, TypeNS)) &&
+ !self.used_imports.contains(&(id, ValueNS)) {
+ self.session
+ .add_lint(lint::builtin::UNUSED_IMPORTS,
+ id,
+ p.span,
+ "unused import".to_string());
+ }
+ }
+ }
+ }
+ }
+
+ visit::walk_view_item(self, vi);
+ }
+}
+
+pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) {
+ let mut visitor = UnusedImportCheckVisitor { resolver: resolver };
+ visit::walk_crate(&mut visitor, krate);
+}
--- /dev/null
+// Copyright 2012-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.
+
+#![crate_name = "rustc_resolve"]
+#![experimental]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+ html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_root_url = "http://doc.rust-lang.org/nightly/")]
+
+#![feature(globs, phase, slicing_syntax)]
+#![feature(rustc_diagnostic_macros)]
+
+#[phase(plugin, link)] extern crate log;
+#[phase(plugin, link)] extern crate syntax;
+
+extern crate rustc;
+
+use self::PatternBindingMode::*;
+use self::Namespace::*;
+use self::NamespaceError::*;
+use self::NamespaceResult::*;
+use self::NameDefinition::*;
+use self::ImportDirectiveSubclass::*;
+use self::ReducedGraphParent::*;
+use self::ResolveResult::*;
+use self::FallbackSuggestion::*;
+use self::TypeParameters::*;
+use self::RibKind::*;
+use self::MethodSort::*;
+use self::UseLexicalScopeFlag::*;
+use self::ModulePrefixResult::*;
+use self::NameSearchType::*;
+use self::BareIdentifierPatternResolution::*;
+use self::DuplicateCheckingMode::*;
+use self::ParentLink::*;
+use self::ModuleKind::*;
+use self::TraitReferenceType::*;
+use self::FallbackChecks::*;
+
+use rustc::session::Session;
+use rustc::lint;
+use rustc::metadata::csearch;
+use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
+use rustc::middle::def::*;
+use rustc::middle::lang_items::LanguageItems;
+use rustc::middle::pat_util::pat_bindings;
+use rustc::middle::privacy::*;
+use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace};
+use rustc::middle::ty::{CaptureModeMap, Freevar, FreevarMap, TraitMap};
+use rustc::util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap};
+
+use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
+use syntax::ast::{DeclItem, DefId, Expr, ExprAgain, ExprBreak, ExprField};
+use syntax::ast::{ExprClosure, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall};
+use syntax::ast::{ExprPath, ExprStruct, FnDecl};
+use syntax::ast::{ForeignItem, ForeignItemFn, ForeignItemStatic, Generics};
+use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemFn};
+use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic};
+use syntax::ast::{ItemStruct, ItemTrait, ItemTy, Local};
+use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId};
+use syntax::ast::{Pat, PatEnum, PatIdent, PatLit};
+use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod};
+use syntax::ast::{PolyTraitRef, PrimTy, Public, SelfExplicit, SelfStatic};
+use syntax::ast::{RegionTyParamBound, StmtDecl, StructField};
+use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound};
+use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32};
+use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt, TyObjectSum};
+use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyPolyTraitRef, TyQPath};
+use syntax::ast::{TyRptr, TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint};
+use syntax::ast::{TypeImplItem, UnnamedField};
+use syntax::ast::{Variant, ViewItem, ViewItemExternCrate};
+use syntax::ast::{ViewItemUse, ViewPathGlob, ViewPathList, ViewPathSimple};
+use syntax::ast::{Visibility};
+use syntax::ast;
+use syntax::ast_util::{mod, PostExpansionMethod, local_def, walk_pat};
+use syntax::attr::AttrMetaMethods;
+use syntax::ext::mtwt;
+use syntax::parse::token::{mod, special_names, special_idents};
+use syntax::codemap::{Span, DUMMY_SP, Pos};
+use syntax::owned_slice::OwnedSlice;
+use syntax::visit::{mod, Visitor};
+
+use std::collections::{HashMap, HashSet};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
+use std::cell::{Cell, RefCell};
+use std::mem::replace;
+use std::rc::{Rc, Weak};
+use std::uint;
+
+mod check_unused;
+mod record_exports;
+
+#[deriving(Copy)]
+struct BindingInfo {
+ span: Span,
+ binding_mode: BindingMode,
+}
+
+// Map from the name in a pattern to its binding mode.
+type BindingMap = HashMap<Name, BindingInfo>;
+
+#[deriving(Copy, PartialEq)]
+enum PatternBindingMode {
+ RefutableMode,
+ LocalIrrefutableMode,
+ ArgumentIrrefutableMode,
+}
+
+#[deriving(Copy, PartialEq, Eq, Hash, Show)]
+enum Namespace {
+ TypeNS,
+ ValueNS
+}
+
+#[deriving(Copy, PartialEq)]
+enum NamespaceError {
+ NoError,
+ ModuleError,
+ TypeError,
+ ValueError
+}
+
+/// A NamespaceResult represents the result of resolving an import in
+/// a particular namespace. The result is either definitely-resolved,
+/// definitely- unresolved, or unknown.
+#[deriving(Clone)]
+enum NamespaceResult {
+ /// Means that resolve hasn't gathered enough information yet to determine
+ /// whether the name is bound in this namespace. (That is, it hasn't
+ /// resolved all `use` directives yet.)
+ UnknownResult,
+ /// Means that resolve has determined that the name is definitely
+ /// not bound in the namespace.
+ UnboundResult,
+ /// Means that resolve has determined that the name is bound in the Module
+ /// argument, and specified by the NameBindings argument.
+ BoundResult(Rc<Module>, Rc<NameBindings>)
+}
+
+impl NamespaceResult {
+ fn is_unknown(&self) -> bool {
+ match *self {
+ UnknownResult => true,
+ _ => false
+ }
+ }
+ fn is_unbound(&self) -> bool {
+ match *self {
+ UnboundResult => true,
+ _ => false
+ }
+ }
+}
+
+enum NameDefinition {
+ NoNameDefinition, //< The name was unbound.
+ ChildNameDefinition(Def, LastPrivate), //< The name identifies an immediate child.
+ ImportNameDefinition(Def, LastPrivate) //< The name identifies an import.
+}
+
+impl<'a, 'v> Visitor<'v> for Resolver<'a> {
+ fn visit_item(&mut self, item: &Item) {
+ self.resolve_item(item);
+ }
+ fn visit_arm(&mut self, arm: &Arm) {
+ self.resolve_arm(arm);
+ }
+ fn visit_block(&mut self, block: &Block) {
+ self.resolve_block(block);
+ }
+ fn visit_expr(&mut self, expr: &Expr) {
+ self.resolve_expr(expr);
+ }
+ fn visit_local(&mut self, local: &Local) {
+ self.resolve_local(local);
+ }
+ fn visit_ty(&mut self, ty: &Ty) {
+ self.resolve_type(ty);
+ }
+}
+
+/// Contains data for specific types of import directives.
+#[deriving(Copy)]
+enum ImportDirectiveSubclass {
+ SingleImport(Name /* target */, Name /* source */),
+ GlobImport
+}
+
+/// The context that we thread through while building the reduced graph.
+#[deriving(Clone)]
+enum ReducedGraphParent {
+ ModuleReducedGraphParent(Rc<Module>)
+}
+
+impl ReducedGraphParent {
+ fn module(&self) -> Rc<Module> {
+ match *self {
+ ModuleReducedGraphParent(ref m) => {
+ m.clone()
+ }
+ }
+ }
+}
+
+type ErrorMessage = Option<(Span, String)>;
+
+enum ResolveResult<T> {
+ Failed(ErrorMessage), // Failed to resolve the name, optional helpful error message.
+ Indeterminate, // Couldn't determine due to unresolved globs.
+ Success(T) // Successfully resolved the import.
+}
+
+impl<T> ResolveResult<T> {
+ fn indeterminate(&self) -> bool {
+ match *self { Indeterminate => true, _ => false }
+ }
+}
+
+enum FallbackSuggestion {
+ NoSuggestion,
+ Field,
+ Method,
+ TraitItem,
+ StaticMethod(String),
+ TraitMethod(String),
+}
+
+#[deriving(Copy)]
+enum TypeParameters<'a> {
+ NoTypeParameters,
+ HasTypeParameters(
+ // Type parameters.
+ &'a Generics,
+
+ // Identifies the things that these parameters
+ // were declared on (type, fn, etc)
+ ParamSpace,
+
+ // ID of the enclosing item.
+ NodeId,
+
+ // The kind of the rib used for type parameters.
+ RibKind)
+}
+
+// The rib kind controls the translation of local
+// definitions (`DefLocal`) to upvars (`DefUpvar`).
+#[deriving(Copy, Show)]
+enum RibKind {
+ // No translation needs to be applied.
+ NormalRibKind,
+
+ // We passed through a closure scope at the given node ID.
+ // Translate upvars as appropriate.
+ ClosureRibKind(NodeId /* func id */, NodeId /* body id if proc or unboxed */),
+
+ // We passed through an impl or trait and are now in one of its
+ // methods. Allow references to ty params that impl or trait
+ // binds. Disallow any other upvars (including other ty params that are
+ // upvars).
+ // parent; method itself
+ MethodRibKind(NodeId, MethodSort),
+
+ // We passed through an item scope. Disallow upvars.
+ ItemRibKind,
+
+ // We're in a constant item. Can't refer to dynamic stuff.
+ ConstantItemRibKind
+}
+
+// Methods can be required or provided. RequiredMethod methods only occur in traits.
+#[deriving(Copy, Show)]
+enum MethodSort {
+ RequiredMethod,
+ ProvidedMethod(NodeId)
+}
+
+#[deriving(Copy)]
+enum UseLexicalScopeFlag {
+ DontUseLexicalScope,
+ UseLexicalScope
+}
+
+enum ModulePrefixResult {
+ NoPrefixFound,
+ PrefixFound(Rc<Module>, uint)
+}
+
+#[deriving(Copy, PartialEq)]
+enum NameSearchType {
+ /// We're doing a name search in order to resolve a `use` directive.
+ ImportSearch,
+
+ /// We're doing a name search in order to resolve a path type, a path
+ /// expression, or a path pattern.
+ PathSearch,
+}
+
+#[deriving(Copy)]
+enum BareIdentifierPatternResolution {
+ FoundStructOrEnumVariant(Def, LastPrivate),
+ FoundConst(Def, LastPrivate),
+ BareIdentifierPatternUnresolved
+}
+
+// Specifies how duplicates should be handled when adding a child item if
+// another item exists with the same name in some namespace.
+#[deriving(Copy, PartialEq)]
+enum DuplicateCheckingMode {
+ ForbidDuplicateModules,
+ ForbidDuplicateTypesAndModules,
+ ForbidDuplicateValues,
+ ForbidDuplicateTypesAndValues,
+ OverwriteDuplicates
+}
+
+/// One local scope.
+#[deriving(Show)]
+struct Rib {
+ bindings: HashMap<Name, DefLike>,
+ kind: RibKind,
+}
+
+impl Rib {
+ fn new(kind: RibKind) -> Rib {
+ Rib {
+ bindings: HashMap::new(),
+ kind: kind
+ }
+ }
+}
+
+/// One import directive.
+struct ImportDirective {
+ module_path: Vec<Name>,
+ subclass: ImportDirectiveSubclass,
+ span: Span,
+ id: NodeId,
+ is_public: bool, // see note in ImportResolution about how to use this
+ shadowable: bool,
+}
+
+impl ImportDirective {
+ fn new(module_path: Vec<Name> ,
+ subclass: ImportDirectiveSubclass,
+ span: Span,
+ id: NodeId,
+ is_public: bool,
+ shadowable: bool)
+ -> ImportDirective {
+ ImportDirective {
+ module_path: module_path,
+ subclass: subclass,
+ span: span,
+ id: id,
+ is_public: is_public,
+ shadowable: shadowable,
+ }
+ }
+}
+
+/// The item that an import resolves to.
+#[deriving(Clone)]
+struct Target {
+ target_module: Rc<Module>,
+ bindings: Rc<NameBindings>,
+ shadowable: bool,
+}
+
+impl Target {
+ fn new(target_module: Rc<Module>,
+ bindings: Rc<NameBindings>,
+ shadowable: bool)
+ -> Target {
+ Target {
+ target_module: target_module,
+ bindings: bindings,
+ shadowable: shadowable,
+ }
+ }
+}
+
+/// An ImportResolution represents a particular `use` directive.
+struct ImportResolution {
+ /// Whether this resolution came from a `use` or a `pub use`. Note that this
+ /// should *not* be used whenever resolution is being performed, this is
+ /// only looked at for glob imports statements currently. Privacy testing
+ /// occurs during a later phase of compilation.
+ is_public: bool,
+
+ // The number of outstanding references to this name. When this reaches
+ // zero, outside modules can count on the targets being correct. Before
+ // then, all bets are off; future imports could override this name.
+ outstanding_references: uint,
+
+ /// The value that this `use` directive names, if there is one.
+ value_target: Option<Target>,
+ /// The source node of the `use` directive leading to the value target
+ /// being non-none
+ value_id: NodeId,
+
+ /// The type that this `use` directive names, if there is one.
+ type_target: Option<Target>,
+ /// The source node of the `use` directive leading to the type target
+ /// being non-none
+ type_id: NodeId,
+}
+
+impl ImportResolution {
+ fn new(id: NodeId, is_public: bool) -> ImportResolution {
+ ImportResolution {
+ type_id: id,
+ value_id: id,
+ outstanding_references: 0,
+ value_target: None,
+ type_target: None,
+ is_public: is_public,
+ }
+ }
+
+ fn target_for_namespace(&self, namespace: Namespace)
+ -> Option<Target> {
+ match namespace {
+ TypeNS => self.type_target.clone(),
+ ValueNS => self.value_target.clone(),
+ }
+ }
+
+ fn id(&self, namespace: Namespace) -> NodeId {
+ match namespace {
+ TypeNS => self.type_id,
+ ValueNS => self.value_id,
+ }
+ }
+}
+
+/// The link from a module up to its nearest parent node.
+#[deriving(Clone)]
+enum ParentLink {
+ NoParentLink,
+ ModuleParentLink(Weak<Module>, Name),
+ BlockParentLink(Weak<Module>, NodeId)
+}
+
+/// The type of module this is.
+#[deriving(Copy, PartialEq)]
+enum ModuleKind {
+ NormalModuleKind,
+ TraitModuleKind,
+ ImplModuleKind,
+ EnumModuleKind,
+ AnonymousModuleKind,
+}
+
+/// One node in the tree of modules.
+struct Module {
+ parent_link: ParentLink,
+ def_id: Cell<Option<DefId>>,
+ kind: Cell<ModuleKind>,
+ is_public: bool,
+
+ children: RefCell<HashMap<Name, Rc<NameBindings>>>,
+ imports: RefCell<Vec<ImportDirective>>,
+
+ // The external module children of this node that were declared with
+ // `extern crate`.
+ external_module_children: RefCell<HashMap<Name, Rc<Module>>>,
+
+ // The anonymous children of this node. Anonymous children are pseudo-
+ // modules that are implicitly created around items contained within
+ // blocks.
+ //
+ // For example, if we have this:
+ //
+ // fn f() {
+ // fn g() {
+ // ...
+ // }
+ // }
+ //
+ // There will be an anonymous module created around `g` with the ID of the
+ // entry block for `f`.
+ anonymous_children: RefCell<NodeMap<Rc<Module>>>,
+
+ // The status of resolving each import in this module.
+ import_resolutions: RefCell<HashMap<Name, ImportResolution>>,
+
+ // The number of unresolved globs that this module exports.
+ glob_count: Cell<uint>,
+
+ // The index of the import we're resolving.
+ resolved_import_count: Cell<uint>,
+
+ // Whether this module is populated. If not populated, any attempt to
+ // access the children must be preceded with a
+ // `populate_module_if_necessary` call.
+ populated: Cell<bool>,
+}
+
+impl Module {
+ fn new(parent_link: ParentLink,
+ def_id: Option<DefId>,
+ kind: ModuleKind,
+ external: bool,
+ is_public: bool)
+ -> Module {
+ Module {
+ parent_link: parent_link,
+ def_id: Cell::new(def_id),
+ kind: Cell::new(kind),
+ is_public: is_public,
+ children: RefCell::new(HashMap::new()),
+ imports: RefCell::new(Vec::new()),
+ external_module_children: RefCell::new(HashMap::new()),
+ anonymous_children: RefCell::new(NodeMap::new()),
+ import_resolutions: RefCell::new(HashMap::new()),
+ glob_count: Cell::new(0),
+ resolved_import_count: Cell::new(0),
+ populated: Cell::new(!external),
+ }
+ }
+
+ fn all_imports_resolved(&self) -> bool {
+ self.imports.borrow().len() == self.resolved_import_count.get()
+ }
+}
+
+bitflags! {
+ #[deriving(Show)]
+ flags DefModifiers: u8 {
+ const PUBLIC = 0b0000_0001,
+ const IMPORTABLE = 0b0000_0010,
+ }
+}
+
+// Records a possibly-private type definition.
+#[deriving(Clone)]
+struct TypeNsDef {
+ modifiers: DefModifiers, // see note in ImportResolution about how to use this
+ module_def: Option<Rc<Module>>,
+ type_def: Option<Def>,
+ type_span: Option<Span>
+}
+
+// Records a possibly-private value definition.
+#[deriving(Clone, Copy, Show)]
+struct ValueNsDef {
+ modifiers: DefModifiers, // see note in ImportResolution about how to use this
+ def: Def,
+ value_span: Option<Span>,
+}
+
+// Records the definitions (at most one for each namespace) that a name is
+// bound to.
+struct NameBindings {
+ type_def: RefCell<Option<TypeNsDef>>, //< Meaning in type namespace.
+ value_def: RefCell<Option<ValueNsDef>>, //< Meaning in value namespace.
+}
+
+/// Ways in which a trait can be referenced
+#[deriving(Copy)]
+enum TraitReferenceType {
+ TraitImplementation, // impl SomeTrait for T { ... }
+ TraitDerivation, // trait T : SomeTrait { ... }
+ TraitBoundingTypeParameter, // fn f<T:SomeTrait>() { ... }
+ TraitObject, // Box<for<'a> SomeTrait>
+ TraitQPath, // <T as SomeTrait>::
+}
+
+impl NameBindings {
+ fn new() -> NameBindings {
+ NameBindings {
+ type_def: RefCell::new(None),
+ value_def: RefCell::new(None),
+ }
+ }
+
+ /// Creates a new module in this set of name bindings.
+ fn define_module(&self,
+ parent_link: ParentLink,
+ def_id: Option<DefId>,
+ kind: ModuleKind,
+ external: bool,
+ is_public: bool,
+ sp: Span) {
+ // Merges the module with the existing type def or creates a new one.
+ let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
+ let module_ = Rc::new(Module::new(parent_link,
+ def_id,
+ kind,
+ external,
+ is_public));
+ let type_def = self.type_def.borrow().clone();
+ match type_def {
+ None => {
+ *self.type_def.borrow_mut() = Some(TypeNsDef {
+ modifiers: modifiers,
+ module_def: Some(module_),
+ type_def: None,
+ type_span: Some(sp)
+ });
+ }
+ Some(type_def) => {
+ *self.type_def.borrow_mut() = Some(TypeNsDef {
+ modifiers: modifiers,
+ module_def: Some(module_),
+ type_span: Some(sp),
+ type_def: type_def.type_def
+ });
+ }
+ }
+ }
+
+ /// Sets the kind of the module, creating a new one if necessary.
+ fn set_module_kind(&self,
+ parent_link: ParentLink,
+ def_id: Option<DefId>,
+ kind: ModuleKind,
+ external: bool,
+ is_public: bool,
+ _sp: Span) {
+ let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
+ let type_def = self.type_def.borrow().clone();
+ match type_def {
+ None => {
+ let module = Module::new(parent_link,
+ def_id,
+ kind,
+ external,
+ is_public);
+ *self.type_def.borrow_mut() = Some(TypeNsDef {
+ modifiers: modifiers,
+ module_def: Some(Rc::new(module)),
+ type_def: None,
+ type_span: None,
+ });
+ }
+ Some(type_def) => {
+ match type_def.module_def {
+ None => {
+ let module = Module::new(parent_link,
+ def_id,
+ kind,
+ external,
+ is_public);
+ *self.type_def.borrow_mut() = Some(TypeNsDef {
+ modifiers: modifiers,
+ module_def: Some(Rc::new(module)),
+ type_def: type_def.type_def,
+ type_span: None,
+ });
+ }
+ Some(module_def) => module_def.kind.set(kind),
+ }
+ }
+ }
+ }
+
+ /// Records a type definition.
+ fn define_type(&self, def: Def, sp: Span, modifiers: DefModifiers) {
+ debug!("defining type for def {} with modifiers {}", def, modifiers);
+ // Merges the type with the existing type def or creates a new one.
+ let type_def = self.type_def.borrow().clone();
+ match type_def {
+ None => {
+ *self.type_def.borrow_mut() = Some(TypeNsDef {
+ module_def: None,
+ type_def: Some(def),
+ type_span: Some(sp),
+ modifiers: modifiers,
+ });
+ }
+ Some(type_def) => {
+ *self.type_def.borrow_mut() = Some(TypeNsDef {
+ module_def: type_def.module_def,
+ type_def: Some(def),
+ type_span: Some(sp),
+ modifiers: modifiers,
+ });
+ }
+ }
+ }
+
+ /// Records a value definition.
+ fn define_value(&self, def: Def, sp: Span, modifiers: DefModifiers) {
+ debug!("defining value for def {} with modifiers {}", def, modifiers);
+ *self.value_def.borrow_mut() = Some(ValueNsDef {
+ def: def,
+ value_span: Some(sp),
+ modifiers: modifiers,
+ });
+ }
+
+ /// Returns the module node if applicable.
+ fn get_module_if_available(&self) -> Option<Rc<Module>> {
+ match *self.type_def.borrow() {
+ Some(ref type_def) => type_def.module_def.clone(),
+ None => None
+ }
+ }
+
+ /// Returns the module node. Panics if this node does not have a module
+ /// definition.
+ fn get_module(&self) -> Rc<Module> {
+ match self.get_module_if_available() {
+ None => {
+ panic!("get_module called on a node with no module \
+ definition!")
+ }
+ Some(module_def) => module_def
+ }
+ }
+
+ fn defined_in_namespace(&self, namespace: Namespace) -> bool {
+ match namespace {
+ TypeNS => return self.type_def.borrow().is_some(),
+ ValueNS => return self.value_def.borrow().is_some()
+ }
+ }
+
+ fn defined_in_public_namespace(&self, namespace: Namespace) -> bool {
+ self.defined_in_namespace_with(namespace, PUBLIC)
+ }
+
+ fn defined_in_namespace_with(&self, namespace: Namespace, modifiers: DefModifiers) -> bool {
+ match namespace {
+ TypeNS => match *self.type_def.borrow() {
+ Some(ref def) => def.modifiers.contains(modifiers), None => false
+ },
+ ValueNS => match *self.value_def.borrow() {
+ Some(ref def) => def.modifiers.contains(modifiers), None => false
+ }
+ }
+ }
+
+ fn def_for_namespace(&self, namespace: Namespace) -> Option<Def> {
+ match namespace {
+ TypeNS => {
+ match *self.type_def.borrow() {
+ None => None,
+ Some(ref type_def) => {
+ match type_def.type_def {
+ Some(type_def) => Some(type_def),
+ None => {
+ match type_def.module_def {
+ Some(ref module) => {
+ match module.def_id.get() {
+ Some(did) => Some(DefMod(did)),
+ None => None,
+ }
+ }
+ None => None,
+ }
+ }
+ }
+ }
+ }
+ }
+ ValueNS => {
+ match *self.value_def.borrow() {
+ None => None,
+ Some(value_def) => Some(value_def.def)
+ }
+ }
+ }
+ }
+
+ fn span_for_namespace(&self, namespace: Namespace) -> Option<Span> {
+ if self.defined_in_namespace(namespace) {
+ match namespace {
+ TypeNS => {
+ match *self.type_def.borrow() {
+ None => None,
+ Some(ref type_def) => type_def.type_span
+ }
+ }
+ ValueNS => {
+ match *self.value_def.borrow() {
+ None => None,
+ Some(ref value_def) => value_def.value_span
+ }
+ }
+ }
+ } else {
+ None
+ }
+ }
+}
+
+/// Interns the names of the primitive types.
+struct PrimitiveTypeTable {
+ primitive_types: HashMap<Name, PrimTy>,
+}
+
+impl PrimitiveTypeTable {
+ fn new() -> PrimitiveTypeTable {
+ let mut table = PrimitiveTypeTable {
+ primitive_types: HashMap::new()
+ };
+
+ table.intern("bool", TyBool);
+ table.intern("char", TyChar);
+ table.intern("f32", TyFloat(TyF32));
+ table.intern("f64", TyFloat(TyF64));
+ table.intern("int", TyInt(TyI));
+ table.intern("i8", TyInt(TyI8));
+ table.intern("i16", TyInt(TyI16));
+ table.intern("i32", TyInt(TyI32));
+ table.intern("i64", TyInt(TyI64));
+ table.intern("str", TyStr);
+ table.intern("uint", TyUint(TyU));
+ table.intern("u8", TyUint(TyU8));
+ table.intern("u16", TyUint(TyU16));
+ table.intern("u32", TyUint(TyU32));
+ table.intern("u64", TyUint(TyU64));
+
+ table
+ }
+
+ fn intern(&mut self, string: &str, primitive_type: PrimTy) {
+ self.primitive_types.insert(token::intern(string), primitive_type);
+ }
+}
+
+
+fn namespace_error_to_string(ns: NamespaceError) -> &'static str {
+ match ns {
+ NoError => "",
+ ModuleError | TypeError => "type or module",
+ ValueError => "value",
+ }
+}
+
+/// The main resolver class.
+struct Resolver<'a> {
+ session: &'a Session,
+
+ graph_root: NameBindings,
+
+ trait_item_map: FnvHashMap<(Name, DefId), TraitItemKind>,
+
+ structs: FnvHashMap<DefId, Vec<Name>>,
+
+ // The number of imports that are currently unresolved.
+ unresolved_imports: uint,
+
+ // The module that represents the current item scope.
+ current_module: Rc<Module>,
+
+ // The current set of local scopes, for values.
+ // FIXME #4948: Reuse ribs to avoid allocation.
+ value_ribs: Vec<Rib>,
+
+ // The current set of local scopes, for types.
+ type_ribs: Vec<Rib>,
+
+ // The current set of local scopes, for labels.
+ label_ribs: Vec<Rib>,
+
+ // The trait that the current context can refer to.
+ current_trait_ref: Option<(DefId, TraitRef)>,
+
+ // The current self type if inside an impl (used for better errors).
+ current_self_type: Option<Ty>,
+
+ // The ident for the keyword "self".
+ self_name: Name,
+ // The ident for the non-keyword "Self".
+ type_self_name: Name,
+
+ // The idents for the primitive types.
+ primitive_type_table: PrimitiveTypeTable,
+
+ def_map: DefMap,
+ freevars: RefCell<FreevarMap>,
+ freevars_seen: RefCell<NodeMap<NodeSet>>,
+ capture_mode_map: CaptureModeMap,
+ export_map: ExportMap,
+ trait_map: TraitMap,
+ external_exports: ExternalExports,
+ last_private: LastPrivateMap,
+
+ // Whether or not to print error messages. Can be set to true
+ // when getting additional info for error message suggestions,
+ // so as to avoid printing duplicate errors
+ emit_errors: bool,
+
+ used_imports: HashSet<(NodeId, Namespace)>,
+ used_crates: HashSet<CrateNum>,
+}
+
+struct BuildReducedGraphVisitor<'a, 'b:'a> {
+ resolver: &'a mut Resolver<'b>,
+ parent: ReducedGraphParent
+}
+
+impl<'a, 'b, 'v> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b> {
+
+ fn visit_item(&mut self, item: &Item) {
+ let p = self.resolver.build_reduced_graph_for_item(item, self.parent.clone());
+ let old_parent = replace(&mut self.parent, p);
+ visit::walk_item(self, item);
+ self.parent = old_parent;
+ }
+
+ fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
+ let parent = self.parent.clone();
+ self.resolver.build_reduced_graph_for_foreign_item(foreign_item,
+ parent.clone(),
+ |r| {
+ let mut v = BuildReducedGraphVisitor {
+ resolver: r,
+ parent: parent.clone()
+ };
+ visit::walk_foreign_item(&mut v, foreign_item);
+ })
+ }
+
+ fn visit_view_item(&mut self, view_item: &ViewItem) {
+ self.resolver.build_reduced_graph_for_view_item(view_item, self.parent.clone());
+ }
+
+ fn visit_block(&mut self, block: &Block) {
+ let np = self.resolver.build_reduced_graph_for_block(block, self.parent.clone());
+ let old_parent = replace(&mut self.parent, np);
+ visit::walk_block(self, block);
+ self.parent = old_parent;
+ }
+
+}
+
+#[deriving(PartialEq)]
+enum FallbackChecks {
+ Everything,
+ OnlyTraitAndStatics
+}
+
+
+impl<'a> Resolver<'a> {
+ fn new(session: &'a Session, crate_span: Span) -> Resolver<'a> {
+ let graph_root = NameBindings::new();
+
+ graph_root.define_module(NoParentLink,
+ Some(DefId { krate: 0, node: 0 }),
+ NormalModuleKind,
+ false,
+ true,
+ crate_span);
+
+ let current_module = graph_root.get_module();
+
+ Resolver {
+ session: session,
+
+ // The outermost module has def ID 0; this is not reflected in the
+ // AST.
+
+ graph_root: graph_root,
+
+ trait_item_map: FnvHashMap::new(),
+ structs: FnvHashMap::new(),
+
+ unresolved_imports: 0,
+
+ current_module: current_module,
+ value_ribs: Vec::new(),
+ type_ribs: Vec::new(),
+ label_ribs: Vec::new(),
+
+ current_trait_ref: None,
+ current_self_type: None,
+
+ self_name: special_names::self_,
+ type_self_name: special_names::type_self,
+
+ primitive_type_table: PrimitiveTypeTable::new(),
+
+ def_map: RefCell::new(NodeMap::new()),
+ freevars: RefCell::new(NodeMap::new()),
+ freevars_seen: RefCell::new(NodeMap::new()),
+ capture_mode_map: NodeMap::new(),
+ export_map: NodeMap::new(),
+ trait_map: NodeMap::new(),
+ used_imports: HashSet::new(),
+ used_crates: HashSet::new(),
+ external_exports: DefIdSet::new(),
+ last_private: NodeMap::new(),
+
+ emit_errors: true,
+ }
+ }
+
+ //
+ // Reduced graph building
+ //
+ // Here we build the "reduced graph": the graph of the module tree without
+ // any imports resolved.
+ //
+
+ /// Constructs the reduced graph for the entire crate.
+ fn build_reduced_graph(&mut self, krate: &ast::Crate) {
+ let parent = ModuleReducedGraphParent(self.graph_root.get_module());
+ let mut visitor = BuildReducedGraphVisitor {
+ resolver: self,
+ parent: parent
+ };
+ visit::walk_crate(&mut visitor, krate);
+ }
+
+ /// Adds a new child item to the module definition of the parent node and
+ /// returns its corresponding name bindings as well as the current parent.
+ /// Or, if we're inside a block, creates (or reuses) an anonymous module
+ /// corresponding to the innermost block ID and returns the name bindings
+ /// as well as the newly-created parent.
+ ///
+ /// # Panics
+ ///
+ /// Panics if this node does not have a module definition and we are not inside
+ /// a block.
+ fn add_child(&self,
+ name: Name,
+ reduced_graph_parent: ReducedGraphParent,
+ duplicate_checking_mode: DuplicateCheckingMode,
+ // For printing errors
+ sp: Span)
+ -> Rc<NameBindings> {
+ // If this is the immediate descendant of a module, then we add the
+ // child name directly. Otherwise, we create or reuse an anonymous
+ // module and add the child to that.
+
+ let module_ = reduced_graph_parent.module();
+
+ self.check_for_conflicts_between_external_crates_and_items(&*module_,
+ name,
+ sp);
+
+ // Add or reuse the child.
+ let child = module_.children.borrow().get(&name).cloned();
+ match child {
+ None => {
+ let child = Rc::new(NameBindings::new());
+ module_.children.borrow_mut().insert(name, child.clone());
+ child
+ }
+ Some(child) => {
+ // Enforce the duplicate checking mode:
+ //
+ // * If we're requesting duplicate module checking, check that
+ // there isn't a module in the module with the same name.
+ //
+ // * If we're requesting duplicate type checking, check that
+ // there isn't a type in the module with the same name.
+ //
+ // * If we're requesting duplicate value checking, check that
+ // there isn't a value in the module with the same name.
+ //
+ // * If we're requesting duplicate type checking and duplicate
+ // value checking, check that there isn't a duplicate type
+ // and a duplicate value with the same name.
+ //
+ // * If no duplicate checking was requested at all, do
+ // nothing.
+
+ let mut duplicate_type = NoError;
+ let ns = match duplicate_checking_mode {
+ ForbidDuplicateModules => {
+ if child.get_module_if_available().is_some() {
+ duplicate_type = ModuleError;
+ }
+ Some(TypeNS)
+ }
+ ForbidDuplicateTypesAndModules => {
+ match child.def_for_namespace(TypeNS) {
+ None => {}
+ Some(_) if child.get_module_if_available()
+ .map(|m| m.kind.get()) ==
+ Some(ImplModuleKind) => {}
+ Some(_) => duplicate_type = TypeError
+ }
+ Some(TypeNS)
+ }
+ ForbidDuplicateValues => {
+ if child.defined_in_namespace(ValueNS) {
+ duplicate_type = ValueError;
+ }
+ Some(ValueNS)
+ }
+ ForbidDuplicateTypesAndValues => {
+ let mut n = None;
+ match child.def_for_namespace(TypeNS) {
+ Some(DefMod(_)) | None => {}
+ Some(_) => {
+ n = Some(TypeNS);
+ duplicate_type = TypeError;
+ }
+ };
+ if child.defined_in_namespace(ValueNS) {
+ duplicate_type = ValueError;
+ n = Some(ValueNS);
+ }
+ n
+ }
+ OverwriteDuplicates => None
+ };
+ if duplicate_type != NoError {
+ // Return an error here by looking up the namespace that
+ // had the duplicate.
+ let ns = ns.unwrap();
+ self.resolve_error(sp,
+ format!("duplicate definition of {} `{}`",
+ namespace_error_to_string(duplicate_type),
+ token::get_name(name)).as_slice());
+ {
+ let r = child.span_for_namespace(ns);
+ for sp in r.iter() {
+ self.session.span_note(*sp,
+ format!("first definition of {} `{}` here",
+ namespace_error_to_string(duplicate_type),
+ token::get_name(name)).as_slice());
+ }
+ }
+ }
+ child
+ }
+ }
+ }
+
+ fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
+ // If the block has view items, we need an anonymous module.
+ if block.view_items.len() > 0 {
+ return true;
+ }
+
+ // Check each statement.
+ for statement in block.stmts.iter() {
+ match statement.node {
+ StmtDecl(ref declaration, _) => {
+ match declaration.node {
+ DeclItem(_) => {
+ return true;
+ }
+ _ => {
+ // Keep searching.
+ }
+ }
+ }
+ _ => {
+ // Keep searching.
+ }
+ }
+ }
+
+ // If we found neither view items nor items, we don't need to create
+ // an anonymous module.
+
+ return false;
+ }
+
+ fn get_parent_link(&mut self, parent: ReducedGraphParent, name: Name)
+ -> ParentLink {
+ match parent {
+ ModuleReducedGraphParent(module_) => {
+ return ModuleParentLink(module_.downgrade(), name);
+ }
+ }
+ }
+
+ /// Constructs the reduced graph for one item.
+ fn build_reduced_graph_for_item(&mut self,
+ item: &Item,
+ parent: ReducedGraphParent)
+ -> ReducedGraphParent
+ {
+ let name = item.ident.name;
+ let sp = item.span;
+ let is_public = item.vis == ast::Public;
+ let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
+
+ match item.node {
+ ItemMod(..) => {
+ let name_bindings =
+ self.add_child(name, parent.clone(), ForbidDuplicateModules, sp);
+
+ let parent_link = self.get_parent_link(parent, name);
+ let def_id = DefId { krate: 0, node: item.id };
+ name_bindings.define_module(parent_link,
+ Some(def_id),
+ NormalModuleKind,
+ false,
+ item.vis == ast::Public,
+ sp);
+
+ ModuleReducedGraphParent(name_bindings.get_module())
+ }
+
+ ItemForeignMod(..) => parent,
+
+ // These items live in the value namespace.
+ ItemStatic(_, m, _) => {
+ let name_bindings =
+ self.add_child(name, parent.clone(), ForbidDuplicateValues, sp);
+ let mutbl = m == ast::MutMutable;
+
+ name_bindings.define_value
+ (DefStatic(local_def(item.id), mutbl), sp, modifiers);
+ parent
+ }
+ ItemConst(_, _) => {
+ self.add_child(name, parent.clone(), ForbidDuplicateValues, sp)
+ .define_value(DefConst(local_def(item.id)),
+ sp, modifiers);
+ parent
+ }
+ ItemFn(_, _, _, _, _) => {
+ let name_bindings =
+ self.add_child(name, parent.clone(), ForbidDuplicateValues, sp);
+
+ let def = DefFn(local_def(item.id), false);
+ name_bindings.define_value(def, sp, modifiers);
+ parent
+ }
+
+ // These items live in the type namespace.
+ ItemTy(..) => {
+ let name_bindings =
+ self.add_child(name,
+ parent.clone(),
+ ForbidDuplicateTypesAndModules,
+ sp);
+
+ name_bindings.define_type
+ (DefTy(local_def(item.id), false), sp, modifiers);
+ parent
+ }
+
+ ItemEnum(ref enum_definition, _) => {
+ let name_bindings =
+ self.add_child(name,
+ parent.clone(),
+ ForbidDuplicateTypesAndModules,
+ sp);
+
+ name_bindings.define_type
+ (DefTy(local_def(item.id), true), sp, modifiers);
+
+ let parent_link = self.get_parent_link(parent.clone(), name);
+ // We want to make sure the module type is EnumModuleKind
+ // even if there's already an ImplModuleKind module defined,
+ // since that's how we prevent duplicate enum definitions
+ name_bindings.set_module_kind(parent_link,
+ Some(local_def(item.id)),
+ EnumModuleKind,
+ false,
+ is_public,
+ sp);
+
+ for variant in (*enum_definition).variants.iter() {
+ self.build_reduced_graph_for_variant(
+ &**variant,
+ local_def(item.id),
+ ModuleReducedGraphParent(name_bindings.get_module()));
+ }
+ parent
+ }
+
+ // These items live in both the type and value namespaces.
+ ItemStruct(ref struct_def, _) => {
+ // Adding to both Type and Value namespaces or just Type?
+ let (forbid, ctor_id) = match struct_def.ctor_id {
+ Some(ctor_id) => (ForbidDuplicateTypesAndValues, Some(ctor_id)),
+ None => (ForbidDuplicateTypesAndModules, None)
+ };
+
+ let name_bindings = self.add_child(name, parent.clone(), forbid, sp);
+
+ // Define a name in the type namespace.
+ name_bindings.define_type(DefTy(local_def(item.id), false), sp, modifiers);
+
+ // If this is a newtype or unit-like struct, define a name
+ // in the value namespace as well
+ match ctor_id {
+ Some(cid) => {
+ name_bindings.define_value(DefStruct(local_def(cid)),
+ sp, modifiers);
+ }
+ None => {}
+ }
+
+ // Record the def ID and fields of this struct.
+ let named_fields = struct_def.fields.iter().filter_map(|f| {
+ match f.node.kind {
+ NamedField(ident, _) => Some(ident.name),
+ UnnamedField(_) => None
+ }
+ }).collect();
+ self.structs.insert(local_def(item.id), named_fields);
+
+ parent
+ }
+
+ ItemImpl(_, _, None, ref ty, ref impl_items) => {
+ // If this implements an anonymous trait, then add all the
+ // methods within to a new module, if the type was defined
+ // within this module.
+
+ let mod_name = match ty.node {
+ TyPath(ref path, _) if path.segments.len() == 1 => {
+ // FIXME(18446) we should distinguish between the name of
+ // a trait and the name of an impl of that trait.
+ Some(path.segments.last().unwrap().identifier.name)
+ }
+ TyObjectSum(ref lhs_ty, _) => {
+ match lhs_ty.node {
+ TyPath(ref path, _) if path.segments.len() == 1 => {
+ Some(path.segments.last().unwrap().identifier.name)
+ }
+ _ => {
+ None
+ }
+ }
+ }
+ _ => {
+ None
+ }
+ };
+
+ match mod_name {
+ None => {
+ self.resolve_error(ty.span,
+ "inherent implementations may \
+ only be implemented in the same \
+ module as the type they are \
+ implemented for")
+ }
+ Some(mod_name) => {
+ // Create the module and add all methods.
+ let parent_opt = parent.module().children.borrow()
+ .get(&mod_name).cloned();
+ let new_parent = match parent_opt {
+ // It already exists
+ Some(ref child) if child.get_module_if_available()
+ .is_some() &&
+ (child.get_module().kind.get() == ImplModuleKind ||
+ child.get_module().kind.get() == TraitModuleKind) => {
+ ModuleReducedGraphParent(child.get_module())
+ }
+ Some(ref child) if child.get_module_if_available()
+ .is_some() &&
+ child.get_module().kind.get() ==
+ EnumModuleKind => {
+ ModuleReducedGraphParent(child.get_module())
+ }
+ // Create the module
+ _ => {
+ let name_bindings =
+ self.add_child(mod_name,
+ parent.clone(),
+ ForbidDuplicateModules,
+ sp);
+
+ let parent_link =
+ self.get_parent_link(parent.clone(), name);
+ let def_id = local_def(item.id);
+ let ns = TypeNS;
+ let is_public =
+ !name_bindings.defined_in_namespace(ns) ||
+ name_bindings.defined_in_public_namespace(ns);
+
+ name_bindings.define_module(parent_link,
+ Some(def_id),
+ ImplModuleKind,
+ false,
+ is_public,
+ sp);
+
+ ModuleReducedGraphParent(
+ name_bindings.get_module())
+ }
+ };
+
+ // For each implementation item...
+ for impl_item in impl_items.iter() {
+ match *impl_item {
+ MethodImplItem(ref method) => {
+ // Add the method to the module.
+ let name = method.pe_ident().name;
+ let method_name_bindings =
+ self.add_child(name,
+ new_parent.clone(),
+ ForbidDuplicateValues,
+ method.span);
+ let def = match method.pe_explicit_self()
+ .node {
+ SelfStatic => {
+ // Static methods become
+ // `DefStaticMethod`s.
+ DefStaticMethod(local_def(method.id),
+ FromImpl(local_def(item.id)))
+ }
+ _ => {
+ // Non-static methods become
+ // `DefMethod`s.
+ DefMethod(local_def(method.id),
+ None,
+ FromImpl(local_def(item.id)))
+ }
+ };
+
+ // NB: not IMPORTABLE
+ let modifiers = if method.pe_vis() == ast::Public {
+ PUBLIC
+ } else {
+ DefModifiers::empty()
+ };
+ method_name_bindings.define_value(
+ def,
+ method.span,
+ modifiers);
+ }
+ TypeImplItem(ref typedef) => {
+ // Add the typedef to the module.
+ let name = typedef.ident.name;
+ let typedef_name_bindings =
+ self.add_child(
+ name,
+ new_parent.clone(),
+ ForbidDuplicateTypesAndModules,
+ typedef.span);
+ let def = DefAssociatedTy(local_def(
+ typedef.id));
+ // NB: not IMPORTABLE
+ let modifiers = if typedef.vis == ast::Public {
+ PUBLIC
+ } else {
+ DefModifiers::empty()
+ };
+ typedef_name_bindings.define_type(
+ def,
+ typedef.span,
+ modifiers);
+ }
+ }
+ }
+ }
+ }
+
+ parent
+ }
+
+ ItemImpl(_, _, Some(_), _, _) => parent,
+
+ ItemTrait(_, _, _, _, ref items) => {
+ let name_bindings =
+ self.add_child(name,
+ parent.clone(),
+ ForbidDuplicateTypesAndModules,
+ sp);
+
+ // Add all the items within to a new module.
+ let parent_link = self.get_parent_link(parent.clone(), name);
+ name_bindings.define_module(parent_link,
+ Some(local_def(item.id)),
+ TraitModuleKind,
+ false,
+ item.vis == ast::Public,
+ sp);
+ let module_parent = ModuleReducedGraphParent(name_bindings.
+ get_module());
+
+ let def_id = local_def(item.id);
+
+ // Add the names of all the items to the trait info.
+ for trait_item in items.iter() {
+ let (name, kind) = match *trait_item {
+ ast::RequiredMethod(_) |
+ ast::ProvidedMethod(_) => {
+ let ty_m = ast_util::trait_item_to_ty_method(trait_item);
+
+ let name = ty_m.ident.name;
+
+ // Add it as a name in the trait module.
+ let (def, static_flag) = match ty_m.explicit_self
+ .node {
+ SelfStatic => {
+ // Static methods become `DefStaticMethod`s.
+ (DefStaticMethod(
+ local_def(ty_m.id),
+ FromTrait(local_def(item.id))),
+ StaticMethodTraitItemKind)
+ }
+ _ => {
+ // Non-static methods become `DefMethod`s.
+ (DefMethod(local_def(ty_m.id),
+ Some(local_def(item.id)),
+ FromTrait(local_def(item.id))),
+ NonstaticMethodTraitItemKind)
+ }
+ };
+
+ let method_name_bindings =
+ self.add_child(name,
+ module_parent.clone(),
+ ForbidDuplicateTypesAndValues,
+ ty_m.span);
+ // NB: not IMPORTABLE
+ method_name_bindings.define_value(def,
+ ty_m.span,
+ PUBLIC);
+
+ (name, static_flag)
+ }
+ ast::TypeTraitItem(ref associated_type) => {
+ let def = DefAssociatedTy(local_def(
+ associated_type.ty_param.id));
+
+ let name_bindings =
+ self.add_child(associated_type.ty_param.ident.name,
+ module_parent.clone(),
+ ForbidDuplicateTypesAndValues,
+ associated_type.ty_param.span);
+ // NB: not IMPORTABLE
+ name_bindings.define_type(def,
+ associated_type.ty_param.span,
+ PUBLIC);
+
+ (associated_type.ty_param.ident.name, TypeTraitItemKind)
+ }
+ };
+
+ self.trait_item_map.insert((name, def_id), kind);
+ }
+
+ name_bindings.define_type(DefTrait(def_id), sp, modifiers);
+ parent
+ }
+ ItemMac(..) => parent
+ }
+ }
+
+ // Constructs the reduced graph for one variant. Variants exist in the
+ // type and value namespaces.
+ fn build_reduced_graph_for_variant(&mut self,
+ variant: &Variant,
+ item_id: DefId,
+ parent: ReducedGraphParent) {
+ let name = variant.node.name.name;
+ let is_exported = match variant.node.kind {
+ TupleVariantKind(_) => false,
+ StructVariantKind(_) => {
+ // Not adding fields for variants as they are not accessed with a self receiver
+ self.structs.insert(local_def(variant.node.id), Vec::new());
+ true
+ }
+ };
+
+ let child = self.add_child(name, parent,
+ ForbidDuplicateTypesAndValues,
+ variant.span);
+ // variants are always treated as importable to allow them to be glob
+ // used
+ child.define_value(DefVariant(item_id,
+ local_def(variant.node.id), is_exported),
+ variant.span, PUBLIC | IMPORTABLE);
+ child.define_type(DefVariant(item_id,
+ local_def(variant.node.id), is_exported),
+ variant.span, PUBLIC | IMPORTABLE);
+ }
+
+ /// Constructs the reduced graph for one 'view item'. View items consist
+ /// of imports and use directives.
+ fn build_reduced_graph_for_view_item(&mut self, view_item: &ViewItem,
+ parent: ReducedGraphParent) {
+ match view_item.node {
+ ViewItemUse(ref view_path) => {
+ // Extract and intern the module part of the path. For
+ // globs and lists, the path is found directly in the AST;
+ // for simple paths we have to munge the path a little.
+ let module_path = match view_path.node {
+ ViewPathSimple(_, ref full_path, _) => {
+ full_path.segments
+ .init()
+ .iter().map(|ident| ident.identifier.name)
+ .collect()
+ }
+
+ ViewPathGlob(ref module_ident_path, _) |
+ ViewPathList(ref module_ident_path, _, _) => {
+ module_ident_path.segments
+ .iter().map(|ident| ident.identifier.name).collect()
+ }
+ };
+
+ // Build up the import directives.
+ let module_ = parent.module();
+ let is_public = view_item.vis == ast::Public;
+ let shadowable =
+ view_item.attrs
+ .iter()
+ .any(|attr| {
+ attr.name() == token::get_name(
+ special_idents::prelude_import.name)
+ });
+
+ match view_path.node {
+ ViewPathSimple(binding, ref full_path, id) => {
+ let source_name =
+ full_path.segments.last().unwrap().identifier.name;
+ if token::get_name(source_name).get() == "mod" {
+ self.resolve_error(view_path.span,
+ "`mod` imports are only allowed within a { } list");
+ }
+
+ let subclass = SingleImport(binding.name,
+ source_name);
+ self.build_import_directive(&*module_,
+ module_path,
+ subclass,
+ view_path.span,
+ id,
+ is_public,
+ shadowable);
+ }
+ ViewPathList(_, ref source_items, _) => {
+ // Make sure there's at most one `mod` import in the list.
+ let mod_spans = source_items.iter().filter_map(|item| match item.node {
+ PathListMod { .. } => Some(item.span),
+ _ => None
+ }).collect::<Vec<Span>>();
+ if mod_spans.len() > 1 {
+ self.resolve_error(mod_spans[0],
+ "`mod` import can only appear once in the list");
+ for other_span in mod_spans.iter().skip(1) {
+ self.session.span_note(*other_span,
+ "another `mod` import appears here");
+ }
+ }
+
+ for source_item in source_items.iter() {
+ let (module_path, name) = match source_item.node {
+ PathListIdent { name, .. } =>
+ (module_path.clone(), name.name),
+ PathListMod { .. } => {
+ let name = match module_path.last() {
+ Some(name) => *name,
+ None => {
+ self.resolve_error(source_item.span,
+ "`mod` import can only appear in an import list \
+ with a non-empty prefix");
+ continue;
+ }
+ };
+ let module_path = module_path.init();
+ (module_path.to_vec(), name)
+ }
+ };
+ self.build_import_directive(
+ &*module_,
+ module_path,
+ SingleImport(name, name),
+ source_item.span,
+ source_item.node.id(),
+ is_public,
+ shadowable);
+ }
+ }
+ ViewPathGlob(_, id) => {
+ self.build_import_directive(&*module_,
+ module_path,
+ GlobImport,
+ view_path.span,
+ id,
+ is_public,
+ shadowable);
+ }
+ }
+ }
+
+ ViewItemExternCrate(name, _, node_id) => {
+ // n.b. we don't need to look at the path option here, because cstore already did
+ for &crate_id in self.session.cstore
+ .find_extern_mod_stmt_cnum(node_id).iter() {
+ let def_id = DefId { krate: crate_id, node: 0 };
+ self.external_exports.insert(def_id);
+ let parent_link =
+ ModuleParentLink(parent.module().downgrade(), name.name);
+ let external_module = Rc::new(Module::new(parent_link,
+ Some(def_id),
+ NormalModuleKind,
+ false,
+ true));
+ debug!("(build reduced graph for item) found extern `{}`",
+ self.module_to_string(&*external_module));
+ self.check_for_conflicts_between_external_crates(
+ &*parent.module(),
+ name.name,
+ view_item.span);
+ parent.module().external_module_children.borrow_mut()
+ .insert(name.name, external_module.clone());
+ self.build_reduced_graph_for_external_crate(external_module);
+ }
+ }
+ }
+ }
+
+ /// Constructs the reduced graph for one foreign item.
+ fn build_reduced_graph_for_foreign_item<F>(&mut self,
+ foreign_item: &ForeignItem,
+ parent: ReducedGraphParent,
+ f: F) where
+ F: FnOnce(&mut Resolver),
+ {
+ let name = foreign_item.ident.name;
+ let is_public = foreign_item.vis == ast::Public;
+ let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
+ let name_bindings =
+ self.add_child(name, parent, ForbidDuplicateValues,
+ foreign_item.span);
+
+ match foreign_item.node {
+ ForeignItemFn(_, ref generics) => {
+ let def = DefFn(local_def(foreign_item.id), false);
+ name_bindings.define_value(def, foreign_item.span, modifiers);
+
+ self.with_type_parameter_rib(
+ HasTypeParameters(generics,
+ FnSpace,
+ foreign_item.id,
+ NormalRibKind),
+ f);
+ }
+ ForeignItemStatic(_, m) => {
+ let def = DefStatic(local_def(foreign_item.id), m);
+ name_bindings.define_value(def, foreign_item.span, modifiers);
+
+ f(self)
+ }
+ }
+ }
+
+ fn build_reduced_graph_for_block(&mut self,
+ block: &Block,
+ parent: ReducedGraphParent)
+ -> ReducedGraphParent
+ {
+ if self.block_needs_anonymous_module(block) {
+ let block_id = block.id;
+
+ debug!("(building reduced graph for block) creating a new \
+ anonymous module for block {}",
+ block_id);
+
+ let parent_module = parent.module();
+ let new_module = Rc::new(Module::new(
+ BlockParentLink(parent_module.downgrade(), block_id),
+ None,
+ AnonymousModuleKind,
+ false,
+ false));
+ parent_module.anonymous_children.borrow_mut()
+ .insert(block_id, new_module.clone());
+ ModuleReducedGraphParent(new_module)
+ } else {
+ parent
+ }
+ }
+
+ fn handle_external_def(&mut self,
+ def: Def,
+ vis: Visibility,
+ child_name_bindings: &NameBindings,
+ final_ident: &str,
+ name: Name,
+ new_parent: ReducedGraphParent) {
+ debug!("(building reduced graph for \
+ external crate) building external def, priv {}",
+ vis);
+ let is_public = vis == ast::Public;
+ let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE;
+ let is_exported = is_public && match new_parent {
+ ModuleReducedGraphParent(ref module) => {
+ match module.def_id.get() {
+ None => true,
+ Some(did) => self.external_exports.contains(&did)
+ }
+ }
+ };
+ if is_exported {
+ self.external_exports.insert(def.def_id());
+ }
+
+ let kind = match def {
+ DefTy(_, true) => EnumModuleKind,
+ DefStruct(..) | DefTy(..) => ImplModuleKind,
+ _ => NormalModuleKind
+ };
+
+ match def {
+ DefMod(def_id) | DefForeignMod(def_id) | DefStruct(def_id) |
+ DefTy(def_id, _) => {
+ let type_def = child_name_bindings.type_def.borrow().clone();
+ match type_def {
+ Some(TypeNsDef { module_def: Some(module_def), .. }) => {
+ debug!("(building reduced graph for external crate) \
+ already created module");
+ module_def.def_id.set(Some(def_id));
+ }
+ Some(_) | None => {
+ debug!("(building reduced graph for \
+ external crate) building module \
+ {}", final_ident);
+ let parent_link = self.get_parent_link(new_parent.clone(), name);
+
+ child_name_bindings.define_module(parent_link,
+ Some(def_id),
+ kind,
+ true,
+ is_public,
+ DUMMY_SP);
+ }
+ }
+ }
+ _ => {}
+ }
+
+ match def {
+ DefMod(_) | DefForeignMod(_) => {}
+ DefVariant(_, variant_id, is_struct) => {
+ debug!("(building reduced graph for external crate) building \
+ variant {}",
+ final_ident);
+ // variants are always treated as importable to allow them to be
+ // glob used
+ let modifiers = PUBLIC | IMPORTABLE;
+ if is_struct {
+ child_name_bindings.define_type(def, DUMMY_SP, modifiers);
+ // Not adding fields for variants as they are not accessed with a self receiver
+ self.structs.insert(variant_id, Vec::new());
+ } else {
+ child_name_bindings.define_value(def, DUMMY_SP, modifiers);
+ }
+ }
+ DefFn(ctor_id, true) => {
+ child_name_bindings.define_value(
+ csearch::get_tuple_struct_definition_if_ctor(&self.session.cstore, ctor_id)
+ .map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, modifiers);
+ }
+ DefFn(..) | DefStaticMethod(..) | DefStatic(..) | DefConst(..) | DefMethod(..) => {
+ debug!("(building reduced graph for external \
+ crate) building value (fn/static) {}", final_ident);
+ // impl methods have already been defined with the correct importability modifier
+ let mut modifiers = match *child_name_bindings.value_def.borrow() {
+ Some(ref def) => (modifiers & !IMPORTABLE) | (def.modifiers & IMPORTABLE),
+ None => modifiers
+ };
+ if new_parent.module().kind.get() != NormalModuleKind {
+ modifiers = modifiers & !IMPORTABLE;
+ }
+ child_name_bindings.define_value(def, DUMMY_SP, modifiers);
+ }
+ DefTrait(def_id) => {
+ debug!("(building reduced graph for external \
+ crate) building type {}", final_ident);
+
+ // If this is a trait, add all the trait item names to the trait
+ // info.
+
+ let trait_item_def_ids =
+ csearch::get_trait_item_def_ids(&self.session.cstore, def_id);
+ for trait_item_def_id in trait_item_def_ids.iter() {
+ let (trait_item_name, trait_item_kind) =
+ csearch::get_trait_item_name_and_kind(
+ &self.session.cstore,
+ trait_item_def_id.def_id());
+
+ debug!("(building reduced graph for external crate) ... \
+ adding trait item '{}'",
+ token::get_name(trait_item_name));
+
+ self.trait_item_map.insert((trait_item_name, def_id), trait_item_kind);
+
+ if is_exported {
+ self.external_exports
+ .insert(trait_item_def_id.def_id());
+ }
+ }
+
+ child_name_bindings.define_type(def, DUMMY_SP, modifiers);
+
+ // Define a module if necessary.
+ let parent_link = self.get_parent_link(new_parent, name);
+ child_name_bindings.set_module_kind(parent_link,
+ Some(def_id),
+ TraitModuleKind,
+ true,
+ is_public,
+ DUMMY_SP)
+ }
+ DefTy(..) | DefAssociatedTy(..) | DefAssociatedPath(..) => {
+ debug!("(building reduced graph for external \
+ crate) building type {}", final_ident);
+
+ child_name_bindings.define_type(def, DUMMY_SP, modifiers);
+ }
+ DefStruct(def_id) => {
+ debug!("(building reduced graph for external \
+ crate) building type and value for {}",
+ final_ident);
+ child_name_bindings.define_type(def, DUMMY_SP, modifiers);
+ let fields = csearch::get_struct_fields(&self.session.cstore, def_id).iter().map(|f| {
+ f.name
+ }).collect::<Vec<_>>();
+
+ if fields.len() == 0 {
+ child_name_bindings.define_value(def, DUMMY_SP, modifiers);
+ }
+
+ // Record the def ID and fields of this struct.
+ self.structs.insert(def_id, fields);
+ }
+ DefLocal(..) | DefPrimTy(..) | DefTyParam(..) |
+ DefUse(..) | DefUpvar(..) | DefRegion(..) |
+ DefTyParamBinder(..) | DefLabel(..) | DefSelfTy(..) => {
+ panic!("didn't expect `{}`", def);
+ }
+ }
+ }
+
+ /// Builds the reduced graph for a single item in an external crate.
+ fn build_reduced_graph_for_external_crate_def(&mut self,
+ root: Rc<Module>,
+ def_like: DefLike,
+ name: Name,
+ visibility: Visibility) {
+ match def_like {
+ DlDef(def) => {
+ // Add the new child item, if necessary.
+ match def {
+ DefForeignMod(def_id) => {
+ // Foreign modules have no names. Recur and populate
+ // eagerly.
+ csearch::each_child_of_item(&self.session.cstore,
+ def_id,
+ |def_like,
+ child_name,
+ vis| {
+ self.build_reduced_graph_for_external_crate_def(
+ root.clone(),
+ def_like,
+ child_name,
+ vis)
+ });
+ }
+ _ => {
+ let child_name_bindings =
+ self.add_child(name,
+ ModuleReducedGraphParent(root.clone()),
+ OverwriteDuplicates,
+ DUMMY_SP);
+
+ self.handle_external_def(def,
+ visibility,
+ &*child_name_bindings,
+ token::get_name(name).get(),
+ name,
+ ModuleReducedGraphParent(root));
+ }
+ }
+ }
+ DlImpl(def) => {
+ match csearch::get_type_name_if_impl(&self.session.cstore, def) {
+ None => {}
+ Some(final_name) => {
+ let methods_opt =
+ csearch::get_methods_if_impl(&self.session.cstore, def);
+ match methods_opt {
+ Some(ref methods) if
+ methods.len() >= 1 => {
+ debug!("(building reduced graph for \
+ external crate) processing \
+ static methods for type name {}",
+ token::get_name(final_name));
+
+ let child_name_bindings =
+ self.add_child(
+ final_name,
+ ModuleReducedGraphParent(root.clone()),
+ OverwriteDuplicates,
+ DUMMY_SP);
+
+ // Process the static methods. First,
+ // create the module.
+ let type_module;
+ let type_def = child_name_bindings.type_def.borrow().clone();
+ match type_def {
+ Some(TypeNsDef {
+ module_def: Some(module_def),
+ ..
+ }) => {
+ // We already have a module. This
+ // is OK.
+ type_module = module_def;
+
+ // Mark it as an impl module if
+ // necessary.
+ type_module.kind.set(ImplModuleKind);
+ }
+ Some(_) | None => {
+ let parent_link =
+ self.get_parent_link(ModuleReducedGraphParent(root),
+ final_name);
+ child_name_bindings.define_module(
+ parent_link,
+ Some(def),
+ ImplModuleKind,
+ true,
+ true,
+ DUMMY_SP);
+ type_module =
+ child_name_bindings.
+ get_module();
+ }
+ }
+
+ // Add each static method to the module.
+ let new_parent =
+ ModuleReducedGraphParent(type_module);
+ for method_info in methods.iter() {
+ let name = method_info.name;
+ debug!("(building reduced graph for \
+ external crate) creating \
+ static method '{}'",
+ token::get_name(name));
+
+ let method_name_bindings =
+ self.add_child(name,
+ new_parent.clone(),
+ OverwriteDuplicates,
+ DUMMY_SP);
+ let def = DefFn(method_info.def_id, false);
+
+ // NB: not IMPORTABLE
+ let modifiers = if visibility == ast::Public {
+ PUBLIC
+ } else {
+ DefModifiers::empty()
+ };
+ method_name_bindings.define_value(
+ def, DUMMY_SP, modifiers);
+ }
+ }
+
+ // Otherwise, do nothing.
+ Some(_) | None => {}
+ }
+ }
+ }
+ }
+ DlField => {
+ debug!("(building reduced graph for external crate) \
+ ignoring field");
+ }
+ }
+ }
+
+ /// Builds the reduced graph rooted at the given external module.
+ fn populate_external_module(&mut self, module: Rc<Module>) {
+ debug!("(populating external module) attempting to populate {}",
+ self.module_to_string(&*module));
+
+ let def_id = match module.def_id.get() {
+ None => {
+ debug!("(populating external module) ... no def ID!");
+ return
+ }
+ Some(def_id) => def_id,
+ };
+
+ csearch::each_child_of_item(&self.session.cstore,
+ def_id,
+ |def_like, child_name, visibility| {
+ debug!("(populating external module) ... found ident: {}",
+ token::get_name(child_name));
+ self.build_reduced_graph_for_external_crate_def(module.clone(),
+ def_like,
+ child_name,
+ visibility)
+ });
+ module.populated.set(true)
+ }
+
+ /// Ensures that the reduced graph rooted at the given external module
+ /// is built, building it if it is not.
+ fn populate_module_if_necessary(&mut self, module: &Rc<Module>) {
+ if !module.populated.get() {
+ self.populate_external_module(module.clone())
+ }
+ assert!(module.populated.get())
+ }
+
+ /// Builds the reduced graph rooted at the 'use' directive for an external
+ /// crate.
+ fn build_reduced_graph_for_external_crate(&mut self, root: Rc<Module>) {
+ csearch::each_top_level_item_of_crate(&self.session.cstore,
+ root.def_id
+ .get()
+ .unwrap()
+ .krate,
+ |def_like, name, visibility| {
+ self.build_reduced_graph_for_external_crate_def(root.clone(),
+ def_like,
+ name,
+ visibility)
+ });
+ }
+
+ /// Creates and adds an import directive to the given module.
+ fn build_import_directive(&mut self,
+ module_: &Module,
+ module_path: Vec<Name>,
+ subclass: ImportDirectiveSubclass,
+ span: Span,
+ id: NodeId,
+ is_public: bool,
+ shadowable: bool) {
+ module_.imports.borrow_mut().push(ImportDirective::new(module_path,
+ subclass,
+ span,
+ id,
+ is_public,
+ shadowable));
+ self.unresolved_imports += 1;
+ // Bump the reference count on the name. Or, if this is a glob, set
+ // the appropriate flag.
+
+ match subclass {
+ SingleImport(target, _) => {
+ debug!("(building import directive) building import \
+ directive: {}::{}",
+ self.names_to_string(module_.imports.borrow().last().unwrap()
+ .module_path.as_slice()),
+ token::get_name(target));
+
+ let mut import_resolutions = module_.import_resolutions
+ .borrow_mut();
+ match import_resolutions.get_mut(&target) {
+ Some(resolution) => {
+ debug!("(building import directive) bumping \
+ reference");
+ resolution.outstanding_references += 1;
+
+ // the source of this name is different now
+ resolution.type_id = id;
+ resolution.value_id = id;
+ resolution.is_public = is_public;
+ return;
+ }
+ None => {}
+ }
+ debug!("(building import directive) creating new");
+ let mut resolution = ImportResolution::new(id, is_public);
+ resolution.outstanding_references = 1;
+ import_resolutions.insert(target, resolution);
+ }
+ GlobImport => {
+ // Set the glob flag. This tells us that we don't know the
+ // module's exports ahead of time.
+
+ module_.glob_count.set(module_.glob_count.get() + 1);
+ }
+ }
+ }
+
+ // Import resolution
+ //
+ // This is a fixed-point algorithm. We resolve imports until our efforts
+ // are stymied by an unresolved import; then we bail out of the current
+ // module and continue. We terminate successfully once no more imports
+ // remain or unsuccessfully when no forward progress in resolving imports
+ // is made.
+
+ /// Resolves all imports for the crate. This method performs the fixed-
+ /// point iteration.
+ fn resolve_imports(&mut self) {
+ let mut i = 0u;
+ let mut prev_unresolved_imports = 0;
+ loop {
+ debug!("(resolving imports) iteration {}, {} imports left",
+ i, self.unresolved_imports);
+
+ let module_root = self.graph_root.get_module();
+ self.resolve_imports_for_module_subtree(module_root.clone());
+
+ if self.unresolved_imports == 0 {
+ debug!("(resolving imports) success");
+ break;
+ }
+
+ if self.unresolved_imports == prev_unresolved_imports {
+ self.report_unresolved_imports(module_root);
+ break;
+ }
+
+ i += 1;
+ prev_unresolved_imports = self.unresolved_imports;
+ }
+ }
+
+ /// Attempts to resolve imports for the given module and all of its
+ /// submodules.
+ fn resolve_imports_for_module_subtree(&mut self, module_: Rc<Module>) {
+ debug!("(resolving imports for module subtree) resolving {}",
+ self.module_to_string(&*module_));
+ let orig_module = replace(&mut self.current_module, module_.clone());
+ self.resolve_imports_for_module(module_.clone());
+ self.current_module = orig_module;
+
+ self.populate_module_if_necessary(&module_);
+ for (_, child_node) in module_.children.borrow().iter() {
+ match child_node.get_module_if_available() {
+ None => {
+ // Nothing to do.
+ }
+ Some(child_module) => {
+ self.resolve_imports_for_module_subtree(child_module);
+ }
+ }
+ }
+
+ for (_, child_module) in module_.anonymous_children.borrow().iter() {
+ self.resolve_imports_for_module_subtree(child_module.clone());
+ }
+ }
+
+ /// Attempts to resolve imports for the given module only.
+ fn resolve_imports_for_module(&mut self, module: Rc<Module>) {
+ if module.all_imports_resolved() {
+ debug!("(resolving imports for module) all imports resolved for \
+ {}",
+ self.module_to_string(&*module));
+ return;
+ }
+
+ let imports = module.imports.borrow();
+ let import_count = imports.len();
+ while module.resolved_import_count.get() < import_count {
+ let import_index = module.resolved_import_count.get();
+ let import_directive = &(*imports)[import_index];
+ match self.resolve_import_for_module(module.clone(),
+ import_directive) {
+ Failed(err) => {
+ let (span, help) = match err {
+ Some((span, msg)) => (span, format!(". {}", msg)),
+ None => (import_directive.span, String::new())
+ };
+ let msg = format!("unresolved import `{}`{}",
+ self.import_path_to_string(
+ import_directive.module_path
+ .as_slice(),
+ import_directive.subclass),
+ help);
+ self.resolve_error(span, msg.as_slice());
+ }
+ Indeterminate => break, // Bail out. We'll come around next time.
+ Success(()) => () // Good. Continue.
+ }
+
+ module.resolved_import_count
+ .set(module.resolved_import_count.get() + 1);
+ }
+ }
+
+ fn names_to_string(&self, names: &[Name]) -> String {
+ let mut first = true;
+ let mut result = String::new();
+ for name in names.iter() {
+ if first {
+ first = false
+ } else {
+ result.push_str("::")
+ }
+ result.push_str(token::get_name(*name).get());
+ };
+ result
+ }
+
+ fn path_names_to_string(&self, path: &Path) -> String {
+ let names: Vec<ast::Name> = path.segments
+ .iter()
+ .map(|seg| seg.identifier.name)
+ .collect();
+ self.names_to_string(names.as_slice())
+ }
+
+ fn import_directive_subclass_to_string(&mut self,
+ subclass: ImportDirectiveSubclass)
+ -> String {
+ match subclass {
+ SingleImport(_, source) => {
+ token::get_name(source).get().to_string()
+ }
+ GlobImport => "*".to_string()
+ }
+ }
+
+ fn import_path_to_string(&mut self,
+ names: &[Name],
+ subclass: ImportDirectiveSubclass)
+ -> String {
+ if names.is_empty() {
+ self.import_directive_subclass_to_string(subclass)
+ } else {
+ (format!("{}::{}",
+ self.names_to_string(names),
+ self.import_directive_subclass_to_string(
+ subclass))).to_string()
+ }
+ }
+
+ /// Attempts to resolve the given import. The return value indicates
+ /// failure if we're certain the name does not exist, indeterminate if we
+ /// don't know whether the name exists at the moment due to other
+ /// currently-unresolved imports, or success if we know the name exists.
+ /// If successful, the resolved bindings are written into the module.
+ fn resolve_import_for_module(&mut self,
+ module_: Rc<Module>,
+ import_directive: &ImportDirective)
+ -> ResolveResult<()> {
+ let mut resolution_result = Failed(None);
+ let module_path = &import_directive.module_path;
+
+ debug!("(resolving import for module) resolving import `{}::...` in \
+ `{}`",
+ self.names_to_string(module_path.as_slice()),
+ self.module_to_string(&*module_));
+
+ // First, resolve the module path for the directive, if necessary.
+ let container = if module_path.len() == 0 {
+ // Use the crate root.
+ Some((self.graph_root.get_module(), LastMod(AllPublic)))
+ } else {
+ match self.resolve_module_path(module_.clone(),
+ module_path.as_slice(),
+ DontUseLexicalScope,
+ import_directive.span,
+ ImportSearch) {
+ Failed(err) => {
+ resolution_result = Failed(err);
+ None
+ },
+ Indeterminate => {
+ resolution_result = Indeterminate;
+ None
+ }
+ Success(container) => Some(container),
+ }
+ };
+
+ match container {
+ None => {}
+ Some((containing_module, lp)) => {
+ // We found the module that the target is contained
+ // within. Attempt to resolve the import within it.
+
+ match import_directive.subclass {
+ SingleImport(target, source) => {
+ resolution_result =
+ self.resolve_single_import(&*module_,
+ containing_module,
+ target,
+ source,
+ import_directive,
+ lp);
+ }
+ GlobImport => {
+ resolution_result =
+ self.resolve_glob_import(&*module_,
+ containing_module,
+ import_directive,
+ lp);
+ }
+ }
+ }
+ }
+
+ // Decrement the count of unresolved imports.
+ match resolution_result {
+ Success(()) => {
+ assert!(self.unresolved_imports >= 1);
+ self.unresolved_imports -= 1;
+ }
+ _ => {
+ // Nothing to do here; just return the error.
+ }
+ }
+
+ // Decrement the count of unresolved globs if necessary. But only if
+ // the resolution result is indeterminate -- otherwise we'll stop
+ // processing imports here. (See the loop in
+ // resolve_imports_for_module.)
+
+ if !resolution_result.indeterminate() {
+ match import_directive.subclass {
+ GlobImport => {
+ assert!(module_.glob_count.get() >= 1);
+ module_.glob_count.set(module_.glob_count.get() - 1);
+ }
+ SingleImport(..) => {
+ // Ignore.
+ }
+ }
+ }
+
+ return resolution_result;
+ }
+
+ fn create_name_bindings_from_module(module: Rc<Module>) -> NameBindings {
+ NameBindings {
+ type_def: RefCell::new(Some(TypeNsDef {
+ modifiers: IMPORTABLE,
+ module_def: Some(module),
+ type_def: None,
+ type_span: None
+ })),
+ value_def: RefCell::new(None),
+ }
+ }
+
+ fn resolve_single_import(&mut self,
+ module_: &Module,
+ containing_module: Rc<Module>,
+ target: Name,
+ source: Name,
+ directive: &ImportDirective,
+ lp: LastPrivate)
+ -> ResolveResult<()> {
+ debug!("(resolving single import) resolving `{}` = `{}::{}` from \
+ `{}` id {}, last private {}",
+ token::get_name(target),
+ self.module_to_string(&*containing_module),
+ token::get_name(source),
+ self.module_to_string(module_),
+ directive.id,
+ lp);
+
+ let lp = match lp {
+ LastMod(lp) => lp,
+ LastImport {..} => {
+ self.session
+ .span_bug(directive.span,
+ "not expecting Import here, must be LastMod")
+ }
+ };
+
+ // We need to resolve both namespaces for this to succeed.
+ //
+
+ let mut value_result = UnknownResult;
+ let mut type_result = UnknownResult;
+
+ // Search for direct children of the containing module.
+ self.populate_module_if_necessary(&containing_module);
+
+ match containing_module.children.borrow().get(&source) {
+ None => {
+ // Continue.
+ }
+ Some(ref child_name_bindings) => {
+ if child_name_bindings.defined_in_namespace(ValueNS) {
+ debug!("(resolving single import) found value binding");
+ value_result = BoundResult(containing_module.clone(),
+ (*child_name_bindings).clone());
+ }
+ if child_name_bindings.defined_in_namespace(TypeNS) {
+ debug!("(resolving single import) found type binding");
+ type_result = BoundResult(containing_module.clone(),
+ (*child_name_bindings).clone());
+ }
+ }
+ }
+
+ // Unless we managed to find a result in both namespaces (unlikely),
+ // search imports as well.
+ let mut value_used_reexport = false;
+ let mut type_used_reexport = false;
+ match (value_result.clone(), type_result.clone()) {
+ (BoundResult(..), BoundResult(..)) => {} // Continue.
+ _ => {
+ // If there is an unresolved glob at this point in the
+ // containing module, bail out. We don't know enough to be
+ // able to resolve this import.
+
+ if containing_module.glob_count.get() > 0 {
+ debug!("(resolving single import) unresolved glob; \
+ bailing out");
+ return Indeterminate;
+ }
+
+ // Now search the exported imports within the containing module.
+ match containing_module.import_resolutions.borrow().get(&source) {
+ None => {
+ debug!("(resolving single import) no import");
+ // The containing module definitely doesn't have an
+ // exported import with the name in question. We can
+ // therefore accurately report that the names are
+ // unbound.
+
+ if value_result.is_unknown() {
+ value_result = UnboundResult;
+ }
+ if type_result.is_unknown() {
+ type_result = UnboundResult;
+ }
+ }
+ Some(import_resolution)
+ if import_resolution.outstanding_references == 0 => {
+
+ fn get_binding(this: &mut Resolver,
+ import_resolution: &ImportResolution,
+ namespace: Namespace)
+ -> NamespaceResult {
+
+ // Import resolutions must be declared with "pub"
+ // in order to be exported.
+ if !import_resolution.is_public {
+ return UnboundResult;
+ }
+
+ match import_resolution.
+ target_for_namespace(namespace) {
+ None => {
+ return UnboundResult;
+ }
+ Some(Target {
+ target_module,
+ bindings,
+ shadowable: _
+ }) => {
+ debug!("(resolving single import) found \
+ import in ns {}", namespace);
+ let id = import_resolution.id(namespace);
+ // track used imports and extern crates as well
+ this.used_imports.insert((id, namespace));
+ match target_module.def_id.get() {
+ Some(DefId{krate: kid, ..}) => {
+ this.used_crates.insert(kid);
+ },
+ _ => {}
+ }
+ return BoundResult(target_module, bindings);
+ }
+ }
+ }
+
+ // The name is an import which has been fully
+ // resolved. We can, therefore, just follow it.
+ if value_result.is_unknown() {
+ value_result = get_binding(self, import_resolution,
+ ValueNS);
+ value_used_reexport = import_resolution.is_public;
+ }
+ if type_result.is_unknown() {
+ type_result = get_binding(self, import_resolution,
+ TypeNS);
+ type_used_reexport = import_resolution.is_public;
+ }
+
+ }
+ Some(_) => {
+ // If containing_module is the same module whose import we are resolving
+ // and there it has an unresolved import with the same name as `source`,
+ // then the user is actually trying to import an item that is declared
+ // in the same scope
+ //
+ // e.g
+ // use self::submodule;
+ // pub mod submodule;
+ //
+ // In this case we continue as if we resolved the import and let the
+ // check_for_conflicts_between_imports_and_items call below handle
+ // the conflict
+ match (module_.def_id.get(), containing_module.def_id.get()) {
+ (Some(id1), Some(id2)) if id1 == id2 => {
+ if value_result.is_unknown() {
+ value_result = UnboundResult;
+ }
+ if type_result.is_unknown() {
+ type_result = UnboundResult;
+ }
+ }
+ _ => {
+ // The import is unresolved. Bail out.
+ debug!("(resolving single import) unresolved import; \
+ bailing out");
+ return Indeterminate;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // If we didn't find a result in the type namespace, search the
+ // external modules.
+ let mut value_used_public = false;
+ let mut type_used_public = false;
+ match type_result {
+ BoundResult(..) => {}
+ _ => {
+ match containing_module.external_module_children.borrow_mut()
+ .get(&source).cloned() {
+ None => {} // Continue.
+ Some(module) => {
+ debug!("(resolving single import) found external \
+ module");
+ // track the module as used.
+ match module.def_id.get() {
+ Some(DefId{krate: kid, ..}) => { self.used_crates.insert(kid); },
+ _ => {}
+ }
+ let name_bindings =
+ Rc::new(Resolver::create_name_bindings_from_module(
+ module));
+ type_result = BoundResult(containing_module.clone(),
+ name_bindings);
+ type_used_public = true;
+ }
+ }
+ }
+ }
+
+ // We've successfully resolved the import. Write the results in.
+ let mut import_resolutions = module_.import_resolutions.borrow_mut();
+ let import_resolution = &mut (*import_resolutions)[target];
+
+ match value_result {
+ BoundResult(ref target_module, ref name_bindings) => {
+ debug!("(resolving single import) found value target: {}",
+ { name_bindings.value_def.borrow().clone().unwrap().def });
+ self.check_for_conflicting_import(
+ &import_resolution.value_target,
+ directive.span,
+ target,
+ ValueNS);
+
+ self.check_that_import_is_importable(
+ &**name_bindings,
+ directive.span,
+ target,
+ ValueNS);
+
+ import_resolution.value_target =
+ Some(Target::new(target_module.clone(),
+ name_bindings.clone(),
+ directive.shadowable));
+ import_resolution.value_id = directive.id;
+ import_resolution.is_public = directive.is_public;
+ value_used_public = name_bindings.defined_in_public_namespace(ValueNS);
+ }
+ UnboundResult => { /* Continue. */ }
+ UnknownResult => {
+ panic!("value result should be known at this point");
+ }
+ }
+ match type_result {
+ BoundResult(ref target_module, ref name_bindings) => {
+ debug!("(resolving single import) found type target: {}",
+ { name_bindings.type_def.borrow().clone().unwrap().type_def });
+ self.check_for_conflicting_import(
+ &import_resolution.type_target,
+ directive.span,
+ target,
+ TypeNS);
+
+ self.check_that_import_is_importable(
+ &**name_bindings,
+ directive.span,
+ target,
+ TypeNS);
+
+ import_resolution.type_target =
+ Some(Target::new(target_module.clone(),
+ name_bindings.clone(),
+ directive.shadowable));
+ import_resolution.type_id = directive.id;
+ import_resolution.is_public = directive.is_public;
+ type_used_public = name_bindings.defined_in_public_namespace(TypeNS);
+ }
+ UnboundResult => { /* Continue. */ }
+ UnknownResult => {
+ panic!("type result should be known at this point");
+ }
+ }
+
+ self.check_for_conflicts_between_imports_and_items(
+ module_,
+ import_resolution,
+ directive.span,
+ target);
+
+ if value_result.is_unbound() && type_result.is_unbound() {
+ let msg = format!("There is no `{}` in `{}`",
+ token::get_name(source),
+ self.module_to_string(&*containing_module));
+ return Failed(Some((directive.span, msg)));
+ }
+ let value_used_public = value_used_reexport || value_used_public;
+ let type_used_public = type_used_reexport || type_used_public;
+
+ assert!(import_resolution.outstanding_references >= 1);
+ import_resolution.outstanding_references -= 1;
+
+ // record what this import resolves to for later uses in documentation,
+ // this may resolve to either a value or a type, but for documentation
+ // purposes it's good enough to just favor one over the other.
+ let value_private = match import_resolution.value_target {
+ Some(ref target) => {
+ let def = target.bindings.def_for_namespace(ValueNS).unwrap();
+ self.def_map.borrow_mut().insert(directive.id, def);
+ let did = def.def_id();
+ if value_used_public {Some(lp)} else {Some(DependsOn(did))}
+ },
+ // AllPublic here and below is a dummy value, it should never be used because
+ // _exists is false.
+ None => None,
+ };
+ let type_private = match import_resolution.type_target {
+ Some(ref target) => {
+ let def = target.bindings.def_for_namespace(TypeNS).unwrap();
+ self.def_map.borrow_mut().insert(directive.id, def);
+ let did = def.def_id();
+ if type_used_public {Some(lp)} else {Some(DependsOn(did))}
+ },
+ None => None,
+ };
+
+ self.last_private.insert(directive.id, LastImport{value_priv: value_private,
+ value_used: Used,
+ type_priv: type_private,
+ type_used: Used});
+
+ debug!("(resolving single import) successfully resolved import");
+ return Success(());
+ }
+
+ // Resolves a glob import. Note that this function cannot panic; it either
+ // succeeds or bails out (as importing * from an empty module or a module
+ // that exports nothing is valid).
+ fn resolve_glob_import(&mut self,
+ module_: &Module,
+ containing_module: Rc<Module>,
+ import_directive: &ImportDirective,
+ lp: LastPrivate)
+ -> ResolveResult<()> {
+ let id = import_directive.id;
+ let is_public = import_directive.is_public;
+
+ // This function works in a highly imperative manner; it eagerly adds
+ // everything it can to the list of import resolutions of the module
+ // node.
+ debug!("(resolving glob import) resolving glob import {}", id);
+
+ // We must bail out if the node has unresolved imports of any kind
+ // (including globs).
+ if !(*containing_module).all_imports_resolved() {
+ debug!("(resolving glob import) target module has unresolved \
+ imports; bailing out");
+ return Indeterminate;
+ }
+
+ assert_eq!(containing_module.glob_count.get(), 0);
+
+ // Add all resolved imports from the containing module.
+ let import_resolutions = containing_module.import_resolutions
+ .borrow();
+ for (ident, target_import_resolution) in import_resolutions.iter() {
+ debug!("(resolving glob import) writing module resolution \
+ {} into `{}`",
+ target_import_resolution.type_target.is_none(),
+ self.module_to_string(module_));
+
+ if !target_import_resolution.is_public {
+ debug!("(resolving glob import) nevermind, just kidding");
+ continue
+ }
+
+ // Here we merge two import resolutions.
+ let mut import_resolutions = module_.import_resolutions.borrow_mut();
+ match import_resolutions.get_mut(ident) {
+ Some(dest_import_resolution) => {
+ // Merge the two import resolutions at a finer-grained
+ // level.
+
+ match target_import_resolution.value_target {
+ None => {
+ // Continue.
+ }
+ Some(ref value_target) => {
+ dest_import_resolution.value_target =
+ Some(value_target.clone());
+ }
+ }
+ match target_import_resolution.type_target {
+ None => {
+ // Continue.
+ }
+ Some(ref type_target) => {
+ dest_import_resolution.type_target =
+ Some(type_target.clone());
+ }
+ }
+ dest_import_resolution.is_public = is_public;
+ continue;
+ }
+ None => {}
+ }
+
+ // Simple: just copy the old import resolution.
+ let mut new_import_resolution = ImportResolution::new(id, is_public);
+ new_import_resolution.value_target =
+ target_import_resolution.value_target.clone();
+ new_import_resolution.type_target =
+ target_import_resolution.type_target.clone();
+
+ import_resolutions.insert(*ident, new_import_resolution);
+ }
+
+ // Add all children from the containing module.
+ self.populate_module_if_necessary(&containing_module);
+
+ for (&name, name_bindings) in containing_module.children
+ .borrow().iter() {
+ self.merge_import_resolution(module_,
+ containing_module.clone(),
+ import_directive,
+ name,
+ name_bindings.clone());
+
+ }
+
+ // Add external module children from the containing module.
+ for (&name, module) in containing_module.external_module_children
+ .borrow().iter() {
+ let name_bindings =
+ Rc::new(Resolver::create_name_bindings_from_module(module.clone()));
+ self.merge_import_resolution(module_,
+ containing_module.clone(),
+ import_directive,
+ name,
+ name_bindings);
+ }
+
+ // Record the destination of this import
+ match containing_module.def_id.get() {
+ Some(did) => {
+ self.def_map.borrow_mut().insert(id, DefMod(did));
+ self.last_private.insert(id, lp);
+ }
+ None => {}
+ }
+
+ debug!("(resolving glob import) successfully resolved import");
+ return Success(());
+ }
+
+ fn merge_import_resolution(&mut self,
+ module_: &Module,
+ containing_module: Rc<Module>,
+ import_directive: &ImportDirective,
+ name: Name,
+ name_bindings: Rc<NameBindings>) {
+ let id = import_directive.id;
+ let is_public = import_directive.is_public;
+
+ let mut import_resolutions = module_.import_resolutions.borrow_mut();
+ let dest_import_resolution = match import_resolutions.entry(name) {
+ Occupied(entry) => entry.into_mut(),
+ Vacant(entry) => {
+ // Create a new import resolution from this child.
+ entry.set(ImportResolution::new(id, is_public))
+ }
+ };
+
+ debug!("(resolving glob import) writing resolution `{}` in `{}` \
+ to `{}`",
+ token::get_name(name).get().to_string(),
+ self.module_to_string(&*containing_module),
+ self.module_to_string(module_));
+
+ // Merge the child item into the import resolution.
+ if name_bindings.defined_in_namespace_with(ValueNS, IMPORTABLE | PUBLIC) {
+ debug!("(resolving glob import) ... for value target");
+ dest_import_resolution.value_target =
+ Some(Target::new(containing_module.clone(),
+ name_bindings.clone(),
+ import_directive.shadowable));
+ dest_import_resolution.value_id = id;
+ }
+ if name_bindings.defined_in_namespace_with(TypeNS, IMPORTABLE | PUBLIC) {
+ debug!("(resolving glob import) ... for type target");
+ dest_import_resolution.type_target =
+ Some(Target::new(containing_module,
+ name_bindings.clone(),
+ import_directive.shadowable));
+ dest_import_resolution.type_id = id;
+ }
+ dest_import_resolution.is_public = is_public;
+
+ self.check_for_conflicts_between_imports_and_items(
+ module_,
+ dest_import_resolution,
+ import_directive.span,
+ name);
+ }
+
+ /// Checks that imported names and items don't have the same name.
+ fn check_for_conflicting_import(&mut self,
+ target: &Option<Target>,
+ import_span: Span,
+ name: Name,
+ namespace: Namespace) {
+ if self.session.features.borrow().import_shadowing {
+ return
+ }
+
+ match *target {
+ Some(ref target) if !target.shadowable => {
+ let msg = format!("a {} named `{}` has already been imported \
+ in this module",
+ match namespace {
+ TypeNS => "type",
+ ValueNS => "value",
+ },
+ token::get_name(name).get());
+ self.session.span_err(import_span, msg.as_slice());
+ }
+ Some(_) | None => {}
+ }
+ }
+
+ /// Checks that an import is actually importable
+ fn check_that_import_is_importable(&mut self,
+ name_bindings: &NameBindings,
+ import_span: Span,
+ name: Name,
+ namespace: Namespace) {
+ if !name_bindings.defined_in_namespace_with(namespace, IMPORTABLE) {
+ let msg = format!("`{}` is not directly importable",
+ token::get_name(name));
+ self.session.span_err(import_span, msg.as_slice());
+ }
+ }
+
+ /// Checks that imported names and items don't have the same name.
+ fn check_for_conflicts_between_imports_and_items(&mut self,
+ module: &Module,
+ import_resolution:
+ &ImportResolution,
+ import_span: Span,
+ name: Name) {
+ if self.session.features.borrow().import_shadowing {
+ return
+ }
+
+ // First, check for conflicts between imports and `extern crate`s.
+ if module.external_module_children
+ .borrow()
+ .contains_key(&name) {
+ match import_resolution.type_target {
+ Some(ref target) if !target.shadowable => {
+ let msg = format!("import `{0}` conflicts with imported \
+ crate in this module \
+ (maybe you meant `use {0}::*`?)",
+ token::get_name(name).get());
+ self.session.span_err(import_span, msg.as_slice());
+ }
+ Some(_) | None => {}
+ }
+ }
+
+ // Check for item conflicts.
+ let children = module.children.borrow();
+ let name_bindings = match children.get(&name) {
+ None => {
+ // There can't be any conflicts.
+ return
+ }
+ Some(ref name_bindings) => (*name_bindings).clone(),
+ };
+
+ match import_resolution.value_target {
+ Some(ref target) if !target.shadowable => {
+ if let Some(ref value) = *name_bindings.value_def.borrow() {
+ let msg = format!("import `{}` conflicts with value \
+ in this module",
+ token::get_name(name).get());
+ self.session.span_err(import_span, msg.as_slice());
+ if let Some(span) = value.value_span {
+ self.session.span_note(span,
+ "conflicting value here");
+ }
+ }
+ }
+ Some(_) | None => {}
+ }
+
+ match import_resolution.type_target {
+ Some(ref target) if !target.shadowable => {
+ if let Some(ref ty) = *name_bindings.type_def.borrow() {
+ match ty.module_def {
+ None => {
+ let msg = format!("import `{}` conflicts with type in \
+ this module",
+ token::get_name(name).get());
+ self.session.span_err(import_span, msg.as_slice());
+ if let Some(span) = ty.type_span {
+ self.session.span_note(span,
+ "note conflicting type here")
+ }
+ }
+ Some(ref module_def) => {
+ match module_def.kind.get() {
+ ImplModuleKind => {
+ if let Some(span) = ty.type_span {
+ let msg = format!("inherent implementations \
+ are only allowed on types \
+ defined in the current module");
+ self.session.span_err(span, msg.as_slice());
+ self.session.span_note(import_span,
+ "import from other module here")
+ }
+ }
+ _ => {
+ let msg = format!("import `{}` conflicts with existing \
+ submodule",
+ token::get_name(name).get());
+ self.session.span_err(import_span, msg.as_slice());
+ if let Some(span) = ty.type_span {
+ self.session.span_note(span,
+ "note conflicting module here")
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Some(_) | None => {}
+ }
+ }
+
+ /// Checks that the names of external crates don't collide with other
+ /// external crates.
+ fn check_for_conflicts_between_external_crates(&self,
+ module: &Module,
+ name: Name,
+ span: Span) {
+ if self.session.features.borrow().import_shadowing {
+ return
+ }
+
+ if module.external_module_children.borrow().contains_key(&name) {
+ self.session
+ .span_err(span,
+ format!("an external crate named `{}` has already \
+ been imported into this module",
+ token::get_name(name).get()).as_slice());
+ }
+ }
+
+ /// Checks that the names of items don't collide with external crates.
+ fn check_for_conflicts_between_external_crates_and_items(&self,
+ module: &Module,
+ name: Name,
+ span: Span) {
+ if self.session.features.borrow().import_shadowing {
+ return
+ }
+
+ if module.external_module_children.borrow().contains_key(&name) {
+ self.session
+ .span_err(span,
+ format!("the name `{}` conflicts with an external \
+ crate that has been imported into this \
+ module",
+ token::get_name(name).get()).as_slice());
+ }
+ }
+
+ /// Resolves the given module path from the given root `module_`.
+ fn resolve_module_path_from_root(&mut self,
+ module_: Rc<Module>,
+ module_path: &[Name],
+ index: uint,
+ span: Span,
+ name_search_type: NameSearchType,
+ lp: LastPrivate)
+ -> ResolveResult<(Rc<Module>, LastPrivate)> {
+ fn search_parent_externals(needle: Name, module: &Rc<Module>)
+ -> Option<Rc<Module>> {
+ module.external_module_children.borrow()
+ .get(&needle).cloned()
+ .map(|_| module.clone())
+ .or_else(|| {
+ match module.parent_link.clone() {
+ ModuleParentLink(parent, _) => {
+ search_parent_externals(needle,
+ &parent.upgrade().unwrap())
+ }
+ _ => None
+ }
+ })
+ }
+
+ let mut search_module = module_;
+ let mut index = index;
+ let module_path_len = module_path.len();
+ let mut closest_private = lp;
+
+ // Resolve the module part of the path. This does not involve looking
+ // upward though scope chains; we simply resolve names directly in
+ // modules as we go.
+ while index < module_path_len {
+ let name = module_path[index];
+ match self.resolve_name_in_module(search_module.clone(),
+ name,
+ TypeNS,
+ name_search_type,
+ false) {
+ Failed(None) => {
+ let segment_name = token::get_name(name);
+ let module_name = self.module_to_string(&*search_module);
+ let mut span = span;
+ let msg = if "???" == module_name.as_slice() {
+ span.hi = span.lo + Pos::from_uint(segment_name.get().len());
+
+ match search_parent_externals(name,
+ &self.current_module) {
+ Some(module) => {
+ let path_str = self.names_to_string(module_path);
+ let target_mod_str = self.module_to_string(&*module);
+ let current_mod_str =
+ self.module_to_string(&*self.current_module);
+
+ let prefix = if target_mod_str == current_mod_str {
+ "self::".to_string()
+ } else {
+ format!("{}::", target_mod_str)
+ };
+
+ format!("Did you mean `{}{}`?", prefix, path_str)
+ },
+ None => format!("Maybe a missing `extern crate {}`?",
+ segment_name),
+ }
+ } else {
+ format!("Could not find `{}` in `{}`",
+ segment_name,
+ module_name)
+ };
+
+ return Failed(Some((span, msg)));
+ }
+ Failed(err) => return Failed(err),
+ Indeterminate => {
+ debug!("(resolving module path for import) module \
+ resolution is indeterminate: {}",
+ token::get_name(name));
+ return Indeterminate;
+ }
+ Success((target, used_proxy)) => {
+ // Check to see whether there are type bindings, and, if
+ // so, whether there is a module within.
+ match *target.bindings.type_def.borrow() {
+ Some(ref type_def) => {
+ match type_def.module_def {
+ None => {
+ let msg = format!("Not a module `{}`",
+ token::get_name(name));
+
+ return Failed(Some((span, msg)));
+ }
+ Some(ref module_def) => {
+ search_module = module_def.clone();
+
+ // track extern crates for unused_extern_crate lint
+ if let Some(did) = module_def.def_id.get() {
+ self.used_crates.insert(did.krate);
+ }
+
+ // Keep track of the closest
+ // private module used when
+ // resolving this import chain.
+ if !used_proxy && !search_module.is_public {
+ if let Some(did) = search_module.def_id.get() {
+ closest_private = LastMod(DependsOn(did));
+ }
+ }
+ }
+ }
+ }
+ None => {
+ // There are no type bindings at all.
+ let msg = format!("Not a module `{}`",
+ token::get_name(name));
+ return Failed(Some((span, msg)));
+ }
+ }
+ }
+ }
+
+ index += 1;
+ }
+
+ return Success((search_module, closest_private));
+ }
+
+ /// Attempts to resolve the module part of an import directive or path
+ /// rooted at the given module.
+ ///
+ /// On success, returns the resolved module, and the closest *private*
+ /// module found to the destination when resolving this path.
+ fn resolve_module_path(&mut self,
+ module_: Rc<Module>,
+ module_path: &[Name],
+ use_lexical_scope: UseLexicalScopeFlag,
+ span: Span,
+ name_search_type: NameSearchType)
+ -> ResolveResult<(Rc<Module>, LastPrivate)> {
+ let module_path_len = module_path.len();
+ assert!(module_path_len > 0);
+
+ debug!("(resolving module path for import) processing `{}` rooted at `{}`",
+ self.names_to_string(module_path),
+ self.module_to_string(&*module_));
+
+ // Resolve the module prefix, if any.
+ let module_prefix_result = self.resolve_module_prefix(module_.clone(),
+ module_path);
+
+ let search_module;
+ let start_index;
+ let last_private;
+ match module_prefix_result {
+ Failed(None) => {
+ let mpath = self.names_to_string(module_path);
+ let mpath = mpath.as_slice();
+ match mpath.rfind(':') {
+ Some(idx) => {
+ let msg = format!("Could not find `{}` in `{}`",
+ // idx +- 1 to account for the
+ // colons on either side
+ mpath.slice_from(idx + 1),
+ mpath.slice_to(idx - 1));
+ return Failed(Some((span, msg)));
+ },
+ None => {
+ return Failed(None)
+ }
+ }
+ }
+ Failed(err) => return Failed(err),
+ Indeterminate => {
+ debug!("(resolving module path for import) indeterminate; \
+ bailing");
+ return Indeterminate;
+ }
+ Success(NoPrefixFound) => {
+ // There was no prefix, so we're considering the first element
+ // of the path. How we handle this depends on whether we were
+ // instructed to use lexical scope or not.
+ match use_lexical_scope {
+ DontUseLexicalScope => {
+ // This is a crate-relative path. We will start the
+ // resolution process at index zero.
+ search_module = self.graph_root.get_module();
+ start_index = 0;
+ last_private = LastMod(AllPublic);
+ }
+ UseLexicalScope => {
+ // This is not a crate-relative path. We resolve the
+ // first component of the path in the current lexical
+ // scope and then proceed to resolve below that.
+ match self.resolve_module_in_lexical_scope(module_,
+ module_path[0]) {
+ Failed(err) => return Failed(err),
+ Indeterminate => {
+ debug!("(resolving module path for import) \
+ indeterminate; bailing");
+ return Indeterminate;
+ }
+ Success(containing_module) => {
+ search_module = containing_module;
+ start_index = 1;
+ last_private = LastMod(AllPublic);
+ }
+ }
+ }
+ }
+ }
+ Success(PrefixFound(ref containing_module, index)) => {
+ search_module = containing_module.clone();
+ start_index = index;
+ last_private = LastMod(DependsOn(containing_module.def_id
+ .get()
+ .unwrap()));
+ }
+ }
+
+ self.resolve_module_path_from_root(search_module,
+ module_path,
+ start_index,
+ span,
+ name_search_type,
+ last_private)
+ }
+
+ /// Invariant: This must only be called during main resolution, not during
+ /// import resolution.
+ fn resolve_item_in_lexical_scope(&mut self,
+ module_: Rc<Module>,
+ name: Name,
+ namespace: Namespace)
+ -> ResolveResult<(Target, bool)> {
+ debug!("(resolving item in lexical scope) resolving `{}` in \
+ namespace {} in `{}`",
+ token::get_name(name),
+ namespace,
+ self.module_to_string(&*module_));
+
+ // The current module node is handled specially. First, check for
+ // its immediate children.
+ self.populate_module_if_necessary(&module_);
+
+ match module_.children.borrow().get(&name) {
+ Some(name_bindings)
+ if name_bindings.defined_in_namespace(namespace) => {
+ debug!("top name bindings succeeded");
+ return Success((Target::new(module_.clone(),
+ name_bindings.clone(),
+ false),
+ false));
+ }
+ Some(_) | None => { /* Not found; continue. */ }
+ }
+
+ // Now check for its import directives. We don't have to have resolved
+ // all its imports in the usual way; this is because chains of
+ // adjacent import statements are processed as though they mutated the
+ // current scope.
+ if let Some(import_resolution) = module_.import_resolutions.borrow().get(&name) {
+ match (*import_resolution).target_for_namespace(namespace) {
+ None => {
+ // Not found; continue.
+ debug!("(resolving item in lexical scope) found \
+ import resolution, but not in namespace {}",
+ namespace);
+ }
+ Some(target) => {
+ debug!("(resolving item in lexical scope) using \
+ import resolution");
+ // track used imports and extern crates as well
+ self.used_imports.insert((import_resolution.id(namespace), namespace));
+ if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
+ self.used_crates.insert(kid);
+ }
+ return Success((target, false));
+ }
+ }
+ }
+
+ // Search for external modules.
+ if namespace == TypeNS {
+ if let Some(module) = module_.external_module_children.borrow().get(&name).cloned() {
+ let name_bindings =
+ Rc::new(Resolver::create_name_bindings_from_module(module));
+ debug!("lower name bindings succeeded");
+ return Success((Target::new(module_, name_bindings, false),
+ false));
+ }
+ }
+
+ // Finally, proceed up the scope chain looking for parent modules.
+ let mut search_module = module_;
+ loop {
+ // Go to the next parent.
+ match search_module.parent_link.clone() {
+ NoParentLink => {
+ // No more parents. This module was unresolved.
+ debug!("(resolving item in lexical scope) unresolved \
+ module");
+ return Failed(None);
+ }
+ ModuleParentLink(parent_module_node, _) => {
+ match search_module.kind.get() {
+ NormalModuleKind => {
+ // We stop the search here.
+ debug!("(resolving item in lexical \
+ scope) unresolved module: not \
+ searching through module \
+ parents");
+ return Failed(None);
+ }
+ TraitModuleKind |
+ ImplModuleKind |
+ EnumModuleKind |
+ AnonymousModuleKind => {
+ search_module = parent_module_node.upgrade().unwrap();
+ }
+ }
+ }
+ BlockParentLink(ref parent_module_node, _) => {
+ search_module = parent_module_node.upgrade().unwrap();
+ }
+ }
+
+ // Resolve the name in the parent module.
+ match self.resolve_name_in_module(search_module.clone(),
+ name,
+ namespace,
+ PathSearch,
+ true) {
+ Failed(Some((span, msg))) =>
+ self.resolve_error(span, format!("failed to resolve. {}",
+ msg)),
+ Failed(None) => (), // Continue up the search chain.
+ Indeterminate => {
+ // We couldn't see through the higher scope because of an
+ // unresolved import higher up. Bail.
+
+ debug!("(resolving item in lexical scope) indeterminate \
+ higher scope; bailing");
+ return Indeterminate;
+ }
+ Success((target, used_reexport)) => {
+ // We found the module.
+ debug!("(resolving item in lexical scope) found name \
+ in module, done");
+ return Success((target, used_reexport));
+ }
+ }
+ }
+ }
+
+ /// Resolves a module name in the current lexical scope.
+ fn resolve_module_in_lexical_scope(&mut self,
+ module_: Rc<Module>,
+ name: Name)
+ -> ResolveResult<Rc<Module>> {
+ // If this module is an anonymous module, resolve the item in the
+ // lexical scope. Otherwise, resolve the item from the crate root.
+ let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS);
+ match resolve_result {
+ Success((target, _)) => {
+ let bindings = &*target.bindings;
+ match *bindings.type_def.borrow() {
+ Some(ref type_def) => {
+ match type_def.module_def {
+ None => {
+ debug!("!!! (resolving module in lexical \
+ scope) module wasn't actually a \
+ module!");
+ return Failed(None);
+ }
+ Some(ref module_def) => {
+ return Success(module_def.clone());
+ }
+ }
+ }
+ None => {
+ debug!("!!! (resolving module in lexical scope) module
+ wasn't actually a module!");
+ return Failed(None);
+ }
+ }
+ }
+ Indeterminate => {
+ debug!("(resolving module in lexical scope) indeterminate; \
+ bailing");
+ return Indeterminate;
+ }
+ Failed(err) => {
+ debug!("(resolving module in lexical scope) failed to resolve");
+ return Failed(err);
+ }
+ }
+ }
+
+ /// Returns the nearest normal module parent of the given module.
+ fn get_nearest_normal_module_parent(&mut self, module_: Rc<Module>)
+ -> Option<Rc<Module>> {
+ let mut module_ = module_;
+ loop {
+ match module_.parent_link.clone() {
+ NoParentLink => return None,
+ ModuleParentLink(new_module, _) |
+ BlockParentLink(new_module, _) => {
+ let new_module = new_module.upgrade().unwrap();
+ match new_module.kind.get() {
+ NormalModuleKind => return Some(new_module),
+ TraitModuleKind |
+ ImplModuleKind |
+ EnumModuleKind |
+ AnonymousModuleKind => module_ = new_module,
+ }
+ }
+ }
+ }
+ }
+
+ /// Returns the nearest normal module parent of the given module, or the
+ /// module itself if it is a normal module.
+ fn get_nearest_normal_module_parent_or_self(&mut self, module_: Rc<Module>)
+ -> Rc<Module> {
+ match module_.kind.get() {
+ NormalModuleKind => return module_,
+ TraitModuleKind |
+ ImplModuleKind |
+ EnumModuleKind |
+ AnonymousModuleKind => {
+ match self.get_nearest_normal_module_parent(module_.clone()) {
+ None => module_,
+ Some(new_module) => new_module
+ }
+ }
+ }
+ }
+
+ /// Resolves a "module prefix". A module prefix is one or both of (a) `self::`;
+ /// (b) some chain of `super::`.
+ /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) *
+ fn resolve_module_prefix(&mut self,
+ module_: Rc<Module>,
+ module_path: &[Name])
+ -> ResolveResult<ModulePrefixResult> {
+ // Start at the current module if we see `self` or `super`, or at the
+ // top of the crate otherwise.
+ let mut containing_module;
+ let mut i;
+ let first_module_path_string = token::get_name(module_path[0]);
+ if "self" == first_module_path_string.get() {
+ containing_module =
+ self.get_nearest_normal_module_parent_or_self(module_);
+ i = 1;
+ } else if "super" == first_module_path_string.get() {
+ containing_module =
+ self.get_nearest_normal_module_parent_or_self(module_);
+ i = 0; // We'll handle `super` below.
+ } else {
+ return Success(NoPrefixFound);
+ }
+
+ // Now loop through all the `super`s we find.
+ while i < module_path.len() {
+ let string = token::get_name(module_path[i]);
+ if "super" != string.get() {
+ break
+ }
+ debug!("(resolving module prefix) resolving `super` at {}",
+ self.module_to_string(&*containing_module));
+ match self.get_nearest_normal_module_parent(containing_module) {
+ None => return Failed(None),
+ Some(new_module) => {
+ containing_module = new_module;
+ i += 1;
+ }
+ }
+ }
+
+ debug!("(resolving module prefix) finished resolving prefix at {}",
+ self.module_to_string(&*containing_module));
+
+ return Success(PrefixFound(containing_module, i));
+ }
+
+ /// Attempts to resolve the supplied name in the given module for the
+ /// given namespace. If successful, returns the target corresponding to
+ /// the name.
+ ///
+ /// The boolean returned on success is an indicator of whether this lookup
+ /// passed through a public re-export proxy.
+ fn resolve_name_in_module(&mut self,
+ module_: Rc<Module>,
+ name: Name,
+ namespace: Namespace,
+ name_search_type: NameSearchType,
+ allow_private_imports: bool)
+ -> ResolveResult<(Target, bool)> {
+ debug!("(resolving name in module) resolving `{}` in `{}`",
+ token::get_name(name).get(),
+ self.module_to_string(&*module_));
+
+ // First, check the direct children of the module.
+ self.populate_module_if_necessary(&module_);
+
+ match module_.children.borrow().get(&name) {
+ Some(name_bindings)
+ if name_bindings.defined_in_namespace(namespace) => {
+ debug!("(resolving name in module) found node as child");
+ return Success((Target::new(module_.clone(),
+ name_bindings.clone(),
+ false),
+ false));
+ }
+ Some(_) | None => {
+ // Continue.
+ }
+ }
+
+ // Next, check the module's imports if necessary.
+
+ // If this is a search of all imports, we should be done with glob
+ // resolution at this point.
+ if name_search_type == PathSearch {
+ assert_eq!(module_.glob_count.get(), 0);
+ }
+
+ // Check the list of resolved imports.
+ match module_.import_resolutions.borrow().get(&name) {
+ Some(import_resolution) if allow_private_imports ||
+ import_resolution.is_public => {
+
+ if import_resolution.is_public &&
+ import_resolution.outstanding_references != 0 {
+ debug!("(resolving name in module) import \
+ unresolved; bailing out");
+ return Indeterminate;
+ }
+ match import_resolution.target_for_namespace(namespace) {
+ None => {
+ debug!("(resolving name in module) name found, \
+ but not in namespace {}",
+ namespace);
+ }
+ Some(target) => {
+ debug!("(resolving name in module) resolved to \
+ import");
+ // track used imports and extern crates as well
+ self.used_imports.insert((import_resolution.id(namespace), namespace));
+ if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
+ self.used_crates.insert(kid);
+ }
+ return Success((target, true));
+ }
+ }
+ }
+ Some(..) | None => {} // Continue.
+ }
+
+ // Finally, search through external children.
+ if namespace == TypeNS {
+ if let Some(module) = module_.external_module_children.borrow().get(&name).cloned() {
+ let name_bindings =
+ Rc::new(Resolver::create_name_bindings_from_module(module));
+ return Success((Target::new(module_, name_bindings, false),
+ false));
+ }
+ }
+
+ // We're out of luck.
+ debug!("(resolving name in module) failed to resolve `{}`",
+ token::get_name(name).get());
+ return Failed(None);
+ }
+
+ fn report_unresolved_imports(&mut self, module_: Rc<Module>) {
+ let index = module_.resolved_import_count.get();
+ let imports = module_.imports.borrow();
+ let import_count = imports.len();
+ if index != import_count {
+ let sn = self.session
+ .codemap()
+ .span_to_snippet((*imports)[index].span)
+ .unwrap();
+ if sn.contains("::") {
+ self.resolve_error((*imports)[index].span,
+ "unresolved import");
+ } else {
+ let err = format!("unresolved import (maybe you meant `{}::*`?)",
+ sn.slice(0, sn.len()));
+ self.resolve_error((*imports)[index].span, err.as_slice());
+ }
+ }
+
+ // Descend into children and anonymous children.
+ self.populate_module_if_necessary(&module_);
+
+ for (_, child_node) in module_.children.borrow().iter() {
+ match child_node.get_module_if_available() {
+ None => {
+ // Continue.
+ }
+ Some(child_module) => {
+ self.report_unresolved_imports(child_module);
+ }
+ }
+ }
+
+ for (_, module_) in module_.anonymous_children.borrow().iter() {
+ self.report_unresolved_imports(module_.clone());
+ }
+ }
+
+ // AST resolution
+ //
+ // We maintain a list of value ribs and type ribs.
+ //
+ // Simultaneously, we keep track of the current position in the module
+ // graph in the `current_module` pointer. When we go to resolve a name in
+ // the value or type namespaces, we first look through all the ribs and
+ // then query the module graph. When we resolve a name in the module
+ // namespace, we can skip all the ribs (since nested modules are not
+ // allowed within blocks in Rust) and jump straight to the current module
+ // graph node.
+ //
+ // Named implementations are handled separately. When we find a method
+ // call, we consult the module node to find all of the implementations in
+ // scope. This information is lazily cached in the module node. We then
+ // generate a fake "implementation scope" containing all the
+ // implementations thus found, for compatibility with old resolve pass.
+
+ fn with_scope<F>(&mut self, name: Option<Name>, f: F) where
+ F: FnOnce(&mut Resolver),
+ {
+ let orig_module = self.current_module.clone();
+
+ // Move down in the graph.
+ match name {
+ None => {
+ // Nothing to do.
+ }
+ Some(name) => {
+ self.populate_module_if_necessary(&orig_module);
+
+ match orig_module.children.borrow().get(&name) {
+ None => {
+ debug!("!!! (with scope) didn't find `{}` in `{}`",
+ token::get_name(name),
+ self.module_to_string(&*orig_module));
+ }
+ Some(name_bindings) => {
+ match (*name_bindings).get_module_if_available() {
+ None => {
+ debug!("!!! (with scope) didn't find module \
+ for `{}` in `{}`",
+ token::get_name(name),
+ self.module_to_string(&*orig_module));
+ }
+ Some(module_) => {
+ self.current_module = module_;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ f(self);
+
+ self.current_module = orig_module;
+ }
+
+ /// Wraps the given definition in the appropriate number of `DefUpvar`
+ /// wrappers.
+ fn upvarify(&self,
+ ribs: &[Rib],
+ def_like: DefLike,
+ span: Span)
+ -> Option<DefLike> {
+ match def_like {
+ DlDef(d @ DefUpvar(..)) => {
+ self.session.span_bug(span,
+ format!("unexpected {} in bindings", d).as_slice())
+ }
+ DlDef(d @ DefLocal(_)) => {
+ let node_id = d.def_id().node;
+ let mut def = d;
+ let mut last_proc_body_id = ast::DUMMY_NODE_ID;
+ for rib in ribs.iter() {
+ match rib.kind {
+ NormalRibKind => {
+ // Nothing to do. Continue.
+ }
+ ClosureRibKind(function_id, maybe_proc_body) => {
+ let prev_def = def;
+ if maybe_proc_body != ast::DUMMY_NODE_ID {
+ last_proc_body_id = maybe_proc_body;
+ }
+ def = DefUpvar(node_id, function_id, last_proc_body_id);
+
+ let mut seen = self.freevars_seen.borrow_mut();
+ let seen = match seen.entry(function_id) {
+ Occupied(v) => v.into_mut(),
+ Vacant(v) => v.set(NodeSet::new()),
+ };
+ if seen.contains(&node_id) {
+ continue;
+ }
+ match self.freevars.borrow_mut().entry(function_id) {
+ Occupied(v) => v.into_mut(),
+ Vacant(v) => v.set(vec![]),
+ }.push(Freevar { def: prev_def, span: span });
+ seen.insert(node_id);
+ }
+ MethodRibKind(item_id, _) => {
+ // If the def is a ty param, and came from the parent
+ // item, it's ok
+ match def {
+ DefTyParam(_, did, _) if {
+ self.def_map.borrow().get(&did.node).cloned()
+ == Some(DefTyParamBinder(item_id))
+ } => {} // ok
+ DefSelfTy(did) if did == item_id => {} // ok
+ _ => {
+ // This was an attempt to access an upvar inside a
+ // named function item. This is not allowed, so we
+ // report an error.
+
+ self.resolve_error(
+ span,
+ "can't capture dynamic environment in a fn item; \
+ use the || { ... } closure form instead");
+
+ return None;
+ }
+ }
+ }
+ ItemRibKind => {
+ // This was an attempt to access an upvar inside a
+ // named function item. This is not allowed, so we
+ // report an error.
+
+ self.resolve_error(
+ span,
+ "can't capture dynamic environment in a fn item; \
+ use the || { ... } closure form instead");
+
+ return None;
+ }
+ ConstantItemRibKind => {
+ // Still doesn't deal with upvars
+ self.resolve_error(span,
+ "attempt to use a non-constant \
+ value in a constant");
+
+ }
+ }
+ }
+ Some(DlDef(def))
+ }
+ DlDef(def @ DefTyParam(..)) |
+ DlDef(def @ DefSelfTy(..)) => {
+ for rib in ribs.iter() {
+ match rib.kind {
+ NormalRibKind | ClosureRibKind(..) => {
+ // Nothing to do. Continue.
+ }
+ MethodRibKind(item_id, _) => {
+ // If the def is a ty param, and came from the parent
+ // item, it's ok
+ match def {
+ DefTyParam(_, did, _) if {
+ self.def_map.borrow().get(&did.node).cloned()
+ == Some(DefTyParamBinder(item_id))
+ } => {} // ok
+ DefSelfTy(did) if did == item_id => {} // ok
+
+ _ => {
+ // This was an attempt to use a type parameter outside
+ // its scope.
+
+ self.resolve_error(span,
+ "can't use type parameters from \
+ outer function; try using a local \
+ type parameter instead");
+
+ return None;
+ }
+ }
+ }
+ ItemRibKind => {
+ // This was an attempt to use a type parameter outside
+ // its scope.
+
+ self.resolve_error(span,
+ "can't use type parameters from \
+ outer function; try using a local \
+ type parameter instead");
+
+ return None;
+ }
+ ConstantItemRibKind => {
+ // see #9186
+ self.resolve_error(span,
+ "cannot use an outer type \
+ parameter in this context");
+
+ }
+ }
+ }
+ Some(DlDef(def))
+ }
+ _ => Some(def_like)
+ }
+ }
+
+ fn search_ribs(&self,
+ ribs: &[Rib],
+ name: Name,
+ span: Span)
+ -> Option<DefLike> {
+ // FIXME #4950: Try caching?
+
+ for (i, rib) in ribs.iter().enumerate().rev() {
+ match rib.bindings.get(&name).cloned() {
+ Some(def_like) => {
+ return self.upvarify(ribs[i + 1..], def_like, span);
+ }
+ None => {
+ // Continue.
+ }
+ }
+ }
+
+ None
+ }
+
+ fn resolve_crate(&mut self, krate: &ast::Crate) {
+ debug!("(resolving crate) starting");
+
+ visit::walk_crate(self, krate);
+ }
+
+ fn resolve_item(&mut self, item: &Item) {
+ let name = item.ident.name;
+
+ debug!("(resolving item) resolving {}",
+ token::get_name(name));
+
+ match item.node {
+
+ // enum item: resolve all the variants' discrs,
+ // then resolve the ty params
+ ItemEnum(ref enum_def, ref generics) => {
+ for variant in (*enum_def).variants.iter() {
+ for dis_expr in variant.node.disr_expr.iter() {
+ // resolve the discriminator expr
+ // as a constant
+ self.with_constant_rib(|this| {
+ this.resolve_expr(&**dis_expr);
+ });
+ }
+ }
+
+ // n.b. the discr expr gets visited twice.
+ // but maybe it's okay since the first time will signal an
+ // error if there is one? -- tjc
+ self.with_type_parameter_rib(HasTypeParameters(generics,
+ TypeSpace,
+ item.id,
+ ItemRibKind),
+ |this| {
+ this.resolve_type_parameters(&generics.ty_params);
+ this.resolve_where_clause(&generics.where_clause);
+ visit::walk_item(this, item);
+ });
+ }
+
+ ItemTy(_, ref generics) => {
+ self.with_type_parameter_rib(HasTypeParameters(generics,
+ TypeSpace,
+ item.id,
+ ItemRibKind),
+ |this| {
+ this.resolve_type_parameters(&generics.ty_params);
+ visit::walk_item(this, item);
+ });
+ }
+
+ ItemImpl(_,
+ ref generics,
+ ref implemented_traits,
+ ref self_type,
+ ref impl_items) => {
+ self.resolve_implementation(item.id,
+ generics,
+ implemented_traits,
+ &**self_type,
+ impl_items.as_slice());
+ }
+
+ ItemTrait(_, ref generics, ref unbound, ref bounds, ref trait_items) => {
+ // Create a new rib for the self type.
+ let mut self_type_rib = Rib::new(ItemRibKind);
+
+ // plain insert (no renaming, types are not currently hygienic....)
+ let name = self.type_self_name;
+ self_type_rib.bindings.insert(name, DlDef(DefSelfTy(item.id)));
+ self.type_ribs.push(self_type_rib);
+
+ // Create a new rib for the trait-wide type parameters.
+ self.with_type_parameter_rib(HasTypeParameters(generics,
+ TypeSpace,
+ item.id,
+ NormalRibKind),
+ |this| {
+ this.resolve_type_parameters(&generics.ty_params);
+ this.resolve_where_clause(&generics.where_clause);
+
+ this.resolve_type_parameter_bounds(item.id, bounds,
+ TraitDerivation);
+
+ match *unbound {
+ Some(ref tpb) => {
+ this.resolve_trait_reference(item.id, tpb, TraitDerivation);
+ }
+ None => {}
+ }
+
+ for trait_item in (*trait_items).iter() {
+ // Create a new rib for the trait_item-specific type
+ // parameters.
+ //
+ // FIXME #4951: Do we need a node ID here?
+
+ match *trait_item {
+ ast::RequiredMethod(ref ty_m) => {
+ this.with_type_parameter_rib
+ (HasTypeParameters(&ty_m.generics,
+ FnSpace,
+ item.id,
+ MethodRibKind(item.id, RequiredMethod)),
+ |this| {
+
+ // Resolve the method-specific type
+ // parameters.
+ this.resolve_type_parameters(
+ &ty_m.generics.ty_params);
+ this.resolve_where_clause(&ty_m.generics
+ .where_clause);
+
+ for argument in ty_m.decl.inputs.iter() {
+ this.resolve_type(&*argument.ty);
+ }
+
+ if let SelfExplicit(ref typ, _) = ty_m.explicit_self.node {
+ this.resolve_type(&**typ)
+ }
+
+ if let ast::Return(ref ret_ty) = ty_m.decl.output {
+ this.resolve_type(&**ret_ty);
+ }
+ });
+ }
+ ast::ProvidedMethod(ref m) => {
+ this.resolve_method(MethodRibKind(item.id,
+ ProvidedMethod(m.id)),
+ &**m)
+ }
+ ast::TypeTraitItem(ref data) => {
+ this.resolve_type_parameter(&data.ty_param);
+ visit::walk_trait_item(this, trait_item);
+ }
+ }
+ }
+ });
+
+ self.type_ribs.pop();
+ }
+
+ ItemStruct(ref struct_def, ref generics) => {
+ self.resolve_struct(item.id,
+ generics,
+ struct_def.fields.as_slice());
+ }
+
+ ItemMod(ref module_) => {
+ self.with_scope(Some(name), |this| {
+ this.resolve_module(module_, item.span, name,
+ item.id);
+ });
+ }
+
+ ItemForeignMod(ref foreign_module) => {
+ self.with_scope(Some(name), |this| {
+ for foreign_item in foreign_module.items.iter() {
+ match foreign_item.node {
+ ForeignItemFn(_, ref generics) => {
+ this.with_type_parameter_rib(
+ HasTypeParameters(
+ generics, FnSpace, foreign_item.id,
+ ItemRibKind),
+ |this| visit::walk_foreign_item(this,
+ &**foreign_item));
+ }
+ ForeignItemStatic(..) => {
+ visit::walk_foreign_item(this,
+ &**foreign_item);
+ }
+ }
+ }
+ });
+ }
+
+ ItemFn(ref fn_decl, _, _, ref generics, ref block) => {
+ self.resolve_function(ItemRibKind,
+ Some(&**fn_decl),
+ HasTypeParameters
+ (generics,
+ FnSpace,
+ item.id,
+ ItemRibKind),
+ &**block);
+ }
+
+ ItemConst(..) | ItemStatic(..) => {
+ self.with_constant_rib(|this| {
+ visit::walk_item(this, item);
+ });
+ }
+
+ ItemMac(..) => {
+ // do nothing, these are just around to be encoded
+ }
+ }
+ }
+
+ fn with_type_parameter_rib<F>(&mut self, type_parameters: TypeParameters, f: F) where
+ F: FnOnce(&mut Resolver),
+ {
+ match type_parameters {
+ HasTypeParameters(generics, space, node_id, rib_kind) => {
+ let mut function_type_rib = Rib::new(rib_kind);
+ let mut seen_bindings = HashSet::new();
+ for (index, type_parameter) in generics.ty_params.iter().enumerate() {
+ let name = type_parameter.ident.name;
+ debug!("with_type_parameter_rib: {} {}", node_id,
+ type_parameter.id);
+
+ if seen_bindings.contains(&name) {
+ self.resolve_error(type_parameter.span,
+ format!("the name `{}` is already \
+ used for a type \
+ parameter in this type \
+ parameter list",
+ token::get_name(
+ name)).as_slice())
+ }
+ seen_bindings.insert(name);
+
+ let def_like = DlDef(DefTyParam(space,
+ local_def(type_parameter.id),
+ index));
+ // Associate this type parameter with
+ // the item that bound it
+ self.record_def(type_parameter.id,
+ (DefTyParamBinder(node_id), LastMod(AllPublic)));
+ // plain insert (no renaming)
+ function_type_rib.bindings.insert(name, def_like);
+ }
+ self.type_ribs.push(function_type_rib);
+ }
+
+ NoTypeParameters => {
+ // Nothing to do.
+ }
+ }
+
+ f(self);
+
+ match type_parameters {
+ HasTypeParameters(..) => { self.type_ribs.pop(); }
+ NoTypeParameters => { }
+ }
+ }
+
+ fn with_label_rib<F>(&mut self, f: F) where
+ F: FnOnce(&mut Resolver),
+ {
+ self.label_ribs.push(Rib::new(NormalRibKind));
+ f(self);
+ self.label_ribs.pop();
+ }
+
+ fn with_constant_rib<F>(&mut self, f: F) where
+ F: FnOnce(&mut Resolver),
+ {
+ self.value_ribs.push(Rib::new(ConstantItemRibKind));
+ self.type_ribs.push(Rib::new(ConstantItemRibKind));
+ f(self);
+ self.type_ribs.pop();
+ self.value_ribs.pop();
+ }
+
+ fn resolve_function(&mut self,
+ rib_kind: RibKind,
+ optional_declaration: Option<&FnDecl>,
+ type_parameters: TypeParameters,
+ block: &Block) {
+ // Create a value rib for the function.
+ let function_value_rib = Rib::new(rib_kind);
+ self.value_ribs.push(function_value_rib);
+
+ // Create a label rib for the function.
+ let function_label_rib = Rib::new(rib_kind);
+ self.label_ribs.push(function_label_rib);
+
+ // If this function has type parameters, add them now.
+ self.with_type_parameter_rib(type_parameters, |this| {
+ // Resolve the type parameters.
+ match type_parameters {
+ NoTypeParameters => {
+ // Continue.
+ }
+ HasTypeParameters(ref generics, _, _, _) => {
+ this.resolve_type_parameters(&generics.ty_params);
+ this.resolve_where_clause(&generics.where_clause);
+ }
+ }
+
+ // Add each argument to the rib.
+ match optional_declaration {
+ None => {
+ // Nothing to do.
+ }
+ Some(declaration) => {
+ let mut bindings_list = HashMap::new();
+ for argument in declaration.inputs.iter() {
+ this.resolve_pattern(&*argument.pat,
+ ArgumentIrrefutableMode,
+ &mut bindings_list);
+
+ this.resolve_type(&*argument.ty);
+
+ debug!("(resolving function) recorded argument");
+ }
+
+ if let ast::Return(ref ret_ty) = declaration.output {
+ this.resolve_type(&**ret_ty);
+ }
+ }
+ }
+
+ // Resolve the function body.
+ this.resolve_block(&*block);
+
+ debug!("(resolving function) leaving function");
+ });
+
+ self.label_ribs.pop();
+ self.value_ribs.pop();
+ }
+
+ fn resolve_type_parameters(&mut self,
+ type_parameters: &OwnedSlice<TyParam>) {
+ for type_parameter in type_parameters.iter() {
+ self.resolve_type_parameter(type_parameter);
+ }
+ }
+
+ fn resolve_type_parameter(&mut self,
+ type_parameter: &TyParam) {
+ for bound in type_parameter.bounds.iter() {
+ self.resolve_type_parameter_bound(type_parameter.id, bound,
+ TraitBoundingTypeParameter);
+ }
+ match &type_parameter.unbound {
+ &Some(ref unbound) =>
+ self.resolve_trait_reference(
+ type_parameter.id, unbound, TraitBoundingTypeParameter),
+ &None => {}
+ }
+ match type_parameter.default {
+ Some(ref ty) => self.resolve_type(&**ty),
+ None => {}
+ }
+ }
+
+ fn resolve_type_parameter_bounds(&mut self,
+ id: NodeId,
+ type_parameter_bounds: &OwnedSlice<TyParamBound>,
+ reference_type: TraitReferenceType) {
+ for type_parameter_bound in type_parameter_bounds.iter() {
+ self.resolve_type_parameter_bound(id, type_parameter_bound,
+ reference_type);
+ }
+ }
+
+ fn resolve_type_parameter_bound(&mut self,
+ id: NodeId,
+ type_parameter_bound: &TyParamBound,
+ reference_type: TraitReferenceType) {
+ match *type_parameter_bound {
+ TraitTyParamBound(ref tref) => {
+ self.resolve_poly_trait_reference(id, tref, reference_type)
+ }
+ RegionTyParamBound(..) => {}
+ }
+ }
+
+ fn resolve_poly_trait_reference(&mut self,
+ id: NodeId,
+ poly_trait_reference: &PolyTraitRef,
+ reference_type: TraitReferenceType) {
+ self.resolve_trait_reference(id, &poly_trait_reference.trait_ref, reference_type)
+ }
+
+ fn resolve_trait_reference(&mut self,
+ id: NodeId,
+ trait_reference: &TraitRef,
+ reference_type: TraitReferenceType) {
+ match self.resolve_path(id, &trait_reference.path, TypeNS, true) {
+ None => {
+ let path_str = self.path_names_to_string(&trait_reference.path);
+ let usage_str = match reference_type {
+ TraitBoundingTypeParameter => "bound type parameter with",
+ TraitImplementation => "implement",
+ TraitDerivation => "derive",
+ TraitObject => "reference",
+ TraitQPath => "extract an associated type from",
+ };
+
+ let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
+ self.resolve_error(trait_reference.path.span, msg.as_slice());
+ }
+ Some(def) => {
+ match def {
+ (DefTrait(_), _) => {
+ debug!("(resolving trait) found trait def: {}", def);
+ self.record_def(trait_reference.ref_id, def);
+ }
+ (def, _) => {
+ self.resolve_error(trait_reference.path.span,
+ format!("`{}` is not a trait",
+ self.path_names_to_string(
+ &trait_reference.path)));
+
+ // If it's a typedef, give a note
+ if let DefTy(..) = def {
+ self.session.span_note(
+ trait_reference.path.span,
+ format!("`type` aliases cannot be used for traits")
+ .as_slice());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fn resolve_where_clause(&mut self, where_clause: &ast::WhereClause) {
+ for predicate in where_clause.predicates.iter() {
+ match predicate {
+ &ast::WherePredicate::BoundPredicate(ref bound_pred) => {
+ self.resolve_type(&*bound_pred.bounded_ty);
+
+ for bound in bound_pred.bounds.iter() {
+ self.resolve_type_parameter_bound(bound_pred.bounded_ty.id, bound,
+ TraitBoundingTypeParameter);
+ }
+ }
+ &ast::WherePredicate::RegionPredicate(_) => {}
+ &ast::WherePredicate::EqPredicate(ref eq_pred) => {
+ match self.resolve_path(eq_pred.id, &eq_pred.path, TypeNS, true) {
+ Some((def @ DefTyParam(..), last_private)) => {
+ self.record_def(eq_pred.id, (def, last_private));
+ }
+ _ => {
+ self.resolve_error(eq_pred.path.span,
+ "undeclared associated type");
+ }
+ }
+
+ self.resolve_type(&*eq_pred.ty);
+ }
+ }
+ }
+ }
+
+ fn resolve_struct(&mut self,
+ id: NodeId,
+ generics: &Generics,
+ fields: &[StructField]) {
+ // If applicable, create a rib for the type parameters.
+ self.with_type_parameter_rib(HasTypeParameters(generics,
+ TypeSpace,
+ id,
+ ItemRibKind),
+ |this| {
+ // Resolve the type parameters.
+ this.resolve_type_parameters(&generics.ty_params);
+ this.resolve_where_clause(&generics.where_clause);
+
+ // Resolve fields.
+ for field in fields.iter() {
+ this.resolve_type(&*field.node.ty);
+ }
+ });
+ }
+
+ // Does this really need to take a RibKind or is it always going
+ // to be NormalRibKind?
+ fn resolve_method(&mut self,
+ rib_kind: RibKind,
+ method: &ast::Method) {
+ let method_generics = method.pe_generics();
+ let type_parameters = HasTypeParameters(method_generics,
+ FnSpace,
+ method.id,
+ rib_kind);
+
+ if let SelfExplicit(ref typ, _) = method.pe_explicit_self().node {
+ self.resolve_type(&**typ);
+ }
+
+ self.resolve_function(rib_kind,
+ Some(method.pe_fn_decl()),
+ type_parameters,
+ method.pe_body());
+ }
+
+ fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T where
+ F: FnOnce(&mut Resolver) -> T,
+ {
+ // Handle nested impls (inside fn bodies)
+ let previous_value = replace(&mut self.current_self_type, Some(self_type.clone()));
+ let result = f(self);
+ self.current_self_type = previous_value;
+ result
+ }
+
+ fn with_optional_trait_ref<T, F>(&mut self, id: NodeId,
+ opt_trait_ref: &Option<TraitRef>,
+ f: F) -> T where
+ F: FnOnce(&mut Resolver) -> T,
+ {
+ let new_val = match *opt_trait_ref {
+ Some(ref trait_ref) => {
+ self.resolve_trait_reference(id, trait_ref, TraitImplementation);
+
+ match self.def_map.borrow().get(&trait_ref.ref_id) {
+ Some(def) => {
+ let did = def.def_id();
+ Some((did, trait_ref.clone()))
+ }
+ None => None
+ }
+ }
+ None => None
+ };
+ let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
+ let result = f(self);
+ self.current_trait_ref = original_trait_ref;
+ result
+ }
+
+ fn resolve_implementation(&mut self,
+ id: NodeId,
+ generics: &Generics,
+ opt_trait_reference: &Option<TraitRef>,
+ self_type: &Ty,
+ impl_items: &[ImplItem]) {
+ // If applicable, create a rib for the type parameters.
+ self.with_type_parameter_rib(HasTypeParameters(generics,
+ TypeSpace,
+ id,
+ NormalRibKind),
+ |this| {
+ // Resolve the type parameters.
+ this.resolve_type_parameters(&generics.ty_params);
+ this.resolve_where_clause(&generics.where_clause);
+
+ // Resolve the trait reference, if necessary.
+ this.with_optional_trait_ref(id, opt_trait_reference, |this| {
+ // Resolve the self type.
+ this.resolve_type(self_type);
+
+ this.with_current_self_type(self_type, |this| {
+ for impl_item in impl_items.iter() {
+ match *impl_item {
+ MethodImplItem(ref method) => {
+ // If this is a trait impl, ensure the method
+ // exists in trait
+ this.check_trait_item(method.pe_ident().name,
+ method.span);
+
+ // We also need a new scope for the method-
+ // specific type parameters.
+ this.resolve_method(
+ MethodRibKind(id, ProvidedMethod(method.id)),
+ &**method);
+ }
+ TypeImplItem(ref typedef) => {
+ // If this is a trait impl, ensure the method
+ // exists in trait
+ this.check_trait_item(typedef.ident.name,
+ typedef.span);
+
+ this.resolve_type(&*typedef.typ);
+ }
+ }
+ }
+ });
+ });
+ });
+
+ // Check that the current type is indeed a type, if we have an anonymous impl
+ if opt_trait_reference.is_none() {
+ match self_type.node {
+ // TyPath is the only thing that we handled in `build_reduced_graph_for_item`,
+ // where we created a module with the name of the type in order to implement
+ // an anonymous trait. In the case that the path does not resolve to an actual
+ // type, the result will be that the type name resolves to a module but not
+ // a type (shadowing any imported modules or types with this name), leading
+ // to weird user-visible bugs. So we ward this off here. See #15060.
+ TyPath(ref path, path_id) => {
+ match self.def_map.borrow().get(&path_id) {
+ // FIXME: should we catch other options and give more precise errors?
+ Some(&DefMod(_)) => {
+ self.resolve_error(path.span, "inherent implementations are not \
+ allowed for types not defined in \
+ the current module");
+ }
+ _ => {}
+ }
+ }
+ _ => { }
+ }
+ }
+ }
+
+ fn check_trait_item(&self, name: Name, span: Span) {
+ // If there is a TraitRef in scope for an impl, then the method must be in the trait.
+ for &(did, ref trait_ref) in self.current_trait_ref.iter() {
+ if self.trait_item_map.get(&(name, did)).is_none() {
+ let path_str = self.path_names_to_string(&trait_ref.path);
+ self.resolve_error(span,
+ format!("method `{}` is not a member of trait `{}`",
+ token::get_name(name),
+ path_str).as_slice());
+ }
+ }
+ }
+
+ fn resolve_module(&mut self, module: &Mod, _span: Span,
+ _name: Name, id: NodeId) {
+ // Write the implementations in scope into the module metadata.
+ debug!("(resolving module) resolving module ID {}", id);
+ visit::walk_mod(self, module);
+ }
+
+ fn resolve_local(&mut self, local: &Local) {
+ // Resolve the type.
+ self.resolve_type(&*local.ty);
+
+ // Resolve the initializer, if necessary.
+ match local.init {
+ None => {
+ // Nothing to do.
+ }
+ Some(ref initializer) => {
+ self.resolve_expr(&**initializer);
+ }
+ }
+
+ // Resolve the pattern.
+ let mut bindings_list = HashMap::new();
+ self.resolve_pattern(&*local.pat,
+ LocalIrrefutableMode,
+ &mut bindings_list);
+ }
+
+ // build a map from pattern identifiers to binding-info's.
+ // this is done hygienically. This could arise for a macro
+ // that expands into an or-pattern where one 'x' was from the
+ // 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, path1| {
+ let name = mtwt::resolve(path1.node);
+ result.insert(name, BindingInfo {
+ span: sp,
+ binding_mode: binding_mode
+ });
+ });
+ return result;
+ }
+
+ // check that all of the arms in an or-pattern have exactly the
+ // same set of bindings, with the same binding modes for each.
+ fn check_consistent_bindings(&mut self, arm: &Arm) {
+ if arm.pats.len() == 0 {
+ return
+ }
+ let map_0 = self.binding_mode_map(&*arm.pats[0]);
+ for (i, p) in arm.pats.iter().enumerate() {
+ let map_i = self.binding_mode_map(&**p);
+
+ for (&key, &binding_0) in map_0.iter() {
+ match map_i.get(&key) {
+ None => {
+ self.resolve_error(
+ p.span,
+ format!("variable `{}` from pattern #1 is \
+ not bound in pattern #{}",
+ token::get_name(key),
+ i + 1).as_slice());
+ }
+ Some(binding_i) => {
+ if binding_0.binding_mode != binding_i.binding_mode {
+ self.resolve_error(
+ binding_i.span,
+ format!("variable `{}` is bound with different \
+ mode in pattern #{} than in pattern #1",
+ token::get_name(key),
+ i + 1).as_slice());
+ }
+ }
+ }
+ }
+
+ for (&key, &binding) in map_i.iter() {
+ if !map_0.contains_key(&key) {
+ self.resolve_error(
+ binding.span,
+ format!("variable `{}` from pattern {}{} is \
+ not bound in pattern {}1",
+ token::get_name(key),
+ "#", i + 1, "#").as_slice());
+ }
+ }
+ }
+ }
+
+ fn resolve_arm(&mut self, arm: &Arm) {
+ self.value_ribs.push(Rib::new(NormalRibKind));
+
+ let mut bindings_list = HashMap::new();
+ for pattern in arm.pats.iter() {
+ self.resolve_pattern(&**pattern, RefutableMode, &mut bindings_list);
+ }
+
+ // This has to happen *after* we determine which
+ // pat_idents are variants
+ self.check_consistent_bindings(arm);
+
+ visit::walk_expr_opt(self, &arm.guard);
+ self.resolve_expr(&*arm.body);
+
+ self.value_ribs.pop();
+ }
+
+ fn resolve_block(&mut self, block: &Block) {
+ debug!("(resolving block) entering block");
+ self.value_ribs.push(Rib::new(NormalRibKind));
+
+ // Move down in the graph, if there's an anonymous module rooted here.
+ let orig_module = self.current_module.clone();
+ match orig_module.anonymous_children.borrow().get(&block.id) {
+ None => { /* Nothing to do. */ }
+ Some(anonymous_module) => {
+ debug!("(resolving block) found anonymous module, moving \
+ down");
+ self.current_module = anonymous_module.clone();
+ }
+ }
+
+ // Descend into the block.
+ visit::walk_block(self, block);
+
+ // Move back up.
+ self.current_module = orig_module;
+
+ self.value_ribs.pop();
+ debug!("(resolving block) leaving block");
+ }
+
+ fn resolve_type(&mut self, ty: &Ty) {
+ match ty.node {
+ // Like path expressions, the interpretation of path types depends
+ // on whether the path has multiple elements in it or not.
+
+ TyPath(ref path, path_id) => {
+ // This is a path in the type namespace. Walk through scopes
+ // looking for it.
+ let mut result_def = None;
+
+ // First, check to see whether the name is a primitive type.
+ if path.segments.len() == 1 {
+ let id = path.segments.last().unwrap().identifier;
+
+ match self.primitive_type_table
+ .primitive_types
+ .get(&id.name) {
+
+ Some(&primitive_type) => {
+ result_def =
+ Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
+
+ if path.segments[0].parameters.has_lifetimes() {
+ span_err!(self.session, path.span, E0157,
+ "lifetime parameters are not allowed on this type");
+ } else if !path.segments[0].parameters.is_empty() {
+ span_err!(self.session, path.span, E0153,
+ "type parameters are not allowed on this type");
+ }
+ }
+ None => {
+ // Continue.
+ }
+ }
+ }
+
+ match result_def {
+ None => {
+ match self.resolve_path(ty.id, path, TypeNS, true) {
+ Some(def) => {
+ debug!("(resolving type) resolved `{}` to \
+ type {}",
+ token::get_ident(path.segments
+ .last().unwrap()
+ .identifier),
+ def);
+ result_def = Some(def);
+ }
+ None => {
+ result_def = None;
+ }
+ }
+ }
+ Some(_) => {} // Continue.
+ }
+
+ match result_def {
+ Some(def) => {
+ // Write the result into the def map.
+ debug!("(resolving type) writing resolution for `{}` \
+ (id {})",
+ self.path_names_to_string(path),
+ path_id);
+ self.record_def(path_id, def);
+ }
+ None => {
+ let msg = format!("use of undeclared type name `{}`",
+ self.path_names_to_string(path));
+ self.resolve_error(ty.span, msg.as_slice());
+ }
+ }
+ }
+
+ TyObjectSum(ref ty, ref bound_vec) => {
+ self.resolve_type(&**ty);
+ self.resolve_type_parameter_bounds(ty.id, bound_vec,
+ TraitBoundingTypeParameter);
+ }
+
+ TyQPath(ref qpath) => {
+ self.resolve_type(&*qpath.self_type);
+ self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath);
+ }
+
+ TyClosure(ref c) => {
+ self.resolve_type_parameter_bounds(
+ ty.id,
+ &c.bounds,
+ TraitBoundingTypeParameter);
+ visit::walk_ty(self, ty);
+ }
+
+ TyPolyTraitRef(ref bounds) => {
+ self.resolve_type_parameter_bounds(
+ ty.id,
+ bounds,
+ TraitObject);
+ visit::walk_ty(self, ty);
+ }
+ _ => {
+ // Just resolve embedded types.
+ visit::walk_ty(self, ty);
+ }
+ }
+ }
+
+ fn resolve_pattern(&mut self,
+ pattern: &Pat,
+ mode: PatternBindingMode,
+ // Maps idents to the node ID for the (outermost)
+ // pattern that binds them
+ bindings_list: &mut HashMap<Name, NodeId>) {
+ let pat_id = pattern.id;
+ walk_pat(pattern, |pattern| {
+ match pattern.node {
+ PatIdent(binding_mode, ref path1, _) => {
+
+ // The meaning of pat_ident with no type parameters
+ // depends on whether an enum variant or unit-like struct
+ // with that name is in scope. The probing lookup has to
+ // be careful not to emit spurious errors. Only matching
+ // patterns (match) can match nullary variants or
+ // unit-like structs. For binding patterns (let), matching
+ // such a value is simply disallowed (since it's rarely
+ // what you want).
+
+ let ident = path1.node;
+ let renamed = mtwt::resolve(ident);
+
+ match self.resolve_bare_identifier_pattern(ident.name, pattern.span) {
+ FoundStructOrEnumVariant(ref def, lp)
+ if mode == RefutableMode => {
+ debug!("(resolving pattern) resolving `{}` to \
+ struct or enum variant",
+ token::get_name(renamed));
+
+ self.enforce_default_binding_mode(
+ pattern,
+ binding_mode,
+ "an enum variant");
+ self.record_def(pattern.id, (def.clone(), lp));
+ }
+ FoundStructOrEnumVariant(..) => {
+ self.resolve_error(
+ pattern.span,
+ format!("declaration of `{}` shadows an enum \
+ variant or unit-like struct in \
+ scope",
+ token::get_name(renamed)).as_slice());
+ }
+ FoundConst(ref def, lp) if mode == RefutableMode => {
+ debug!("(resolving pattern) resolving `{}` to \
+ constant",
+ token::get_name(renamed));
+
+ self.enforce_default_binding_mode(
+ pattern,
+ binding_mode,
+ "a constant");
+ self.record_def(pattern.id, (def.clone(), lp));
+ }
+ FoundConst(..) => {
+ self.resolve_error(pattern.span,
+ "only irrefutable patterns \
+ allowed here");
+ }
+ BareIdentifierPatternUnresolved => {
+ debug!("(resolving pattern) binding `{}`",
+ token::get_name(renamed));
+
+ let def = DefLocal(pattern.id);
+
+ // Record the definition so that later passes
+ // will be able to distinguish variants from
+ // locals in patterns.
+
+ self.record_def(pattern.id, (def, LastMod(AllPublic)));
+
+ // Add the binding to the local ribs, if it
+ // doesn't already exist in the bindings list. (We
+ // must not add it if it's in the bindings list
+ // because that breaks the assumptions later
+ // passes make about or-patterns.)
+ if !bindings_list.contains_key(&renamed) {
+ let this = &mut *self;
+ let last_rib = this.value_ribs.last_mut().unwrap();
+ last_rib.bindings.insert(renamed, DlDef(def));
+ bindings_list.insert(renamed, pat_id);
+ } else if mode == ArgumentIrrefutableMode &&
+ bindings_list.contains_key(&renamed) {
+ // Forbid duplicate bindings in the same
+ // parameter list.
+ self.resolve_error(pattern.span,
+ format!("identifier `{}` \
+ is bound more \
+ than once in \
+ this parameter \
+ list",
+ token::get_ident(
+ ident))
+ .as_slice())
+ } else if bindings_list.get(&renamed) ==
+ Some(&pat_id) {
+ // Then this is a duplicate variable in the
+ // same disjunction, which is an error.
+ self.resolve_error(pattern.span,
+ format!("identifier `{}` is bound \
+ more than once in the same \
+ pattern",
+ token::get_ident(ident)).as_slice());
+ }
+ // Else, not bound in the same pattern: do
+ // nothing.
+ }
+ }
+ }
+
+ PatEnum(ref path, _) => {
+ // This must be an enum variant, struct or const.
+ match self.resolve_path(pat_id, path, ValueNS, false) {
+ Some(def @ (DefVariant(..), _)) |
+ Some(def @ (DefStruct(..), _)) |
+ Some(def @ (DefConst(..), _)) => {
+ self.record_def(pattern.id, def);
+ }
+ Some((DefStatic(..), _)) => {
+ self.resolve_error(path.span,
+ "static variables cannot be \
+ referenced in a pattern, \
+ use a `const` instead");
+ }
+ Some(_) => {
+ self.resolve_error(path.span,
+ format!("`{}` is not an enum variant, struct or const",
+ token::get_ident(
+ path.segments
+ .last()
+ .unwrap()
+ .identifier)).as_slice());
+ }
+ None => {
+ self.resolve_error(path.span,
+ format!("unresolved enum variant, struct or const `{}`",
+ token::get_ident(
+ path.segments
+ .last()
+ .unwrap()
+ .identifier)).as_slice());
+ }
+ }
+
+ // Check the types in the path pattern.
+ for ty in path.segments
+ .iter()
+ .flat_map(|s| s.parameters.types().into_iter()) {
+ self.resolve_type(&**ty);
+ }
+ }
+
+ PatLit(ref expr) => {
+ self.resolve_expr(&**expr);
+ }
+
+ PatRange(ref first_expr, ref last_expr) => {
+ self.resolve_expr(&**first_expr);
+ self.resolve_expr(&**last_expr);
+ }
+
+ PatStruct(ref path, _, _) => {
+ match self.resolve_path(pat_id, path, TypeNS, false) {
+ Some(definition) => {
+ self.record_def(pattern.id, definition);
+ }
+ result => {
+ debug!("(resolving pattern) didn't find struct \
+ def: {}", result);
+ let msg = format!("`{}` does not name a structure",
+ self.path_names_to_string(path));
+ self.resolve_error(path.span, msg.as_slice());
+ }
+ }
+ }
+
+ _ => {
+ // Nothing to do.
+ }
+ }
+ true
+ });
+ }
+
+ fn resolve_bare_identifier_pattern(&mut self, name: Name, span: Span)
+ -> BareIdentifierPatternResolution {
+ let module = self.current_module.clone();
+ match self.resolve_item_in_lexical_scope(module,
+ name,
+ ValueNS) {
+ Success((target, _)) => {
+ debug!("(resolve bare identifier pattern) succeeded in \
+ finding {} at {}",
+ token::get_name(name),
+ target.bindings.value_def.borrow());
+ match *target.bindings.value_def.borrow() {
+ None => {
+ panic!("resolved name in the value namespace to a \
+ set of name bindings with no def?!");
+ }
+ Some(def) => {
+ // For the two success cases, this lookup can be
+ // considered as not having a private component because
+ // the lookup happened only within the current module.
+ match def.def {
+ def @ DefVariant(..) | def @ DefStruct(..) => {
+ return FoundStructOrEnumVariant(def, LastMod(AllPublic));
+ }
+ def @ DefConst(..) => {
+ return FoundConst(def, LastMod(AllPublic));
+ }
+ DefStatic(..) => {
+ self.resolve_error(span,
+ "static variables cannot be \
+ referenced in a pattern, \
+ use a `const` instead");
+ return BareIdentifierPatternUnresolved;
+ }
+ _ => {
+ return BareIdentifierPatternUnresolved;
+ }
+ }
+ }
+ }
+ }
+
+ Indeterminate => {
+ panic!("unexpected indeterminate result");
+ }
+ Failed(err) => {
+ match err {
+ Some((span, msg)) => {
+ self.resolve_error(span, format!("failed to resolve: {}",
+ msg));
+ }
+ None => ()
+ }
+
+ debug!("(resolve bare identifier pattern) failed to find {}",
+ token::get_name(name));
+ return BareIdentifierPatternUnresolved;
+ }
+ }
+ }
+
+ /// If `check_ribs` is true, checks the local definitions first; i.e.
+ /// doesn't skip straight to the containing module.
+ fn resolve_path(&mut self,
+ id: NodeId,
+ path: &Path,
+ namespace: Namespace,
+ check_ribs: bool) -> Option<(Def, LastPrivate)> {
+ // First, resolve the types and associated type bindings.
+ for ty in path.segments.iter().flat_map(|s| s.parameters.types().into_iter()) {
+ self.resolve_type(&**ty);
+ }
+ for binding in path.segments.iter().flat_map(|s| s.parameters.bindings().into_iter()) {
+ self.resolve_type(&*binding.ty);
+ }
+
+ // A special case for sugared associated type paths `T::A` where `T` is
+ // a type parameter and `A` is an associated type on some bound of `T`.
+ if namespace == TypeNS && path.segments.len() == 2 {
+ match self.resolve_identifier(path.segments[0].identifier,
+ TypeNS,
+ true,
+ path.span) {
+ Some((def, last_private)) => {
+ match def {
+ DefTyParam(_, did, _) => {
+ let def = DefAssociatedPath(TyParamProvenance::FromParam(did),
+ path.segments.last()
+ .unwrap().identifier);
+ return Some((def, last_private));
+ }
+ DefSelfTy(nid) => {
+ let def = DefAssociatedPath(TyParamProvenance::FromSelf(local_def(nid)),
+ path.segments.last()
+ .unwrap().identifier);
+ return Some((def, last_private));
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+
+ if path.global {
+ return self.resolve_crate_relative_path(path, namespace);
+ }
+
+ // Try to find a path to an item in a module.
+ let unqualified_def =
+ self.resolve_identifier(path.segments
+ .last().unwrap()
+ .identifier,
+ namespace,
+ check_ribs,
+ path.span);
+
+ if path.segments.len() > 1 {
+ let def = self.resolve_module_relative_path(path, namespace);
+ match (def, unqualified_def) {
+ (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => {
+ self.session
+ .add_lint(lint::builtin::UNUSED_QUALIFICATIONS,
+ id,
+ path.span,
+ "unnecessary qualification".to_string());
+ }
+ _ => ()
+ }
+
+ return def;
+ }
+
+ return unqualified_def;
+ }
+
+ // resolve a single identifier (used as a varref)
+ fn resolve_identifier(&mut self,
+ identifier: Ident,
+ namespace: Namespace,
+ check_ribs: bool,
+ span: Span)
+ -> Option<(Def, LastPrivate)> {
+ if check_ribs {
+ match self.resolve_identifier_in_local_ribs(identifier,
+ namespace,
+ span) {
+ Some(def) => {
+ return Some((def, LastMod(AllPublic)));
+ }
+ None => {
+ // Continue.
+ }
+ }
+ }
+
+ return self.resolve_item_by_name_in_lexical_scope(identifier.name, namespace);
+ }
+
+ // FIXME #4952: Merge me with resolve_name_in_module?
+ fn resolve_definition_of_name_in_module(&mut self,
+ containing_module: Rc<Module>,
+ name: Name,
+ namespace: Namespace)
+ -> NameDefinition {
+ // First, search children.
+ self.populate_module_if_necessary(&containing_module);
+
+ match containing_module.children.borrow().get(&name) {
+ Some(child_name_bindings) => {
+ match child_name_bindings.def_for_namespace(namespace) {
+ Some(def) => {
+ // Found it. Stop the search here.
+ let p = child_name_bindings.defined_in_public_namespace(
+ namespace);
+ let lp = if p {LastMod(AllPublic)} else {
+ LastMod(DependsOn(def.def_id()))
+ };
+ return ChildNameDefinition(def, lp);
+ }
+ None => {}
+ }
+ }
+ None => {}
+ }
+
+ // Next, search import resolutions.
+ match containing_module.import_resolutions.borrow().get(&name) {
+ Some(import_resolution) if import_resolution.is_public => {
+ if let Some(target) = (*import_resolution).target_for_namespace(namespace) {
+ match target.bindings.def_for_namespace(namespace) {
+ Some(def) => {
+ // Found it.
+ let id = import_resolution.id(namespace);
+ // track imports and extern crates as well
+ self.used_imports.insert((id, namespace));
+ match target.target_module.def_id.get() {
+ Some(DefId{krate: kid, ..}) => {
+ self.used_crates.insert(kid);
+ },
+ _ => {}
+ }
+ return ImportNameDefinition(def, LastMod(AllPublic));
+ }
+ None => {
+ // This can happen with external impls, due to
+ // the imperfect way we read the metadata.
+ }
+ }
+ }
+ }
+ Some(..) | None => {} // Continue.
+ }
+
+ // Finally, search through external children.
+ if namespace == TypeNS {
+ if let Some(module) = containing_module.external_module_children.borrow()
+ .get(&name).cloned() {
+ if let Some(def_id) = module.def_id.get() {
+ // track used crates
+ self.used_crates.insert(def_id.krate);
+ let lp = if module.is_public {LastMod(AllPublic)} else {
+ LastMod(DependsOn(def_id))
+ };
+ return ChildNameDefinition(DefMod(def_id), lp);
+ }
+ }
+ }
+
+ return NoNameDefinition;
+ }
+
+ // resolve a "module-relative" path, e.g. a::b::c
+ fn resolve_module_relative_path(&mut self,
+ path: &Path,
+ namespace: Namespace)
+ -> Option<(Def, LastPrivate)> {
+ let module_path = path.segments.init().iter()
+ .map(|ps| ps.identifier.name)
+ .collect::<Vec<_>>();
+
+ let containing_module;
+ let last_private;
+ let module = self.current_module.clone();
+ match self.resolve_module_path(module,
+ module_path.as_slice(),
+ UseLexicalScope,
+ path.span,
+ PathSearch) {
+ Failed(err) => {
+ let (span, msg) = match err {
+ Some((span, msg)) => (span, msg),
+ None => {
+ let msg = format!("Use of undeclared type or module `{}`",
+ self.names_to_string(module_path.as_slice()));
+ (path.span, msg)
+ }
+ };
+
+ self.resolve_error(span, format!("failed to resolve. {}",
+ msg.as_slice()));
+ return None;
+ }
+ Indeterminate => panic!("indeterminate unexpected"),
+ Success((resulting_module, resulting_last_private)) => {
+ containing_module = resulting_module;
+ last_private = resulting_last_private;
+ }
+ }
+
+ let name = path.segments.last().unwrap().identifier.name;
+ let def = match self.resolve_definition_of_name_in_module(containing_module.clone(),
+ name,
+ namespace) {
+ NoNameDefinition => {
+ // We failed to resolve the name. Report an error.
+ return None;
+ }
+ ChildNameDefinition(def, lp) | ImportNameDefinition(def, lp) => {
+ (def, last_private.or(lp))
+ }
+ };
+ if let Some(DefId{krate: kid, ..}) = containing_module.def_id.get() {
+ self.used_crates.insert(kid);
+ }
+ return Some(def);
+ }
+
+ /// Invariant: This must be called only during main resolution, not during
+ /// import resolution.
+ fn resolve_crate_relative_path(&mut self,
+ path: &Path,
+ namespace: Namespace)
+ -> Option<(Def, LastPrivate)> {
+ let module_path = path.segments.init().iter()
+ .map(|ps| ps.identifier.name)
+ .collect::<Vec<_>>();
+
+ let root_module = self.graph_root.get_module();
+
+ let containing_module;
+ let last_private;
+ match self.resolve_module_path_from_root(root_module,
+ module_path.as_slice(),
+ 0,
+ path.span,
+ PathSearch,
+ LastMod(AllPublic)) {
+ Failed(err) => {
+ let (span, msg) = match err {
+ Some((span, msg)) => (span, msg),
+ None => {
+ let msg = format!("Use of undeclared module `::{}`",
+ self.names_to_string(module_path.as_slice()));
+ (path.span, msg)
+ }
+ };
+
+ self.resolve_error(span, format!("failed to resolve. {}",
+ msg.as_slice()));
+ return None;
+ }
+
+ Indeterminate => {
+ panic!("indeterminate unexpected");
+ }
+
+ Success((resulting_module, resulting_last_private)) => {
+ containing_module = resulting_module;
+ last_private = resulting_last_private;
+ }
+ }
+
+ let name = path.segments.last().unwrap().identifier.name;
+ match self.resolve_definition_of_name_in_module(containing_module,
+ name,
+ namespace) {
+ NoNameDefinition => {
+ // We failed to resolve the name. Report an error.
+ return None;
+ }
+ ChildNameDefinition(def, lp) | ImportNameDefinition(def, lp) => {
+ return Some((def, last_private.or(lp)));
+ }
+ }
+ }
+
+ fn resolve_identifier_in_local_ribs(&mut self,
+ ident: Ident,
+ namespace: Namespace,
+ span: Span)
+ -> Option<Def> {
+ // Check the local set of ribs.
+ let search_result = match namespace {
+ ValueNS => {
+ let renamed = mtwt::resolve(ident);
+ self.search_ribs(self.value_ribs.as_slice(), renamed, span)
+ }
+ TypeNS => {
+ let name = ident.name;
+ self.search_ribs(self.type_ribs.as_slice(), name, span)
+ }
+ };
+
+ match search_result {
+ Some(DlDef(def)) => {
+ debug!("(resolving path in local ribs) resolved `{}` to \
+ local: {}",
+ token::get_ident(ident),
+ def);
+ return Some(def);
+ }
+ Some(DlField) | Some(DlImpl(_)) | None => {
+ return None;
+ }
+ }
+ }
+
+ fn resolve_item_by_name_in_lexical_scope(&mut self,
+ name: Name,
+ namespace: Namespace)
+ -> Option<(Def, LastPrivate)> {
+ // Check the items.
+ let module = self.current_module.clone();
+ match self.resolve_item_in_lexical_scope(module,
+ name,
+ namespace) {
+ Success((target, _)) => {
+ match (*target.bindings).def_for_namespace(namespace) {
+ None => {
+ // This can happen if we were looking for a type and
+ // found a module instead. Modules don't have defs.
+ debug!("(resolving item path by identifier in lexical \
+ scope) failed to resolve {} after success...",
+ token::get_name(name));
+ return None;
+ }
+ Some(def) => {
+ debug!("(resolving item path in lexical scope) \
+ resolved `{}` to item",
+ token::get_name(name));
+ // This lookup is "all public" because it only searched
+ // for one identifier in the current module (couldn't
+ // have passed through reexports or anything like that.
+ return Some((def, LastMod(AllPublic)));
+ }
+ }
+ }
+ Indeterminate => {
+ panic!("unexpected indeterminate result");
+ }
+ Failed(err) => {
+ match err {
+ Some((span, msg)) =>
+ self.resolve_error(span, format!("failed to resolve. {}", msg)),
+ None => ()
+ }
+
+ debug!("(resolving item path by identifier in lexical scope) \
+ failed to resolve {}", token::get_name(name));
+ return None;
+ }
+ }
+ }
+
+ fn with_no_errors<T, F>(&mut self, f: F) -> T where
+ F: FnOnce(&mut Resolver) -> T,
+ {
+ self.emit_errors = false;
+ let rs = f(self);
+ self.emit_errors = true;
+ rs
+ }
+
+ fn resolve_error<T: Str>(&self, span: Span, s: T) {
+ if self.emit_errors {
+ self.session.span_err(span, s.as_slice());
+ }
+ }
+
+ fn find_fallback_in_self_type(&mut self, name: Name) -> FallbackSuggestion {
+ fn extract_path_and_node_id(t: &Ty, allow: FallbackChecks)
+ -> Option<(Path, NodeId, FallbackChecks)> {
+ match t.node {
+ TyPath(ref path, node_id) => Some((path.clone(), node_id, allow)),
+ TyPtr(ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, OnlyTraitAndStatics),
+ TyRptr(_, ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, allow),
+ // This doesn't handle the remaining `Ty` variants as they are not
+ // that commonly the self_type, it might be interesting to provide
+ // support for those in future.
+ _ => None,
+ }
+ }
+
+ fn get_module(this: &mut Resolver, span: Span, name_path: &[ast::Name])
+ -> Option<Rc<Module>> {
+ let root = this.current_module.clone();
+ let last_name = name_path.last().unwrap();
+
+ if name_path.len() == 1 {
+ match this.primitive_type_table.primitive_types.get(last_name) {
+ Some(_) => None,
+ None => {
+ match this.current_module.children.borrow().get(last_name) {
+ Some(child) => child.get_module_if_available(),
+ None => None
+ }
+ }
+ }
+ } else {
+ match this.resolve_module_path(root,
+ name_path.as_slice(),
+ UseLexicalScope,
+ span,
+ PathSearch) {
+ Success((module, _)) => Some(module),
+ _ => None
+ }
+ }
+ }
+
+ let (path, node_id, allowed) = match self.current_self_type {
+ Some(ref ty) => match extract_path_and_node_id(ty, Everything) {
+ Some(x) => x,
+ None => return NoSuggestion,
+ },
+ None => return NoSuggestion,
+ };
+
+ if allowed == Everything {
+ // Look for a field with the same name in the current self_type.
+ match self.def_map.borrow().get(&node_id) {
+ Some(&DefTy(did, _))
+ | Some(&DefStruct(did))
+ | Some(&DefVariant(_, did, _)) => match self.structs.get(&did) {
+ None => {}
+ Some(fields) => {
+ if fields.iter().any(|&field_name| name == field_name) {
+ return Field;
+ }
+ }
+ },
+ _ => {} // Self type didn't resolve properly
+ }
+ }
+
+ let name_path = path.segments.iter().map(|seg| seg.identifier.name).collect::<Vec<_>>();
+
+ // Look for a method in the current self type's impl module.
+ match get_module(self, path.span, name_path.as_slice()) {
+ Some(module) => match module.children.borrow().get(&name) {
+ Some(binding) => {
+ let p_str = self.path_names_to_string(&path);
+ match binding.def_for_namespace(ValueNS) {
+ Some(DefStaticMethod(_, provenance)) => {
+ match provenance {
+ FromImpl(_) => return StaticMethod(p_str),
+ FromTrait(_) => unreachable!()
+ }
+ }
+ Some(DefMethod(_, None, _)) if allowed == Everything => return Method,
+ Some(DefMethod(_, Some(_), _)) => return TraitItem,
+ _ => ()
+ }
+ }
+ None => {}
+ },
+ None => {}
+ }
+
+ // Look for a method in the current trait.
+ match self.current_trait_ref {
+ Some((did, ref trait_ref)) => {
+ let path_str = self.path_names_to_string(&trait_ref.path);
+
+ match self.trait_item_map.get(&(name, did)) {
+ Some(&StaticMethodTraitItemKind) => {
+ return TraitMethod(path_str)
+ }
+ Some(_) => return TraitItem,
+ None => {}
+ }
+ }
+ None => {}
+ }
+
+ NoSuggestion
+ }
+
+ fn find_best_match_for_name(&mut self, name: &str, max_distance: uint)
+ -> Option<String> {
+ let this = &mut *self;
+
+ let mut maybes: Vec<token::InternedString> = Vec::new();
+ let mut values: Vec<uint> = Vec::new();
+
+ for rib in this.value_ribs.iter().rev() {
+ for (&k, _) in rib.bindings.iter() {
+ maybes.push(token::get_name(k));
+ values.push(uint::MAX);
+ }
+ }
+
+ let mut smallest = 0;
+ for (i, other) in maybes.iter().enumerate() {
+ values[i] = name.lev_distance(other.get());
+
+ if values[i] <= values[smallest] {
+ smallest = i;
+ }
+ }
+
+ if values.len() > 0 &&
+ values[smallest] != uint::MAX &&
+ values[smallest] < name.len() + 2 &&
+ values[smallest] <= max_distance &&
+ name != maybes[smallest].get() {
+
+ Some(maybes[smallest].get().to_string())
+
+ } else {
+ None
+ }
+ }
+
+ fn resolve_expr(&mut self, expr: &Expr) {
+ // First, record candidate traits for this expression if it could
+ // result in the invocation of a method call.
+
+ self.record_candidate_traits_for_expr_if_necessary(expr);
+
+ // Next, resolve the node.
+ match expr.node {
+ // The interpretation of paths depends on whether the path has
+ // multiple elements in it or not.
+
+ ExprPath(ref path) => {
+ // This is a local path in the value namespace. Walk through
+ // scopes looking for it.
+
+ let path_name = self.path_names_to_string(path);
+
+ match self.resolve_path(expr.id, path, ValueNS, true) {
+ // Check if struct variant
+ Some((DefVariant(_, _, true), _)) => {
+ self.resolve_error(expr.span,
+ format!("`{}` is a struct variant name, but \
+ this expression \
+ uses it like a function name",
+ path_name).as_slice());
+
+ self.session.span_help(expr.span,
+ format!("Did you mean to write: \
+ `{} {{ /* fields */ }}`?",
+ path_name).as_slice());
+ }
+ Some(def) => {
+ // Write the result into the def map.
+ debug!("(resolving expr) resolved `{}`",
+ path_name);
+
+ self.record_def(expr.id, def);
+ }
+ None => {
+ // Be helpful if the name refers to a struct
+ // (The pattern matching def_tys where the id is in self.structs
+ // matches on regular structs while excluding tuple- and enum-like
+ // structs, which wouldn't result in this error.)
+ match self.with_no_errors(|this|
+ this.resolve_path(expr.id, path, TypeNS, false)) {
+ Some((DefTy(struct_id, _), _))
+ if self.structs.contains_key(&struct_id) => {
+ self.resolve_error(expr.span,
+ format!("`{}` is a structure name, but \
+ this expression \
+ uses it like a function name",
+ path_name).as_slice());
+
+ self.session.span_help(expr.span,
+ format!("Did you mean to write: \
+ `{} {{ /* fields */ }}`?",
+ path_name).as_slice());
+
+ }
+ _ => {
+ let mut method_scope = false;
+ self.value_ribs.iter().rev().all(|rib| {
+ let res = match *rib {
+ Rib { bindings: _, kind: MethodRibKind(_, _) } => true,
+ Rib { bindings: _, kind: ItemRibKind } => false,
+ _ => return true, // Keep advancing
+ };
+
+ method_scope = res;
+ false // Stop advancing
+ });
+
+ if method_scope && token::get_name(self.self_name).get()
+ == path_name {
+ self.resolve_error(
+ expr.span,
+ "`self` is not available \
+ in a static method. Maybe a \
+ `self` argument is missing?");
+ } else {
+ 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
+ self.find_best_match_for_name(path_name.as_slice(), 5)
+ .map_or("".to_string(),
+ |x| format!("`{}`", x))
+ }
+ Field =>
+ format!("`self.{}`", path_name),
+ Method
+ | TraitItem =>
+ format!("to call `self.{}`", path_name),
+ TraitMethod(path_str)
+ | StaticMethod(path_str) =>
+ format!("to call `{}::{}`", path_str, path_name)
+ };
+
+ if msg.len() > 0 {
+ msg = format!(". Did you mean {}?", msg)
+ }
+
+ self.resolve_error(
+ expr.span,
+ format!("unresolved name `{}`{}",
+ path_name,
+ msg).as_slice());
+ }
+ }
+ }
+ }
+ }
+
+ visit::walk_expr(self, expr);
+ }
+
+ ExprClosure(capture_clause, _, ref fn_decl, ref block) => {
+ self.capture_mode_map.insert(expr.id, capture_clause);
+ self.resolve_function(ClosureRibKind(expr.id, ast::DUMMY_NODE_ID),
+ Some(&**fn_decl), NoTypeParameters,
+ &**block);
+ }
+
+ ExprStruct(ref path, _, _) => {
+ // Resolve the path to the structure it goes to. We don't
+ // check to ensure that the path is actually a structure; that
+ // is checked later during typeck.
+ match self.resolve_path(expr.id, path, TypeNS, false) {
+ Some(definition) => self.record_def(expr.id, definition),
+ result => {
+ debug!("(resolving expression) didn't find struct \
+ def: {}", result);
+ let msg = format!("`{}` does not name a structure",
+ self.path_names_to_string(path));
+ self.resolve_error(path.span, msg.as_slice());
+ }
+ }
+
+ visit::walk_expr(self, expr);
+ }
+
+ ExprLoop(_, Some(label)) | ExprWhile(_, _, Some(label)) => {
+ self.with_label_rib(|this| {
+ let def_like = DlDef(DefLabel(expr.id));
+
+ {
+ let rib = this.label_ribs.last_mut().unwrap();
+ let renamed = mtwt::resolve(label);
+ rib.bindings.insert(renamed, def_like);
+ }
+
+ visit::walk_expr(this, expr);
+ })
+ }
+
+ ExprForLoop(ref pattern, ref head, ref body, optional_label) => {
+ self.resolve_expr(&**head);
+
+ self.value_ribs.push(Rib::new(NormalRibKind));
+
+ self.resolve_pattern(&**pattern,
+ LocalIrrefutableMode,
+ &mut HashMap::new());
+
+ match optional_label {
+ None => {}
+ Some(label) => {
+ self.label_ribs
+ .push(Rib::new(NormalRibKind));
+ let def_like = DlDef(DefLabel(expr.id));
+
+ {
+ let rib = self.label_ribs.last_mut().unwrap();
+ let renamed = mtwt::resolve(label);
+ rib.bindings.insert(renamed, def_like);
+ }
+ }
+ }
+
+ self.resolve_block(&**body);
+
+ if optional_label.is_some() {
+ drop(self.label_ribs.pop())
+ }
+
+ self.value_ribs.pop();
+ }
+
+ ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
+ let renamed = mtwt::resolve(label);
+ match self.search_ribs(self.label_ribs.as_slice(),
+ renamed, expr.span) {
+ None => {
+ self.resolve_error(
+ expr.span,
+ format!("use of undeclared label `{}`",
+ token::get_ident(label)).as_slice())
+ }
+ Some(DlDef(def @ DefLabel(_))) => {
+ // Since this def is a label, it is never read.
+ self.record_def(expr.id, (def, LastMod(AllPublic)))
+ }
+ Some(_) => {
+ self.session.span_bug(expr.span,
+ "label wasn't mapped to a \
+ label def!")
+ }
+ }
+ }
+
+ _ => {
+ visit::walk_expr(self, expr);
+ }
+ }
+ }
+
+ fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
+ match expr.node {
+ ExprField(_, ident) => {
+ // FIXME(#6890): Even though you can't treat a method like a
+ // field, we need to add any trait methods we find that match
+ // the field name so that we can do some nice error reporting
+ // later on in typeck.
+ let traits = self.search_for_traits_containing_method(ident.node.name);
+ self.trait_map.insert(expr.id, traits);
+ }
+ ExprMethodCall(ident, _, _) => {
+ debug!("(recording candidate traits for expr) recording \
+ traits for {}",
+ expr.id);
+ let traits = self.search_for_traits_containing_method(ident.node.name);
+ self.trait_map.insert(expr.id, traits);
+ }
+ _ => {
+ // Nothing to do.
+ }
+ }
+ }
+
+ fn search_for_traits_containing_method(&mut self, name: Name) -> Vec<DefId> {
+ debug!("(searching for traits containing method) looking for '{}'",
+ token::get_name(name));
+
+ fn add_trait_info(found_traits: &mut Vec<DefId>,
+ trait_def_id: DefId,
+ name: Name) {
+ debug!("(adding trait info) found trait {}:{} for method '{}'",
+ trait_def_id.krate,
+ trait_def_id.node,
+ token::get_name(name));
+ found_traits.push(trait_def_id);
+ }
+
+ let mut found_traits = Vec::new();
+ let mut search_module = self.current_module.clone();
+ loop {
+ // Look for the current trait.
+ match self.current_trait_ref {
+ Some((trait_def_id, _)) => {
+ if self.trait_item_map.contains_key(&(name, trait_def_id)) {
+ add_trait_info(&mut found_traits, trait_def_id, name);
+ }
+ }
+ None => {} // Nothing to do.
+ }
+
+ // Look for trait children.
+ self.populate_module_if_necessary(&search_module);
+
+ {
+ for (_, child_names) in search_module.children.borrow().iter() {
+ let def = match child_names.def_for_namespace(TypeNS) {
+ Some(def) => def,
+ None => continue
+ };
+ let trait_def_id = match def {
+ DefTrait(trait_def_id) => trait_def_id,
+ _ => continue,
+ };
+ if self.trait_item_map.contains_key(&(name, trait_def_id)) {
+ add_trait_info(&mut found_traits, trait_def_id, name);
+ }
+ }
+ }
+
+ // Look for imports.
+ for (_, import) in search_module.import_resolutions.borrow().iter() {
+ let target = match import.target_for_namespace(TypeNS) {
+ None => continue,
+ Some(target) => target,
+ };
+ let did = match target.bindings.def_for_namespace(TypeNS) {
+ Some(DefTrait(trait_def_id)) => trait_def_id,
+ Some(..) | None => continue,
+ };
+ if self.trait_item_map.contains_key(&(name, did)) {
+ add_trait_info(&mut found_traits, did, name);
+ self.used_imports.insert((import.type_id, TypeNS));
+ if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
+ self.used_crates.insert(kid);
+ }
+ }
+ }
+
+ match search_module.parent_link.clone() {
+ NoParentLink | ModuleParentLink(..) => break,
+ BlockParentLink(parent_module, _) => {
+ search_module = parent_module.upgrade().unwrap();
+ }
+ }
+ }
+
+ found_traits
+ }
+
+ fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) {
+ debug!("(recording def) recording {} for {}, last private {}",
+ def, node_id, lp);
+ assert!(match lp {LastImport{..} => false, _ => true},
+ "Import should only be used for `use` directives");
+ self.last_private.insert(node_id, lp);
+
+ match self.def_map.borrow_mut().entry(node_id) {
+ // Resolve appears to "resolve" the same ID multiple
+ // times, so here is a sanity check it at least comes to
+ // the same conclusion! - nmatsakis
+ Occupied(entry) => if def != *entry.get() {
+ self.session
+ .bug(format!("node_id {} resolved first to {} and \
+ then {}",
+ node_id,
+ *entry.get(),
+ def).as_slice());
+ },
+ Vacant(entry) => { entry.set(def); },
+ }
+ }
+
+ fn enforce_default_binding_mode(&mut self,
+ pat: &Pat,
+ pat_binding_mode: BindingMode,
+ descr: &str) {
+ match pat_binding_mode {
+ BindByValue(_) => {}
+ BindByRef(..) => {
+ self.resolve_error(pat.span,
+ format!("cannot use `ref` binding mode \
+ with {}",
+ descr).as_slice());
+ }
+ }
+ }
+
+ //
+ // Diagnostics
+ //
+ // Diagnostics are not particularly efficient, because they're rarely
+ // hit.
+ //
+
+ /// A somewhat inefficient routine to obtain the name of a module.
+ fn module_to_string(&self, module: &Module) -> String {
+ let mut names = Vec::new();
+
+ fn collect_mod(names: &mut Vec<ast::Name>, module: &Module) {
+ match module.parent_link {
+ NoParentLink => {}
+ ModuleParentLink(ref module, name) => {
+ names.push(name);
+ collect_mod(names, &*module.upgrade().unwrap());
+ }
+ BlockParentLink(ref module, _) => {
+ // danger, shouldn't be ident?
+ names.push(special_idents::opaque.name);
+ collect_mod(names, &*module.upgrade().unwrap());
+ }
+ }
+ }
+ collect_mod(&mut names, module);
+
+ if names.len() == 0 {
+ return "???".to_string();
+ }
+ self.names_to_string(names.into_iter().rev()
+ .collect::<Vec<ast::Name>>()
+ .as_slice())
+ }
+
+ #[allow(dead_code)] // useful for debugging
+ fn dump_module(&mut self, module_: Rc<Module>) {
+ debug!("Dump of module `{}`:", self.module_to_string(&*module_));
+
+ debug!("Children:");
+ self.populate_module_if_necessary(&module_);
+ for (&name, _) in module_.children.borrow().iter() {
+ debug!("* {}", token::get_name(name));
+ }
+
+ debug!("Import resolutions:");
+ let import_resolutions = module_.import_resolutions.borrow();
+ for (&name, import_resolution) in import_resolutions.iter() {
+ let value_repr;
+ match import_resolution.target_for_namespace(ValueNS) {
+ None => { value_repr = "".to_string(); }
+ Some(_) => {
+ value_repr = " value:?".to_string();
+ // FIXME #4954
+ }
+ }
+
+ let type_repr;
+ match import_resolution.target_for_namespace(TypeNS) {
+ None => { type_repr = "".to_string(); }
+ Some(_) => {
+ type_repr = " type:?".to_string();
+ // FIXME #4954
+ }
+ }
+
+ debug!("* {}:{}{}", token::get_name(name), value_repr, type_repr);
+ }
+ }
+}
+
+pub struct CrateMap {
+ pub def_map: DefMap,
+ pub freevars: RefCell<FreevarMap>,
+ pub capture_mode_map: RefCell<CaptureModeMap>,
+ pub export_map: ExportMap,
+ pub trait_map: TraitMap,
+ pub external_exports: ExternalExports,
+ pub last_private_map: LastPrivateMap,
+}
+
+/// Entry point to crate resolution.
+pub fn resolve_crate(session: &Session,
+ _: &LanguageItems,
+ krate: &Crate)
+ -> CrateMap {
+ let mut resolver = Resolver::new(session, krate.span);
+
+ resolver.build_reduced_graph(krate);
+ session.abort_if_errors();
+
+ resolver.resolve_imports();
+ session.abort_if_errors();
+
+ record_exports::record(&mut resolver);
+ session.abort_if_errors();
+
+ resolver.resolve_crate(krate);
+ session.abort_if_errors();
+
+ check_unused::check_crate(&mut resolver, krate);
+
+ CrateMap {
+ def_map: resolver.def_map,
+ freevars: resolver.freevars,
+ capture_mode_map: RefCell::new(resolver.capture_mode_map),
+ export_map: resolver.export_map,
+ trait_map: resolver.trait_map,
+ external_exports: resolver.external_exports,
+ last_private_map: resolver.last_private,
+ }
+}
--- /dev/null
+// Copyright 2012-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.
+
+
+// Export recording
+//
+// This pass simply determines what all "export" keywords refer to and
+// writes the results into the export map.
+//
+// FIXME #4953 This pass will be removed once exports change to per-item.
+// Then this operation can simply be performed as part of item (or import)
+// processing.
+
+use {Module, NameBindings, Resolver};
+use Namespace::{mod, TypeNS, ValueNS};
+
+use rustc::middle::def::Export;
+use syntax::ast;
+use syntax::parse::token;
+
+use std::rc::Rc;
+
+struct ExportRecorder<'a, 'b:'a> {
+ resolver: &'a mut Resolver<'b>
+}
+
+// Deref and DerefMut impls allow treating ExportRecorder as Resolver.
+impl<'a, 'b> Deref<Resolver<'b>> for ExportRecorder<'a, 'b> {
+ fn deref<'c>(&'c self) -> &'c Resolver<'b> {
+ &*self.resolver
+ }
+}
+
+impl<'a, 'b> DerefMut<Resolver<'b>> for ExportRecorder<'a, 'b> {
+ fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> {
+ &mut *self.resolver
+ }
+}
+
+impl<'a, 'b> ExportRecorder<'a, 'b> {
+ fn record_exports_for_module_subtree(&mut self,
+ module_: Rc<Module>) {
+ // If this isn't a local krate, then bail out. We don't need to record
+ // exports for nonlocal crates.
+
+ match module_.def_id.get() {
+ Some(def_id) if def_id.krate == ast::LOCAL_CRATE => {
+ // OK. Continue.
+ debug!("(recording exports for module subtree) recording \
+ exports for local module `{}`",
+ self.module_to_string(&*module_));
+ }
+ None => {
+ // Record exports for the root module.
+ debug!("(recording exports for module subtree) recording \
+ exports for root module `{}`",
+ self.module_to_string(&*module_));
+ }
+ Some(_) => {
+ // Bail out.
+ debug!("(recording exports for module subtree) not recording \
+ exports for `{}`",
+ self.module_to_string(&*module_));
+ return;
+ }
+ }
+
+ self.record_exports_for_module(&*module_);
+ self.populate_module_if_necessary(&module_);
+
+ for (_, child_name_bindings) in module_.children.borrow().iter() {
+ match child_name_bindings.get_module_if_available() {
+ None => {
+ // Nothing to do.
+ }
+ Some(child_module) => {
+ self.record_exports_for_module_subtree(child_module);
+ }
+ }
+ }
+
+ for (_, child_module) in module_.anonymous_children.borrow().iter() {
+ self.record_exports_for_module_subtree(child_module.clone());
+ }
+ }
+
+ fn record_exports_for_module(&mut self, module_: &Module) {
+ let mut exports = Vec::new();
+
+ self.add_exports_for_module(&mut exports, module_);
+ match module_.def_id.get() {
+ Some(def_id) => {
+ self.export_map.insert(def_id.node, exports);
+ debug!("(computing exports) writing exports for {} (some)",
+ def_id.node);
+ }
+ None => {}
+ }
+ }
+
+ fn add_exports_of_namebindings(&mut self,
+ exports: &mut Vec<Export>,
+ name: ast::Name,
+ namebindings: &NameBindings,
+ ns: Namespace) {
+ match namebindings.def_for_namespace(ns) {
+ Some(d) => {
+ debug!("(computing exports) YES: export '{}' => {}",
+ name, d.def_id());
+ exports.push(Export {
+ name: name,
+ def_id: d.def_id()
+ });
+ }
+ d_opt => {
+ debug!("(computing exports) NO: {}", d_opt);
+ }
+ }
+ }
+
+ fn add_exports_for_module(&mut self,
+ exports: &mut Vec<Export>,
+ module_: &Module) {
+ for (name, importresolution) in module_.import_resolutions.borrow().iter() {
+ if !importresolution.is_public {
+ continue
+ }
+ let xs = [TypeNS, ValueNS];
+ for &ns in xs.iter() {
+ match importresolution.target_for_namespace(ns) {
+ Some(target) => {
+ debug!("(computing exports) maybe export '{}'",
+ token::get_name(*name));
+ self.add_exports_of_namebindings(exports,
+ *name,
+ &*target.bindings,
+ ns)
+ }
+ _ => ()
+ }
+ }
+ }
+ }
+}
+
+pub fn record(resolver: &mut Resolver) {
+ let mut recorder = ExportRecorder { resolver: resolver };
+ let root_module = recorder.graph_root.get_module();
+ recorder.record_exports_for_module_subtree(root_module);
+}
modules_config.emit_obj = true;
metadata_config.emit_obj = true;
},
+ config::OutputTypeDepInfo => {}
}
}
link_obj(&crate_output.temp_path(config::OutputTypeObject));
}
}
+ config::OutputTypeDepInfo => {}
}
}
let user_wants_bitcode = user_wants_bitcode;
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![feature(default_type_params, globs, import_shadowing, macro_rules, phase, quote)]
+#![feature(default_type_params, globs, macro_rules, phase, quote)]
#![feature(slicing_syntax, unsafe_destructor)]
#![feature(rustc_diagnostic_macros)]
#![feature(unboxed_closures)]
use middle::check_match::StaticInliner;
use middle::check_match;
use middle::const_eval;
-use middle::def;
+use middle::def::{mod, DefMap};
use middle::expr_use_visitor as euv;
use middle::lang_items::StrEqFnLangItem;
use middle::mem_categorization as mc;
use middle::pat_util::*;
-use middle::resolve::DefMap;
use trans::adt;
use trans::base::*;
use trans::build::{AddCase, And, BitCast, Br, CondBr, GEPi, InBoundsGEP, Load};
use llvm;
use metadata::{csearch, encoder, loader};
use middle::astencode;
+use middle::cfg;
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
use middle::subst;
use middle::weak_lang_items;
}
}
-struct CheckForNestedReturnsVisitor {
+struct FindNestedReturn {
found: bool,
- in_return: bool
}
-impl CheckForNestedReturnsVisitor {
- fn explicit() -> CheckForNestedReturnsVisitor {
- CheckForNestedReturnsVisitor { found: false, in_return: false }
- }
- fn implicit() -> CheckForNestedReturnsVisitor {
- CheckForNestedReturnsVisitor { found: false, in_return: true }
+impl FindNestedReturn {
+ fn new() -> FindNestedReturn {
+ FindNestedReturn { found: false }
}
}
-impl<'v> Visitor<'v> for CheckForNestedReturnsVisitor {
+impl<'v> Visitor<'v> for FindNestedReturn {
fn visit_expr(&mut self, e: &ast::Expr) {
match e.node {
ast::ExprRet(..) => {
- if self.in_return {
- self.found = true;
- } else {
- self.in_return = true;
- visit::walk_expr(self, e);
- self.in_return = false;
- }
+ self.found = true;
}
_ => visit::walk_expr(self, e)
}
}
}
-fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
- match tcx.map.find(id) {
+fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>) {
+ let blk = match tcx.map.find(id) {
Some(ast_map::NodeItem(i)) => {
match i.node {
ast::ItemFn(_, _, _, _, ref blk) => {
- let mut explicit = CheckForNestedReturnsVisitor::explicit();
- let mut implicit = CheckForNestedReturnsVisitor::implicit();
- visit::walk_item(&mut explicit, &*i);
- visit::walk_expr_opt(&mut implicit, &blk.expr);
- explicit.found || implicit.found
+ blk
}
_ => tcx.sess.bug("unexpected item variant in has_nested_returns")
}
ast::ProvidedMethod(ref m) => {
match m.node {
ast::MethDecl(_, _, _, _, _, _, ref blk, _) => {
- let mut explicit = CheckForNestedReturnsVisitor::explicit();
- let mut implicit = CheckForNestedReturnsVisitor::implicit();
- visit::walk_method_helper(&mut explicit, &**m);
- visit::walk_expr_opt(&mut implicit, &blk.expr);
- explicit.found || implicit.found
+ blk
}
ast::MethMac(_) => tcx.sess.bug("unexpanded macro")
}
ast::MethodImplItem(ref m) => {
match m.node {
ast::MethDecl(_, _, _, _, _, _, ref blk, _) => {
- let mut explicit = CheckForNestedReturnsVisitor::explicit();
- let mut implicit = CheckForNestedReturnsVisitor::implicit();
- visit::walk_method_helper(&mut explicit, &**m);
- visit::walk_expr_opt(&mut implicit, &blk.expr);
- explicit.found || implicit.found
+ blk
}
ast::MethMac(_) => tcx.sess.bug("unexpanded macro")
}
Some(ast_map::NodeExpr(e)) => {
match e.node {
ast::ExprClosure(_, _, _, ref blk) => {
- let mut explicit = CheckForNestedReturnsVisitor::explicit();
- let mut implicit = CheckForNestedReturnsVisitor::implicit();
- visit::walk_expr(&mut explicit, e);
- visit::walk_expr_opt(&mut implicit, &blk.expr);
- explicit.found || implicit.found
+ blk
}
_ => tcx.sess.bug("unexpected expr variant in has_nested_returns")
}
}
-
- Some(ast_map::NodeVariant(..)) | Some(ast_map::NodeStructCtor(..)) => false,
+ Some(ast_map::NodeVariant(..)) |
+ Some(ast_map::NodeStructCtor(..)) => return (ast::DUMMY_NODE_ID, None),
// glue, shims, etc
- None if id == ast::DUMMY_NODE_ID => false,
+ None if id == ast::DUMMY_NODE_ID => return (ast::DUMMY_NODE_ID, None),
_ => tcx.sess.bug(format!("unexpected variant in has_nested_returns: {}",
tcx.map.path_to_string(id)).as_slice())
+ };
+
+ (blk.id, Some(cfg::CFG::new(tcx, &**blk)))
+}
+
+// Checks for the presence of "nested returns" in a function.
+// Nested returns are when the inner expression of a return expression
+// (the 'expr' in 'return expr') contains a return expression. Only cases
+// where the outer return is actually reachable are considered. Implicit
+// returns from the end of blocks are considered as well.
+//
+// This check is needed to handle the case where the inner expression is
+// part of a larger expression that may have already partially-filled the
+// return slot alloca. This can cause errors related to clean-up due to
+// the clobbering of the existing value in the return slot.
+fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
+ for n in cfg.graph.depth_traverse(cfg.entry) {
+ match tcx.map.find(n.id) {
+ Some(ast_map::NodeExpr(ex)) => {
+ if let ast::ExprRet(Some(ref ret_expr)) = ex.node {
+ let mut visitor = FindNestedReturn::new();
+ visit::walk_expr(&mut visitor, &**ret_expr);
+ if visitor.found {
+ return true;
+ }
+ }
+ }
+ Some(ast_map::NodeBlock(blk)) if blk.id == blk_id => {
+ let mut visitor = FindNestedReturn::new();
+ visit::walk_expr_opt(&mut visitor, &blk.expr);
+ if visitor.found {
+ return true;
+ }
+ }
+ _ => {}
+ }
}
+
+ return false;
}
// NB: must keep 4 fns in sync:
ty::FnDiverging => false
};
let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
- let nested_returns = has_nested_returns(ccx.tcx(), id);
+ let (blk_id, cfg) = build_cfg(ccx.tcx(), id);
+ let nested_returns = if let Some(ref cfg) = cfg {
+ has_nested_returns(ccx.tcx(), cfg, blk_id)
+ } else {
+ false
+ };
let mut fcx = FunctionContext {
llfn: llfndecl,
block_arena: block_arena,
ccx: ccx,
debug_context: debug_context,
- scopes: RefCell::new(Vec::new())
+ scopes: RefCell::new(Vec::new()),
+ cfg: cfg
};
if has_env {
encoder::EncodeParams {
diag: cx.sess().diagnostic(),
tcx: cx.tcx(),
- reexports2: cx.exp_map2(),
+ reexports: cx.export_map(),
item_symbols: cx.item_symbols(),
link_meta: cx.link_meta(),
cstore: &cx.sess().cstore,
pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
-> (ty::ctxt<'tcx>, CrateTranslation) {
- let ty::CrateAnalysis { ty_cx: tcx, exp_map2, reachable, name, .. } = analysis;
+ let ty::CrateAnalysis { ty_cx: tcx, export_map, reachable, name, .. } = analysis;
let krate = tcx.map.krate();
// Before we touch LLVM, make sure that multithreading is enabled.
let shared_ccx = SharedCrateContext::new(link_meta.crate_name.as_slice(),
codegen_units,
tcx,
- exp_map2,
+ export_map,
Sha256::new(),
link_meta.clone(),
reachable);
let opt_ref_id = match node {
ExprId(id) => if id != 0 { Some(id) } else { None },
- MethodCall(_) => None,
+ MethodCallKey(_) => None,
};
let (val, must_cast) =
// are subst'd)
let ref_ty = match node {
ExprId(id) => node_id_type(bcx, id),
- MethodCall(method_call) => {
+ MethodCallKey(method_call) => {
let t = (*bcx.tcx().method_map.borrow())[method_call].ty;
monomorphize_type(bcx, t)
}
use llvm;
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef};
use llvm::{True, False, Bool};
+use middle::cfg;
use middle::def;
use middle::infer;
use middle::lang_items::LangItem;
// Cleanup scopes.
pub scopes: RefCell<Vec<cleanup::CleanupScope<'a, 'tcx>>>,
+
+ pub cfg: Option<cfg::CFG>,
}
impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
ExprId(ast::NodeId),
// Type parameters for a method call like `a.foo::<int>()`
- MethodCall(ty::MethodCall)
+ MethodCallKey(ty::MethodCall)
}
pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ExprId(id) => {
ty::node_id_item_substs(tcx, id).substs
}
- MethodCall(method_call) => {
+ MethodCallKey(method_call) => {
(*tcx.method_map.borrow())[method_call].substs.clone()
}
};
use llvm::{TargetData};
use llvm::mk_target_data;
use metadata::common::LinkMeta;
-use middle::resolve;
+use middle::def::ExportMap;
use middle::traits;
use trans::adt;
use trans::base;
metadata_llmod: ModuleRef,
metadata_llcx: ContextRef,
- exp_map2: resolve::ExportMap2,
+ export_map: ExportMap,
reachable: NodeSet,
item_symbols: RefCell<NodeMap<String>>,
link_meta: LinkMeta,
pub fn new(crate_name: &str,
local_count: uint,
tcx: ty::ctxt<'tcx>,
- emap2: resolve::ExportMap2,
+ export_map: ExportMap,
symbol_hasher: Sha256,
link_meta: LinkMeta,
reachable: NodeSet)
local_ccxs: Vec::with_capacity(local_count),
metadata_llmod: metadata_llmod,
metadata_llcx: metadata_llcx,
- exp_map2: emap2,
+ export_map: export_map,
reachable: reachable,
item_symbols: RefCell::new(NodeMap::new()),
link_meta: link_meta,
self.metadata_llcx
}
- pub fn exp_map2<'a>(&'a self) -> &'a resolve::ExportMap2 {
- &self.exp_map2
+ pub fn export_map<'a>(&'a self) -> &'a ExportMap {
+ &self.export_map
}
pub fn reachable<'a>(&'a self) -> &'a NodeSet {
&self.local.item_vals
}
- pub fn exp_map2<'a>(&'a self) -> &'a resolve::ExportMap2 {
- &self.shared.exp_map2
+ pub fn export_map<'a>(&'a self) -> &'a ExportMap {
+ &self.shared.export_map
}
pub fn reachable<'a>(&'a self) -> &'a NodeSet {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::*;
+use llvm::ValueRef;
use middle::def;
use middle::lang_items::{PanicFnLangItem, PanicBoundsCheckFnLangItem};
use trans::_match;
if dest != expr::Ignore {
let block_ty = node_id_type(bcx, b.id);
+
if b.expr.is_none() || type_is_zero_size(bcx.ccx(), block_ty) {
dest = expr::Ignore;
+ } else if b.expr.is_some() {
+ // If the block has an expression, but that expression isn't reachable,
+ // don't save into the destination given, ignore it.
+ if let Some(ref cfg) = bcx.fcx.cfg {
+ if !cfg.node_is_reachable(b.expr.as_ref().unwrap().id) {
+ dest = expr::Ignore;
+ }
+ }
}
}
debug!("iterator type is {}, datum type is {}",
ppaux::ty_to_string(bcx.tcx(), iterator_type),
ppaux::ty_to_string(bcx.tcx(), iterator_datum.ty));
+
let lliterator = load_ty(bcx, iterator_datum.val, iterator_datum.ty);
// Create our basic blocks and set up our loop cleanups.
llpayload,
binding_cleanup_scope_id);
+ debuginfo::create_for_loop_var_metadata(body_bcx_in, pat);
+
// Codegen the body.
body_bcx_out = trans_block(body_bcx_out, body, expr::Ignore);
body_bcx_out =
//! comparatively expensive to construct, though, `ty::type_id()` is still used
//! additionally as an optimization for cases where the exact same type has been
//! seen before (which is most of the time).
-use self::FunctionDebugContextRepr::*;
use self::VariableAccess::*;
use self::VariableKind::*;
use self::MemberOffset::*;
// mut ptr (*mut) -> {*mut :pointee-uid:}
// unique ptr (~) -> {~ :pointee-uid:}
// @-ptr (@) -> {@ :pointee-uid:}
- // sized vec ([T, ..x]) -> {[:size:] :element-uid:}
+ // sized vec ([T; x]) -> {[:size:] :element-uid:}
// unsized vec ([T]) -> {[] :element-uid:}
// trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> }
// closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \
}
}
-pub struct FunctionDebugContext {
- repr: FunctionDebugContextRepr,
-}
-
-enum FunctionDebugContextRepr {
- DebugInfo(Box<FunctionDebugContextData>),
+pub enum FunctionDebugContext {
+ RegularContext(Box<FunctionDebugContextData>),
DebugInfoDisabled,
FunctionWithoutDebugInfo,
}
cx: &CrateContext,
span: Span)
-> &'a FunctionDebugContextData {
- match self.repr {
- DebugInfo(box ref data) => data,
- DebugInfoDisabled => {
+ match *self {
+ FunctionDebugContext::RegularContext(box ref data) => data,
+ FunctionDebugContext::DebugInfoDisabled => {
cx.sess().span_bug(span,
FunctionDebugContext::debuginfo_disabled_message());
}
- FunctionWithoutDebugInfo => {
+ FunctionDebugContext::FunctionWithoutDebugInfo => {
cx.sess().span_bug(span,
FunctionDebugContext::should_be_ignored_message());
}
/// Creates debug information for the given local variable.
///
+/// This function assumes that there's a datum for each pattern component of the
+/// local in `bcx.fcx.lllocals`.
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) {
if fn_should_be_ignored(bcx.fcx) {
let cx = bcx.ccx();
let def_map = &cx.tcx().def_map;
+ let locals = bcx.fcx.lllocals.borrow();
- pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, path1| {
- let var_ident = path1.node;
-
- let datum = match bcx.fcx.lllocals.borrow().get(&node_id).cloned() {
+ pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, var_ident| {
+ let datum = match locals.get(&node_id) {
Some(datum) => datum,
None => {
bcx.sess().span_bug(span,
}
};
+ if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() {
+ cx.sess().span_bug(span, "debuginfo::create_local_var_metadata() - \
+ Referenced variable location is not an alloca!");
+ }
+
let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
declare_local(bcx,
- var_ident,
+ var_ident.node,
datum.ty,
scope_metadata,
DirectVariable { alloca: datum.val },
// for the binding. For ByRef bindings that's a `T*` but for ByMove bindings we
// actually have `T**`. So to get the actual variable we need to dereference once
// more. For ByCopy we just use the stack slot we created for the binding.
- let var_type = match binding.trmode {
+ let var_access = match binding.trmode {
TrByCopy(llbinding) => DirectVariable {
alloca: llbinding
},
variable_ident,
binding.ty,
scope_metadata,
- var_type,
+ var_access,
LocalVariable,
binding.span);
}
/// Creates debug information for the given function argument.
///
+/// This function assumes that there's a datum for each pattern component of the
+/// argument in `bcx.fcx.lllocals`.
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
if fn_should_be_ignored(bcx.fcx) {
return;
}
- let fcx = bcx.fcx;
- let cx = fcx.ccx;
+ let def_map = &bcx.tcx().def_map;
+ let scope_metadata = bcx
+ .fcx
+ .debug_context
+ .get_ref(bcx.ccx(), arg.pat.span)
+ .fn_metadata;
+ let locals = bcx.fcx.lllocals.borrow();
- 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, path1| {
- let llarg = match bcx.fcx.lllocals.borrow().get(&node_id).cloned() {
+ pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, var_ident| {
+ let datum = match locals.get(&node_id) {
Some(v) => v,
None => {
bcx.sess().span_bug(span,
}
};
- if unsafe { llvm::LLVMIsAAllocaInst(llarg.val) } == ptr::null_mut() {
- cx.sess().span_bug(span, "debuginfo::create_argument_metadata() - \
- Referenced variable location is not an alloca!");
+ if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() {
+ bcx.sess().span_bug(span, "debuginfo::create_argument_metadata() - \
+ Referenced variable location is not an alloca!");
}
let argument_index = {
- let counter = &fcx.debug_context.get_ref(cx, span).argument_counter;
+ let counter = &bcx
+ .fcx
+ .debug_context
+ .get_ref(bcx.ccx(), span)
+ .argument_counter;
let argument_index = counter.get();
counter.set(argument_index + 1);
argument_index
};
declare_local(bcx,
- path1.node,
- llarg.ty,
+ var_ident.node,
+ datum.ty,
scope_metadata,
- DirectVariable { alloca: llarg.val },
+ DirectVariable { alloca: datum.val },
ArgumentVariable(argument_index),
span);
})
}
+/// Creates debug information for the given for-loop variable.
+///
+/// This function assumes that there's a datum for each pattern component of the
+/// loop variable in `bcx.fcx.lllocals`.
+/// Adds the created metadata nodes directly to the crate's IR.
+pub fn create_for_loop_var_metadata(bcx: Block, pat: &ast::Pat) {
+ if fn_should_be_ignored(bcx.fcx) {
+ return;
+ }
+
+ let def_map = &bcx.tcx().def_map;
+ let locals = bcx.fcx.lllocals.borrow();
+
+ pat_util::pat_bindings(def_map, pat, |_, node_id, span, var_ident| {
+ let datum = match locals.get(&node_id) {
+ Some(datum) => datum,
+ None => {
+ bcx.sess().span_bug(span,
+ format!("no entry in lllocals table for {}",
+ node_id).as_slice());
+ }
+ };
+
+ if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() {
+ bcx.sess().span_bug(span, "debuginfo::create_for_loop_var_metadata() - \
+ Referenced variable location is not an alloca!");
+ }
+
+ let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
+
+ declare_local(bcx,
+ var_ident.node,
+ datum.ty,
+ scope_metadata,
+ DirectVariable { alloca: datum.val },
+ LocalVariable,
+ span);
+ })
+}
+
pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
node_id: ast::NodeId,
node_span: Span,
pub fn set_source_location(fcx: &FunctionContext,
node_id: ast::NodeId,
span: Span) {
- match fcx.debug_context.repr {
- DebugInfoDisabled => return,
- FunctionWithoutDebugInfo => {
+ match fcx.debug_context {
+ FunctionDebugContext::DebugInfoDisabled => return,
+ FunctionDebugContext::FunctionWithoutDebugInfo => {
set_debug_location(fcx.ccx, UnknownLocation);
return;
}
- DebugInfo(box ref function_debug_context) => {
+ FunctionDebugContext::RegularContext(box ref function_debug_context) => {
let cx = fcx.ccx;
debug!("set_source_location: {}", cx.sess().codemap().span_to_string(span));
/// switches source location emitting on and must therefore be called before the
/// first real statement/expression of the function is translated.
pub fn start_emitting_source_locations(fcx: &FunctionContext) {
- match fcx.debug_context.repr {
- DebugInfo(box ref data) => {
+ match fcx.debug_context {
+ FunctionDebugContext::RegularContext(box ref data) => {
data.source_locations_enabled.set(true)
},
_ => { /* safe to ignore */ }
param_substs: &Substs<'tcx>,
llfn: ValueRef) -> FunctionDebugContext {
if cx.sess().opts.debuginfo == NoDebugInfo {
- return FunctionDebugContext { repr: DebugInfoDisabled };
+ return FunctionDebugContext::DebugInfoDisabled;
}
// Clear the debug location so we don't assign them in the function prelude.
if fn_ast_id == ast::DUMMY_NODE_ID {
// This is a function not linked to any source location, so don't
// generate debuginfo for it.
- return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
+ return FunctionDebugContext::FunctionWithoutDebugInfo;
}
let empty_generics = ast_util::empty_generics();
let (ident, fn_decl, generics, top_level_block, span, has_path) = match fnitem {
ast_map::NodeItem(ref item) => {
if contains_nodebug_attribute(item.attrs.as_slice()) {
- return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
+ return FunctionDebugContext::FunctionWithoutDebugInfo;
}
match item.node {
match **item {
ast::MethodImplItem(ref method) => {
if contains_nodebug_attribute(method.attrs.as_slice()) {
- return FunctionDebugContext {
- repr: FunctionWithoutDebugInfo
- };
+ return FunctionDebugContext::FunctionWithoutDebugInfo;
}
(method.pe_ident(),
match **trait_method {
ast::ProvidedMethod(ref method) => {
if contains_nodebug_attribute(method.attrs.as_slice()) {
- return FunctionDebugContext {
- repr: FunctionWithoutDebugInfo
- };
+ return FunctionDebugContext::FunctionWithoutDebugInfo;
}
(method.pe_ident(),
ast_map::NodeForeignItem(..) |
ast_map::NodeVariant(..) |
ast_map::NodeStructCtor(..) => {
- return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
+ return FunctionDebugContext::FunctionWithoutDebugInfo;
}
_ => cx.sess().bug(format!("create_function_debug_context: \
unexpected sort of node: {}",
// This can be the case for functions inlined from another crate
if span == codemap::DUMMY_SP {
- return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
+ return FunctionDebugContext::FunctionWithoutDebugInfo;
}
let loc = span_start(cx, span);
})
});
+ let scope_map = create_scope_map(cx,
+ fn_decl.inputs.as_slice(),
+ &*top_level_block,
+ fn_metadata,
+ fn_ast_id);
+
// Initialize fn debug context (including scope map and namespace map)
let fn_debug_context = box FunctionDebugContextData {
- scope_map: RefCell::new(NodeMap::new()),
+ scope_map: RefCell::new(scope_map),
fn_metadata: fn_metadata,
argument_counter: Cell::new(1),
source_locations_enabled: Cell::new(false),
};
- populate_scope_map(cx,
- fn_decl.inputs.as_slice(),
- &*top_level_block,
- fn_metadata,
- fn_ast_id,
- &mut *fn_debug_context.scope_map.borrow_mut());
- return FunctionDebugContext { repr: DebugInfo(fn_debug_context) };
+
+ return FunctionDebugContext::RegularContext(fn_debug_context);
fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
fn_ast_id: ast::NodeId,
}
fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
- match fcx.debug_context.repr {
- DebugInfo(_) => false,
+ match fcx.debug_context {
+ FunctionDebugContext::RegularContext(_) => false,
_ => true
}
}
// what belongs to which scope, creating DIScope DIEs along the way, and
// introducing *artificial* lexical scope descriptors where necessary. These
// artificial scopes allow GDB to correctly handle name shadowing.
-fn populate_scope_map(cx: &CrateContext,
- args: &[ast::Arg],
- fn_entry_block: &ast::Block,
- fn_metadata: DISubprogram,
- fn_ast_id: ast::NodeId,
- scope_map: &mut NodeMap<DIScope>) {
+fn create_scope_map(cx: &CrateContext,
+ args: &[ast::Arg],
+ fn_entry_block: &ast::Block,
+ fn_metadata: DISubprogram,
+ fn_ast_id: ast::NodeId)
+ -> NodeMap<DIScope> {
+ let mut scope_map = NodeMap::new();
+
let def_map = &cx.tcx().def_map;
struct ScopeStackEntry {
with_new_scope(cx,
fn_entry_block.span,
&mut scope_stack,
- scope_map,
+ &mut scope_map,
|cx, scope_stack, scope_map| {
walk_block(cx, fn_entry_block, scope_stack, scope_map);
});
+ return scope_map;
+
+
// local helper functions for walking the AST.
fn with_new_scope<F>(cx: &CrateContext,
scope_span: Span,
}
ast::PatMac(_) => {
- cx.sess().span_bug(pat.span, "debuginfo::populate_scope_map() - \
+ cx.sess().span_bug(pat.span, "debuginfo::create_scope_map() - \
Found unexpanded macro.");
}
}
}
ast::ExprIfLet(..) => {
- cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \
+ cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
Found unexpanded if-let.");
}
}
ast::ExprWhileLet(..) => {
- cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \
+ cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
Found unexpanded while-let.");
}
}
ast::ExprMac(_) => {
- cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \
+ cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \
Found unexpanded macro.");
}
match optional_length {
Some(len) => {
- output.push_str(format!(", ..{}", len).as_slice());
+ output.push_str(format!("; {}", len).as_slice());
}
None => { /* nothing to do */ }
};
controlflow::trans_cont(bcx, expr.id, label_opt)
}
ast::ExprRet(ref ex) => {
- controlflow::trans_ret(bcx, ex.as_ref().map(|e| &**e))
+ // Check to see if the return expression itself is reachable.
+ // This can occur when the inner expression contains a return
+ let reachable = if let Some(ref cfg) = bcx.fcx.cfg {
+ cfg.node_is_reachable(expr.id)
+ } else {
+ true
+ };
+
+ if reachable {
+ controlflow::trans_ret(bcx, ex.as_ref().map(|e| &**e))
+ } else {
+ // If it's not reachable, just translate the inner expression
+ // directly. This avoids having to manage a return slot when
+ // it won't actually be used anyway.
+ if let &Some(ref x) = ex {
+ bcx = trans_into(bcx, &**x, Ignore);
+ }
+ // Mark the end of the block as unreachable. Once we get to
+ // a return expression, there's no more we should be doing
+ // after this.
+ Unreachable(bcx);
+ bcx
+ }
}
ast::ExprWhile(ref cond, ref body, _) => {
controlflow::trans_while(bcx, expr.id, &**cond, &**body)
bcx: bcx,
data: Fn(callee::trans_fn_ref(bcx,
did,
- MethodCall(method_call))),
+ MethodCallKey(method_call))),
}
}
// those from the impl and those from the method:
let callee_substs =
combine_impl_and_methods_tps(
- bcx, MethodCall(method_call), vtable_impl.substs);
+ bcx, MethodCallKey(method_call), vtable_impl.substs);
// translate the function
let llfn = trans_fn_ref_with_substs(bcx,
mth_id,
- MethodCall(method_call),
+ MethodCallKey(method_call),
callee_substs);
Callee { bcx: bcx, data: Fn(llfn) }
// after passing through fulfill_obligation
let llfn = trans_fn_ref_with_substs(bcx,
closure_def_id,
- MethodCall(method_call),
+ MethodCallKey(method_call),
substs);
Callee {
ast_bounds: &[ast::TyParamBound])
-> ty::ExistentialBounds
{
- let ast_bound_refs: Vec<&ast::TyParamBound> =
- ast_bounds.iter().collect();
-
let partitioned_bounds =
- partition_bounds(this.tcx(), span, ast_bound_refs.as_slice());
+ partition_bounds(this.tcx(), span, ast_bounds);
conv_existential_bounds_from_partitioned_bounds(
this, rscope, span, principal_trait_ref, partitioned_bounds)
-> Ty<'tcx>
where AC: AstConv<'tcx>, RS:RegionScope
{
- let ast_bounds: Vec<&ast::TyParamBound> = ast_bounds.iter().collect();
let mut partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds[]);
let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) {
/// general trait bounds, and region bounds.
pub fn partition_bounds<'a>(tcx: &ty::ctxt,
_span: Span,
- ast_bounds: &'a [&ast::TyParamBound])
+ ast_bounds: &'a [ast::TyParamBound])
-> PartitionedBounds<'a>
{
let mut builtin_bounds = ty::empty_builtin_bounds();
let mut region_bounds = Vec::new();
let mut trait_bounds = Vec::new();
let mut trait_def_ids = DefIdMap::new();
- for &ast_bound in ast_bounds.iter() {
+ for ast_bound in ast_bounds.iter() {
match *ast_bound {
ast::TraitTyParamBound(ref b) => {
match ::lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
use util::ppaux::Repr;
use std::cmp;
-use std::collections::hash_map::{Occupied, Vacant};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax::ast;
use syntax::ast_util;
use syntax::codemap::{Span, Spanned};
expr: &ast::Expr,
discrim: &ast::Expr,
arms: &[ast::Arm],
- expected: Expectation<'tcx>) {
+ expected: Expectation<'tcx>,
+ match_src: ast::MatchSource) {
let tcx = fcx.ccx.tcx;
let discrim_ty = fcx.infcx().next_ty_var();
if ty::type_is_error(result_ty) || ty::type_is_error(bty) {
ty::mk_err()
} else {
+ let (origin, expected, found) = match match_src {
+ /* if-let construct without an else block */
+ ast::MatchSource::IfLetDesugar { contains_else_clause }
+ if !contains_else_clause => (
+ infer::IfExpressionWithNoElse(expr.span),
+ bty,
+ result_ty,
+ ),
+ _ => (
+ infer::MatchExpressionArm(expr.span, arm.body.span),
+ result_ty,
+ bty,
+ ),
+ };
+
infer::common_supertype(
fcx.infcx(),
- infer::MatchExpressionArm(expr.span, arm.body.span),
- true, // result_ty is "expected" here
- result_ty,
- bty
+ origin,
+ true,
+ expected,
+ found,
)
}
});
// Find the expected input/output types (if any). Substitute
// fresh bound regions for any bound regions we find in the
// expected types so as to avoid capture.
- let expected_sty = expected.map_to_option(fcx, |x| Some((*x).clone()));
- let (expected_sig,
- expected_onceness,
- expected_bounds) = {
- match expected_sty {
- Some(ty::ty_closure(ref cenv)) => {
- let (sig, _) =
- ty::replace_late_bound_regions(
- tcx,
- &cenv.sig,
- |_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn));
- let onceness = match (&store, &cenv.store) {
- // As the closure type and onceness go, only three
- // combinations are legit:
- // once closure
- // many closure
- // once proc
- // If the actual and expected closure type disagree with
- // each other, set expected onceness to be always Once or
- // Many according to the actual type. Otherwise, it will
- // yield either an illegal "many proc" or a less known
- // "once closure" in the error message.
- (&ty::UniqTraitStore, &ty::UniqTraitStore) |
- (&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
- cenv.onceness,
- (&ty::UniqTraitStore, _) => ast::Once,
- (&ty::RegionTraitStore(..), _) => ast::Many,
- };
- (Some(sig), onceness, cenv.bounds)
- }
- _ => {
- // Not an error! Means we're inferring the closure type
- let region = fcx.infcx().next_region_var(
- infer::AddrOfRegion(expr.span));
- let bounds = ty::region_existential_bound(region);
- let onceness = ast::Many;
- (None, onceness, bounds)
- }
+ let expected_cenv = expected.map_to_option(fcx, |ty| match ty.sty {
+ ty::ty_closure(ref cenv) => Some(cenv),
+ _ => None
+ });
+ let (expected_sig, expected_onceness, expected_bounds) = match expected_cenv {
+ Some(cenv) => {
+ let (sig, _) =
+ ty::replace_late_bound_regions(
+ tcx,
+ &cenv.sig,
+ |_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn));
+ let onceness = match (&store, &cenv.store) {
+ // As the closure type and onceness go, only three
+ // combinations are legit:
+ // once closure
+ // many closure
+ // once proc
+ // If the actual and expected closure type disagree with
+ // each other, set expected onceness to be always Once or
+ // Many according to the actual type. Otherwise, it will
+ // yield either an illegal "many proc" or a less known
+ // "once closure" in the error message.
+ (&ty::UniqTraitStore, &ty::UniqTraitStore) |
+ (&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
+ cenv.onceness,
+ (&ty::UniqTraitStore, _) => ast::Once,
+ (&ty::RegionTraitStore(..), _) => ast::Many,
+ };
+ (Some(sig), onceness, cenv.bounds)
+ }
+ _ => {
+ // Not an error! Means we're inferring the closure type
+ let region = fcx.infcx().next_region_var(
+ infer::AddrOfRegion(expr.span));
+ let bounds = ty::region_existential_bound(region);
+ let onceness = ast::Many;
+ (None, onceness, bounds)
}
};
-> bool {
// Bail out if the callee is a bare function or a closure. We check those
// manually.
- match *structure_of(fcx, callee.span, callee_type) {
+ match structurally_resolved_type(fcx, callee.span, callee_type).sty {
ty::ty_bare_fn(_) | ty::ty_closure(_) => return false,
_ => {}
}
ast::LitInt(_, ast::SignedIntLit(t, _)) => ty::mk_mach_int(t),
ast::LitInt(_, ast::UnsignedIntLit(t)) => ty::mk_mach_uint(t),
ast::LitInt(_, ast::UnsuffixedIntLit(_)) => {
- let opt_ty = expected.map_to_option(fcx, |sty| {
- match *sty {
- ty::ty_int(i) => Some(ty::mk_mach_int(i)),
- ty::ty_uint(i) => Some(ty::mk_mach_uint(i)),
+ let opt_ty = expected.map_to_option(fcx, |ty| {
+ match ty.sty {
+ ty::ty_int(_) | ty::ty_uint(_) => Some(ty),
ty::ty_char => Some(ty::mk_mach_uint(ast::TyU8)),
ty::ty_ptr(..) => Some(ty::mk_mach_uint(ast::TyU)),
ty::ty_bare_fn(..) => Some(ty::mk_mach_uint(ast::TyU)),
}
ast::LitFloat(_, t) => ty::mk_mach_float(t),
ast::LitFloatUnsuffixed(_) => {
- let opt_ty = expected.map_to_option(fcx, |sty| {
- match *sty {
- ty::ty_float(i) => Some(ty::mk_mach_float(i)),
+ let opt_ty = expected.map_to_option(fcx, |ty| {
+ match ty.sty {
+ ty::ty_float(_) => Some(ty),
_ => None
}
});
let fn_ty = fcx.expr_ty(f);
// Extract the function signature from `in_fty`.
- let fn_sty = structure_of(fcx, f.span, fn_ty);
+ let fn_ty = structurally_resolved_type(fcx, f.span, fn_ty);
// This is the "default" function signature, used in case of error.
// In that case, we check each argument against "error" in order to
variadic: false
});
- let fn_sig = match *fn_sty {
+ let fn_sig = match fn_ty.sty {
ty::ty_bare_fn(ty::BareFnTy {ref sig, ..}) |
ty::ty_closure(box ty::ClosureTy {ref sig, ..}) => sig,
_ => {
}
}
ast::ExprUnary(unop, ref oprnd) => {
- let expected_inner = expected.map(fcx, |sty| {
+ let expected_inner = expected.map(fcx, |ty| {
match unop {
- ast::UnUniq => match *sty {
+ ast::UnUniq => match ty.sty {
ty::ty_uniq(ty) => {
ExpectHasType(ty)
}
}
ast::ExprAddrOf(mutbl, ref oprnd) => {
let expected = expected.only_has_type();
- let hint = expected.map(fcx, |sty| {
- match *sty { ty::ty_rptr(_, ref mt) | ty::ty_ptr(ref mt) => ExpectHasType(mt.ty),
- _ => NoExpectation }
+ let hint = expected.map(fcx, |ty| {
+ match ty.sty {
+ ty::ty_rptr(_, ref mt) | ty::ty_ptr(ref mt) => ExpectHasType(mt.ty),
+ _ => NoExpectation
+ }
});
let lvalue_pref = match mutbl {
ast::MutMutable => PreferMutLvalue,
fcx.write_nil(id);
}
}
- ast::ExprMatch(ref discrim, ref arms, _) => {
- _match::check_match(fcx, expr, &**discrim, arms.as_slice(), expected);
+ ast::ExprMatch(ref discrim, ref arms, match_src) => {
+ _match::check_match(fcx, expr, &**discrim, arms.as_slice(), expected, match_src);
}
ast::ExprClosure(_, opt_kind, ref decl, ref body) => {
closure::check_expr_closure(fcx, expr, opt_kind, &**decl, &**body, expected);
}
ast::ExprTup(ref elts) => {
let expected = expected.only_has_type();
- let flds = expected.map_to_option(fcx, |sty| {
- match *sty {
- ty::ty_tup(ref flds) => Some((*flds).clone()),
+ let flds = expected.map_to_option(fcx, |ty| {
+ match ty.sty {
+ ty::ty_tup(ref flds) => Some(flds[]),
_ => None
}
});
}
fn map<'a, F>(self, fcx: &FnCtxt<'a, 'tcx>, unpack: F) -> Expectation<'tcx> where
- F: FnOnce(&ty::sty<'tcx>) -> Expectation<'tcx>
+ F: FnOnce(Ty<'tcx>) -> Expectation<'tcx>
{
match self.resolve(fcx) {
NoExpectation => NoExpectation,
- ExpectCastableToType(t) | ExpectHasType(t) => unpack(&t.sty),
+ ExpectCastableToType(ty) | ExpectHasType(ty) => unpack(ty),
}
}
fn map_to_option<'a, O, F>(self, fcx: &FnCtxt<'a, 'tcx>, unpack: F) -> Option<O> where
- F: FnOnce(&ty::sty<'tcx>) -> Option<O>,
+ F: FnOnce(Ty<'tcx>) -> Option<O>,
{
match self.resolve(fcx) {
NoExpectation => None,
- ExpectCastableToType(t) | ExpectHasType(t) => unpack(&t.sty),
+ ExpectCastableToType(ty) | ExpectHasType(ty) => unpack(ty),
}
}
}
ty
}
-// Returns the one-level-deep structure of the given type.
-pub fn structure_of<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, typ: Ty<'tcx>)
- -> &'tcx ty::sty<'tcx> {
- &structurally_resolved_type(fcx, sp, typ).sty
-}
-
// Returns true if b contains a break that can exit from b
pub fn may_break(cx: &ty::ctxt, id: ast::NodeId, b: &ast::Block) -> bool {
// First: is there an unlabeled break immediately
use syntax::visit::Visitor;
use std::cell::{RefCell};
-use std::collections::hash_map::{Vacant, Occupied};
+use std::collections::hash_map::Entry::{Vacant, Occupied};
use self::RepeatingScope::Repeating;
use self::SubjectNode::Subject;
use middle::traits;
use middle::ty::{mod, Ty};
use middle::ty::liberate_late_bound_regions;
-use middle::ty_fold::{TypeFolder, TypeFoldable};
+use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty};
use util::ppaux::Repr;
use std::collections::HashSet;
self.binding_count -= 1;
}
- ref sty => {
- self.fold_sty(sty);
+ _ => {
+ super_fold_ty(self, t);
}
}
self_param_ty,
bounds.as_slice(),
unbound,
- it.span,
- &generics.where_clause);
+ it.span);
let substs = mk_item_substs(ccx, &ty_generics);
let trait_def = Rc::new(ty::TraitDef {
subst::AssocSpace,
&associated_type.ty_param,
generics.types.len(subst::AssocSpace),
- &ast_generics.where_clause,
Some(local_def(trait_id)));
ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.ty_param.id,
def.clone());
space,
param,
i,
- where_clause,
None);
debug!("ty_generics: def for type param: {}, {}",
def.repr(this.tcx()),
// into the predicates list. This is currently kind of non-DRY.
create_predicates(this.tcx(), &mut result, space);
+ // Add the bounds not associated with a type parameter
+ for predicate in where_clause.predicates.iter() {
+ match predicate {
+ &ast::WherePredicate::BoundPredicate(ref bound_pred) => {
+ let ty = ast_ty_to_ty(this, &ExplicitRscope, &*bound_pred.bounded_ty);
+
+ for bound in bound_pred.bounds.iter() {
+ match bound {
+ &ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref) => {
+ let trait_ref = astconv::instantiate_poly_trait_ref(
+ this,
+ &ExplicitRscope,
+ //@jroesch: for now trait_ref, poly_trait_ref?
+ poly_trait_ref,
+ Some(ty),
+ AllowEqConstraints::Allow
+ );
+
+ result.predicates.push(space, ty::Predicate::Trait(trait_ref));
+ }
+
+ &ast::TyParamBound::RegionTyParamBound(ref lifetime) => {
+ let region = ast_region_to_region(this.tcx(), lifetime);
+ let pred = ty::Binder(ty::OutlivesPredicate(ty, region));
+ result.predicates.push(space, ty::Predicate::TypeOutlives(pred))
+ }
+ }
+ }
+ }
+
+ &ast::WherePredicate::RegionPredicate(ref region_pred) => {
+ let r1 = ast_region_to_region(this.tcx(), ®ion_pred.lifetime);
+ for bound in region_pred.bounds.iter() {
+ let r2 = ast_region_to_region(this.tcx(), bound);
+ let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
+ result.predicates.push(space, ty::Predicate::RegionOutlives(pred))
+ }
+ }
+
+ &ast::WherePredicate::EqPredicate(ref eq_pred) => {
+ // FIXME(#20041)
+ this.tcx().sess.span_bug(eq_pred.span,
+ "Equality constraints are not yet \
+ implemented (#20041)")
+ }
+ }
+ }
+
return result;
fn create_type_parameters_for_associated_types<'tcx, AC>(
space: subst::ParamSpace,
param: &ast::TyParam,
index: uint,
- where_clause: &ast::WhereClause,
associated_with: Option<ast::DefId>)
-> ty::TypeParameterDef<'tcx>
where AC: AstConv<'tcx>
param_ty,
param.bounds.as_slice(),
¶m.unbound,
- param.span,
- where_clause);
+ param.span);
let default = match param.default {
None => None,
Some(ref path) => {
param_ty: ty::ParamTy,
ast_bounds: &[ast::TyParamBound],
unbound: &Option<ast::TraitRef>,
- span: Span,
- where_clause: &ast::WhereClause)
+ span: Span)
-> ty::ParamBounds<'tcx>
where AC: AstConv<'tcx> {
let mut param_bounds = conv_param_bounds(this,
span,
param_ty,
- ast_bounds,
- where_clause);
+ ast_bounds);
add_unsized_bound(this,
fn conv_param_bounds<'tcx,AC>(this: &AC,
span: Span,
param_ty: ty::ParamTy,
- ast_bounds: &[ast::TyParamBound],
- where_clause: &ast::WhereClause)
+ ast_bounds: &[ast::TyParamBound])
-> ty::ParamBounds<'tcx>
- where AC: AstConv<'tcx> {
- let all_bounds =
- merge_param_bounds(this.tcx(), param_ty, ast_bounds, where_clause);
+ where AC: AstConv<'tcx>
+{
let astconv::PartitionedBounds { builtin_bounds,
trait_bounds,
region_bounds } =
- astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice());
+ astconv::partition_bounds(this.tcx(), span, ast_bounds.as_slice());
let trait_bounds: Vec<Rc<ty::PolyTraitRef>> =
trait_bounds.into_iter()
.map(|bound| {
}
}
-/// Merges the bounds declared on a type parameter with those found from where clauses into a
-/// single list.
-fn merge_param_bounds<'a>(tcx: &ty::ctxt,
- param_ty: ty::ParamTy,
- ast_bounds: &'a [ast::TyParamBound],
- where_clause: &'a ast::WhereClause)
- -> Vec<&'a ast::TyParamBound> {
- let mut result = Vec::new();
-
- for ast_bound in ast_bounds.iter() {
- result.push(ast_bound);
- }
-
- for predicate in where_clause.predicates.iter() {
- match predicate {
- &ast::WherePredicate::BoundPredicate(ref bound_pred) => {
- let predicate_param_id =
- tcx.def_map
- .borrow()
- .get(&bound_pred.id)
- .expect("merge_param_bounds(): resolve didn't resolve the \
- type parameter identifier in a `where` clause")
- .def_id();
- if param_ty.def_id != predicate_param_id {
- continue
- }
- for bound in bound_pred.bounds.iter() {
- result.push(bound);
- }
- }
- &ast::WherePredicate::EqPredicate(_) => panic!("not implemented")
- }
- }
-
- result
-}
-
pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
decl: &ast::FnDecl,
def_id: ast::DefId,
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![feature(default_type_params, globs, import_shadowing, macro_rules, phase, quote)]
+#![feature(default_type_params, globs, macro_rules, phase, quote)]
#![feature(slicing_syntax, unsafe_destructor)]
#![feature(rustc_diagnostic_macros)]
#![feature(unboxed_closures)]
pub use rustc::util;
use middle::def;
-use middle::resolve;
use middle::infer;
use middle::subst;
use middle::subst::VecPerParamSpace;
struct CrateCtxt<'a, 'tcx: 'a> {
// A mapping from method call sites to traits that have that method.
- trait_map: resolve::TraitMap,
+ trait_map: ty::TraitMap,
tcx: &'a ty::ctxt<'tcx>
}
}
}
-pub fn check_crate(tcx: &ty::ctxt, trait_map: resolve::TraitMap) {
+pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
let time_passes = tcx.sess.time_passes();
let ccx = CrateCtxt {
trait_map: trait_map,
};
let mut tmp = Vec::new();
for child in m.items.iter_mut() {
- let inner = match child.inner {
- ModuleItem(ref mut m) => m,
+ match child.inner {
+ ModuleItem(..) => {}
_ => continue,
- };
+ }
let prim = match PrimitiveType::find(child.attrs.as_slice()) {
Some(prim) => prim,
None => continue,
};
primitives.push(prim);
- let mut i = Item {
+ tmp.push(Item {
source: Span::empty(),
name: Some(prim.to_url_str().to_string()),
- attrs: Vec::new(),
- visibility: None,
+ attrs: child.attrs.clone(),
+ visibility: Some(ast::Public),
stability: None,
def_id: ast_util::local_def(prim.to_node_id()),
inner: PrimitiveItem(prim),
- };
- // Push one copy to get indexed for the whole crate, and push a
- // another copy in the proper location which will actually get
- // documented. The first copy will also serve as a redirect to
- // the other copy.
- tmp.push(i.clone());
- i.visibility = Some(ast::Public);
- i.attrs = child.attrs.clone();
- inner.items.push(i);
-
+ });
}
m.items.extend(tmp.into_iter());
}
#[deriving(Clone, Encodable, Decodable, PartialEq)]
pub struct WherePredicate {
- pub name: String,
+ pub ty: Type,
pub bounds: Vec<TyParamBound>
}
match *self {
ast::WherePredicate::BoundPredicate(ref wbp) => {
WherePredicate {
- name: wbp.ident.clean(cx),
+ ty: wbp.bounded_ty.clean(cx),
bounds: wbp.bounds.clean(cx)
}
}
- ast::WherePredicate::EqPredicate(_) => {
+ // FIXME(#20048)
+ _ => {
unimplemented!();
}
}
try!(f.write(", ".as_bytes()));
}
let bounds = pred.bounds.as_slice();
- try!(write!(f, "{}: {}", pred.name, TyParamBounds(bounds)));
+ try!(write!(f, "{}: {}", pred.ty, TyParamBounds(bounds)));
}
Ok(())
}
pub use self::ExternalLocation::*;
use std::cell::RefCell;
-use std::collections::hash_map::{Occupied, Vacant};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{HashMap, HashSet};
use std::default::Default;
use std::fmt;
use std::cell::RefCell;
use std::collections::HashMap;
-use std::collections::hash_map::{Occupied, Vacant};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::io::File;
use std::io;
use std::rc::Rc;
usage(args[0].as_slice());
return 0;
} else if matches.opt_present("version") {
- match rustc_driver::version("rustdoc", &matches) {
- Some(err) => {
- println!("{}", err);
- return 1
- },
- None => return 0
- }
+ rustc_driver::version("rustdoc", &matches);
+ return 0;
}
if matches.opt_strs("passes") == ["list"] {
impl ::Decoder<DecoderError> for Decoder {
fn read_nil(&mut self) -> DecodeResult<()> {
- debug!("read_nil");
expect!(self.pop(), Null)
}
fn read_f32(&mut self) -> DecodeResult<f32> { self.read_f64().map(|x| x as f32) }
fn read_f64(&mut self) -> DecodeResult<f64> {
- debug!("read_f64");
match self.pop() {
Json::I64(f) => Ok(f as f64),
Json::U64(f) => Ok(f as f64),
}
fn read_bool(&mut self) -> DecodeResult<bool> {
- debug!("read_bool");
expect!(self.pop(), Boolean)
}
}
fn read_str(&mut self) -> DecodeResult<string::String> {
- debug!("read_str");
expect!(self.pop(), String)
}
- fn read_enum<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T> where
+ fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_enum({})", name);
f(self)
}
mut f: F) -> DecodeResult<T>
where F: FnMut(&mut Decoder, uint) -> DecodeResult<T>,
{
- debug!("read_enum_variant(names={})", names);
let name = match self.pop() {
Json::String(s) => s,
Json::Object(mut o) => {
f(self, idx)
}
- fn read_enum_variant_arg<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
+ fn read_enum_variant_arg<T, F>(&mut self, _idx: uint, f: F) -> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_enum_variant_arg(idx={})", idx);
f(self)
}
fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T> where
F: FnMut(&mut Decoder, uint) -> DecodeResult<T>,
{
- debug!("read_enum_struct_variant(names={})", names);
self.read_enum_variant(names, f)
}
fn read_enum_struct_variant_field<T, F>(&mut self,
- name: &str,
+ _name: &str,
idx: uint,
f: F)
-> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_enum_struct_variant_field(name={}, idx={})", name, idx);
self.read_enum_variant_arg(idx, f)
}
- fn read_struct<T, F>(&mut self, name: &str, len: uint, f: F) -> DecodeResult<T> where
+ fn read_struct<T, F>(&mut self, _name: &str, _len: uint, f: F) -> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_struct(name={}, len={})", name, len);
let value = try!(f(self));
self.pop();
Ok(value)
fn read_struct_field<T, F>(&mut self,
name: &str,
- idx: uint,
+ _idx: uint,
f: F)
-> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_struct_field(name={}, idx={})", name, idx);
let mut obj = try!(expect!(self.pop(), Object));
let value = match obj.remove(&name.to_string()) {
fn read_tuple<T, F>(&mut self, tuple_len: uint, f: F) -> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_tuple()");
self.read_seq(move |d, len| {
if len == tuple_len {
f(d)
fn read_tuple_arg<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_tuple_arg(idx={})", idx);
self.read_seq_elt(idx, f)
}
fn read_tuple_struct<T, F>(&mut self,
- name: &str,
+ _name: &str,
len: uint,
f: F)
-> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_tuple_struct(name={})", name);
self.read_tuple(len, f)
}
-> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_tuple_struct_arg(idx={})", idx);
self.read_tuple_arg(idx, f)
}
fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where
F: FnMut(&mut Decoder, bool) -> DecodeResult<T>,
{
- debug!("read_option()");
match self.pop() {
Json::Null => f(self, false),
value => { self.stack.push(value); f(self, true) }
fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where
F: FnOnce(&mut Decoder, uint) -> DecodeResult<T>,
{
- debug!("read_seq()");
let array = try!(expect!(self.pop(), Array));
let len = array.len();
for v in array.into_iter().rev() {
f(self, len)
}
- fn read_seq_elt<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
+ fn read_seq_elt<T, F>(&mut self, _idx: uint, f: F) -> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_seq_elt(idx={})", idx);
f(self)
}
fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T> where
F: FnOnce(&mut Decoder, uint) -> DecodeResult<T>,
{
- debug!("read_map()");
let obj = try!(expect!(self.pop(), Object));
let len = obj.len();
for (key, value) in obj.into_iter() {
f(self, len)
}
- fn read_map_elt_key<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
+ fn read_map_elt_key<T, F>(&mut self, _idx: uint, f: F) -> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_map_elt_key(idx={})", idx);
f(self)
}
- fn read_map_elt_val<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
+ fn read_map_elt_val<T, F>(&mut self, _idx: uint, f: F) -> DecodeResult<T> where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- debug!("read_map_elt_val(idx={})", idx);
f(self)
}
use super::ParserError::*;
use super::DecoderError::*;
use super::JsonEvent::*;
- use super::ParserState::*;
use super::StackElement::*;
- use super::InternalStackElement::*;
use super::{PrettyEncoder, Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser,
StackElement, Stack, Encoder, Decoder};
use std::{i64, u64, f32, f64, io};
}
fn with_str_writer<F>(f: F) -> string::String where F: FnOnce(&mut io::Writer){
- use std::str;
-
let mut m = Vec::new();
f(&mut m as &mut io::Writer);
string::String::from_utf8(m).unwrap()
fn test_write_char() {
check_encoder_for_simple!('a', "\"a\"");
check_encoder_for_simple!('\t', "\"\\t\"");
- check_encoder_for_simple!('\u00a0', "\"\u00a0\"");
- check_encoder_for_simple!('\uabcd', "\"\uabcd\"");
- check_encoder_for_simple!('\U0010ffff', "\"\U0010ffff\"");
+ check_encoder_for_simple!('\u{00a0}', "\"\u{00a0}\"");
+ check_encoder_for_simple!('\u{abcd}', "\"\u{abcd}\"");
+ check_encoder_for_simple!('\u{10ffff}', "\"\u{10ffff}\"");
}
#[test]
use prelude::*;
use super::*;
use char::from_u32;
- use str::StrPrelude;
macro_rules! v2ascii {
( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
/// ```{.rust}
/// bitflags! {
/// flags Flags: u32 {
-/// const FLAG_A = 0x00000001,
-/// const FLAG_B = 0x00000010,
-/// const FLAG_C = 0x00000100,
+/// const FLAG_A = 0b00000001,
+/// const FLAG_B = 0b00000010,
+/// const FLAG_C = 0b00000100,
/// const FLAG_ABC = FLAG_A.bits
/// | FLAG_B.bits
/// | FLAG_C.bits,
///
/// bitflags! {
/// flags Flags: u32 {
-/// const FLAG_A = 0x00000001,
-/// const FLAG_B = 0x00000010,
+/// const FLAG_A = 0b00000001,
+/// const FLAG_B = 0b00000010,
/// }
/// }
///
#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
- use kinds::Copy;
use hash;
use option::Option::{Some, None};
use ops::{BitOr, BitAnd, BitXor, Sub, Not};
#[doc = "> "]
#[doc = "> - Richard Feynman"]
flags Flags: u32 {
- const FlagA = 0x00000001,
+ const FlagA = 0b00000001,
#[doc = "<pcwalton> macros are way better at generating code than trans is"]
- const FlagB = 0x00000010,
- const FlagC = 0x00000100,
+ const FlagB = 0b00000010,
+ const FlagC = 0b00000100,
#[doc = "* cmr bed"]
#[doc = "* strcat table"]
#[doc = "<strcat> wait what?"]
#[test]
fn test_bits(){
- assert_eq!(Flags::empty().bits(), 0x00000000);
- assert_eq!(FlagA.bits(), 0x00000001);
- assert_eq!(FlagABC.bits(), 0x00000111);
+ assert_eq!(Flags::empty().bits(), 0b00000000);
+ assert_eq!(FlagA.bits(), 0b00000001);
+ assert_eq!(FlagABC.bits(), 0b00000111);
- assert_eq!(AnotherSetOfFlags::empty().bits(), 0x00);
+ assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00);
assert_eq!(AnotherFlag.bits(), !0_i8);
}
#[test]
fn test_from_bits() {
assert!(Flags::from_bits(0) == Some(Flags::empty()));
- assert!(Flags::from_bits(0x1) == Some(FlagA));
- assert!(Flags::from_bits(0x10) == Some(FlagB));
- assert!(Flags::from_bits(0x11) == Some(FlagA | FlagB));
- assert!(Flags::from_bits(0x1000) == None);
+ assert!(Flags::from_bits(0b1) == Some(FlagA));
+ assert!(Flags::from_bits(0b10) == Some(FlagB));
+ assert!(Flags::from_bits(0b11) == Some(FlagA | FlagB));
+ assert!(Flags::from_bits(0b1000) == None);
assert!(AnotherSetOfFlags::from_bits(!0_i8) == Some(AnotherFlag));
}
#[test]
fn test_from_bits_truncate() {
assert!(Flags::from_bits_truncate(0) == Flags::empty());
- assert!(Flags::from_bits_truncate(0x1) == FlagA);
- assert!(Flags::from_bits_truncate(0x10) == FlagB);
- assert!(Flags::from_bits_truncate(0x11) == (FlagA | FlagB));
- assert!(Flags::from_bits_truncate(0x1000) == Flags::empty());
- assert!(Flags::from_bits_truncate(0x1001) == FlagA);
+ assert!(Flags::from_bits_truncate(0b1) == FlagA);
+ assert!(Flags::from_bits_truncate(0b10) == FlagB);
+ assert!(Flags::from_bits_truncate(0b11) == (FlagA | FlagB));
+ assert!(Flags::from_bits_truncate(0b1000) == Flags::empty());
+ assert!(Flags::from_bits_truncate(0b1001) == FlagA);
assert!(AnotherSetOfFlags::from_bits_truncate(0_i8) == AnotherSetOfFlags::empty());
}
--- /dev/null
+// Copyright 2013 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.
+
+//! The boolean type
+
+#![doc(primitive = "bool")]
+#![stable]
+
//! }
//! ```
-use string::String;
-use hash;
+use core::prelude::*;
+use libc;
+
use fmt;
+use hash;
use kinds::marker;
use mem;
-use core::prelude::*;
-
use ptr;
-use raw::Slice;
-use slice;
+use slice::{mod, ImmutableIntSlice};
use str;
-use libc;
+use string::String;
+
/// The representation of a C String.
///
#[inline]
pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
unsafe {
- mem::transmute(Slice { data: self.buf, len: self.len() + 1 })
+ slice::from_raw_buf(&self.buf, self.len() + 1).as_unsigned()
}
}
#[inline]
pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] {
unsafe {
- mem::transmute(Slice { data: self.buf, len: self.len() })
+ slice::from_raw_buf(&self.buf, self.len()).as_unsigned()
}
}
//
// ignore-lexer-test FIXME #15883
-pub use self::Entry::*;
+use self::Entry::*;
use self::SearchResult::*;
use self::VacantEntryState::*;
use result::Result;
use result::Result::{Ok, Err};
-use super::table;
use super::table::{
+ mod,
Bucket,
- Empty,
EmptyBucket,
- Full,
FullBucket,
FullBucketImm,
FullBucketMut,
RawTable,
SafeHash
};
+use super::table::BucketState::{
+ Empty,
+ Full,
+};
const INITIAL_LOG2_CAP: uint = 5;
pub const INITIAL_CAPACITY: uint = 1 << INITIAL_LOG2_CAP; // 2^5
assert!(probe.index() != idx_end);
let full_bucket = match probe.peek() {
- table::Empty(bucket) => {
+ Empty(bucket) => {
// Found a hole!
let b = bucket.put(old_hash, old_key, old_val);
// Now that it's stolen, just read the value's pointer
.into_mut_refs()
.1;
},
- table::Full(bucket) => bucket
+ Full(bucket) => bucket
};
let probe_ib = full_bucket.index() - full_bucket.distance();
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn is_empty(&self) -> bool { self.len() == 0 }
+ /// Clears the map, returning all key-value pairs as an iterator. Keeps the
+ /// allocated memory for reuse.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::collections::HashMap;
+ ///
+ /// let mut a = HashMap::new();
+ /// a.insert(1u, "a");
+ /// a.insert(2u, "b");
+ ///
+ /// for (k, v) in a.drain().take(1) {
+ /// assert!(k == 1 || k == 2);
+ /// assert!(v == "a" || v == "b");
+ /// }
+ ///
+ /// assert!(a.is_empty());
+ /// ```
+ #[inline]
+ #[unstable = "matches collection reform specification, waiting for dust to settle"]
+ pub fn drain(&mut self) -> Drain<K, V> {
+ fn last_two<A, B, C>((_, b, c): (A, B, C)) -> (B, C) { (b, c) }
+
+ Drain {
+ inner: self.table.drain().map(last_two),
+ }
+ }
+
/// Clears the map, removing all key-value pairs. Keeps the allocated memory
/// for reuse.
///
/// assert!(a.is_empty());
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
+ #[inline]
pub fn clear(&mut self) {
- let cap = self.table.capacity();
- let mut buckets = Bucket::first(&mut self.table);
-
- while buckets.index() != cap {
- buckets = match buckets.peek() {
- Empty(b) => b.next(),
- Full(full) => full.take().0.next(),
- };
- }
+ self.drain();
}
/// Deprecated: Renamed to `get`.
inner: Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>
}
+/// HashMap drain iterator
+pub struct Drain<'a, K: 'a, V: 'a> {
+ inner: iter::Map<
+ (SafeHash, K, V),
+ (K, V),
+ table::Drain<'a, K, V>,
+ fn((SafeHash, K, V)) -> (K, V),
+ >
+}
+
/// A view into a single occupied location in a HashMap
pub struct OccupiedEntry<'a, K:'a, V:'a> {
elem: FullBucket<K, V, &'a mut RawTable<K, V>>,
#[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() }
}
+impl<'a, K: 'a, V: 'a> Iterator<(K, V)> for Drain<'a, K, V> {
+ #[inline]
+ fn next(&mut self) -> Option<(K, V)> {
+ self.inner.next()
+ }
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ self.inner.size_hint()
+ }
+}
+
impl<'a, K, V> OccupiedEntry<'a, K, V> {
/// Gets a reference to the value in the entry
pub fn get(&self) -> &V {
use prelude::*;
use super::HashMap;
- use super::{Occupied, Vacant};
+ use super::Entry::{Occupied, Vacant};
use cmp::Equiv;
use hash;
- use iter::{Iterator,range_inclusive,range_step_inclusive};
+ use iter::{range_inclusive, range_step_inclusive};
use cell::RefCell;
use rand::{weak_rng, Rng};
use fmt::Show;
use fmt;
use hash::{Hash, Hasher, RandomSipHasher};
-use iter::{Iterator, IteratorExt, FromIterator, Map, FilterMap, Chain, Repeat, Zip, Extend, repeat};
+use iter::{Iterator, IteratorExt, FromIterator, Map, Chain, Extend};
use option::Option::{Some, None, mod};
use result::Result::{Ok, Err};
-use super::map::{HashMap, MoveEntries, Keys, INITIAL_CAPACITY};
+use super::map::{mod, HashMap, MoveEntries, Keys, INITIAL_CAPACITY};
// FIXME(conventions): implement BitOr, BitAnd, BitXor, and Sub
/// }
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
- pub fn iter<'a>(&'a self) -> SetItems<'a, T> {
- SetItems { iter: self.map.keys() }
+ pub fn iter<'a>(&'a self) -> Iter<'a, T> {
+ Iter { iter: self.map.keys() }
}
/// Creates a consuming iterator, that is, one that moves each value out
/// }
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
- pub fn into_iter(self) -> SetMoveItems<T> {
+ pub fn into_iter(self) -> IntoIter<T> {
fn first<A, B>((a, _): (A, B)) -> A { a }
- SetMoveItems { iter: self.map.into_iter().map(first) }
+ IntoIter { iter: self.map.into_iter().map(first) }
}
/// Visit the values representing the difference.
/// assert_eq!(diff, [4i].iter().map(|&x| x).collect());
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
- pub fn difference<'a>(&'a self, other: &'a HashSet<T, H>) -> SetAlgebraItems<'a, T, H> {
- fn filter<'a, T, S, H>((other, elt): (&HashSet<T, H>, &'a T)) -> Option<&'a T> where
- T: Eq + Hash<S>, H: Hasher<S>
- {
- if !other.contains(elt) { Some(elt) } else { None }
+ pub fn difference<'a>(&'a self, other: &'a HashSet<T, H>) -> Difference<'a, T, H> {
+ Difference {
+ iter: self.iter(),
+ other: other,
}
-
- SetAlgebraItems { iter: repeat(other).zip(self.iter()).filter_map(filter) }
}
/// Visit the values representing the symmetric difference.
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, H>)
- -> SymDifferenceItems<'a, T, H> {
- SymDifferenceItems { iter: self.difference(other).chain(other.difference(self)) }
+ -> SymmetricDifference<'a, T, H> {
+ SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) }
}
/// Visit the values representing the intersection.
/// assert_eq!(diff, [2i, 3].iter().map(|&x| x).collect());
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
- pub fn intersection<'a>(&'a self, other: &'a HashSet<T, H>) -> SetAlgebraItems<'a, T, H> {
- fn filter<'a, T, S, H>((other, elt): (&HashSet<T, H>, &'a T)) -> Option<&'a T> where
- T: Eq + Hash<S>, H: Hasher<S>
- {
- if other.contains(elt) { Some(elt) } else { None }
+ pub fn intersection<'a>(&'a self, other: &'a HashSet<T, H>) -> Intersection<'a, T, H> {
+ Intersection {
+ iter: self.iter(),
+ other: other,
}
-
- SetAlgebraItems { iter: repeat(other).zip(self.iter()).filter_map(filter) }
}
/// Visit the values representing the union.
/// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect());
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
- pub fn union<'a>(&'a self, other: &'a HashSet<T, H>) -> UnionItems<'a, T, H> {
- UnionItems { iter: self.iter().chain(other.difference(self)) }
+ pub fn union<'a>(&'a self, other: &'a HashSet<T, H>) -> Union<'a, T, H> {
+ Union { iter: self.iter().chain(other.difference(self)) }
}
/// Return the number of elements in the set
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn is_empty(&self) -> bool { self.map.len() == 0 }
+ /// Clears the set, returning all elements in an iterator.
+ #[inline]
+ #[unstable = "matches collection reform specification, waiting for dust to settle"]
+ pub fn drain(&mut self) -> Drain<T> {
+ fn first<A, B>((a, _): (A, B)) -> A { a }
+ Drain { iter: self.map.drain().map(first) }
+ }
+
/// Clears the set, removing all values.
///
/// # Example
}
/// HashSet iterator
-pub struct SetItems<'a, K: 'a> {
+pub struct Iter<'a, K: 'a> {
iter: Keys<'a, K, ()>
}
/// HashSet move iterator
-pub struct SetMoveItems<K> {
+pub struct IntoIter<K> {
iter: Map<(K, ()), K, MoveEntries<K, ()>, fn((K, ())) -> K>
}
-// `Repeat` is used to feed the filter closure an explicit capture
-// of a reference to the other set
-/// Set operations iterator, used directly for intersection and difference
-pub struct SetAlgebraItems<'a, T: 'a, H: 'a> {
- iter: FilterMap<
- (&'a HashSet<T, H>, &'a T),
- &'a T,
- Zip<Repeat<&'a HashSet<T, H>>, SetItems<'a, T>>,
- for<'b> fn((&HashSet<T, H>, &'b T)) -> Option<&'b T>,
- >
+/// HashSet drain iterator
+pub struct Drain<'a, K: 'a> {
+ iter: Map<(K, ()), K, map::Drain<'a, K, ()>, fn((K, ())) -> K>,
+}
+
+/// Intersection iterator
+pub struct Intersection<'a, T: 'a, H: 'a> {
+ // iterator of the first set
+ iter: Iter<'a, T>,
+ // the second set
+ other: &'a HashSet<T, H>,
+}
+
+/// Difference iterator
+pub struct Difference<'a, T: 'a, H: 'a> {
+ // iterator of the first set
+ iter: Iter<'a, T>,
+ // the second set
+ other: &'a HashSet<T, H>,
}
/// Symmetric difference iterator.
-pub struct SymDifferenceItems<'a, T: 'a, H: 'a> {
- iter: Chain<SetAlgebraItems<'a, T, H>, SetAlgebraItems<'a, T, H>>
+pub struct SymmetricDifference<'a, T: 'a, H: 'a> {
+ iter: Chain<Difference<'a, T, H>, Difference<'a, T, H>>
}
/// Set union iterator.
-pub struct UnionItems<'a, T: 'a, H: 'a> {
- iter: Chain<SetItems<'a, T>, SetAlgebraItems<'a, T, H>>
+pub struct Union<'a, T: 'a, H: 'a> {
+ iter: Chain<Iter<'a, T>, Difference<'a, T, H>>
}
-impl<'a, K> Iterator<&'a K> for SetItems<'a, K> {
+impl<'a, K> Iterator<&'a K> for Iter<'a, K> {
fn next(&mut self) -> Option<&'a K> { self.iter.next() }
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
}
-impl<K> Iterator<K> for SetMoveItems<K> {
+impl<K> Iterator<K> for IntoIter<K> {
fn next(&mut self) -> Option<K> { self.iter.next() }
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
}
-impl<'a, T, H> Iterator<&'a T> for SetAlgebraItems<'a, T, H> {
- fn next(&mut self) -> Option<&'a T> { self.iter.next() }
+impl<'a, K: 'a> Iterator<K> for Drain<'a, K> {
+ fn next(&mut self) -> Option<K> { self.iter.next() }
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
}
-impl<'a, T, H> Iterator<&'a T> for SymDifferenceItems<'a, T, H> {
+impl<'a, T, S, H> Iterator<&'a T> for Intersection<'a, T, H>
+ where T: Eq + Hash<S>, H: Hasher<S>
+{
+ fn next(&mut self) -> Option<&'a T> {
+ loop {
+ match self.iter.next() {
+ None => return None,
+ Some(elt) => if self.other.contains(elt) {
+ return Some(elt)
+ },
+ }
+ }
+ }
+
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper)
+ }
+}
+
+impl<'a, T, S, H> Iterator<&'a T> for Difference<'a, T, H>
+ where T: Eq + Hash<S>, H: Hasher<S>
+{
+ fn next(&mut self) -> Option<&'a T> {
+ loop {
+ match self.iter.next() {
+ None => return None,
+ Some(elt) => if !self.other.contains(elt) {
+ return Some(elt)
+ },
+ }
+ }
+ }
+
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper)
+ }
+}
+
+impl<'a, T, S, H> Iterator<&'a T> for SymmetricDifference<'a, T, H>
+ where T: Eq + Hash<S>, H: Hasher<S>
+{
fn next(&mut self) -> Option<&'a T> { self.iter.next() }
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
}
-impl<'a, T, H> Iterator<&'a T> for UnionItems<'a, T, H> {
+impl<'a, T, S, H> Iterator<&'a T> for Union<'a, T, H>
+ where T: Eq + Hash<S>, H: Hasher<S>
+{
fn next(&mut self) -> Option<&'a T> { self.iter.next() }
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
}
use prelude::*;
use super::HashSet;
- use slice::PartialEqSliceExt;
#[test]
fn test_disjoint() {
assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
assert_eq!(format!("{}", empty), "{}");
}
+
+ #[test]
+ fn test_trivial_drain() {
+ let mut s = HashSet::<int>::new();
+ for _ in s.drain() {}
+ assert!(s.is_empty());
+ drop(s);
+
+ let mut s = HashSet::<int>::new();
+ drop(s.drain());
+ assert!(s.is_empty());
+ }
+
+ #[test]
+ fn test_drain() {
+ let mut s: HashSet<int> = range(1, 100).collect();
+
+ // try this a bunch of times to make sure we don't screw up internal state.
+ for _ in range(0i, 20) {
+ assert_eq!(s.len(), 99);
+
+ {
+ let mut last_i = 0;
+ let mut d = s.drain();
+ for (i, x) in d.by_ref().take(50).enumerate() {
+ last_i = i;
+ assert!(x != 0);
+ }
+ assert_eq!(last_i, 49);
+ }
+
+ for _ in s.iter() { panic!("s should be empty!"); }
+
+ // reset to try again.
+ s.extend(range(1, 100));
+ }
+ }
}
//
// ignore-lexer-test FIXME #15883
-pub use self::BucketState::*;
+use self::BucketState::*;
use clone::Clone;
use cmp;
}
}
+ pub fn drain(&mut self) -> Drain<K, V> {
+ let RawBuckets { raw, hashes_end, .. } = self.raw_buckets();
+ // Replace the marker regardless of lifetime bounds on parameters.
+ Drain {
+ iter: RawBuckets {
+ raw: raw,
+ hashes_end: hashes_end,
+ marker: marker::ContravariantLifetime::<'static>,
+ },
+ table: self,
+ }
+ }
+
/// Returns an iterator that copies out each entry. Used while the table
/// is being dropped.
unsafe fn rev_move_buckets(&mut self) -> RevMoveBuckets<K, V> {
iter: RawBuckets<'static, K, V>
}
+/// Iterator over the entries in a table, clearing the table.
+pub struct Drain<'a, K: 'a, V: 'a> {
+ table: &'a mut RawTable<K, V>,
+ iter: RawBuckets<'static, K, V>,
+}
+
impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> {
fn next(&mut self) -> Option<(&'a K, &'a V)> {
self.iter.next().map(|bucket| {
}
}
+impl<'a, K: 'a, V: 'a> Iterator<(SafeHash, K, V)> for Drain<'a, K, V> {
+ #[inline]
+ fn next(&mut self) -> Option<(SafeHash, K, V)> {
+ self.iter.next().map(|bucket| {
+ self.table.size -= 1;
+ unsafe {
+ (
+ SafeHash {
+ hash: ptr::replace(bucket.hash, EMPTY_BUCKET),
+ },
+ ptr::read(bucket.key as *const K),
+ ptr::read(bucket.val as *const V)
+ )
+ }
+ })
+ }
+
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let size = self.table.size();
+ (size, Some(size))
+ }
+}
+
+#[unsafe_destructor]
+impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> {
+ fn drop(&mut self) {
+ for _ in *self {}
+ }
+}
+
impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
fn clone(&self) -> RawTable<K, V> {
unsafe {
}
}
-#[unstable]
+#[stable]
impl<T: Send> Clone for Sender<T> {
fn clone(&self) -> Sender<T> {
let (packet, sleeper, guard) = match *unsafe { self.inner() } {
}
}
-#[unstable]
+#[stable]
impl<T: Send> Clone for SyncSender<T> {
fn clone(&self) -> SyncSender<T> {
unsafe { (*self.inner.get()).clone_chan(); }
#![experimental]
#![allow(missing_docs)]
-use clone::Clone;
-use c_str::ToCStr;
-use iter::IteratorExt;
+use prelude::*;
use mem;
-use ops::*;
-use option::*;
-use option::Option::{None, Some};
use os;
-use path::{Path,GenericPath};
-use result::*;
-use result::Result::{Err, Ok};
-use slice::{AsSlice,SliceExt};
use str;
-use string::String;
-use vec::Vec;
#[allow(missing_copy_implementations)]
pub struct DynamicLibrary {
target_os = "freebsd",
target_os = "dragonfly"))]
pub mod dl {
- pub use self::Rtld::*;
+ use self::Rtld::*;
- use c_str::{CString, ToCStr};
+ use prelude::*;
+ use c_str::CString;
use libc;
- use ops::FnOnce;
use ptr;
- use result::*;
- use result::Result::{Err, Ok};
- use string::String;
pub unsafe fn open_external<T: ToCStr>(filename: T) -> *mut u8 {
filename.with_c_str(|raw_name| {
use super::super::{IoResult, EndOfFile};
use super::super::mem::MemReader;
use self::test::Bencher;
- use str::StrPrelude;
/// A type, free to create, primarily intended for benchmarking creation of
/// wrappers that, just for construction, don't need a Reader/Writer that
}
}
+#[stable]
impl Clone for ChanWriter {
fn clone(&self) -> ChanWriter {
ChanWriter { tx: self.tx.clone() }
use io;
use str;
use io::fs::*;
- use path::Path;
- use io;
- use ops::Drop;
- use str::StrPrelude;
macro_rules! check { ($e:expr) => (
match $e {
#[cfg(test)]
mod test {
- extern crate test;
+ extern crate "test" as test_crate;
use prelude::*;
use super::*;
use io::*;
use io;
- use self::test::Bencher;
- use str::StrPrelude;
+ use self::test_crate::Bencher;
#[test]
fn test_vec_writer() {
inner: Arc<Mutex<BufferedReader<StdReader>>>,
}
-/// A guard for exlusive access to `StdinReader`'s internal `BufferedReader`.
+/// A guard for exclusive access to `StdinReader`'s internal `BufferedReader`.
pub struct StdinReaderGuard<'a> {
inner: MutexGuard<'a, BufferedReader<StdReader>>,
}
/// A wrapper for a path to temporary directory implementing automatic
/// scope-based deletion.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::TempDir;
+///
+/// {
+/// // create a temporary directory
+/// let tmpdir = match TempDir::new("mysuffix") {
+/// Ok(dir) => dir,
+/// Err(e) => panic!("couldn't create temporary directory: {}", e)
+/// };
+///
+/// // get the path of the temporary directory without affecting the wrapper
+/// let tmppath = tmpdir.path();
+///
+/// println!("The path of temporary directory is {}", tmppath.display());
+///
+/// // the temporary directory is automatically removed when tmpdir goes
+/// // out of scope at the end of the block
+/// }
+/// {
+/// // create a temporary directory, this time using a custom path
+/// let tmpdir = match TempDir::new_in(&Path::new("/tmp/best/custom/path"), "mysuffix") {
+/// Ok(dir) => dir,
+/// Err(e) => panic!("couldn't create temporary directory: {}", e)
+/// };
+///
+/// // get the path of the temporary directory and disable automatic deletion in the wrapper
+/// let tmppath = tmpdir.into_inner();
+///
+/// println!("The path of the not-so-temporary directory is {}", tmppath.display());
+///
+/// // the temporary directory is not removed here
+/// // because the directory is detached from the wrapper
+/// }
+/// {
+/// // create a temporary directory
+/// let tmpdir = match TempDir::new("mysuffix") {
+/// Ok(dir) => dir,
+/// Err(e) => panic!("couldn't create temporary directory: {}", e)
+/// };
+///
+/// // close the temporary directory manually and check the result
+/// match tmpdir.close() {
+/// Ok(_) => println!("success!"),
+/// Err(e) => panic!("couldn't remove temporary directory: {}", e)
+/// };
+/// }
+/// ```
pub struct TempDir {
path: Option<Path>,
disarmed: bool
#[cfg(test)]
mod test {
- use super::*;
- use time::Duration;
- use task::spawn;
use prelude::*;
+ use super::Timer;
+ use time::Duration;
+
#[test]
fn test_io_timer_sleep_simple() {
let mut timer = Timer::new().unwrap();
#![allow(unknown_features)]
#![feature(macro_rules, globs, linkage, thread_local, asm)]
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
-#![feature(import_shadowing, slicing_syntax, tuple_indexing)]
-#![feature(unboxed_closures)]
+#![feature(slicing_syntax, unboxed_closures)]
// Don't link to std. We are std.
#![no_std]
// NB: These reexports are in the order they should be listed in rustdoc
pub use core::any;
-pub use core::bool;
pub use core::borrow;
pub use core::cell;
pub use core::clone;
pub use core::ptr;
pub use core::raw;
pub use core::simd;
-pub use core::tuple;
-// FIXME #15320: primitive documentation needs top-level modules, this
-// should be `std::tuple::unit`.
-pub use core::unit;
pub use core::result;
pub use core::option;
-pub use alloc::boxed;
+#[cfg(not(test))] pub use alloc::boxed;
pub use alloc::rc;
pub use core_collections::slice;
pub mod rt;
mod failure;
+// Documentation for primitive types
+
+mod bool;
+mod unit;
+mod tuple;
+
// A curious inner-module that's not exported that contains the binding
// 'std' so that macro-expanded references to std::error and such
// can be resolved within libstd.
use libc::c_int;
use num::{Float, FloatMath};
use num::strconv;
+use num::strconv::ExponentFormat::{ExpNone, ExpDec};
+use num::strconv::SignificantDigits::{DigAll, DigMax, DigExact};
+use num::strconv::SignFormat::SignNeg;
pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE};
pub use core::f32::{MIN_POS_VALUE, MAX_VALUE, MIN_EXP, MAX_EXP, MIN_10_EXP};
#[experimental = "may be removed or relocated"]
pub fn to_string(num: f32) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 10u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
+ num, 10u, true, SignNeg, DigAll, ExpNone, false);
r
}
#[experimental = "may be removed or relocated"]
pub fn to_str_hex(num: f32) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 16u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
+ num, 16u, true, SignNeg, DigAll, ExpNone, false);
r
}
#[inline]
#[experimental = "may be removed or relocated"]
pub fn to_str_radix_special(num: f32, rdx: uint) -> (String, bool) {
- strconv::float_to_str_common(num, rdx, true,
- strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false)
+ strconv::float_to_str_common(num, rdx, true, SignNeg, DigAll, ExpNone, false)
}
/// Converts a float to a string with exactly the number of
#[experimental = "may be removed or relocated"]
pub fn to_str_exact(num: f32, dig: uint) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpNone, false);
+ num, 10u, true, SignNeg, DigExact(dig), ExpNone, false);
r
}
#[experimental = "may be removed or relocated"]
pub fn to_str_digits(num: f32, dig: uint) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpNone, false);
+ num, 10u, true, SignNeg, DigMax(dig), ExpNone, false);
r
}
#[experimental = "may be removed or relocated"]
pub fn to_str_exp_exact(num: f32, dig: uint, upper: bool) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpDec, upper);
+ num, 10u, true, SignNeg, DigExact(dig), ExpDec, upper);
r
}
#[experimental = "may be removed or relocated"]
pub fn to_str_exp_digits(num: f32, dig: uint, upper: bool) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpDec, upper);
+ num, 10u, true, SignNeg, DigMax(dig), ExpDec, upper);
r
}
mod tests {
use f32::*;
use num::*;
- use num;
#[test]
fn test_min_nan() {
}
#[test]
- fn test_num() {
- num::test_num(10f32, 2f32);
+ fn test_num_f32() {
+ test_num(10f32, 2f32);
}
#[test]
use libc::c_int;
use num::{Float, FloatMath};
use num::strconv;
+use num::strconv::ExponentFormat::{ExpNone, ExpDec};
+use num::strconv::SignificantDigits::{DigAll, DigMax, DigExact};
+use num::strconv::SignFormat::SignNeg;
pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE};
pub use core::f64::{MIN_POS_VALUE, MAX_VALUE, MIN_EXP, MAX_EXP, MIN_10_EXP};
#[experimental = "may be removed or relocated"]
pub fn to_string(num: f64) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 10u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
+ num, 10u, true, SignNeg, DigAll, ExpNone, false);
r
}
#[experimental = "may be removed or relocated"]
pub fn to_str_hex(num: f64) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 16u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
+ num, 16u, true, SignNeg, DigAll, ExpNone, false);
r
}
#[inline]
#[experimental = "may be removed or relocated"]
pub fn to_str_radix_special(num: f64, rdx: uint) -> (String, bool) {
- strconv::float_to_str_common(num, rdx, true,
- strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false)
+ strconv::float_to_str_common(num, rdx, true, SignNeg, DigAll, ExpNone, false)
}
/// Converts a float to a string with exactly the number of
#[experimental = "may be removed or relocated"]
pub fn to_str_exact(num: f64, dig: uint) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpNone, false);
+ num, 10u, true, SignNeg, DigExact(dig), ExpNone, false);
r
}
#[experimental = "may be removed or relocated"]
pub fn to_str_digits(num: f64, dig: uint) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpNone, false);
+ num, 10u, true, SignNeg, DigMax(dig), ExpNone, false);
r
}
#[experimental = "may be removed or relocated"]
pub fn to_str_exp_exact(num: f64, dig: uint, upper: bool) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpDec, upper);
+ num, 10u, true, SignNeg, DigExact(dig), ExpDec, upper);
r
}
#[experimental = "may be removed or relocated"]
pub fn to_str_exp_digits(num: f64, dig: uint, upper: bool) -> String {
let (r, _) = strconv::float_to_str_common(
- num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpDec, upper);
+ num, 10u, true, SignNeg, DigMax(dig), ExpDec, upper);
r
}
mod tests {
use f64::*;
use num::*;
- use num;
#[test]
fn test_min_nan() {
}
#[test]
- fn test_num() {
- num::test_num(10f64, 2f64);
+ fn test_num_f64() {
+ test_num(10f64, 2f64);
}
#[test]
//! Operations and constants for architecture-sized signed integers (`int` type)
-#![unstable]
+#![stable]
#![doc(primitive = "int")]
pub use core::int::{BITS, BYTES, MIN, MAX};
#![allow(missing_docs)]
-pub use self::ExponentFormat::*;
-pub use self::SignificantDigits::*;
-pub use self::SignFormat::*;
+use self::ExponentFormat::*;
+use self::SignificantDigits::*;
+use self::SignFormat::*;
use char::{mod, Char};
use num::{mod, Int, Float, FPNaN, FPInfinite, ToPrimitive};
//! Operations and constants for architecture-sized unsigned integers (`uint` type)
-#![unstable]
+#![stable]
#![doc(primitive = "uint")]
pub use core::uint::{BITS, BYTES, MIN, MAX};
#![allow(non_snake_case)]
#![allow(unused_imports)]
-pub use self::MemoryMapKind::*;
-pub use self::MapOption::*;
-pub use self::MapError::*;
+use self::MemoryMapKind::*;
+use self::MapOption::*;
+use self::MapError::*;
use clone::Clone;
use error::{FromError, Error};
#[cfg(test)]
mod tests {
use prelude::*;
- use c_str::ToCStr;
use option;
use os::{env, getcwd, getenv, make_absolute};
use os::{split_paths, join_paths, setenv, unsetenv};
use result::Result::{Ok, Err};
let chunk = match os::MemoryMap::new(16, &[
- os::MapReadable,
- os::MapWritable
+ os::MapOption::MapReadable,
+ os::MapOption::MapWritable
]) {
Ok(chunk) => chunk,
Err(msg) => panic!("{}", msg)
file.write_u8(0);
let chunk = MemoryMap::new(size / 2, &[
- MapReadable,
- MapWritable,
- MapFd(get_fd(&file)),
- MapOffset(size / 2)
+ MapOption::MapReadable,
+ MapOption::MapWritable,
+ MapOption::MapFd(get_fd(&file)),
+ MapOption::MapOffset(size / 2)
]).unwrap();
assert!(chunk.len > 0);
#[cfg(test)]
mod tests {
use prelude::*;
- use super::{GenericPath, PosixPath, WindowsPath};
- use c_str::ToCStr;
#[test]
fn test_cstring() {
use prelude::*;
use super::*;
use str;
- use str::StrPrelude;
macro_rules! t {
(s: $path:expr, $exp:expr) => (
//! Windows file path handling
-pub use self::PathPrefix::*;
+use self::PathPrefix::*;
use ascii::AsciiCast;
use c_str::{CString, ToCStr};
mod tests {
use prelude::*;
use super::*;
+ use super::PathPrefix::*;
use super::parse_prefix;
macro_rules! t {
#[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek, BufferPrelude};
#[doc(no_inline)] pub use str::{Str, StrVector, StrPrelude};
#[doc(no_inline)] pub use str::{StrAllocating, UnicodeStrPrelude};
-#[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
-#[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
-#[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
+#[doc(no_inline)] pub use core::prelude::{Tuple1, Tuple2, Tuple3, Tuple4};
+#[doc(no_inline)] pub use core::prelude::{Tuple5, Tuple6, Tuple7, Tuple8};
+#[doc(no_inline)] pub use core::prelude::{Tuple9, Tuple10, Tuple11, Tuple12};
#[doc(no_inline)] pub use slice::AsSlice;
#[doc(no_inline)] pub use slice::{VectorVector, PartialEqSliceExt};
#[doc(no_inline)] pub use slice::{CloneSliceExt, OrdSliceExt, SliceExt};
extern crate libc;
use io::{IoResult};
- use kinds::marker;
use mem;
use os;
use rand::Rng;
use libc::{mod, uintptr_t};
use os;
-use str::{FromStr, from_str, Str};
use sync::atomic;
/// Dynamically inquire about whether we're running under V.
pub fn default_sched_threads() -> uint {
match os::getenv("RUST_THREADS") {
Some(nstr) => {
- let opt_n: Option<uint> = FromStr::from_str(nstr.as_slice());
+ let opt_n: Option<uint> = from_str(nstr.as_slice());
match opt_n {
Some(n) if n > 0 => n,
_ => panic!("`RUST_THREADS` is `{}`, should be a positive integer", nstr)
use prelude::*;
use sync::Future;
use task;
- use comm::channel;
#[test]
fn test_from_value() {
#[cfg(test)]
mod test {
- use core::prelude::*;
+ use prelude::*;
use super::*;
- use comm::channel;
- use iter::range;
const TEST_TASKS: uint = 4u;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub use sys::mutex::raw;
-
use sys::mutex as imp;
/// An OS-based mutual exclusion lock.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub use self::SocketStatus::*;
-pub use self::InAddr::*;
+use self::SocketStatus::*;
+use self::InAddr::*;
use alloc::arc::Arc;
use libc::{mod, c_char, c_int};
#[cfg(all(target_os = "ios", target_arch = "arm"))]
#[inline(never)]
pub fn write(w: &mut Writer) -> IoResult<()> {
- use iter::{Iterator, range};
+ use iter::{IteratorExt, range};
use result;
use slice::SliceExt;
// while it doesn't requires lock for work as everything is
// local, it still displays much nicer backtraces when a
// couple of tasks panic simultaneously
- static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
+ static LOCK: StaticMutex = MUTEX_INIT;
let _g = unsafe { LOCK.lock() };
try!(writeln!(w, "stack backtrace:"));
use prelude::*;
use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
-use io::{IoResult, FileStat, SeekStyle, Reader};
+use io::{IoResult, FileStat, SeekStyle};
use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
-use result::Result::{Ok, Err};
use sys::retry;
use sys_common::{keep_going, eof, mkerr_libc};
-pub use path::PosixPath as Path;
-
pub type fd_t = libc::c_int;
pub struct FileDesc {
use fmt;
use io::{IoError, IoResult};
use libc::{mod, c_int, c_char, c_void};
-use path::{Path, GenericPath, BytesContainer};
-use ptr::{mod, RawPtr};
+use path::BytesContainer;
+use ptr;
use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
use sys::fs::FileDesc;
use os;
use sys::{mod, timer, retry, c, set_nonblocking, wouldblock};
use sys::fs::{fd_t, FileDesc};
use sys_common::net::*;
+use sys_common::net::SocketStatus::*;
use sys_common::{eof, mkerr_libc};
fn unix_socket(ty: libc::c_int) -> IoResult<fd_t> {
use sys::{set_nonblocking, wouldblock};
use sys;
use sys_common;
-use sys_common::net::*;
+use sys_common::net;
+use sys_common::net::SocketStatus::Readable;
pub use sys_common::net::TcpStream;
impl TcpListener {
pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
- let fd = try!(socket(addr, libc::SOCK_STREAM));
+ let fd = try!(net::socket(addr, libc::SOCK_STREAM));
let ret = TcpListener { inner: FileDesc::new(fd, true) };
let mut storage = unsafe { mem::zeroed() };
- let len = addr_to_sockaddr(addr, &mut storage);
+ let len = net::addr_to_sockaddr(addr, &mut storage);
let addrp = &storage as *const _ as *const libc::sockaddr;
// On platforms with Berkeley-derived sockets, this allows
// to quickly rebind a socket, without needing to wait for
// the OS to clean up the previous one.
- try!(setsockopt(fd, libc::SOL_SOCKET, libc::SO_REUSEADDR, 1 as libc::c_int));
+ try!(net::setsockopt(fd, libc::SOL_SOCKET,
+ libc::SO_REUSEADDR,
+ 1 as libc::c_int));
match unsafe { libc::bind(fd, addrp, len) } {
}
pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
- sockname(self.fd(), libc::getsockname)
+ net::sockname(self.fd(), libc::getsockname)
}
}
-1 => return Err(last_net_error()),
fd => return Ok(TcpStream::new(fd as sock_t)),
}
- try!(await(&[self.fd(), self.inner.reader.fd()],
+ try!(net::await(&[self.fd(), self.inner.reader.fd()],
deadline, Readable));
}
}
pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
- sockname(self.fd(), libc::getsockname)
+ net::sockname(self.fd(), libc::getsockname)
}
pub fn set_timeout(&mut self, timeout: Option<u64>) {
//!
//! Note that all time units in this file are in *milliseconds*.
-pub use self::Req::*;
+use self::Req::*;
use libc;
use mem;
use cell::UnsafeCell;
use libc::{mod, DWORD};
-use libc;
use os;
use sys::mutex::{mod, Mutex};
use sys::sync as ffi;
use sys_common::{keep_going, eof, mkerr_libc};
use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
-use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader};
+use io::{IoResult, IoError, FileStat, SeekStyle};
use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
-pub use path::WindowsPath as Path;
pub type fd_t = libc::c_int;
pub struct FileDesc {
use libc::{c_int, c_char, c_void};
use libc;
use os;
-use path::{Path, GenericPath, BytesContainer};
-use ptr::{mod, RawPtr};
+use path::BytesContainer;
+use ptr;
use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
use sys::fs::FileDesc;
-use option::Option;
-use option::Option::{Some, None};
use slice;
use os::TMPBUF_SZ;
use sys_common::{AsInner, mkerr_libc, timeout};
use io::fs::PathExtensions;
-use string::String;
pub use sys_common::ProcessConfig;
use sync::{Arc, atomic};
use sys::fs::FileDesc;
use sys::{mod, c, set_nonblocking, wouldblock, timer};
-use sys_common::{mod, timeout, eof};
-use sys_common::net::*;
+use sys_common::{mod, timeout, eof, net};
pub use sys_common::net::TcpStream;
pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
sys::init_net();
- let sock = try!(socket(addr, libc::SOCK_STREAM));
+ let sock = try!(net::socket(addr, libc::SOCK_STREAM));
let ret = TcpListener { sock: sock };
let mut storage = unsafe { mem::zeroed() };
- let len = addr_to_sockaddr(addr, &mut storage);
+ let len = net::addr_to_sockaddr(addr, &mut storage);
let addrp = &storage as *const _ as *const libc::sockaddr;
match unsafe { libc::bind(sock, addrp, len) } {
}
pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
- sockname(self.socket(), libc::getsockname)
+ net::sockname(self.socket(), libc::getsockname)
}
}
}
pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
- sockname(self.socket(), libc::getsockname)
+ net::sockname(self.socket(), libc::getsockname)
}
pub fn set_timeout(&mut self, timeout: Option<u64>) {
//! Other than that, the implementation is pretty straightforward in terms of
//! the other two implementations of timers with nothing *that* new showing up.
-pub use self::Req::*;
+use self::Req::*;
use libc;
use ptr;
//!
//! * It can be implemented highly efficiently on many platforms.
-use core::prelude::*;
-
use any::Any;
use borrow::IntoCow;
use boxed::Box;
use cell::UnsafeCell;
+use clone::Clone;
+use kinds::Send;
+use ops::{Drop, FnOnce};
+use option::Option::{mod, Some, None};
+use result::Result::{Err, Ok};
use sync::{Mutex, Condvar, Arc};
+use str::Str;
use string::String;
use rt::{mod, unwind};
use io::{Writer, stdio};
#[cfg(test)]
mod test {
+ use prelude::*;
use any::{Any, AnyRefExt};
use boxed::BoxAny;
- use prelude::*;
- use result::Result::{Ok, Err};
use result;
use std::io::{ChanReader, ChanWriter};
- use string::String;
use thunk::Thunk;
use super::{Thread, Builder};
--- /dev/null
+// 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.
+
+//! Operations on tuples
+//!
+//! To access a single element of a tuple one can use the following
+//! methods:
+//!
+//! * `valN` - returns a value of _N_-th element
+//! * `refN` - returns a reference to _N_-th element
+//! * `mutN` - returns a mutable reference to _N_-th element
+//!
+//! Indexing starts from zero, so `val0` returns first value, `val1`
+//! returns second value, and so on. In general, a tuple with _S_
+//! elements provides aforementioned methods suffixed with numbers
+//! from `0` to `S-1`. Traits which contain these methods are
+//! implemented for tuples with up to 12 elements.
+//!
+//! If every type inside a tuple implements one of the following
+//! traits, then a tuple itself also implements it.
+//!
+//! * `Clone`
+//! * `PartialEq`
+//! * `Eq`
+//! * `PartialOrd`
+//! * `Ord`
+//! * `Default`
+//!
+//! # Examples
+//!
+//! Using methods:
+//!
+//! ```
+//! #[allow(deprecated)]
+//! # fn main() {
+//! let pair = ("pi", 3.14f64);
+//! assert_eq!(pair.val0(), "pi");
+//! assert_eq!(pair.val1(), 3.14f64);
+//! # }
+//! ```
+//!
+//! Using traits implemented for tuples:
+//!
+//! ```
+//! use std::default::Default;
+//!
+//! let a = (1i, 2i);
+//! let b = (3i, 4i);
+//! assert!(a != b);
+//!
+//! let c = b.clone();
+//! assert!(b == c);
+//!
+//! let d : (u32, f32) = Default::default();
+//! assert_eq!(d, (0u32, 0.0f32));
+//! ```
+
+#![doc(primitive = "tuple")]
+#![stable]
--- /dev/null
+// 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.
+
+#![doc(primitive = "unit")]
+#![stable]
+
+//! The `()` type, sometimes called "unit" or "nil".
+//!
+//! The `()` type has exactly one value `()`, and is used when there
+//! is no other meaningful value that could be returned. `()` is most
+//! commonly seen implicitly: functions without a `-> ...` implicitly
+//! have return type `()`, that is, these are equivalent:
+//!
+//! ```rust
+//! fn long() -> () {}
+//!
+//! fn short() {}
+//! ```
+//!
+//! The semicolon `;` can be used to discard the result of an
+//! expression at the end of a block, making the expression (and thus
+//! the block) evaluate to `()`. For example,
+//!
+//! ```rust
+//! fn returns_i64() -> i64 {
+//! 1i64
+//! }
+//! fn returns_unit() {
+//! 1i64;
+//! }
+//!
+//! let is_i64 = {
+//! returns_i64()
+//! };
+//! let is_unit = {
+//! returns_i64();
+//! };
+//! ```
pub use self::LocalSource::*;
pub use self::Mac_::*;
pub use self::MacStmtStyle::*;
-pub use self::MatchSource::*;
pub use self::MetaItem_::*;
pub use self::Method_::*;
pub use self::Mutability::*;
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum WherePredicate {
BoundPredicate(WhereBoundPredicate),
+ RegionPredicate(WhereRegionPredicate),
EqPredicate(WhereEqPredicate)
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct WhereBoundPredicate {
- pub id: NodeId,
pub span: Span,
- pub ident: Ident,
+ pub bounded_ty: P<Ty>,
pub bounds: OwnedSlice<TyParamBound>,
}
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct WhereRegionPredicate {
+ pub span: Span,
+ pub lifetime: Lifetime,
+ pub bounds: Vec<Lifetime>,
+}
+
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct WhereEqPredicate {
pub id: NodeId,
#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum MatchSource {
- MatchNormal,
- MatchIfLetDesugar,
- MatchWhileLetDesugar,
+ Normal,
+ IfLetDesugar { contains_else_clause: bool },
+ WhileLetDesugar,
}
#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
/// Returns a `Folder` for deeply expanding all macros in a AST node.
pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
- expand::MacroExpander { cx: self }
+ expand::MacroExpander::new(self)
}
pub fn new_parser_from_tts(&self, tts: &[ast::TokenTree])
}
fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: Vec<ast::Arm>) -> P<Expr> {
- self.expr(span, ast::ExprMatch(arg, arms, ast::MatchNormal))
+ self.expr(span, ast::ExprMatch(arg, arms, ast::MatchSource::Normal))
}
fn expr_if(&self, span: Span, cond: P<ast::Expr>,
match *clause {
ast::WherePredicate::BoundPredicate(ref wb) => {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
- id: ast::DUMMY_NODE_ID,
span: self.span,
- ident: wb.ident,
+ bounded_ty: wb.bounded_ty.clone(),
bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect())
})
}
+ ast::WherePredicate::RegionPredicate(ref rb) => {
+ ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+ span: self.span,
+ lifetime: rb.lifetime,
+ bounds: rb.bounds.iter().map(|b| b.clone()).collect()
+ })
+ }
ast::WherePredicate::EqPredicate(ref we) => {
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
id: ast::DUMMY_NODE_ID,
use ast::{StmtExpr, StmtSemi};
use ast::TokenTree;
use ast;
+use ast_util::path_to_ident;
use ext::mtwt;
use ext::build::AstBuilder;
use attr;
Right(R)
}
+pub fn expand_type(t: P<ast::Ty>,
+ fld: &mut MacroExpander,
+ impl_ty: Option<P<ast::Ty>>)
+ -> P<ast::Ty> {
+ debug!("expanding type {} with impl_ty {}", t, impl_ty);
+ let t = match (t.node.clone(), impl_ty) {
+ // Expand uses of `Self` in impls to the concrete type.
+ (ast::Ty_::TyPath(ref path, _), Some(ref impl_ty)) => {
+ let path_as_ident = path_to_ident(path);
+ // Note unhygenic comparison here. I think this is correct, since
+ // even though `Self` is almost just a type parameter, the treatment
+ // for this expansion is as if it were a keyword.
+ if path_as_ident.is_some() &&
+ path_as_ident.unwrap().name == token::special_idents::type_self.name {
+ impl_ty.clone()
+ } else {
+ t
+ }
+ }
+ _ => t
+ };
+ fold::noop_fold_ty(t, fld)
+}
+
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
e.and_then(|ast::Expr {id, node, span}| match node {
// expr_mac should really be expr_ext or something; it's the
// `match <expr> { ... }`
let arms = vec![pat_arm, break_arm];
let match_expr = fld.cx.expr(span,
- ast::ExprMatch(expr, arms, ast::MatchWhileLetDesugar));
+ ast::ExprMatch(expr, arms, ast::MatchSource::WhileLetDesugar));
// `[opt_ident]: loop { ... }`
let loop_block = fld.cx.block_expr(match_expr);
arms
};
+ let contains_else_clause = elseopt.is_some();
+
// `_ => [<elseopt> | ()]`
let else_arm = {
let pat_under = fld.cx.pat_wild(span);
arms.extend(else_if_arms.into_iter());
arms.push(else_arm);
- let match_expr = fld.cx.expr(span, ast::ExprMatch(expr, arms, ast::MatchIfLetDesugar));
+ let match_expr = fld.cx.expr(span,
+ ast::ExprMatch(expr, arms,
+ ast::MatchSource::IfLetDesugar {
+ contains_else_clause: contains_else_clause,
+ }));
fld.fold_expr(match_expr)
}
/// A tree-folder that performs macro expansion
pub struct MacroExpander<'a, 'b:'a> {
pub cx: &'a mut ExtCtxt<'b>,
+ // The type of the impl currently being expanded.
+ current_impl_type: Option<P<ast::Ty>>,
+}
+
+impl<'a, 'b> MacroExpander<'a, 'b> {
+ pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
+ MacroExpander { cx: cx, current_impl_type: None }
+ }
}
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
}
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
- expand_item(item, self)
+ let prev_type = self.current_impl_type.clone();
+ if let ast::Item_::ItemImpl(_, _, _, ref ty, _) = item.node {
+ self.current_impl_type = Some(ty.clone());
+ }
+
+ let result = expand_item(item, self);
+ self.current_impl_type = prev_type;
+ result
}
fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
expand_method(method, self)
}
+ fn fold_ty(&mut self, t: P<ast::Ty>) -> P<ast::Ty> {
+ let impl_type = self.current_impl_type.clone();
+ expand_type(t, self, impl_type)
+ }
+
fn new_span(&mut self, span: Span) -> Span {
new_span(self.cx, span)
}
user_exts: Vec<NamedSyntaxExtension>,
c: Crate) -> Crate {
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
- let mut expander = MacroExpander {
- cx: &mut cx,
- };
+ let mut expander = MacroExpander::new(&mut cx);
for ExportedMacros { crate_name, macros } in imported_macros.into_iter() {
let name = format!("<{} macros>", token::get_ident(crate_name))
Known(ref tyname) => {
match tyname.as_slice() {
"" => "Show",
+ "?" => "Show",
"e" => "LowerExp",
"E" => "UpperExp",
"o" => "Octal",
use std::cell::RefCell;
use std::collections::HashMap;
-use std::collections::hash_map::{Occupied, Vacant};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
/// The SCTable contains a table of SyntaxContext_'s. It
/// represents a flattened tree structure, to avoid having
use std::mem;
use std::rc::Rc;
use std::collections::HashMap;
-use std::collections::hash_map::{Vacant, Occupied};
+use std::collections::hash_map::Entry::{Vacant, Occupied};
// To avoid costly uniqueness checks, we require that `MatchSeq` always has
// a nonempty body.
fld: &mut T)
-> WherePredicate {
match pred {
- ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{id,
- ident,
+ ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bounded_ty,
bounds,
span}) => {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
- id: fld.new_id(id),
- ident: fld.fold_ident(ident),
+ bounded_ty: fld.fold_ty(bounded_ty),
bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
span: fld.new_span(span)
})
}
+ ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{lifetime,
+ bounds,
+ span}) => {
+ ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+ span: fld.new_span(span),
+ lifetime: fld.fold_lifetime(lifetime),
+ bounds: bounds.move_map(|bound| fld.fold_lifetime(bound))
+ })
+ }
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
path,
ty,
#![allow(unknown_features)]
#![feature(macro_rules, globs, default_type_params, phase, slicing_syntax)]
-#![feature(quote, unsafe_destructor, import_shadowing)]
+#![feature(quote, unsafe_destructor)]
#![feature(unboxed_closures)]
extern crate arena;
use owned_slice::OwnedSlice;
use ast;
use abi;
- use attr;
- use attr::AttrMetaMethods;
+ use attr::{first_attr_value_str_by_name, AttrMetaMethods};
use parse::parser::Parser;
use parse::token::{str_to_ident};
use print::pprust::view_item_to_string;
let name = "<source>".to_string();
let source = "/// doc comment\r\nfn foo() {}".to_string();
let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess).unwrap();
- let doc = attr::first_attr_value_str_by_name(item.attrs.as_slice(), "doc").unwrap();
+ let doc = first_attr_value_str_by_name(item.attrs.as_slice(), "doc").unwrap();
assert_eq!(doc.get(), "/// doc comment");
let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string();
let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string();
let item = parse_item_from_source_str(name, source, Vec::new(), &sess).unwrap();
- let doc = attr::first_attr_value_str_by_name(item.attrs.as_slice(), "doc").unwrap();
+ let doc = first_attr_value_str_by_name(item.attrs.as_slice(), "doc").unwrap();
assert_eq!(doc.get(), "/** doc comment\n * with CRLF */");
}
}
use ast::{LitBool, LitChar, LitByte, LitBinary};
use ast::{LitStr, LitInt, Local, LocalLet};
use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces};
-use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchNormal};
+use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource};
use ast::{Method, MutTy, BiMul, Mutability};
use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, NodeId, UnNot};
use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct};
}
/// Parse a type.
- ///
- /// The second parameter specifies whether the `+` binary operator is
- /// allowed in the type grammar.
pub fn parse_ty(&mut self) -> P<Ty> {
maybe_whole!(no_clone self, NtTy);
self.expect(&token::OpenDelim(token::Bracket));
let t = self.parse_ty_sum();
- // Parse the `, ..e` in `[ int, ..e ]`
+ // Parse the `; e` in `[ int; e ]`
// where `e` is a const expression
let t = match self.maybe_parse_fixed_vstore() {
None => TyVec(t),
self.bump();
self.bump();
Some(self.parse_expr())
+ } else if self.check(&token::Semi) {
+ self.bump();
+ Some(self.parse_expr())
} else {
None
}
let count = self.parse_expr();
self.expect(&token::CloseDelim(token::Bracket));
ex = ExprRepeat(first_expr, count);
+ } else if self.check(&token::Semi) {
+ // Repeating vector syntax: [ 0; 512 ]
+ self.bump();
+ let count = self.parse_expr();
+ self.expect(&token::CloseDelim(token::Bracket));
+ ex = ExprRepeat(first_expr, count);
} else if self.check(&token::Comma) {
// Vector with two or more elements.
self.bump();
}
let hi = self.span.hi;
self.bump();
- return self.mk_expr(lo, hi, ExprMatch(discriminant, arms, MatchNormal));
+ return self.mk_expr(lo, hi, ExprMatch(discriminant, arms, MatchSource::Normal));
}
pub fn parse_arm(&mut self) -> Arm {
}
/// Parses an optional `where` clause and places it in `generics`.
+ ///
+ /// ```
+ /// where T : Trait<U, V> + 'b, 'a : 'b
+ /// ```
fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
if !self.eat_keyword(keywords::Where) {
return
let mut parsed_something = false;
loop {
let lo = self.span.lo;
- let path = match self.token {
- token::Ident(..) => self.parse_path(NoTypesAllowed),
- _ => break,
- };
+ match self.token {
+ token::OpenDelim(token::Brace) => {
+ break
+ }
- if self.eat(&token::Colon) {
- let bounds = self.parse_ty_param_bounds();
- let hi = self.span.hi;
- let span = mk_sp(lo, hi);
+ token::Lifetime(..) => {
+ let bounded_lifetime =
+ self.parse_lifetime();
- if bounds.len() == 0 {
- self.span_err(span,
- "each predicate in a `where` clause must have \
- at least one bound in it");
+ self.eat(&token::Colon);
+
+ let bounds =
+ self.parse_lifetimes(token::BinOp(token::Plus));
+
+ let hi = self.span.hi;
+ let span = mk_sp(lo, hi);
+
+ generics.where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
+ ast::WhereRegionPredicate {
+ span: span,
+ lifetime: bounded_lifetime,
+ bounds: bounds
+ }
+ ));
+
+ parsed_something = true;
}
- let ident = match ast_util::path_to_ident(&path) {
- Some(ident) => ident,
- None => {
- self.span_err(path.span, "expected a single identifier \
- in bound where clause");
- break;
- }
- };
+ _ => {
+ let bounded_ty = self.parse_ty();
- generics.where_clause.predicates.push(
- ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
- id: ast::DUMMY_NODE_ID,
- span: span,
- ident: ident,
- bounds: bounds,
- }));
- parsed_something = true;
- } else if self.eat(&token::Eq) {
- let ty = self.parse_ty();
- let hi = self.span.hi;
- let span = mk_sp(lo, hi);
- generics.where_clause.predicates.push(
- ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
- id: ast::DUMMY_NODE_ID,
- span: span,
- path: path,
- ty: ty,
- }));
- parsed_something = true;
- // FIXME(#18433)
- self.span_err(span, "equality constraints are not yet supported in where clauses");
- } else {
- let last_span = self.last_span;
- self.span_err(last_span,
+ if self.eat(&token::Colon) {
+ let bounds = self.parse_ty_param_bounds();
+ let hi = self.span.hi;
+ let span = mk_sp(lo, hi);
+
+ if bounds.len() == 0 {
+ self.span_err(span,
+ "each predicate in a `where` clause must have \
+ at least one bound in it");
+ }
+
+ generics.where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
+ ast::WhereBoundPredicate {
+ span: span,
+ bounded_ty: bounded_ty,
+ bounds: bounds,
+ }));
+
+ parsed_something = true;
+ } else if self.eat(&token::Eq) {
+ // let ty = self.parse_ty();
+ let hi = self.span.hi;
+ let span = mk_sp(lo, hi);
+ // generics.where_clause.predicates.push(
+ // ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
+ // id: ast::DUMMY_NODE_ID,
+ // span: span,
+ // path: panic!("NYI"), //bounded_ty,
+ // ty: ty,
+ // }));
+ // parsed_something = true;
+ // // FIXME(#18433)
+ self.span_err(span,
+ "equality constraints are not yet supported \
+ in where clauses (#20041)");
+ } else {
+ let last_span = self.last_span;
+ self.span_err(last_span,
"unexpected token in `where` clause");
- }
+ }
+ }
+ };
if !self.eat(&token::Comma) {
break
ast::TyFixedLengthVec(ref ty, ref v) => {
try!(word(&mut self.s, "["));
try!(self.print_type(&**ty));
- try!(word(&mut self.s, ", .."));
+ try!(word(&mut self.s, "; "));
try!(self.print_expr(&**v));
try!(word(&mut self.s, "]"));
}
try!(self.ibox(indent_unit));
try!(word(&mut self.s, "["));
try!(self.print_expr(&**element));
- try!(word(&mut self.s, ","));
- try!(word(&mut self.s, ".."));
+ try!(self.word_space(";"));
try!(self.print_expr(&**count));
try!(word(&mut self.s, "]"));
try!(self.end());
}
match predicate {
- &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ident,
+ &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounded_ty,
ref bounds,
..}) => {
- try!(self.print_ident(ident));
+ try!(self.print_type(&**bounded_ty));
try!(self.print_bounds(":", bounds.as_slice()));
}
+ &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
+ ref bounds,
+ ..}) => {
+ try!(self.print_lifetime(lifetime));
+ try!(word(&mut self.s, ":"));
+
+ for (i, bound) in bounds.iter().enumerate() {
+ try!(self.print_lifetime(bound));
+
+ if i != 0 {
+ try!(word(&mut self.s, ":"));
+ }
+ }
+ }
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
try!(self.print_path(path, false));
try!(space(&mut self.s));
walk_lifetime_decls_helper(visitor, &generics.lifetimes);
for predicate in generics.where_clause.predicates.iter() {
match predicate {
- &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{span,
- ident,
+ &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounded_ty,
ref bounds,
..}) => {
- visitor.visit_ident(span, ident);
+ visitor.visit_ty(&**bounded_ty);
walk_ty_param_bounds_helper(visitor, bounds);
}
+ &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
+ ref bounds,
+ ..}) => {
+ visitor.visit_lifetime_ref(lifetime);
+
+ for bound in bounds.iter() {
+ visitor.visit_lifetime_ref(bound);
+ }
+ }
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
ref path,
ref ty,
#![allow(missing_docs)]
use std::collections::hash_map;
-use std::collections::hash_map::{Occupied, Vacant};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::fmt::Show;
use std::hash::Hash;
use std::io;
pub struct Parser<T>;
impl<T: std::iter::Iterator<char>> Parser<T> {
fn in_doctype(&mut self) {
- static DOCTYPEPattern: [char, ..6] = ['O', 'C', 'T', 'Y', 'P', 'E'];
+ static DOCTYPEPattern: [char; 6] = ['O', 'C', 'T', 'Y', 'P', 'E'];
}
}
}
struct Noise2DContext {
- rgradients: [Vec2, ..256],
- permutations: [i32, ..256],
+ rgradients: [Vec2; 256],
+ permutations: [i32; 256],
}
impl Noise2DContext {
fn new() -> Noise2DContext {
let mut rng = StdRng::new().unwrap();
- let mut rgradients = [Vec2 { x: 0.0, y: 0.0 }, ..256];
+ let mut rgradients = [Vec2 { x: 0.0, y: 0.0 }; 256];
for x in rgradients.iter_mut() {
*x = random_gradient(&mut rng);
}
- let mut permutations = [0i32, ..256];
+ let mut permutations = [0i32; 256];
for (i, x) in permutations.iter_mut().enumerate() {
*x = i as i32;
}
self.rgradients[(idx & 255) as uint]
}
- fn get_gradients(&self, x: f32, y: f32) -> ([Vec2, ..4], [Vec2, ..4]) {
+ fn get_gradients(&self, x: f32, y: f32) -> ([Vec2; 4], [Vec2; 4]) {
let x0f = x.floor();
let y0f = y.floor();
let x1f = x0f + 1.0;
fn main() {
let symbols = [' ', 'â–‘', 'â–’', 'â–“', 'â–ˆ', 'â–ˆ'];
- let mut pixels = [0f32, ..256*256];
+ let mut pixels = [0f32; 256*256];
let n2d = Noise2DContext::new();
for _ in range(0u, 100) {
}
struct P {
- p: [i32, .. 16],
+ p: [i32; 16],
}
impl Copy for P {}
struct Perm {
- cnt: [i32, .. 16],
- fact: [u32, .. 16],
+ cnt: [i32; 16],
+ fact: [u32; 16],
n: u32,
permcount: u32,
perm: P,
impl Perm {
fn new(n: u32) -> Perm {
- let mut fact = [1, .. 16];
+ let mut fact = [1; 16];
for i in range(1, n as uint + 1) {
fact[i] = fact[i - 1] * i as u32;
}
Perm {
- cnt: [0, .. 16],
+ cnt: [0; 16],
fact: fact,
n: n,
permcount: 0,
- perm: P { p: [0, .. 16 ] }
+ perm: P { p: [0; 16 ] }
}
}
fn get(&mut self, mut idx: i32) -> P {
- let mut pp = [0u8, .. 16];
+ let mut pp = [0u8; 16];
self.permcount = idx as u32;
for (i, place) in self.perm.p.iter_mut().enumerate() {
*place = i as i32 + 1;
const NULL_AMINO_ACID: AminoAcid = AminoAcid { c: ' ' as u8, p: 0.0 };
-static IUB: [AminoAcid, ..15] = [
+static IUB: [AminoAcid;15] = [
AminoAcid { c: 'a' as u8, p: 0.27 },
AminoAcid { c: 'c' as u8, p: 0.12 },
AminoAcid { c: 'g' as u8, p: 0.12 },
AminoAcid { c: 'Y' as u8, p: 0.02 },
];
-static HOMO_SAPIENS: [AminoAcid, ..4] = [
+static HOMO_SAPIENS: [AminoAcid;4] = [
AminoAcid { c: 'a' as u8, p: 0.3029549426680 },
AminoAcid { c: 'c' as u8, p: 0.1979883004921 },
AminoAcid { c: 'g' as u8, p: 0.1975473066391 },
}
}
-fn make_lookup(a: &[AminoAcid]) -> [AminoAcid, ..LOOKUP_SIZE] {
- let mut lookup = [ NULL_AMINO_ACID, ..LOOKUP_SIZE ];
+fn make_lookup(a: &[AminoAcid]) -> [AminoAcid;LOOKUP_SIZE] {
+ let mut lookup = [ NULL_AMINO_ACID;LOOKUP_SIZE ];
let mut j = 0;
for (i, slot) in lookup.iter_mut().enumerate() {
while a[j].p < (i as f32) {
struct RandomFasta<'a, W:'a> {
seed: u32,
- lookup: [AminoAcid, ..LOOKUP_SIZE],
+ lookup: [AminoAcid;LOOKUP_SIZE],
out: &'a mut W,
}
fn make(&mut self, n: uint) -> IoResult<()> {
let lines = n / LINE_LEN;
let chars_left = n % LINE_LEN;
- let mut buf = [0, ..LINE_LEN + 1];
+ let mut buf = [0;LINE_LEN + 1];
for _ in range(0, lines) {
for i in range(0u, LINE_LEN) {
-> std::io::IoResult<()>
{
try!(wr.write(header.as_bytes()));
- let mut line = [0u8, .. LINE_LENGTH + 1];
+ let mut line = [0u8; LINE_LENGTH + 1];
while n > 0 {
let nb = min(LINE_LENGTH, n);
for i in range(0, nb) {
use std::slice;
use std::sync::{Arc, Future};
-static TABLE: [u8, ..4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
+static TABLE: [u8;4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
static TABLE_SIZE: uint = 2 << 16;
-static OCCURRENCES: [&'static str, ..5] = [
+static OCCURRENCES: [&'static str;5] = [
"GGT",
"GGTA",
"GGTATT",
const YEAR: f64 = 365.24;
const N_BODIES: uint = 5;
-static BODIES: [Planet, ..N_BODIES] = [
+static BODIES: [Planet;N_BODIES] = [
// Sun
Planet {
x: 0.0, y: 0.0, z: 0.0,
impl Copy for Planet {}
-fn advance(bodies: &mut [Planet, ..N_BODIES], dt: f64, steps: int) {
+fn advance(bodies: &mut [Planet;N_BODIES], dt: f64, steps: int) {
for _ in range(0, steps) {
let mut b_slice = bodies.as_mut_slice();
loop {
}
}
-fn energy(bodies: &[Planet, ..N_BODIES]) -> f64 {
+fn energy(bodies: &[Planet;N_BODIES]) -> f64 {
let mut e = 0.0;
let mut bodies = bodies.iter();
loop {
e
}
-fn offset_momentum(bodies: &mut [Planet, ..N_BODIES]) {
+fn offset_momentum(bodies: &mut [Planet;N_BODIES]) {
let mut px = 0.0;
let mut py = 0.0;
let mut pz = 0.0;
use std::io::{IoResult, EndOfFile};
struct Tables {
- table8: [u8, ..1 << 8],
- table16: [u16, ..1 << 16]
+ table8: [u8;1 << 8],
+ table16: [u16;1 << 16]
}
impl Tables {
fn new() -> Tables {
- let mut table8 = [0, ..1 << 8];
+ let mut table8 = [0;1 << 8];
for (i, v) in table8.iter_mut().enumerate() {
*v = Tables::computed_cpl8(i as u8);
}
- let mut table16 = [0, ..1 << 16];
+ let mut table16 = [0;1 << 16];
for (i, v) in table16.iter_mut().enumerate() {
*v = table8[i & 255] as u16 << 8 |
table8[i >> 8] as u16;
return Sudoku { grid: g }
}
- pub fn from_vec(vec: &[[u8, ..9], ..9]) -> Sudoku {
+ pub fn from_vec(vec: &[[u8;9];9]) -> Sudoku {
let g = Vec::from_fn(9u, |i| {
Vec::from_fn(9u, |j| { vec[i][j] })
});
}
}
-static DEFAULT_SUDOKU: [[u8, ..9], ..9] = [
+static DEFAULT_SUDOKU: [[u8;9];9] = [
/* 0 1 2 3 4 5 6 7 8 */
/* 0 */ [0u8, 4u8, 0u8, 6u8, 0u8, 0u8, 0u8, 3u8, 2u8],
/* 1 */ [0u8, 0u8, 8u8, 0u8, 2u8, 0u8, 0u8, 0u8, 0u8],
];
#[cfg(test)]
-static DEFAULT_SOLUTION: [[u8, ..9], ..9] = [
+static DEFAULT_SOLUTION: [[u8;9];9] = [
/* 0 1 2 3 4 5 6 7 8 */
/* 0 */ [1u8, 4u8, 9u8, 6u8, 7u8, 5u8, 8u8, 3u8, 2u8],
/* 1 */ [5u8, 3u8, 8u8, 1u8, 2u8, 9u8, 7u8, 4u8, 6u8],
// except according to those terms.
fn main() {
- let x: [int ..3]; //~ ERROR expected one of `(`, `+`, `,`, `::`, or `]`, found `..`
+ let x: [int 3]; //~ ERROR expected one of `(`, `+`, `,`, `::`, `;`, or `]`, found `3`
}
// Issue #16205.
struct Foo {
- a: [Box<int>, ..3],
+ a: [Box<int>; 3],
}
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Tests that we forbid coercion from `[T, ..n]` to `&[T]`
+// Tests that we forbid coercion from `[T; n]` to `&[T]`
fn main() {
- let _: &[int] = [0i]; //~ERROR: mismatched types: expected `&[int]`, found `[int, ..1]`
+ let _: &[int] = [0i]; //~ERROR: mismatched types: expected `&[int]`, found `[int; 1]`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-static a: [u8, ..3] = ['h' as u8, 'i' as u8, 0 as u8];
+static a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
static b: *const i8 = &a as *const i8; //~ ERROR mismatched types
fn main() {
pub fn main() {
// With a vec of ints.
let f1 = Fat { ptr: [1, 2, 3] };
- let f2: &Fat<[int, ..3]> = &f1;
+ let f2: &Fat<[int; 3]> = &f1;
let f3: &Fat<[uint]> = f2;
- //~^ ERROR mismatched types: expected `&Fat<[uint]>`, found `&Fat<[int, ..3]>`
+ //~^ ERROR mismatched types: expected `&Fat<[uint]>`, found `&Fat<[int; 3]>`
// With a trait.
let f1 = Fat { ptr: Foo };
pub fn main() {
// With a vec of ints.
let f1 = Fat { ptr: [1, 2, 3] };
- let f2: &Fat<[int, ..3]> = &f1;
+ let f2: &Fat<[int; 3]> = &f1;
let f3: &mut Fat<[int]> = f2; //~ ERROR mismatched types
// With a trait.
fn baz<'a>() {
// With a vec of ints.
let f1 = Fat { ptr: [1, 2, 3] };
- let f2: &Fat<[int, ..3]> = &f1; //~ ERROR `f1` does not live long enough
+ let f2: &Fat<[int; 3]> = &f1; //~ ERROR `f1` does not live long enough
let f3: &'a Fat<[int]> = f2;
// With a trait.
pub fn main() {
// With a vec of ints.
let f1: &Fat<[int]> = &Fat { ptr: [1, 2, 3] };
- let f2: &Fat<[int, ..3]> = f1;
- //~^ ERROR mismatched types: expected `&Fat<[int, ..3]>`, found `&Fat<[int]>`
+ let f2: &Fat<[int; 3]> = f1;
+ //~^ ERROR mismatched types: expected `&Fat<[int; 3]>`, found `&Fat<[int]>`
}
}
pub fn main() {
- let f: Fat<[int, ..3]> = Fat { ptr: [5i, 6, 7] };
+ let f: Fat<[int; 3]> = Fat { ptr: [5i, 6, 7] };
let g: &Fat<[int]> = &f;
let h: &Fat<Fat<[int]>> = &Fat { ptr: *g };
//~^ ERROR the trait `core::kinds::Sized` is not implemented
// error-pattern: too big for the current
fn main() {
- let fat : [u8, ..(1<<61)+(1<<31)] = [0, ..(1u64<<61) as uint +(1u64<<31) as uint];
+ let fat : [u8; (1<<61)+(1<<31)] = [0; (1u64<<61) as uint +(1u64<<31) as uint];
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: ..1518599999
+// error-pattern:; 1518599999
fn generic<T: Copy>(t: T) {
- let s: [T, ..1518600000] = [t, ..1518600000];
+ let s: [T; 1518600000] = [t; 1518600000];
}
fn main() {
- let x: [u8, ..1518599999] = [0, ..1518599999];
- generic::<[u8, ..1518599999]>(x);
+ let x: [u8; 1518599999] = [0; 1518599999];
+ generic::<[u8; 1518599999]>(x);
}
#[cfg(target_word_size = "32")]
fn main() {
- let big: Option<[u32, ..(1<<29)-1]> = None;
+ let big: Option<[u32; (1<<29)-1]> = None;
}
#[cfg(target_word_size = "64")]
fn main() {
- let big: Option<[u32, ..(1<<45)-1]> = None;
+ let big: Option<[u32; (1<<45)-1]> = None;
}
// error-pattern: mismatched types
-static VEC: [u32, ..256] = vec!();
+static VEC: [u32; 256] = vec!();
fn main() {}
let x = [1,2];
let y = match x {
[] => None,
- //~^ ERROR types: expected `[_#0i, ..2]`, found `[_#7t, ..0]`
+ //~^ ERROR types: expected `[_#0i; 2]`, found `[_#7t; 0]`
// (expected array of 2 elements, found array of 0 elements)
[a,_] => Some(a)
};
let x = [1,2];
let y = match x {
[] => None,
-//~^ ERROR types: expected `[_, ..2]`, found `[_, ..0]`
+//~^ ERROR types: expected `[_; 2]`, found `[_; 0]`
// (expected array of 2 elements, found array of 0 elements)
[a,_] => Some(a)
};
struct X {
- a: [u8, ..1]
+ a: [u8; 1]
}
fn main() {
let x = X { a: [0] };
let _f = &x.a as *mut u8;
- //~^ ERROR mismatched types: expected `*mut u8`, found `&[u8, ..1]`
+ //~^ ERROR mismatched types: expected `*mut u8`, found `&[u8; 1]`
let local = [0u8];
let _v = &local as *mut u8;
- //~^ ERROR mismatched types: expected `*mut u8`, found `&[u8, ..1]`
+ //~^ ERROR mismatched types: expected `*mut u8`, found `&[u8; 1]`
}
static FOO: uint = FOO; //~ ERROR recursive constant
fn main() {
- let _x: [u8, ..FOO]; // caused stack overflow prior to fix
+ let _x: [u8; FOO]; // caused stack overflow prior to fix
let _y: uint = 1 + {
static BAR: uint = BAR; //~ ERROR recursive constant
- let _z: [u8, ..BAR]; // caused stack overflow prior to fix
+ let _z: [u8; BAR]; // caused stack overflow prior to fix
1
};
}
fn main() {
let _foo = &[1u, 2] as [uint];
- //~^ ERROR cast to unsized type: `&[uint, ..2]` as `[uint]`
+ //~^ ERROR cast to unsized type: `&[uint; 2]` as `[uint]`
//~^^ HELP consider using an implicit coercion to `&[uint]` instead
let _bar = box 1u as std::fmt::Show;
//~^ ERROR cast to unsized type: `Box<uint>` as `core::fmt::Show`
//~^ ERROR cast to unsized type: `uint` as `core::fmt::Show`
//~^^ HELP consider using a box or reference as appropriate
let _quux = [1u, 2] as [uint];
- //~^ ERROR cast to unsized type: `[uint, ..2]` as `[uint]`
+ //~^ ERROR cast to unsized type: `[uint; 2]` as `[uint]`
//~^^ HELP consider using a box or reference as appropriate
}
static C: &'static uint = &(A.a);
//~^ ERROR: cannot refer to the interior of another static
-static D: [uint, ..1] = [1];
+static D: [uint; 1] = [1];
static E: uint = D[0];
//~^ ERROR: cannot refer to other statics by value
static F: &'static uint = &D[0];
const TUP: (uint,) = (42,);
fn main() {
- let a: [int, ..TUP.1];
+ let a: [int; TUP.1];
//~^ ERROR expected constant expr for array length: tuple index out of bounds
}
const STRUCT: MyStruct = MyStruct { field: 42 };
fn main() {
- let a: [int, ..STRUCT.nonexistent_field];
+ let a: [int; STRUCT.nonexistent_field];
//~^ ERROR expected constant expr for array length: nonexistent struct field
}
--- /dev/null
+// 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.
+
+// Test if the sugared if-let construct correctly prints "missing an else clause" when an else
+// clause does not exist, instead of the unsympathetic "match arms have incompatible types"
+
+fn main() {
+ if let Some(homura) = Some("madoka") { //~ ERROR missing an else clause: expected `()`
+ 765i32
+ };
+}
}
fn main() {
["hi"].bind(|x| [x] );
- //~^ ERROR type `[&str, ..1]` does not implement any method in scope named `bind`
+ //~^ ERROR type `[&str; 1]` does not implement any method in scope named `bind`
}
fn bar(int_param: int) {}
fn main() {
- let foo: [u8, ..4] = [1u8, ..4u];
+ let foo: [u8; 4] = [1u8; 4u];
bar(foo);
- //~^ ERROR mismatched types: expected `int`, found `[u8, ..4]`
+ //~^ ERROR mismatched types: expected `int`, found `[u8; 4]`
// (expected int, found vector)
}
pub extern crate core; //~ ERROR: `pub` visibility is not allowed
fn main() {
- pub use std::bool; //~ ERROR: imports in functions are never reachable
+ pub use std::uint; //~ ERROR: imports in functions are never reachable
}
println!("{}", Test);
let mut f = File::open(&Path::new("something.txt"));
- let mut buff = [0u8, ..16];
+ let mut buff = [0u8; 16];
match f.read(&mut buff) {
Ok(cnt) => println!("read this many bytes: {}", cnt),
Err(IoError{ kind: EndOfFile, .. }) => println!("Got end of file: {}", EndOfFile.to_string()),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test moving array structures, e.g. `[T, ..3]` as well as moving
+// Test moving array structures, e.g. `[T; 3]` as well as moving
// elements in and out of such arrays.
//
// Note also that the `test_move_array_then_overwrite` tests represent
impl Drop for D { fn drop(&mut self) { } }
#[rustc_move_fragments]
-pub fn test_move_array_via_return(a: [D, ..3]) -> [D, ..3] {
+pub fn test_move_array_via_return(a: [D; 3]) -> [D; 3] {
//~^ ERROR assigned_leaf_path: `$(local a)`
//~| ERROR moved_leaf_path: `$(local a)`
return a;
}
#[rustc_move_fragments]
-pub fn test_move_array_into_recv(a: [D, ..3], recv: &mut [D, ..3]) {
+pub fn test_move_array_into_recv(a: [D; 3], recv: &mut [D; 3]) {
//~^ ERROR parent_of_fragments: `$(local recv)`
//~| ERROR assigned_leaf_path: `$(local a)`
//~| ERROR moved_leaf_path: `$(local a)`
}
#[rustc_move_fragments]
-pub fn test_extract_array_elem(a: [D, ..3], i: uint) -> D {
+pub fn test_extract_array_elem(a: [D; 3], i: uint) -> D {
//~^ ERROR parent_of_fragments: `$(local a)`
//~| ERROR assigned_leaf_path: `$(local i)`
//~| ERROR moved_leaf_path: `$(local a).[]`
}
#[rustc_move_fragments]
-pub fn test_overwrite_array_elem(mut a: [D, ..3], i: uint, d: D) {
+pub fn test_overwrite_array_elem(mut a: [D; 3], i: uint, d: D) {
//~^ ERROR parent_of_fragments: `$(local mut a)`
//~| ERROR assigned_leaf_path: `$(local i)`
//~| ERROR assigned_leaf_path: `$(local d)`
// See RFC PR 320 for more discussion.
#[rustc_move_fragments]
-pub fn test_move_array_then_overwrite_elem1(mut a: [D, ..3], i: uint, recv: &mut [D, ..3], d: D) {
+pub fn test_move_array_then_overwrite_elem1(mut a: [D; 3], i: uint, recv: &mut [D; 3], d: D) {
//~^ ERROR parent_of_fragments: `$(local mut a)`
//~| ERROR parent_of_fragments: `$(local recv)`
//~| ERROR assigned_leaf_path: `$(local recv).*`
}
#[rustc_move_fragments]
-pub fn test_move_array_then_overwrite_elem2(mut a: [D, ..3], i: uint, j: uint,
- recv: &mut [D, ..3], d1: D, d2: D) {
+pub fn test_move_array_then_overwrite_elem2(mut a: [D; 3], i: uint, j: uint,
+ recv: &mut [D; 3], d1: D, d2: D) {
//~^^ ERROR parent_of_fragments: `$(local mut a)`
//~| ERROR parent_of_fragments: `$(local recv)`
//~| ERROR assigned_leaf_path: `$(local recv).*`
fn f110() {
let x = vec!("hi".to_string());
- let _y = [x.into_iter().next().unwrap(), ..1];
+ let _y = [x.into_iter().next().unwrap(); 1];
touch(&x); //~ ERROR use of moved value: `x`
}
enum State { ST_NULL, ST_WHITESPACE }
fn main() {
- [State::ST_NULL, ..(State::ST_WHITESPACE as uint)];
+ [State::ST_NULL; (State::ST_WHITESPACE as uint)];
//~^ ERROR expected constant integer for repeat count, found non-constant expression
}
fn main() {
fn bar(n: int) {
- let _x: [int, ..n];
+ let _x: [int; n];
//~^ ERROR expected constant expr for array length: non-constant path in constant expr
}
}
fn main() {
fn bar(n: uint) {
- let _x = [0, ..n]; //~ ERROR expected constant integer for repeat count, found variable
+ let _x = [0; n]; //~ ERROR expected constant integer for repeat count, found variable
}
}
struct Foo {
first: bool,
- second: Option<[uint, ..4]>
+ second: Option<[uint; 4]>
}
enum Color {
fn main() {
let foo = Foo { bar: [1u8, 2, 3, 4, 5], baz: 10i32 };
unsafe {
- let oof: Oof<[u8, .. 5], i32> = mem::transmute(foo);
+ let oof: Oof<[u8; 5], i32> = mem::transmute(foo);
println!("{} {}", oof.rab[], oof.zab);
}
}
--- /dev/null
+// 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.
+
+fn a<'a, 'b>(x: &mut &'a int, y: &mut &'b int) where 'b: 'a {
+ // Note: this is legal because of the `'b:'a` declaration.
+ *x = *y;
+}
+
+fn b<'a, 'b>(x: &mut &'a int, y: &mut &'b int) {
+ // Illegal now because there is no `'b:'a` declaration.
+ *x = *y; //~ ERROR mismatched types
+}
+
+fn c<'a,'b>(x: &mut &'a int, y: &mut &'b int) {
+ // Here we try to call `foo` but do not know that `'a` and `'b` are
+ // related as required.
+ a(x, y); //~ ERROR cannot infer
+}
+
+fn d() {
+ // 'a and 'b are early bound in the function `a` because they appear
+ // inconstraints:
+ let _: fn(&mut &int, &mut &int) = a; //~ ERROR mismatched types
+}
+
+fn e() {
+ // 'a and 'b are late bound in the function `b` because there are
+ // no constraints:
+ let _: fn(&mut &int, &mut &int) = b;
+}
+
+fn main() { }
--- /dev/null
+// 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.
+
+fn a<'a, 'b, 'c>(x: &mut &'a int, y: &mut &'b int, z: &mut &'c int) where 'b: 'a + 'c {
+ // Note: this is legal because of the `'b:'a` declaration.
+ *x = *y;
+ *z = *y;
+}
+
+fn b<'a, 'b, 'c>(x: &mut &'a int, y: &mut &'b int, z: &mut &'c int) {
+ // Illegal now because there is no `'b:'a` declaration.
+ *x = *y; //~ ERROR mismatched types
+ *z = *y; //~ ERROR mismatched types
+}
+
+fn c<'a,'b, 'c>(x: &mut &'a int, y: &mut &'b int, z: &mut &'c int) {
+ // Here we try to call `foo` but do not know that `'a` and `'b` are
+ // related as required.
+ a(x, y, z); //~ ERROR cannot infer
+}
+
+fn d() {
+ // 'a and 'b are early bound in the function `a` because they appear
+ // inconstraints:
+ let _: fn(&mut &int, &mut &int, &mut &int) = a; //~ ERROR mismatched types
+}
+
+fn e() {
+ // 'a and 'b are late bound in the function `b` because there are
+ // no constraints:
+ let _: fn(&mut &int, &mut &int, &mut &int) = b;
+}
+
+fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-type v = [int * 3]; //~ ERROR expected one of `(`, `+`, `,`, `::`, or `]`, found `*`
+type v = [int * 3]; //~ ERROR expected one of `(`, `+`, `,`, `::`, `;`, or `]`, found `*`
fn f() {
let v = [mut 1, 2, 3, 4];
//~^ ERROR expected identifier, found keyword `mut`
- //~^^ ERROR expected one of `!`, `,`, `.`, `::`, `]`, `{`, or an operator, found `1`
+ //~^^ ERROR expected one of `!`, `,`, `.`, `::`, `;`, `]`, `{`, or an operator, found `1`
}
type v = [mut int];
//~^ ERROR expected identifier, found keyword `mut`
- //~^^ ERROR expected one of `(`, `+`, `,`, `::`, or `]`, found `int`
+ //~^^ ERROR expected one of `(`, `+`, `,`, `::`, `;`, or `]`, found `int`
fn main() {
let a = Foo { x: 3 };
- let _ = [ a, ..5 ];
+ let _ = [ a; 5 ];
//~^ ERROR the trait `core::kinds::Copy` is not implemented for the type `Foo`
}
fn main() {
let n = 1;
- let a = [0, ..n]; //~ ERROR expected constant integer for repeat count, found variable
- let b = [0, ..()];
+ let a = [0; n]; //~ ERROR expected constant integer for repeat count, found variable
+ let b = [0; ()];
//~^ ERROR expected constant integer for repeat count, found non-constant expression
//~^^ ERROR: expected `uint`, found `()`
- let c = [0, ..true]; //~ ERROR expected positive integer for repeat count, found boolean
+ let c = [0; true]; //~ ERROR expected positive integer for repeat count, found boolean
//~^ ERROR: expected `uint`, found `bool`
- let d = [0, ..0.5]; //~ ERROR expected positive integer for repeat count, found float
+ let d = [0; 0.5]; //~ ERROR expected positive integer for repeat count, found float
//~^ ERROR: expected `uint`, found `_`
- let e = [0, .."foo"]; //~ ERROR expected positive integer for repeat count, found string
+ let e = [0; "foo"]; //~ ERROR expected positive integer for repeat count, found string
//~^ ERROR: expected `uint`, found `&'static str`
- let f = [0, ..-4];
+ let f = [0; -4];
//~^ ERROR expected positive integer for repeat count, found negative integer
- let f = [0u, ..-1];
+ let f = [0u; -1];
//~^ ERROR expected positive integer for repeat count, found negative integer
}
fn foo() -> int { 23 }
-static a: [int, ..2] = [foo(), ..2];
+static a: [int; 2] = [foo(); 2];
//~^ ERROR: function calls in constants are limited to struct and enum constructors
fn main() {}
+++ /dev/null
-// 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.
-
-fn main() {
- let [_, ..,] = [(), ()]; //~ ERROR unexpected token: `]`
-}
let _: int = transmute(x); //~ ERROR cannot transmute
}
-unsafe fn h<T>(x: [T, ..10]) {
+unsafe fn h<T>(x: [T; 10]) {
let _: int = transmute(x); //~ ERROR cannot transmute
}
// presence of the `_` type shorthand notation.
struct X {
- y: [u8, ..2],
+ y: [u8; 2],
}
fn main() {
let x1 = X { y: [0, 0] };
let p1: *const u8 = &x1.y as *const _; //~ ERROR mismatched types
- let t1: *const [u8, ..2] = &x1.y as *const _;
- let h1: *const [u8, ..2] = &x1.y as *const [u8, ..2];
+ let t1: *const [u8; 2] = &x1.y as *const _;
+ let h1: *const [u8; 2] = &x1.y as *const [u8; 2];
let mut x1 = X { y: [0, 0] };
let p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR mismatched types
- let t1: *mut [u8, ..2] = &mut x1.y as *mut _;
- let h1: *mut [u8, ..2] = &mut x1.y as *mut [u8, ..2];
+ let t1: *mut [u8; 2] = &mut x1.y as *mut _;
+ let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];
}
trait Foo {}
-pub fn f<T:Foo>() {} //~ ERROR private type in exported type
+pub fn f<
+ T
+ : Foo //~ ERROR private trait in exported type parameter bound
+>() {}
-pub fn g<T>() where T: Foo {} //~ ERROR private type in exported type
+pub fn g<T>() where
+ T
+ : Foo //~ ERROR private trait in exported type parameter bound
+{}
-pub struct H<T:Foo> { //~ ERROR private type in exported type
- x: T,
+pub struct S;
+
+impl S {
+ pub fn f<
+ T
+ : Foo //~ ERROR private trait in exported type parameter bound
+ >() {}
+
+ pub fn g<T>() where
+ T
+ : Foo //~ ERROR private trait in exported type parameter bound
+ {}
}
-pub struct I<T> where T: Foo { //~ ERROR private type in exported type
- x: T,
+pub struct S1<
+ T
+ : Foo //~ ERROR private trait in exported type parameter bound
+> {
+ x: T
}
-fn main() {}
+pub struct S2<T> where
+ T
+ : Foo //~ ERROR private trait in exported type parameter bound
+{
+ x: T
+}
+pub enum E1<
+ T
+ : Foo //~ ERROR private trait in exported type parameter bound
+> {
+ V1(T)
+}
+
+pub enum E2<T> where
+ T
+ : Foo //~ ERROR private trait in exported type parameter bound
+{
+ V2(T)
+}
+
+fn main() {}
trait Foo {}
-pub trait Bar : Foo {} //~ ERROR private type in exported type
+pub trait Bar : Foo {} //~ ERROR private trait in exported type
fn main() {}
-
--- /dev/null
+// 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.
+
+fn require_copy<T: Copy>(x: T) {}
+
+struct Foo<T> { x: T }
+
+// Ensure constraints are only attached to methods locally
+impl<T> Foo<T> {
+ fn needs_copy(self) where T: Copy {
+ require_copy(self.x);
+
+ }
+
+ fn fails_copy(self) {
+ require_copy(self.x);
+ //~^ ERROR the trait `core::kinds::Copy` is not implemented for the type `T`
+ }
+}
+
+fn main() {}
--- /dev/null
+// 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.
+
+fn require_copy<T: Copy>(x: T) {}
+
+struct Bar<T> { x: T }
+
+trait Foo<T> {
+ fn needs_copy(self) where T: Copy;
+ fn fails_copy(self);
+}
+
+// Ensure constraints are only attached to methods locally
+impl<T> Foo<T> for Bar<T> {
+ fn needs_copy(self) where T: Copy {
+ require_copy(self.x);
+
+ }
+
+ fn fails_copy(self) {
+ require_copy(self.x);
+ //~^ ERROR the trait `core::kinds::Copy` is not implemented for the type `T`
+ }
+}
+
+fn main() {}
--- /dev/null
+// 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.
+
+trait Foo<T> {}
+
+trait Bar<A> {
+ fn method<B>(&self) where A: Foo<B>;
+}
+
+struct S;
+struct X;
+
+// Remove this impl causing the below resolution to fail // impl Foo<S> for X {}
+
+impl Bar<X> for int {
+ fn method<U>(&self) where X: Foo<U> {
+ }
+}
+
+fn main() {
+ 1.method::<X>();
+ //~^ ERROR the trait `Foo<X>` is not implemented for the type `X`
+}
--- /dev/null
+// 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.
+
+// Test that a where clause attached to a method allows us to add
+// additional constraints to a parameter out of scope.
+
+struct Foo<T> {
+ value: T
+}
+
+struct Bar; // does not implement Eq
+
+impl<T> Foo<T> {
+ fn equals(&self, u: &Foo<T>) -> bool where T : Eq {
+ self.value == u.value
+ }
+}
+
+fn main() {
+ let x = Foo { value: Bar };
+ x.equals(&x);
+ //~^ ERROR the trait `core::cmp::Eq` is not implemented for the type `Bar`
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn equal<T>(_: &T, _: &T) -> bool where int : Eq {
- //~^ ERROR undeclared type parameter
+struct A;
+
+trait U {}
+
+// impl U for A {}
+
+fn equal<T>(_: &T, _: &T) -> bool where A : U {
+ true
}
fn main() {
+ equal(&0i, &0i);
+ //~^ ERROR the trait `U` is not implemented for the type `A`
}
-
--- /dev/null
+// Copyright 2013-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.
+
+// ignore-android: FIXME(#10381)
+// min-lldb-version: 310
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+
+// DESTRUCTURED STRUCT
+// gdb-command:print x
+// gdb-check:$1 = 400
+// gdb-command:print y
+// gdb-check:$2 = 401.5
+// gdb-command:print z
+// gdb-check:$3 = true
+// gdb-command:continue
+
+// DESTRUCTURED TUPLE
+// gdb-command:print/x _i8
+// gdb-check:$4 = 0x6f
+// gdb-command:print/x _u8
+// gdb-check:$5 = 0x70
+// gdb-command:print _i16
+// gdb-check:$6 = -113
+// gdb-command:print _u16
+// gdb-check:$7 = 114
+// gdb-command:print _i32
+// gdb-check:$8 = -115
+// gdb-command:print _u32
+// gdb-check:$9 = 116
+// gdb-command:print _i64
+// gdb-check:$10 = -117
+// gdb-command:print _u64
+// gdb-check:$11 = 118
+// gdb-command:print _f32
+// gdb-check:$12 = 119.5
+// gdb-command:print _f64
+// gdb-check:$13 = 120.5
+// gdb-command:continue
+
+// MORE COMPLEX CASE
+// gdb-command:print v1
+// gdb-check:$14 = 80000
+// gdb-command:print x1
+// gdb-check:$15 = 8000
+// gdb-command:print *y1
+// gdb-check:$16 = 80001.5
+// gdb-command:print z1
+// gdb-check:$17 = false
+// gdb-command:print *x2
+// gdb-check:$18 = -30000
+// gdb-command:print y2
+// gdb-check:$19 = -300001.5
+// gdb-command:print *z2
+// gdb-check:$20 = true
+// gdb-command:print v2
+// gdb-check:$21 = 854237.5
+// gdb-command:continue
+
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:type format add --format hex char
+// lldb-command:type format add --format hex 'unsigned char'
+
+// lldb-command:run
+
+// DESTRUCTURED STRUCT
+// lldb-command:print x
+// lldb-check:[...]$0 = 400
+// lldb-command:print y
+// lldb-check:[...]$1 = 401.5
+// lldb-command:print z
+// lldb-check:[...]$2 = true
+// lldb-command:continue
+
+// DESTRUCTURED TUPLE
+// lldb-command:print _i8
+// lldb-check:[...]$3 = 0x6f
+// lldb-command:print _u8
+// lldb-check:[...]$4 = 0x70
+// lldb-command:print _i16
+// lldb-check:[...]$5 = -113
+// lldb-command:print _u16
+// lldb-check:[...]$6 = 114
+// lldb-command:print _i32
+// lldb-check:[...]$7 = -115
+// lldb-command:print _u32
+// lldb-check:[...]$8 = 116
+// lldb-command:print _i64
+// lldb-check:[...]$9 = -117
+// lldb-command:print _u64
+// lldb-check:[...]$10 = 118
+// lldb-command:print _f32
+// lldb-check:[...]$11 = 119.5
+// lldb-command:print _f64
+// lldb-check:[...]$12 = 120.5
+// lldb-command:continue
+
+// MORE COMPLEX CASE
+// lldb-command:print v1
+// lldb-check:[...]$13 = 80000
+// lldb-command:print x1
+// lldb-check:[...]$14 = 8000
+// lldb-command:print *y1
+// lldb-check:[...]$15 = 80001.5
+// lldb-command:print z1
+// lldb-check:[...]$16 = false
+// lldb-command:print *x2
+// lldb-check:[...]$17 = -30000
+// lldb-command:print y2
+// lldb-check:[...]$18 = -300001.5
+// lldb-command:print *z2
+// lldb-check:[...]$19 = true
+// lldb-command:print v2
+// lldb-check:[...]$20 = 854237.5
+// lldb-command:continue
+
+
+struct Struct {
+ x: i16,
+ y: f32,
+ z: bool
+}
+
+fn main() {
+
+ let s = Struct {
+ x: 400,
+ y: 401.5,
+ z: true
+ };
+
+ for &Struct { x, y, z } in [s].iter() {
+ zzz(); // #break
+ }
+
+ let tuple: (i8, u8, i16, u16, i32, u32, i64, u64, f32, f64) =
+ (0x6f, 0x70, -113, 114, -115, 116, -117, 118, 119.5, 120.5);
+
+ for &(_i8, _u8, _i16, _u16, _i32, _u32, _i64, _u64, _f32, _f64) in [tuple].iter() {
+ zzz(); // #break
+ }
+
+ let more_complex: (i32, &Struct, Struct, Box<f64>) =
+ (80000,
+ &Struct {
+ x: 8000,
+ y: 80001.5,
+ z: false
+ },
+ Struct {
+ x: -30000,
+ y: -300001.5,
+ z: true
+ },
+ box 854237.5);
+
+ for &(v1,
+ &Struct { x: x1, y: ref y1, z: z1 },
+ Struct { x: ref x2, y: y2, z: ref z2 },
+ box v2) in [more_complex].iter() {
+ zzz(); // #break
+ }
+}
+
+fn zzz() {()}
#![allow(unused_variables)]
struct NoPadding1 {
- x: [u32, ..3],
+ x: [u32; 3],
y: i32,
- z: [f32, ..2]
+ z: [f32; 2]
}
struct NoPadding2 {
- x: [u32, ..3],
- y: [[u32, ..2], ..2]
+ x: [u32; 3],
+ y: [[u32; 2]; 2]
}
struct StructInternalPadding {
- x: [i16, ..2],
- y: [i64, ..2]
+ x: [i16; 2],
+ y: [i64; 2]
}
struct SingleVec {
- x: [i16, ..5]
+ x: [i16; 5]
}
struct StructPaddedAtEnd {
- x: [i64, ..2],
- y: [i16, ..2]
+ x: [i64; 2],
+ y: [i16; 2]
}
fn main() {
// except according to those terms.
// ignore-android: FIXME(#10381)
-// ignore-test: Not sure what is going on here --pcwalton
// min-lldb-version: 310
// compile-flags:-g
sentinel();
val
- }, ..10];
+ }; 10];
zzz(); // #break
sentinel();
sentinel();
// index expression
- let a_vector = [10i, ..20];
+ let a_vector = [10i; 20];
let _ = a_vector[{
zzz(); // #break
sentinel();
value: 2,
};
- let vec_unique: [UniqueNode<f32>, ..1] = [UniqueNode {
+ let vec_unique: [UniqueNode<f32>; 1] = [UniqueNode {
next: Val {
val: box UniqueNode {
next: Empty,
// VECTORS
// gdb-command:whatis fixed_size_vec1
-// gdb-check:type = struct ([type-names::Struct1, ..3], i16)
+// gdb-check:type = struct ([type-names::Struct1; 3], i16)
// gdb-command:whatis fixed_size_vec2
-// gdb-check:type = struct ([uint, ..3], i16)
+// gdb-check:type = struct ([uint; 3], i16)
// gdb-command:whatis slice1
// gdb-check:type = struct &[uint]
#![allow(unused_variables)]
-static mut VECT: [i32, ..3] = [1, 2, 3];
+static mut VECT: [i32; 3] = [1, 2, 3];
fn main() {
let a = [1i, 2, 3];
// except according to those terms.
// pp-exact
-fn f() -> [int, ..3] {
+fn f() -> [int; 3] {
let picard = 0;
let data = 1;
// #4264 fixed-length vector types
-pub fn foo(_: [int, ..(3 as uint)]) { }
+pub fn foo(_: [int; (3 as uint)]) { }
pub fn bar() {
const FOO: uint = ((5u as uint) - (4u as uint) as uint);
- let _: [(), ..(FOO as uint)] = ([(() as ())] as [(), ..1]);
+ let _: [(); (FOO as uint)] = ([(() as ())] as [(); 1]);
- let _: [(), ..(1u as uint)] = ([(() as ())] as [(), ..1]);
+ let _: [(); (1u as uint)] = ([(() as ())] as [(); 1]);
let _ =
- (((&((([(1i as int), (2 as int), (3 as int)] as [int, ..3])) as
- [int, ..3]) as &[int, ..3]) as *const _ as *const [int, ..3])
- as *const [int, ..(3u as uint)] as *const [int, ..3]);
+ (((&((([(1i as int), (2 as int), (3 as int)] as [int; 3])) as
+ [int; 3]) as &[int; 3]) as *const _ as *const [int; 3]) as
+ *const [int; (3u as uint)] as *const [int; 3]);
(match (() as ()) {
() => {
#[inline]
#[allow(dead_code)]
static __STATIC_FMTSTR: &'static [&'static str] =
- (&([("test" as &'static str)] as [&'static str, ..1]) as
- &'static [&'static str, ..1]);
+ (&([("test" as &'static str)] as [&'static str; 1]) as
+ &'static [&'static str; 1]);
&'static [&'static str]),
(&([]
as
- [core::fmt::Argument<'_>, ..0])
+ [core::fmt::Argument<'_>; 0])
as
- &[core::fmt::Argument<'_>, ..0]))
+ &[core::fmt::Argument<'_>; 0]))
as
core::fmt::Arguments<'_>)
as
}
} as collections::string::String);
}
-pub type Foo = [int, ..(3u as uint)];
+pub type Foo = [int; (3u as uint)];
pub struct Bar {
- pub x: [int, ..(3u as uint)],
+ pub x: [int; (3u as uint)],
}
-pub struct TupleBar([int, ..(4u as uint)]);
-pub enum Baz { BazVariant([int, ..(5u as uint)]), }
+pub struct TupleBar([int; (4u as uint)]);
+pub enum Baz { BazVariant([int; (5u as uint)]), }
pub fn id<T>(x: T) -> T { (x as T) }
pub fn use_id() {
let _ =
- ((id::<[int, ..(3u as uint)]> as
- fn([int, ..3]) -> [int, ..3])(([(1 as int), (2 as int),
- (3 as int)] as [int, ..3])) as
- [int, ..3]);
+ ((id::<[int; (3u as uint)]> as
+ fn([int; 3]) -> [int; 3])(([(1 as int), (2 as int), (3 as int)]
+ as [int; 3])) as [int; 3]);
}
fn main() { }
--- /dev/null
+// Copyright 2013 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.
+
+// pp-exact
+
+fn f<'a, 'b, T>(t: T) -> int where T: 'a, 'a:'b, T: Eq { 0 }
+
+fn main() { }
+
-LIB := $(shell $(RUSTC) --crate-file-name --crate-type=lib lib.rs)
+LIB := $(shell $(RUSTC) --print file-names --crate-type=lib lib.rs)
$(TMPDIR)/$(LIB):
$(RUSTC) --dep-info $(TMPDIR)/custom-deps-file.d --crate-type=lib lib.rs
-LIB := $(shell $(RUSTC) --crate-file-name --crate-type=lib lib.rs)
+LIB := $(shell $(RUSTC) --print file-names --crate-type=lib lib.rs)
$(TMPDIR)/$(LIB):
- $(RUSTC) --dep-info --crate-type=lib lib.rs
+ $(RUSTC) --emit dep-info,link --crate-type=lib lib.rs
touch $(TMPDIR)/done
-include $(TMPDIR)/foo.d
# used in the inner functions should each appear only once in the generated IR.
all:
- $(RUSTC) foo.rs --emit=ir
+ $(RUSTC) foo.rs --emit=llvm-ir
[ "$$(grep -c 8675309 "$(TMPDIR)/foo.ll")" -eq "1" ]
[ "$$(grep -c 11235813 "$(TMPDIR)/foo.ll")" -eq "1" ]
all:
else
-NAME := $(shell $(RUSTC) --crate-file-name foo.rs)
+NAME := $(shell $(RUSTC) --print file-names foo.rs)
all:
mkdir -p $(TMPDIR)/outdir
#[no_stack_check]
pub unsafe fn foo() {
// Make sure we use the stack
- let x: [u8, ..50] = [0, ..50];
+ let x: [u8; 50] = [0; 50];
black_box(x.as_ptr());
}
pub unsafe fn foo() {
// Make sure we use the stack
- let x: [u8, ..50] = [0, ..50];
+ let x: [u8; 50] = [0; 50];
black_box(x.as_ptr());
}
rm $(TMPDIR)/$(call BIN,bar)
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --emit=asm,ir,bc,obj,link
+ $(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link
rm $(TMPDIR)/bar.ll
rm $(TMPDIR)/bar.bc
rm $(TMPDIR)/bar.s
rm $(TMPDIR)/foo
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --emit=bc -o $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit=llvm-bc -o $(TMPDIR)/foo
rm $(TMPDIR)/foo
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --emit=ir -o $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit=llvm-ir -o $(TMPDIR)/foo
rm $(TMPDIR)/foo
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
rm $(TMPDIR)/$(call BIN,foo)
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --emit=asm,ir,bc,obj,link --crate-type=staticlib
+ $(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link --crate-type=staticlib
rm $(TMPDIR)/bar.ll
rm $(TMPDIR)/bar.s
rm $(TMPDIR)/bar.o
# Don't check that the $(TMPDIR) is empty - we left `foo.bc` for later
# comparison.
- $(RUSTC) foo.rs --emit=bc,link --crate-type=rlib
+ $(RUSTC) foo.rs --emit=llvm-bc,link --crate-type=rlib
cmp $(TMPDIR)/foo.bc $(TMPDIR)/bar.bc
rm $(TMPDIR)/bar.bc
rm $(TMPDIR)/foo.bc
all:
$(RUSTC) cci_lib.rs
- $(RUSTC) foo.rs --emit=ir -C codegen-units=3
+ $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ .*cci_fn)" -eq "2" ]
# function should be defined in only one compilation unit.
all:
- $(RUSTC) foo.rs --emit=ir -C codegen-units=3
+ $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "1" ]
[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ available_externally\ i32\ .*inlined)" -eq "2" ]
[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*normal)" -eq "1" ]
# wind up in three different compilation units.
all:
- $(RUSTC) foo.rs --emit=ir -C codegen-units=3
+ $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ .*magic_fn)" -eq "3" ]
fn start(_main: *const u8, _argc: int, _argv: *const *const u8) -> int { 0 }
extern {
- fn _foo() -> [u8, ..16];
+ fn _foo() -> [u8; 16];
}
fn _main() {
-include ../tools.mk
all:
- $(RUSTC) -v
- $(RUSTC) -v verbose
- $(RUSTC) -v bad_arg && exit 1 || exit 0
- $(RUSTC) --version verbose
- $(RUSTC) --version bad_arg && exit 1 || exit 0
+ $(RUSTC) -V
+ $(RUSTC) -vV
+ $(RUSTC) --version --verbose
$(RUSTC) main.rs
$(call RUN,main)
# ... and the loads/stores must not be optimized out.
- $(RUSTC) main.rs --emit=ir
+ $(RUSTC) main.rs --emit=llvm-ir
grep "load volatile" $(TMPDIR)/main.ll
grep "store volatile" $(TMPDIR)/main.ll
const SIZE: int = 25;
fn main() {
- let _a: [bool, ..1 as uint];
- let _b: [int, ..SIZE as uint] = [1, ..SIZE as uint];
- let _c: [bool, ..'\n' as uint] = [true, ..'\n' as uint];
- let _d: [bool, ..true as uint] = [true, ..true as uint];
+ let _a: [bool; 1 as uint];
+ let _b: [int; SIZE as uint] = [1; SIZE as uint];
+ let _c: [bool; '\n' as uint] = [true; '\n' as uint];
+ let _d: [bool; true as uint] = [true; true as uint];
}
// Check that the various ways of getting to a reference to a vec (both sized
// and unsized) work properly.
-const aa: [int, ..3] = [1, 2, 3];
-const ab: &'static [int, ..3] = &aa;
+const aa: [int; 3] = [1, 2, 3];
+const ab: &'static [int; 3] = &aa;
const ac: &'static [int] = ab;
const ad: &'static [int] = &aa;
-const ae: &'static [int, ..3] = &[1, 2, 3];
+const ae: &'static [int; 3] = &[1, 2, 3];
const af: &'static [int] = &[1, 2, 3];
static ca: int = aa[0];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-static A: [u8, ..1] = ['h' as u8];
+static A: [u8; 1] = ['h' as u8];
static B: u8 = (&A)[0];
-static C: &'static &'static &'static &'static [u8, ..1] = & & & &A;
+static C: &'static &'static &'static &'static [u8; 1] = & & & &A;
static D: u8 = (&C)[0];
pub fn main() {
const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)];
static C0: E = C[0];
static C1: E = C[1];
-const D: &'static [E, ..2] = &[E::V0, E::V1(0xDEADBEE)];
+const D: &'static [E; 2] = &[E::V0, E::V1(0xDEADBEE)];
static D0: E = C[0];
static D1: E = C[1];
// except according to those terms.
enum E { V1(int), V0 }
-static C: [E, ..3] = [E::V0, E::V1(0xDEADBEE), E::V0];
+static C: [E; 3] = [E::V0, E::V1(0xDEADBEE), E::V0];
pub fn main() {
match C[1] {
pub fn main() {
const FOO: uint = 2;
- let _v: [int, ..FOO*3];
+ let _v: [int; FOO*3];
}
pub fn main() {
const FOO: uint = 2;
- let _v = [0i, ..FOO*3*2/2];
+ let _v = [0i; FOO*3*2/2];
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-const x : [int, ..4] = [1,2,3,4];
+const x : [int; 4] = [1,2,3,4];
static p : int = x[2];
const y : &'static [int] = &[1,2,3,4];
static q : int = y[2];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-type Big = [u64, ..8];
+type Big = [u64; 8];
struct Pair<'a> { a: int, b: &'a Big }
const x: &'static Big = &([13, 14, 10, 13, 11, 14, 14, 15]);
const y: &'static Pair<'static> = &Pair {a: 15, b: x};
use std::{str, string};
-const A: [u8, ..2] = ['h' as u8, 'i' as u8];
-const B: &'static [u8, ..2] = &A;
+const A: [u8; 2] = ['h' as u8, 'i' as u8];
+const B: &'static [u8; 2] = &A;
const C: *const u8 = B as *const u8;
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-static x : [int, ..4] = [1,2,3,4];
+static x : [int; 4] = [1,2,3,4];
static y : &'static [int] = &[1,2,3,4];
-static z : &'static [int, ..4] = &[1,2,3,4];
+static z : &'static [int; 4] = &[1,2,3,4];
static zz : &'static [int] = &[1,2,3,4];
pub fn main() {
assert!((*f2)[1] == 2);
// Nested Box.
- let f1 : Box<Fat<[int, ..3]>> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] };
+ let f1 : Box<Fat<[int; 3]>> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] };
foo(&*f1);
let f2 : Box<Fat<[int]>> = f1;
foo(&*f2);
const BAR2:uint = BAR;
pub fn main() {
- let _v = [0i, .. Flopsy::Bunny as uint];
- let _v = [0i, .. BAR];
- let _v = [0i, .. BAR2];
+ let _v = [0i; Flopsy::Bunny as uint];
+ let _v = [0i; BAR];
+ let _v = [0i; BAR2];
const BAR3:uint = BAR2;
- let _v = [0i, .. BAR3];
+ let _v = [0i; BAR3];
}
// Doesn't work; needs a design decision.
pub fn main() {
- let x : [int, ..5] = [1,2,3,4,5];
- let _y : [int, ..5] = [1,2,3,4,5];
+ let x : [int; 5] = [1,2,3,4,5];
+ let _y : [int; 5] = [1,2,3,4,5];
let mut z = [1,2,3,4,5];
z = x;
assert_eq!(z[0], 1);
assert_eq!(z[4], 5);
- let a : [int, ..5] = [1,1,1,1,1];
- let b : [int, ..5] = [2,2,2,2,2];
- let c : [int, ..5] = [2,2,2,2,3];
+ let a : [int; 5] = [1,1,1,1,1];
+ let b : [int; 5] = [2,2,2,2,2];
+ let c : [int; 5] = [2,2,2,2,3];
log(debug, a);
#![feature(macro_rules)]
-use std::num::strconv as s;
+use std::num::strconv::ExponentFormat::{ExpBin, ExpDec};
+use std::num::strconv::SignificantDigits::DigMax;
+use std::num::strconv::SignFormat::{SignAll, SignNeg};
use std::num::strconv::float_to_str_common as to_string;
macro_rules! t(($a:expr, $b:expr) => { { let (r, _) = $a; assert_eq!(r, $b.to_string()); } });
pub fn main() {
// Basic usage
- t!(to_string(1.2345678e-5f64, 10u, true, s::SignNeg, s::DigMax(6), s::ExpDec, false),
+ t!(to_string(1.2345678e-5f64, 10u, true, SignNeg, DigMax(6), ExpDec, false),
"1.234568e-5");
// Hexadecimal output
- t!(to_string(7.281738281250e+01f64, 16u, true, s::SignAll, s::DigMax(6), s::ExpBin, false),
+ t!(to_string(7.281738281250e+01f64, 16u, true, SignAll, DigMax(6), ExpBin, false),
"+1.2345p+6");
- t!(to_string(-1.777768135071e-02f64, 16u, true, s::SignAll, s::DigMax(6), s::ExpBin, false),
+ t!(to_string(-1.777768135071e-02f64, 16u, true, SignAll, DigMax(6), ExpBin, false),
"-1.2345p-6");
// Some denormals
- t!(to_string(4.9406564584124654e-324f64, 10u, true, s::SignNeg, s::DigMax(6), s::ExpBin, false),
+ t!(to_string(4.9406564584124654e-324f64, 10u, true, SignNeg, DigMax(6), ExpBin, false),
"1p-1074");
- t!(to_string(2.2250738585072009e-308f64, 10u, true, s::SignNeg, s::DigMax(6), s::ExpBin, false),
+ t!(to_string(2.2250738585072009e-308f64, 10u, true, SignNeg, DigMax(6), ExpBin, false),
"1p-1022");
}
#[cfg(target_word_size = "32")]
pub fn main() {
- assert_eq!(size_of::<[u8, ..(1 << 31) - 1]>(), (1 << 31) - 1);
+ assert_eq!(size_of::<[u8; (1 << 31) - 1]>(), (1 << 31) - 1);
}
#[cfg(target_word_size = "64")]
pub fn main() {
- assert_eq!(size_of::<[u8, ..(1 << 47) - 1]>(), (1 << 47) - 1);
+ assert_eq!(size_of::<[u8; (1 << 47) - 1]>(), (1 << 47) - 1);
}
t!(format!("{}", 10i), "10");
t!(format!("{}", 10i), "10");
t!(format!("{}", 10u), "10");
+ t!(format!("{:?}", true), "true");
t!(format!("{:o}", 10u), "12");
t!(format!("{:x}", 10u), "a");
t!(format!("{:X}", 10u), "A");
trait Foo {}
impl Foo for int {}
-fn foo(_: [&Foo, ..2]) {}
+fn foo(_: [&Foo; 2]) {}
fn foos(_: &[&Foo]) {}
fn foog<T>(_: &[T], _: &[T]) {}
-fn bar(_: [Box<Foo>, ..2]) {}
+fn bar(_: [Box<Foo>; 2]) {}
fn bars(_: &[Box<Foo>]) {}
fn main() {
- let x: [&Foo, ..2] = [&1i, &2i];
+ let x: [&Foo; 2] = [&1i, &2i];
foo(x);
foo([&1i, &2i]);
let r = &1i;
- let x: [&Foo, ..2] = [r, ..2];
+ let x: [&Foo; 2] = [r; 2];
foo(x);
- foo([&1i, ..2]);
+ foo([&1i; 2]);
let x: &[&Foo] = &[&1i, &2i];
foos(x);
let r = &1i;
foog(x, &[r]);
- let x: [Box<Foo>, ..2] = [box 1i, box 2i];
+ let x: [Box<Foo>; 2] = [box 1i, box 2i];
bar(x);
bar([box 1i, box 2i]);
foog(x, &[box 1i]);
struct T<'a> {
- t: [&'a (Foo+'a), ..2]
+ t: [&'a (Foo+'a); 2]
}
let _n = T {
t: [&1i, &2i]
};
let r = &1i;
let _n = T {
- t: [r, ..2]
+ t: [r; 2]
};
- let x: [&Foo, ..2] = [&1i, &2i];
+ let x: [&Foo; 2] = [&1i, &2i];
let _n = T {
t: x
};
t: &[&1i, &2i]
};
let r = &1i;
- let r: [&Foo, ..2] = [r, ..2];
+ let r: [&Foo; 2] = [r; 2];
let _n = F {
t: &r
};
- let x: [&Foo, ..2] = [&1i, &2i];
+ let x: [&Foo; 2] = [&1i, &2i];
let _n = F {
t: &x
};
let _n = M {
t: &[box 1i, box 2i]
};
- let x: [Box<Foo>, ..2] = [box 1i, box 2i];
+ let x: [Box<Foo>; 2] = [box 1i, box 2i];
let _n = M {
t: &x
};
}
pub fn test() {
- let mut buf: [u16, ..50] = [0, ..50];
+ let mut buf: [u16; 50] = [0; 50];
let ret = unsafe {
FormatMessageW(0x1000, 0 as *mut c_void, 1, 0x400,
buf.as_mut_ptr(), buf.len() as u32, 0 as *const c_void)
const NUM: uint = u8::BITS as uint;
-struct MyStruct { nums: [uint, ..8] }
+struct MyStruct { nums: [uint; 8] }
fn main() {
- let _s = MyStruct { nums: [0, ..NUM] };
+ let _s = MyStruct { nums: [0; NUM] };
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-static TEST_VALUE : *const [int, ..2] = 0x1234 as *const [int, ..2];
+static TEST_VALUE : *const [int; 2] = 0x1234 as *const [int; 2];
fn main() {}
fn b(&self) {}
}
-// If these fail, it's necessary to update middle::resolve and the cfail tests.
+// If these fail, it's necessary to update rustc_resolve and the cfail tests.
impl Foo for *const BarTy {
fn bar(&self) {
self.baz();
}
}
-// If these fail, it's necessary to update middle::resolve and the cfail tests.
+// If these fail, it's necessary to update rustc_resolve and the cfail tests.
impl<'a> Foo for &'a BarTy {
fn bar(&self) {
self.baz();
}
}
-// If these fail, it's necessary to update middle::resolve and the cfail tests.
+// If these fail, it's necessary to update rustc_resolve and the cfail tests.
impl<'a> Foo for &'a mut BarTy {
fn bar(&self) {
self.baz();
}
}
-// If these fail, it's necessary to update middle::resolve and the cfail tests.
+// If these fail, it's necessary to update rustc_resolve and the cfail tests.
impl Foo for Box<BarTy> {
fn bar(&self) {
self.baz();
}
}
-// If these fail, it's necessary to update middle::resolve and the cfail tests.
+// If these fail, it's necessary to update rustc_resolve and the cfail tests.
impl Foo for *const int {
fn bar(&self) {
self.baz();
}
}
-// If these fail, it's necessary to update middle::resolve and the cfail tests.
+// If these fail, it's necessary to update rustc_resolve and the cfail tests.
impl<'a> Foo for &'a int {
fn bar(&self) {
self.baz();
}
}
-// If these fail, it's necessary to update middle::resolve and the cfail tests.
+// If these fail, it's necessary to update rustc_resolve and the cfail tests.
impl<'a> Foo for &'a mut int {
fn bar(&self) {
self.baz();
}
}
-// If these fail, it's necessary to update middle::resolve and the cfail tests.
+// If these fail, it's necessary to update rustc_resolve and the cfail tests.
impl Foo for Box<int> {
fn bar(&self) {
self.baz();
let args = os::args();
if args.len() > 1 {
let mut out = stdio::stdout();
- out.write(&['a' as u8, ..128 * 1024]).unwrap();
+ out.write(&['a' as u8; 128 * 1024]).unwrap();
} else {
let out = Command::new(args[0].as_slice()).arg("child").output();
let out = out.unwrap();
use std::iter::AdditiveIterator;
fn main() {
- let x: [u64, ..3] = [1, 2, 3];
+ let x: [u64; 3] = [1, 2, 3];
assert_eq!(6, range(0, 3).map(|i| x[i]).sum());
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-static mut DROPPED: [bool, ..2] = [false, false];
+static mut DROPPED: [bool; 2] = [false, false];
struct A(uint);
struct Foo { _a: A, _b: int }
// except according to those terms.
fn main() {
- assert_eq!(match [0u8, ..1024] {
+ assert_eq!(match [0u8; 1024] {
_ => 42u,
}, 42u);
- assert_eq!(match [0u8, ..1024] {
+ assert_eq!(match [0u8; 1024] {
[1, _..] => 0u,
[0, _..] => 1u,
_ => 2u
// expression with a count of 1 and a non-Copy element type.
fn main() {
- let _ = [box 1u, ..1];
+ let _ = [box 1u; 1];
}
const TUP: (uint,) = (43,);
fn main() {
- let a = [0i, ..STRUCT.field];
- let b = [0i, ..TUP.0];
+ let a = [0i; STRUCT.field];
+ let b = [0i; TUP.0];
assert!(a.len() == 42);
assert!(b.len() == 43);
--- /dev/null
+// 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.
+
+fn main() {
+ let mut escaped = String::from_str("");
+ for c in '\u{10401}'.escape_unicode() {
+ escaped.push(c);
+ }
+ assert_eq!("\\u{10401}", escaped);
+}
-> Vec<Vec<square>> {
let mut input: &mut io::Reader = &mut input;
let mut grid = Vec::new();
- let mut line = [0, ..10];
+ let mut line = [0; 10];
input.read(&mut line);
let mut row = Vec::new();
for c in line.iter() {
use libc::{c_uint, uint32_t, c_void};
pub struct KEYGEN {
- hash_algorithm: [c_uint, ..2],
+ hash_algorithm: [c_uint; 2],
count: uint32_t,
salt: *const c_void,
salt_size: uint32_t,
// except according to those terms.
pub fn main() {
- let _foo = [0i, ..2*4];
+ let _foo = [0i; 2*4];
}
...should print &[1, 2, 3] but instead prints something like
&[4492532864, 24]. It is pretty evident that the compiler messed up
-with the representation of [int, ..n] and [int] somehow, or at least
+with the representation of [int; n] and [int] somehow, or at least
failed to typecheck correctly.
*/
#![feature(advanced_slice_patterns)]
-fn foo<T: Add<T, T> + Clone>([x, y, z]: [T, ..3]) -> (T, T, T) {
+fn foo<T: Add<T, T> + Clone>([x, y, z]: [T; 3]) -> (T, T, T) {
(x.clone(), x.clone() + y.clone(), x + y + z)
}
-fn bar(a: &'static str, b: &'static str) -> [&'static str, ..4] {
+fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] {
[a, b, b, a]
}
// except according to those terms.
pub fn main() {
- const S: uint = 23 as uint; [0i, ..S]; ()
+ const S: uint = 23 as uint; [0i; S]; ()
}
);
fn main() {
- let _x: [u16, ..four!()];
+ let _x: [u16; four!()];
}
}
fn issue_13626() {
- const VAL: [u8, ..1] = [0];
+ const VAL: [u8; 1] = [0];
match [1] {
VAL => unreachable!(),
_ => ()
}
fn main() {
- let mut buf = [0_u8, .. 6];
+ let mut buf = [0_u8; 6];
{
let mut writer = buf.as_mut_slice();
}
fn main() {
- let x: [int, ..4] = [1,2,3,4];
+ let x: [int; 4] = [1,2,3,4];
let xptr = x.as_slice() as *const _;
xptr.foo();
}
// except according to those terms.
fn test1() {
- let mut ints = [0i, ..32];
+ let mut ints = [0i; 32];
ints[0] += 1;
assert_eq!(ints[0], 1);
}
fn test2() {
- let mut ints = [0i, ..32];
+ let mut ints = [0i; 32];
for i in ints.iter_mut() { *i += 22; }
for i in ints.iter() { assert!(*i == 22); }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-static FOO: [int, ..3] = [1, 2, 3];
+static FOO: [int; 3] = [1, 2, 3];
pub fn main() {
println!("{} {} {}", FOO[0], FOO[1], FOO[2]);
// trying to get assert failure messages that at least identify which case
// failed.
-enum E<T> { Thing(int, T), Nothing((), ((), ()), [i8, ..0]) }
+enum E<T> { Thing(int, T), Nothing((), ((), ()), [i8; 0]) }
impl<T> E<T> {
fn is_none(&self) -> bool {
match *self {
check_fancy!($e: $T, |ptr| assert!(*ptr == $e));
}};
($e:expr: $T:ty, |$v:ident| $chk:expr) => {{
- assert!(E::Nothing::<$T>((), ((), ()), [23i8, ..0]).is_none());
+ assert!(E::Nothing::<$T>((), ((), ()), [23i8; 0]).is_none());
let e = $e;
let t_ = E::Thing::<$T>(23, e);
match t_.get_ref() {
use std::mem;
-enum E<T> { Thing(int, T), Nothing((), ((), ()), [i8, ..0]) }
+enum E<T> { Thing(int, T), Nothing((), ((), ()), [i8; 0]) }
struct S<T>(int, T);
// These are macros so we get useful assert messages.
// in ORDER matching up to when it ran.
// Correct order is: matched, inner, outer
-static mut ORDER: [uint, ..3] = [0, 0, 0];
+static mut ORDER: [uint; 3] = [0, 0, 0];
static mut INDEX: uint = 0;
struct A;
#[no_stack_check]
fn recurse() {
- let buf = [0i, ..10];
+ let buf = [0i; 10];
black_box(buf);
recurse();
}
#[no_stack_check]
fn recurse() {
- let buf = [0i, ..10];
+ let buf = [0i; 10];
black_box(buf);
recurse();
}
pub fn black_box<T>(dummy: T) { unsafe { asm!("" : : "r"(&dummy)) } }
fn silent_recurse() {
- let buf = [0i, ..1000];
+ let buf = [0i; 1000];
black_box(buf);
silent_recurse();
}
pub fn main() {
unsafe {
let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as i32 };
- let transd : [u8, .. 9] = mem::transmute(s);
+ let transd : [u8; 9] = mem::transmute(s);
// Don't worry about endianness, the numbers are palindromic.
assert!(transd ==
[0xff, 0xff, 0xff, 0xff,
let s = S { a: 1u8, b: 2u8, c: 0b10000001_10000001 as i16};
- let transd : [u8, .. 4] = mem::transmute(s);
+ let transd : [u8; 4] = mem::transmute(s);
// Again, no endianness problems.
assert!(transd ==
[1, 2, 0b10000001, 0b10000001]);
#[repr(packed)]
struct S4 {
a: u8,
- b: [u8, .. 3],
+ b: [u8; 3],
}
#[repr(packed)]
pub fn main() {
unsafe {
let s4 = S4 { a: 1, b: [2,3,4] };
- let transd : [u8, .. 4] = mem::transmute(s4);
+ let transd : [u8; 4] = mem::transmute(s4);
assert!(transd == [1, 2, 3, 4]);
let s5 = S5 { a: 1, b: 0xff_00_00_ff };
- let transd : [u8, .. 5] = mem::transmute(s5);
+ let transd : [u8; 5] = mem::transmute(s5);
// Don't worry about endianness, the u32 is palindromic.
assert!(transd == [1, 0xff, 0, 0, 0xff]);
}
#[repr(packed)]
struct S4 {
a: u8,
- b: [u8, .. 3],
+ b: [u8; 3],
}
#[repr(packed)]
impl Copy for Foo {}
pub fn main() {
- let foos = [Foo { bar: 1, baz: 2 }, .. 10];
+ let foos = [Foo { bar: 1, baz: 2 }; 10];
- assert_eq!(mem::size_of::<[Foo, .. 10]>(), 90);
+ assert_eq!(mem::size_of::<[Foo; 10]>(), 90);
for i in range(0u, 10) {
assert_eq!(foos[i], Foo { bar: 1, baz: 2});
use std::mem;
#[repr(packed)]
-struct S4(u8,[u8, .. 3]);
+struct S4(u8,[u8; 3]);
#[repr(packed)]
struct S5(u8,u32);
pub fn main() {
unsafe {
let s4 = S4(1, [2,3,4]);
- let transd : [u8, .. 4] = mem::transmute(s4);
+ let transd : [u8; 4] = mem::transmute(s4);
assert!(transd == [1, 2, 3, 4]);
let s5 = S5(1, 0xff_00_00_ff);
- let transd : [u8, .. 5] = mem::transmute(s5);
+ let transd : [u8; 5] = mem::transmute(s5);
// Don't worry about endianness, the u32 is palindromic.
assert!(transd == [1, 0xff, 0, 0, 0xff]);
}
use std::mem;
#[repr(packed)]
-struct S4(u8,[u8, .. 3]);
+struct S4(u8,[u8; 3]);
#[repr(packed)]
struct S5(u8, u32);
struct B {
v1: int,
- v2: [int, ..3],
+ v2: [int; 3],
v3: Vec<int> ,
v4: C,
v5: Box<C>,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-static FOO: [int, ..4] = [32, ..4];
-static BAR: [int, ..4] = [32, 32, 32, 32];
+static FOO: [int; 4] = [32; 4];
+static BAR: [int; 4] = [32, 32, 32, 32];
pub fn main() {
assert!(FOO == BAR);
#![feature(slicing_syntax)]
pub fn main() {
- let x = [ [true], ..512 ];
- let y = [ 0i, ..1 ];
+ let x = [ [true]; 512 ];
+ let y = [ 0i; 1 ];
print!("[");
for xi in x.iter() {
--- /dev/null
+// 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.
+
+// Test that we can use `Self` types in impls in the expected way.
+
+struct Foo;
+
+// Test uses on inherant impl.
+impl Foo {
+ fn foo(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
+ Foo
+ }
+}
+
+// Test uses when implementing a trait and with a type parameter.
+pub struct Baz<X> {
+ pub f: X,
+}
+
+trait Bar<X> {
+ fn bar(x: Self, y: &Self, z: Box<Self>) -> Self;
+}
+
+impl Bar<int> for Box<Baz<int>> {
+ fn bar(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
+ box Baz { f: 42 }
+ }
+}
+
+fn main() {
+ let _: Foo = Foo::foo(Foo, &Foo, box Foo);
+ let _: Box<Baz<int>> = Bar::bar(box Baz { f: 42 },
+ &box Baz { f: 42 },
+ box box Baz { f: 42 });
+}
pub fn main() {
unsafe {
let _x: Foo = mem::uninitialized();
- let _x: [Foo, ..2] = mem::uninitialized();
+ let _x: [Foo; 2] = mem::uninitialized();
}
}
unsafe {
struct Foo_<T> {
- f: [T, ..3]
+ f: [T; 3]
}
let data = box Foo_{f: [1i32, 2, 3] };
struct Baz_ {
f1: uint,
- f2: [u8, ..5],
+ f2: [u8; 5],
}
let data = box Baz_{ f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] };
}
unsafe fn check<T>(expected: &str, f: |*mut c_char| -> T) {
- let mut x = [0 as c_char, ..50];
+ let mut x = [0 as c_char; 50];
f(&mut x[0] as *mut c_char);
let res = CString::new(&x[0], false);
assert_eq!(expected, res.as_str().unwrap());
// except according to those terms.
pub fn main() {
- // Tests for indexing into box/& [T, ..n]
- let x: [int, ..3] = [1, 2, 3];
- let mut x: Box<[int, ..3]> = box x;
+ // Tests for indexing into box/& [T; n]
+ let x: [int; 3] = [1, 2, 3];
+ let mut x: Box<[int; 3]> = box x;
assert!(x[0] == 1);
assert!(x[1] == 2);
assert!(x[2] == 3);
assert!(x[1] == 45);
assert!(x[2] == 3);
- let mut x: [int, ..3] = [1, 2, 3];
- let x: &mut [int, ..3] = &mut x;
+ let mut x: [int; 3] = [1, 2, 3];
+ let x: &mut [int; 3] = &mut x;
assert!(x[0] == 1);
assert!(x[1] == 2);
assert!(x[2] == 3);
use std::mem::size_of;
pub fn main() {
- let x: [int, ..4] = [1, 2, 3, 4];
+ let x: [int; 4] = [1, 2, 3, 4];
assert_eq!(x[0], 1);
assert_eq!(x[1], 2);
assert_eq!(x[2], 3);
assert_eq!(x[3], 4);
- assert_eq!(size_of::<[u8, ..4]>(), 4u);
+ assert_eq!(size_of::<[u8; 4]>(), 4u);
// FIXME #10183
// FIXME #18069
//if cfg!(target_word_size = "64") {
- // assert_eq!(size_of::<[u8, ..(1 << 32)]>(), (1u << 32));
+ // assert_eq!(size_of::<[u8; (1 << 32)]>(), (1u << 32));
//}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub fn main() { let _a = [0i, ..1 as uint]; }
+pub fn main() { let _a = [0i; 1 as uint]; }
const REPEATS: uint = 5;
const MAX_LEN: uint = 32;
-static drop_counts: [AtomicUint, .. MAX_LEN] =
+static drop_counts: [AtomicUint; MAX_LEN] =
// FIXME #5244: AtomicUint is not Copy.
[
INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT,
--- /dev/null
+// 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.
+
+trait TheTrait { }
+
+impl TheTrait for &'static int { }
+
+fn foo<'a,T>(_: &'a T) where &'a T : TheTrait { }
+
+fn bar<T>(_: &'static T) where &'static T : TheTrait { }
+
+fn main() {
+ static x: int = 1;
+ foo(&x);
+ bar(&x);
+}
--- /dev/null
+// 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.
+
+trait Foo<T> {}
+
+trait Bar<A> {
+ fn method<B>(&self) where A: Foo<B>;
+}
+
+struct S;
+struct X;
+
+impl Foo<S> for X {}
+
+impl Bar<X> for int {
+ fn method<U>(&self) where X: Foo<U> {
+ }
+}
+
+fn main() {
+ 1.method::<S>();
+}
+
--- /dev/null
+// 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.
+
+struct A<'a, 'b> where 'a : 'b { x: &'a int, y: &'b int }
+
+fn main() {
+ let x = 1i;
+ let y = 1i;
+ let a = A { x: &x, y: &y };
+}
--- /dev/null
+// 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.
+
+// Test that a where clause attached to a method allows us to add
+// additional constraints to a parameter out of scope.
+
+struct Foo<T> {
+ value: T
+}
+
+impl<T> Foo<T> {
+ fn equals(&self, u: &Foo<T>) -> bool where T : Eq {
+ self.value == u.value
+ }
+}
+
+fn main() {
+ let x = Foo { value: 1i };
+ let y = Foo { value: 2i };
+ println!("{}", x.equals(&x));
+ println!("{}", x.equals(&y));
+}
--- /dev/null
+// 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.
+
+fn equal<T>(_: &T, _: &T) -> bool where int : Eq {
+ true
+}
+
+fn main() {
+ equal(&0i, &0i);
+}