diff options
| author | Brian Anderson <banderson@mozilla.com> | 2013-07-02 17:36:58 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2013-07-03 14:49:13 -0700 |
| commit | 1098d6980b13dc00e3f20deae987423e3bcae9ce (patch) | |
| tree | 4d6cfd62f1d0d3298d4144aebd6c81c91edea9dc | |
| parent | f8a4d09f7efb618ca3f8b70374e158504cb33cb0 (diff) | |
| parent | ab34864a304fa364dc91bf16988e272e93de8d62 (diff) | |
| download | rust-1098d6980b13dc00e3f20deae987423e3bcae9ce.tar.gz rust-1098d6980b13dc00e3f20deae987423e3bcae9ce.zip | |
Merge remote-tracking branch 'mozilla/master'
Conflicts: src/libextra/test.rs src/libstd/at_vec.rs src/libstd/cleanup.rs src/libstd/rt/comm.rs src/libstd/rt/global_heap.rs src/libstd/task/spawn.rs src/libstd/unstable/lang.rs src/libstd/vec.rs src/rt/rustrt.def.in src/test/run-pass/extern-pub.rs
765 files changed, 23479 insertions, 17295 deletions
diff --git a/.gitmodules b/.gitmodules index 52ece628c57..c8442616179 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,8 @@ [submodule "src/llvm"] path = src/llvm url = https://github.com/brson/llvm.git + branch = master [submodule "src/libuv"] path = src/libuv url = https://github.com/brson/libuv.git + branch = master diff --git a/AUTHORS.txt b/AUTHORS.txt index 2f80341e21a..e742886961f 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -10,9 +10,11 @@ Aleksander Balicki <balicki.aleksander@gmail.com> Alex Crichton <alex@alexcrichton.com> Alex Rønne Petersen <alex@lycus.org> Alexander Stavonin <a.stavonin@gmail.com> +Alexei Sholik <alcosholik@gmail.com> Andreas Gal <gal@mozilla.com> Andrew Dunham <andrew@du.nham.ca> Andrew Paseltiner <apaseltiner@gmail.com> +Anthony Juckel <ajuckel@gmail.com> Arkaitz Jimenez <arkaitzj@gmail.com> Armin Ronacher <armin.ronacher@active-4.com> Ashok Gautham <ScriptDevil@gmail.com> @@ -29,23 +31,32 @@ Benjamin Kircher <benjamin.kircher@gmail.com> Benjamin Peterson <benjamin@python.org> Bilal Husain <bilal@bilalhusain.com> Bill Fallon <bill.fallon@robos.li> +Bill Myers <bill_myers@outlook.com> +Bill Wendling <wendling@apple.com> +Björn Steinbrink <bsteinbr@gmail.com> Brendan Eich <brendan@mozilla.org> Brendan Zabarauskas <bjzaba@yahoo.com.au> Brett Cannon <brett@python.org> Brian Anderson <banderson@mozilla.com> Brian J. Burg <burg@cs.washington.edu> Brian Leibig <brian.leibig@gmail.com> +Bryan Dunsmore <dunsmoreb@gmail.com> +Caitlin Potter <snowball@defpixel.com> Chris Double <chris.double@double.co.nz> Chris Peterson <cpeterson@mozilla.com> Chris Pressey <cpressey@gmail.com> Cody Schroeder <codys@cs.washington.edu> +Corey Richardson <corey@octayn.net> Damian Gryski <damian@gryski.com> Damien Grassart <damien@grassart.com> Damien Schoof <damien.schoof@gmail.com> Daniel Brooks <db48x@db48x.net> +Daniel Farina <daniel@fdr.io> +Dan Luu <danluu@gmail.com> Daniel Luz <dev@mernen.com> Daniel Micay <danielmicay@gmail.com> Daniel Patterson <dbp@riseup.net> +Daniel Ralston <Wubbulous@gmail.com> Daniel Ursache Dogariu <contact@danniel.net> Dave Herman <dherman@mozilla.com> David Forsythe <dforsythe@gmail.com> @@ -62,17 +73,21 @@ Eric Holmes <eric@ejholmes.net> Erick Tryzelaar <erick.tryzelaar@gmail.com> Erik Rose <erik@mozilla.com> Evan McClanahan <evan@evanmcc.com> +Fedor Indutny <fedor.indutny@gmail.com> Felix S. Klock II <pnkfelix@pnkfx.org> Francisco Souza <f@souza.cc> Franklin Chen <franklinchen@franklinchen.com> +Gábor Horváth <xazax.hun@gmail.com> Gabriel <g2p.code@gmail.com> Gareth Daniel Smith <garethdanielsmith@gmail.com> +gifnksm <makoto.nksm@gmail.com> Glenn Willen <gwillen@nerdnet.org> Gonçalo Cabrita <_@gmcabrita.com> Graham Fawcett <fawcett@uwindsor.ca> Grahame Bowland <grahame@angrygoats.net> Haitao Li <lihaitao@gmail.com> hansjorg <hansjorg@gmail.com> +Herman J. Radtke III <hermanradtke@gmail.com> Huon Wilson <dbau.pp+github@gmail.com> Ian D. Bollinger <ian.bollinger@gmail.com> Ilyong Cho <ilyoan@gmail.com> @@ -83,6 +98,7 @@ Jacob Harris Cryer Kragh <jhckragh@gmail.com> Jacob Parker <j3parker@csclub.uwaterloo.ca> Jakub Wieczorek <jakubw@jakubw.net> James Miller <bladeon@gmail.com> +James Tranovich <james@openhorizonlabs.com> Jason Orendorff <jorendorff@mozilla.com> Jed Davis <jld@panix.com> Jeff Balogh <jbalogh@mozilla.com> @@ -92,6 +108,7 @@ Jeffrey Yasskin <jyasskin@gmail.com> Jeong YunWon <jeong@youknowone.org> Jens Nockert <jens@nockert.se> Jesse Jones <jesse9jones@gmail.com> +Jesse Luehrs <doy@tozt.net> Jesse Ruderman <jruderman@gmail.com> Jihyun Yu <jihyun@nclab.kaist.ac.kr> Jim Blandy <jimb@red-bean.com> @@ -104,14 +121,18 @@ Jonathan Sternberg <jonathansternberg@gmail.com> Josh Matthews <josh@joshmatthews.net> Joshua Clark <joshua.clark@txstate.edu> Joshua Wise <joshua@joshuawise.com> +Junyoung Cho <june0.cho@samsung.com> Jyun-Yan You <jyyou@cs.nctu.edu.tw> Kang Seonghoon <kang.seonghoon@mearie.org> Kelly Wilson <wilsonk@cpsc.ucalgary.ca> Kevin Atkinson <kevina@cs.utah.edu> +Kevin Ballard <kevin@sb.org> Kevin Cantu <me@kevincantu.org> +klutzy <klutzytheklutzy@gmail.com> Kyeongwoon Lee <kyeongwoon.lee@samsung.com> Laurent Bonnans <bonnans.l@gmail.com> Lawrence Velázquez <larryv@alum.mit.edu> +Leah Hanson <astrieanna@gmail.com> Lennart Kudling <github@kudling.de> Lindsey Kuper <lindsey@composition.al> Luca Bruno <lucab@debian.org> @@ -122,6 +143,7 @@ Margaret Meyerhofer <mmeyerho@andrew.cmu.edu> Marijn Haverbeke <marijnh@gmail.com> Mark Lacey <641@rudkx.com> Mark Vian <mrv.caseus@gmail.com> +Marti Raudsepp <marti@juffo.org> Martin DeMello <martindemello@gmail.com> Marvin Löbel <loebel.marvin@gmail.com> Matt Brubeck <mbrubeck@limpet.net> @@ -143,43 +165,64 @@ Patrick Walton <pwalton@mozilla.com> Patrik Kårlin <patrik.karlin@gmail.com> Paul Stansifer <paul.stansifer@gmail.com> Paul Woolcock <pwoolcoc+github@gmail.com> +Pavel Panchekha <me@pavpanchekha.com> Peter Hull <peterhull90@gmail.com> Peter Williams <peter@newton.cx> Philipp Brüschweiler <blei42@gmail.com> Rafael Ávila de Espíndola <respindola@mozilla.com> +Ralph Bodenner <rkbodenner+github@gmail.com> Ralph Giles <giles@thaumas.net> +Ramkumar Ramachandra <artagnon@gmail.com> Reuben Morais <reuben.morais@gmail.com> Rick Waldron <waldron.rick@gmail.com> Rob Arnold <robarnold@cs.cmu.edu> +Rob Hoelz <rob@hoelz.ro> Roland Tanglao <roland@rolandtanglao.com> +Ron Dahlgren <ronald.dahlgren@gmail.com> Roy Frostig <rfrostig@mozilla.com> Ryan Scheel <ryan.havvy@gmail.com> +Samuel Chase <samebchase@gmail.com> +Sander Mathijs van Veen <smvv@kompiler.org> +Sangeun Kim <sammy.kim@samsung.com> +Saurabh Anand <saurabhanandiit@gmail.com> +Sean Moon <ssamoon@ucla.edu> Sean Stangl <sstangl@mozilla.com> Sebastian N. Fernandez <cachobot@gmail.com> Seth Pink <sethpink@gmail.com> Seo Sanghyeon <sanxiyn@gmail.com> sevrak <sevrak@rediffmail.com> +SiegeLord <slabode@aim.com> Simon Barber-Dueck <sbarberdueck@gmail.com> Simon Sapin <simon@exyr.org> startling <tdixon51793@gmail.com> Stefan Plantikow <stefan.plantikow@googlemail.com> Steve Klabnik <steve@steveklabnik.com> +Steven De Coeyer <steven@banteng.be> +Steven Fackler <sfackler@gmail.com> +Steven Stewart-Gallus <sstewartgallus00@langara.bc.ca> Taras Shpot <mrshpot@gmail.com> Ted Horst <ted.horst@earthlink.net> Thad Guidry <thadguidry@gmail.com> +Thomas Daede <daede003@umn.edu> Tim Chevalier <chevalier@alum.wellesley.edu> Tim Taubert <tim@timtaubert.de> Tom Lee <github@tomlee.co> +Tommy M. McGuire <mcguire@crsr.net> Tomoki Aonuma <uasi@99cm.org> Tony Young <tony@rfw.name> Trinick <slicksilver555@mac.com> Tycho Sci <tychosci@gmail.com> Tyler Bindon <martica@martica.org> +Uwe Dauernheim <uwe@dauernheim.net> +Vadim Chugunov <vadimcn@gmail.com> Viktor Dahl <pazaconyoman@gmail.com> Vincent Belliard <vincent@famillebelliard.fr> +Vivek Galatage <vivekgalatage@gmail.com> Wade Mealing <wmealing@gmail.com> William Ting <william.h.ting@gmail.com> Yasuhiro Fujii <y-fujii@mimosa-pudica.net> Young-il Choi <duddlf.choi@samsung.com> +Youngmin Yoo <youngmin.yoo@samsung.com> Youngsoo Son <ysson83@gmail.com> Zack Corr <zack@z0w0.me> +zofrex <zofrex@gmail.com> diff --git a/Makefile.in b/Makefile.in index baae56c4f40..de30113ca4b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -139,8 +139,11 @@ endif # version-string calculation CFG_GIT_DIR := $(CFG_SRC_DIR).git -CFG_RELEASE = 0.6 +CFG_RELEASE = 0.7 CFG_VERSION = $(CFG_RELEASE) +# windows exe's need numeric versions - don't use anything but +# numbers and dots here +CFG_VERSION_WIN = 0.7 ifneq ($(wildcard $(CFG_GIT)),) ifneq ($(wildcard $(CFG_GIT_DIR)),) @@ -239,29 +242,29 @@ $(foreach target,$(CFG_TARGET_TRIPLES),\ # Standard library variables ###################################################################### -STDLIB_CRATE := $(S)src/libstd/core.rc +STDLIB_CRATE := $(S)src/libstd/std.rs STDLIB_INPUTS := $(wildcard $(addprefix $(S)src/libstd/, \ - core.rc *.rs */*.rs */*/*rs */*/*/*rs)) + *.rs */*.rs */*/*rs */*/*/*rs)) ###################################################################### # Extra library variables ###################################################################### -EXTRALIB_CRATE := $(S)src/libextra/std.rc +EXTRALIB_CRATE := $(S)src/libextra/extra.rs EXTRALIB_INPUTS := $(wildcard $(addprefix $(S)src/libextra/, \ - std.rc *.rs */*.rs)) + *.rs */*.rs)) ###################################################################### # rustc crate variables ###################################################################### -COMPILER_CRATE := $(S)src/librustc/rustc.rc +COMPILER_CRATE := $(S)src/librustc/rustc.rs COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/librustc/, \ - rustc.rc *.rs */*.rs */*/*.rs */*/*/*.rs)) + *.rs */*.rs */*/*.rs */*/*/*.rs)) -LIBSYNTAX_CRATE := $(S)src/libsyntax/syntax.rc +LIBSYNTAX_CRATE := $(S)src/libsyntax/syntax.rs LIBSYNTAX_INPUTS := $(wildcard $(addprefix $(S)src/libsyntax/, \ - syntax.rc *.rs */*.rs */*/*.rs)) + *.rs */*.rs */*/*.rs)) DRIVER_CRATE := $(S)src/driver/driver.rs @@ -311,6 +314,7 @@ $(foreach host,$(CFG_HOST_TRIPLES), \ export CFG_SRC_DIR export CFG_BUILD_DIR export CFG_VERSION +export CFG_VERSION_WIN export CFG_BUILD_TRIPLE export CFG_LLVM_ROOT export CFG_ENABLE_MINGW_CROSS @@ -536,10 +540,19 @@ ALL_TARGET_RULES = $(foreach target,$(CFG_TARGET_TRIPLES), \ $(foreach host,$(CFG_HOST_TRIPLES), \ all-target-$(target)-host-$(host))) -all: $(ALL_TARGET_RULES) $(GENERATED) docs +all: rustllvm/llvm-auto-clean-stamp \ + $(ALL_TARGET_RULES) $(GENERATED) docs endif +# This is used to independently force an LLVM clean rebuild +# when we changed something not otherwise captured by builtin +# dependencies. In these cases, commit a change that touches +# the stamp in the source dir. +rustllvm/llvm-auto-clean-stamp: $(S)src/rustllvm/llvm-auto-clean-trigger + $(Q)$(MAKE) clean-llvm + touch $@ + ###################################################################### # Re-configuration diff --git a/README.md b/README.md index 65f5942fd16..f01ed1958c6 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,9 @@ packages: Assuming you're on a relatively modern *nix system and have met the prerequisites, something along these lines should work. - $ curl -O http://static.rust-lang.org/dist/rust-0.6.tar.gz - $ tar -xzf rust-0.6.tar.gz - $ cd rust-0.6 + $ curl -O http://static.rust-lang.org/dist/rust-0.7.tar.gz + $ tar -xzf rust-0.7.tar.gz + $ cd rust-0.7 $ ./configure $ make && make install @@ -59,8 +59,8 @@ When complete, `make install` will place several programs into API-documentation tool, and `rustpkg`, the Rust package manager and build system. [wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust -[tarball]: http://static.rust-lang.org/dist/rust-0.6.tar.gz -[win-exe]: http://static.rust-lang.org/dist/rust-0.6-install.exe +[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz +[win-exe]: http://static.rust-lang.org/dist/rust-0.7-install.exe ## License diff --git a/RELEASES.txt b/RELEASES.txt index d099b1336df..33f749d0010 100644 --- a/RELEASES.txt +++ b/RELEASES.txt @@ -1,79 +1,108 @@ Version 0.7 (July 2013) ----------------------- - * ??? changes, numerous bugfixes - - * Syntax changes - * `use mod` is no longer valid. - * `fail!` and `assert!` accept `~str`, `&'static str` or `fmt!`-style - argument list. - * `Encodable`, `Decodable`, `TotalOrd`, `TotalEq`, `DeepClone` can all - be automatically derived with `#[deriving(...)]`. - * The `Durable` trait is replaced with the `'static` bounds. - * At long last, 'argument modes' no longer exist. - * The `bytes!` macro returns a vector of bytes for string, u8, char, - and unsuffixed integer literals. + * ~2000 changes, numerous bugfixes - * Semantic changes + * Language + * `impl`s no longer accept a visibility qualifier. Put them on methods + instead. * The borrow checker has been rewritten with flow-sensitivity, fixing many bugs and inconveniences. * The `self` parameter no longer implicitly means `&'self self`, and can be explicitly marked with a lifetime. - * Structs with the `#[packed]` attribute have byte alignment and - no padding between fields. + * Overloadable compound operators (`+=`, etc.) have been temporarily + removed due to bugs. * The `for` loop protocol now requires `for`-iterators to return `bool` so they compose better. + * The `Durable` trait is replaced with the `'static` bounds. + * Trait default methods work more often. + * Structs with the `#[packed]` attribute have byte alignment and + no padding between fields. + * Type parameters bound by `Copy` must now be copied explicitly with + the `copy` keyword. + * It is now illegal to move out of a dereferenced unsafe pointer. * `Option<~T>` is now represented as a nullable pointer. * `@mut` does dynamic borrow checks correctly. - * Macros TODO * The `main` function is only detected at the topmost level of the crate. The `#[main]` attribute is still valid anywhere. * Struct fields may no longer be mutable. Use inherited mutability. - * The `#[non_owned]` attribute makes a type that would otherwise be - `Owned`, not. TODO this may change to non_send before 0.7 - * The `#[mutable]` attribute makes a type that would otherwise be - `Const`, note. TODO this may change to non_freeze before 0.7 + * The `#[no_send]` attribute makes a type that would otherwise be + `Send`, not. + * The `#[no_freeze]` attribute makes a type that would otherwise be + `Freeze`, not. * Unbounded recursion will abort the process after reaching the limit - specified by the `RUST_MAX_STACK` environment variable. + specified by the `RUST_MAX_STACK` environment variable (default: 1GB). * The `vecs_implicitly_copyable` lint mode has been removed. Vectors are never implicitly copyable. + * `#[static_assert]` makes compile-time assertions about static bools. + * At long last, 'argument modes' no longer exist. + * The rarely used `use mod` statement no longer exists. + + * Syntax extensions + * `fail!` and `assert!` accept `~str`, `&'static str` or `fmt!`-style + argument list. + * `Encodable`, `Decodable`, `Ord`, `TotalOrd`, `TotalEq`, `DeepClone`, + `Rand`, `Zero` and `ToStr` can all be automatically derived with + `#[deriving(...)]`. + * The `bytes!` macro returns a vector of bytes for string, u8, char, + and unsuffixed integer literals. * Libraries * The `core` crate was renamed to `std`. * The `std` crate was renamed to `extra`. - * `std::mut` removed. + * More and improved documentation. + * std: `iterator` module for external iterator objects. + * Many old-style (internal, higher-order function) iterators replaced by + implementations of `Iterator`. + * std: Many old internal vector and string iterators, + incl. `any`, `all`. removed. + * std: The `finalize` method of `Drop` renamed to `drop`. * std: The prelude no longer reexports any modules, only types and traits. * std: Prelude additions: `print`, `println`, `FromStr`, `ApproxEq`, `Equiv`, `Iterator`, `IteratorUtil`, many numeric traits, many tuple traits. - * std: `iterator` module for external iterator objects. - * std: new numeric traits: `Fractional`, `Real`, `RealExt`, `Integer`, `Ratio`, + * std: New numeric traits: `Fractional`, `Real`, `RealExt`, `Integer`, `Ratio`, `Algebraic`, `Trigonometric`, `Exponential`, `Primitive`. * std: Tuple traits and accessors defined for up to 12-tuples, e.g. `(0, 1, 2).n2()` or `(0, 1, 2).n2_ref()`. - * std: many types implement `Clone` - tuples, @, @mut. TODO + * std: Many types implement `Clone`. * std: `path` type renamed to `Path`. - * std: Many standalone functions removed in favor of methods in - `vec`, `str`. In the future methods will also work as functions. - * std: `reinterpret_cast` removed. Used `transmute`. + * std: `mut` module and `Mut` type removed. + * std: Many standalone functions removed in favor of methods and iterators + in `vec`, `str`. In the future methods will also work as functions. + * std: `reinterpret_cast` removed. Use `transmute`. * std: ascii string handling in `std::ascii`. * std: `Rand` is implemented for ~/@. * std: `run` module for spawning processes overhauled. * std: Various atomic types added to `unstable::atomic`. + * std: Various types implement `Zero`. * std: `LinearMap` and `LinearSet` renamed to `HashMap` and `HashSet`. + * std: Borrowed pointer functions moved from `ptr` to `borrow`. * std: Added `os::mkdir_recursive`. * std: Added `os::glob` function performs filesystems globs. * std: `FuzzyEq` renamed to `ApproxEq`. * std: `Map` now defines `pop` and `swap` methods. + * std: `Cell` constructors converted to static methods. + * extra: `rc` module adds the reference counted pointers, `Rc` and `RcMut`. * extra: `flate` module moved from `std` to `extra`. - * extra: `FileInput` implements `std::io::Reader`. + * extra: `fileinput` module for iterating over a series of files. * extra: `Complex` number type and `complex` module. * extra: `Rational` number type and `rational` module. * extra: `BigInt`, `BigUint` implement numeric and comparison traits. * extra: `term` uses terminfo now, is more correct. + * extra: `arc` functions converted to methods. + * extra: Implementation of fixed output size variations of SHA-2. * Tooling - * `unused_unsafe` lint mode for detecting unnecessary `unsafe` blocks. - * `unused_mut` lint mode for identifying unused `mut` qualifiers. + * `unused_variable` lint mode for unused variables (default: warn). + * `unused_unsafe` lint mode for detecting unnecessary `unsafe` blocks + (default: warn). + * `unused_mut` lint mode for identifying unused `mut` qualifiers + (default: warn). + * `dead_assignment` lint mode for unread variables (default: warn). + * `unnecessary_allocation` lint mode detects some heap allocations that are + immediately borrowed so could be written without allocating (default: warn). + * `missing_doc` lint mode (default: allow). + * `unreachable_code` lint mode (default: warn). * The `rusti` command has been rewritten and a number of bugs addressed. * rustc outputs in color on more terminals. * rustc accepts a `--link-args` flag to pass arguments to the linker. @@ -82,12 +111,7 @@ Version 0.7 (July 2013) dynamic borrowcheck failures for debugging. * rustdoc has a nicer stylesheet. * Various improvements to rustdoc. - - * Other - * More and improved library documentation. - * Various improvements on ARM and Android. - * Various improvements to MIPS backend. - * jemalloc is the Rust allocator. + * Improvements to rustpkg (see the detailed release notes). Version 0.6 (April 2013) ------------------------ diff --git a/configure b/configure index 1c658af9fee..d0a98fbfa75 100755 --- a/configure +++ b/configure @@ -834,9 +834,7 @@ do LLVM_TARGET="--target=$t" # Disable unused LLVM features - LLVM_OPTS="$LLVM_DBG_OPTS --disable-docs \ - --enable-bindings=none --disable-threads \ - --disable-pthreads" + LLVM_OPTS="$LLVM_DBG_OPTS --disable-docs --enable-bindings=none" case "$CFG_C_COMPILER" in ("ccache clang") diff --git a/doc/README b/doc/README index c3bb28a9e85..bb6ab77a802 100644 --- a/doc/README +++ b/doc/README @@ -1,10 +1,25 @@ -The markdown docs are only generated by make when node is installed (use -`make doc`). If you don't have node installed you can generate them yourself. -Unfortunately there's no real standard for markdown and all the tools work -differently. pandoc is one that seems to work well. +Pandoc, a universal document converter, is required to generate docs as HTML +from Rust's source code. It's available for most platforms here: +http://johnmacfarlane.net/pandoc/installing.html -To generate an html version of a doc do something like: -pandoc --from=markdown --to=html --number-sections -o build/doc/rust.html doc/rust.md && git web--browse build/doc/rust.html +Node.js (http://nodejs.org/) is also required for generating HTML from +the Markdown docs (reference manual, tutorials, etc.) distributed with +this git repository. + +To generate all the docs, run `make docs` from the root of the repository. +This will convert the distributed Markdown docs to HTML and generate HTML doc +for the 'std' and 'extra' libraries. + +To generate HTML documentation from one source file/crate, do something like: + + rustdoc --output-dir html-doc/ --output-format html ../src/libstd/path.rs + +(This, of course, requires that you've built/installed the `rustdoc` tool.) + +To generate an HTML version of a doc from Markdown, without having Node.js +installed, do something like: + + pandoc --from=markdown --to=html --number-sections -o rust.html rust.md The syntax for pandoc flavored markdown can be found at: http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown diff --git a/doc/rust.md b/doc/rust.md index 9edbc44d6c2..cc53d7d17a2 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -882,11 +882,11 @@ the function name. ~~~~ {.xfail-test} fn iter<T>(seq: &[T], f: &fn(T)) { - for seq.each |elt| { f(elt); } + for seq.iter().advance |elt| { f(elt); } } fn map<T, U>(seq: &[T], f: &fn(T) -> U) -> ~[U] { let mut acc = ~[]; - for seq.each |elt| { acc.push(f(elt)); } + for seq.iter().advance |elt| { acc.push(f(elt)); } acc } ~~~~ @@ -1561,8 +1561,11 @@ Supported traits for `deriving` are: * `Clone` and `DeepClone`, to perform (deep) copies. * `IterBytes`, to iterate over the bytes in a data type. * `Rand`, to create a random instance of a data type. +* `Zero`, to create an zero (or empty) instance of a data type. * `ToStr`, to convert to a string. For a type with this instance, - `obj.to_str()` has the same output as `fmt!("%?", obj)`. + `obj.to_str()` has similar output as `fmt!("%?", obj)`, but it differs in that + each constituent field of the type must also implement `ToStr` and will have + `field.to_str()` invoked to build up the result. # Statements and expressions @@ -2326,7 +2329,7 @@ An example of a for loop over the contents of a vector: let v: &[foo] = &[a, b, c]; -for v.each |e| { +for v.iter().advance |e| { bar(*e); } ~~~~ @@ -2617,7 +2620,7 @@ assert!(b != "world"); The vector type constructor represents a homogeneous array of values of a given type. A vector has a fixed size. -(Operations like `vec::push` operate solely on owned vectors.) +(Operations like `vec.push` operate solely on owned vectors.) A vector type can be annotated with a _definite_ size, written with a trailing asterisk and integer literal, such as `[int * 10]`. Such a definite-sized vector type is a first-class type, since its size is known statically. @@ -2859,13 +2862,13 @@ call to the method `make_string`. Types in Rust are categorized into kinds, based on various properties of the components of the type. The kinds are: -`Const` +`Freeze` : Types of this kind are deeply immutable; they contain no mutable memory locations directly or indirectly via pointers. -`Owned` +`Send` : Types of this kind can be safely sent between tasks. This kind includes scalars, owning pointers, owned closures, and - structural types containing only other owned types. All `Owned` types are `Static`. + structural types containing only other owned types. All `Send` types are `Static`. `Static` : Types of this kind do not contain any borrowed pointers; this can be a useful guarantee for code that breaks borrowing assumptions using [`unsafe` operations](#unsafe-functions). @@ -2879,7 +2882,7 @@ The kinds are: trait provides a single method `finalize` that takes no parameters, and is run when values of the type are dropped. Such a method is called a "destructor", and are always executed in "top-down" order: a value is completely destroyed - before any of the values it owns run their destructors. Only `Owned` types + before any of the values it owns run their destructors. Only `Send` types that do not implement `Copy` can implement `Drop`. > **Note:** The `finalize` method may be renamed in future versions of Rust. @@ -2965,10 +2968,10 @@ frame they are allocated within. A task owns all memory it can *safely* reach through local variables, as well as managed, owning and borrowed pointers. -When a task sends a value that has the `Owned` trait to another task, +When a task sends a value that has the `Send` trait to another task, it loses ownership of the value sent and can no longer refer to it. This is statically guaranteed by the combined use of "move semantics", -and the compiler-checked _meaning_ of the `Owned` trait: +and the compiler-checked _meaning_ of the `Send` trait: it is only instantiated for (transitively) sendable kinds of data constructor and pointers, never including managed or borrowed pointers. @@ -3113,7 +3116,7 @@ These include: - read-only and read-write shared variables with various safe mutual exclusion patterns - simple locks and semaphores -When such facilities carry values, the values are restricted to the [`Owned` type-kind](#type-kinds). +When such facilities carry values, the values are restricted to the [`Send` type-kind](#type-kinds). Restricting communication interfaces to this kind ensures that no borrowed or managed pointers move between tasks. Thus access to an entire data structure can be mediated through its owning "root" value; no further locking or copying is required to avoid data races within the substructure of such a value. diff --git a/doc/rustpkg.md b/doc/rustpkg.md index b12bce5a0af..506fc2ad15a 100644 --- a/doc/rustpkg.md +++ b/doc/rustpkg.md @@ -95,12 +95,22 @@ When building a package that is in a `git` repository, When building a package that is not under version control, or that has no tags, `rustpkg` assumes the intended version is 0.1. +# Dependencies + +rustpkg infers dependencies from `extern mod` directives. +Thus, there should be no need to pass a `-L` flag to rustpkg to tell it where to find a library. +(In the future, it will also be possible to write an `extern mod` directive referring to a remote package.) + # Custom build scripts A file called `pkg.rs` at the root level in a workspace is called a *package script*. If a package script exists, rustpkg executes it to build the package rather than inferring crates as described previously. +Inside `pkg.rs`, it's possible to call back into rustpkg to finish up the build. +`rustpkg::api` contains functions to build, install, or clean libraries and executables +in the way rustpkg normally would without custom build logic. + # Command reference ## build diff --git a/doc/tutorial-borrowed-ptr.md b/doc/tutorial-borrowed-ptr.md index 90b8e1051eb..1da1d046878 100644 --- a/doc/tutorial-borrowed-ptr.md +++ b/doc/tutorial-borrowed-ptr.md @@ -234,7 +234,7 @@ would therefore be subject to garbage collection. A heap box that is unrooted is one such that no pointer values in the heap point to it. It would violate memory safety for the box that was originally assigned to `x` to be garbage-collected, since a non-heap -pointer---`y`---still points into it. +pointer *`y`* still points into it. > ***Note:*** Our current implementation implements the garbage collector > using reference counting and cycle detection. @@ -475,7 +475,7 @@ but otherwise it requires that the data reside in immutable memory. # Returning borrowed pointers -So far, all of the examples we've looked at use borrowed pointers in a +So far, all of the examples we have looked at, use borrowed pointers in a “downward” direction. That is, a method or code block creates a borrowed pointer, then uses it within the same scope. It is also possible to return borrowed pointers as the result of a function, but @@ -509,7 +509,7 @@ guaranteed to refer to a distinct lifetime from the lifetimes of all other parameters. Named lifetimes that appear in function signatures are conceptually -the same as the other lifetimes we've seen before, but they are a bit +the same as the other lifetimes we have seen before, but they are a bit abstract: they don’t refer to a specific expression within `get_x()`, but rather to some expression within the *caller of `get_x()`*. The lifetime `r` is actually a kind of *lifetime parameter*: it is defined diff --git a/doc/tutorial-container.md b/doc/tutorial-container.md new file mode 100644 index 00000000000..66bd0b9c131 --- /dev/null +++ b/doc/tutorial-container.md @@ -0,0 +1,207 @@ +% Containers and iterators + +# Containers + +The container traits are defined in the `std::container` module. + +## Unique and managed vectors + +Vectors have `O(1)` indexing and removal from the end, along with `O(1)` +amortized insertion. Vectors are the most common container in Rust, and are +flexible enough to fit many use cases. + +Vectors can also be sorted and used as efficient lookup tables with the +`std::vec::bsearch` function, if all the elements are inserted at one time and +deletions are unnecessary. + +## Maps and sets + +Maps are collections of unique keys with corresponding values, and sets are +just unique keys without a corresponding value. The `Map` and `Set` traits in +`std::container` define the basic interface. + +The standard library provides three owned map/set types: + +* `std::hashmap::HashMap` and `std::hashmap::HashSet`, requiring the keys to + implement `Eq` and `Hash` +* `std::trie::TrieMap` and `std::trie::TrieSet`, requiring the keys to be `uint` +* `extra::treemap::TreeMap` and `extra::treemap::TreeSet`, requiring the keys + to implement `TotalOrd` + +These maps do not use managed pointers so they can be sent between tasks as +long as the key and value types are sendable. Neither the key or value type has +to be copyable. + +The `TrieMap` and `TreeMap` maps are ordered, while `HashMap` uses an arbitrary +order. + +Each `HashMap` instance has a random 128-bit key to use with a keyed hash, +making the order of a set of keys in a given hash table randomized. Rust +provides a [SipHash](https://131002.net/siphash/) implementation for any type +implementing the `IterBytes` trait. + +## Double-ended queues + +The `extra::deque` module implements a double-ended queue with `O(1)` amortized +inserts and removals from both ends of the container. It also has `O(1)` +indexing like a vector. The contained elements are not required to be copyable, +and the queue will be sendable if the contained type is sendable. + +## Priority queues + +The `extra::priority_queue` module implements a queue ordered by a key. The +contained elements are not required to be copyable, and the queue will be +sendable if the contained type is sendable. + +Insertions have `O(log n)` time complexity and checking or popping the largest +element is `O(1)`. Converting a vector to a priority queue can be done +in-place, and has `O(n)` complexity. A priority queue can also be converted to +a sorted vector in-place, allowing it to be used for an `O(n log n)` in-place +heapsort. + +# Iterators + +## Iteration protocol + +The iteration protocol is defined by the `Iterator` trait in the +`std::iterator` module. The minimal implementation of the trait is a `next` +method, yielding the next element from an iterator object: + +~~~ +/// An infinite stream of zeroes +struct ZeroStream; + +impl Iterator<int> for ZeroStream { + fn next(&mut self) -> Option<int> { + Some(0) + } +} +~~~~ + +Reaching the end of the iterator is signalled by returning `None` instead of +`Some(item)`: + +~~~ +/// A stream of N zeroes +struct ZeroStream { + priv remaining: uint +} + +impl ZeroStream { + fn new(n: uint) -> ZeroStream { + ZeroStream { remaining: n } + } +} + +impl Iterator<int> for ZeroStream { + fn next(&mut self) -> Option<int> { + if self.remaining == 0 { + None + } else { + self.remaining -= 1; + Some(0) + } + } +} +~~~ + +## Container iterators + +Containers implement iteration over the contained elements by returning an +iterator object. For example, vectors have four iterators available: + +* `vector.iter()`, for immutable references to the elements +* `vector.mut_iter()`, for mutable references to the elements +* `vector.rev_iter()`, for immutable references to the elements in reverse order +* `vector.mut_rev_iter()`, for mutable references to the elements in reverse order + +### Freezing + +Unlike most other languages with external iterators, Rust has no *iterator +invalidation*. As long an iterator is still in scope, the compiler will prevent +modification of the container through another handle. + +~~~ +let mut xs = [1, 2, 3]; +{ + let _it = xs.iter(); + + // the vector is frozen for this scope, the compiler will statically + // prevent modification +} +// the vector becomes unfrozen again at the end of the scope +~~~ + +These semantics are due to most container iterators being implemented with `&` +and `&mut`. + +## Iterator adaptors + +The `IteratorUtil` trait implements common algorithms as methods extending +every `Iterator` implementation. For example, the `fold` method will accumulate +the items yielded by an `Iterator` into a single value: + +~~~ +let xs = [1, 9, 2, 3, 14, 12]; +let result = xs.iter().fold(0, |accumulator, item| accumulator - *item); +assert_eq!(result, -41); +~~~ + +Some adaptors return an adaptor object implementing the `Iterator` trait itself: + +~~~ +let xs = [1, 9, 2, 3, 14, 12]; +let ys = [5, 2, 1, 8]; +let sum = xs.iter().chain_(ys.iter()).fold(0, |a, b| a + *b); +assert_eq!(sum, 57); +~~~ + +Note that some adaptors like the `chain_` method above use a trailing +underscore to work around an issue with method resolve. The underscores will be +dropped when they become unnecessary. + +## For loops + +The `for` loop syntax is currently in transition, and will switch from the old +closure-based iteration protocol to iterator objects. For now, the `advance` +adaptor is required as a compatibility shim to use iterators with for loops. + +~~~ +let xs = [2, 3, 5, 7, 11, 13, 17]; + +// print out all the elements in the vector +for xs.iter().advance |x| { + println(x.to_str()) +} + +// print out all but the first 3 elements in the vector +for xs.iter().skip(3).advance |x| { + println(x.to_str()) +} +~~~ + +For loops are *often* used with a temporary iterator object, as above. They can +also advance the state of an iterator in a mutable location: + +~~~ +let xs = [1, 2, 3, 4, 5]; +let ys = ["foo", "bar", "baz", "foobar"]; + +// create an iterator yielding tuples of elements from both vectors +let mut it = xs.iter().zip(ys.iter()); + +// print out the pairs of elements up to (&3, &"baz") +for it.advance |(x, y)| { + println(fmt!("%d %s", *x, *y)); + + if *x == 3 { + break; + } +} + +// yield and print the last pair from the iterator +println(fmt!("last: %?", it.next())); + +// the iterator is now fully consumed +assert!(it.next().is_none()); +~~~ diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md index d3c682ce1ad..047b57e56a6 100644 --- a/doc/tutorial-ffi.md +++ b/doc/tutorial-ffi.md @@ -159,7 +159,7 @@ pub struct Unique<T> { priv ptr: *mut T } -impl<T: Owned> Unique<T> { +impl<T: Send> Unique<T> { pub fn new(value: T) -> Unique<T> { unsafe { let ptr = malloc(std::sys::size_of::<T>() as size_t) as *mut T; @@ -182,8 +182,8 @@ impl<T: Owned> Unique<T> { } #[unsafe_destructor] -impl<T: Owned> Drop for Unique<T> { - fn finalize(&self) { +impl<T: Send> Drop for Unique<T> { + fn drop(&self) { unsafe { let x = intrinsics::init(); // dummy value to swap in // moving the object out is needed to call the destructor diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index 2e3ce40c9f7..d302916025c 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -283,7 +283,7 @@ let ports = do vec::from_fn(3) |init_val| { }; // Wait on each port, accumulating the results -let result = ports.foldl(0, |accum, port| *accum + port.recv() ); +let result = ports.iter().fold(0, |accum, port| accum + port.recv() ); # fn some_expensive_computation(_i: uint) -> int { 42 } ~~~ @@ -481,7 +481,7 @@ an `Error` result. TODO: Need discussion of `future_result` in order to make failure modes useful. -But not all failure is created equal. In some cases you might need to +But not all failures are created equal. In some cases you might need to abort the entire program (perhaps you're writing an assert which, if it trips, indicates an unrecoverable logic error); in other cases you might want to contain the failure at a certain boundary (perhaps a diff --git a/doc/tutorial.md b/doc/tutorial.md index f69f569faee..d3113703c7c 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -99,9 +99,9 @@ If you've fulfilled those prerequisites, something along these lines should work. ~~~~ {.notrust} -$ curl -O http://static.rust-lang.org/dist/rust-0.6.tar.gz -$ tar -xzf rust-0.6.tar.gz -$ cd rust-0.6 +$ curl -O http://static.rust-lang.org/dist/rust-0.7.tar.gz +$ tar -xzf rust-0.7.tar.gz +$ cd rust-0.7 $ ./configure $ make && make install ~~~~ @@ -119,8 +119,8 @@ API-documentation tool; `rustpkg`, the Rust package manager; interface for them, and for a few common command line scenarios. [wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust -[tarball]: http://static.rust-lang.org/dist/rust-0.6.tar.gz -[win-exe]: http://static.rust-lang.org/dist/rust-0.6-install.exe +[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz +[win-exe]: http://static.rust-lang.org/dist/rust-0.7-install.exe ## Compiling your first program @@ -1084,8 +1084,8 @@ let managed_box : @Point = @Point { x: 5.0, y: 1.0 }; let owned_box : ~Point = ~Point { x: 7.0, y: 9.0 }; ~~~ -Suppose we wanted to write a procedure that computed the distance -between any two points, no matter where they were stored. For example, +Suppose we want to write a procedure that computes the distance +between any two points, no matter where they are stored. For example, we might like to compute the distance between `on_the_stack` and `managed_box`, or between `managed_box` and `owned_box`. One option is to define a function that takes two arguments of type point—that is, @@ -1230,7 +1230,7 @@ let area = rect.area(); ~~~ You can write an expression that dereferences any number of pointers -automatically. For example, if you felt inclined, you could write +automatically. For example, if you feel inclined, you could write something silly like ~~~ @@ -1281,9 +1281,9 @@ let your_crayons = ~[BananaMania, Beaver, Bittersweet]; // Add two vectors to create a new one let our_crayons = my_crayons + your_crayons; -// += will append to a vector, provided it lives in a mutable slot +// .push_all() will append to a vector, provided it lives in a mutable slot let mut my_crayons = my_crayons; -my_crayons += your_crayons; +my_crayons.push_all(your_crayons); ~~~~ > ***Note:*** The above examples of vector addition use owned @@ -1396,7 +1396,7 @@ assert!(!crayons.is_empty()); // Iterate over a vector, obtaining a pointer to each element // (`for` is explained in the next section) -for crayons.each |crayon| { +for crayons.iter().advance |crayon| { let delicious_crayon_wax = unwrap_crayon(*crayon); eat_crayon_wax(delicious_crayon_wax); } @@ -1552,13 +1552,6 @@ fn each(v: &[int], op: &fn(v: &int)) { } ~~~~ -As an aside, the reason we pass in a *pointer* to an integer rather -than the integer itself is that this is how the actual `each()` -function for vectors works. `vec::each` though is a -[generic](#generics) function, so must be efficient to use for all -types. Passing the elements by pointer avoids copying potentially -large objects. - As a caller, if we use a closure to provide the final operator argument, we can write it in a way that has a pleasant, block-like structure. @@ -1614,93 +1607,6 @@ do spawn { If you want to see the output of `debug!` statements, you will need to turn on `debug!` logging. To enable `debug!` logging, set the RUST_LOG environment variable to the name of your crate, which, for a file named `foo.rs`, will be `foo` (e.g., with bash, `export RUST_LOG=foo`). -## For loops - -The most common way to express iteration in Rust is with a `for` -loop. Like `do`, `for` is a nice syntax for describing control flow -with closures. Additionally, within a `for` loop, `break`, `loop`, -and `return` work just as they do with `while` and `loop`. - -Consider again our `each` function, this time improved to return -immediately when the iteratee returns `false`: - -~~~~ -fn each(v: &[int], op: &fn(v: &int) -> bool) -> bool { - let mut n = 0; - while n < v.len() { - if !op(&v[n]) { - return false; - } - n += 1; - } - return true; -} -~~~~ - -And using this function to iterate over a vector: - -~~~~ -# use each = std::vec::each; -each([2, 4, 8, 5, 16], |n| { - if *n % 2 != 0 { - println("found odd number!"); - false - } else { true } -}); -~~~~ - -With `for`, functions like `each` can be treated more -like built-in looping structures. When calling `each` -in a `for` loop, instead of returning `false` to break -out of the loop, you just write `break`. To skip ahead -to the next iteration, write `loop`. - -~~~~ -# use each = std::vec::each; -for each([2, 4, 8, 5, 16]) |n| { - if *n % 2 != 0 { - println("found odd number!"); - break; - } -} -~~~~ - -As an added bonus, you can use the `return` keyword, which is not -normally allowed in closures, in a block that appears as the body of a -`for` loop: the meaning of `return` in such a block is to return from -the enclosing function, not just the loop body. - -~~~~ -# use each = std::vec::each; -fn contains(v: &[int], elt: int) -> bool { - for each(v) |x| { - if (*x == elt) { return true; } - } - false -} -~~~~ - -Notice that, because `each` passes each value by borrowed pointer, -the iteratee needs to dereference it before using it. -In these situations it can be convenient to lean on Rust's -argument patterns to bind `x` to the actual value, not the pointer. - -~~~~ -# use each = std::vec::each; -# fn contains(v: &[int], elt: int) -> bool { - for each(v) |&x| { - if (x == elt) { return true; } - } -# false -# } -~~~~ - -`for` syntax only works with stack closures. - -> ***Note:*** This is, essentially, a special loop protocol: -> the keywords `break`, `loop`, and `return` work, in varying degree, -> with `while`, `loop`, `do`, and `for` constructs. - # Methods Methods are like functions except that they always begin with a special argument, @@ -1808,7 +1714,7 @@ s.draw_borrowed(); ~~~ Implementations may also define standalone (sometimes called "static") -methods. The absence of a `self` paramater distinguishes such methods. +methods. The absence of a `self` parameter distinguishes such methods. These methods are the preferred way to define constructor functions. ~~~~ {.xfail-test} @@ -1841,10 +1747,9 @@ vector consisting of the result of applying `function` to each element of `vector`: ~~~~ -# use std::vec; fn map<T, U>(vector: &[T], function: &fn(v: &T) -> U) -> ~[U] { let mut accumulator = ~[]; - for vec::each(vector) |element| { + for vector.iter().advance |element| { accumulator.push(function(element)); } return accumulator; @@ -1979,7 +1884,7 @@ types by the compiler, and may not be overridden: > iterations of the language, and often still are. Additionally, the `Drop` trait is used to define destructors. This -trait defines one method called `finalize`, which is automatically +trait defines one method called `drop`, which is automatically called when a value of the type that implements this trait is destroyed, either because the value went out of scope or because the garbage collector reclaimed it. @@ -1990,7 +1895,7 @@ struct TimeBomb { } impl Drop for TimeBomb { - fn finalize(&self) { + fn drop(&self) { for self.explosivity.times { println("blam!"); } @@ -1998,7 +1903,7 @@ impl Drop for TimeBomb { } ~~~ -It is illegal to call `finalize` directly. Only code inserted by the compiler +It is illegal to call `drop` directly. Only code inserted by the compiler may call it. ## Declaring and implementing traits @@ -2119,7 +2024,7 @@ generic types. ~~~~ # trait Printable { fn print(&self); } fn print_all<T: Printable>(printable_things: ~[T]) { - for printable_things.each |thing| { + for printable_things.iter().advance |thing| { thing.print(); } } @@ -2165,7 +2070,7 @@ However, consider this function: trait Drawable { fn draw(&self); } fn draw_all<T: Drawable>(shapes: ~[T]) { - for shapes.each |shape| { shape.draw(); } + for shapes.iter().advance |shape| { shape.draw(); } } # let c: Circle = new_circle(); # draw_all(~[c]); @@ -2180,7 +2085,7 @@ an _object_. ~~~~ # trait Drawable { fn draw(&self); } fn draw_all(shapes: &[@Drawable]) { - for shapes.each |shape| { shape.draw(); } + for shapes.iter().advance |shape| { shape.draw(); } } ~~~~ @@ -2319,7 +2224,7 @@ enum ABC { A, B, C } The full list of derivable traits is `Eq`, `TotalEq`, `Ord`, `TotalOrd`, `Encodable` `Decodable`, `Clone`, `DeepClone`, -`IterBytes`, `Rand` and `ToStr`. +`IterBytes`, `Rand`, `Zero`, and `ToStr`. # Modules and crates @@ -2522,7 +2427,7 @@ will not be compiled successfully. ## A minimal example -Now for something that you can actually compile yourself. We have +Now for something that you can actually compile yourself, we have these two files: ~~~~ @@ -2622,6 +2527,7 @@ tutorials on individual topics. * [Tasks and communication][tasks] * [Macros][macros] * [The foreign function interface][ffi] +* [Containers and iterators](tutorial-container.html) There is further documentation on the [wiki]. diff --git a/man/rustc.1 b/man/rustc.1 index 9ed98c14294..4e76749f707 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -1,4 +1,4 @@ -.TH RUSTC "1" "February 2013" "rustc 0.6" "User Commands" +.TH RUSTC "1" "July 2013" "rustc 0.7" "User Commands" .SH NAME rustc \- rust compiler .SH SYNOPSIS @@ -33,6 +33,12 @@ Add a directory to the library search path \fB\-\-lib\fR Compile a library crate .TP +\fB\-\-linker\fR LINKER +Program to use for linking instead of the default +.TP +\fB\-\-link-args\fR FLAGS +A space-separated list of flags passed to the linker +.TP \fB\-\-ls\fR List the symbols defined by a library crate .TP @@ -48,6 +54,11 @@ Write output to <filename> \fB\-\-opt\-level\fR LEVEL Optimize with possible levels 0-3 .TP +\fB\-\-passes\fR NAMES +Comma- or space-separated list of optimization passes. Overrides +the default passes for the optimization level. A value of 'list' +will list the available passes. +.TP \fB\-\-out\-dir\fR DIR Write output to compiler-chosen filename in <dir> .TP @@ -77,6 +88,12 @@ Target triple cpu-manufacturer-kernel[-os] to compile for (see http://sources.redhat.com/autobook/autobook/autobook_17.html for detail) .TP +\fB\-\-target-feature\fR TRIPLE +Target-specific attributes (see llc -mattr=help for detail) +.TP +\fB\-\-android-cross-path\fR PATH +The path to the Android NDK +.TP \fB\-W\fR help Print 'lint' options and default settings .TP @@ -94,56 +111,6 @@ Set lint forbidden .TP \fB\-Z\fR FLAG Set internal debugging options. Use "-Z help" to print available options. - -Available debug flags are: -.RS -.IP \[bu] -\fBverbose\fR - in general, enable more debug printouts -.IP \[bu] -\fBtime\-passes\fR - measure time of each rustc pass -.IP \[bu] -\fBcount\-llvm\-insns\fR - count where LLVM instrs originate -.IP \[bu] -\fBtime\-llvm\-passes\fR - measure time of each LLVM pass -.IP \[bu] -\fBtrans\-stats\fR - gather trans statistics -.IP \[bu] -\fBno\-asm\-comments\fR - omit comments when using \fI\-S\fR -.IP \[bu] -\fBno\-verify\fR - skip LLVM verification -.IP \[bu] -\fBtrace\fR - emit trace logs -.IP \[bu] -\fBcoherence\fR - perform coherence checking -.IP \[bu] -\fBborrowck\-stats\fR - gather borrowck statistics -.IP \[bu] -\fBborrowck\-note\-pure\fR - note where purity is req'd -.IP \[bu] -\fBborrowck\-note\-loan\fR - note where loans are req'd -.IP \[bu] -\fBno\-landing\-pads\fR - omit landing pads for unwinding -.IP \[bu] -\fBdebug\-llvm\fR - enable debug output from LLVM -.IP \[bu] -\fBcount\-type\-sizes\fR - count the sizes of aggregate types -.IP \[bu] -\fBmeta\-stats\fR - gather metadata statistics -.IP \[bu] -\fBno\-opt\fR - do not optimize, even if \fI\-O\fR is passed -.IP \[bu] -\fBno\-monomorphic\-collapse\fR - do not collapse template instantiations -.IP \[bu] -\fBgc\fR - Garbage collect shared data (experimental) -.IP \[bu] -\fBjit\fR - Execute using JIT (experimental) -.IP \[bu] -\fBextra\-debug\-info\fR - Extra debugging info (experimental) -.IP \[bu] -\fBdebug\-info\fR - Produce debug info (experimental) -.IP \[bu] -\fBstatic\fR - Use or produce static libraries or binaries (experimental) -.RE .TP \fB\-v\fR, \fB\-\-version\fR Print version info and exit diff --git a/mk/clean.mk b/mk/clean.mk index 23efbb3ee15..fcb6a2b4290 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -20,10 +20,10 @@ CLEAN_STAGE_RULES = \ clean$(stage)_T_$(target)_H_$(host)))) CLEAN_LLVM_RULES = \ - $(foreach target, $(CFG_TARGET_TRIPLES), \ + $(foreach target, $(CFG_HOST_TRIPLES), \ clean-llvm$(target)) -.PHONY: clean clean-all clean-misc +.PHONY: clean clean-all clean-misc clean-llvm clean-all: clean clean-llvm diff --git a/mk/dist.mk b/mk/dist.mk index 912b692a247..cb5b3607fca 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -57,7 +57,7 @@ LICENSE.txt: $(S)COPYRIGHT $(S)LICENSE-APACHE $(S)LICENSE-MIT cp $< $@ $(PKG_EXE): rust.iss modpath.iss LICENSE.txt rust-logo.ico \ - $(PKG_FILES) all rustc-stage3 + $(PKG_FILES) $(CSREQ3_T_$(CFG_BUILD_TRIPLE)_H_$(CFG_BUILD_TRIPLE)) @$(call E, ISCC: $@) $(Q)"$(CFG_ISCC)" $< endif diff --git a/mk/docs.mk b/mk/docs.mk index 8470da7c07b..f11a3d24b8d 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -99,6 +99,16 @@ doc/tutorial-macros.html: tutorial-macros.md doc/version_info.html \ --include-before-body=doc/version_info.html \ --output=$@ +DOCS += doc/tutorial-container.html +doc/tutorial-container.html: tutorial-container.md doc/version_info.html doc/rust.css + @$(call E, pandoc: $@) + $(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \ + $(CFG_PANDOC) --standalone --toc \ + --section-divs --number-sections \ + --from=markdown --to=html --css=rust.css \ + --include-before-body=doc/version_info.html \ + --output=$@ + DOCS += doc/tutorial-ffi.html doc/tutorial-ffi.html: tutorial-ffi.md doc/version_info.html doc/rust.css @$(call E, pandoc: $@) diff --git a/mk/target.mk b/mk/target.mk index 737b3b82c00..47ab7c86728 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -13,6 +13,15 @@ # this exists can be found on issue #2400 export CFG_COMPILER_TRIPLE +# The standard libraries should be held up to a higher standard than any old +# code, make sure that these common warnings are denied by default. These can +# be overridden during development temporarily. For stage0, we allow all these +# to suppress warnings which may be bugs in stage0 (should be fixed in stage1+) +# NOTE: add "-A warnings" after snapshot to WFLAGS_ST0 +WFLAGS_ST0 = -A unrecognized-lint +WFLAGS_ST1 = -D warnings +WFLAGS_ST2 = -D warnings + # TARGET_STAGE_N template: This defines how target artifacts are built # for all stage/target architecture combinations. The arguments: # $(1) is the stage @@ -39,7 +48,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)): \ $$(TSREQ$(1)_T_$(2)_H_$(3)) \ | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) - $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@ + $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) -o $$@ $$< && touch $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \ $$(EXTRALIB_CRATE) $$(EXTRALIB_INPUTS) \ @@ -47,7 +56,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \ $$(TSREQ$(1)_T_$(2)_H_$(3)) \ | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) - $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@ + $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) -o $$@ $$< && touch $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \ $$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \ diff --git a/mk/tests.mk b/mk/tests.mk index 3858de3f264..35d567ef771 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -122,9 +122,7 @@ CFG_ADB_TEST_DIR=/data/tmp $(info check: android device test dir $(CFG_ADB_TEST_DIR) ready \ $(shell adb remount 1>/dev/null) \ $(shell adb shell mkdir $(CFG_ADB_TEST_DIR) 1>/dev/null) \ - $(shell adb shell rm $(CFG_ADB_TEST_DIR)/*.so 1>/dev/null) \ - $(shell adb shell rm $(CFG_ADB_TEST_DIR)/*-arm-linux-androideabi 1>/dev/null) \ - $(shell adb shell rm $(CFG_ADB_TEST_DIR)/*-arm-linux-androideabi.* 1>/dev/null) \ + $(shell adb shell rm -rf $(CFG_ADB_TEST_DIR)/* 1>/dev/null) \ $(shell adb push $(S)src/etc/adb_run_wrapper.sh $(CFG_ADB_TEST_DIR) 1>/dev/null) \ $(shell adb push $(CFG_ANDROID_CROSS_PATH)/arm-linux-androideabi/lib/armv7-a/libgnustl_shared.so \ $(CFG_ADB_TEST_DIR) 1>/dev/null) \ diff --git a/mk/tools.mk b/mk/tools.mk index 8319d8d4e48..0a901358ac1 100644 --- a/mk/tools.mk +++ b/mk/tools.mk @@ -12,23 +12,23 @@ # and host architectures # The test runner that runs the cfail/rfail/rpass and bxench tests -COMPILETEST_CRATE := $(S)src/compiletest/compiletest.rc -COMPILETEST_INPUTS := $(wildcard $(S)src/compiletest/*rs) +COMPILETEST_CRATE := $(S)src/compiletest/compiletest.rs +COMPILETEST_INPUTS := $(wildcard $(S)src/compiletest/*.rs) # Rustpkg, the package manager and build system -RUSTPKG_LIB := $(S)src/librustpkg/rustpkg.rc -RUSTPKG_INPUTS := $(wildcard $(S)src/librustpkg/*rs) +RUSTPKG_LIB := $(S)src/librustpkg/rustpkg.rs +RUSTPKG_INPUTS := $(wildcard $(S)src/librustpkg/*.rs) # Rustdoc, the documentation tool -RUSTDOC_LIB := $(S)src/librustdoc/rustdoc.rc +RUSTDOC_LIB := $(S)src/librustdoc/rustdoc.rs RUSTDOC_INPUTS := $(wildcard $(S)src/librustdoc/*.rs) # Rusti, the JIT REPL -RUSTI_LIB := $(S)src/librusti/rusti.rc +RUSTI_LIB := $(S)src/librusti/rusti.rs RUSTI_INPUTS := $(wildcard $(S)src/librusti/*.rs) # Rust, the convenience tool -RUST_LIB := $(S)src/librust/rust.rc +RUST_LIB := $(S)src/librust/rust.rs RUST_INPUTS := $(wildcard $(S)src/librust/*.rs) # FIXME: These are only built for the host arch. Eventually we'll @@ -191,7 +191,8 @@ $(foreach host,$(CFG_HOST_TRIPLES), \ $(foreach target,$(CFG_TARGET_TRIPLES), \ $(eval $(call TOOLS_STAGE_N_TARGET,0,1,$(host),$(target))) \ $(eval $(call TOOLS_STAGE_N_TARGET,1,2,$(host),$(target))) \ - $(eval $(call TOOLS_STAGE_N_TARGET,2,3,$(host),$(target))))) + $(eval $(call TOOLS_STAGE_N_TARGET,2,3,$(host),$(target))) \ + $(eval $(call TOOLS_STAGE_N_TARGET,3,bogus,$(host),$(target))))) $(foreach host,$(CFG_HOST_TRIPLES), \ $(eval $(call TOOLS_STAGE_N_HOST,0,1,$(host),$(host))) \ diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rs index e832534b227..82206f12fae 100644 --- a/src/compiletest/compiletest.rc +++ b/src/compiletest/compiletest.rs @@ -15,8 +15,8 @@ #[no_core]; // XXX: Remove after snapshot #[no_std]; -extern mod core(name = "std", vers = "0.7-pre"); -extern mod extra(name = "extra", vers = "0.7-pre"); +extern mod core(name = "std", vers = "0.7"); +extern mod extra(name = "extra", vers = "0.7"); use core::prelude::*; use core::*; @@ -75,7 +75,7 @@ pub fn parse_config(args: ~[~str]) -> config { ]; assert!(!args.is_empty()); - let args_ = vec::tail(args); + let args_ = args.tail(); let matches = &match getopts::getopts(args_, opts) { Ok(m) => m, @@ -208,7 +208,8 @@ pub fn make_tests(config: &config) -> ~[test::TestDescAndFn] { debug!("making tests from %s", config.src_base.to_str()); let mut tests = ~[]; - for os::list_dir_path(&config.src_base).each |file| { + let dirs = os::list_dir_path(&config.src_base); + for dirs.iter().advance |file| { let file = copy *file; debug!("inspecting file %s", file.to_str()); if is_test(config, file) { @@ -230,11 +231,11 @@ pub fn is_test(config: &config, testfile: &Path) -> bool { let mut valid = false; - for valid_extensions.each |ext| { + for valid_extensions.iter().advance |ext| { if name.ends_with(*ext) { valid = true; } } - for invalid_prefixes.each |pre| { + for invalid_prefixes.iter().advance |pre| { if name.starts_with(*pre) { valid = false; } } @@ -253,9 +254,17 @@ pub fn make_test(config: &config, testfile: &Path) -> test::TestDescAndFn { } pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName { + + // Try to elide redundant long paths + fn shorten(path: &Path) -> ~str { + let filename = path.filename(); + let dir = path.pop().filename(); + fmt!("%s/%s", dir.get_or_default(~""), filename.get_or_default(~"")) + } + test::DynTestName(fmt!("[%s] %s", mode_str(config.mode), - testfile.to_str())) + shorten(testfile))) } pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn { diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs index cdc0defcbca..4649d4dfc3c 100644 --- a/src/compiletest/errors.rs +++ b/src/compiletest/errors.rs @@ -21,7 +21,7 @@ pub fn load_errors(testfile: &Path) -> ~[ExpectedError] { let mut line_num = 1u; while !rdr.eof() { let ln = rdr.read_line(); - error_patterns += parse_expected(line_num, ln); + error_patterns.push_all_move(parse_expected(line_num, ln)); line_num += 1u; } return error_patterns; diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index e0ceb79a37d..715f6d91e09 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -226,8 +226,8 @@ actual:\n\ ~"-L", config.build_base.to_str(), ~"-L", aux_output_dir_name(config, testfile).to_str()]; - args += split_maybe_args(&config.rustcflags); - args += split_maybe_args(&props.compile_flags); + args.push_all_move(split_maybe_args(&config.rustcflags)); + args.push_all_move(split_maybe_args(&props.compile_flags)); return ProcArgs {prog: config.rustc_path.to_str(), args: args}; } } @@ -321,13 +321,12 @@ fn check_error_patterns(props: &TestProps, if done { return; } let missing_patterns = - vec::slice(props.error_patterns, next_err_idx, - props.error_patterns.len()); + props.error_patterns.slice(next_err_idx, props.error_patterns.len()); if missing_patterns.len() == 1u { fatal_ProcRes(fmt!("error pattern '%s' not found!", missing_patterns[0]), ProcRes); } else { - for missing_patterns.each |pattern| { + for missing_patterns.iter().advance |pattern| { error(fmt!("error pattern '%s' not found!", *pattern)); } fatal_ProcRes(~"multiple error patterns not found", ProcRes); @@ -346,9 +345,9 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError], fatal(~"process did not return an error status"); } - let prefixes = vec::map(expected_errors, |ee| { + let prefixes = expected_errors.iter().transform(|ee| { fmt!("%s:%u:", testfile.to_str(), ee.line) - }); + }).collect::<~[~str]>(); // Scan and extract our error/warning messages, // which look like: @@ -358,7 +357,7 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError], // is the ending point, and * represents ANSI color codes. for ProcRes.stderr.line_iter().advance |line| { let mut was_expected = false; - for vec::eachi(expected_errors) |i, ee| { + for expected_errors.iter().enumerate().advance |(i, ee)| { if !found_flags[i] { debug!("prefix=%s ee.kind=%s ee.msg=%s line=%s", prefixes[i], ee.kind, ee.msg, line); @@ -529,7 +528,7 @@ fn compose_and_run_compiler( let extra_link_args = ~[~"-L", aux_output_dir_name(config, testfile).to_str()]; - for vec::each(props.aux_builds) |rel_ab| { + for props.aux_builds.iter().advance |rel_ab| { let abs_ab = config.aux_base.push_rel(&Path(*rel_ab)); let aux_args = make_compile_args(config, props, ~[~"--lib"] + extra_link_args, @@ -582,8 +581,8 @@ fn make_compile_args(config: &config, props: &TestProps, extras: ~[~str], ~"-o", xform(config, testfile).to_str(), ~"-L", config.build_base.to_str()] + extras; - args += split_maybe_args(&config.rustcflags); - args += split_maybe_args(&props.compile_flags); + args.push_all_move(split_maybe_args(&config.rustcflags)); + args.push_all_move(split_maybe_args(&props.compile_flags)); return ProcArgs {prog: config.rustc_path.to_str(), args: args}; } @@ -757,7 +756,7 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps, runargs.push(fmt!("%s", config.adb_test_dir)); runargs.push(fmt!("%s", prog_short)); - for args.args.each |tv| { + for args.args.iter().advance |tv| { runargs.push(tv.to_owned()); } @@ -822,7 +821,8 @@ fn _dummy_exec_compiled_test(config: &config, props: &TestProps, fn _arm_push_aux_shared_library(config: &config, testfile: &Path) { let tstr = aux_output_dir_name(config, testfile).to_str(); - for os::list_dir_path(&Path(tstr)).each |file| { + let dirs = os::list_dir_path(&Path(tstr)); + for dirs.iter().advance |file| { if (file.filetype() == Some(~".so")) { diff --git a/src/driver/driver.rs b/src/driver/driver.rs index ccedd3adbaa..0f61ede4fc5 100644 --- a/src/driver/driver.rs +++ b/src/driver/driver.rs @@ -11,7 +11,7 @@ #[no_core]; #[no_std]; -extern mod core(name = "std", vers = "0.7-pre"); +extern mod core(name = "std", vers = "0.7"); #[cfg(rustpkg)] extern mod this(name = "rustpkg"); diff --git a/src/etc/adb_run_wrapper.sh b/src/etc/adb_run_wrapper.sh index fb1e0937fc9..7cbcf94dd40 100755 --- a/src/etc/adb_run_wrapper.sh +++ b/src/etc/adb_run_wrapper.sh @@ -17,16 +17,17 @@ then L_RET=1 L_COUNT=0 + cd $PATH while [ $L_RET -eq 1 ] do - LD_LIBRARY_PATH=$PATH $PATH/$RUN $@ 1>$PATH/$RUN.stdout 2>$PATH/$RUN.stderr + TEST_EXEC_ENV=22 LD_LIBRARY_PATH=$PATH $PATH/$RUN $@ 1>$PATH/$RUN.stdout 2>$PATH/$RUN.stderr L_RET=$? if [ $L_COUNT -gt 0 ] then /system/bin/sleep $WAIT /system/bin/sync fi - L_COUNT=`expr $L_COUNT+1` + L_COUNT=$((L_COUNT+1)) done echo $L_RET > $PATH/$RUN.exitcode diff --git a/src/etc/combine-tests.py b/src/etc/combine-tests.py index 8e9caf189c2..36031d31149 100755 --- a/src/etc/combine-tests.py +++ b/src/etc/combine-tests.py @@ -60,7 +60,7 @@ i = 0 for t in stage2_tests: p = os.path.join("test", "run-pass", t) p = p.replace("\\", "\\\\") - d.write(" out.write_str(~\"run-pass [stage2]: %s\\n\");\n" % p) + d.write(" out.write_str(\"run-pass [stage2]: %s\\n\");\n" % p) d.write(" t_%d::main();\n" % i) i += 1 d.write("}\n") diff --git a/src/etc/ctags.rust b/src/etc/ctags.rust index 4654116bc4d..5c2f4f82566 100644 --- a/src/etc/ctags.rust +++ b/src/etc/ctags.rust @@ -8,3 +8,4 @@ --regex-rust=/[ \t]*static[ \t]+([a-zA-Z0-9_]+)/\1/m,consts/ --regex-rust=/[ \t]*trait[ \t]+([a-zA-Z0-9_]+)/\1/m,traits/ --regex-rust=/[ \t]*impl[ \t]+([a-zA-Z0-9_]+)/\1/m,impls/ +--regex-rust=/[ \t]*macro_rules![ \t]+([a-zA-Z0-9_]+)/\1/m,macros/ diff --git a/src/etc/kate/rust.xml b/src/etc/kate/rust.xml index 44d0ce1a27f..63f1e50fcaf 100644 --- a/src/etc/kate/rust.xml +++ b/src/etc/kate/rust.xml @@ -7,7 +7,7 @@ <!ENTITY rustIdent "[a-zA-Z_][a-zA-Z_0-9]*"> <!ENTITY rustIntSuf "([iu](8|16|32|64)?)?"> ]> -<language name="Rust" version="0.7-pre" kateversion="2.4" section="Sources" extensions="*.rs;*.rc" mimetype="text/x-rust" priority="15"> +<language name="Rust" version="0.7" kateversion="2.4" section="Sources" extensions="*.rs;*.rc" mimetype="text/x-rust" priority="15"> <highlighting> <list name="fn"> <item> fn </item> diff --git a/src/etc/pkg/rust.iss b/src/etc/pkg/rust.iss index 18f358a9893..0375a041a39 100644 --- a/src/etc/pkg/rust.iss +++ b/src/etc/pkg/rust.iss @@ -1,4 +1,5 @@ #define CFG_VERSION GetEnv("CFG_VERSION") +#define CFG_VERSION_WIN GetEnv("CFG_VERSION_WIN") [Setup] @@ -8,7 +9,7 @@ AppVersion={#CFG_VERSION} AppCopyright=Copyright (C) 2006-2013 Mozilla Foundation, MIT license AppPublisher=Mozilla Foundation AppPublisherURL=http://www.rust-lang.org -VersionInfoVersion={#CFG_VERSION} +VersionInfoVersion={#CFG_VERSION_WIN} LicenseFile=LICENSE.txt DisableWelcomePage=true diff --git a/src/etc/unicode.py b/src/etc/unicode.py index afb3d168480..2a252f3f1f3 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -122,14 +122,14 @@ def ch_prefix(ix): def emit_bsearch_range_table(f): f.write(""" - pure fn bsearch_range_table(c: char, r: &[(char,char)]) -> bool { - use cmp::{EQ, LT, GT}; - use vec::bsearch; + fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { + use cmp::{Equal, Less, Greater}; + use vec::ImmutableVector; use option::None; - (do bsearch(r) |&(lo,hi)| { - if lo <= c && c <= hi { EQ } - else if hi < c { LT } - else { GT } + (do r.bsearch |&(lo,hi)| { + if lo <= c && c <= hi { Equal } + else if hi < c { Less } + else { Greater } }) != None }\n\n """); @@ -140,7 +140,7 @@ def emit_property_module(f, mod, tbl): keys.sort() emit_bsearch_range_table(f); for cat in keys: - f.write(" const %s_table : &[(char,char)] = &[\n" % cat) + f.write(" static %s_table : &'static [(char,char)] = &[\n" % cat) ix = 0 for pair in tbl[cat]: f.write(ch_prefix(ix)) @@ -148,7 +148,7 @@ def emit_property_module(f, mod, tbl): ix += 1 f.write("\n ];\n\n") - f.write(" pub pure fn %s(c: char) -> bool {\n" % cat) + f.write(" pub fn %s(c: char) -> bool {\n" % cat) f.write(" bsearch_range_table(c, %s_table)\n" % cat) f.write(" }\n\n") f.write("}\n") @@ -159,7 +159,7 @@ def emit_property_module_old(f, mod, tbl): keys = tbl.keys() keys.sort() for cat in keys: - f.write(" pure fn %s(c: char) -> bool {\n" % cat) + f.write(" fn %s(c: char) -> bool {\n" % cat) f.write(" ret alt c {\n") prefix = ' ' for pair in tbl[cat]: @@ -236,8 +236,22 @@ rf = open(r, "w") (canon_decomp, compat_decomp, gencats) = load_unicode_data("UnicodeData.txt") -# Explain that the source code was generated by this script. -rf.write('// The following code was generated by "src/etc/unicode.py"\n\n') +# Preamble +rf.write('''// Copyright 2012-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 following code was generated by "src/etc/unicode.py" + +#[allow(missing_doc)]; + +''') emit_property_module(rf, "general_category", gencats) diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index 5c08fdfecca..25e44c62a8a 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -2,7 +2,7 @@ " Language: Rust " Maintainer: Patrick Walton <pcwalton@mozilla.com> " Maintainer: Ben Blum <bblum@cs.cmu.edu> -" Last Change: 2012 Dec 25 +" Last Change: 2013 Jun 14 if version < 600 syntax clear @@ -13,13 +13,16 @@ endif syn keyword rustConditional match if else syn keyword rustOperator as -syn keyword rustKeyword break copy do drop extern +syn match rustAssert "\<assert\(\w\)*!" +syn match rustFail "\<fail\(\w\)*!" +syn keyword rustKeyword break copy do extern syn keyword rustKeyword for if impl let log syn keyword rustKeyword copy do extern syn keyword rustKeyword for impl let log syn keyword rustKeyword loop mod once priv pub syn keyword rustKeyword return -syn keyword rustKeyword unsafe use while +syn keyword rustKeyword unsafe while +syn keyword rustKeyword use nextgroup=rustModPath skipwhite " FIXME: Scoped impl's name is also fallen in this category syn keyword rustKeyword mod trait struct enum type nextgroup=rustIdentifier skipwhite syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite @@ -45,7 +48,8 @@ syn keyword rustType c_longlong c_ulonglong intptr_t uintptr_t syn keyword rustType off_t dev_t ino_t pid_t mode_t ssize_t syn keyword rustTrait Const Copy Send Owned Sized " inherent traits -syn keyword rustTrait Eq Ord Num Ptr +syn keyword rustTrait Clone Decodable Encodable IterBytes Rand ToStr +syn keyword rustTrait Eq Ord TotalEq TotalOrd Num Ptr syn keyword rustTrait Drop Add Sub Mul Quot Rem Neg BitAnd BitOr syn keyword rustTrait BitXor Shl Shr Index @@ -72,19 +76,21 @@ syn keyword rustConstant STDIN_FILENO STDOUT_FILENO STDERR_FILENO " If foo::bar changes to foo.bar, change this ("::" to "\."). " If foo::bar changes to Foo::bar, change this (first "\w" to "\u"). syn match rustModPath "\w\(\w\)*::[^<]"he=e-3,me=e-3 +syn match rustModPath "\w\(\w\)*" contained " only for 'use path;' syn match rustModPathSep "::" syn match rustFuncCall "\w\(\w\)*("he=e-1,me=e-1 syn match rustFuncCall "\w\(\w\)*::<"he=e-3,me=e-3 " foo::<T>(); -syn match rustMacro '\w\(\w\)*!' -syn match rustMacro '#\w\(\w\)*' +syn match rustMacro '\w\(\w\)*!' contains=rustAssert,rustFail +syn match rustMacro '#\w\(\w\)*' contains=rustAssert,rustFail syn match rustFormat display "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlLjzt]\|ll\|hh\)\=\([aAbdiuoxXDOUfFeEgGcCsSpn?]\|\[\^\=.[^]]*\]\)" contained syn match rustFormat display "%%" contained syn region rustString start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=rustTodo,rustFormat -syn region rustAttribute start="#\[" end="\]" contains=rustString +syn region rustAttribute start="#\[" end="\]" contains=rustString,rustDeriving +syn region rustDeriving start="deriving(" end=")" contains=rustTrait " Number literals syn match rustNumber display "\<[0-9][0-9_]*\>" @@ -137,17 +143,24 @@ hi def link rustConditional Conditional hi def link rustIdentifier Identifier hi def link rustModPath Include hi def link rustFuncName Function +hi def link rustFuncCall Function hi def link rustCommentDoc SpecialComment hi def link rustComment Comment hi def link rustMacro Macro hi def link rustType Type hi def link rustTodo Todo hi def link rustAttribute PreProc +hi def link rustDeriving PreProc hi def link rustStorage StorageClass hi def link rustLifetime Special " Other Suggestions: +" hi rustAttribute ctermfg=cyan +" hi rustDeriving ctermfg=cyan +" hi rustAssert ctermfg=yellow +" hi rustFail ctermfg=red " hi rustMacro ctermfg=magenta +" hi rustModPathSep ctermfg=grey syn sync minlines=200 syn sync maxlines=500 diff --git a/src/etc/zsh/_rust b/src/etc/zsh/_rust index faa21a29616..86dcbab93fd 100644 --- a/src/etc/zsh/_rust +++ b/src/etc/zsh/_rust @@ -29,36 +29,30 @@ _rustc_opts_switches=( --target'[Target triple cpu-manufacturer-kernel\[-os\] to compile]' --target-feature'[Target specific attributes (llc -mattr=help for detail)]' --android-cross-path'[The path to the Android NDK]' - {-W,--warn}'[Set lint warnings]' - {-A,--allow}'[Set lint allowed]' - {-D,--deny}'[Set lint denied]' - {-F,--forbid}'[Set lint forbidden]' - -Z'[Set internal debugging options]' {-v,--version}'[Print version info and exit]' ) - _rustc_opts_lint=( - 'path-statement:path statements with no effect' - 'deprecated-pattern:warn about deprecated uses of pattern bindings' - 'non-implicitly-copyable-typarams:passing non implicitly copyable types as copy type params' - 'missing-trait-doc:detects missing documentation for traits' - 'missing-struct-doc:detects missing documentation for structs' - 'ctypes:proper use of core::libc types in foreign modules' - 'implicit-copies:implicit copies of non implicitly copyable data' - "unused-mut:detect mut variables which don't need to be mutable" - 'unused-imports:imports that are never used' - 'heap-memory:use of any (~ type or @ type) heap memory' - 'default-methods:allow default methods' - 'unused-variable:detect variables which are not used in any way' - 'dead-assignment:detect assignments that will never be read' - 'unrecognized-lint:unrecognized lint attribute' - 'type-limits:comparisons made useless by limits of the types involved' - 'unused-unsafe:unnecessary use of an `unsafe` block' - 'while-true:suggest using loop { } instead of while(true) { }' - 'non-camel-case-types:types, variants and traits should have camel case names' - 'managed-heap-memory:use of managed (@ type) heap memory' - 'unnecessary-allocation:detects unnecessary allocations that can be eliminated' - 'owned-heap-memory:use of owned (~ type) heap memory' + 'path-statement[path statements with no effect]' + 'deprecated-pattern[warn about deprecated uses of pattern bindings]' + 'non-implicitly-copyable-typarams[passing non implicitly copyable types as copy type params]' + 'missing-trait-doc[detects missing documentation for traits]' + 'missing-struct-doc[detects missing documentation for structs]' + 'ctypes[proper use of core::libc types in foreign modules]' + 'implicit-copies[implicit copies of non implicitly copyable data]' + "unused-mut[detect mut variables which don't need to be mutable]" + 'unused-imports[imports that are never used]' + 'heap-memory[use of any (~ type or @ type) heap memory]' + 'default-methods[allow default methods]' + 'unused-variable[detect variables which are not used in any way]' + 'dead-assignment[detect assignments that will never be read]' + 'unrecognized-lint[unrecognized lint attribute]' + 'type-limits[comparisons made useless by limits of the types involved]' + 'unused-unsafe[unnecessary use of an `unsafe` block]' + 'while-true[suggest using loop { } instead of while(true) { }]' + 'non-camel-case-types[types, variants and traits should have camel case names]' + 'managed-heap-memory[use of managed (@ type) heap memory]' + 'unnecessary-allocation[detects unnecessary allocations that can be eliminated]' + 'owned-heap-memory[use of owned (~ type) heap memory]' ) _rustc_opts_debug=( @@ -90,13 +84,20 @@ _rustc_opts_debug=( 'lint-llvm:Run the LLVM lint pass on the pre-optimization IR' ) -_rustc() { - case $words[2] in - -[WADF]) _describe 'options' _rustc_opts_lint ;; - -Z) _describe 'options' _rustc_opts_debug ;; - -) _arguments -s -w : "$_rustc_opts_switches[@]" ;; - *) _files -g "*.rs" ;; - esac +_rustc_opts_fun_lint(){ + _values -s , 'options' \ + "$_rustc_opts_lint[@]" +} + +_rustc_opts_fun_debug(){ + _describe 'options' _rustc_opts_debug } -_rustc "$@" +_arguments -s : \ + '(-W --warn)'{-W,--warn}'[Set lint warnings]:lint options:_rustc_opts_fun_lint' \ + '(-A --allow)'{-A,--allow}'[Set lint allowed]:lint options:_rustc_opts_fun_lint' \ + '(-D --deny)'{-D,--deny}'[Set lint denied]:lint options:_rustc_opts_fun_lint' \ + '(-F --forbid)'{-F,--forbid}'[Set lint forbidden]:lint options:_rustc_opts_fun_lint' \ + '*-Z[Set internal debugging options]:debug options:_rustc_opts_fun_debug' \ + "$_rustc_opts_switches[@]" \ + '*::files:_files -g "*.rs"' diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index 661224b0a80..be9ab863942 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -19,7 +19,7 @@ * * ~~~ {.rust} * extern mod std; - * use std::arc; + * use extra::arc; * let numbers=vec::from_fn(100, |ind| (ind as float)*rand::random()); * let shared_numbers=arc::ARC(numbers); * @@ -39,15 +39,14 @@ #[allow(missing_doc)]; -use core::prelude::*; use sync; use sync::{Mutex, mutex_with_condvars, RWlock, rwlock_with_condvars}; -use core::cast; -use core::unstable::sync::UnsafeAtomicRcBox; -use core::task; -use core::borrow; +use std::cast; +use std::unstable::sync::UnsafeAtomicRcBox; +use std::task; +use std::borrow; /// As sync::condvar, a mechanism for unlock-and-descheduling and signaling. pub struct Condvar<'self> { @@ -112,7 +111,7 @@ impl<'self> Condvar<'self> { pub struct ARC<T> { x: UnsafeAtomicRcBox<T> } /// Create an atomically reference counted wrapper. -pub fn ARC<T:Const + Owned>(data: T) -> ARC<T> { +pub fn ARC<T:Freeze + Send>(data: T) -> ARC<T> { ARC { x: UnsafeAtomicRcBox::new(data) } } @@ -120,7 +119,7 @@ pub fn ARC<T:Const + Owned>(data: T) -> ARC<T> { * Access the underlying data in an atomically reference counted * wrapper. */ -impl<T:Const+Owned> ARC<T> { +impl<T:Freeze+Send> ARC<T> { pub fn get<'a>(&'a self) -> &'a T { unsafe { &*self.x.get_immut() } } @@ -133,7 +132,7 @@ impl<T:Const+Owned> ARC<T> { * object. However, one of the `arc` objects can be sent to another task, * allowing them to share the underlying data. */ -impl<T:Const + Owned> Clone for ARC<T> { +impl<T:Freeze + Send> Clone for ARC<T> { fn clone(&self) -> ARC<T> { ARC { x: self.x.clone() } } @@ -149,14 +148,14 @@ struct MutexARCInner<T> { lock: Mutex, failed: bool, data: T } struct MutexARC<T> { x: UnsafeAtomicRcBox<MutexARCInner<T>> } /// Create a mutex-protected ARC with the supplied data. -pub fn MutexARC<T:Owned>(user_data: T) -> MutexARC<T> { +pub fn MutexARC<T:Send>(user_data: T) -> MutexARC<T> { mutex_arc_with_condvars(user_data, 1) } /** * Create a mutex-protected ARC with the supplied data and a specified number * of condvars (as sync::mutex_with_condvars). */ -pub fn mutex_arc_with_condvars<T:Owned>(user_data: T, +pub fn mutex_arc_with_condvars<T:Send>(user_data: T, num_condvars: uint) -> MutexARC<T> { let data = MutexARCInner { lock: mutex_with_condvars(num_condvars), @@ -164,7 +163,7 @@ pub fn mutex_arc_with_condvars<T:Owned>(user_data: T, MutexARC { x: UnsafeAtomicRcBox::new(data) } } -impl<T:Owned> Clone for MutexARC<T> { +impl<T:Send> Clone for MutexARC<T> { /// Duplicate a mutex-protected ARC, as arc::clone. fn clone(&self) -> MutexARC<T> { // NB: Cloning the underlying mutex is not necessary. Its reference @@ -173,7 +172,7 @@ impl<T:Owned> Clone for MutexARC<T> { } } -impl<T:Owned> MutexARC<T> { +impl<T:Send> MutexARC<T> { /** * Access the underlying mutable data with mutual exclusion from other @@ -247,7 +246,7 @@ struct PoisonOnFail { } impl Drop for PoisonOnFail { - fn finalize(&self) { + fn drop(&self) { unsafe { /* assert!(!*self.failed); -- might be false in case of cond.wait() */ @@ -276,20 +275,21 @@ struct RWARCInner<T> { lock: RWlock, failed: bool, data: T } * * Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested. */ -#[mutable] +#[mutable] // XXX remove after snap +#[no_freeze] struct RWARC<T> { x: UnsafeAtomicRcBox<RWARCInner<T>>, } /// Create a reader/writer ARC with the supplied data. -pub fn RWARC<T:Const + Owned>(user_data: T) -> RWARC<T> { +pub fn RWARC<T:Freeze + Send>(user_data: T) -> RWARC<T> { rw_arc_with_condvars(user_data, 1) } /** * Create a reader/writer ARC with the supplied data and a specified number * of condvars (as sync::rwlock_with_condvars). */ -pub fn rw_arc_with_condvars<T:Const + Owned>( +pub fn rw_arc_with_condvars<T:Freeze + Send>( user_data: T, num_condvars: uint) -> RWARC<T> { @@ -299,7 +299,7 @@ pub fn rw_arc_with_condvars<T:Const + Owned>( RWARC { x: UnsafeAtomicRcBox::new(data), } } -impl<T:Const + Owned> RWARC<T> { +impl<T:Freeze + Send> RWARC<T> { /// Duplicate a rwlock-protected ARC, as arc::clone. pub fn clone(&self) -> RWARC<T> { RWARC { @@ -309,7 +309,7 @@ impl<T:Const + Owned> RWARC<T> { } -impl<T:Const + Owned> RWARC<T> { +impl<T:Freeze + Send> RWARC<T> { /** * Access the underlying data mutably. Locks the rwlock in write mode; * other readers and writers will block. @@ -435,8 +435,8 @@ impl<T:Const + Owned> RWARC<T> { // lock it. This wraps the unsafety, with the justification that the 'lock' // field is never overwritten; only 'failed' and 'data'. #[doc(hidden)] -fn borrow_rwlock<T:Const + Owned>(state: *const RWARCInner<T>) -> *RWlock { - unsafe { cast::transmute(&const (*state).lock) } +fn borrow_rwlock<T:Freeze + Send>(state: *mut RWARCInner<T>) -> *RWlock { + unsafe { cast::transmute(&(*state).lock) } } /// The "write permission" token used for RWARC.write_downgrade(). @@ -452,7 +452,7 @@ pub struct RWReadMode<'self, T> { token: sync::RWlockReadMode<'self>, } -impl<'self, T:Const + Owned> RWWriteMode<'self, T> { +impl<'self, T:Freeze + Send> RWWriteMode<'self, T> { /// Access the pre-downgrade RWARC in write mode. pub fn write<U>(&mut self, blk: &fn(x: &mut T) -> U) -> U { match *self { @@ -493,7 +493,7 @@ impl<'self, T:Const + Owned> RWWriteMode<'self, T> { } } -impl<'self, T:Const + Owned> RWReadMode<'self, T> { +impl<'self, T:Freeze + Send> RWReadMode<'self, T> { /// Access the post-downgrade rwlock in read mode. pub fn read<U>(&self, blk: &fn(x: &T) -> U) -> U { match *self { @@ -513,13 +513,13 @@ impl<'self, T:Const + Owned> RWReadMode<'self, T> { #[cfg(test)] mod tests { - use core::prelude::*; use arc::*; - use core::cell::Cell; - use core::comm; - use core::task; + use std::cell::Cell; + use std::comm; + use std::task; + use std::uint; #[test] fn manually_share_arc() { @@ -725,7 +725,7 @@ mod tests { } // Wait for children to pass their asserts - for children.each |r| { + for children.iter().advance |r| { r.recv(); } @@ -789,18 +789,20 @@ mod tests { } assert_eq!(*state, 42); *state = 31337; + // FIXME: #7372: hits type inference bug with iterators // send to other readers - for reader_convos.each |x| { - match *x { + for uint::range(0, reader_convos.len()) |i| { + match reader_convos[i] { (ref rc, _) => rc.send(()), } } } let read_mode = arc.downgrade(write_mode); do (&read_mode).read |state| { + // FIXME: #7372: hits type inference bug with iterators // complete handshake with other readers - for reader_convos.each |x| { - match *x { + for uint::range(0, reader_convos.len()) |i| { + match reader_convos[i] { (_, ref rp) => rp.recv(), } } diff --git a/src/libextra/arena.rs b/src/libextra/arena.rs index db4cf564bab..f378384c564 100644 --- a/src/libextra/arena.rs +++ b/src/libextra/arena.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -34,37 +34,27 @@ #[allow(missing_doc)]; -use core::prelude::*; use list::{MutList, MutCons, MutNil}; -use core::at_vec; -use core::cast::{transmute, transmute_mut_region}; -use core::cast; -use core::libc::size_t; -use core::ptr; -use core::sys::TypeDesc; -use core::sys; -use core::uint; -use core::vec; -use core::unstable::intrinsics; - -pub mod rustrt { - use core::libc::size_t; - use core::sys::TypeDesc; - - pub extern { - #[rust_stack] - unsafe fn rust_call_tydesc_glue(root: *u8, - tydesc: *TypeDesc, - field: size_t); - } +use std::at_vec; +use std::cast::{transmute, transmute_mut, transmute_mut_region}; +use std::cast; +use std::ptr; +use std::sys; +use std::uint; +use std::vec; +use std::unstable::intrinsics; +use std::unstable::intrinsics::{TyDesc}; + +#[cfg(not(stage0))] +use std::unstable::intrinsics::{get_tydesc}; + +#[cfg(stage0)] +unsafe fn get_tydesc<T>() -> *TyDesc { + intrinsics::get_tydesc::<T>() as *TyDesc } -// This probably belongs somewhere else. Needs to be kept in sync with -// changes to glue... -static tydesc_drop_glue_index: size_t = 3 as size_t; - // The way arena uses arrays is really deeply awful. The arrays are // allocated, and have capacities reserved, but the fill for the array // will always stay at 0. @@ -74,6 +64,8 @@ struct Chunk { is_pod: bool, } +#[mutable] // XXX remove after snap +#[no_freeze] pub struct Arena { // The head is separated out from the list as a unbenchmarked // microoptimization, to avoid needing to case on the list to @@ -85,7 +77,7 @@ pub struct Arena { #[unsafe_destructor] impl Drop for Arena { - fn finalize(&self) { + fn drop(&self) { unsafe { destroy_chunk(&self.head); for self.chunks.each |chunk| { @@ -124,6 +116,19 @@ fn round_up_to(base: uint, align: uint) -> uint { (base + (align - 1)) & !(align - 1) } +#[inline] +#[cfg(not(stage0))] +unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) { + // This function should be inlined when stage0 is gone + ((*tydesc).drop_glue)(data); +} + +#[inline] +#[cfg(stage0)] +unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) { + ((*tydesc).drop_glue)(0 as **TyDesc, data); +} + // Walk down a chunk, running the destructors for any objects stored // in it. unsafe fn destroy_chunk(chunk: &Chunk) { @@ -136,19 +141,18 @@ unsafe fn destroy_chunk(chunk: &Chunk) { let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data); let (size, align) = ((*tydesc).size, (*tydesc).align); - let after_tydesc = idx + sys::size_of::<*TypeDesc>(); + let after_tydesc = idx + sys::size_of::<*TyDesc>(); let start = round_up_to(after_tydesc, align); //debug!("freeing object: idx = %u, size = %u, align = %u, done = %b", // start, size, align, is_done); if is_done { - rustrt::rust_call_tydesc_glue( - ptr::offset(buf, start), tydesc, tydesc_drop_glue_index); + call_drop_glue(tydesc, ptr::offset(buf, start) as *i8); } // Find where the next tydesc lives - idx = round_up_to(start + size, sys::pref_align_of::<*TypeDesc>()); + idx = round_up_to(start + size, sys::pref_align_of::<*TyDesc>()); } } @@ -157,12 +161,12 @@ unsafe fn destroy_chunk(chunk: &Chunk) { // is necessary in order to properly do cleanup if a failure occurs // during an initializer. #[inline] -unsafe fn bitpack_tydesc_ptr(p: *TypeDesc, is_done: bool) -> uint { +unsafe fn bitpack_tydesc_ptr(p: *TyDesc, is_done: bool) -> uint { let p_bits: uint = transmute(p); p_bits | (is_done as uint) } #[inline] -unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TypeDesc, bool) { +unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TyDesc, bool) { (transmute(p & !1), p & 1 == 1) } @@ -182,27 +186,25 @@ impl Arena { #[inline] fn alloc_pod_inner(&mut self, n_bytes: uint, align: uint) -> *u8 { unsafe { - // XXX: Borrow check - let head = transmute_mut_region(&mut self.pod_head); - - let start = round_up_to(head.fill, align); + let this = transmute_mut_region(self); + let start = round_up_to(this.pod_head.fill, align); let end = start + n_bytes; - if end > at_vec::capacity(head.data) { - return self.alloc_pod_grow(n_bytes, align); + if end > at_vec::capacity(this.pod_head.data) { + return this.alloc_pod_grow(n_bytes, align); } - head.fill = end; + this.pod_head.fill = end; //debug!("idx = %u, size = %u, align = %u, fill = %u", // start, n_bytes, align, head.fill); - ptr::offset(vec::raw::to_ptr(head.data), start) + ptr::offset(vec::raw::to_ptr(this.pod_head.data), start) } } #[inline] fn alloc_pod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { - let tydesc = sys::get_type_desc::<T>(); + let tydesc = get_tydesc::<T>(); let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align); let ptr: *mut T = transmute(ptr); intrinsics::move_val_init(&mut (*ptr), op()); @@ -227,21 +229,31 @@ impl Arena { fn alloc_nonpod_inner(&mut self, n_bytes: uint, align: uint) -> (*u8, *u8) { unsafe { - let head = transmute_mut_region(&mut self.head); + let start; + let end; + let tydesc_start; + let after_tydesc; + + { + let head = transmute_mut_region(&mut self.head); + + tydesc_start = head.fill; + after_tydesc = head.fill + sys::size_of::<*TyDesc>(); + start = round_up_to(after_tydesc, align); + end = start + n_bytes; + } - let tydesc_start = head.fill; - let after_tydesc = head.fill + sys::size_of::<*TypeDesc>(); - let start = round_up_to(after_tydesc, align); - let end = start + n_bytes; - if end > at_vec::capacity(head.data) { + if end > at_vec::capacity(self.head.data) { return self.alloc_nonpod_grow(n_bytes, align); } - head.fill = round_up_to(end, sys::pref_align_of::<*TypeDesc>()); + + let head = transmute_mut_region(&mut self.head); + head.fill = round_up_to(end, sys::pref_align_of::<*TyDesc>()); //debug!("idx = %u, size = %u, align = %u, fill = %u", // start, n_bytes, align, head.fill); - let buf = vec::raw::to_ptr(head.data); + let buf = vec::raw::to_ptr(self.head.data); return (ptr::offset(buf, tydesc_start), ptr::offset(buf, start)); } } @@ -249,7 +261,7 @@ impl Arena { #[inline] fn alloc_nonpod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { - let tydesc = sys::get_type_desc::<T>(); + let tydesc = get_tydesc::<T>(); let (ty_ptr, ptr) = self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align); let ty_ptr: *mut uint = transmute(ty_ptr); @@ -269,23 +281,22 @@ impl Arena { // The external interface #[inline] - pub fn alloc<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { + pub fn alloc<'a, T>(&'a self, op: &fn() -> T) -> &'a T { unsafe { // XXX: Borrow check - let this = transmute_mut_region(self); - if !intrinsics::needs_drop::<T>() { - return this.alloc_pod(op); + let this = transmute_mut(self); + if intrinsics::needs_drop::<T>() { + this.alloc_nonpod(op) + } else { + this.alloc_pod(op) } - // XXX: Borrow check - let this = transmute_mut_region(self); - this.alloc_nonpod(op) } } } #[test] fn test_arena_destructors() { - let mut arena = Arena(); + let arena = Arena(); for uint::range(0, 10) |i| { // Arena allocate something with drop glue to make sure it // doesn't leak. @@ -300,7 +311,7 @@ fn test_arena_destructors() { #[should_fail] #[ignore(cfg(windows))] fn test_arena_destructors_fail() { - let mut arena = Arena(); + let arena = Arena(); // Put some stuff in the arena. for uint::range(0, 10) |i| { // Arena allocate something with drop glue to make sure it diff --git a/src/libextra/base64.rs b/src/libextra/base64.rs index 5bf4dd517a5..a53a22ee831 100644 --- a/src/libextra/base64.rs +++ b/src/libextra/base64.rs @@ -10,9 +10,8 @@ //! Base64 binary-to-text encoding -use core::prelude::*; -use core::vec; +use std::vec; /// A trait for converting a value to base64 encoding. pub trait ToBase64 { @@ -36,8 +35,8 @@ impl<'self> ToBase64 for &'self [u8] { * # Example * * ~~~ {.rust} - * extern mod std; - * use std::base64::ToBase64; + * extern mod extra; + * use extra::base64::ToBase64; * * fn main () { * let str = [52,32].to_base64(); @@ -99,8 +98,8 @@ impl<'self> ToBase64 for &'self str { * # Example * * ~~~ {.rust} - * extern mod std; - * use std::base64::ToBase64; + * extern mod extra; + * use extra::base64::ToBase64; * * fn main () { * let str = "Hello, World".to_base64(); @@ -127,9 +126,9 @@ impl<'self> FromBase64 for &'self [u8] { * # Example * * ~~~ {.rust} - * extern mod std; - * use std::base64::ToBase64; - * use std::base64::FromBase64; + * extern mod extra; + * use extra::base64::ToBase64; + * use extra::base64::FromBase64; * * fn main () { * let str = [52,32].to_base64(); @@ -199,7 +198,7 @@ impl<'self> FromBase64 for &'self str { * Convert any base64 encoded string (literal, `@`, `&`, or `~`) * to the byte values it encodes. * - * You can use the `from_bytes` function in `core::str` + * You can use the `from_bytes` function in `std::str` * to turn a `[u8]` into a string with characters corresponding to those values. * * # Example @@ -207,10 +206,10 @@ impl<'self> FromBase64 for &'self str { * This converts a string literal to base64 and back. * * ~~~ {.rust} - * extern mod std; - * use std::base64::ToBase64; - * use std::base64::FromBase64; - * use core::str; + * extern mod extra; + * use extra::base64::ToBase64; + * use extra::base64::FromBase64; + * use std::str; * * fn main () { * let hello_str = "Hello, World".to_base64(); diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index 647fa81c718..30541f83238 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -10,12 +10,11 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::cmp; -use core::ops; -use core::uint; -use core::vec; +use std::cmp; +use std::ops; +use std::uint; +use std::vec; struct SmallBitv { /// only the lowest nbits of this value are used. the rest is undefined. @@ -476,9 +475,15 @@ impl Bitv { * character is either '0' or '1'. */ pub fn to_str(&self) -> ~str { - let mut rs = ~""; - for self.each() |i| { if i { rs += "1"; } else { rs += "0"; } }; - rs + let mut rs = ~""; + for self.each() |i| { + if i { + rs.push_char('1'); + } else { + rs.push_char('0'); + } + }; + rs } @@ -639,7 +644,7 @@ impl BitvSet { if self.capacity() < other.capacity() { self.bitv.storage.grow(other.capacity() / uint::bits, &0); } - for other.bitv.storage.eachi |i, &w| { + for other.bitv.storage.iter().enumerate().advance |(i, &w)| { let old = self.bitv.storage[i]; let new = f(old, w); self.bitv.storage[i] = new; @@ -666,13 +671,9 @@ impl BitvSet { pub fn symmetric_difference_with(&mut self, other: &BitvSet) { self.other_op(other, |w1, w2| w1 ^ w2); } -} - -impl BaseIter<uint> for BitvSet { - fn size_hint(&self) -> Option<uint> { Some(self.len()) } - fn each(&self, blk: &fn(v: &uint) -> bool) -> bool { - for self.bitv.storage.eachi |i, &w| { + pub fn each(&self, blk: &fn(v: &uint) -> bool) -> bool { + for self.bitv.storage.iter().enumerate().advance |(i, &w)| { if !iterate_bits(i * uint::bits, w, |b| blk(&b)) { return false; } @@ -703,8 +704,8 @@ impl cmp::Eq for BitvSet { } impl Container for BitvSet { - fn len(&const self) -> uint { self.size } - fn is_empty(&const self) -> bool { self.size == 0 } + fn len(&self) -> uint { self.size } + fn is_empty(&self) -> bool { self.size == 0 } } impl Mutable for BitvSet { @@ -826,7 +827,7 @@ impl BitvSet { f: &fn(uint, uint, uint) -> bool) -> bool { let min = uint::min(self.bitv.storage.len(), other.bitv.storage.len()); - self.bitv.storage.slice(0, min).eachi(|i, &w| { + self.bitv.storage.slice(0, min).iter().enumerate().advance(|(i, &w)| { f(i * uint::bits, w, other.bitv.storage[i]) }) } @@ -845,12 +846,12 @@ impl BitvSet { let min = uint::min(len1, len2); /* only one of these loops will execute and that's the point */ - for self.bitv.storage.slice(min, len1).eachi |i, &w| { + for self.bitv.storage.slice(min, len1).iter().enumerate().advance |(i, &w)| { if !f(true, (i + min) * uint::bits, w) { return false; } } - for other.bitv.storage.slice(min, len2).eachi |i, &w| { + for other.bitv.storage.slice(min, len2).iter().enumerate().advance |(i, &w)| { if !f(false, (i + min) * uint::bits, w) { return false; } @@ -861,15 +862,15 @@ impl BitvSet { #[cfg(test)] mod tests { - use std::test::BenchHarness; + use extra::test::BenchHarness; use bitv::*; use bitv; - use core::uint; - use core::vec; - use core::rand; - use core::rand::Rng; + use std::uint; + use std::vec; + use std::rand; + use std::rand::Rng; static bench_bits : uint = 1 << 14; diff --git a/src/libextra/c_vec.rs b/src/libextra/c_vec.rs index fd48e7d5958..c6e7b5b0aa7 100644 --- a/src/libextra/c_vec.rs +++ b/src/libextra/c_vec.rs @@ -36,10 +36,9 @@ * still held if needed. */ -use core::prelude::*; -use core::option; -use core::ptr; +use std::option; +use std::ptr; /** * The type representing a foreign chunk of memory @@ -57,7 +56,7 @@ struct DtorRes { #[unsafe_destructor] impl Drop for DtorRes { - fn finalize(&self) { + fn drop(&self) { match self.dtor { option::None => (), option::Some(f) => f() @@ -150,8 +149,8 @@ mod tests { use c_vec::*; - use core::libc::*; - use core::libc; + use std::libc::*; + use std::libc; fn malloc(n: size_t) -> CVec<u8> { unsafe { @@ -159,8 +158,7 @@ mod tests { assert!(mem as int != 0); - return c_vec_with_dtor(mem as *mut u8, n as uint, - || unsafe { free(mem) }); + c_vec_with_dtor(mem as *mut u8, n as uint, || free(mem)) } } diff --git a/src/libextra/comm.rs b/src/libextra/comm.rs index 1001d4f6ac9..44581efc6f0 100644 --- a/src/libextra/comm.rs +++ b/src/libextra/comm.rs @@ -16,12 +16,11 @@ Higher level communication abstractions. #[allow(missing_doc)]; -use core::prelude::*; -use core::comm::{GenericChan, GenericSmartChan, GenericPort}; -use core::comm::{Chan, Port, Selectable, Peekable}; -use core::comm; -use core::pipes; +use std::comm::{GenericChan, GenericSmartChan, GenericPort}; +use std::comm::{Chan, Port, Selectable, Peekable}; +use std::comm; +use std::pipes; /// An extension of `pipes::stream` that allows both sending and receiving. pub struct DuplexStream<T, U> { @@ -30,7 +29,7 @@ pub struct DuplexStream<T, U> { } // Allow these methods to be used without import: -impl<T:Owned,U:Owned> DuplexStream<T, U> { +impl<T:Send,U:Send> DuplexStream<T, U> { pub fn send(&self, x: T) { self.chan.send(x) } @@ -48,19 +47,19 @@ impl<T:Owned,U:Owned> DuplexStream<T, U> { } } -impl<T:Owned,U:Owned> GenericChan<T> for DuplexStream<T, U> { +impl<T:Send,U:Send> GenericChan<T> for DuplexStream<T, U> { fn send(&self, x: T) { self.chan.send(x) } } -impl<T:Owned,U:Owned> GenericSmartChan<T> for DuplexStream<T, U> { +impl<T:Send,U:Send> GenericSmartChan<T> for DuplexStream<T, U> { fn try_send(&self, x: T) -> bool { self.chan.try_send(x) } } -impl<T:Owned,U:Owned> GenericPort<U> for DuplexStream<T, U> { +impl<T:Send,U:Send> GenericPort<U> for DuplexStream<T, U> { fn recv(&self) -> U { self.port.recv() } @@ -70,20 +69,20 @@ impl<T:Owned,U:Owned> GenericPort<U> for DuplexStream<T, U> { } } -impl<T:Owned,U:Owned> Peekable<U> for DuplexStream<T, U> { +impl<T:Send,U:Send> Peekable<U> for DuplexStream<T, U> { fn peek(&self) -> bool { self.port.peek() } } -impl<T:Owned,U:Owned> Selectable for DuplexStream<T, U> { +impl<T:Send,U:Send> Selectable for DuplexStream<T, U> { fn header(&mut self) -> *mut pipes::PacketHeader { self.port.header() } } /// Creates a bidirectional stream. -pub fn DuplexStream<T:Owned,U:Owned>() +pub fn DuplexStream<T:Send,U:Send>() -> (DuplexStream<T, U>, DuplexStream<U, T>) { let (p1, c2) = comm::stream(); diff --git a/src/libextra/crypto/digest.rs b/src/libextra/crypto/digest.rs new file mode 100644 index 00000000000..26e8b80d8e3 --- /dev/null +++ b/src/libextra/crypto/digest.rs @@ -0,0 +1,87 @@ +// Copyright 2012-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. + + +use std::uint; +use std::vec; + +/** + * The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2 + * family of digest functions. + */ +pub trait Digest { + /** + * Provide message data. + * + * # Arguments + * + * * input - A vector of message data + */ + fn input(&mut self, input: &[u8]); + + /** + * Retrieve the digest result. This method may be called multiple times. + */ + fn result(&mut self, out: &mut [u8]); + + /** + * Reset the digest. This method must be called after result() and before supplying more + * data. + */ + fn reset(&mut self); + + /** + * Get the output size in bits. + */ + fn output_bits(&self) -> uint; +} + +fn to_hex(rr: &[u8]) -> ~str { + let mut s = ~""; + for rr.iter().advance() |b| { + let hex = uint::to_str_radix(*b as uint, 16u); + if hex.len() == 1 { + s.push_char('0'); + } + s.push_str(hex); + } + return s; +} + +/// Contains utility methods for Digests. +/// FIXME: #7339: Convert to default methods when issues with them are resolved. +pub trait DigestUtil { + /** + * Convenience functon that feeds a string into a digest + * + * # Arguments + * + * * in The string to feed into the digest + */ + fn input_str(&mut self, in: &str); + + /** + * Convenience functon that retrieves the result of a digest as a + * ~str in hexadecimal format. + */ + fn result_str(&mut self) -> ~str; +} + +impl<D: Digest> DigestUtil for D { + fn input_str(&mut self, in: &str) { + self.input(in.as_bytes()); + } + + fn result_str(&mut self) -> ~str { + let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8); + self.result(buf); + return to_hex(buf); + } +} diff --git a/src/libextra/crypto/sha1.rs b/src/libextra/crypto/sha1.rs new file mode 100644 index 00000000000..238e4a4d238 --- /dev/null +++ b/src/libextra/crypto/sha1.rs @@ -0,0 +1,369 @@ +// 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. + +/*! + * An implementation of the SHA-1 cryptographic hash. + * + * First create a `sha1` object using the `sha1` constructor, then + * feed it input using the `input` or `input_str` methods, which may be + * called any number of times. + * + * After the entire input has been fed to the hash read the result using + * the `result` or `result_str` methods. + * + * The `sha1` object may be reused to create multiple hashes by calling + * the `reset` method. + */ + + +use digest::Digest; + +/* + * A SHA-1 implementation derived from Paul E. Jones's reference + * implementation, which is written for clarity, not speed. At some + * point this will want to be rewritten. + */ + +// Some unexported constants +static DIGEST_BUF_LEN: uint = 5u; +static MSG_BLOCK_LEN: uint = 64u; +static WORK_BUF_LEN: uint = 80u; +static K0: u32 = 0x5A827999u32; +static K1: u32 = 0x6ED9EBA1u32; +static K2: u32 = 0x8F1BBCDCu32; +static K3: u32 = 0xCA62C1D6u32; + +/// Structure representing the state of a Sha1 computation +pub struct Sha1 { + priv h: [u32, ..DIGEST_BUF_LEN], + priv len_low: u32, + priv len_high: u32, + priv msg_block: [u8, ..MSG_BLOCK_LEN], + priv msg_block_idx: uint, + priv computed: bool, + priv work_buf: [u32, ..WORK_BUF_LEN] +} + +fn add_input(st: &mut Sha1, msg: &[u8]) { + assert!((!st.computed)); + for msg.iter().advance |element| { + st.msg_block[st.msg_block_idx] = *element; + st.msg_block_idx += 1; + st.len_low += 8; + if st.len_low == 0 { + st.len_high += 1; + if st.len_high == 0 { + // FIXME: Need better failure mode (#2346) + fail!(); + } + } + if st.msg_block_idx == MSG_BLOCK_LEN { process_msg_block(st); } + } +} + +fn process_msg_block(st: &mut Sha1) { + let mut t: int; // Loop counter + let mut w = st.work_buf; + + // Initialize the first 16 words of the vector w + t = 0; + while t < 16 { + let mut tmp; + tmp = (st.msg_block[t * 4] as u32) << 24u32; + tmp = tmp | (st.msg_block[t * 4 + 1] as u32) << 16u32; + tmp = tmp | (st.msg_block[t * 4 + 2] as u32) << 8u32; + tmp = tmp | (st.msg_block[t * 4 + 3] as u32); + w[t] = tmp; + t += 1; + } + + // Initialize the rest of vector w + while t < 80 { + let val = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; + w[t] = circular_shift(1, val); + t += 1; + } + let mut a = st.h[0]; + let mut b = st.h[1]; + let mut c = st.h[2]; + let mut d = st.h[3]; + let mut e = st.h[4]; + let mut temp: u32; + t = 0; + while t < 20 { + temp = circular_shift(5, a) + (b & c | !b & d) + e + w[t] + K0; + e = d; + d = c; + c = circular_shift(30, b); + b = a; + a = temp; + t += 1; + } + while t < 40 { + temp = circular_shift(5, a) + (b ^ c ^ d) + e + w[t] + K1; + e = d; + d = c; + c = circular_shift(30, b); + b = a; + a = temp; + t += 1; + } + while t < 60 { + temp = + circular_shift(5, a) + (b & c | b & d | c & d) + e + w[t] + + K2; + e = d; + d = c; + c = circular_shift(30, b); + b = a; + a = temp; + t += 1; + } + while t < 80 { + temp = circular_shift(5, a) + (b ^ c ^ d) + e + w[t] + K3; + e = d; + d = c; + c = circular_shift(30, b); + b = a; + a = temp; + t += 1; + } + st.h[0] = st.h[0] + a; + st.h[1] = st.h[1] + b; + st.h[2] = st.h[2] + c; + st.h[3] = st.h[3] + d; + st.h[4] = st.h[4] + e; + st.msg_block_idx = 0; +} + +fn circular_shift(bits: u32, word: u32) -> u32 { + return word << bits | word >> 32u32 - bits; +} + +fn mk_result(st: &mut Sha1, rs: &mut [u8]) { + if !st.computed { pad_msg(st); st.computed = true; } + let mut i = 0; + for st.h.mut_iter().advance |ptr_hpart| { + let hpart = *ptr_hpart; + rs[i] = (hpart >> 24u32 & 0xFFu32) as u8; + rs[i+1] = (hpart >> 16u32 & 0xFFu32) as u8; + rs[i+2] = (hpart >> 8u32 & 0xFFu32) as u8; + rs[i+3] = (hpart & 0xFFu32) as u8; + i += 4; + } +} + +/* + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 bits + * represent the length of the original message. All bits in between + * should be 0. This function will pad the message according to those + * rules by filling the msg_block vector accordingly. It will also + * call process_msg_block() appropriately. When it returns, it + * can be assumed that the message digest has been computed. + */ +fn pad_msg(st: &mut Sha1) { + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second block. + */ + if st.msg_block_idx > 55 { + st.msg_block[st.msg_block_idx] = 0x80; + st.msg_block_idx += 1; + while st.msg_block_idx < MSG_BLOCK_LEN { + st.msg_block[st.msg_block_idx] = 0; + st.msg_block_idx += 1; + } + process_msg_block(st); + } else { + st.msg_block[st.msg_block_idx] = 0x80; + st.msg_block_idx += 1; + } + while st.msg_block_idx < 56 { + st.msg_block[st.msg_block_idx] = 0u8; + st.msg_block_idx += 1; + } + + // Store the message length as the last 8 octets + st.msg_block[56] = (st.len_high >> 24u32 & 0xFFu32) as u8; + st.msg_block[57] = (st.len_high >> 16u32 & 0xFFu32) as u8; + st.msg_block[58] = (st.len_high >> 8u32 & 0xFFu32) as u8; + st.msg_block[59] = (st.len_high & 0xFFu32) as u8; + st.msg_block[60] = (st.len_low >> 24u32 & 0xFFu32) as u8; + st.msg_block[61] = (st.len_low >> 16u32 & 0xFFu32) as u8; + st.msg_block[62] = (st.len_low >> 8u32 & 0xFFu32) as u8; + st.msg_block[63] = (st.len_low & 0xFFu32) as u8; + process_msg_block(st); +} + +impl Sha1 { + /// Construct a `sha` object + pub fn new() -> Sha1 { + let mut st = Sha1 { + h: [0u32, ..DIGEST_BUF_LEN], + len_low: 0u32, + len_high: 0u32, + msg_block: [0u8, ..MSG_BLOCK_LEN], + msg_block_idx: 0, + computed: false, + work_buf: [0u32, ..WORK_BUF_LEN] + }; + st.reset(); + return st; + } +} + +impl Digest for Sha1 { + pub fn reset(&mut self) { + self.len_low = 0; + self.len_high = 0; + self.msg_block_idx = 0; + self.h[0] = 0x67452301u32; + self.h[1] = 0xEFCDAB89u32; + self.h[2] = 0x98BADCFEu32; + self.h[3] = 0x10325476u32; + self.h[4] = 0xC3D2E1F0u32; + self.computed = false; + } + pub fn input(&mut self, msg: &[u8]) { add_input(self, msg); } + pub fn result(&mut self, out: &mut [u8]) { return mk_result(self, out); } + pub fn output_bits(&self) -> uint { 160 } +} + +#[cfg(test)] +mod tests { + use std::vec; + + use digest::{Digest, DigestUtil}; + use sha1::Sha1; + + #[test] + fn test() { + struct Test { + input: ~str, + output: ~[u8], + output_str: ~str, + } + + fn a_million_letter_a() -> ~str { + let mut i = 0; + let mut rs = ~""; + while i < 100000 { + rs.push_str("aaaaaaaaaa"); + i += 1; + } + return rs; + } + // Test messages from FIPS 180-1 + + let fips_180_1_tests = ~[ + Test { + input: ~"abc", + output: ~[ + 0xA9u8, 0x99u8, 0x3Eu8, 0x36u8, + 0x47u8, 0x06u8, 0x81u8, 0x6Au8, + 0xBAu8, 0x3Eu8, 0x25u8, 0x71u8, + 0x78u8, 0x50u8, 0xC2u8, 0x6Cu8, + 0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8, + ], + output_str: ~"a9993e364706816aba3e25717850c26c9cd0d89d" + }, + Test { + input: + ~"abcdbcdecdefdefgefghfghighij" + + "hijkijkljklmklmnlmnomnopnopq", + output: ~[ + 0x84u8, 0x98u8, 0x3Eu8, 0x44u8, + 0x1Cu8, 0x3Bu8, 0xD2u8, 0x6Eu8, + 0xBAu8, 0xAEu8, 0x4Au8, 0xA1u8, + 0xF9u8, 0x51u8, 0x29u8, 0xE5u8, + 0xE5u8, 0x46u8, 0x70u8, 0xF1u8, + ], + output_str: ~"84983e441c3bd26ebaae4aa1f95129e5e54670f1" + }, + Test { + input: a_million_letter_a(), + output: ~[ + 0x34u8, 0xAAu8, 0x97u8, 0x3Cu8, + 0xD4u8, 0xC4u8, 0xDAu8, 0xA4u8, + 0xF6u8, 0x1Eu8, 0xEBu8, 0x2Bu8, + 0xDBu8, 0xADu8, 0x27u8, 0x31u8, + 0x65u8, 0x34u8, 0x01u8, 0x6Fu8, + ], + output_str: ~"34aa973cd4c4daa4f61eeb2bdbad27316534016f" + }, + ]; + // Examples from wikipedia + + let wikipedia_tests = ~[ + Test { + input: ~"The quick brown fox jumps over the lazy dog", + output: ~[ + 0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8, + 0x7au8, 0x2du8, 0x28u8, 0xfcu8, + 0xedu8, 0x84u8, 0x9eu8, 0xe1u8, + 0xbbu8, 0x76u8, 0xe7u8, 0x39u8, + 0x1bu8, 0x93u8, 0xebu8, 0x12u8, + ], + output_str: ~"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + }, + Test { + input: ~"The quick brown fox jumps over the lazy cog", + output: ~[ + 0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8, + 0xd2u8, 0x5eu8, 0x1bu8, 0x3au8, + 0xfau8, 0xd3u8, 0xe8u8, 0x5au8, + 0x0bu8, 0xd1u8, 0x7du8, 0x9bu8, + 0x10u8, 0x0du8, 0xb4u8, 0xb3u8, + ], + output_str: ~"de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3", + }, + ]; + let tests = fips_180_1_tests + wikipedia_tests; + + // Test that it works when accepting the message all at once + + let mut out = [0u8, ..20]; + + let mut sh = ~Sha1::new(); + for tests.iter().advance |t| { + (*sh).input_str(t.input); + sh.result(out); + assert!(vec::eq(t.output, out)); + + let out_str = (*sh).result_str(); + assert_eq!(out_str.len(), 40); + assert!(out_str == t.output_str); + + sh.reset(); + } + + + // Test that it works when accepting the message in pieces + for tests.iter().advance |t| { + let len = t.input.len(); + let mut left = len; + while left > 0u { + let take = (left + 1u) / 2u; + (*sh).input_str(t.input.slice(len - left, take + len - left)); + left = left - take; + } + sh.result(out); + assert!(vec::eq(t.output, out)); + + let out_str = (*sh).result_str(); + assert_eq!(out_str.len(), 40); + assert!(out_str == t.output_str); + + sh.reset(); + } + } +} diff --git a/src/libextra/crypto/sha2.rs b/src/libextra/crypto/sha2.rs new file mode 100644 index 00000000000..4b120c7b118 --- /dev/null +++ b/src/libextra/crypto/sha2.rs @@ -0,0 +1,1123 @@ +// Copyright 2012-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. + + +use std::uint; + +use digest::Digest; + +// BitCounter is a specialized structure intended simply for counting the +// number of bits that have been processed by the SHA-2 512 family of functions. +// It does very little overflow checking since such checking is not necessary +// for how it is used. A more generic structure would have to do this checking. +// So, don't copy this structure and use it elsewhere! +struct BitCounter { + high_bit_count: u64, + low_byte_count: u64 +} + +impl BitCounter { + fn add_bytes(&mut self, bytes: uint) { + self.low_byte_count += bytes as u64; + if(self.low_byte_count > 0x1fffffffffffffffu64) { + self.high_bit_count += (self.low_byte_count >> 61); + self.low_byte_count &= 0x1fffffffffffffffu64; + } + } + + fn reset(&mut self) { + self.low_byte_count = 0; + self.high_bit_count = 0; + } + + fn get_low_bit_count(&self) -> u64 { + self.low_byte_count << 3 + } + + fn get_high_bit_count(&self) -> u64 { + self.high_bit_count + } +} + +// A structure that represents that state of a digest computation +// for the SHA-2 512 family of digest functions +struct Engine512 { + input_buffer: [u8, ..8], + input_buffer_idx: uint, + bit_counter: BitCounter, + H0: u64, + H1: u64, + H2: u64, + H3: u64, + H4: u64, + H5: u64, + H6: u64, + H7: u64, + W: [u64, ..80], + W_idx: uint, + finished: bool, +} + +// Convert a [u8] to a u64 in big-endian format +fn to_u64(in: &[u8]) -> u64 { + (in[0] as u64) << 56 | + (in[1] as u64) << 48 | + (in[2] as u64) << 40 | + (in[3] as u64) << 32 | + (in[4] as u64) << 24 | + (in[5] as u64) << 16 | + (in[6] as u64) << 8 | + (in[7] as u64) +} + +// Convert a u64 to a [u8] in big endian format +fn from_u64(in: u64, out: &mut [u8]) { + out[0] = (in >> 56) as u8; + out[1] = (in >> 48) as u8; + out[2] = (in >> 40) as u8; + out[3] = (in >> 32) as u8; + out[4] = (in >> 24) as u8; + out[5] = (in >> 16) as u8; + out[6] = (in >> 8) as u8; + out[7] = in as u8; +} + +impl Engine512 { + fn input_byte(&mut self, in: u8) { + assert!(!self.finished) + + self.input_buffer[self.input_buffer_idx] = in; + self.input_buffer_idx += 1; + + if (self.input_buffer_idx == 8) { + self.input_buffer_idx = 0; + let w = to_u64(self.input_buffer); + self.process_word(w); + } + + self.bit_counter.add_bytes(1); + } + + fn input_vec(&mut self, in: &[u8]) { + assert!(!self.finished) + + let mut i = 0; + + while i < in.len() && self.input_buffer_idx != 0 { + self.input_byte(in[i]); + i += 1; + } + + while in.len() - i >= 8 { + let w = to_u64(in.slice(i, i + 8)); + self.process_word(w); + self.bit_counter.add_bytes(8); + i += 8; + } + + while i < in.len() { + self.input_byte(in[i]); + i += 1; + } + } + + fn reset(&mut self) { + self.bit_counter.reset(); + self.finished = false; + self.input_buffer_idx = 0; + self.W_idx = 0; + } + + fn process_word(&mut self, in: u64) { + self.W[self.W_idx] = in; + self.W_idx += 1; + if (self.W_idx == 16) { + self.W_idx = 0; + self.process_block(); + } + } + + fn process_block(&mut self) { + fn ch(x: u64, y: u64, z: u64) -> u64 { + ((x & y) ^ ((!x) & z)) + } + + fn maj(x: u64, y: u64, z: u64) -> u64 { + ((x & y) ^ (x & z) ^ (y & z)) + } + + fn sum0(x: u64) -> u64 { + ((x << 36) | (x >> 28)) ^ ((x << 30) | (x >> 34)) ^ ((x << 25) | (x >> 39)) + } + + fn sum1(x: u64) -> u64 { + ((x << 50) | (x >> 14)) ^ ((x << 46) | (x >> 18)) ^ ((x << 23) | (x >> 41)) + } + + fn sigma0(x: u64) -> u64 { + ((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7) + } + + fn sigma1(x: u64) -> u64 { + ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6) + } + + for uint::range(16, 80) |t| { + self.W[t] = sigma1(self.W[t - 2]) + self.W[t - 7] + sigma0(self.W[t - 15]) + + self.W[t - 16]; + } + + let mut a = self.H0; + let mut b = self.H1; + let mut c = self.H2; + let mut d = self.H3; + let mut e = self.H4; + let mut f = self.H5; + let mut g = self.H6; + let mut h = self.H7; + + let mut t = 0; + for uint::range(0, 10) |_| { + h += sum1(e) + ch(e, f, g) + K64[t] + self.W[t]; + d += h; + h += sum0(a) + maj(a, b, c); + t += 1; + + g += sum1(d) + ch(d, e, f) + K64[t] + self.W[t]; + c += g; + g += sum0(h) + maj(h, a, b); + t += 1; + + f += sum1(c) + ch(c, d, e) + K64[t] + self.W[t]; + b += f; + f += sum0(g) + maj(g, h, a); + t += 1; + + e += sum1(b) + ch(b, c, d) + K64[t] + self.W[t]; + a += e; + e += sum0(f) + maj(f, g, h); + t += 1; + + d += sum1(a) + ch(a, b, c) + K64[t] + self.W[t]; + h += d; + d += sum0(e) + maj(e, f, g); + t += 1; + + c += sum1(h) + ch(h, a, b) + K64[t] + self.W[t]; + g += c; + c += sum0(d) + maj(d, e, f); + t += 1; + + b += sum1(g) + ch(g, h, a) + K64[t] + self.W[t]; + f += b; + b += sum0(c) + maj(c, d, e); + t += 1; + + a += sum1(f) + ch(f, g, h) + K64[t] + self.W[t]; + e += a; + a += sum0(b) + maj(b, c, d); + t += 1; + } + + self.H0 += a; + self.H1 += b; + self.H2 += c; + self.H3 += d; + self.H4 += e; + self.H5 += f; + self.H6 += g; + self.H7 += h; + } + + fn finish(&mut self) { + if (self.finished) { + return; + } + + // must get message length before padding is added + let high_bit_count = self.bit_counter.get_high_bit_count(); + let low_bit_count = self.bit_counter.get_low_bit_count(); + + // add padding + self.input_byte(128u8); + + while self.input_buffer_idx != 0 { + self.input_byte(0u8); + } + + // add length + if (self.W_idx > 14) { + for uint::range(self.W_idx, 16) |_| { + self.process_word(0); + } + } + + while self.W_idx < 14 { + self.process_word(0); + } + + self.process_word(high_bit_count); + self.process_word(low_bit_count); + + self.finished = true; + } + + fn result_512(&mut self, out: &mut [u8]) { + self.finish(); + + from_u64(self.H0, out.mut_slice(0, 8)); + from_u64(self.H1, out.mut_slice(8, 16)); + from_u64(self.H2, out.mut_slice(16, 24)); + from_u64(self.H3, out.mut_slice(24, 32)); + from_u64(self.H4, out.mut_slice(32, 40)); + from_u64(self.H5, out.mut_slice(40, 48)); + from_u64(self.H6, out.mut_slice(48, 56)); + from_u64(self.H7, out.mut_slice(56, 64)); + } + + fn result_384(&mut self, out: &mut [u8]) { + self.finish(); + + from_u64(self.H0, out.mut_slice(0, 8)); + from_u64(self.H1, out.mut_slice(8, 16)); + from_u64(self.H2, out.mut_slice(16, 24)); + from_u64(self.H3, out.mut_slice(24, 32)); + from_u64(self.H4, out.mut_slice(32, 40)); + from_u64(self.H5, out.mut_slice(40, 48)); + } + + fn result_256(&mut self, out: &mut [u8]) { + self.finish(); + + from_u64(self.H0, out.mut_slice(0, 8)); + from_u64(self.H1, out.mut_slice(8, 16)); + from_u64(self.H2, out.mut_slice(16, 24)); + from_u64(self.H3, out.mut_slice(24, 32)); + } + + fn result_224(&mut self, out: &mut [u8]) { + self.finish(); + + from_u64(self.H0, out.mut_slice(0, 8)); + from_u64(self.H1, out.mut_slice(8, 16)); + from_u64(self.H2, out.mut_slice(16, 24)); + from_u32((self.H3 >> 32) as u32, out.mut_slice(24, 28)); + } +} + +// Constants necessary for SHA-2 512 family of digests. +static K64: [u64, ..80] = [ + 0x428a2f98d728ae22u64, 0x7137449123ef65cdu64, 0xb5c0fbcfec4d3b2fu64, 0xe9b5dba58189dbbcu64, + 0x3956c25bf348b538u64, 0x59f111f1b605d019u64, 0x923f82a4af194f9bu64, 0xab1c5ed5da6d8118u64, + 0xd807aa98a3030242u64, 0x12835b0145706fbeu64, 0x243185be4ee4b28cu64, 0x550c7dc3d5ffb4e2u64, + 0x72be5d74f27b896fu64, 0x80deb1fe3b1696b1u64, 0x9bdc06a725c71235u64, 0xc19bf174cf692694u64, + 0xe49b69c19ef14ad2u64, 0xefbe4786384f25e3u64, 0x0fc19dc68b8cd5b5u64, 0x240ca1cc77ac9c65u64, + 0x2de92c6f592b0275u64, 0x4a7484aa6ea6e483u64, 0x5cb0a9dcbd41fbd4u64, 0x76f988da831153b5u64, + 0x983e5152ee66dfabu64, 0xa831c66d2db43210u64, 0xb00327c898fb213fu64, 0xbf597fc7beef0ee4u64, + 0xc6e00bf33da88fc2u64, 0xd5a79147930aa725u64, 0x06ca6351e003826fu64, 0x142929670a0e6e70u64, + 0x27b70a8546d22ffcu64, 0x2e1b21385c26c926u64, 0x4d2c6dfc5ac42aedu64, 0x53380d139d95b3dfu64, + 0x650a73548baf63deu64, 0x766a0abb3c77b2a8u64, 0x81c2c92e47edaee6u64, 0x92722c851482353bu64, + 0xa2bfe8a14cf10364u64, 0xa81a664bbc423001u64, 0xc24b8b70d0f89791u64, 0xc76c51a30654be30u64, + 0xd192e819d6ef5218u64, 0xd69906245565a910u64, 0xf40e35855771202au64, 0x106aa07032bbd1b8u64, + 0x19a4c116b8d2d0c8u64, 0x1e376c085141ab53u64, 0x2748774cdf8eeb99u64, 0x34b0bcb5e19b48a8u64, + 0x391c0cb3c5c95a63u64, 0x4ed8aa4ae3418acbu64, 0x5b9cca4f7763e373u64, 0x682e6ff3d6b2b8a3u64, + 0x748f82ee5defb2fcu64, 0x78a5636f43172f60u64, 0x84c87814a1f0ab72u64, 0x8cc702081a6439ecu64, + 0x90befffa23631e28u64, 0xa4506cebde82bde9u64, 0xbef9a3f7b2c67915u64, 0xc67178f2e372532bu64, + 0xca273eceea26619cu64, 0xd186b8c721c0c207u64, 0xeada7dd6cde0eb1eu64, 0xf57d4f7fee6ed178u64, + 0x06f067aa72176fbau64, 0x0a637dc5a2c898a6u64, 0x113f9804bef90daeu64, 0x1b710b35131c471bu64, + 0x28db77f523047d84u64, 0x32caab7b40c72493u64, 0x3c9ebe0a15c9bebcu64, 0x431d67c49c100d4cu64, + 0x4cc5d4becb3e42b6u64, 0x597f299cfc657e2au64, 0x5fcb6fab3ad6faecu64, 0x6c44198c4a475817u64 +]; + +// A structure that represents that state of a digest computation +// for the SHA-2 256 family of digest functions +struct Engine256 { + input_buffer: [u8, ..4], + input_buffer_idx: uint, + length_bytes: u64, + H0: u32, + H1: u32, + H2: u32, + H3: u32, + H4: u32, + H5: u32, + H6: u32, + H7: u32, + W: [u32, ..64], + W_idx: uint, + finished: bool +} + +// Convert a [u8] to a u32 in big endian format +fn to_u32(in: &[u8]) -> u32 { + (in[0] as u32) << 24 | + (in[1] as u32) << 16 | + (in[2] as u32) << 8 | + (in[3] as u32) +} + +// Convert a u32 to a [u8] in big endian format +fn from_u32(in: u32, out: &mut [u8]) { + out[0] = (in >> 24) as u8; + out[1] = (in >> 16) as u8; + out[2] = (in >> 8) as u8; + out[3] = in as u8; +} + +impl Engine256 { + fn input_byte(&mut self, in: u8) { + assert!(!self.finished) + + self.input_buffer[self.input_buffer_idx] = in; + self.input_buffer_idx += 1; + + if (self.input_buffer_idx == 4) { + self.input_buffer_idx = 0; + let w = to_u32(self.input_buffer); + self.process_word(w); + } + + self.length_bytes += 1; + } + + fn input_vec(&mut self, in: &[u8]) { + assert!(!self.finished) + + let mut i = 0; + + while i < in.len() && self.input_buffer_idx != 0 { + self.input_byte(in[i]); + i += 1; + } + + while in.len() - i >= 4 { + let w = to_u32(in.slice(i, i + 4)); + self.process_word(w); + self.length_bytes += 4; + i += 4; + } + + while i < in.len() { + self.input_byte(in[i]); + i += 1; + } + + } + + fn reset(&mut self) { + self.length_bytes = 0; + self.finished = false; + self.input_buffer_idx = 0; + self.W_idx = 0; + } + + fn process_word(&mut self, in: u32) { + self.W[self.W_idx] = in; + self.W_idx += 1; + if (self.W_idx == 16) { + self.W_idx = 0; + self.process_block(); + } + } + + fn process_block(&mut self) { + fn ch(x: u32, y: u32, z: u32) -> u32 { + ((x & y) ^ ((!x) & z)) + } + + fn maj(x: u32, y: u32, z: u32) -> u32 { + ((x & y) ^ (x & z) ^ (y & z)) + } + + fn sum0(x: u32) -> u32 { + ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10)) + } + + fn sum1(x: u32) -> u32 { + ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7)) + } + + fn sigma0(x: u32) -> u32 { + ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ (x >> 3) + } + + fn sigma1(x: u32) -> u32 { + ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10) + } + + for uint::range(16, 64) |t| { + self.W[t] = sigma1(self.W[t - 2]) + self.W[t - 7] + sigma0(self.W[t - 15]) + + self.W[t - 16]; + } + + let mut a = self.H0; + let mut b = self.H1; + let mut c = self.H2; + let mut d = self.H3; + let mut e = self.H4; + let mut f = self.H5; + let mut g = self.H6; + let mut h = self.H7; + + let mut t = 0; + for uint::range(0, 8) |_| { + h += sum1(e) + ch(e, f, g) + K32[t] + self.W[t]; + d += h; + h += sum0(a) + maj(a, b, c); + t += 1; + + g += sum1(d) + ch(d, e, f) + K32[t] + self.W[t]; + c += g; + g += sum0(h) + maj(h, a, b); + t += 1; + + f += sum1(c) + ch(c, d, e) + K32[t] + self.W[t]; + b += f; + f += sum0(g) + maj(g, h, a); + t += 1; + + e += sum1(b) + ch(b, c, d) + K32[t] + self.W[t]; + a += e; + e += sum0(f) + maj(f, g, h); + t += 1; + + d += sum1(a) + ch(a, b, c) + K32[t] + self.W[t]; + h += d; + d += sum0(e) + maj(e, f, g); + t += 1; + + c += sum1(h) + ch(h, a, b) + K32[t] + self.W[t]; + g += c; + c += sum0(d) + maj(d, e, f); + t += 1; + + b += sum1(g) + ch(g, h, a) + K32[t] + self.W[t]; + f += b; + b += sum0(c) + maj(c, d, e); + t += 1; + + a += sum1(f) + ch(f, g, h) + K32[t] + self.W[t]; + e += a; + a += sum0(b) + maj(b, c, d); + t += 1; + } + + self.H0 += a; + self.H1 += b; + self.H2 += c; + self.H3 += d; + self.H4 += e; + self.H5 += f; + self.H6 += g; + self.H7 += h; + } + + fn finish(&mut self) { + if (self.finished) { + return; + } + + // must get length before adding padding + let bit_length = self.length_bytes << 3; + + // add padding + self.input_byte(128u8); + + while self.input_buffer_idx != 0 { + self.input_byte(0u8); + } + + // add length + if (self.W_idx > 14) { + for uint::range(self.W_idx, 16) |_| { + self.process_word(0); + } + } + + while self.W_idx < 14 { + self.process_word(0); + } + + self.process_word((bit_length >> 32) as u32); + self.process_word(bit_length as u32); + + self.finished = true; + } + + fn result_256(&mut self, out: &mut [u8]) { + self.finish(); + + from_u32(self.H0, out.mut_slice(0, 4)); + from_u32(self.H1, out.mut_slice(4, 8)); + from_u32(self.H2, out.mut_slice(8, 12)); + from_u32(self.H3, out.mut_slice(12, 16)); + from_u32(self.H4, out.mut_slice(16, 20)); + from_u32(self.H5, out.mut_slice(20, 24)); + from_u32(self.H6, out.mut_slice(24, 28)); + from_u32(self.H7, out.mut_slice(28, 32)); + } + + fn result_224(&mut self, out: &mut [u8]) { + self.finish(); + + from_u32(self.H0, out.mut_slice(0, 4)); + from_u32(self.H1, out.mut_slice(4, 8)); + from_u32(self.H2, out.mut_slice(8, 12)); + from_u32(self.H3, out.mut_slice(12, 16)); + from_u32(self.H4, out.mut_slice(16, 20)); + from_u32(self.H5, out.mut_slice(20, 24)); + from_u32(self.H6, out.mut_slice(24, 28)); + } +} + +static K32: [u32, ..64] = [ + 0x428a2f98u32, 0x71374491u32, 0xb5c0fbcfu32, 0xe9b5dba5u32, + 0x3956c25bu32, 0x59f111f1u32, 0x923f82a4u32, 0xab1c5ed5u32, + 0xd807aa98u32, 0x12835b01u32, 0x243185beu32, 0x550c7dc3u32, + 0x72be5d74u32, 0x80deb1feu32, 0x9bdc06a7u32, 0xc19bf174u32, + 0xe49b69c1u32, 0xefbe4786u32, 0x0fc19dc6u32, 0x240ca1ccu32, + 0x2de92c6fu32, 0x4a7484aau32, 0x5cb0a9dcu32, 0x76f988dau32, + 0x983e5152u32, 0xa831c66du32, 0xb00327c8u32, 0xbf597fc7u32, + 0xc6e00bf3u32, 0xd5a79147u32, 0x06ca6351u32, 0x14292967u32, + 0x27b70a85u32, 0x2e1b2138u32, 0x4d2c6dfcu32, 0x53380d13u32, + 0x650a7354u32, 0x766a0abbu32, 0x81c2c92eu32, 0x92722c85u32, + 0xa2bfe8a1u32, 0xa81a664bu32, 0xc24b8b70u32, 0xc76c51a3u32, + 0xd192e819u32, 0xd6990624u32, 0xf40e3585u32, 0x106aa070u32, + 0x19a4c116u32, 0x1e376c08u32, 0x2748774cu32, 0x34b0bcb5u32, + 0x391c0cb3u32, 0x4ed8aa4au32, 0x5b9cca4fu32, 0x682e6ff3u32, + 0x748f82eeu32, 0x78a5636fu32, 0x84c87814u32, 0x8cc70208u32, + 0x90befffau32, 0xa4506cebu32, 0xbef9a3f7u32, 0xc67178f2u32 +]; + +struct Sha512 { + priv engine: Engine512 +} + +struct Sha384 { + priv engine: Engine512 +} + +struct Sha512Trunc256 { + priv engine: Engine512 +} + +struct Sha512Trunc224 { + priv engine: Engine512 +} + +struct Sha256 { + priv engine: Engine256 +} + +struct Sha224 { + priv engine: Engine256 +} + +impl Sha512 { + /** + * Construct an new instance of a SHA-512 digest. + */ + pub fn new() -> Sha512 { + Sha512 { + engine: Engine512 { + input_buffer: [0u8, ..8], + input_buffer_idx: 0, + bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, + H0: 0x6a09e667f3bcc908u64, + H1: 0xbb67ae8584caa73bu64, + H2: 0x3c6ef372fe94f82bu64, + H3: 0xa54ff53a5f1d36f1u64, + H4: 0x510e527fade682d1u64, + H5: 0x9b05688c2b3e6c1fu64, + H6: 0x1f83d9abfb41bd6bu64, + H7: 0x5be0cd19137e2179u64, + W: [0u64, ..80], + W_idx: 0, + finished: false, + } + } + } +} + +impl Sha384 { + /** + * Construct an new instance of a SHA-384 digest. + */ + pub fn new() -> Sha384 { + Sha384 { + engine: Engine512 { + input_buffer: [0u8, ..8], + input_buffer_idx: 0, + bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, + H0: 0xcbbb9d5dc1059ed8u64, + H1: 0x629a292a367cd507u64, + H2: 0x9159015a3070dd17u64, + H3: 0x152fecd8f70e5939u64, + H4: 0x67332667ffc00b31u64, + H5: 0x8eb44a8768581511u64, + H6: 0xdb0c2e0d64f98fa7u64, + H7: 0x47b5481dbefa4fa4u64, + W: [0u64, ..80], + W_idx: 0, + finished: false, + } + } + } +} + +impl Sha512Trunc256 { + /** + * Construct an new instance of a SHA-512/256 digest. + */ + pub fn new() -> Sha512Trunc256 { + Sha512Trunc256 { + engine: Engine512 { + input_buffer: [0u8, ..8], + input_buffer_idx: 0, + bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, + H0: 0x22312194fc2bf72cu64, + H1: 0x9f555fa3c84c64c2u64, + H2: 0x2393b86b6f53b151u64, + H3: 0x963877195940eabdu64, + H4: 0x96283ee2a88effe3u64, + H5: 0xbe5e1e2553863992u64, + H6: 0x2b0199fc2c85b8aau64, + H7: 0x0eb72ddc81c52ca2u64, + W: [0u64, ..80], + W_idx: 0, + finished: false, + } + } + } +} + +impl Sha512Trunc224 { + /** + * Construct an new instance of a SHA-512/224 digest. + */ + pub fn new() -> Sha512Trunc224 { + Sha512Trunc224 { + engine: Engine512 { + input_buffer: [0u8, ..8], + input_buffer_idx: 0, + bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, + H0: 0x8c3d37c819544da2u64, + H1: 0x73e1996689dcd4d6u64, + H2: 0x1dfab7ae32ff9c82u64, + H3: 0x679dd514582f9fcfu64, + H4: 0x0f6d2b697bd44da8u64, + H5: 0x77e36f7304c48942u64, + H6: 0x3f9d85a86a1d36c8u64, + H7: 0x1112e6ad91d692a1u64, + W: [0u64, ..80], + W_idx: 0, + finished: false, + } + } + } +} + +impl Sha256 { + /** + * Construct an new instance of a SHA-256 digest. + */ + pub fn new() -> Sha256 { + Sha256 { + engine: Engine256 { + input_buffer: [0u8, ..4], + input_buffer_idx: 0, + length_bytes: 0, + H0: 0x6a09e667u32, + H1: 0xbb67ae85u32, + H2: 0x3c6ef372u32, + H3: 0xa54ff53au32, + H4: 0x510e527fu32, + H5: 0x9b05688cu32, + H6: 0x1f83d9abu32, + H7: 0x5be0cd19u32, + W: [0u32, ..64], + W_idx: 0, + finished: false, + } + } + } +} + +impl Sha224 { + /** + * Construct an new instance of a SHA-224 digest. + */ + pub fn new() -> Sha224 { + Sha224 { + engine: Engine256 { + input_buffer: [0u8, ..4], + input_buffer_idx: 0, + length_bytes: 0, + H0: 0xc1059ed8u32, + H1: 0x367cd507u32, + H2: 0x3070dd17u32, + H3: 0xf70e5939u32, + H4: 0xffc00b31u32, + H5: 0x68581511u32, + H6: 0x64f98fa7u32, + H7: 0xbefa4fa4u32, + W: [0u32, ..64], + W_idx: 0, + finished: false, + } + } + } +} + +impl Digest for Sha512 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_512(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0x6a09e667f3bcc908u64; + self.engine.H1 = 0xbb67ae8584caa73bu64; + self.engine.H2 = 0x3c6ef372fe94f82bu64; + self.engine.H3 = 0xa54ff53a5f1d36f1u64; + self.engine.H4 = 0x510e527fade682d1u64; + self.engine.H5 = 0x9b05688c2b3e6c1fu64; + self.engine.H6 = 0x1f83d9abfb41bd6bu64; + self.engine.H7 = 0x5be0cd19137e2179u64; + } + + fn output_bits(&self) -> uint { 512 } +} + +impl Digest for Sha384 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_384(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0xcbbb9d5dc1059ed8u64; + self.engine.H1 = 0x629a292a367cd507u64; + self.engine.H2 = 0x9159015a3070dd17u64; + self.engine.H3 = 0x152fecd8f70e5939u64; + self.engine.H4 = 0x67332667ffc00b31u64; + self.engine.H5 = 0x8eb44a8768581511u64; + self.engine.H6 = 0xdb0c2e0d64f98fa7u64; + self.engine.H7 = 0x47b5481dbefa4fa4u64; + } + + fn output_bits(&self) -> uint { 384 } +} + +impl Digest for Sha512Trunc256 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_256(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0x22312194fc2bf72cu64; + self.engine.H1 = 0x9f555fa3c84c64c2u64; + self.engine.H2 = 0x2393b86b6f53b151u64; + self.engine.H3 = 0x963877195940eabdu64; + self.engine.H4 = 0x96283ee2a88effe3u64; + self.engine.H5 = 0xbe5e1e2553863992u64; + self.engine.H6 = 0x2b0199fc2c85b8aau64; + self.engine.H7 = 0x0eb72ddc81c52ca2u64; + } + + fn output_bits(&self) -> uint { 256 } +} + +impl Digest for Sha512Trunc224 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_224(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0x8c3d37c819544da2u64; + self.engine.H1 = 0x73e1996689dcd4d6u64; + self.engine.H2 = 0x1dfab7ae32ff9c82u64; + self.engine.H3 = 0x679dd514582f9fcfu64; + self.engine.H4 = 0x0f6d2b697bd44da8u64; + self.engine.H5 = 0x77e36f7304c48942u64; + self.engine.H6 = 0x3f9d85a86a1d36c8u64; + self.engine.H7 = 0x1112e6ad91d692a1u64; + } + + fn output_bits(&self) -> uint { 224 } +} + +impl Digest for Sha256 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_256(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0x6a09e667u32; + self.engine.H1 = 0xbb67ae85u32; + self.engine.H2 = 0x3c6ef372u32; + self.engine.H3 = 0xa54ff53au32; + self.engine.H4 = 0x510e527fu32; + self.engine.H5 = 0x9b05688cu32; + self.engine.H6 = 0x1f83d9abu32; + self.engine.H7 = 0x5be0cd19u32; + } + + fn output_bits(&self) -> uint { 256 } +} + +impl Digest for Sha224 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_224(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0xc1059ed8u32; + self.engine.H1 = 0x367cd507u32; + self.engine.H2 = 0x3070dd17u32; + self.engine.H3 = 0xf70e5939u32; + self.engine.H4 = 0xffc00b31u32; + self.engine.H5 = 0x68581511u32; + self.engine.H6 = 0x64f98fa7u32; + self.engine.H7 = 0xbefa4fa4u32; + } + + fn output_bits(&self) -> uint { 224 } +} + + +#[cfg(test)] +mod tests { + use digest::{Digest, DigestUtil}; + use sha2::{Sha512, Sha384, Sha512Trunc256, Sha512Trunc224, Sha256, Sha224}; + + struct Test { + input: ~str, + output_str: ~str, + } + + fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) { + // Test that it works when accepting the message all at once + for tests.iter().advance() |t| { + sh.input_str(t.input); + + let out_str = sh.result_str(); + assert!(out_str == t.output_str); + + sh.reset(); + } + + // Test that it works when accepting the message in pieces + for tests.iter().advance() |t| { + let len = t.input.len(); + let mut left = len; + while left > 0u { + let take = (left + 1u) / 2u; + sh.input_str(t.input.slice(len - left, take + len - left)); + left = left - take; + } + + let out_str = sh.result_str(); + assert!(out_str == t.output_str); + + sh.reset(); + } + } + + #[test] + fn test_sha512() { + // Examples from wikipedia + let wikipedia_tests = ~[ + Test { + input: ~"", + output_str: ~"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce" + + "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog", + output_str: ~"07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb64" + + "2e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog.", + output_str: ~"91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bb" + + "c6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed" + }, + ]; + + let tests = wikipedia_tests; + + let mut sh = ~Sha512::new(); + + test_hash(sh, tests); + } + + #[test] + fn test_sha384() { + // Examples from wikipedia + let wikipedia_tests = ~[ + Test { + input: ~"", + output_str: ~"38b060a751ac96384cd9327eb1b1e36a21fdb71114be0743" + + "4c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog", + output_str: ~"ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c49" + + "4011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog.", + output_str: ~"ed892481d8272ca6df370bf706e4d7bc1b5739fa2177aae6" + + "c50e946678718fc67a7af2819a021c2fc34e91bdb63409d7" + }, + ]; + + let tests = wikipedia_tests; + + let mut sh = ~Sha384::new(); + + test_hash(sh, tests); + } + + #[test] + fn test_sha512_256() { + // Examples from wikipedia + let wikipedia_tests = ~[ + Test { + input: ~"", + output_str: ~"c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog", + output_str: ~"dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog.", + output_str: ~"1546741840f8a492b959d9b8b2344b9b0eb51b004bba35c0aebaac86d45264c3" + }, + ]; + + let tests = wikipedia_tests; + + let mut sh = ~Sha512Trunc256::new(); + + test_hash(sh, tests); + } + + #[test] + fn test_sha512_224() { + // Examples from wikipedia + let wikipedia_tests = ~[ + Test { + input: ~"", + output_str: ~"6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog", + output_str: ~"944cd2847fb54558d4775db0485a50003111c8e5daa63fe722c6aa37" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog.", + output_str: ~"6d6a9279495ec4061769752e7ff9c68b6b0b3c5a281b7917ce0572de" + }, + ]; + + let tests = wikipedia_tests; + + let mut sh = ~Sha512Trunc224::new(); + + test_hash(sh, tests); + } + + #[test] + fn test_sha256() { + // Examples from wikipedia + let wikipedia_tests = ~[ + Test { + input: ~"", + output_str: ~"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog", + output_str: ~"d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog.", + output_str: ~"ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c" + }, + ]; + + let tests = wikipedia_tests; + + let mut sh = ~Sha256::new(); + + test_hash(sh, tests); + } + + #[test] + fn test_sha224() { + // Examples from wikipedia + let wikipedia_tests = ~[ + Test { + input: ~"", + output_str: ~"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog", + output_str: ~"730e109bd7a8a32b1cb9d9a09aa2325d2430587ddbc0c38bad911525" + }, + Test { + input: ~"The quick brown fox jumps over the lazy dog.", + output_str: ~"619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4c" + }, + ]; + + let tests = wikipedia_tests; + + let mut sh = ~Sha224::new(); + + test_hash(sh, tests); + } +} diff --git a/src/libextra/dbg.rs b/src/libextra/dbg.rs index cbd7cb5e3c0..1f424b23430 100644 --- a/src/libextra/dbg.rs +++ b/src/libextra/dbg.rs @@ -12,57 +12,63 @@ #[allow(missing_doc)]; -use core::cast::transmute; -use core::sys; +use std::cast::transmute; +#[cfg(stage0)] +use intrinsic::{get_tydesc}; +#[cfg(not(stage0))] +use std::unstable::intrinsics::{get_tydesc}; pub mod rustrt { - use core::sys; + #[cfg(stage0)] + use intrinsic::{TyDesc}; + #[cfg(not(stage0))] + use std::unstable::intrinsics::{TyDesc}; #[abi = "cdecl"] pub extern { - pub unsafe fn debug_tydesc(td: *sys::TypeDesc); - pub unsafe fn debug_opaque(td: *sys::TypeDesc, x: *()); - pub unsafe fn debug_box(td: *sys::TypeDesc, x: *()); - pub unsafe fn debug_tag(td: *sys::TypeDesc, x: *()); - pub unsafe fn debug_fn(td: *sys::TypeDesc, x: *()); - pub unsafe fn debug_ptrcast(td: *sys::TypeDesc, x: *()) -> *(); + pub unsafe fn debug_tydesc(td: *TyDesc); + pub unsafe fn debug_opaque(td: *TyDesc, x: *()); + pub unsafe fn debug_box(td: *TyDesc, x: *()); + pub unsafe fn debug_tag(td: *TyDesc, x: *()); + pub unsafe fn debug_fn(td: *TyDesc, x: *()); + pub unsafe fn debug_ptrcast(td: *TyDesc, x: *()) -> *(); pub unsafe fn rust_dbg_breakpoint(); } } pub fn debug_tydesc<T>() { unsafe { - rustrt::debug_tydesc(sys::get_type_desc::<T>()); + rustrt::debug_tydesc(get_tydesc::<T>()); } } pub fn debug_opaque<T>(x: T) { unsafe { - rustrt::debug_opaque(sys::get_type_desc::<T>(), transmute(&x)); + rustrt::debug_opaque(get_tydesc::<T>(), transmute(&x)); } } pub fn debug_box<T>(x: @T) { unsafe { - rustrt::debug_box(sys::get_type_desc::<T>(), transmute(&x)); + rustrt::debug_box(get_tydesc::<T>(), transmute(&x)); } } pub fn debug_tag<T>(x: T) { unsafe { - rustrt::debug_tag(sys::get_type_desc::<T>(), transmute(&x)); + rustrt::debug_tag(get_tydesc::<T>(), transmute(&x)); } } pub fn debug_fn<T>(x: T) { unsafe { - rustrt::debug_fn(sys::get_type_desc::<T>(), transmute(&x)); + rustrt::debug_fn(get_tydesc::<T>(), transmute(&x)); } } pub unsafe fn ptr_cast<T, U>(x: @T) -> @U { transmute( - rustrt::debug_ptrcast(sys::get_type_desc::<T>(), transmute(x))) + rustrt::debug_ptrcast(get_tydesc::<T>(), transmute(x))) } /// Triggers a debugger breakpoint diff --git a/src/libextra/deque.rs b/src/libextra/deque.rs index c8bb984736a..f834860a4f7 100644 --- a/src/libextra/deque.rs +++ b/src/libextra/deque.rs @@ -10,11 +10,10 @@ //! A double-ended queue implemented as a circular buffer -use core::prelude::*; - -use core::uint; -use core::util::replace; -use core::vec; +use std::uint; +use std::util::replace; +use std::vec; +use std::cast::transmute; static initial_capacity: uint = 32u; // 2^5 @@ -28,10 +27,10 @@ pub struct Deque<T> { impl<T> Container for Deque<T> { /// Return the number of elements in the deque - fn len(&const self) -> uint { self.nelts } + fn len(&self) -> uint { self.nelts } /// Return true if the deque contains no elements - fn is_empty(&const self) -> bool { self.len() == 0 } + fn is_empty(&self) -> bool { self.len() == 0 } } impl<T> Mutable for Deque<T> { @@ -137,7 +136,7 @@ impl<T> Deque<T> { /// /// * n - The number of elements to reserve space for pub fn reserve(&mut self, n: uint) { - vec::reserve(&mut self.elts, n); + self.elts.reserve(n); } /// Reserve capacity for at least `n` elements in the given deque, @@ -151,10 +150,89 @@ impl<T> Deque<T> { /// /// * n - The number of elements to reserve space for pub fn reserve_at_least(&mut self, n: uint) { - vec::reserve_at_least(&mut self.elts, n); + self.elts.reserve_at_least(n); + } + + /// Front-to-back iterator. + pub fn iter<'a>(&'a self) -> DequeIterator<'a, T> { + DequeIterator { idx: self.lo, nelts: self.nelts, used: 0, vec: self.elts } + } + + /// Front-to-back iterator which returns mutable values. + pub fn mut_iter<'a>(&'a mut self) -> DequeMutIterator<'a, T> { + DequeMutIterator { idx: self.lo, nelts: self.nelts, used: 0, vec: self.elts } + } + + /// Back-to-front iterator. + pub fn rev_iter<'a>(&'a self) -> DequeRevIterator<'a, T> { + DequeRevIterator { idx: self.hi - 1u, nelts: self.nelts, used: 0, vec: self.elts } + } + + /// Back-to-front iterator which returns mutable values. + pub fn mut_rev_iter<'a>(&'a mut self) -> DequeMutRevIterator<'a, T> { + DequeMutRevIterator { idx: self.hi - 1u, nelts: self.nelts, used: 0, vec: self.elts } + } +} + +macro_rules! iterator { + (impl $name:ident -> $elem:ty, $step:expr) => { + impl<'self, T> Iterator<$elem> for $name<'self, T> { + #[inline] + fn next(&mut self) -> Option<$elem> { + if self.used >= self.nelts { + return None; + } + let ret = unsafe { + match self.vec[self.idx % self.vec.len()] { + Some(ref e) => Some(transmute(e)), + None => None + } + }; + self.idx += $step; + self.used += 1; + ret + } + } } } +/// Deque iterator +pub struct DequeIterator<'self, T> { + priv idx: uint, + priv nelts: uint, + priv used: uint, + priv vec: &'self [Option<T>] +} +iterator!{impl DequeIterator -> &'self T, 1} + +/// Deque reverse iterator +pub struct DequeRevIterator<'self, T> { + priv idx: uint, + priv nelts: uint, + priv used: uint, + priv vec: &'self [Option<T>] +} +iterator!{impl DequeRevIterator -> &'self T, -1} + +/// Deque mutable iterator +pub struct DequeMutIterator<'self, T> { + priv idx: uint, + priv nelts: uint, + priv used: uint, + priv vec: &'self mut [Option<T>] + +} +iterator!{impl DequeMutIterator -> &'self mut T, 1} + +/// Deque mutable reverse iterator +pub struct DequeMutRevIterator<'self, T> { + priv idx: uint, + priv nelts: uint, + priv used: uint, + priv vec: &'self mut [Option<T>] +} +iterator!{impl DequeMutRevIterator -> &'self mut T, -1} + /// Grow is only called on full elts, so nelts is also len(elts), unlike /// elsewhere. fn grow<T>(nelts: uint, lo: uint, elts: &mut [Option<T>]) -> ~[Option<T>] { @@ -175,9 +253,9 @@ fn get<'r, T>(elts: &'r [Option<T>], i: uint) -> &'r T { #[cfg(test)] mod tests { use super::*; - use core::cmp::Eq; - use core::kinds::Copy; - use core::vec::capacity; + use std::cmp::Eq; + use std::kinds::Copy; + use std::int; #[test] fn test_simple() { @@ -318,8 +396,7 @@ mod tests { #[test] fn test_param_taggy() { - test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3), - Two(17, 42)); + test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3), Two(17, 42)); } #[test] @@ -363,11 +440,11 @@ mod tests { let mut d = Deque::new(); d.add_back(0u64); d.reserve(50); - assert_eq!(capacity(&mut d.elts), 50); + assert_eq!(d.elts.capacity(), 50); let mut d = Deque::new(); d.add_back(0u32); d.reserve(50); - assert_eq!(capacity(&mut d.elts), 50); + assert_eq!(d.elts.capacity(), 50); } #[test] @@ -375,11 +452,38 @@ mod tests { let mut d = Deque::new(); d.add_back(0u64); d.reserve_at_least(50); - assert_eq!(capacity(&mut d.elts), 64); + assert_eq!(d.elts.capacity(), 64); let mut d = Deque::new(); d.add_back(0u32); d.reserve_at_least(50); - assert_eq!(capacity(&mut d.elts), 64); + assert_eq!(d.elts.capacity(), 64); } + #[test] + fn test_iter() { + let mut d = Deque::new(); + for int::range(0,5) |i| { + d.add_back(i); + } + assert_eq!(d.iter().collect::<~[&int]>(), ~[&0,&1,&2,&3,&4]); + + for int::range(6,9) |i| { + d.add_front(i); + } + assert_eq!(d.iter().collect::<~[&int]>(), ~[&8,&7,&6,&0,&1,&2,&3,&4]); + } + + #[test] + fn test_rev_iter() { + let mut d = Deque::new(); + for int::range(0,5) |i| { + d.add_back(i); + } + assert_eq!(d.rev_iter().collect::<~[&int]>(), ~[&4,&3,&2,&1,&0]); + + for int::range(6,9) |i| { + d.add_front(i); + } + assert_eq!(d.rev_iter().collect::<~[&int]>(), ~[&4,&3,&2,&1,&0,&6,&7,&8]); + } } diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index 953803c6843..e7dcb0fd7ce 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -18,11 +18,8 @@ Do not use ==, !=, <, etc on doubly-linked lists -- it may not terminate. */ -use core::prelude::*; -use core::managed; -use core::old_iter; -use core::vec; +use std::managed; pub type DListLink<T> = Option<@mut DListNode<T>>; @@ -213,6 +210,42 @@ impl<T> DList<T> { } impl<T> DList<T> { + /** + * Iterates through the current contents. + * + * Attempts to access this dlist during iteration are allowed (to + * allow for e.g. breadth-first search with in-place enqueues), but + * removing the current node is forbidden. + */ + pub fn each(@mut self, f: &fn(v: &T) -> bool) -> bool { + let mut link = self.peek_n(); + while link.is_some() { + let nobe = link.get(); + assert!(nobe.linked); + + { + let frozen_nobe = &*nobe; + if !f(&frozen_nobe.data) { return false; } + } + + // Check (weakly) that the user didn't do a remove. + if self.size == 0 { + fail!("The dlist became empty during iteration??") + } + if !nobe.linked || + (!((nobe.prev.is_some() + || managed::mut_ptr_eq(self.hd.expect("headless dlist?"), + nobe)) + && (nobe.next.is_some() + || managed::mut_ptr_eq(self.tl.expect("tailless dlist?"), + nobe)))) { + fail!("Removing a dlist node during iteration is forbidden!") + } + link = nobe.next_link(); + } + return true; + } + /// Get the size of the list. O(1). pub fn len(@mut self) -> uint { self.size } /// Returns true if the list is empty. O(1). @@ -484,67 +517,13 @@ impl<T:Copy> DList<T> { /// Get data at the list's tail, failing if empty. O(1). pub fn tail(@mut self) -> T { copy self.tail_n().data } - - /// Get the elements of the list as a vector. O(n). - pub fn to_vec(@mut self) -> ~[T] { - let mut v = vec::with_capacity(self.size); - for old_iter::eachi(&self) |index,data| { - v[index] = copy *data; - } - v - } -} - -impl<T> BaseIter<T> for @mut DList<T> { - /** - * Iterates through the current contents. - * - * Attempts to access this dlist during iteration are allowed (to - * allow for e.g. breadth-first search with in-place enqueues), but - * removing the current node is forbidden. - */ - fn each(&self, f: &fn(v: &T) -> bool) -> bool { - let mut link = self.peek_n(); - while link.is_some() { - let nobe = link.get(); - assert!(nobe.linked); - - { - let frozen_nobe = &*nobe; - if !f(&frozen_nobe.data) { return false; } - } - - // Check (weakly) that the user didn't do a remove. - if self.size == 0 { - fail!("The dlist became empty during iteration??") - } - if !nobe.linked || - (!((nobe.prev.is_some() - || managed::mut_ptr_eq(self.hd.expect("headless dlist?"), - nobe)) - && (nobe.next.is_some() - || managed::mut_ptr_eq(self.tl.expect("tailless dlist?"), - nobe)))) { - fail!("Removing a dlist node during iteration is forbidden!") - } - link = nobe.next_link(); - } - return true; - } - - #[inline] - fn size_hint(&self) -> Option<uint> { Some(self.len()) } } #[cfg(test)] mod tests { - use core::prelude::*; use super::*; - use core::old_iter; - use core::vec; - #[test] fn test_dlist_concat() { let a = from_vec([1,2]); @@ -759,11 +738,6 @@ mod tests { assert_eq!(l.len(), 3); } #[test] - fn test_dlist_foldl() { - let l = from_vec(vec::from_fn(101, |x|x)); - assert_eq!(old_iter::foldl(&l, 0, |accum,elem| *accum+*elem), 5050); - } - #[test] fn test_dlist_break_early() { let l = from_vec([1,2,3,4,5]); let mut x = 0; diff --git a/src/libextra/ebml.rs b/src/libextra/ebml.rs index dd08f23a7a1..c79b012cfc5 100644 --- a/src/libextra/ebml.rs +++ b/src/libextra/ebml.rs @@ -10,7 +10,8 @@ #[allow(missing_doc)]; -use core::prelude::*; + +use std::str; // Simple Extensible Binary Markup Language (ebml) reader and writer on a // cursor model. See the specification here: @@ -34,6 +35,20 @@ pub struct Doc { end: uint, } +impl Doc { + pub fn get(&self, tag: uint) -> Doc { + reader::get_doc(*self, tag) + } + + pub fn as_str_slice<'a>(&'a self) -> &'a str { + str::from_bytes_slice(self.data.slice(self.start, self.end)) + } + + pub fn as_str(&self) -> ~str { + self.as_str_slice().to_owned() + } +} + pub struct TaggedDoc { tag: uint, doc: Doc, @@ -78,30 +93,20 @@ pub mod reader { use serialize; - use core::prelude::*; - use core::cast::transmute; - use core::int; - use core::io; - use core::ptr::offset; - use core::str; - use core::unstable::intrinsics::bswap32; - use core::vec; - - // ebml reading + use std::cast::transmute; + use std::int; + use std::io; + use std::option::{None, Option, Some}; - impl Doc { - pub fn get(&self, tag: uint) -> Doc { - get_doc(*self, tag) - } + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "x86_64")] + use std::ptr::offset; - pub fn as_str_slice<'a>(&'a self) -> &'a str { - str::from_bytes_slice(self.data.slice(self.start, self.end)) - } + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "x86_64")] + use std::unstable::intrinsics::bswap32; - pub fn as_str(&self) -> ~str { - self.as_str_slice().to_owned() - } - } + // ebml reading struct Res { val: uint, @@ -248,7 +253,7 @@ pub mod reader { } pub fn with_doc_data<T>(d: Doc, f: &fn(x: &[u8]) -> T) -> T { - f(vec::slice(*d.data, d.start, d.end)) + f(d.data.slice(d.start, d.end)) } @@ -372,7 +377,7 @@ pub mod reader { fn read_u8 (&mut self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) } fn read_uint(&mut self) -> uint { let v = doc_as_u64(self.next_doc(EsUint)); - if v > (::core::uint::max_value as u64) { + if v > (::std::uint::max_value as u64) { fail!("uint %? too large for this architecture", v); } v as uint @@ -605,8 +610,8 @@ pub mod reader { pub mod writer { use super::*; - use core::cast; - use core::io; + use std::cast; + use std::io; // ebml writing pub struct Encoder { @@ -951,8 +956,8 @@ mod tests { use serialize::Encodable; use serialize; - use core::io; - use core::option::{None, Option, Some}; + use std::io; + use std::option::{None, Option, Some}; #[test] fn test_option_int() { diff --git a/src/libextra/std.rc b/src/libextra/extra.rs index d4c85ef5136..50c57b28d22 100644 --- a/src/libextra/std.rc +++ b/src/libextra/extra.rs @@ -21,7 +21,7 @@ Rust extras are part of the standard Rust distribution. */ #[link(name = "extra", - vers = "0.7-pre", + vers = "0.7", uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297", url = "https://github.com/mozilla/rust/tree/master/src/libextra")]; @@ -32,13 +32,9 @@ Rust extras are part of the standard Rust distribution. #[deny(non_camel_case_types)]; #[deny(missing_doc)]; -#[no_std]; +use std::str::{StrSlice, OwnedStr}; -extern mod core(name = "std", vers = "0.7-pre"); - -use core::str::{StrSlice, OwnedStr}; - -pub use core::os; +pub use std::os; pub mod uv_ll; @@ -86,13 +82,20 @@ pub mod sort; pub mod dlist; pub mod treemap; +// Crypto +#[path="crypto/digest.rs"] +pub mod digest; +#[path="crypto/sha1.rs"] +pub mod sha1; +#[path="crypto/sha2.rs"] +pub mod sha2; + // And ... other stuff pub mod ebml; pub mod dbg; pub mod getopts; pub mod json; -pub mod sha1; pub mod md4; pub mod tempfile; pub mod term; @@ -128,21 +131,16 @@ pub mod serialize; // 'extra' so that macro-expanded references to extra::serialize and such // can be resolved within libextra. #[doc(hidden)] -pub mod std { +pub mod extra { pub use serialize; pub use test; // For bootstrapping. - pub use core::clone; - pub use core::condition; - pub use core::cmp; - pub use core::sys; - pub use core::unstable; - pub use core::str; - pub use core::os; -} -#[doc(hidden)] -pub mod extra { - pub use serialize; - pub use test; + pub use std::clone; + pub use std::condition; + pub use std::cmp; + pub use std::sys; + pub use std::unstable; + pub use std::str; + pub use std::os; } diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs index ed38db1d686..f91260f4752 100644 --- a/src/libextra/fileinput.rs +++ b/src/libextra/fileinput.rs @@ -57,14 +57,14 @@ For more complicated uses (e.g. if one needs to pause iteration and resume it later), a `FileInput` instance can be constructed via the `from_vec`, `from_vec_raw` and `from_args` functions. -Once created, the `each_line` (from the `core::io::ReaderUtil` trait) +Once created, the `each_line` (from the `std::io::ReaderUtil` trait) and `each_line_state` methods allow one to iterate on the lines; the latter provides more information about the position within the iteration to the caller. It is possible (and safe) to skip lines and files using the `read_line` and `next_file` methods. Also, `FileInput` implements -`core::io::Reader`, and the state will be updated correctly while +`std::io::Reader`, and the state will be updated correctly while using any of those methods. E.g. the following program reads until an empty line, pauses for user @@ -96,12 +96,10 @@ total line count). #[allow(missing_doc)]; -use core::prelude::*; -use core::io::ReaderUtil; -use core::io; -use core::os; -use core::vec; +use std::io::ReaderUtil; +use std::io; +use std::os; /** A summary of the internal state of a `FileInput` object. `line_num` @@ -354,13 +352,13 @@ a literal `-`. */ // XXX: stupid, unclear name pub fn pathify(vec: &[~str], stdin_hyphen : bool) -> ~[Option<Path>] { - vec::map(vec, |&str : & ~str| { - if stdin_hyphen && str == ~"-" { + vec.iter().transform(|str| { + if stdin_hyphen && "-" == *str { None } else { - Some(Path(str)) + Some(Path(*str)) } - }) + }).collect() } /** @@ -410,18 +408,17 @@ pub fn input_vec_state(files: ~[Option<Path>], #[cfg(test)] mod test { - use core::prelude::*; use super::{FileInput, pathify, input_vec, input_vec_state}; - use core::io; - use core::uint; - use core::vec; + use std::io; + use std::uint; + use std::vec; fn make_file(path : &Path, contents: &[~str]) { let file = io::file_writer(path, [io::Create, io::Truncate]).get(); - for contents.each |&str| { + for contents.iter().advance |&str| { file.write_str(str); file.write_char('\n'); } @@ -448,7 +445,7 @@ mod test { |i| fmt!("tmp/lib-fileinput-test-fileinput-read-byte-%u.tmp", i)), true); // 3 files containing 0\n, 1\n, and 2\n respectively - for filenames.eachi |i, &filename| { + for filenames.iter().enumerate().advance |(i, &filename)| { make_file(filename.get_ref(), [fmt!("%u", i)]); } @@ -478,7 +475,7 @@ mod test { |i| fmt!("tmp/lib-fileinput-test-fileinput-read-%u.tmp", i)), true); // 3 files containing 1\n, 2\n, and 3\n respectively - for filenames.eachi |i, &filename| { + for filenames.iter().enumerate().advance |(i, &filename)| { make_file(filename.get_ref(), [fmt!("%u", i)]); } @@ -498,7 +495,7 @@ mod test { 3, |i| fmt!("tmp/lib-fileinput-test-input-vec-%u.tmp", i)), true); - for filenames.eachi |i, &filename| { + for filenames.iter().enumerate().advance |(i, &filename)| { let contents = vec::from_fn(3, |j| fmt!("%u %u", i, j)); make_file(filename.get_ref(), contents); @@ -518,7 +515,7 @@ mod test { 3, |i| fmt!("tmp/lib-fileinput-test-input-vec-state-%u.tmp", i)),true); - for filenames.eachi |i, &filename| { + for filenames.iter().enumerate().advance |(i, &filename)| { let contents = vec::from_fn(3, |j| fmt!("%u %u", i, j + 1)); make_file(filename.get_ref(), contents); @@ -582,7 +579,7 @@ mod test { 3, |i| fmt!("tmp/lib-fileinput-test-next-file-%u.tmp", i)),true); - for filenames.eachi |i, &filename| { + for filenames.iter().enumerate().advance |(i, &filename)| { let contents = vec::from_fn(3, |j| fmt!("%u %u", i, j + 1)); make_file(&filename.get(), contents); diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs index 0fde03b69cb..92f9f834f52 100644 --- a/src/libextra/flate.rs +++ b/src/libextra/flate.rs @@ -16,12 +16,12 @@ Simple compression #[allow(missing_doc)]; -use core::libc::{c_void, size_t, c_int}; -use core::libc; -use core::vec; +use std::libc::{c_void, size_t, c_int}; +use std::libc; +use std::vec; pub mod rustrt { - use core::libc::{c_int, c_void, size_t}; + use std::libc::{c_int, c_void, size_t}; #[link_name = "rustrt"] pub extern { @@ -44,8 +44,8 @@ static lz_fast : c_int = 0x1; // LZ with only one probe static lz_norm : c_int = 0x80; // LZ with 128 probes, "normal" static lz_best : c_int = 0xfff; // LZ with 4095 probes, "best" -pub fn deflate_bytes(bytes: &const [u8]) -> ~[u8] { - do vec::as_const_buf(bytes) |b, len| { +pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { + do vec::as_imm_buf(bytes) |b, len| { unsafe { let mut outsz : size_t = 0; let res = @@ -62,8 +62,8 @@ pub fn deflate_bytes(bytes: &const [u8]) -> ~[u8] { } } -pub fn inflate_bytes(bytes: &const [u8]) -> ~[u8] { - do vec::as_const_buf(bytes) |b, len| { +pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { + do vec::as_imm_buf(bytes) |b, len| { unsafe { let mut outsz : size_t = 0; let res = @@ -83,9 +83,8 @@ pub fn inflate_bytes(bytes: &const [u8]) -> ~[u8] { #[cfg(test)] mod tests { use super::*; - use core::rand; - use core::rand::RngUtil; - use core::prelude::*; + use std::rand; + use std::rand::RngUtil; #[test] #[allow(non_implicitly_copyable_typarams)] diff --git a/src/libextra/flatpipes.rs b/src/libextra/flatpipes.rs index 9a8ee395936..e8bdc951ca4 100644 --- a/src/libextra/flatpipes.rs +++ b/src/libextra/flatpipes.rs @@ -49,14 +49,13 @@ block the scheduler thread, so will their pipes. #[allow(missing_doc)]; -use core::prelude::*; // The basic send/recv interface FlatChan and PortChan will implement -use core::io; -use core::comm::GenericChan; -use core::comm::GenericPort; -use core::sys::size_of; -use core::vec; +use std::io; +use std::comm::GenericChan; +use std::comm::GenericPort; +use std::sys::size_of; +use std::vec; /** A FlatPort, consisting of a `BytePort` that receives byte vectors, @@ -95,9 +94,9 @@ pub mod serial { use flatpipes::bytepipes::{PipeBytePort, PipeByteChan}; use flatpipes::{FlatPort, FlatChan}; - use core::io::{Reader, Writer}; - use core::comm::{Port, Chan}; - use core::comm; + use std::io::{Reader, Writer}; + use std::comm::{Port, Chan}; + use std::comm; pub type ReaderPort<T, R> = FlatPort< T, DeserializingUnflattener<DefaultDecoder, T>, @@ -166,22 +165,21 @@ Constructors for flat pipes that send POD types using memcpy. # Safety Note -This module is currently unsafe because it uses `Copy Owned` as a type -parameter bounds meaning POD (plain old data), but `Copy Owned` and +This module is currently unsafe because it uses `Copy Send` as a type +parameter bounds meaning POD (plain old data), but `Copy Send` and POD are not equivelant. */ pub mod pod { - use core::prelude::*; use flatpipes::flatteners::{PodUnflattener, PodFlattener}; use flatpipes::bytepipes::{ReaderBytePort, WriterByteChan}; use flatpipes::bytepipes::{PipeBytePort, PipeByteChan}; use flatpipes::{FlatPort, FlatChan}; - use core::io::{Reader, Writer}; - use core::comm::{Port, Chan}; - use core::comm; + use std::io::{Reader, Writer}; + use std::comm::{Port, Chan}; + use std::comm; pub type ReaderPort<T, R> = FlatPort<T, PodUnflattener<T>, ReaderBytePort<R>>; @@ -191,7 +189,7 @@ pub mod pod { pub type PipeChan<T> = FlatChan<T, PodFlattener<T>, PipeByteChan>; /// Create a `FlatPort` from a `Reader` - pub fn reader_port<T:Copy + Owned,R:Reader>( + pub fn reader_port<T:Copy + Send,R:Reader>( reader: R ) -> ReaderPort<T, R> { let unflat: PodUnflattener<T> = PodUnflattener::new(); @@ -200,7 +198,7 @@ pub mod pod { } /// Create a `FlatChan` from a `Writer` - pub fn writer_chan<T:Copy + Owned,W:Writer>( + pub fn writer_chan<T:Copy + Send,W:Writer>( writer: W ) -> WriterChan<T, W> { let flat: PodFlattener<T> = PodFlattener::new(); @@ -209,21 +207,21 @@ pub mod pod { } /// Create a `FlatPort` from a `Port<~[u8]>` - pub fn pipe_port<T:Copy + Owned>(port: Port<~[u8]>) -> PipePort<T> { + pub fn pipe_port<T:Copy + Send>(port: Port<~[u8]>) -> PipePort<T> { let unflat: PodUnflattener<T> = PodUnflattener::new(); let byte_port = PipeBytePort::new(port); FlatPort::new(unflat, byte_port) } /// Create a `FlatChan` from a `Chan<~[u8]>` - pub fn pipe_chan<T:Copy + Owned>(chan: Chan<~[u8]>) -> PipeChan<T> { + pub fn pipe_chan<T:Copy + Send>(chan: Chan<~[u8]>) -> PipeChan<T> { let flat: PodFlattener<T> = PodFlattener::new(); let byte_chan = PipeByteChan::new(chan); FlatChan::new(flat, byte_chan) } /// Create a pair of `FlatChan` and `FlatPort`, backed by pipes - pub fn pipe_stream<T:Copy + Owned>() -> (PipePort<T>, PipeChan<T>) { + pub fn pipe_stream<T:Copy + Send>() -> (PipePort<T>, PipeChan<T>) { let (port, chan) = comm::stream(); return (pipe_port(port), pipe_chan(chan)); } @@ -307,11 +305,11 @@ impl<T,U:Unflattener<T>,P:BytePort> GenericPort<T> for FlatPort<T, U, P> { impl<T,F:Flattener<T>,C:ByteChan> GenericChan<T> for FlatChan<T, F, C> { fn send(&self, val: T) { - self.byte_chan.send(CONTINUE.to_vec()); + self.byte_chan.send(CONTINUE.to_owned()); let bytes = self.flattener.flatten(val); let len = bytes.len() as u64; do io::u64_to_be_bytes(len, size_of::<u64>()) |len_bytes| { - self.byte_chan.send(len_bytes.to_vec()); + self.byte_chan.send(len_bytes.to_owned()); } self.byte_chan.send(bytes); } @@ -337,7 +335,6 @@ impl<T,F:Flattener<T>,C:ByteChan> FlatChan<T, F, C> { pub mod flatteners { - use core::prelude::*; use ebml; use flatpipes::{Flattener, Unflattener}; @@ -345,14 +342,14 @@ pub mod flatteners { use json; use serialize::{Encoder, Decoder, Encodable, Decodable}; - use core::cast; - use core::io::{Writer, Reader, ReaderUtil}; - use core::io; - use core::ptr; - use core::sys::size_of; - use core::vec; + use std::cast; + use std::io::{Writer, Reader, ReaderUtil}; + use std::io; + use std::ptr; + use std::sys::size_of; + use std::vec; - // FIXME #4074: Copy + Owned != POD + // FIXME #4074: Copy + Send != POD pub struct PodUnflattener<T> { bogus: () } @@ -361,7 +358,7 @@ pub mod flatteners { bogus: () } - impl<T:Copy + Owned> Unflattener<T> for PodUnflattener<T> { + impl<T:Copy + Send> Unflattener<T> for PodUnflattener<T> { fn unflatten(&self, buf: ~[u8]) -> T { assert!(size_of::<T>() != 0); assert_eq!(size_of::<T>(), buf.len()); @@ -371,7 +368,7 @@ pub mod flatteners { } } - impl<T:Copy + Owned> Flattener<T> for PodFlattener<T> { + impl<T:Copy + Send> Flattener<T> for PodFlattener<T> { fn flatten(&self, val: T) -> ~[u8] { assert!(size_of::<T>() != 0); let val: *T = ptr::to_unsafe_ptr(&val); @@ -380,7 +377,7 @@ pub mod flatteners { } } - impl<T:Copy + Owned> PodUnflattener<T> { + impl<T:Copy + Send> PodUnflattener<T> { pub fn new() -> PodUnflattener<T> { PodUnflattener { bogus: () @@ -388,7 +385,7 @@ pub mod flatteners { } } - impl<T:Copy + Owned> PodFlattener<T> { + impl<T:Copy + Send> PodFlattener<T> { pub fn new() -> PodFlattener<T> { PodFlattener { bogus: () @@ -509,13 +506,12 @@ pub mod flatteners { } pub mod bytepipes { - use core::prelude::*; use flatpipes::{ByteChan, BytePort}; - use core::comm::{Port, Chan}; - use core::comm; - use core::io::{Writer, Reader, ReaderUtil}; + use std::comm::{Port, Chan}; + use std::comm; + use std::io::{Writer, Reader, ReaderUtil}; pub struct ReaderBytePort<R> { reader: R @@ -583,12 +579,12 @@ pub mod bytepipes { impl BytePort for PipeBytePort { fn try_recv(&self, count: uint) -> Option<~[u8]> { if self.buf.len() >= count { - let mut bytes = ::core::util::replace(&mut *self.buf, ~[]); + let mut bytes = ::std::util::replace(&mut *self.buf, ~[]); *self.buf = bytes.slice(count, bytes.len()).to_owned(); bytes.truncate(count); return Some(bytes); } else if !self.buf.is_empty() { - let mut bytes = ::core::util::replace(&mut *self.buf, ~[]); + let mut bytes = ::std::util::replace(&mut *self.buf, ~[]); assert!(count > bytes.len()); match self.try_recv(count - bytes.len()) { Some(rest) => { @@ -637,7 +633,6 @@ pub mod bytepipes { #[cfg(test)] mod test { - use core::prelude::*; use flatpipes::{Flattener, Unflattener}; use flatpipes::bytepipes::*; @@ -647,11 +642,11 @@ mod test { use flatpipes::{BytePort, FlatChan, FlatPort}; use net::tcp::TcpSocketBuf; - use core::comm; - use core::int; - use core::io::BytesWriter; - use core::result; - use core::task; + use std::comm; + use std::int; + use std::io::BytesWriter; + use std::result; + use std::task; #[test] #[ignore(reason = "ebml failure")] @@ -772,7 +767,7 @@ mod test { writer_chan: WriterChanFactory<F>, port: uint) { - use core::cell::Cell; + use std::cell::Cell; use net::ip; use net::tcp; use uv; @@ -871,17 +866,16 @@ mod test { // Tests that the different backends behave the same when the // binary streaming protocol is broken mod broken_protocol { - use core::prelude::*; use flatpipes::{BytePort, FlatPort}; use flatpipes::flatteners::PodUnflattener; use flatpipes::pod; use io_util::BufReader; - use core::comm; - use core::io; - use core::sys; - use core::task; + use std::comm; + use std::io; + use std::sys; + use std::task; type PortLoader<P> = ~fn(~[u8]) -> FlatPort<int, PodUnflattener<int>, P>; @@ -937,7 +931,7 @@ mod test { fn test_try_recv_none3<P:BytePort>(loader: PortLoader<P>) { static CONTINUE: [u8, ..4] = [0xAA, 0xBB, 0xCC, 0xDD]; // The control word is followed by garbage - let bytes = CONTINUE.to_vec() + [0]; + let bytes = CONTINUE.to_owned() + [0]; let port = loader(bytes); let res: Option<int> = port.try_recv(); assert!(res.is_none()); @@ -959,9 +953,9 @@ mod test { // then undeserializable garbage let len_bytes = do io::u64_to_be_bytes( 1, sys::size_of::<u64>()) |len_bytes| { - len_bytes.to_vec() + len_bytes.to_owned() }; - let bytes = CONTINUE.to_vec() + len_bytes + [0, 0, 0, 0]; + let bytes = CONTINUE.to_owned() + len_bytes + [0, 0, 0, 0]; let port = loader(bytes); diff --git a/src/libextra/fun_treemap.rs b/src/libextra/fun_treemap.rs index eb8c27e9902..4461a4dba5f 100644 --- a/src/libextra/fun_treemap.rs +++ b/src/libextra/fun_treemap.rs @@ -19,10 +19,9 @@ * of features. */ -use core::prelude::*; -use core::cmp::{Eq, Ord}; -use core::option::{Some, None}; +use std::cmp::{Eq, Ord}; +use std::option::{Some, None}; pub type Treemap<K, V> = @TreeNode<K, V>; @@ -66,9 +65,9 @@ pub fn traverse<K, V: Copy>(m: Treemap<K, V>, f: &fn(&K, &V)) { // matches to me, so I changed it. but that may be a // de-optimization -- tjc Node(@ref k, @ref v, left, right) => { - traverse(left, f); + traverse(left, |k,v| f(k,v)); f(k, v); - traverse(right, f); + traverse(right, |k,v| f(k,v)); } } } diff --git a/src/libextra/future.rs b/src/libextra/future.rs index 4652e1d6477..3ef71e1731b 100644 --- a/src/libextra/future.rs +++ b/src/libextra/future.rs @@ -17,7 +17,7 @@ * ~~~ {.rust} * # fn fib(n: uint) -> uint {42}; * # fn make_a_sandwich() {}; - * let mut delayed_fib = std::future::spawn (|| fib(5000) ); + * let mut delayed_fib = extra::future::spawn (|| fib(5000) ); * make_a_sandwich(); * println(fmt!("fib(5000) = %?", delayed_fib.get())) * ~~~ @@ -25,13 +25,12 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::cast; -use core::cell::Cell; -use core::comm::{PortOne, oneshot, send_one, recv_one}; -use core::task; -use core::util::replace; +use std::cast; +use std::cell::Cell; +use std::comm::{PortOne, oneshot, send_one, recv_one}; +use std::task; +use std::util::replace; #[doc = "The future type"] pub struct Future<A> { @@ -44,7 +43,7 @@ pub struct Future<A> { // over ~fn's that have pipes and so forth within! #[unsafe_destructor] impl<A> Drop for Future<A> { - fn finalize(&self) {} + fn drop(&self) {} } priv enum FutureState<A> { @@ -101,7 +100,7 @@ pub fn from_value<A>(val: A) -> Future<A> { Future {state: Forced(val)} } -pub fn from_port<A:Owned>(port: PortOne<A>) -> Future<A> { +pub fn from_port<A:Send>(port: PortOne<A>) -> Future<A> { /*! * Create a future from a port * @@ -127,7 +126,7 @@ pub fn from_fn<A>(f: ~fn() -> A) -> Future<A> { Future {state: Pending(f)} } -pub fn spawn<A:Owned>(blk: ~fn() -> A) -> Future<A> { +pub fn spawn<A:Send>(blk: ~fn() -> A) -> Future<A> { /*! * Create a future from a unique closure. * @@ -151,9 +150,9 @@ pub fn spawn<A:Owned>(blk: ~fn() -> A) -> Future<A> { mod test { use future::*; - use core::cell::Cell; - use core::comm::{oneshot, send_one}; - use core::task; + use std::cell::Cell; + use std::comm::{oneshot, send_one}; + use std::task; #[test] fn test_from_value() { diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs index 05649104c31..1a494f36c64 100644 --- a/src/libextra/getopts.rs +++ b/src/libextra/getopts.rs @@ -81,14 +81,13 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::cmp::Eq; -use core::result::{Err, Ok}; -use core::result; -use core::option::{Some, None}; -use core::str; -use core::vec; +use std::cmp::Eq; +use std::result::{Err, Ok}; +use std::result; +use std::option::{Some, None}; +use std::str; +use std::vec; #[deriving(Eq)] pub enum Name { @@ -177,7 +176,7 @@ fn name_str(nm: &Name) -> ~str { } fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> { - vec::position(opts, |opt| opt.name == nm) + opts.iter().position_(|opt| opt.name == nm) } /** @@ -295,7 +294,7 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result { } } let mut name_pos = 0; - for names.each() |nm| { + for names.iter().advance() |nm| { name_pos += 1; let optid = match find_opt(opts, copy *nm) { Some(id) => id, @@ -373,7 +372,7 @@ pub fn opt_count(mm: &Matches, nm: &str) -> uint { /// Returns true if any of several options were matched pub fn opts_present(mm: &Matches, names: &[~str]) -> bool { - for names.each |nm| { + for names.iter().advance |nm| { match find_opt(mm.opts, mkname(*nm)) { Some(id) if !mm.vals[id].is_empty() => return true, _ => (), @@ -400,7 +399,7 @@ pub fn opt_str(mm: &Matches, nm: &str) -> ~str { * option took an argument */ pub fn opts_str(mm: &Matches, names: &[~str]) -> ~str { - for names.each |nm| { + for names.iter().advance |nm| { match opt_val(mm, *nm) { Val(ref s) => return copy *s, _ => () @@ -418,10 +417,11 @@ pub fn opts_str(mm: &Matches, names: &[~str]) -> ~str { */ pub fn opt_strs(mm: &Matches, nm: &str) -> ~[~str] { let mut acc: ~[~str] = ~[]; - for vec::each(opt_vals(mm, nm)) |v| { + let r = opt_vals(mm, nm); + for r.iter().advance |v| { match *v { Val(ref s) => acc.push(copy *s), _ => () } } - return acc; + acc } /// Returns the string argument supplied to a matching option or none @@ -465,8 +465,8 @@ pub mod groups { use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req}; use getopts::{Short, Yes}; - use core::str; - use core::vec; + use std::str; + use std::vec; /** one group of options, e.g., both -h and --help, along with * their shared description and properties @@ -592,9 +592,9 @@ pub mod groups { */ pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str { - let desc_sep = ~"\n" + " ".repeat(24); + let desc_sep = "\n" + " ".repeat(24); - let rows = vec::map(opts, |optref| { + let mut rows = opts.iter().transform(|optref| { let OptGroup{short_name: short_name, long_name: long_name, hint: hint, @@ -605,33 +605,47 @@ pub mod groups { let mut row = " ".repeat(4); // short option - row += match short_name.len() { - 0 => ~"", - 1 => ~"-" + short_name + " ", + match short_name.len() { + 0 => {} + 1 => { + row.push_char('-'); + row.push_str(short_name); + row.push_char(' '); + } _ => fail!("the short name should only be 1 ascii char long"), - }; + } // long option - row += match long_name.len() { - 0 => ~"", - _ => ~"--" + long_name + " ", - }; + match long_name.len() { + 0 => {} + _ => { + row.push_str("--"); + row.push_str(long_name); + row.push_char(' '); + } + } // arg - row += match hasarg { - No => ~"", - Yes => hint, - Maybe => ~"[" + hint + "]", - }; + match hasarg { + No => {} + Yes => row.push_str(hint), + Maybe => { + row.push_char('['); + row.push_str(hint); + row.push_char(']'); + } + } // FIXME: #5516 // here we just need to indent the start of the description let rowlen = row.len(); - row += if rowlen < 24 { - " ".repeat(24 - rowlen) + if rowlen < 24 { + for (24 - rowlen).times { + row.push_char(' ') + } } else { - copy desc_sep - }; + row.push_str(desc_sep) + } // Normalize desc to contain words separated by one space character let mut desc_normalized_whitespace = ~""; @@ -648,14 +662,14 @@ pub mod groups { // FIXME: #5516 // wrapped description - row += desc_rows.connect(desc_sep); + row.push_str(desc_rows.connect(desc_sep)); row }); return str::to_owned(brief) + "\n\nOptions:\n" + - rows.connect("\n") + + rows.collect::<~[~str]>().connect("\n") + "\n\n"; } } // end groups module @@ -666,8 +680,8 @@ mod tests { use getopts::groups::OptGroup; use getopts::*; - use core::result::{Err, Ok}; - use core::result; + use std::result::{Err, Ok}; + use std::result; fn check_fail_type(f: Fail_, ft: FailType) { match f { diff --git a/src/libextra/io_util.rs b/src/libextra/io_util.rs index 91424ae3ba2..afefca8ae65 100644 --- a/src/libextra/io_util.rs +++ b/src/libextra/io_util.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::io::{Reader, BytesReader}; -use core::io; +use std::io::{Reader, BytesReader}; +use std::io; +use std::cast; /// An implementation of the io::Reader interface which reads a buffer of bytes pub struct BufReader { @@ -29,10 +30,13 @@ impl BufReader { } fn as_bytes_reader<A>(&self, f: &fn(&BytesReader) -> A) -> A { + // XXX FIXME(#5723) + let bytes = ::std::util::id::<&[u8]>(self.buf); + let bytes: &'static [u8] = unsafe { cast::transmute(bytes) }; // Recreating the BytesReader state every call since // I can't get the borrowing to work correctly let bytes_reader = BytesReader { - bytes: ::core::util::id::<&[u8]>(self.buf), + bytes: bytes, pos: @mut *self.pos }; diff --git a/src/libextra/json.rs b/src/libextra/json.rs index db95327f0aa..210921aa3d7 100644 --- a/src/libextra/json.rs +++ b/src/libextra/json.rs @@ -16,16 +16,15 @@ //! json serialization -use core::prelude::*; -use core::char; -use core::float; -use core::hashmap::HashMap; -use core::io::{WriterUtil, ReaderUtil}; -use core::io; -use core::str; -use core::to_str; -use core::vec; +use std::char; +use std::float; +use std::hashmap::HashMap; +use std::io::{WriterUtil, ReaderUtil}; +use std::io; +use std::str; +use std::to_str; +use std::vec; use serialize::Encodable; use serialize; @@ -60,25 +59,27 @@ fn escape_str(s: &str) -> ~str { let mut escaped = ~"\""; for s.iter().advance |c| { match c { - '"' => escaped += "\\\"", - '\\' => escaped += "\\\\", - '\x08' => escaped += "\\b", - '\x0c' => escaped += "\\f", - '\n' => escaped += "\\n", - '\r' => escaped += "\\r", - '\t' => escaped += "\\t", - _ => escaped += str::from_char(c) + '"' => escaped.push_str("\\\""), + '\\' => escaped.push_str("\\\\"), + '\x08' => escaped.push_str("\\b"), + '\x0c' => escaped.push_str("\\f"), + '\n' => escaped.push_str("\\n"), + '\r' => escaped.push_str("\\r"), + '\t' => escaped.push_str("\\t"), + _ => escaped.push_char(c), } }; - escaped += "\""; + escaped.push_char('"'); escaped } fn spaces(n: uint) -> ~str { let mut ss = ~""; - for n.times { ss.push_str(" "); } + for n.times { + ss.push_str(" "); + } return ss; } @@ -950,7 +951,7 @@ impl serialize::Decoder for Decoder { } ref json => fail!("invalid variant: %?", *json), }; - let idx = match vec::position(names, |n| str::eq_slice(*n, name)) { + let idx = match names.iter().position_(|n| str::eq_slice(*n, name)) { Some(idx) => idx, None => fail!("Unknown variant name: %?", name), }; @@ -1123,7 +1124,7 @@ impl Eq for Json { &Object(ref d1) => { if d0.len() == d1.len() { let mut equal = true; - for d0.each |k, v0| { + for d0.iter().advance |(k, v0)| { match d1.find(k) { Some(v1) if v0 == v1 => { }, _ => { equal = false; break } @@ -1186,12 +1187,12 @@ impl Ord for Json { let mut d1_flat = ~[]; // FIXME #4430: this is horribly inefficient... - for d0.each |k, v| { + for d0.iter().advance |(k, v)| { d0_flat.push((@copy *k, @copy *v)); } d0_flat.qsort(); - for d1.each |k, v| { + for d1.iter().advance |(k, v)| { d1_flat.push((@copy *k, @copy *v)); } d1_flat.qsort(); @@ -1326,7 +1327,7 @@ impl<A:ToJson> ToJson for ~[A] { impl<A:ToJson + Copy> ToJson for HashMap<~str, A> { fn to_json(&self) -> Json { let mut d = HashMap::new(); - for self.each |key, value| { + for self.iter().advance |(key, value)| { d.insert(copy *key, value.to_json()); } Object(~d) @@ -1354,15 +1355,14 @@ impl to_str::ToStr for Error { #[cfg(test)] mod tests { - use core::prelude::*; use super::*; - use core::hashmap::HashMap; - use core::io; - use core::result; + use std::hashmap::HashMap; + use std::io; + use std::result; - use std::serialize::Decodable; + use extra::serialize::Decodable; #[deriving(Eq, Encodable, Decodable)] enum Animal { @@ -1385,7 +1385,7 @@ mod tests { fn mk_object(items: &[(~str, Json)]) -> Json { let mut d = ~HashMap::new(); - for items.each |item| { + for items.iter().advance |item| { match *item { (ref key, ref value) => { d.insert(copy *key, copy *value); }, } diff --git a/src/libextra/list.rs b/src/libextra/list.rs index 34c35e0d7fd..86b01cf157d 100644 --- a/src/libextra/list.rs +++ b/src/libextra/list.rs @@ -10,7 +10,6 @@ //! A standard, garbage-collected linked list. -use core::prelude::*; #[deriving(Eq)] @@ -181,7 +180,7 @@ mod tests { use list::*; use list; - use core::option; + use std::option; #[test] fn test_is_empty() { diff --git a/src/libextra/md4.rs b/src/libextra/md4.rs index 6c972a313c4..6b08fea580f 100644 --- a/src/libextra/md4.rs +++ b/src/libextra/md4.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; -use core::uint; -use core::vec; +use std::uint; +use std::vec; struct Quad { a: u32, @@ -59,7 +58,8 @@ pub fn md4(msg: &[u8]) -> Quad { while i < e { let (aa, bb, cc, dd) = (a, b, c, d); - let mut (j, base) = (0u, i); + let mut j = 0u; + let mut base = i; while j < 16u { x[j] = (msg[base] as u32) + (msg[base + 1u] as u32 << 8u32) + (msg[base + 2u] as u32 << 16u32) + @@ -118,8 +118,10 @@ pub fn md4_str(msg: &[u8]) -> ~str { let mut i = 0u32; while i < 4u32 { let byte = (u >> (i * 8u32)) as u8; - if byte <= 16u8 { result += "0"; } - result += uint::to_str_radix(byte as uint, 16u); + if byte <= 16u8 { + result.push_char('0') + } + result.push_str(uint::to_str_radix(byte as uint, 16u)); i += 1u32; } } diff --git a/src/libextra/net_ip.rs b/src/libextra/net_ip.rs index 518a9d8685a..d18aac68481 100644 --- a/src/libextra/net_ip.rs +++ b/src/libextra/net_ip.rs @@ -12,13 +12,12 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::libc; -use core::comm::{stream, SharedChan}; -use core::ptr; -use core::result; -use core::str; +use std::libc; +use std::comm::{stream, SharedChan}; +use std::ptr; +use std::result; +use std::str; use iotask = uv::iotask::IoTask; use interact = uv::iotask::interact; @@ -55,7 +54,7 @@ pub struct ParseAddrErr { * * # Arguments * - * * ip - a `std::net::ip::IpAddr` + * * ip - a `extra::net::ip::IpAddr` */ pub fn format_addr(ip: &IpAddr) -> ~str { match *ip { @@ -80,7 +79,7 @@ pub fn format_addr(ip: &IpAddr) -> ~str { * Get the associated port * * # Arguments - * * ip - a `std::net::ip::IpAddr` + * * ip - a `extra::net::ip::IpAddr` */ pub fn get_port(ip: &IpAddr) -> uint { match *ip { @@ -149,16 +148,15 @@ pub fn get_addr(node: &str, iotask: &iotask) } pub mod v4 { - use core::prelude::*; use net::ip::{IpAddr, Ipv4, ParseAddrErr}; use uv::ll; use uv_ip4_addr = uv::ll::ip4_addr; use uv_ip4_name = uv::ll::ip4_name; - use core::cast::transmute; - use core::result; - use core::uint; + use std::cast::transmute; + use std::result; + use std::uint; /** * Convert a str to `ip_addr` @@ -205,7 +203,7 @@ pub mod v4 { }).collect(); if parts.len() != 4 { Err(fmt!("'%s' doesn't have 4 parts", ip)) - } else if parts.contains(&256) { + } else if parts.iter().any_(|x| *x == 256u) { Err(fmt!("invalid octal in addr '%s'", ip)) } else { Ok(Ipv4Rep { @@ -248,13 +246,12 @@ pub mod v4 { } } pub mod v6 { - use core::prelude::*; use net::ip::{IpAddr, Ipv6, ParseAddrErr}; use uv_ip6_addr = uv::ll::ip6_addr; use uv_ip6_name = uv::ll::ip6_name; - use core::result; + use std::result; /** * Convert a str to `ip_addr` @@ -371,7 +368,7 @@ mod test { use net_ip::v6; use uv; - use core::result; + use std::result; #[test] fn test_ip_ipv4_parse_and_format_ip() { @@ -426,7 +423,7 @@ mod test { let results = result::unwrap(ga_result); debug!("test_get_addr: Number of results for %s: %?", localhost_name, results.len()); - for results.each |r| { + for results.iter().advance |r| { let ipv_prefix = match *r { Ipv4(_) => ~"IPv4", Ipv6(_) => ~"IPv6" diff --git a/src/libextra/net_tcp.rs b/src/libextra/net_tcp.rs index 51d744955b8..6a22950ec04 100644 --- a/src/libextra/net_tcp.rs +++ b/src/libextra/net_tcp.rs @@ -13,7 +13,6 @@ #[allow(missing_doc)]; -use core::prelude::*; use future; use future_spawn = future::spawn; @@ -22,18 +21,18 @@ use uv; use uv::iotask; use uv::iotask::IoTask; -use core::io; -use core::libc::size_t; -use core::libc; -use core::comm::{stream, Port, SharedChan}; -use core::ptr; -use core::result::{Result}; -use core::result; -use core::uint; -use core::vec; +use std::io; +use std::libc::size_t; +use std::libc; +use std::comm::{stream, Port, SharedChan}; +use std::ptr; +use std::result::{Result}; +use std::result; +use std::uint; +use std::vec; pub mod rustrt { - use core::libc; + use std::libc; #[nolink] pub extern { @@ -57,7 +56,7 @@ pub struct TcpSocket { #[unsafe_destructor] impl Drop for TcpSocket { - fn finalize(&self) { + fn drop(&self) { tear_down_socket_data(self.socket_data) } } @@ -360,7 +359,7 @@ pub fn write_future(sock: &TcpSocket, raw_write_data: ~[u8]) * # Returns * * * A `Result` instance that will either contain a - * `core::comm::Port<Result<~[u8], TcpErrData>>` that the user can read + * `std::comm::Port<Result<~[u8], TcpErrData>>` that the user can read * (and * optionally, loop on) from until `read_stop` is called, or a * `TcpErrData` record */ @@ -619,7 +618,7 @@ pub fn accept(new_conn: TcpNewConnection) * callback's arguments are: * * `new_conn` - an opaque type that can be passed to * `net::tcp::accept` in order to be converted to a `TcpSocket`. - * * `kill_ch` - channel of type `core::comm::Chan<Option<tcp_err_data>>`. + * * `kill_ch` - channel of type `std::comm::Chan<Option<tcp_err_data>>`. * this channel can be used to send a message to cause `listen` to begin * closing the underlying libuv data structures. * @@ -683,7 +682,7 @@ fn listen_common(host_ip: ip::IpAddr, // will defeat a move sigil, as is done to the host_ip // arg above.. this same pattern works w/o complaint in // tcp::connect (because the iotask::interact cb isn't - // nested within a core::comm::listen block) + // nested within a std::comm::listen block) let loc_ip = copy(host_ip); do iotask::interact(iotask) |loop_ptr| { unsafe { @@ -976,9 +975,7 @@ impl io::Writer for TcpSocketBuf { let socket_data_ptr: *TcpSocketData = &(*((*(self.data)).sock).socket_data); let w_result = write_common_impl(socket_data_ptr, - vec::slice(data, - 0, - data.len()).to_vec()); + data.slice(0, data.len()).to_owned()); if w_result.is_err() { let err_data = w_result.get_err(); debug!( @@ -1431,7 +1428,6 @@ struct TcpBufferedSocketData { #[cfg(test)] mod test { - use core::prelude::*; use net::ip; use net::tcp::{GenericListenErr, TcpConnectErrData, TcpListenErrData}; @@ -1440,12 +1436,12 @@ mod test { use uv::iotask::IoTask; use uv; - use core::cell::Cell; - use core::comm::{stream, SharedChan}; - use core::io; - use core::result; - use core::str; - use core::task; + use std::cell::Cell; + use std::comm::{stream, SharedChan}; + use std::io; + use std::result; + use std::str; + use std::task; // FIXME don't run on fbsd or linux 32 bit (#2064) #[cfg(target_os="win32")] @@ -1459,33 +1455,23 @@ mod test { #[test] fn test_gl_tcp_server_and_client_ipv4() { - unsafe { - impl_gl_tcp_ipv4_server_and_client(); - } + impl_gl_tcp_ipv4_server_and_client(); } #[test] fn test_gl_tcp_get_peer_addr() { - unsafe { - impl_gl_tcp_ipv4_get_peer_addr(); - } + impl_gl_tcp_ipv4_get_peer_addr(); } #[test] fn test_gl_tcp_ipv4_client_error_connection_refused() { - unsafe { - impl_gl_tcp_ipv4_client_error_connection_refused(); - } + impl_gl_tcp_ipv4_client_error_connection_refused(); } #[test] fn test_gl_tcp_server_address_in_use() { - unsafe { - impl_gl_tcp_ipv4_server_address_in_use(); - } + impl_gl_tcp_ipv4_server_address_in_use(); } #[test] fn test_gl_tcp_server_access_denied() { - unsafe { - impl_gl_tcp_ipv4_server_access_denied(); - } + impl_gl_tcp_ipv4_server_access_denied(); } // Strange failure on Windows. --pcwalton #[test] @@ -1757,7 +1743,7 @@ mod test { } pub fn impl_tcp_socket_impl_reader_handles_eof() { - use core::io::{Reader,ReaderUtil}; + use std::io::{Reader,ReaderUtil}; let hl_loop = &uv::global_loop::get(); let server_ip = "127.0.0.1"; diff --git a/src/libextra/net_url.rs b/src/libextra/net_url.rs index a0ce1669a44..9ac58efe793 100644 --- a/src/libextra/net_url.rs +++ b/src/libextra/net_url.rs @@ -12,14 +12,13 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::cmp::Eq; -use core::io::{Reader, ReaderUtil}; -use core::io; -use core::hashmap::HashMap; -use core::to_bytes; -use core::uint; +use std::cmp::Eq; +use std::io::{Reader, ReaderUtil}; +use std::io; +use std::hashmap::HashMap; +use std::to_bytes; +use std::uint; #[deriving(Clone, Eq)] struct Url { @@ -93,10 +92,10 @@ fn encode_inner(s: &str, full_url: bool) -> ~str { out.push_char(ch); } - _ => out += fmt!("%%%X", ch as uint) + _ => out.push_str(fmt!("%%%X", ch as uint)) } } else { - out += fmt!("%%%X", ch as uint); + out.push_str(fmt!("%%%X", ch as uint)); } } } @@ -192,7 +191,7 @@ fn encode_plus(s: &str) -> ~str { out.push_char(ch); } ' ' => out.push_char('+'), - _ => out += fmt!("%%%X", ch as uint) + _ => out.push_str(fmt!("%%%X", ch as uint)) } } @@ -207,10 +206,10 @@ pub fn encode_form_urlencoded(m: &HashMap<~str, ~[~str]>) -> ~str { let mut out = ~""; let mut first = true; - for m.each |key, values| { + for m.iter().advance |(key, values)| { let key = encode_plus(*key); - for values.each |value| { + for values.iter().advance |value| { if first { first = false; } else { @@ -218,7 +217,7 @@ pub fn encode_form_urlencoded(m: &HashMap<~str, ~[~str]>) -> ~str { first = false; } - out += fmt!("%s=%s", key, encode_plus(*value)); + out.push_str(fmt!("%s=%s", key, encode_plus(*value))); } } @@ -342,7 +341,7 @@ fn query_from_str(rawquery: &str) -> Query { pub fn query_to_str(query: &Query) -> ~str { let mut strvec = ~[]; - for query.each |kv| { + for query.iter().advance |kv| { match kv { &(ref k, ref v) => { strvec.push(fmt!("%s=%s", @@ -415,7 +414,9 @@ fn get_authority(rawurl: &str) -> let mut port = None; let mut colon_count = 0; - let mut (pos, begin, end) = (0, 2, len); + let mut pos = 0; + let mut begin = 2; + let mut end = len; for rawurl.iter().enumerate().advance |(i,c)| { if i < 2 { loop; } // ignore the leading // @@ -519,8 +520,9 @@ fn get_authority(rawurl: &str) -> let end = end; // make end immutable so it can be captured let host_is_end_plus_one: &fn() -> bool = || { + let xs = ['?', '#', '/']; end+1 == len - && !['?', '#', '/'].contains(&(rawurl[end] as char)) + && !xs.iter().any_(|x| *x == (rawurl[end] as char)) }; // finish up @@ -800,7 +802,7 @@ mod tests { use net_url::*; - use core::hashmap::HashMap; + use std::hashmap::HashMap; #[test] fn test_url_parse() { diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 14156e8b901..9422ad0c9f2 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -18,13 +18,12 @@ A BigInt is a combination of BigUint and Sign. #[allow(missing_doc)]; -use core::prelude::*; -use core::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; -use core::int; -use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable}; -use core::str; -use core::uint; -use core::vec; +use std::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; +use std::int; +use std::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable}; +use std::str; +use std::uint; +use std::vec; /** A BigDigit is a BigUint's composing element. @@ -284,13 +283,13 @@ impl Mul<BigUint, BigUint> for BigUint { if n == 1 { return copy *a; } let mut carry = 0; - let prod = do vec::map(a.data) |ai| { + let prod = do a.data.iter().transform |ai| { let (hi, lo) = BigDigit::from_uint( (*ai as uint) * (n as uint) + (carry as uint) ); carry = hi; lo - }; + }.collect::<~[BigDigit]>(); if carry == 0 { return BigUint::new(prod) }; return BigUint::new(prod + [carry]); } @@ -298,9 +297,8 @@ impl Mul<BigUint, BigUint> for BigUint { fn cut_at(a: &BigUint, n: uint) -> (BigUint, BigUint) { let mid = uint::min(a.data.len(), n); - return (BigUint::from_slice(vec::slice(a.data, mid, - a.data.len())), - BigUint::from_slice(vec::slice(a.data, 0, mid))); + return (BigUint::from_slice(a.data.slice(mid, a.data.len())), + BigUint::from_slice(a.data.slice(0, mid))); } @@ -381,7 +379,8 @@ impl Integer for BigUint { let mut d = Zero::zero::<BigUint>(); let mut n = 1; while m >= b { - let mut (d0, d_unit, b_unit) = div_estimate(&m, &b, n); + let (d0, d_unit, b_unit) = div_estimate(&m, &b, n); + let mut d0 = d0; let mut prod = b * d0; while prod > m { // FIXME(#6050): overloaded operators force moves with generic types @@ -413,7 +412,7 @@ impl Integer for BigUint { return (Zero::zero(), Zero::zero(), copy *a); } - let an = vec::slice(a.data, a.data.len() - n, a.data.len()); + let an = a.data.slice(a.data.len() - n, a.data.len()); let bn = *b.data.last(); let mut d = ~[]; let mut carry = 0; @@ -443,7 +442,8 @@ impl Integer for BigUint { fn gcd(&self, other: &BigUint) -> BigUint { // Use Euclid's algorithm - let mut (m, n) = (copy *self, copy *other); + let mut m = copy *self; + let mut n = copy *other; while !m.is_zero() { let temp = m; m = n % temp; @@ -507,11 +507,11 @@ impl ToStrRadix for BigUint { let mut m = n; while m > divider { let (d, m0) = m.div_mod_floor(÷r); - result += [m0.to_uint() as BigDigit]; + result.push(m0.to_uint() as BigDigit); m = d; } if !m.is_zero() { - result += [m.to_uint() as BigDigit]; + result.push(m.to_uint() as BigDigit); } return result; } @@ -578,7 +578,7 @@ impl BigUint { let mut power: BigUint = One::one(); loop { let start = uint::max(end, unit_len) - unit_len; - match uint::parse_bytes(vec::slice(buf, start, end), radix) { + match uint::parse_bytes(buf.slice(start, end), radix) { // FIXME(#6102): Assignment operator for BigInt causes ICE // Some(d) => n += BigUint::from_uint(d) * power, Some(d) => n = n + BigUint::from_uint(d) * power, @@ -618,13 +618,13 @@ impl BigUint { if n_bits == 0 || self.is_zero() { return copy *self; } let mut carry = 0; - let shifted = do vec::map(self.data) |elem| { + let shifted = do self.data.iter().transform |elem| { let (hi, lo) = BigDigit::from_uint( (*elem as uint) << n_bits | (carry as uint) ); carry = hi; lo - }; + }.collect::<~[BigDigit]>(); if carry == 0 { return BigUint::new(shifted); } return BigUint::new(shifted + [carry]); } @@ -634,7 +634,7 @@ impl BigUint { if n_unit == 0 { return copy *self; } if self.data.len() < n_unit { return Zero::zero(); } return BigUint::from_slice( - vec::slice(self.data, n_unit, self.data.len()) + self.data.slice(n_unit, self.data.len()) ); } @@ -1132,7 +1132,7 @@ impl BigInt { sign = Minus; start = 1; } - return BigUint::parse_bytes(vec::slice(buf, start, buf.len()), radix) + return BigUint::parse_bytes(buf.slice(start, buf.len()), radix) .map_consume(|bu| BigInt::from_biguint(sign, bu)); } @@ -1147,16 +1147,15 @@ impl BigInt { #[cfg(test)] mod biguint_tests { - use core::prelude::*; use super::*; - use core::cmp::{Less, Equal, Greater}; - use core::int; - use core::num::{IntConvertible, Zero, One, FromStrRadix}; - use core::str; - use core::uint; - use core::vec; + use std::cmp::{Less, Equal, Greater}; + use std::int; + use std::num::{IntConvertible, Zero, One, FromStrRadix}; + use std::str; + use std::uint; + use std::vec; #[test] fn test_from_slice() { @@ -1173,10 +1172,10 @@ mod biguint_tests { #[test] fn test_cmp() { - let data = [ &[], &[1], &[2], &[-1], &[0, 1], &[2, 1], &[1, 1, 1] ] + let data: ~[BigUint] = [ &[], &[1], &[2], &[-1], &[0, 1], &[2, 1], &[1, 1, 1] ] .map(|v| BigUint::from_slice(*v)); - for data.eachi |i, ni| { - for vec::slice(data, i, data.len()).eachi |j0, nj| { + for data.iter().enumerate().advance |(i, ni)| { + for data.slice(i, data.len()).iter().enumerate().advance |(j0, nj)| { let j = j0 + i; if i == j { assert_eq!(ni.cmp(nj), Equal); @@ -1349,7 +1348,7 @@ mod biguint_tests { #[test] fn test_add() { - for sum_triples.each |elm| { + for sum_triples.iter().advance |elm| { let (aVec, bVec, cVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); @@ -1362,7 +1361,7 @@ mod biguint_tests { #[test] fn test_sub() { - for sum_triples.each |elm| { + for sum_triples.iter().advance |elm| { let (aVec, bVec, cVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); @@ -1413,7 +1412,7 @@ mod biguint_tests { #[test] fn test_mul() { - for mul_triples.each |elm| { + for mul_triples.iter().advance |elm| { let (aVec, bVec, cVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); @@ -1423,7 +1422,7 @@ mod biguint_tests { assert!(b * a == c); } - for div_rem_quadruples.each |elm| { + for div_rem_quadruples.iter().advance |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); @@ -1437,7 +1436,7 @@ mod biguint_tests { #[test] fn test_div_rem() { - for mul_triples.each |elm| { + for mul_triples.iter().advance |elm| { let (aVec, bVec, cVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); @@ -1451,7 +1450,7 @@ mod biguint_tests { } } - for div_rem_quadruples.each |elm| { + for div_rem_quadruples.iter().advance |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); @@ -1567,9 +1566,10 @@ mod biguint_tests { #[test] fn test_to_str_radix() { - for to_str_pairs().each |num_pair| { + let r = to_str_pairs(); + for r.iter().advance |num_pair| { let &(n, rs) = num_pair; - for rs.each |str_pair| { + for rs.iter().advance |str_pair| { let &(radix, str) = str_pair; assert_eq!(n.to_str_radix(radix), str); } @@ -1578,9 +1578,10 @@ mod biguint_tests { #[test] fn test_from_str_radix() { - for to_str_pairs().each |num_pair| { + let r = to_str_pairs(); + for r.iter().advance |num_pair| { let &(n, rs) = num_pair; - for rs.each |str_pair| { + for rs.iter().advance |str_pair| { let &(radix, str) = str_pair; assert_eq!(&n, &FromStrRadix::from_str_radix(str, radix).get()); } @@ -1620,15 +1621,14 @@ mod biguint_tests { #[cfg(test)] mod bigint_tests { - use core::prelude::*; use super::*; - use core::cmp::{Less, Equal, Greater}; - use core::int; - use core::num::{IntConvertible, Zero, One, FromStrRadix}; - use core::uint; - use core::vec; + use std::cmp::{Less, Equal, Greater}; + use std::int; + use std::num::{IntConvertible, Zero, One, FromStrRadix}; + use std::uint; + use std::vec; #[test] fn test_from_biguint() { @@ -1651,8 +1651,8 @@ mod bigint_tests { nums.push(Zero::zero()); nums.push_all_move(vs.map(|s| BigInt::from_slice(Plus, *s))); - for nums.eachi |i, ni| { - for vec::slice(nums, i, nums.len()).eachi |j0, nj| { + for nums.iter().enumerate().advance |(i, ni)| { + for nums.slice(i, nums.len()).iter().enumerate().advance |(j0, nj)| { let j = i + j0; if i == j { assert_eq!(ni.cmp(nj), Equal); @@ -1756,7 +1756,7 @@ mod bigint_tests { #[test] fn test_add() { - for sum_triples.each |elm| { + for sum_triples.iter().advance |elm| { let (aVec, bVec, cVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1775,7 +1775,7 @@ mod bigint_tests { #[test] fn test_sub() { - for sum_triples.each |elm| { + for sum_triples.iter().advance |elm| { let (aVec, bVec, cVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1832,7 +1832,7 @@ mod bigint_tests { #[test] fn test_mul() { - for mul_triples.each |elm| { + for mul_triples.iter().advance |elm| { let (aVec, bVec, cVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1845,7 +1845,7 @@ mod bigint_tests { assert!((-b) * a == -c); } - for div_rem_quadruples.each |elm| { + for div_rem_quadruples.iter().advance |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1884,7 +1884,7 @@ mod bigint_tests { } } - for mul_triples.each |elm| { + for mul_triples.iter().advance |elm| { let (aVec, bVec, cVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1894,7 +1894,7 @@ mod bigint_tests { if !b.is_zero() { check(&c, &b, &a, &Zero::zero()); } } - for div_rem_quadruples.each |elm| { + for div_rem_quadruples.iter().advance |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1927,7 +1927,7 @@ mod bigint_tests { check_sub(&a.neg(), b, &q.neg(), &r.neg()); check_sub(&a.neg(), &b.neg(), q, &r.neg()); } - for mul_triples.each |elm| { + for mul_triples.iter().advance |elm| { let (aVec, bVec, cVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1937,7 +1937,7 @@ mod bigint_tests { if !b.is_zero() { check(&c, &b, &a, &Zero::zero()); } } - for div_rem_quadruples.each |elm| { + for div_rem_quadruples.iter().advance |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); diff --git a/src/libextra/num/complex.rs b/src/libextra/num/complex.rs index c626260043e..915523443fb 100644 --- a/src/libextra/num/complex.rs +++ b/src/libextra/num/complex.rs @@ -11,9 +11,8 @@ //! Complex numbers. -use core::prelude::*; -use core::num::{Zero,One,ToStrRadix}; +use std::num::{Zero,One,ToStrRadix}; // FIXME #1284: handle complex NaN & infinity etc. This // probably doesn't map to C's _Complex correctly. @@ -193,7 +192,7 @@ impl<T: ToStrRadix + Num + Ord> ToStrRadix for Cmplx<T> { #[cfg(test)] mod test { use super::*; - use core::num::{Zero,One,Real}; + use std::num::{Zero,One,Real}; pub static _0_0i : Complex = Cmplx { re: 0f, im: 0f }; pub static _1_0i : Complex = Cmplx { re: 1f, im: 0f }; @@ -238,14 +237,14 @@ mod test { fn test_scale_unscale() { assert_eq!(_05_05i.scale(2f), _1_1i); assert_eq!(_1_1i.unscale(2f), _05_05i); - for all_consts.each |&c| { + for all_consts.iter().advance |&c| { assert_eq!(c.scale(2f).unscale(2f), c); } } #[test] fn test_conj() { - for all_consts.each |&c| { + for all_consts.iter().advance |&c| { assert_eq!(c.conj(), Cmplx::new(c.re, -c.im)); assert_eq!(c.conj().conj(), c); } @@ -282,12 +281,12 @@ mod test { let (r, theta) = c.to_polar(); assert!((c - Cmplx::from_polar(&r, &theta)).norm() < 1e-6); } - for all_consts.each |&c| { test(c); } + for all_consts.iter().advance |&c| { test(c); } } mod arith { use super::*; - use core::num::Zero; + use std::num::Zero; #[test] fn test_add() { @@ -295,7 +294,7 @@ mod test { assert_eq!(_0_1i + _1_0i, _1_1i); assert_eq!(_1_0i + _neg1_1i, _0_1i); - for all_consts.each |&c| { + for all_consts.iter().advance |&c| { assert_eq!(_0_0i + c, c); assert_eq!(c + _0_0i, c); } @@ -307,7 +306,7 @@ mod test { assert_eq!(_0_1i - _1_0i, _neg1_1i); assert_eq!(_0_1i - _neg1_1i, _1_0i); - for all_consts.each |&c| { + for all_consts.iter().advance |&c| { assert_eq!(c - _0_0i, c); assert_eq!(c - c, _0_0i); } @@ -322,7 +321,7 @@ mod test { assert_eq!(_0_1i * _0_1i, -_1_0i); assert_eq!(_0_1i * _0_1i * _0_1i * _0_1i, _1_0i); - for all_consts.each |&c| { + for all_consts.iter().advance |&c| { assert_eq!(c * _1_0i, c); assert_eq!(_1_0i * c, c); } @@ -330,7 +329,7 @@ mod test { #[test] fn test_div() { assert_eq!(_neg1_1i / _0_1i, _1_1i); - for all_consts.each |&c| { + for all_consts.iter().advance |&c| { if c != Zero::zero() { assert_eq!(c / c, _1_0i); } @@ -340,7 +339,7 @@ mod test { fn test_neg() { assert_eq!(-_1_0i + _0_1i, _neg1_1i); assert_eq!((-_0_1i) * _0_1i, _1_0i); - for all_consts.each |&c| { + for all_consts.iter().advance |&c| { assert_eq!(-(-c), c); } } diff --git a/src/libextra/num/rational.rs b/src/libextra/num/rational.rs index b2b966928e9..6733599d1ea 100644 --- a/src/libextra/num/rational.rs +++ b/src/libextra/num/rational.rs @@ -10,11 +10,10 @@ //! Rational numbers -use core::prelude::*; -use core::cmp; -use core::from_str::FromStr; -use core::num::{Zero,One,ToStrRadix,FromStrRadix,Round}; +use std::cmp; +use std::from_str::FromStr; +use std::num::{Zero,One,ToStrRadix,FromStrRadix,Round}; use super::bigint::BigInt; /// Represents the ratio between 2 numbers. @@ -277,11 +276,10 @@ impl<T: FromStrRadix + Clone + Integer + Ord> #[cfg(test)] mod test { - use core::prelude::*; use super::*; - use core::num::{Zero,One,FromStrRadix,IntConvertible}; - use core::from_str::FromStr; + use std::num::{Zero,One,FromStrRadix,IntConvertible}; + use std::from_str::FromStr; pub static _0 : Rational = Ratio { numer: 0, denom: 1}; pub static _1 : Rational = Ratio { numer: 1, denom: 1}; @@ -482,7 +480,8 @@ mod test { assert_eq!(FromStr::from_str::<Rational>(s), None); } - for ["0 /1", "abc", "", "1/", "--1/2","3/2/1"].each |&s| { + let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"]; + for xs.iter().advance |&s| { test(s); } } @@ -521,7 +520,8 @@ mod test { assert_eq!(FromStrRadix::from_str_radix::<Rational>(s, 3), None); } - for ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "3/2"].each |&s| { + let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "3/2"]; + for xs.iter().advance |&s| { test(s); } } diff --git a/src/libextra/par.rs b/src/libextra/par.rs index 334ab7c9c99..2878a3ee122 100644 --- a/src/libextra/par.rs +++ b/src/libextra/par.rs @@ -8,13 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; -use core::cast; -use core::ptr; -use core::sys; -use core::uint; -use core::vec; +use std::cast; +use std::ptr; +use std::sys; +use std::uint; +use std::vec; use future_spawn = future::spawn; /** @@ -33,7 +32,7 @@ static min_granularity : uint = 1024u; * This is used to build most of the other parallel vector functions, * like map or alli. */ -fn map_slices<A:Copy + Owned,B:Copy + Owned>( +fn map_slices<A:Copy + Send,B:Copy + Send>( xs: &[A], f: &fn() -> ~fn(uint, v: &[A]) -> B) -> ~[B] { @@ -88,26 +87,26 @@ fn map_slices<A:Copy + Owned,B:Copy + Owned>( } /// A parallel version of map. -pub fn map<A:Copy + Owned,B:Copy + Owned>( +pub fn map<A:Copy + Send,B:Copy + Send>( xs: &[A], fn_factory: &fn() -> ~fn(&A) -> B) -> ~[B] { vec::concat(map_slices(xs, || { let f = fn_factory(); let result: ~fn(uint, &[A]) -> ~[B] = - |_, slice| vec::map(slice, |x| f(x)); + |_, slice| slice.iter().transform(|x| f(x)).collect(); result })) } /// A parallel version of mapi. -pub fn mapi<A:Copy + Owned,B:Copy + Owned>( +pub fn mapi<A:Copy + Send,B:Copy + Send>( xs: &[A], fn_factory: &fn() -> ~fn(uint, &A) -> B) -> ~[B] { let slices = map_slices(xs, || { let f = fn_factory(); let result: ~fn(uint, &[A]) -> ~[B] = |base, slice| { - vec::mapi(slice, |i, x| { + slice.iter().enumerate().transform(|(i, x)| { f(i + base, x) - }) + }).collect() }; result }); @@ -118,7 +117,7 @@ pub fn mapi<A:Copy + Owned,B:Copy + Owned>( } /// Returns true if the function holds for all elements in the vector. -pub fn alli<A:Copy + Owned>( +pub fn alli<A:Copy + Send>( xs: &[A], fn_factory: &fn() -> ~fn(uint, &A) -> bool) -> bool { @@ -133,7 +132,7 @@ pub fn alli<A:Copy + Owned>( } /// Returns true if the function holds for any elements in the vector. -pub fn any<A:Copy + Owned>( +pub fn any<A:Copy + Send>( xs: &[A], fn_factory: &fn() -> ~fn(&A) -> bool) -> bool { let mapped = map_slices(xs, || { diff --git a/src/libextra/priority_queue.rs b/src/libextra/priority_queue.rs index efbf23f11b1..3d1ca4a9818 100644 --- a/src/libextra/priority_queue.rs +++ b/src/libextra/priority_queue.rs @@ -12,27 +12,16 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::old_iter::BaseIter; -use core::unstable::intrinsics::{move_val_init, init}; -use core::util::{replace, swap}; -use core::vec; +use std::unstable::intrinsics::{move_val_init, init}; +use std::util::{replace, swap}; +use std::vec; -#[allow(missing_doc)] +/// A priority queue implemented with a binary heap pub struct PriorityQueue<T> { priv data: ~[T], } -impl<T:Ord> BaseIter<T> for PriorityQueue<T> { - /// Visit all values in the underlying vector. - /// - /// The values are **not** visited in order. - fn each(&self, f: &fn(&T) -> bool) -> bool { self.data.each(f) } - - fn size_hint(&self) -> Option<uint> { self.data.size_hint() } -} - impl<T:Ord> Container for PriorityQueue<T> { /// Returns the length of the queue fn len(&self) -> uint { self.data.len() } @@ -47,6 +36,12 @@ impl<T:Ord> Mutable for PriorityQueue<T> { } impl<T:Ord> PriorityQueue<T> { + /// An iterator visiting all values in underlying vector, in + /// arbitrary order. + pub fn iter<'a>(&'a self) -> PriorityQueueIterator<'a, T> { + PriorityQueueIterator { iter: self.data.iter() } + } + /// Returns the greatest item in the queue - fails if empty pub fn top<'a>(&'a self) -> &'a T { &self.data[0] } @@ -56,12 +51,12 @@ impl<T:Ord> PriorityQueue<T> { } /// Returns the number of elements the queue can hold without reallocating - pub fn capacity(&self) -> uint { vec::capacity(&self.data) } + pub fn capacity(&self) -> uint { self.data.capacity() } - pub fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) } + pub fn reserve(&mut self, n: uint) { self.data.reserve(n) } pub fn reserve_at_least(&mut self, n: uint) { - vec::reserve_at_least(&mut self.data, n) + self.data.reserve_at_least(n) } /// Pop the greatest item from the queue - fails if empty @@ -112,7 +107,7 @@ impl<T:Ord> PriorityQueue<T> { let mut end = q.len(); while end > 1 { end -= 1; - vec::swap(q.data, 0, end); + q.data.swap(0, end); q.siftdown_range(0, end) } q.to_vec() @@ -183,12 +178,34 @@ impl<T:Ord> PriorityQueue<T> { } } +/// PriorityQueue iterator +pub struct PriorityQueueIterator <'self, T> { + priv iter: vec::VecIterator<'self, T>, +} + +impl<'self, T> Iterator<&'self T> for PriorityQueueIterator<'self, T> { + #[inline] + fn next(&mut self) -> Option<(&'self T)> { self.iter.next() } +} + #[cfg(test)] mod tests { use sort::merge_sort; use priority_queue::PriorityQueue; #[test] + fn test_iterator() { + let data = ~[5, 9, 3]; + let iterout = ~[9, 5, 3]; + let pq = PriorityQueue::from_vec(data); + let mut i = 0; + for pq.iter().advance |el| { + assert_eq!(*el, iterout[i]); + i += 1; + } + } + + #[test] fn test_top_and_pop() { let data = ~[2u, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; let mut sorted = merge_sort(data, |x, y| x.le(y)); diff --git a/src/libextra/rc.rs b/src/libextra/rc.rs index b90b0983dc2..86080b343c7 100644 --- a/src/libextra/rc.rs +++ b/src/libextra/rc.rs @@ -13,21 +13,20 @@ /** Task-local reference counted smart pointers Task-local reference counted smart pointers are an alternative to managed boxes with deterministic -destruction. They are restricted to containing types that are either `Owned` or `Const` (or both) to +destruction. They are restricted to containing types that are either `Send` or `Freeze` (or both) to prevent cycles. -Neither `Rc<T>` or `RcMut<T>` is ever `Owned` and `RcMut<T>` is never `Const`. If `T` is `Const`, a +Neither `Rc<T>` or `RcMut<T>` is ever `Send` and `RcMut<T>` is never `Freeze`. If `T` is `Freeze`, a cycle cannot be created with `Rc<T>` because there is no way to modify it after creation. */ -use core::prelude::*; -use core::cast; -use core::libc::{c_void, size_t, malloc, free}; -use core::ptr; -use core::sys; -use core::unstable::intrinsics; +use std::cast; +use std::libc::{c_void, size_t, malloc, free}; +use std::ptr; +use std::sys; +use std::unstable::intrinsics; struct RcBox<T> { value: T, @@ -35,7 +34,8 @@ struct RcBox<T> { } /// Immutable reference counted pointer type -#[non_owned] +#[unsafe_no_drop_flag] +#[no_send] pub struct Rc<T> { priv ptr: *mut RcBox<T>, } @@ -50,12 +50,12 @@ impl<T> Rc<T> { } // FIXME: #6516: should be a static method -pub fn rc_from_owned<T: Owned>(value: T) -> Rc<T> { +pub fn rc_from_owned<T: Send>(value: T) -> Rc<T> { unsafe { Rc::new(value) } } // FIXME: #6516: should be a static method -pub fn rc_from_const<T: Const>(value: T) -> Rc<T> { +pub fn rc_from_const<T: Freeze>(value: T) -> Rc<T> { unsafe { Rc::new(value) } } @@ -68,12 +68,14 @@ impl<T> Rc<T> { #[unsafe_destructor] impl<T> Drop for Rc<T> { - fn finalize(&self) { + fn drop(&self) { unsafe { - (*self.ptr).count -= 1; - if (*self.ptr).count == 0 { - ptr::replace_ptr(self.ptr, intrinsics::uninit()); - free(self.ptr as *c_void) + if self.ptr.is_not_null() { + (*self.ptr).count -= 1; + if (*self.ptr).count == 0 { + ptr::replace_ptr(self.ptr, intrinsics::uninit()); + free(self.ptr as *c_void) + } } } } @@ -101,7 +103,7 @@ impl<T: DeepClone> DeepClone for Rc<T> { #[cfg(test)] mod test_rc { use super::*; - use core::cell::Cell; + use std::cell::Cell; #[test] fn test_clone() { @@ -165,7 +167,10 @@ struct RcMutBox<T> { /// Mutable reference counted pointer type #[non_owned] -#[mutable] +#[no_send] +#[mutable] // XXX remove after snap +#[no_freeze] +#[unsafe_no_drop_flag] pub struct RcMut<T> { priv ptr: *mut RcMutBox<T>, } @@ -180,12 +185,12 @@ impl<T> RcMut<T> { } // FIXME: #6516: should be a static method -pub fn rc_mut_from_owned<T: Owned>(value: T) -> RcMut<T> { +pub fn rc_mut_from_owned<T: Send>(value: T) -> RcMut<T> { unsafe { RcMut::new(value) } } // FIXME: #6516: should be a static method -pub fn rc_mut_from_const<T: Const>(value: T) -> RcMut<T> { +pub fn rc_mut_from_const<T: Freeze>(value: T) -> RcMut<T> { unsafe { RcMut::new(value) } } @@ -218,12 +223,14 @@ impl<T> RcMut<T> { #[unsafe_destructor] impl<T> Drop for RcMut<T> { - fn finalize(&self) { + fn drop(&self) { unsafe { - (*self.ptr).count -= 1; - if (*self.ptr).count == 0 { - ptr::replace_ptr(self.ptr, uninit()); - free(self.ptr as *c_void) + if self.ptr.is_not_null() { + (*self.ptr).count -= 1; + if (*self.ptr).count == 0 { + ptr::replace_ptr(self.ptr, uninit()); + free(self.ptr as *c_void) + } } } } diff --git a/src/libextra/rl.rs b/src/libextra/rl.rs index 040adcc443d..693e3ecb53f 100644 --- a/src/libextra/rl.rs +++ b/src/libextra/rl.rs @@ -11,14 +11,13 @@ // FIXME #3921. This is unsafe because linenoise uses global mutable // state without mutexes. -use core::prelude::*; -use core::libc::{c_char, c_int}; -use core::local_data; -use core::str; +use std::libc::{c_char, c_int}; +use std::local_data; +use std::str; pub mod rustrt { - use core::libc::{c_char, c_int}; + use std::libc::{c_char, c_int}; pub extern { pub unsafe fn linenoise(prompt: *c_char) -> *c_char; diff --git a/src/libextra/rope.rs b/src/libextra/rope.rs index fed73256c00..8374c1a86e3 100644 --- a/src/libextra/rope.rs +++ b/src/libextra/rope.rs @@ -35,11 +35,10 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::uint; -use core::vec; -use core::str; +use std::uint; +use std::vec; +use std::str; /// The type of ropes. pub type Rope = node::Root; @@ -447,7 +446,6 @@ pub fn loop_leaves(rope: Rope, it: &fn(node::Leaf) -> bool) -> bool{ pub mod iterator { pub mod leaf { - use core::prelude::*; use rope::{Rope, node}; @@ -462,7 +460,6 @@ pub mod iterator { } } pub mod char { - use core::prelude::*; use rope::{Rope, node}; @@ -558,13 +555,12 @@ pub fn char_at(rope: Rope, pos: uint) -> char { Section: Implementation */ pub mod node { - use core::prelude::*; use rope::node; - use core::cast; - use core::uint; - use core::vec; + use std::cast; + use std::uint; + use std::vec; /// Implementation of type `rope` pub enum Root { @@ -1078,7 +1074,7 @@ pub mod node { pub fn loop_chars(node: @Node, it: &fn(c: char) -> bool) -> bool { return loop_leaves(node,|leaf| { - leaf.content.slice(leaf.byte_offset, leaf.byte_len).iter().all(it) + leaf.content.slice(leaf.byte_offset, leaf.byte_len).iter().all(|c| it(c)) }); } @@ -1101,7 +1097,7 @@ pub mod node { loop { match (*current) { Leaf(x) => return it(x), - Concat(ref x) => if loop_leaves(x.left, it) { //non tail call + Concat(ref x) => if loop_leaves(x.left, |l| it(l)) { //non tail call current = x.right; //tail call } else { return false; @@ -1141,11 +1137,10 @@ pub mod node { } pub mod leaf_iterator { - use core::prelude::*; use rope::node::{Concat, Leaf, Node, height}; - use core::vec; + use std::vec; pub struct T { stack: ~[@Node], @@ -1184,7 +1179,6 @@ pub mod node { } pub mod char_iterator { - use core::prelude::*; use rope::node::{Leaf, Node}; use rope::node::leaf_iterator; @@ -1267,12 +1261,11 @@ pub mod node { #[cfg(test)] mod tests { - use core::prelude::*; use rope::*; - use core::uint; - use core::vec; + use std::uint; + use std::vec; //Utility function, used for sanity check fn rope_to_string(r: Rope) -> ~str { diff --git a/src/libextra/semver.rs b/src/libextra/semver.rs index cb372dd920d..6c9453a5a3b 100644 --- a/src/libextra/semver.rs +++ b/src/libextra/semver.rs @@ -12,15 +12,14 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::char; -use core::cmp; -use core::io::{ReaderUtil}; -use core::io; -use core::option::{Option, Some, None}; -use core::to_str::ToStr; -use core::uint; +use std::char; +use std::cmp; +use std::io::{ReaderUtil}; +use std::io; +use std::option::{Option, Some, None}; +use std::to_str::ToStr; +use std::uint; #[deriving(Eq)] pub enum Identifier { @@ -79,12 +78,12 @@ impl ToStr for Version { let s = if self.pre.is_empty() { s } else { - s + "-" + self.pre.map(|i| i.to_str()).connect(".") + fmt!("%s-%s", s, self.pre.map(|i| i.to_str()).connect(".")) }; if self.build.is_empty() { s } else { - s + "+" + self.build.map(|i| i.to_str()).connect(".") + fmt!("%s+%s", s, self.build.map(|i| i.to_str()).connect(".")) } } } diff --git a/src/libextra/serialize.rs b/src/libextra/serialize.rs index a54db07261a..66b178f49f7 100644 --- a/src/libextra/serialize.rs +++ b/src/libextra/serialize.rs @@ -17,13 +17,12 @@ Core encoding and decoding interfaces. #[allow(missing_doc)]; #[forbid(non_camel_case_types)]; -use core::prelude::*; -use core::at_vec; -use core::hashmap::{HashMap, HashSet}; -use core::trie::{TrieMap, TrieSet}; -use core::uint; -use core::vec; +use std::at_vec; +use std::hashmap::{HashMap, HashSet}; +use std::trie::{TrieMap, TrieSet}; +use std::uint; +use std::vec; use deque::Deque; use dlist::DList; use treemap::{TreeMap, TreeSet}; @@ -432,7 +431,7 @@ impl<D:Decoder,T:Decodable<D>> Decodable<D> for @T { impl<'self, S:Encoder,T:Encodable<S>> Encodable<S> for &'self [T] { fn encode(&self, s: &mut S) { do s.emit_seq(self.len()) |s| { - for self.eachi |i, e| { + for self.iter().enumerate().advance |(i, e)| { s.emit_seq_elt(i, |s| e.encode(s)) } } @@ -442,7 +441,7 @@ impl<'self, S:Encoder,T:Encodable<S>> Encodable<S> for &'self [T] { impl<S:Encoder,T:Encodable<S>> Encodable<S> for ~[T] { fn encode(&self, s: &mut S) { do s.emit_seq(self.len()) |s| { - for self.eachi |i, e| { + for self.iter().enumerate().advance |(i, e)| { s.emit_seq_elt(i, |s| e.encode(s)) } } @@ -462,7 +461,7 @@ impl<D:Decoder,T:Decodable<D>> Decodable<D> for ~[T] { impl<S:Encoder,T:Encodable<S>> Encodable<S> for @[T] { fn encode(&self, s: &mut S) { do s.emit_seq(self.len()) |s| { - for self.eachi |i, e| { + for self.iter().enumerate().advance |(i, e)| { s.emit_seq_elt(i, |s| e.encode(s)) } } @@ -710,7 +709,7 @@ impl< fn encode(&self, e: &mut E) { do e.emit_map(self.len()) |e| { let mut i = 0; - for self.each |key, val| { + for self.iter().advance |(key, val)| { e.emit_map_elt_key(i, |e| key.encode(e)); e.emit_map_elt_val(i, |e| val.encode(e)); i += 1; @@ -744,7 +743,7 @@ impl< fn encode(&self, s: &mut S) { do s.emit_seq(self.len()) |s| { let mut i = 0; - for self.each |e| { + for self.iter().advance |e| { s.emit_seq_elt(i, |s| e.encode(s)); i += 1; } @@ -832,7 +831,7 @@ impl< fn encode(&self, e: &mut E) { do e.emit_map(self.len()) |e| { let mut i = 0; - for self.each |key, val| { + for self.iter().advance |(key, val)| { e.emit_map_elt_key(i, |e| key.encode(e)); e.emit_map_elt_val(i, |e| val.encode(e)); i += 1; @@ -866,7 +865,7 @@ impl< fn encode(&self, s: &mut S) { do s.emit_seq(self.len()) |s| { let mut i = 0; - for self.each |e| { + for self.iter().advance |e| { s.emit_seq_elt(i, |s| e.encode(s)); i += 1; } @@ -901,7 +900,7 @@ pub trait EncoderHelpers { impl<S:Encoder> EncoderHelpers for S { fn emit_from_vec<T>(&mut self, v: &[T], f: &fn(&mut S, &T)) { do self.emit_seq(v.len()) |this| { - for v.eachi |i, e| { + for v.iter().enumerate().advance |(i, e)| { do this.emit_seq_elt(i) |this| { f(this, e) } diff --git a/src/libextra/sha1.rs b/src/libextra/sha1.rs deleted file mode 100644 index 7c4b3f4ce39..00000000000 --- a/src/libextra/sha1.rs +++ /dev/null @@ -1,410 +0,0 @@ -// 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. - -/*! - * An implementation of the SHA-1 cryptographic hash. - * - * First create a `sha1` object using the `sha1` constructor, then - * feed it input using the `input` or `input_str` methods, which may be - * called any number of times. - * - * After the entire input has been fed to the hash read the result using - * the `result` or `result_str` methods. - * - * The `sha1` object may be reused to create multiple hashes by calling - * the `reset` method. - */ - -use core::prelude::*; - -use core::uint; -use core::vec; - -/* - * A SHA-1 implementation derived from Paul E. Jones's reference - * implementation, which is written for clarity, not speed. At some - * point this will want to be rewritten. - */ - -/// The SHA-1 interface -trait Sha1 { - /// Provide message input as bytes - fn input(&mut self, &const [u8]); - /// Provide message input as string - fn input_str(&mut self, &str); - /** - * Read the digest as a vector of 20 bytes. After calling this no further - * input may be provided until reset is called. - */ - fn result(&mut self) -> ~[u8]; - /** - * Read the digest as a hex string. After calling this no further - * input may be provided until reset is called. - */ - fn result_str(&mut self) -> ~str; - /// Reset the SHA-1 state for reuse - fn reset(&mut self); -} - -// Some unexported constants -static digest_buf_len: uint = 5u; -static msg_block_len: uint = 64u; -static work_buf_len: uint = 80u; -static k0: u32 = 0x5A827999u32; -static k1: u32 = 0x6ED9EBA1u32; -static k2: u32 = 0x8F1BBCDCu32; -static k3: u32 = 0xCA62C1D6u32; - - -/// Construct a `sha` object -pub fn sha1() -> @Sha1 { - struct Sha1State - { h: ~[u32], - len_low: u32, - len_high: u32, - msg_block: ~[u8], - msg_block_idx: uint, - computed: bool, - work_buf: @mut ~[u32]}; - - fn add_input(st: &mut Sha1State, msg: &const [u8]) { - assert!((!st.computed)); - for vec::each_const(msg) |element| { - st.msg_block[st.msg_block_idx] = *element; - st.msg_block_idx += 1u; - st.len_low += 8u32; - if st.len_low == 0u32 { - st.len_high += 1u32; - if st.len_high == 0u32 { - // FIXME: Need better failure mode (#2346) - fail!(); - } - } - if st.msg_block_idx == msg_block_len { process_msg_block(st); } - } - } - fn process_msg_block(st: &mut Sha1State) { - assert_eq!(st.h.len(), digest_buf_len); - assert_eq!(st.work_buf.len(), work_buf_len); - let mut t: int; // Loop counter - let w = st.work_buf; - - // Initialize the first 16 words of the vector w - t = 0; - while t < 16 { - let mut tmp; - tmp = (st.msg_block[t * 4] as u32) << 24u32; - tmp = tmp | (st.msg_block[t * 4 + 1] as u32) << 16u32; - tmp = tmp | (st.msg_block[t * 4 + 2] as u32) << 8u32; - tmp = tmp | (st.msg_block[t * 4 + 3] as u32); - w[t] = tmp; - t += 1; - } - - // Initialize the rest of vector w - while t < 80 { - let val = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; - w[t] = circular_shift(1u32, val); - t += 1; - } - let mut a = st.h[0]; - let mut b = st.h[1]; - let mut c = st.h[2]; - let mut d = st.h[3]; - let mut e = st.h[4]; - let mut temp: u32; - t = 0; - while t < 20 { - temp = circular_shift(5u32, a) + (b & c | !b & d) + e + w[t] + k0; - e = d; - d = c; - c = circular_shift(30u32, b); - b = a; - a = temp; - t += 1; - } - while t < 40 { - temp = circular_shift(5u32, a) + (b ^ c ^ d) + e + w[t] + k1; - e = d; - d = c; - c = circular_shift(30u32, b); - b = a; - a = temp; - t += 1; - } - while t < 60 { - temp = - circular_shift(5u32, a) + (b & c | b & d | c & d) + e + w[t] + - k2; - e = d; - d = c; - c = circular_shift(30u32, b); - b = a; - a = temp; - t += 1; - } - while t < 80 { - temp = circular_shift(5u32, a) + (b ^ c ^ d) + e + w[t] + k3; - e = d; - d = c; - c = circular_shift(30u32, b); - b = a; - a = temp; - t += 1; - } - st.h[0] = st.h[0] + a; - st.h[1] = st.h[1] + b; - st.h[2] = st.h[2] + c; - st.h[3] = st.h[3] + d; - st.h[4] = st.h[4] + e; - st.msg_block_idx = 0u; - } - fn circular_shift(bits: u32, word: u32) -> u32 { - return word << bits | word >> 32u32 - bits; - } - fn mk_result(st: &mut Sha1State) -> ~[u8] { - if !(*st).computed { pad_msg(st); (*st).computed = true; } - let mut rs: ~[u8] = ~[]; - for st.h.mut_iter().advance |ptr_hpart| { - let hpart = *ptr_hpart; - let a = (hpart >> 24u32 & 0xFFu32) as u8; - let b = (hpart >> 16u32 & 0xFFu32) as u8; - let c = (hpart >> 8u32 & 0xFFu32) as u8; - let d = (hpart & 0xFFu32) as u8; - rs = vec::append(copy rs, [a, b, c, d]); - } - return rs; - } - - /* - * According to the standard, the message must be padded to an even - * 512 bits. The first padding bit must be a '1'. The last 64 bits - * represent the length of the original message. All bits in between - * should be 0. This function will pad the message according to those - * rules by filling the msg_block vector accordingly. It will also - * call process_msg_block() appropriately. When it returns, it - * can be assumed that the message digest has been computed. - */ - fn pad_msg(st: &mut Sha1State) { - assert_eq!((*st).msg_block.len(), msg_block_len); - - /* - * Check to see if the current message block is too small to hold - * the initial padding bits and length. If so, we will pad the - * block, process it, and then continue padding into a second block. - */ - if (*st).msg_block_idx > 55u { - (*st).msg_block[(*st).msg_block_idx] = 0x80u8; - (*st).msg_block_idx += 1u; - while (*st).msg_block_idx < msg_block_len { - (*st).msg_block[(*st).msg_block_idx] = 0u8; - (*st).msg_block_idx += 1u; - } - process_msg_block(st); - } else { - (*st).msg_block[(*st).msg_block_idx] = 0x80u8; - (*st).msg_block_idx += 1u; - } - while (*st).msg_block_idx < 56u { - (*st).msg_block[(*st).msg_block_idx] = 0u8; - (*st).msg_block_idx += 1u; - } - - // Store the message length as the last 8 octets - (*st).msg_block[56] = ((*st).len_high >> 24u32 & 0xFFu32) as u8; - (*st).msg_block[57] = ((*st).len_high >> 16u32 & 0xFFu32) as u8; - (*st).msg_block[58] = ((*st).len_high >> 8u32 & 0xFFu32) as u8; - (*st).msg_block[59] = ((*st).len_high & 0xFFu32) as u8; - (*st).msg_block[60] = ((*st).len_low >> 24u32 & 0xFFu32) as u8; - (*st).msg_block[61] = ((*st).len_low >> 16u32 & 0xFFu32) as u8; - (*st).msg_block[62] = ((*st).len_low >> 8u32 & 0xFFu32) as u8; - (*st).msg_block[63] = ((*st).len_low & 0xFFu32) as u8; - process_msg_block(st); - } - - impl Sha1 for Sha1State { - fn reset(&mut self) { - assert_eq!(self.h.len(), digest_buf_len); - self.len_low = 0u32; - self.len_high = 0u32; - self.msg_block_idx = 0u; - self.h[0] = 0x67452301u32; - self.h[1] = 0xEFCDAB89u32; - self.h[2] = 0x98BADCFEu32; - self.h[3] = 0x10325476u32; - self.h[4] = 0xC3D2E1F0u32; - self.computed = false; - } - fn input(&mut self, msg: &const [u8]) { add_input(self, msg); } - fn input_str(&mut self, msg: &str) { - add_input(self, msg.as_bytes()); - } - fn result(&mut self) -> ~[u8] { return mk_result(self); } - fn result_str(&mut self) -> ~str { - let rr = mk_result(self); - let mut s = ~""; - for rr.each |b| { - let hex = uint::to_str_radix(*b as uint, 16u); - if hex.len() == 1 { - s += "0"; - } - s += hex; - } - return s; - } - } - let st = Sha1State { - h: vec::from_elem(digest_buf_len, 0u32), - len_low: 0u32, - len_high: 0u32, - msg_block: vec::from_elem(msg_block_len, 0u8), - msg_block_idx: 0u, - computed: false, - work_buf: @mut vec::from_elem(work_buf_len, 0u32) - }; - let mut sh = @st as @Sha1; - sh.reset(); - return sh; -} - -#[cfg(test)] -mod tests { - use sha1; - - #[test] - fn test() { - struct Test { - input: ~str, - output: ~[u8], - output_str: ~str, - } - - fn a_million_letter_a() -> ~str { - let mut i = 0; - let mut rs = ~""; - while i < 100000 { - rs.push_str("aaaaaaaaaa"); - i += 1; - } - return rs; - } - // Test messages from FIPS 180-1 - - let fips_180_1_tests = ~[ - Test { - input: ~"abc", - output: ~[ - 0xA9u8, 0x99u8, 0x3Eu8, 0x36u8, - 0x47u8, 0x06u8, 0x81u8, 0x6Au8, - 0xBAu8, 0x3Eu8, 0x25u8, 0x71u8, - 0x78u8, 0x50u8, 0xC2u8, 0x6Cu8, - 0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8, - ], - output_str: ~"a9993e364706816aba3e25717850c26c9cd0d89d" - }, - Test { - input: - ~"abcdbcdecdefdefgefghfghighij" + - "hijkijkljklmklmnlmnomnopnopq", - output: ~[ - 0x84u8, 0x98u8, 0x3Eu8, 0x44u8, - 0x1Cu8, 0x3Bu8, 0xD2u8, 0x6Eu8, - 0xBAu8, 0xAEu8, 0x4Au8, 0xA1u8, - 0xF9u8, 0x51u8, 0x29u8, 0xE5u8, - 0xE5u8, 0x46u8, 0x70u8, 0xF1u8, - ], - output_str: ~"84983e441c3bd26ebaae4aa1f95129e5e54670f1" - }, - Test { - input: a_million_letter_a(), - output: ~[ - 0x34u8, 0xAAu8, 0x97u8, 0x3Cu8, - 0xD4u8, 0xC4u8, 0xDAu8, 0xA4u8, - 0xF6u8, 0x1Eu8, 0xEBu8, 0x2Bu8, - 0xDBu8, 0xADu8, 0x27u8, 0x31u8, - 0x65u8, 0x34u8, 0x01u8, 0x6Fu8, - ], - output_str: ~"34aa973cd4c4daa4f61eeb2bdbad27316534016f" - }, - ]; - // Examples from wikipedia - - let wikipedia_tests = ~[ - Test { - input: ~"The quick brown fox jumps over the lazy dog", - output: ~[ - 0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8, - 0x7au8, 0x2du8, 0x28u8, 0xfcu8, - 0xedu8, 0x84u8, 0x9eu8, 0xe1u8, - 0xbbu8, 0x76u8, 0xe7u8, 0x39u8, - 0x1bu8, 0x93u8, 0xebu8, 0x12u8, - ], - output_str: ~"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", - }, - Test { - input: ~"The quick brown fox jumps over the lazy cog", - output: ~[ - 0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8, - 0xd2u8, 0x5eu8, 0x1bu8, 0x3au8, - 0xfau8, 0xd3u8, 0xe8u8, 0x5au8, - 0x0bu8, 0xd1u8, 0x7du8, 0x9bu8, - 0x10u8, 0x0du8, 0xb4u8, 0xb3u8, - ], - output_str: ~"de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3", - }, - ]; - let tests = fips_180_1_tests + wikipedia_tests; - fn check_vec_eq(v0: ~[u8], v1: ~[u8]) { - assert_eq!(v0.len(), v1.len()); - let len = v0.len(); - let mut i = 0u; - while i < len { - let a = v0[i]; - let b = v1[i]; - assert_eq!(a, b); - i += 1u; - } - } - // Test that it works when accepting the message all at once - - let mut sh = sha1::sha1(); - for tests.each |t| { - sh.input_str(t.input); - let out = sh.result(); - check_vec_eq(copy t.output, out); - - let out_str = sh.result_str(); - assert_eq!(out_str.len(), 40); - assert!(out_str == t.output_str); - - sh.reset(); - } - - - // Test that it works when accepting the message in pieces - for tests.each |t| { - let len = t.input.len(); - let mut left = len; - while left > 0u { - let take = (left + 1u) / 2u; - sh.input_str(t.input.slice(len - left, take + len - left)); - left = left - take; - } - let out = sh.result(); - check_vec_eq(copy t.output, out); - - let out_str = sh.result_str(); - assert_eq!(out_str.len(), 40); - assert!(out_str == t.output_str); - - sh.reset(); - } - } -} diff --git a/src/libextra/smallintmap.rs b/src/libextra/smallintmap.rs index aee087d3764..9cfe7cf5e4a 100644 --- a/src/libextra/smallintmap.rs +++ b/src/libextra/smallintmap.rs @@ -15,15 +15,11 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::cmp; -use core::container::{Container, Mutable, Map, Set}; -use core::old_iter::BaseIter; -use core::old_iter; -use core::uint; -use core::util::replace; -use core::vec; +use std::cmp; +use std::container::{Container, Mutable, Map, Set}; +use std::uint; +use std::util::replace; #[allow(missing_doc)] pub struct SmallIntMap<T> { @@ -58,38 +54,6 @@ impl<V> Map<uint, V> for SmallIntMap<V> { self.find(key).is_some() } - /// Visit all key-value pairs in order - fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) -> bool { - for uint::range(0, self.v.len()) |i| { - match self.v[i] { - Some(ref elt) => if !it(&i, elt) { return false; }, - None => () - } - } - return true; - } - - /// Visit all keys in order - fn each_key(&self, blk: &fn(key: &uint) -> bool) -> bool { - self.each(|k, _| blk(k)) - } - - /// Visit all values in order - fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) -> bool { - self.each(|_, v| blk(v)) - } - - /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, it: &fn(&uint, &mut V) -> bool) -> bool { - for uint::range(0, self.v.len()) |i| { - match self.v[i] { - Some(ref mut elt) => if !it(&i, elt) { return false; }, - None => () - } - } - return true; - } - /// Return a reference to the value corresponding to the key fn find<'a>(&'a self, key: &uint) -> Option<&'a V> { if *key < self.v.len() { @@ -121,7 +85,7 @@ impl<V> Map<uint, V> for SmallIntMap<V> { let exists = self.contains_key(&key); let len = self.v.len(); if len <= key { - vec::grow_fn(&mut self.v, key - len + 1, |_| None); + self.v.grow_fn(key - len + 1, |_| None); } self.v[key] = Some(value); !exists @@ -158,6 +122,38 @@ impl<V> SmallIntMap<V> { /// Create an empty SmallIntMap pub fn new() -> SmallIntMap<V> { SmallIntMap{v: ~[]} } + /// Visit all key-value pairs in order + pub fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) -> bool { + for uint::range(0, self.v.len()) |i| { + match self.v[i] { + Some(ref elt) => if !it(&i, elt) { return false; }, + None => () + } + } + return true; + } + + /// Visit all keys in order + pub fn each_key(&self, blk: &fn(key: &uint) -> bool) -> bool { + self.each(|k, _| blk(k)) + } + + /// Visit all values in order + pub fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) -> bool { + self.each(|_, v| blk(v)) + } + + /// Iterate over the map and mutate the contained values + pub fn mutate_values(&mut self, it: &fn(&uint, &mut V) -> bool) -> bool { + for uint::range(0, self.v.len()) |i| { + match self.v[i] { + Some(ref mut elt) => if !it(&i, elt) { return false; }, + None => () + } + } + return true; + } + /// Visit all key-value pairs in reverse order pub fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) -> bool { for uint::range_rev(self.v.len(), 0) |i| { @@ -212,12 +208,6 @@ impl Mutable for SmallIntSet { fn clear(&mut self) { self.map.clear() } } -impl BaseIter<uint> for SmallIntSet { - /// Visit all values in order - fn each(&self, f: &fn(&uint) -> bool) -> bool { self.map.each_key(f) } - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - impl Set<uint> for SmallIntSet { /// Return true if the set contains a value fn contains(&self, value: &uint) -> bool { self.map.contains_key(value) } @@ -233,12 +223,14 @@ impl Set<uint> for SmallIntSet { /// Return true if the set has no elements in common with `other`. /// This is equivalent to checking for an empty uintersection. fn is_disjoint(&self, other: &SmallIntSet) -> bool { - old_iter::all(self, |v| !other.contains(v)) + for self.each |v| { if other.contains(v) { return false } } + true } /// Return true if the set is a subset of another fn is_subset(&self, other: &SmallIntSet) -> bool { - old_iter::all(self, |v| other.contains(v)) + for self.each |v| { if !other.contains(v) { return false } } + true } /// Return true if the set is a superset of another @@ -286,11 +278,13 @@ impl Set<uint> for SmallIntSet { impl SmallIntSet { /// Create an empty SmallIntSet pub fn new() -> SmallIntSet { SmallIntSet{map: SmallIntMap::new()} } + + /// Visit all values in order + pub fn each(&self, f: &fn(&uint) -> bool) -> bool { self.map.each_key(f) } } #[cfg(test)] mod tests { - use core::prelude::*; use super::SmallIntMap; @@ -385,12 +379,9 @@ mod tests { #[cfg(test)] mod test_set { - use core::prelude::*; use super::SmallIntSet; - use core::vec; - #[test] fn test_disjoint() { let mut xs = SmallIntSet::new(); @@ -462,7 +453,7 @@ mod test_set { let mut i = 0; let expected = [3, 5, 11, 77]; for a.intersection(&b) |x| { - assert!(vec::contains(expected, x)); + assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); @@ -485,7 +476,7 @@ mod test_set { let mut i = 0; let expected = [1, 5, 11]; for a.difference(&b) |x| { - assert!(vec::contains(expected, x)); + assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); @@ -510,7 +501,7 @@ mod test_set { let mut i = 0; let expected = [1, 5, 11, 14, 22]; for a.symmetric_difference(&b) |x| { - assert!(vec::contains(expected, x)); + assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); @@ -539,7 +530,7 @@ mod test_set { let mut i = 0; let expected = [1, 3, 5, 9, 11, 13, 16, 19, 24]; for a.union(&b) |x| { - assert!(vec::contains(expected, x)); + assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); diff --git a/src/libextra/sort.rs b/src/libextra/sort.rs index 3e81216fc3a..f59a2414aae 100644 --- a/src/libextra/sort.rs +++ b/src/libextra/sort.rs @@ -10,12 +10,11 @@ //! Sorting methods -use core::prelude::*; -use core::cmp::{Eq, Ord}; -use core::uint; -use core::util::swap; -use core::vec; +use std::cmp::{Eq, Ord}; +use std::uint; +use std::util::swap; +use std::vec; type Le<'self, T> = &'self fn(v1: &T, v2: &T) -> bool; @@ -42,7 +41,8 @@ pub fn merge_sort<T:Copy>(v: &[T], le: Le<T>) -> ~[T] { let mid = v_len / 2 + begin; let a = (begin, mid); let b = (mid, end); - return merge(le, merge_sort_(v, a, le), merge_sort_(v, b, le)); + return merge(|x,y| le(x,y), merge_sort_(v, a, |x,y| le(x,y)), + merge_sort_(v, b, |x,y| le(x,y))); } fn merge<T:Copy>(le: Le<T>, a: &[T], b: &[T]) -> ~[T] { @@ -57,25 +57,25 @@ pub fn merge_sort<T:Copy>(v: &[T], le: Le<T>) -> ~[T] { a_ix += 1; } else { rs.push(copy b[b_ix]); b_ix += 1; } } - rs.push_all(vec::slice(a, a_ix, a_len)); - rs.push_all(vec::slice(b, b_ix, b_len)); + rs.push_all(a.slice(a_ix, a_len)); + rs.push_all(b.slice(b_ix, b_len)); rs } } fn part<T>(arr: &mut [T], left: uint, right: uint, pivot: uint, compare_func: Le<T>) -> uint { - vec::swap(arr, pivot, right); + arr.swap(pivot, right); let mut storage_index: uint = left; let mut i: uint = left; while i < right { if compare_func(&arr[i], &arr[right]) { - vec::swap(arr, i, storage_index); + arr.swap(i, storage_index); storage_index += 1; } i += 1; } - vec::swap(arr, storage_index, right); + arr.swap(storage_index, right); return storage_index; } @@ -83,10 +83,10 @@ fn qsort<T>(arr: &mut [T], left: uint, right: uint, compare_func: Le<T>) { if right > left { let pivot = (left + right) / 2u; - let new_pivot = part::<T>(arr, left, right, pivot, compare_func); + let new_pivot = part::<T>(arr, left, right, pivot, |x,y| compare_func(x,y)); if new_pivot != 0u { // Need to do this check before recursing due to overflow - qsort::<T>(arr, left, new_pivot - 1u, compare_func); + qsort::<T>(arr, left, new_pivot - 1u, |x,y| compare_func(x,y)); } qsort::<T>(arr, new_pivot + 1u, right, compare_func); } @@ -120,29 +120,29 @@ fn qsort3<T:Copy + Ord + Eq>(arr: &mut [T], left: int, right: int) { j -= 1; } if i >= j { break; } - vec::swap(arr, i as uint, j as uint); + arr.swap(i as uint, j as uint); if arr[i] == v { p += 1; - vec::swap(arr, p as uint, i as uint); + arr.swap(p as uint, i as uint); } if v == arr[j] { q -= 1; - vec::swap(arr, j as uint, q as uint); + arr.swap(j as uint, q as uint); } } - vec::swap(arr, i as uint, right as uint); + arr.swap(i as uint, right as uint); j = i - 1; i += 1; let mut k: int = left; while k < p { - vec::swap(arr, k as uint, j as uint); + arr.swap(k as uint, j as uint); k += 1; j -= 1; if k == arr.len() as int { break; } } k = right - 1; while k > q { - vec::swap(arr, i as uint, k as uint); + arr.swap(i as uint, k as uint); k -= 1; i += 1; if k == 0 { break; } @@ -201,12 +201,12 @@ pub fn tim_sort<T:Copy + Ord>(array: &mut [T]) { loop { let run_len: uint = { // This scope contains the slice `arr` here: - let arr = vec::mut_slice(array, idx, size); + let arr = array.mut_slice(idx, size); let mut run_len: uint = count_run_ascending(arr); if run_len < min_run { let force = if remaining <= min_run {remaining} else {min_run}; - let slice = vec::mut_slice(arr, 0, force); + let slice = arr.mut_slice(0, force); binarysort(slice, run_len); run_len = force; } @@ -259,7 +259,7 @@ fn binarysort<T:Copy + Ord>(array: &mut [T], start: uint) { fn reverse_slice<T>(v: &mut [T], start: uint, end:uint) { let mut i = start; while i < end / 2 { - vec::swap(v, i, end - i - 1); + v.swap(i, end - i - 1); i += 1; } } @@ -443,14 +443,14 @@ impl<T:Copy + Ord> MergeState<T> { } let k = { // constrain lifetime of slice below - let slice = vec::slice(array, b1, b1+l1); + let slice = array.slice(b1, b1+l1); gallop_right(&array[b2], slice, 0) }; b1 += k; l1 -= k; if l1 != 0 { let l2 = { // constrain lifetime of slice below - let slice = vec::slice(array, b2, b2+l2); + let slice = array.slice(b2, b2+l2); gallop_left(&array[b1+l1-1],slice,l2-1) }; if l2 > 0 { @@ -479,7 +479,7 @@ impl<T:Copy + Ord> MergeState<T> { let mut len1 = len1; let mut len2 = len2; - vec::swap(array, dest, c2); + array.swap(dest, c2); dest += 1; c2 += 1; len2 -= 1; if len2 == 0 { @@ -501,7 +501,7 @@ impl<T:Copy + Ord> MergeState<T> { loop { assert!(len1 > 1 && len2 != 0); if array[c2] < tmp[c1] { - vec::swap(array, dest, c2); + array.swap(dest, c2); dest += 1; c2 += 1; len2 -= 1; count2 += 1; count1 = 0; if len2 == 0 { @@ -526,7 +526,7 @@ impl<T:Copy + Ord> MergeState<T> { assert!(len1 > 1 && len2 != 0); count1 = { - let tmp_view = vec::slice(tmp, c1, c1+len1); + let tmp_view = tmp.slice(c1, c1+len1); gallop_right(&array[c2], tmp_view, 0) }; if count1 != 0 { @@ -534,12 +534,12 @@ impl<T:Copy + Ord> MergeState<T> { dest += count1; c1 += count1; len1 -= count1; if len1 <= 1 { break_outer = true; break; } } - vec::swap(array, dest, c2); + array.swap(dest, c2); dest += 1; c2 += 1; len2 -= 1; if len2 == 0 { break_outer = true; break; } count2 = { - let tmp_view = vec::slice(array, c2, c2+len2); + let tmp_view = array.slice(c2, c2+len2); gallop_left(&tmp[c1], tmp_view, 0) }; if count2 != 0 { @@ -589,7 +589,7 @@ impl<T:Copy + Ord> MergeState<T> { let mut len1 = len1; let mut len2 = len2; - vec::swap(array, dest, c1); + array.swap(dest, c1); dest -= 1; c1 -= 1; len1 -= 1; if len1 == 0 { @@ -613,7 +613,7 @@ impl<T:Copy + Ord> MergeState<T> { loop { assert!(len1 != 0 && len2 > 1); if tmp[c2] < array[c1] { - vec::swap(array, dest, c1); + array.swap(dest, c1); dest -= 1; c1 -= 1; len1 -= 1; count1 += 1; count2 = 0; if len1 == 0 { @@ -638,7 +638,7 @@ impl<T:Copy + Ord> MergeState<T> { assert!(len2 > 1 && len1 != 0); { // constrain scope of tmp_view: - let tmp_view = vec::mut_slice (array, base1, base1+len1); + let tmp_view = array.mut_slice(base1, base1+len1); count1 = len1 - gallop_right( &tmp[c2], tmp_view, len1-1); } @@ -655,7 +655,7 @@ impl<T:Copy + Ord> MergeState<T> { let count2; { // constrain scope of tmp_view - let tmp_view = vec::mut_slice(tmp, 0, len2); + let tmp_view = tmp.mut_slice(0, len2); count2 = len2 - gallop_left(&array[c1], tmp_view, len2-1); @@ -666,7 +666,7 @@ impl<T:Copy + Ord> MergeState<T> { copy_vec(array, dest+1, tmp.slice(c2+1, c2+1+count2)); if len2 <= 1 { break_outer = true; break; } } - vec::swap(array, dest, c1); + array.swap(dest, c1); dest -= 1; c1 -= 1; len1 -= 1; if len1 == 0 { break_outer = true; break; } min_gallop -= 1; @@ -731,7 +731,7 @@ fn copy_vec<T:Copy>(dest: &mut [T], from: &[T]) { assert!(s1+from.len() <= dest.len()); - for from.eachi |i, v| { + for from.iter().enumerate().advance |(i, v)| { dest[s1+i] = copy *v; } } @@ -743,7 +743,7 @@ fn shift_vec<T:Copy>(dest: &mut [T], len: uint) { assert!(s1+len <= dest.len()); - let tmp = dest.slice(s2, s2+len).to_vec(); + let tmp = dest.slice(s2, s2+len).to_owned(); copy_vec(dest, s1, tmp); } @@ -790,12 +790,11 @@ mod test_qsort3 { #[cfg(test)] mod test_qsort { - use core::prelude::*; use sort::*; - use core::int; - use core::vec; + use std::int; + use std::vec; fn check_sort(v1: &mut [int], v2: &mut [int]) { let len = v1.len(); @@ -846,7 +845,7 @@ mod test_qsort { let immut_names = names; let pairs = vec::zip_slice(expected, immut_names); - for pairs.each |p| { + for pairs.iter().advance |p| { let (a, b) = *p; debug!("%d %d", a, b); assert_eq!(a, b); @@ -856,7 +855,6 @@ mod test_qsort { #[cfg(test)] mod tests { - use core::prelude::*; use sort::*; @@ -923,12 +921,11 @@ mod tests { #[cfg(test)] mod test_tim_sort { - use core::prelude::*; use sort::tim_sort; - use core::rand::RngUtil; - use core::rand; - use core::vec; + use std::rand::RngUtil; + use std::rand; + use std::vec; struct CVal { val: float, @@ -1018,15 +1015,14 @@ mod test_tim_sort { #[cfg(test)] mod big_tests { - use core::prelude::*; use sort::*; - use core::local_data; - use core::rand::RngUtil; - use core::rand; - use core::uint; - use core::vec; + use std::local_data; + use std::rand::RngUtil; + use std::rand; + use std::uint; + use std::vec; #[test] fn test_unique() { @@ -1053,7 +1049,7 @@ mod big_tests { fn makeRange(n: uint) -> ~[uint] { let one = do vec::from_fn(n) |i| { i }; let mut two = copy one; - vec::reverse(two); + two.reverse(); vec::append(two, one) } @@ -1077,7 +1073,7 @@ mod big_tests { tim_sort(arr); // *sort isSorted(arr); - vec::reverse(arr); + arr.reverse(); tim_sort(arr); // \sort isSorted(arr); @@ -1087,7 +1083,7 @@ mod big_tests { for 3.times { let i1 = rng.gen_uint_range(0, n); let i2 = rng.gen_uint_range(0, n); - vec::swap(arr, i1, i2); + arr.swap(i1, i2); } tim_sort(arr); // 3sort isSorted(arr); @@ -1111,7 +1107,7 @@ mod big_tests { isSorted(arr); let mut arr = if n > 4 { - let part = vec::slice(arr, 0, 4); + let part = arr.slice(0, 4); multiplyVec(part, n) } else { arr }; tim_sort(arr); // ~sort @@ -1149,7 +1145,7 @@ mod big_tests { tim_sort(arr); // *sort isSorted(arr); - vec::reverse(arr); + arr.reverse(); tim_sort(arr); // \sort isSorted(arr); @@ -1159,7 +1155,7 @@ mod big_tests { for 3.times { let i1 = rng.gen_uint_range(0, n); let i2 = rng.gen_uint_range(0, n); - vec::swap(arr, i1, i2); + arr.swap(i1, i2); } tim_sort(arr); // 3sort isSorted(arr); @@ -1183,7 +1179,7 @@ mod big_tests { isSorted(arr); let mut arr = if n > 4 { - let part = vec::slice(arr, 0, 4); + let part = arr.slice(0, 4); multiplyVec(part, n) } else { arr }; tim_sort(arr); // ~sort @@ -1202,12 +1198,12 @@ mod big_tests { struct LVal<'self> { val: uint, - key: &'self fn(@uint), + key: &'self fn:Copy(@uint), } #[unsafe_destructor] impl<'self> Drop for LVal<'self> { - fn finalize(&self) { + fn drop(&self) { let x = unsafe { local_data::local_data_get(self.key) }; match x { Some(@y) => { diff --git a/src/libextra/stats.rs b/src/libextra/stats.rs index 3a1de5de01d..8351e4db6b8 100644 --- a/src/libextra/stats.rs +++ b/src/libextra/stats.rs @@ -10,12 +10,11 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::f64; -use core::cmp; -use core::num; -use core::vec; +use std::f64; +use std::cmp; +use std::num; +use std::vec; use sort; // NB: this can probably be rewritten in terms of num::Num @@ -72,7 +71,7 @@ impl<'self> Stats for &'self [f64] { } else { let mean = self.mean(); let mut v = 0.0; - for self.each |s| { + for self.iter().advance |s| { let x = *s - mean; v += x*x; } diff --git a/src/libextra/sync.rs b/src/libextra/sync.rs index f5d0b6946d3..b9d25451a8a 100644 --- a/src/libextra/sync.rs +++ b/src/libextra/sync.rs @@ -15,14 +15,13 @@ * in std. */ -use core::prelude::*; -use core::borrow; -use core::comm; -use core::task; -use core::unstable::sync::{Exclusive, exclusive, UnsafeAtomicRcBox}; -use core::unstable::atomics; -use core::util; +use std::borrow; +use std::comm; +use std::task; +use std::unstable::sync::{Exclusive, exclusive, UnsafeAtomicRcBox}; +use std::unstable::atomics; +use std::util; /**************************************************************************** * Internals @@ -86,7 +85,7 @@ struct SemInner<Q> { struct Sem<Q>(Exclusive<SemInner<Q>>); #[doc(hidden)] -fn new_sem<Q:Owned>(count: int, q: Q) -> Sem<Q> { +fn new_sem<Q:Send>(count: int, q: Q) -> Sem<Q> { Sem(exclusive(SemInner { count: count, waiters: new_waitqueue(), blocked: q })) } @@ -101,7 +100,7 @@ fn new_sem_and_signal(count: int, num_condvars: uint) } #[doc(hidden)] -impl<Q:Owned> Sem<Q> { +impl<Q:Send> Sem<Q> { pub fn acquire(&self) { unsafe { let mut waiter_nobe = None; @@ -153,7 +152,7 @@ impl Sem<()> { #[doc(hidden)] impl Sem<~[Waitqueue]> { - pub fn access<U>(&self, blk: &fn() -> U) -> U { + pub fn access_waitqueue<U>(&self, blk: &fn() -> U) -> U { let mut release = None; unsafe { do task::unkillable { @@ -175,8 +174,8 @@ struct SemReleaseGeneric<'self, Q> { sem: &'self Sem<Q> } #[doc(hidden)] #[unsafe_destructor] -impl<'self, Q:Owned> Drop for SemReleaseGeneric<'self, Q> { - fn finalize(&self) { +impl<'self, Q:Send> Drop for SemReleaseGeneric<'self, Q> { + fn drop(&self) { self.sem.release(); } } @@ -219,7 +218,7 @@ pub struct Condvar<'self> { } #[unsafe_destructor] -impl<'self> Drop for Condvar<'self> { fn finalize(&self) {} } +impl<'self> Drop for Condvar<'self> { fn drop(&self) {} } impl<'self> Condvar<'self> { /** @@ -295,7 +294,7 @@ impl<'self> Condvar<'self> { #[unsafe_destructor] impl<'self> Drop for CondvarReacquire<'self> { - fn finalize(&self) { + fn drop(&self) { unsafe { // Needs to succeed, instead of itself dying. do task::unkillable { @@ -381,7 +380,7 @@ impl Sem<~[Waitqueue]> { // The only other places that condvars get built are rwlock.write_cond() // and rwlock_write_mode. pub fn access_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U { - do self.access { + do self.access_waitqueue { blk(&Condvar { sem: self, order: Nothing }) } } @@ -456,7 +455,9 @@ impl Clone for Mutex { impl Mutex { /// Run a function with ownership of the mutex. - pub fn lock<U>(&self, blk: &fn() -> U) -> U { (&self.sem).access(blk) } + pub fn lock<U>(&self, blk: &fn() -> U) -> U { + (&self.sem).access_waitqueue(blk) + } /// Run a function with ownership of the mutex and a handle to a condvar. pub fn lock_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U { @@ -559,9 +560,11 @@ impl RWlock { unsafe { do task::unkillable { (&self.order_lock).acquire(); - do (&self.access_lock).access { + do (&self.access_lock).access_waitqueue { (&self.order_lock).release(); - task::rekillable(blk) + do task::rekillable { + blk() + } } } } @@ -689,7 +692,7 @@ struct RWlockReleaseRead<'self> { #[doc(hidden)] #[unsafe_destructor] impl<'self> Drop for RWlockReleaseRead<'self> { - fn finalize(&self) { + fn drop(&self) { unsafe { do task::unkillable { let state = &mut *self.lock.state.get(); @@ -726,7 +729,7 @@ struct RWlockReleaseDowngrade<'self> { #[doc(hidden)] #[unsafe_destructor] impl<'self> Drop for RWlockReleaseDowngrade<'self> { - fn finalize(&self) { + fn drop(&self) { unsafe { do task::unkillable { let writer_or_last_reader; @@ -769,12 +772,12 @@ fn RWlockReleaseDowngrade<'r>(lock: &'r RWlock) /// The "write permission" token used for rwlock.write_downgrade(). pub struct RWlockWriteMode<'self> { priv lock: &'self RWlock } #[unsafe_destructor] -impl<'self> Drop for RWlockWriteMode<'self> { fn finalize(&self) {} } +impl<'self> Drop for RWlockWriteMode<'self> { fn drop(&self) {} } /// The "read permission" token used for rwlock.write_downgrade(). pub struct RWlockReadMode<'self> { priv lock: &'self RWlock } #[unsafe_destructor] -impl<'self> Drop for RWlockReadMode<'self> { fn finalize(&self) {} } +impl<'self> Drop for RWlockReadMode<'self> { fn drop(&self) {} } impl<'self> RWlockWriteMode<'self> { /// Access the pre-downgrade rwlock in write mode. @@ -799,16 +802,14 @@ impl<'self> RWlockReadMode<'self> { #[cfg(test)] mod tests { - use core::prelude::*; use sync::*; - use core::cast; - use core::cell::Cell; - use core::comm; - use core::result; - use core::task; - use core::vec; + use std::cast; + use std::cell::Cell; + use std::comm; + use std::result; + use std::task; /************************************************************************ * Semaphore tests @@ -994,13 +995,13 @@ mod tests { } // wait until all children get in the mutex - for ports.each |port| { let _ = port.recv(); } + for ports.iter().advance |port| { let _ = port.recv(); } do m.lock_cond |cond| { let num_woken = cond.broadcast(); assert_eq!(num_woken, num_waiters); } // wait until all children wake up - for ports.each |port| { let _ = port.recv(); } + for ports.iter().advance |port| { let _ = port.recv(); } } #[test] fn test_mutex_cond_broadcast() { @@ -1085,7 +1086,7 @@ mod tests { } } } - for sibling_convos.each |p| { + for sibling_convos.iter().advance |p| { let _ = p.recv(); // wait for sibling to get in the mutex } do m2.lock { } @@ -1094,7 +1095,8 @@ mod tests { }; assert!(result.is_err()); // child task must have finished by the time try returns - for vec::each(p.recv()) |p| { p.recv(); } // wait on all its siblings + let r = p.recv(); + for r.iter().advance |p| { p.recv(); } // wait on all its siblings do m.lock_cond |cond| { let woken = cond.broadcast(); assert_eq!(woken, 0); @@ -1104,7 +1106,7 @@ mod tests { } impl Drop for SendOnFailure { - fn finalize(&self) { + fn drop(&self) { self.c.send(()); } } @@ -1180,12 +1182,12 @@ mod tests { Write => x.write(blk), Downgrade => do x.write_downgrade |mode| { - (&mode).write(blk); + do mode.write { blk() }; }, DowngradeRead => do x.write_downgrade |mode| { let mode = x.downgrade(mode); - (&mode).read(blk); + do mode.read { blk() }; }, } } @@ -1338,10 +1340,10 @@ mod tests { fn lock_cond(x: &RWlock, downgrade: bool, blk: &fn(c: &Condvar)) { if downgrade { do x.write_downgrade |mode| { - (&mode).write_cond(blk) + do mode.write_cond |c| { blk(c) } } } else { - x.write_cond(blk) + do x.write_cond |c| { blk(c) } } } let x = ~RWlock(); @@ -1361,13 +1363,13 @@ mod tests { } // wait until all children get in the mutex - for ports.each |port| { let _ = port.recv(); } + for ports.iter().advance |port| { let _ = port.recv(); } do lock_cond(x, dg2) |cond| { let num_woken = cond.broadcast(); assert_eq!(num_woken, num_waiters); } // wait until all children wake up - for ports.each |port| { let _ = port.recv(); } + for ports.iter().advance |port| { let _ = port.recv(); } } #[test] fn test_rwlock_cond_broadcast() { diff --git a/src/libextra/task_pool.rs b/src/libextra/task_pool.rs index b88bbff2a66..49d5dd93869 100644 --- a/src/libextra/task_pool.rs +++ b/src/libextra/task_pool.rs @@ -13,15 +13,14 @@ /// A task pool abstraction. Useful for achieving predictable CPU /// parallelism. -use core::prelude::*; -use core::comm::Chan; -use core::comm; -use core::task::SchedMode; -use core::task; -use core::vec; +use std::comm::Chan; +use std::comm; +use std::task::SchedMode; +use std::task; +use std::vec; -#[cfg(test)] use core::task::SingleThreaded; +#[cfg(test)] use std::task::SingleThreaded; enum Msg<T> { Execute(~fn(&T)), @@ -35,8 +34,8 @@ pub struct TaskPool<T> { #[unsafe_destructor] impl<T> Drop for TaskPool<T> { - fn finalize(&self) { - for self.channels.each |channel| { + fn drop(&self) { + for self.channels.iter().advance |channel| { channel.send(Quit); } } diff --git a/src/libextra/tempfile.rs b/src/libextra/tempfile.rs index 39dcee5eff3..f8948f41101 100644 --- a/src/libextra/tempfile.rs +++ b/src/libextra/tempfile.rs @@ -10,11 +10,10 @@ //! Temporary files and directories -use core::prelude::*; -use core::os; -use core::rand::RngUtil; -use core::rand; +use std::os; +use std::rand::RngUtil; +use std::rand; /// Attempts to make a temporary directory inside of `tmpdir` whose name will /// have the suffix `suffix`. If no directory can be created, None is returned. @@ -31,11 +30,10 @@ pub fn mkdtemp(tmpdir: &Path, suffix: &str) -> Option<Path> { #[cfg(test)] mod tests { - use core::prelude::*; use tempfile::mkdtemp; - use core::os; + use std::os; #[test] fn test_mkdtemp() { @@ -44,12 +42,12 @@ mod tests { assert!(p.to_str().ends_with("foobar")); } - // Ideally these would be in core::os but then core would need + // Ideally these would be in std::os but then core would need // to depend on std #[test] fn recursive_mkdir_rel() { - use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - use core::os; + use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; + use std::os; let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel"). expect("recursive_mkdir_rel"); @@ -67,8 +65,8 @@ mod tests { #[test] fn recursive_mkdir_dot() { - use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - use core::os; + use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; + use std::os; let dot = Path("."); assert!(os::mkdir_recursive(&dot, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); @@ -78,8 +76,8 @@ mod tests { #[test] fn recursive_mkdir_rel_2() { - use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - use core::os; + use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; + use std::os; let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel_2"). expect("recursive_mkdir_rel_2"); @@ -102,8 +100,8 @@ mod tests { // Ideally this would be in core, but needs mkdtemp #[test] pub fn test_rmdir_recursive_ok() { - use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - use core::os; + use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; + use std::os; let rwx = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; diff --git a/src/libextra/term.rs b/src/libextra/term.rs index 17d80ded47f..e21e5c5fb58 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -12,47 +12,49 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::io; -use core::os; +use std::io; -use terminfo::*; -use terminfo::searcher::open; -use terminfo::parser::compiled::parse; -use terminfo::parm::{expand, Number, Variables}; +#[cfg(not(target_os = "win32"))] use std::os; +#[cfg(not(target_os = "win32"))] use terminfo::*; +#[cfg(not(target_os = "win32"))] use terminfo::searcher::open; +#[cfg(not(target_os = "win32"))] use terminfo::parser::compiled::parse; +#[cfg(not(target_os = "win32"))] use terminfo::parm::{expand, Number, Variables}; // FIXME (#2807): Windows support. -pub static color_black: u8 = 0u8; -pub static color_red: u8 = 1u8; -pub static color_green: u8 = 2u8; -pub static color_yellow: u8 = 3u8; -pub static color_blue: u8 = 4u8; -pub static color_magenta: u8 = 5u8; -pub static color_cyan: u8 = 6u8; -pub static color_light_gray: u8 = 7u8; -pub static color_light_grey: u8 = 7u8; -pub static color_dark_gray: u8 = 8u8; -pub static color_dark_grey: u8 = 8u8; -pub static color_bright_red: u8 = 9u8; -pub static color_bright_green: u8 = 10u8; -pub static color_bright_yellow: u8 = 11u8; -pub static color_bright_blue: u8 = 12u8; -pub static color_bright_magenta: u8 = 13u8; -pub static color_bright_cyan: u8 = 14u8; -pub static color_bright_white: u8 = 15u8; +pub mod color { + pub type Color = u16; + + pub static black: Color = 0u16; + pub static red: Color = 1u16; + pub static green: Color = 2u16; + pub static yellow: Color = 3u16; + pub static blue: Color = 4u16; + pub static magenta: Color = 5u16; + pub static cyan: Color = 6u16; + pub static white: Color = 7u16; + + pub static bright_black: Color = 8u16; + pub static bright_red: Color = 9u16; + pub static bright_green: Color = 10u16; + pub static bright_yellow: Color = 11u16; + pub static bright_blue: Color = 12u16; + pub static bright_magenta: Color = 13u16; + pub static bright_cyan: Color = 14u16; + pub static bright_white: Color = 15u16; +} #[cfg(not(target_os = "win32"))] pub struct Terminal { - color_supported: bool, + num_colors: u16, priv out: @io::Writer, priv ti: ~TermInfo } #[cfg(target_os = "win32")] pub struct Terminal { - color_supported: bool, + num_colors: u16, priv out: @io::Writer, } @@ -66,66 +68,86 @@ impl Terminal { let entry = open(term.unwrap()); if entry.is_err() { - return Err(entry.get_err()); + return Err(entry.unwrap_err()); } - let ti = parse(entry.get(), false); + let ti = parse(entry.unwrap(), false); if ti.is_err() { - return Err(entry.get_err()); + return Err(ti.unwrap_err()); } - let mut inf = ti.get(); - let cs = *inf.numbers.find_or_insert(~"colors", 0) >= 16 - && inf.strings.find(&~"setaf").is_some() - && inf.strings.find_equiv(&("setab")).is_some(); + let inf = ti.unwrap(); + let nc = if inf.strings.find_equiv(&("setaf")).is_some() + && inf.strings.find_equiv(&("setab")).is_some() { + inf.numbers.find_equiv(&("colors")).map_consume_default(0, |&n| n) + } else { 0 }; - return Ok(Terminal {out: out, ti: inf, color_supported: cs}); + return Ok(Terminal {out: out, ti: inf, num_colors: nc}); } - pub fn fg(&self, color: u8) { - if self.color_supported { + /// Sets the foreground color to the given color. + /// + /// If the color is a bright color, but the terminal only supports 8 colors, + /// the corresponding normal color will be used instead. + pub fn fg(&self, color: color::Color) { + let color = self.dim_if_necessary(color); + if self.num_colors > color { let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(), [Number(color as int)], &mut Variables::new()); if s.is_ok() { - self.out.write(s.get()); + self.out.write(s.unwrap()); } else { - warn!(s.get_err()); + warn!("%s", s.unwrap_err()); } } } - pub fn bg(&self, color: u8) { - if self.color_supported { + /// Sets the background color to the given color. + /// + /// If the color is a bright color, but the terminal only supports 8 colors, + /// the corresponding normal color will be used instead. + pub fn bg(&self, color: color::Color) { + let color = self.dim_if_necessary(color); + if self.num_colors > color { let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(), [Number(color as int)], &mut Variables::new()); if s.is_ok() { - self.out.write(s.get()); + self.out.write(s.unwrap()); } else { - warn!(s.get_err()); + warn!("%s", s.unwrap_err()); } } } pub fn reset(&self) { - if self.color_supported { - let mut vars = Variables::new(); - let s = expand(*self.ti.strings.find_equiv(&("op")).unwrap(), [], &mut vars); - if s.is_ok() { - self.out.write(s.get()); - } else { - warn!(s.get_err()); - } + let mut vars = Variables::new(); + let s = do self.ti.strings.find_equiv(&("op")) + .map_consume_default(Err(~"can't find terminfo capability `op`")) |&op| { + expand(op, [], &mut vars) + }; + if s.is_ok() { + self.out.write(s.unwrap()); + } else if self.num_colors > 0 { + warn!("%s", s.unwrap_err()); + } else { + debug!("%s", s.unwrap_err()); } } + + priv fn dim_if_necessary(&self, color: color::Color) -> color::Color { + if color >= self.num_colors && color >= 8 && color < 16 { + color-8 + } else { color } + } } #[cfg(target_os = "win32")] impl Terminal { pub fn new(out: @io::Writer) -> Result<Terminal, ~str> { - return Ok(Terminal {out: out, color_supported: false}); + return Ok(Terminal {out: out, num_colors: 0}); } - pub fn fg(&self, color: u8) { + pub fn fg(&self, _color: color::Color) { } - pub fn bg(&self, color: u8) { + pub fn bg(&self, _color: color::Color) { } pub fn reset(&self) { diff --git a/src/libextra/terminfo/parm.rs b/src/libextra/terminfo/parm.rs index 11f0fc23be5..b7d21ea0ee3 100644 --- a/src/libextra/terminfo/parm.rs +++ b/src/libextra/terminfo/parm.rs @@ -10,9 +10,9 @@ //! Parameterized string expansion -use core::prelude::*; -use core::{char, int, vec}; -use core::iterator::IteratorUtil; +use std::{char, vec, util}; +use std::num::strconv::{SignNone,SignNeg,SignAll,int_to_str_bytes_common}; +use std::iterator::IteratorUtil; #[deriving(Eq)] enum States { @@ -23,13 +23,21 @@ enum States { PushParam, CharConstant, CharClose, - IntConstant, + IntConstant(int), + FormatPattern(Flags, FormatState), SeekIfElse(int), SeekIfElsePercent(int), SeekIfEnd(int), SeekIfEndPercent(int) } +#[deriving(Eq)] +enum FormatState { + FormatStateFlags, + FormatStateWidth, + FormatStatePrecision +} + /// Types of parameters a capability can use pub enum Param { String(~str), @@ -71,8 +79,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) let mut stack: ~[Param] = ~[]; - let mut intstate = ~[]; - // Copy parameters into a local vector for mutability let mut mparams = [Number(0), ..9]; for mparams.mut_iter().zip(params.iter()).advance |(dst, &src)| { @@ -100,26 +106,11 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) _ => return Err(~"a non-char was used with %c") } } else { return Err(~"stack is empty") }, - 's' => if stack.len() > 0 { - match stack.pop() { - String(s) => output.push_all(s.as_bytes()), - _ => return Err(~"a non-str was used with %s") - } - } else { return Err(~"stack is empty") }, - 'd' => if stack.len() > 0 { - match stack.pop() { - Number(x) => { - let s = x.to_str(); - output.push_all(s.as_bytes()) - } - _ => return Err(~"a non-number was used with %d") - } - } else { return Err(~"stack is empty") }, 'p' => state = PushParam, 'P' => state = SetVar, 'g' => state = GetVar, '\'' => state = CharConstant, - '{' => state = IntConstant, + '{' => state = IntConstant(0), 'l' => if stack.len() > 0 { match stack.pop() { String(s) => stack.push(Number(s.len() as int)), @@ -231,6 +222,30 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) (_, _) => return Err(~"first two params not numbers with %i") }, + // printf-style support for %doxXs + 'd'|'o'|'x'|'X'|'s' => if stack.len() > 0 { + let flags = Flags::new(); + let res = format(stack.pop(), FormatOp::from_char(cur), flags); + if res.is_err() { return res } + output.push_all(res.unwrap()) + } else { return Err(~"stack is empty") }, + ':'|'#'|' '|'.'|'0'..'9' => { + let mut flags = Flags::new(); + let mut fstate = FormatStateFlags; + match cur { + ':' => (), + '#' => flags.alternate = true, + ' ' => flags.space = true, + '.' => fstate = FormatStatePrecision, + '0'..'9' => { + flags.width = (cur - '0') as uint; + fstate = FormatStateWidth; + } + _ => util::unreachable() + } + state = FormatPattern(flags, fstate); + } + // conditionals '?' => (), 't' => if stack.len() > 0 { @@ -288,17 +303,61 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) return Err(~"malformed character constant"); } }, - IntConstant => { - if cur == '}' { - stack.push(match int::parse_bytes(intstate, 10) { - Some(n) => Number(n), - None => return Err(~"bad int constant") - }); - intstate.clear(); - state = Nothing; - } else { - intstate.push(cur as u8); - old_state = Nothing; + IntConstant(i) => { + match cur { + '}' => { + stack.push(Number(i)); + state = Nothing; + } + '0'..'9' => { + state = IntConstant(i*10 + ((cur - '0') as int)); + old_state = Nothing; + } + _ => return Err(~"bad int constant") + } + } + FormatPattern(ref mut flags, ref mut fstate) => { + old_state = Nothing; + match (*fstate, cur) { + (_,'d')|(_,'o')|(_,'x')|(_,'X')|(_,'s') => if stack.len() > 0 { + let res = format(stack.pop(), FormatOp::from_char(cur), *flags); + if res.is_err() { return res } + output.push_all(res.unwrap()); + old_state = state; // will cause state to go to Nothing + } else { return Err(~"stack is empty") }, + (FormatStateFlags,'#') => { + flags.alternate = true; + } + (FormatStateFlags,'-') => { + flags.left = true; + } + (FormatStateFlags,'+') => { + flags.sign = true; + } + (FormatStateFlags,' ') => { + flags.space = true; + } + (FormatStateFlags,'0'..'9') => { + flags.width = (cur - '0') as uint; + *fstate = FormatStateWidth; + } + (FormatStateFlags,'.') => { + *fstate = FormatStatePrecision; + } + (FormatStateWidth,'0'..'9') => { + let old = flags.width; + flags.width = flags.width * 10 + ((cur - '0') as uint); + if flags.width < old { return Err(~"format width overflow") } + } + (FormatStateWidth,'.') => { + *fstate = FormatStatePrecision; + } + (FormatStatePrecision,'0'..'9') => { + let old = flags.precision; + flags.precision = flags.precision * 10 + ((cur - '0') as uint); + if flags.precision < old { return Err(~"format precision overflow") } + } + _ => return Err(~"invalid format specifier") } } SeekIfElse(level) => { @@ -349,10 +408,153 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) Ok(output) } +#[deriving(Eq)] +priv struct Flags { + width: uint, + precision: uint, + alternate: bool, + left: bool, + sign: bool, + space: bool +} + +impl Flags { + priv fn new() -> Flags { + Flags{ width: 0, precision: 0, alternate: false, + left: false, sign: false, space: false } + } +} + +priv enum FormatOp { + FormatDigit, + FormatOctal, + FormatHex, + FormatHEX, + FormatString +} + +impl FormatOp { + priv fn from_char(c: char) -> FormatOp { + match c { + 'd' => FormatDigit, + 'o' => FormatOctal, + 'x' => FormatHex, + 'X' => FormatHEX, + 's' => FormatString, + _ => fail!("bad FormatOp char") + } + } + priv fn to_char(self) -> char { + match self { + FormatDigit => 'd', + FormatOctal => 'o', + FormatHex => 'x', + FormatHEX => 'X', + FormatString => 's' + } + } +} + +priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { + let mut s = match val { + Number(d) => { + match op { + FormatString => { + return Err(~"non-number on stack with %s") + } + _ => { + let radix = match op { + FormatDigit => 10, + FormatOctal => 8, + FormatHex|FormatHEX => 16, + FormatString => util::unreachable() + }; + let mut s = ~[]; + match op { + FormatDigit => { + let sign = if flags.sign { SignAll } else { SignNeg }; + do int_to_str_bytes_common(d, radix, sign) |c| { + s.push(c); + } + } + _ => { + do int_to_str_bytes_common(d as uint, radix, SignNone) |c| { + s.push(c); + } + } + }; + if flags.precision > s.len() { + let mut s_ = vec::with_capacity(flags.precision); + let n = flags.precision - s.len(); + s_.grow(n, &('0' as u8)); + s_.push_all_move(s); + s = s_; + } + assert!(!s.is_empty(), "string conversion produced empty result"); + match op { + FormatDigit => { + if flags.space && !(s[0] == '-' as u8 || s[0] == '+' as u8) { + s.unshift(' ' as u8); + } + } + FormatOctal => { + if flags.alternate && s[0] != '0' as u8 { + s.unshift('0' as u8); + } + } + FormatHex => { + if flags.alternate { + let s_ = util::replace(&mut s, ~['0' as u8, 'x' as u8]); + s.push_all_move(s_); + } + } + FormatHEX => { + s = s.into_ascii().to_upper().into_bytes(); + if flags.alternate { + let s_ = util::replace(&mut s, ~['0' as u8, 'X' as u8]); + s.push_all_move(s_); + } + } + FormatString => util::unreachable() + } + s + } + } + } + String(s) => { + match op { + FormatString => { + let mut s = s.as_bytes_with_null_consume(); + s.pop(); // remove the null + if flags.precision > 0 && flags.precision < s.len() { + s.truncate(flags.precision); + } + s + } + _ => { + return Err(fmt!("non-string on stack with %%%c", op.to_char())) + } + } + } + }; + if flags.width > s.len() { + let n = flags.width - s.len(); + if flags.left { + s.grow(n, &(' ' as u8)); + } else { + let mut s_ = vec::with_capacity(flags.width); + s_.grow(n, &(' ' as u8)); + s_.push_all_move(s); + s = s_; + } + } + Ok(s) +} + #[cfg(test)] mod test { use super::*; - use core::result::Ok; + use std::result::Ok; #[test] fn test_basic_setabf() { @@ -443,4 +645,20 @@ mod test { assert!(res.is_ok(), res.unwrap_err()); assert_eq!(res.unwrap(), bytes!("\\E[38;5;42m").to_owned()); } + + #[test] + fn test_format() { + let mut varstruct = Variables::new(); + let vars = &mut varstruct; + assert_eq!(expand(bytes!("%p1%s%p2%2s%p3%2s%p4%.2s"), + [String(~"foo"), String(~"foo"), String(~"f"), String(~"foo")], vars), + Ok(bytes!("foofoo ffo").to_owned())); + assert_eq!(expand(bytes!("%p1%:-4.2s"), [String(~"foo")], vars), + Ok(bytes!("fo ").to_owned())); + + assert_eq!(expand(bytes!("%p1%d%p1%.3d%p1%5d%p1%:+d"), [Number(1)], vars), + Ok(bytes!("1001 1+1").to_owned())); + assert_eq!(expand(bytes!("%p1%o%p1%#o%p2%6.4x%p2%#6.4X"), [Number(15), Number(27)], vars), + Ok(bytes!("17017 001b0X001B").to_owned())); + } } diff --git a/src/libextra/terminfo/parser/compiled.rs b/src/libextra/terminfo/parser/compiled.rs index 66649c62fca..063d26d1424 100644 --- a/src/libextra/terminfo/parser/compiled.rs +++ b/src/libextra/terminfo/parser/compiled.rs @@ -10,11 +10,10 @@ /// ncurses-compatible compiled terminfo format parsing (term(5)) -use core::prelude::*; -use core::{vec, int, str}; -use core::io::Reader; -use core::hashmap::HashMap; +use std::{vec, int, str}; +use std::io::Reader; +use std::hashmap::HashMap; use super::super::TermInfo; // These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable. @@ -271,7 +270,7 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { return Err(~"error: hit EOF before end of string table"); } - for string_offsets.eachi |i, v| { + for string_offsets.iter().enumerate().advance |(i, v)| { let offset = *v; if offset == 0xFFFF { // non-entry loop; @@ -292,12 +291,13 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { // Find the offset of the NUL we want to go to - let nulpos = vec::position_between(string_table, offset as uint, - string_table_bytes as uint, |&b| b == 0); + let nulpos = string_table.slice(offset as uint, string_table_bytes as uint) + .iter().position_(|&b| b == 0); match nulpos { - Some(x) => { + Some(len) => { string_map.insert(name.to_owned(), - string_table.slice(offset as uint, x).to_owned()) + string_table.slice(offset as uint, + offset as uint + len).to_owned()) }, None => { return Err(~"invalid file: missing NUL in string_table"); diff --git a/src/libextra/terminfo/searcher.rs b/src/libextra/terminfo/searcher.rs index f8251447572..15aeeb3e654 100644 --- a/src/libextra/terminfo/searcher.rs +++ b/src/libextra/terminfo/searcher.rs @@ -11,11 +11,10 @@ /// Implement ncurses-compatible database discovery /// Does not support hashed database, only filesystem! -use core::prelude::*; -use core::{os, str}; -use core::os::getenv; -use core::io::{file_reader, Reader}; -use path = core::path::Path; +use std::{os, str}; +use std::os::getenv; +use std::io::{file_reader, Reader}; +use path = std::path::Path; /// Return path to database entry for `term` pub fn get_dbpath_for_term(term: &str) -> Option<~path> { @@ -55,7 +54,7 @@ pub fn get_dbpath_for_term(term: &str) -> Option<~path> { }; // Look for the terminal in all of the search directories - for dirs_to_search.each |p| { + for dirs_to_search.iter().advance |p| { let newp = ~p.push_many(&[str::from_char(first_char), term.to_owned()]); if os::path_exists(p) && os::path_exists(newp) { return Some(newp); diff --git a/src/libextra/terminfo/terminfo.rs b/src/libextra/terminfo/terminfo.rs index 141a5b6bf7f..0e0231ad3f4 100644 --- a/src/libextra/terminfo/terminfo.rs +++ b/src/libextra/terminfo/terminfo.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::hashmap::HashMap; +use std::hashmap::HashMap; /// A parsed terminfo entry. pub struct TermInfo { diff --git a/src/libextra/test.rs b/src/libextra/test.rs index 64c6a822a86..f3051e08383 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -15,21 +15,26 @@ // simplest interface possible for representing and running tests // while providing a base that other test frameworks may build off of. -use core::prelude::*; use getopts; use sort; +use stats::Stats; use term; - -use core::comm::{stream, SharedChan}; -use core::either; -use core::io; -use core::option; -use core::result; -use core::task; -use core::to_str::ToStr; -use core::uint; -use core::vec; +use time::precise_time_ns; + +use std::comm::{stream, SharedChan}; +use std::either; +use std::io; +use std::num; +use std::option; +use std::rand::RngUtil; +use std::rand; +use std::result; +use std::task; +use std::to_str::ToStr; +use std::u64; +use std::uint; +use std::vec; // The name of a test. By convention this follows the rules for rust @@ -131,7 +136,7 @@ type OptRes = Either<TestOpts, ~str>; // Parses command line arguments into test options pub fn parse_opts(args: &[~str]) -> OptRes { - let args_ = vec::tail(args); + let args_ = args.tail(); let opts = ~[getopts::optflag("ignored"), getopts::optflag("test"), getopts::optflag("bench"), @@ -318,33 +323,33 @@ pub fn run_tests_console(opts: &TestOpts, } fn write_ok(out: @io::Writer, use_color: bool) { - write_pretty(out, "ok", term::color_green, use_color); + write_pretty(out, "ok", term::color::green, use_color); } fn write_failed(out: @io::Writer, use_color: bool) { - write_pretty(out, "FAILED", term::color_red, use_color); + write_pretty(out, "FAILED", term::color::red, use_color); } fn write_ignored(out: @io::Writer, use_color: bool) { - write_pretty(out, "ignored", term::color_yellow, use_color); + write_pretty(out, "ignored", term::color::yellow, use_color); } fn write_bench(out: @io::Writer, use_color: bool) { - write_pretty(out, "bench", term::color_cyan, use_color); + write_pretty(out, "bench", term::color::cyan, use_color); } fn write_pretty(out: @io::Writer, word: &str, - color: u8, + color: term::color::Color, use_color: bool) { let t = term::Terminal::new(out); match t { Ok(term) => { - if use_color && term.color_supported { + if use_color { term.fg(color); } out.write_str(word); - if use_color && term.color_supported { + if use_color { term.reset(); } }, @@ -361,7 +366,7 @@ fn print_failures(st: &ConsoleTestState) { failures.push(name.to_str()); } sort::tim_sort(failures); - for failures.each |name| { + for failures.iter().advance |name| { st.out.write_line(fmt!(" %s", name.to_str())); } } @@ -415,7 +420,7 @@ type MonitorMsg = (TestDesc, TestResult); fn run_tests(opts: &TestOpts, tests: ~[TestDescAndFn], - callback: @fn(e: TestEvent)) { + callback: &fn(e: TestEvent)) { let filtered_tests = filter_tests(opts, tests); let filtered_descs = filtered_tests.map(|t| copy t.desc); @@ -423,7 +428,7 @@ fn run_tests(opts: &TestOpts, callback(TeFiltered(filtered_descs)); let (filtered_tests, filtered_benchs) = - do vec::partition(filtered_tests) |e| { + do filtered_tests.partition |e| { match e.testfn { StaticTestFn(_) | DynTestFn(_) => true, StaticBenchFn(_) | DynBenchFn(_) => false @@ -436,7 +441,7 @@ fn run_tests(opts: &TestOpts, debug!("using %u test tasks", concurrency); let mut remaining = filtered_tests; - vec::reverse(remaining); + remaining.reverse(); let mut pending = 0; let (p, ch) = stream(); @@ -480,7 +485,7 @@ static sched_overcommit : uint = 1; static sched_overcommit : uint = 4u; fn get_concurrency() -> uint { - use core::rt; + use std::rt; let threads = rt::util::default_sched_threads(); if threads == 1 { 1 } else { threads * sched_overcommit } @@ -558,7 +563,7 @@ pub fn run_test(force_ignore: bool, fn run_test_inner(desc: TestDesc, monitor_ch: SharedChan<MonitorMsg>, testfn: ~fn()) { - let testfn_cell = ::core::cell::Cell::new(testfn); + let testfn_cell = ::std::cell::Cell::new(testfn); do task::spawn { let mut result_future = None; // task::future_result(builder); @@ -600,152 +605,143 @@ fn calc_result(desc: &TestDesc, task_succeeded: bool) -> TestResult { } } -pub mod bench { - use core::prelude::*; - - use core::num; - use core::rand::RngUtil; - use core::rand; - use core::u64; - use core::vec; - use stats::Stats; - use test::{BenchHarness, BenchSamples}; - use time::precise_time_ns; - - impl BenchHarness { - /// Callback for benchmark functions to run in their body. - pub fn iter(&mut self, inner:&fn()) { - self.ns_start = precise_time_ns(); - let k = self.iterations; - for u64::range(0, k) |_| { - inner(); - } - self.ns_end = precise_time_ns(); - } - - pub fn ns_elapsed(&mut self) -> u64 { - if self.ns_start == 0 || self.ns_end == 0 { - 0 - } else { - self.ns_end - self.ns_start - } +impl BenchHarness { + /// Callback for benchmark functions to run in their body. + pub fn iter(&mut self, inner:&fn()) { + self.ns_start = precise_time_ns(); + let k = self.iterations; + for u64::range(0, k) |_| { + inner(); } + self.ns_end = precise_time_ns(); + } - pub fn ns_per_iter(&mut self) -> u64 { - if self.iterations == 0 { - 0 - } else { - self.ns_elapsed() / self.iterations - } + pub fn ns_elapsed(&mut self) -> u64 { + if self.ns_start == 0 || self.ns_end == 0 { + 0 + } else { + self.ns_end - self.ns_start } + } - pub fn bench_n(&mut self, n: u64, f: &fn(&mut BenchHarness)) { - self.iterations = n; - debug!("running benchmark for %u iterations", - n as uint); - f(self); + pub fn ns_per_iter(&mut self) -> u64 { + if self.iterations == 0 { + 0 + } else { + self.ns_elapsed() / self.iterations } + } - // This is the Go benchmark algorithm. It produces a single - // datapoint and always tries to run for 1s. - pub fn go_bench(&mut self, f: &fn(&mut BenchHarness)) { - - // Rounds a number down to the nearest power of 10. - fn round_down_10(n: u64) -> u64 { - let mut n = n; - let mut res = 1; - while n > 10 { - n = n / 10; - res *= 10; - } - res - } + pub fn bench_n(&mut self, n: u64, f: &fn(&mut BenchHarness)) { + self.iterations = n; + debug!("running benchmark for %u iterations", + n as uint); + f(self); + } - // Rounds x up to a number of the form [1eX, 2eX, 5eX]. - fn round_up(n: u64) -> u64 { - let base = round_down_10(n); - if n < (2 * base) { - 2 * base - } else if n < (5 * base) { - 5 * base - } else { - 10 * base - } + // This is the Go benchmark algorithm. It produces a single + // datapoint and always tries to run for 1s. + pub fn go_bench(&mut self, f: &fn(&mut BenchHarness)) { + + // Rounds a number down to the nearest power of 10. + fn round_down_10(n: u64) -> u64 { + let mut n = n; + let mut res = 1; + while n > 10 { + n = n / 10; + res *= 10; } + res + } - // Initial bench run to get ballpark figure. - let mut n = 1_u64; - self.bench_n(n, f); - - while n < 1_000_000_000 && - self.ns_elapsed() < 1_000_000_000 { - let last = n; - - // Try to estimate iter count for 1s falling back to 1bn - // iterations if first run took < 1ns. - if self.ns_per_iter() == 0 { - n = 1_000_000_000; - } else { - n = 1_000_000_000 / self.ns_per_iter(); - } - - n = u64::max(u64::min(n+n/2, 100*last), last+1); - n = round_up(n); - self.bench_n(n, f); + // Rounds x up to a number of the form [1eX, 2eX, 5eX]. + fn round_up(n: u64) -> u64 { + let base = round_down_10(n); + if n < (2 * base) { + 2 * base + } else if n < (5 * base) { + 5 * base + } else { + 10 * base } } - // This is a more statistics-driven benchmark algorithm. - // It stops as quickly as 50ms, so long as the statistical - // properties are satisfactory. If those properties are - // not met, it may run as long as the Go algorithm. - pub fn auto_bench(&mut self, f: &fn(&mut BenchHarness)) -> ~[f64] { - - let mut rng = rand::rng(); - let mut magnitude = 10; - let mut prev_madp = 0.0; + // Initial bench run to get ballpark figure. + let mut n = 1_u64; + self.bench_n(n, |x| f(x)); - loop { - let n_samples = rng.gen_uint_range(50, 60); - let n_iter = rng.gen_uint_range(magnitude, - magnitude * 2); + while n < 1_000_000_000 && + self.ns_elapsed() < 1_000_000_000 { + let last = n; - let samples = do vec::from_fn(n_samples) |_| { - self.bench_n(n_iter as u64, f); - self.ns_per_iter() as f64 - }; + // Try to estimate iter count for 1s falling back to 1bn + // iterations if first run took < 1ns. + if self.ns_per_iter() == 0 { + n = 1_000_000_000; + } else { + n = 1_000_000_000 / self.ns_per_iter(); + } - // Eliminate outliers - let med = samples.median(); - let mad = samples.median_abs_dev(); - let samples = do vec::filter(samples) |f| { - num::abs(*f - med) <= 3.0 * mad - }; + n = u64::max(u64::min(n+n/2, 100*last), last+1); + n = round_up(n); + self.bench_n(n, |x| f(x)); + } + } - debug!("%u samples, median %f, MAD=%f, %u survived filter", - n_samples, med as float, mad as float, - samples.len()); - - if samples.len() != 0 { - // If we have _any_ cluster of signal... - let curr_madp = samples.median_abs_dev_pct(); - if self.ns_elapsed() > 1_000_000 && - (curr_madp < 1.0 || - num::abs(curr_madp - prev_madp) < 0.1) { - return samples; - } - prev_madp = curr_madp; - - if n_iter > 20_000_000 || - self.ns_elapsed() > 20_000_000 { - return samples; - } + // This is a more statistics-driven benchmark algorithm. + // It stops as quickly as 50ms, so long as the statistical + // properties are satisfactory. If those properties are + // not met, it may run as long as the Go algorithm. + pub fn auto_bench(&mut self, f: &fn(&mut BenchHarness)) -> ~[f64] { + + let mut rng = rand::rng(); + let mut magnitude = 10; + let mut prev_madp = 0.0; + + loop { + let n_samples = rng.gen_uint_range(50, 60); + let n_iter = rng.gen_uint_range(magnitude, + magnitude * 2); + + let samples = do vec::from_fn(n_samples) |_| { + self.bench_n(n_iter as u64, |x| f(x)); + self.ns_per_iter() as f64 + }; + + // Eliminate outliers + let med = samples.median(); + let mad = samples.median_abs_dev(); + let samples = do vec::filter(samples) |f| { + num::abs(*f - med) <= 3.0 * mad + }; + + debug!("%u samples, median %f, MAD=%f, %u survived filter", + n_samples, med as float, mad as float, + samples.len()); + + if samples.len() != 0 { + // If we have _any_ cluster of signal... + let curr_madp = samples.median_abs_dev_pct(); + if self.ns_elapsed() > 1_000_000 && + (curr_madp < 1.0 || + num::abs(curr_madp - prev_madp) < 0.1) { + return samples; } + prev_madp = curr_madp; - magnitude *= 2; + if n_iter > 20_000_000 || + self.ns_elapsed() > 20_000_000 { + return samples; + } } + + magnitude *= 2; } } +} + +pub mod bench { + use test::{BenchHarness, BenchSamples}; pub fn benchmark(f: &fn(&mut BenchHarness)) -> BenchSamples { @@ -775,10 +771,10 @@ mod tests { StaticTestName, DynTestName, DynTestFn}; use test::{TestOpts, run_test}; - use core::either; - use core::comm::{stream, SharedChan}; - use core::option; - use core::vec; + use std::either; + use std::comm::{stream, SharedChan}; + use std::option; + use std::vec; #[test] pub fn do_not_run_ignored_tests() { @@ -938,7 +934,7 @@ mod tests { { fn testfn() { } let mut tests = ~[]; - for names.each |name| { + for names.iter().advance |name| { let test = TestDescAndFn { desc: TestDesc { name: DynTestName(copy *name), @@ -964,7 +960,7 @@ mod tests { let pairs = vec::zip(expected, filtered); - for pairs.each |p| { + for pairs.iter().advance |p| { match *p { (ref a, ref b) => { assert!(*a == b.desc.name.to_str()); diff --git a/src/libextra/time.rs b/src/libextra/time.rs index 005238a564e..e1f42934b39 100644 --- a/src/libextra/time.rs +++ b/src/libextra/time.rs @@ -10,12 +10,11 @@ #[allow(missing_doc)]; -use core::prelude::*; -use core::i32; -use core::int; -use core::io; -use core::str; +use std::i32; +use std::int; +use std::io; +use std::str; static NSEC_PER_SEC: i32 = 1_000_000_000_i32; @@ -849,7 +848,7 @@ priv fn do_strftime(format: &str, tm: &Tm) -> ~str { do io::with_str_reader(format) |rdr| { while !rdr.eof() { match rdr.read_char() { - '%' => buf += parse_type(rdr.read_char(), tm), + '%' => buf.push_str(parse_type(rdr.read_char(), tm)), ch => buf.push_char(ch) } } @@ -862,11 +861,11 @@ priv fn do_strftime(format: &str, tm: &Tm) -> ~str { mod tests { use time::*; - use core::float; - use core::os; - use core::result; - use core::result::{Err, Ok}; - use core::str; + use std::float; + use std::os; + use std::result; + use std::result::{Err, Ok}; + use std::str; fn test_get_time() { static some_recent_date: i64 = 1325376000i64; // 2012-01-01T00:00:00Z @@ -1033,7 +1032,7 @@ mod tests { } } - for [ + let days = [ ~"Sunday", ~"Monday", ~"Tuesday", @@ -1041,11 +1040,12 @@ mod tests { ~"Thursday", ~"Friday", ~"Saturday" - ].each |day| { + ]; + for days.iter().advance |day| { assert!(test(*day, "%A")); } - for [ + let days = [ ~"Sun", ~"Mon", ~"Tue", @@ -1053,11 +1053,12 @@ mod tests { ~"Thu", ~"Fri", ~"Sat" - ].each |day| { + ]; + for days.iter().advance |day| { assert!(test(*day, "%a")); } - for [ + let months = [ ~"January", ~"February", ~"March", @@ -1070,11 +1071,12 @@ mod tests { ~"October", ~"November", ~"December" - ].each |day| { + ]; + for months.iter().advance |day| { assert!(test(*day, "%B")); } - for [ + let months = [ ~"Jan", ~"Feb", ~"Mar", @@ -1087,7 +1089,8 @@ mod tests { ~"Oct", ~"Nov", ~"Dec" - ].each |day| { + ]; + for months.iter().advance |day| { assert!(test(*day, "%b")); } @@ -1138,6 +1141,9 @@ mod tests { assert!(result::unwrap(strptime("-0800", "%z")).tm_gmtoff == 0); assert!(test("%", "%%")); + + // Test for #7256 + assert_eq!(strptime("360", "%Y-%m-%d"), Err(~"Invalid year")) } fn test_ctime() { diff --git a/src/libextra/timer.rs b/src/libextra/timer.rs index 7a4ad34b508..d957ac43801 100644 --- a/src/libextra/timer.rs +++ b/src/libextra/timer.rs @@ -10,18 +10,17 @@ //! Utilities that leverage libuv's `uv_timer_*` API -use core::prelude::*; use uv; use uv::iotask; use uv::iotask::IoTask; -use core::cast::transmute; -use core::cast; -use core::comm::{stream, Chan, SharedChan, Port, select2i}; -use core::either; -use core::libc::c_void; -use core::libc; +use std::cast::transmute; +use std::cast; +use std::comm::{stream, Chan, SharedChan, Port, select2i}; +use std::either; +use std::libc::c_void; +use std::libc; /** * Wait for timeout period then send provided value over a channel @@ -39,7 +38,7 @@ use core::libc; * * ch - a channel of type T to send a `val` on * * val - a value of type T to send over the provided `ch` */ -pub fn delayed_send<T:Owned>(iotask: &IoTask, +pub fn delayed_send<T:Send>(iotask: &IoTask, msecs: uint, ch: &Chan<T>, val: T) { @@ -111,7 +110,7 @@ pub fn sleep(iotask: &IoTask, msecs: uint) { * * * `iotask' - `uv::iotask` that the tcp request will run on * * msecs - an mount of time, in milliseconds, to wait to receive - * * wait_port - a `core::comm::port<T>` to receive on + * * wait_port - a `std::comm::port<T>` to receive on * * # Returns * @@ -119,11 +118,12 @@ pub fn sleep(iotask: &IoTask, msecs: uint) { * on the provided port in the allotted timeout period, then the result will * be a `Some(T)`. If not, then `None` will be returned. */ -pub fn recv_timeout<T:Copy + Owned>(iotask: &IoTask, +pub fn recv_timeout<T:Copy + Send>(iotask: &IoTask, msecs: uint, wait_po: &Port<T>) -> Option<T> { - let mut (timeout_po, timeout_ch) = stream::<()>(); + let (timeout_po, timeout_ch) = stream::<()>(); + let mut timeout_po = timeout_po; delayed_send(iotask, msecs, &timeout_ch, ()); // XXX: Workaround due to ports and channels not being &mut. They should @@ -175,16 +175,15 @@ extern fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) { #[cfg(test)] mod test { - use core::prelude::*; use timer::*; use uv; - use core::cell::Cell; - use core::pipes::{stream, SharedChan}; - use core::rand::RngUtil; - use core::rand; - use core::task; + use std::cell::Cell; + use std::pipes::{stream, SharedChan}; + use std::rand::RngUtil; + use std::rand; + use std::task; #[test] fn test_gl_timer_simple_sleep_test() { @@ -217,12 +216,12 @@ mod test { for repeat.times { let ch = ch.clone(); - for spec.each |spec| { + for spec.iter().advance |spec| { let (times, maxms) = *spec; let ch = ch.clone(); let hl_loop_clone = hl_loop.clone(); do task::spawn { - use core::rand::*; + use std::rand::*; let mut rng = rng(); for times.times { sleep(&hl_loop_clone, rng.next() as uint % maxms); diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index f857581c17d..5e898f8e59d 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -12,10 +12,9 @@ //! trees. The only requirement for the types is that the key implements //! `TotalOrd`. -use core::prelude::*; -use core::uint; -use core::util::{swap, replace}; +use std::uint; +use std::util::{swap, replace}; // This is implemented as an AA tree, which is a simplified variation of // a red-black tree where red (horizontal) nodes can only be added @@ -87,10 +86,10 @@ impl<K: Ord + TotalOrd, V> Ord for TreeMap<K, V> { impl<K: TotalOrd, V> Container for TreeMap<K, V> { /// Return the number of elements in the map - fn len(&const self) -> uint { self.length } + fn len(&self) -> uint { self.length } /// Return true if the map contains no elements - fn is_empty(&const self) -> bool { self.root.is_none() } + fn is_empty(&self) -> bool { self.root.is_none() } } impl<K: TotalOrd, V> Mutable for TreeMap<K, V> { @@ -107,26 +106,6 @@ impl<K: TotalOrd, V> Map<K, V> for TreeMap<K, V> { self.find(key).is_some() } - /// Visit all key-value pairs in order - fn each<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) -> bool { - each(&self.root, f) - } - - /// Visit all keys in order - fn each_key(&self, f: &fn(&K) -> bool) -> bool { - self.each(|k, _| f(k)) - } - - /// Visit all values in order - fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) -> bool { - self.each(|_, v| f(v)) - } - - /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) -> bool { - mutate_values(&mut self.root, f) - } - /// Return a reference to the value corresponding to the key fn find<'a>(&'a self, key: &K) -> Option<&'a V> { let mut current: &'a Option<~TreeNode<K, V>> = &self.root; @@ -184,6 +163,21 @@ impl<K: TotalOrd, V> TreeMap<K, V> { /// Create an empty TreeMap pub fn new() -> TreeMap<K, V> { TreeMap{root: None, length: 0} } + /// Visit all keys in order + pub fn each_key(&self, f: &fn(&K) -> bool) -> bool { + self.iter().advance(|(k, _)| f(k)) + } + + /// Visit all values in order + pub fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) -> bool { + self.iter().advance(|(_, v)| f(v)) + } + + /// Iterate over the map and mutate the contained values + pub fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) -> bool { + mutate_values(&mut self.root, f) + } + /// Visit all key-value pairs in reverse order pub fn each_reverse<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) -> bool { each_reverse(&self.root, f) @@ -249,22 +243,6 @@ pub struct TreeSet<T> { priv map: TreeMap<T, ()> } -impl<T: TotalOrd> BaseIter<T> for TreeSet<T> { - /// Visit all values in order - #[inline] - fn each(&self, f: &fn(&T) -> bool) -> bool { self.map.each_key(f) } - #[inline] - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - -impl<T: TotalOrd> ReverseIter<T> for TreeSet<T> { - /// Visit all values in reverse order - #[inline] - fn each_reverse(&self, f: &fn(&T) -> bool) -> bool { - self.map.each_key_reverse(f) - } -} - impl<T: Eq + TotalOrd> Eq for TreeSet<T> { #[inline] fn eq(&self, other: &TreeSet<T>) -> bool { self.map == other.map } @@ -286,11 +264,11 @@ impl<T: Ord + TotalOrd> Ord for TreeSet<T> { impl<T: TotalOrd> Container for TreeSet<T> { /// Return the number of elements in the set #[inline] - fn len(&const self) -> uint { self.map.len() } + fn len(&self) -> uint { self.map.len() } /// Return true if the set contains no elements #[inline] - fn is_empty(&const self) -> bool { self.map.is_empty() } + fn is_empty(&self) -> bool { self.map.is_empty() } } impl<T: TotalOrd> Mutable for TreeSet<T> { @@ -499,6 +477,12 @@ impl<T: TotalOrd> TreeSet<T> { pub fn iter<'a>(&'a self) -> TreeSetIterator<'a, T> { TreeSetIterator{iter: self.map.iter()} } + + /// Visit all values in reverse order + #[inline] + pub fn each_reverse(&self, f: &fn(&T) -> bool) -> bool { + self.map.each_key_reverse(f) + } } /// Lazy forward iterator over a set @@ -526,14 +510,14 @@ impl<K: TotalOrd, V> TreeNode<K, V> { fn each<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>, f: &fn(&'r K, &'r V) -> bool) -> bool { - node.iter().advance(|x| each(&x.left, f) && f(&x.key, &x.value) && - each(&x.right, f)) + node.iter().advance(|x| each(&x.left, |k,v| f(k,v)) && f(&x.key, &x.value) && + each(&x.right, |k,v| f(k,v))) } fn each_reverse<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>, f: &fn(&'r K, &'r V) -> bool) -> bool { - node.iter().advance(|x| each_reverse(&x.right, f) && f(&x.key, &x.value) && - each_reverse(&x.left, f)) + node.iter().advance(|x| each_reverse(&x.right, |k,v| f(k,v)) && f(&x.key, &x.value) && + each_reverse(&x.left, |k,v| f(k,v))) } fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode<K, V>>, @@ -542,9 +526,9 @@ fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode<K, V>>, match *node { Some(~TreeNode{key: ref key, value: ref mut value, left: ref mut left, right: ref mut right, _}) => { - if !mutate_values(left, f) { return false } + if !mutate_values(left, |k,v| f(k,v)) { return false } if !f(key, value) { return false } - if !mutate_values(right, f) { return false } + if !mutate_values(right, |k,v| f(k,v)) { return false } } None => return false } @@ -704,13 +688,11 @@ fn remove<K: TotalOrd, V>(node: &mut Option<~TreeNode<K, V>>, #[cfg(test)] mod test_treemap { - use core::prelude::*; use super::*; - use core::rand::RngUtil; - use core::rand; - use core::vec; + use std::rand::RngUtil; + use std::rand; #[test] fn find_empty() { @@ -781,13 +763,13 @@ mod test_treemap { fn check_equal<K: Eq + TotalOrd, V: Eq>(ctrl: &[(K, V)], map: &TreeMap<K, V>) { assert_eq!(ctrl.is_empty(), map.is_empty()); - for ctrl.each |x| { + for ctrl.iter().advance |x| { let &(k, v) = x; assert!(map.find(&k).unwrap() == &v) } - for map.each |map_k, map_v| { + for map.iter().advance |(map_k, map_v)| { let mut found = false; - for ctrl.each |x| { + for ctrl.iter().advance |x| { let &(ctrl_k, ctrl_v) = x; if *map_k == ctrl_k { assert!(*map_v == ctrl_v); @@ -853,7 +835,7 @@ mod test_treemap { for 90.times { let k = rng.gen(); let v = rng.gen(); - if !ctrl.contains(&(k, v)) { + if !ctrl.iter().any_(|x| x == &(k, v)) { assert!(map.insert(k, v)); ctrl.push((k, v)); check_structure(&map); @@ -863,7 +845,7 @@ mod test_treemap { for 30.times { let r = rng.gen_uint_range(0, ctrl.len()); - let (key, _) = vec::remove(&mut ctrl, r); + let (key, _) = ctrl.remove(r); assert!(map.remove(&key)); check_structure(&map); check_equal(ctrl, &map); @@ -891,7 +873,7 @@ mod test_treemap { } #[test] - fn test_each() { + fn test_iterator() { let mut m = TreeMap::new(); assert!(m.insert(3, 6)); @@ -901,7 +883,7 @@ mod test_treemap { assert!(m.insert(1, 2)); let mut n = 0; - for m.each |k, v| { + for m.iter().advance |(k, v)| { assert_eq!(*k, n); assert_eq!(*v, n * 2); n += 1; @@ -1026,7 +1008,6 @@ mod test_treemap { #[cfg(test)] mod test_set { - use core::prelude::*; use super::*; @@ -1096,7 +1077,7 @@ mod test_set { } #[test] - fn test_each() { + fn test_iterator() { let mut m = TreeSet::new(); assert!(m.insert(3)); @@ -1106,7 +1087,7 @@ mod test_set { assert!(m.insert(1)); let mut n = 0; - for m.each |x| { + for m.iter().advance |x| { println(fmt!("%?", x)); assert_eq!(*x, n); n += 1 @@ -1135,8 +1116,8 @@ mod test_set { let mut set_a = TreeSet::new(); let mut set_b = TreeSet::new(); - for a.each |x| { assert!(set_a.insert(*x)) } - for b.each |y| { assert!(set_b.insert(*y)) } + for a.iter().advance |x| { assert!(set_a.insert(*x)) } + for b.iter().advance |y| { assert!(set_b.insert(*y)) } let mut i = 0; for f(&set_a, &set_b) |x| { diff --git a/src/libextra/uv_global_loop.rs b/src/libextra/uv_global_loop.rs index 286863bef64..5501d73ac86 100644 --- a/src/libextra/uv_global_loop.rs +++ b/src/libextra/uv_global_loop.rs @@ -10,16 +10,15 @@ //! A process-wide libuv event loop for library use. -use core::prelude::*; use iotask = uv_iotask; use uv_iotask::{IoTask, spawn_iotask}; -use core::comm::Chan; -use core::option::{Some, None}; -use core::task::task; -use core::unstable::global::{global_data_clone_create, global_data_clone}; -use core::unstable::weak_task::weaken_task; +use std::comm::Chan; +use std::option::{Some, None}; +use std::task::task; +use std::unstable::global::{global_data_clone_create, global_data_clone}; +use std::unstable::weak_task::weaken_task; /** * Race-free helper to get access to a global task where a libuv @@ -126,11 +125,11 @@ mod test { use uv::ll; use uv_iotask::IoTask; - use core::libc; - use core::task; - use core::cast::transmute; - use core::libc::c_void; - use core::comm::{stream, SharedChan, Chan}; + use std::libc; + use std::task; + use std::cast::transmute; + use std::libc::c_void; + use std::comm::{stream, SharedChan, Chan}; extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) { unsafe { @@ -150,9 +149,7 @@ mod test { let hl_loop = &get_gl(); do iotask::interact(hl_loop) |_loop_ptr| { debug!(~"closing timer"); - unsafe { - ll::close(timer_ptr, simple_timer_close_cb); - } + ll::close(timer_ptr, simple_timer_close_cb); debug!(~"about to deref exit_ch_ptr"); debug!(~"after msg sent on deref'd exit_ch"); }; @@ -169,24 +166,22 @@ mod test { let timer_handle = ll::timer_t(); let timer_ptr: *ll::uv_timer_t = &timer_handle; do iotask::interact(iotask) |loop_ptr| { - unsafe { - debug!(~"user code inside interact loop!!!"); - let init_status = ll::timer_init(loop_ptr, timer_ptr); - if(init_status == 0i32) { - ll::set_data_for_uv_handle( - timer_ptr as *libc::c_void, - exit_ch_ptr); - let start_status = ll::timer_start(timer_ptr, - simple_timer_cb, - 1u, 0u); - if(start_status != 0i32) { - fail!("failure on ll::timer_start()"); - } - } - else { - fail!("failure on ll::timer_init()"); + debug!(~"user code inside interact loop!!!"); + let init_status = ll::timer_init(loop_ptr, timer_ptr); + if(init_status == 0i32) { + ll::set_data_for_uv_handle( + timer_ptr as *libc::c_void, + exit_ch_ptr); + let start_status = ll::timer_start(timer_ptr, + simple_timer_cb, + 1u, 0u); + if(start_status != 0i32) { + fail!("failure on ll::timer_start()"); } } + else { + fail!("failure on ll::timer_init()"); + } }; exit_po.recv(); debug!( diff --git a/src/libextra/uv_iotask.rs b/src/libextra/uv_iotask.rs index 817dfa28aee..0a564045d32 100644 --- a/src/libextra/uv_iotask.rs +++ b/src/libextra/uv_iotask.rs @@ -17,14 +17,13 @@ #[allow(missing_doc)]; -use core::prelude::*; use ll = uv_ll; -use core::comm::{stream, Port, Chan, SharedChan}; -use core::libc::c_void; -use core::libc; -use core::task; +use std::comm::{stream, Port, Chan, SharedChan}; +use std::libc::c_void; +use std::libc; +use std::task; /// Used to abstract-away direct interaction with a libuv loop. pub struct IoTask { @@ -226,7 +225,7 @@ struct AhData { #[cfg(test)] fn impl_uv_iotask_async(iotask: &IoTask) { - use core::ptr; + use std::ptr; let async_handle = ll::async_t(); let ah_ptr: *ll::uv_async_t = &async_handle; diff --git a/src/libextra/uv_ll.rs b/src/libextra/uv_ll.rs index 744f4555d5c..db960f334fd 100644 --- a/src/libextra/uv_ll.rs +++ b/src/libextra/uv_ll.rs @@ -33,14 +33,13 @@ #[allow(non_camel_case_types)]; // C types #[allow(missing_doc)]; -use core::prelude::*; -use core::libc::{c_void, size_t}; -use core::libc; -use core::ptr::to_unsafe_ptr; -use core::ptr; -use core::str; -use core::vec; +use std::libc::{c_void, size_t}; +use std::libc; +use std::ptr::to_unsafe_ptr; +use std::ptr; +use std::str; +use std::vec; pub type uv_handle_t = c_void; pub type uv_loop_t = c_void; @@ -362,7 +361,7 @@ pub struct uv_getaddrinfo_t { pub mod uv_ll_struct_stubgen { - use core::ptr; + use std::ptr; use super::{ uv_async_t, @@ -1228,16 +1227,15 @@ pub unsafe fn addrinfo_as_sockaddr_in6(input: *addrinfo) -> *sockaddr_in6 { #[cfg(test)] mod test { - use core::prelude::*; use super::*; - use core::comm::{SharedChan, stream, GenericChan, GenericPort}; - use core::libc; - use core::str; - use core::sys; - use core::task; - use core::vec; + use std::comm::{SharedChan, stream, GenericChan, GenericPort}; + use std::libc; + use std::str; + use std::sys; + use std::task; + use std::vec; enum tcp_read_data { tcp_read_eof, @@ -1767,9 +1765,7 @@ mod test { mod impl64 { #[test] fn test_uv_ll_tcp_server_and_request() { - unsafe { - super::super::impl_uv_tcp_server_and_request(); - } + super::super::impl_uv_tcp_server_and_request(); } } #[cfg(target_arch="x86")] diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 12a26606f36..503bd05b733 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -10,24 +10,24 @@ #[allow(missing_doc)]; -use core::prelude::*; +use digest::DigestUtil; use json; -use sha1; +use sha1::Sha1; use serialize::{Encoder, Encodable, Decoder, Decodable}; use sort; -use core::cell::Cell; -use core::cmp; -use core::comm::{PortOne, oneshot, send_one, recv_one}; -use core::either::{Either, Left, Right}; -use core::hashmap::HashMap; -use core::io; -use core::result; -use core::run; -use core::task; -use core::to_bytes; -use core::util::replace; +use std::cell::Cell; +use std::cmp; +use std::comm::{PortOne, oneshot, send_one, recv_one}; +use std::either::{Either, Left, Right}; +use std::hashmap::HashMap; +use std::io; +use std::result; +use std::run; +use std::task; +use std::to_bytes; +use std::util::replace; /** * @@ -106,7 +106,7 @@ struct WorkKey { impl to_bytes::IterBytes for WorkKey { #[inline] fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.kind.iter_bytes(lsb0, f) && self.name.iter_bytes(lsb0, f) + self.kind.iter_bytes(lsb0, |b| f(b)) && self.name.iter_bytes(lsb0, |b| f(b)) } } @@ -145,7 +145,7 @@ impl WorkMap { impl<S:Encoder> Encodable<S> for WorkMap { fn encode(&self, s: &mut S) { let mut d = ~[]; - for self.each |k, v| { + for self.iter().advance |(k, v)| { d.push((copy *k, copy *v)) } sort::tim_sort(d); @@ -157,7 +157,7 @@ impl<D:Decoder> Decodable<D> for WorkMap { fn decode(d: &mut D) -> WorkMap { let v : ~[(WorkKey,~str)] = Decodable::decode(d); let mut w = WorkMap::new(); - for v.each |&(k, v)| { + for v.iter().advance |&(k, v)| { w.insert(copy k, copy v); } w @@ -248,16 +248,16 @@ fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T { } fn digest<T:Encodable<json::Encoder>>(t: &T) -> ~str { - let mut sha = sha1::sha1(); - sha.input_str(json_encode(t)); - sha.result_str() + let mut sha = ~Sha1::new(); + (*sha).input_str(json_encode(t)); + (*sha).result_str() } fn digest_file(path: &Path) -> ~str { - let mut sha = sha1::sha1(); + let mut sha = ~Sha1::new(); let s = io::read_whole_file_str(path); - sha.input_str(*s.get_ref()); - sha.result_str() + (*sha).input_str(*s.get_ref()); + (*sha).result_str() } impl Context { @@ -271,7 +271,7 @@ impl Context { } } - pub fn prep<T:Owned + + pub fn prep<T:Send + Encodable<json::Encoder> + Decodable<json::Decoder>>(@self, // FIXME(#5121) fn_name:&str, @@ -291,7 +291,7 @@ trait TPrep { fn declare_input(&mut self, kind:&str, name:&str, val:&str); fn is_fresh(&self, cat:&str, kind:&str, name:&str, val:&str) -> bool; fn all_fresh(&self, cat:&str, map:&WorkMap) -> bool; - fn exec<T:Owned + + fn exec<T:Send + Encodable<json::Encoder> + Decodable<json::Decoder>>( // FIXME(#5121) &self, blk: ~fn(&Exec) -> T) -> Work<T>; @@ -319,7 +319,7 @@ impl TPrep for Prep { } fn all_fresh(&self, cat: &str, map: &WorkMap) -> bool { - for map.each |k, v| { + for map.iter().advance |(k, v)| { if ! self.is_fresh(cat, k.kind, k.name, *v) { return false; } @@ -327,7 +327,7 @@ impl TPrep for Prep { return true; } - fn exec<T:Owned + + fn exec<T:Send + Encodable<json::Encoder> + Decodable<json::Decoder>>( // FIXME(#5121) &self, blk: ~fn(&Exec) -> T) -> Work<T> { @@ -364,7 +364,7 @@ impl TPrep for Prep { } } -impl<T:Owned + +impl<T:Send + Encodable<json::Encoder> + Decodable<json::Decoder>> Work<T> { // FIXME(#5121) pub fn new(p: @mut Prep, e: Either<T,PortOne<(Exec,T)>>) -> Work<T> { @@ -373,7 +373,7 @@ impl<T:Owned + } // FIXME (#3724): movable self. This should be in impl Work. -fn unwrap<T:Owned + +fn unwrap<T:Send + Encodable<json::Encoder> + Decodable<json::Decoder>>( // FIXME(#5121) w: Work<T>) -> T { @@ -402,7 +402,7 @@ fn unwrap<T:Owned + //#[test] fn test() { - use core::io::WriterUtil; + use std::io::WriterUtil; let db = @mut Database { db_filename: Path("db.json"), db_cache: HashMap::new(), diff --git a/src/librust/rust.rc b/src/librust/rust.rs index 9d8f1c1a091..30b980a2f85 100644 --- a/src/librust/rust.rc +++ b/src/librust/rust.rs @@ -13,35 +13,22 @@ // FIXME #2238 Make run only accept source that emits an executable #[link(name = "rust", - vers = "0.7-pre", + vers = "0.7", uuid = "4a24da33-5cc8-4037-9352-2cbe9bd9d27c", url = "https://github.com/mozilla/rust/tree/master/src/rust")]; #[license = "MIT/ASL2"]; #[crate_type = "lib"]; -#[no_std]; - -extern mod core(name = "std"); - extern mod rustpkg; extern mod rustdoc; extern mod rusti; extern mod rustc; -use core::prelude::*; - -use core::io; -use core::os; -use core::run; -use core::libc::exit; - -// For bootstrapping. -mod std { - pub use core::os; - pub use core::str; - pub use core::unstable; -} +use std::io; +use std::os; +use std::run; +use std::libc::exit; enum ValidUsage { Valid(int), Invalid @@ -57,13 +44,13 @@ impl ValidUsage { } enum Action<'self> { - Call(&'self fn(args: &[~str]) -> ValidUsage), - CallMain(&'static str, &'self fn()), + Call(&'self fn:Copy(args: &[~str]) -> ValidUsage), + CallMain(&'static str, &'self fn:Copy()), } enum UsageSource<'self> { UsgStr(&'self str), - UsgCall(&'self fn()), + UsgCall(&'self fn:Copy()), } struct Command<'self> { @@ -135,9 +122,9 @@ fn rustc_help() { } fn find_cmd(command_string: &str) -> Option<Command> { - do commands.find |command| { + do commands.iter().find_ |command| { command.cmd == command_string - } + }.map_consume(|x| copy *x) } fn cmd_help(args: &[~str]) -> ValidUsage { @@ -222,7 +209,7 @@ fn usage() { \n" ); - for commands.each |command| { + for commands.iter().advance |command| { let padding = " ".repeat(indent - command.cmd.len()); io::println(fmt!(" %s%s%s", command.cmd, padding, command.usage_line)); @@ -238,6 +225,12 @@ fn usage() { pub fn main() { let os_args = os::args(); + + if (os_args.len() > 1 && (os_args[1] == ~"-v" || os_args[1] == ~"--version")) { + rustc::version(os_args[0]); + unsafe { exit(0); } + } + let args = os_args.tail(); if !args.is_empty() { diff --git a/src/librustc/back/abi.rs b/src/librustc/back/abi.rs index e722e1a33c6..05b6e90c682 100644 --- a/src/librustc/back/abi.rs +++ b/src/librustc/back/abi.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - - - pub static rc_base_field_refcnt: uint = 0u; pub static task_field_refcnt: uint = 0u; @@ -49,20 +46,16 @@ pub static tydesc_field_take_glue: uint = 2u; pub static tydesc_field_drop_glue: uint = 3u; pub static tydesc_field_free_glue: uint = 4u; pub static tydesc_field_visit_glue: uint = 5u; -pub static tydesc_field_shape: uint = 6u; -pub static tydesc_field_shape_tables: uint = 7u; -pub static n_tydesc_fields: uint = 8u; +pub static n_tydesc_fields: uint = 6u; // The two halves of a closure: code and environment. pub static fn_field_code: uint = 0u; pub static fn_field_box: uint = 1u; -// The three fields of a trait object/trait instance: vtable, box, and type -// description. +// The two fields of a trait object/trait instance: vtable and box. +// The vtable contains the type descriptor as first element. pub static trt_field_vtable: uint = 0u; pub static trt_field_box: uint = 1u; -// This field is only present in unique trait objects, so it comes last. -pub static trt_field_tydesc: uint = 2u; pub static vec_elt_fill: uint = 0u; @@ -73,14 +66,4 @@ pub static vec_elt_elems: uint = 2u; pub static slice_elt_base: uint = 0u; pub static slice_elt_len: uint = 1u; -pub static worst_case_glue_call_args: uint = 7u; - pub static abi_version: uint = 1u; - -pub fn memcpy_glue_name() -> ~str { return ~"rust_memcpy_glue"; } - -pub fn bzero_glue_name() -> ~str { return ~"rust_bzero_glue"; } - -pub fn yield_glue_name() -> ~str { return ~"rust_yield_glue"; } - -pub fn no_op_type_glue_name() -> ~str { return ~"rust_no_op_type_glue"; } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 6aa97e393ea..61d39421b7f 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use back::rpath; use driver::session::Session; @@ -19,24 +18,26 @@ use lib; use metadata::common::LinkMeta; use metadata::{encoder, csearch, cstore}; use middle::trans::context::CrateContext; +use middle::trans::common::gensym_name; use middle::ty; use util::ppaux; -use core::char; -use core::hash::Streaming; -use core::hash; -use core::libc::{c_int, c_uint}; -use core::os::consts::{macos, freebsd, linux, android, win32}; -use core::os; -use core::ptr; -use core::rt::io::Writer; -use core::run; -use core::str; -use core::vec; +use std::char; +use std::hash::Streaming; +use std::hash; +use std::libc::{c_int, c_uint}; +use std::os::consts::{macos, freebsd, linux, android, win32}; +use std::os; +use std::ptr; +use std::rt::io::Writer; +use std::run; +use std::str; +use std::vec; use syntax::ast; use syntax::ast_map::{path, path_mod, path_name}; use syntax::attr; use syntax::print::pprust; +use syntax::parse::token; #[deriving(Eq)] pub enum output_type { @@ -96,7 +97,6 @@ pub fn WriteOutputFile(sess: Session, } pub mod jit { - use core::prelude::*; use back::link::llvm_err; use driver::session::Session; @@ -104,11 +104,11 @@ pub mod jit { use lib::llvm::{ModuleRef, ContextRef}; use metadata::cstore; - use core::cast; - use core::ptr; - use core::str; - use core::sys; - use core::unstable::intrinsics; + use std::cast; + use std::ptr; + use std::str; + use std::sys; + use std::unstable::intrinsics; pub fn exec(sess: Session, c: ContextRef, @@ -124,19 +124,18 @@ pub mod jit { // incase the user wants to use an older extra library. let cstore = sess.cstore; - for cstore::get_used_crate_files(cstore).each |cratepath| { + let r = cstore::get_used_crate_files(cstore); + for r.iter().advance |cratepath| { let path = cratepath.to_str(); debug!("linking: %s", path); - let _: () = str::as_c_str( - path, - |buf_t| { - if !llvm::LLVMRustLoadCrate(manager, buf_t) { - llvm_err(sess, ~"Could not link"); - } - debug!("linked: %s", path); - }); + do str::as_c_str(path) |buf_t| { + if !llvm::LLVMRustLoadCrate(manager, buf_t) { + llvm_err(sess, ~"Could not link"); + } + debug!("linked: %s", path); + } } // We custom-build a JIT execution engine via some rust wrappers @@ -181,7 +180,6 @@ pub mod jit { } pub mod write { - use core::prelude::*; use back::link::jit; use back::link::{WriteOutputFile, output_type}; @@ -197,17 +195,16 @@ pub mod write { use back::passes; - use core::libc::{c_int, c_uint}; - use core::path::Path; - use core::run; - use core::str; + use std::libc::{c_int, c_uint}; + use std::path::Path; + use std::run; + use std::str; pub fn is_object_or_assembly_or_exe(ot: output_type) -> bool { - if ot == output_type_assembly || ot == output_type_object || - ot == output_type_exe { - return true; + match ot { + output_type_assembly | output_type_object | output_type_exe => true, + _ => false } - return false; } pub fn run_passes(sess: Session, @@ -290,11 +287,11 @@ pub mod write { session::Aggressive => LLVMOptAggressive }; - let FileType; - if output_type == output_type_object || - output_type == output_type_exe { - FileType = lib::llvm::ObjectFile; - } else { FileType = lib::llvm::AssemblyFile; } + let FileType = match output_type { + output_type_object | output_type_exe => lib::llvm::ObjectFile, + _ => lib::llvm::AssemblyFile + }; + // Write optimized bitcode if --save-temps was on. if opts.save_temps { @@ -384,11 +381,11 @@ pub mod write { (--android-cross-path)") } }; - let mut cc_args = ~[]; - cc_args.push(~"-c"); - cc_args.push(~"-o"); - cc_args.push(object.to_str()); - cc_args.push(assembly.to_str()); + + let cc_args = ~[ + ~"-c", + ~"-o", object.to_str(), + assembly.to_str()]; let prog = run::process_output(cc_prog, cc_args); @@ -473,20 +470,20 @@ pub fn build_link_meta(sess: Session, let mut cmh_items = ~[]; let linkage_metas = attr::find_linkage_metas(c.node.attrs); attr::require_unique_names(sess.diagnostic(), linkage_metas); - for linkage_metas.each |meta| { - if "name" == attr::get_meta_item_name(*meta) { - match attr::get_meta_item_value_str(*meta) { - // Changing attr would avoid the need for the copy - // here - Some(v) => { name = Some(v); } - None => cmh_items.push(*meta) - } - } else if "vers" == attr::get_meta_item_name(*meta) { - match attr::get_meta_item_value_str(*meta) { - Some(v) => { vers = Some(v); } - None => cmh_items.push(*meta) - } - } else { cmh_items.push(*meta); } + for linkage_metas.iter().advance |meta| { + match attr::get_meta_item_value_str(*meta) { + Some(value) => { + let item_name : &str = attr::get_meta_item_name(*meta); + match item_name { + // Changing attr would avoid the need for the copy + // here + "name" => name = Some(value), + "vers" => vers = Some(value), + _ => cmh_items.push(*meta) + } + }, + None => cmh_items.push(*meta) + } } ProvidedMetas { @@ -521,7 +518,7 @@ pub fn build_link_meta(sess: Session, } ast::meta_list(name, ref mis) => { write_string(symbol_hasher, len_and_str(name)); - for mis.each |m_| { + for mis.iter().advance |m_| { hash(symbol_hasher, m_); } } @@ -529,15 +526,15 @@ pub fn build_link_meta(sess: Session, } symbol_hasher.reset(); - for cmh_items.each |m| { + for cmh_items.iter().advance |m| { hash(symbol_hasher, m); } - for dep_hashes.each |dh| { + for dep_hashes.iter().advance |dh| { write_string(symbol_hasher, len_and_str(*dh)); } - // tjc: allocation is unfortunate; need to change core::hash + // tjc: allocation is unfortunate; need to change std::hash return truncated_hash_result(symbol_hasher).to_managed(); } @@ -548,32 +545,32 @@ pub fn build_link_meta(sess: Session, } fn crate_meta_name(sess: Session, output: &Path, opt_name: Option<@str>) - -> @str { - return match opt_name { - Some(v) => v, - None => { + -> @str { + match opt_name { + Some(v) => v, + None => { // to_managed could go away if there was a version of // filestem that returned an @str let name = session::expect(sess, - output.filestem(), - || fmt!("output file name `%s` doesn't\ - appear to have a stem", - output.to_str())).to_managed(); + output.filestem(), + || fmt!("output file name `%s` doesn't\ + appear to have a stem", + output.to_str())).to_managed(); warn_missing(sess, "name", name); name - } - }; + } + } } fn crate_meta_vers(sess: Session, opt_vers: Option<@str>) -> @str { - return match opt_vers { - Some(v) => v, - None => { + match opt_vers { + Some(v) => v, + None => { let vers = @"0.0"; warn_missing(sess, "vers", vers); vers - } - }; + } + } } let ProvidedMetas { @@ -618,7 +615,7 @@ pub fn symbol_hash(tcx: ty::ctxt, let mut hash = truncated_hash_result(symbol_hasher); // Prefix with _ so that it never blends into adjacent digits hash.unshift_char('_'); - // tjc: allocation is unfortunate; need to change core::hash + // tjc: allocation is unfortunate; need to change std::hash hash.to_managed() } @@ -642,15 +639,15 @@ pub fn sanitize(s: &str) -> ~str { for s.iter().advance |c| { match c { // Escape these with $ sequences - '@' => result += "$SP$", - '~' => result += "$UP$", - '*' => result += "$RP$", - '&' => result += "$BP$", - '<' => result += "$LT$", - '>' => result += "$GT$", - '(' => result += "$LP$", - ')' => result += "$RP$", - ',' => result += "$C$", + '@' => result.push_str("$SP$"), + '~' => result.push_str("$UP$"), + '*' => result.push_str("$RP$"), + '&' => result.push_str("$BP$"), + '<' => result.push_str("$LT$"), + '>' => result.push_str("$GT$"), + '(' => result.push_str("$LP$"), + ')' => result.push_str("$RP$"), + ',' => result.push_str("$C$"), // '.' doesn't occur in types and functions, so reuse it // for ':' @@ -663,9 +660,10 @@ pub fn sanitize(s: &str) -> ~str { | '_' => result.push_char(c), _ => { - if c > 'z' && char::is_XID_continue(c) { - result.push_char(c); - } + let mut tstr = ~""; + do char::escape_unicode(c) |c| { tstr.push_char(c); } + result.push_char('$'); + result.push_str(tstr.slice_from(1)); } } } @@ -685,13 +683,15 @@ pub fn mangle(sess: Session, ss: path) -> ~str { let mut n = ~"_ZN"; // Begin name-sequence. - for ss.each |s| { - match *s { path_name(s) | path_mod(s) => { - let sani = sanitize(sess.str_of(s)); - n += fmt!("%u%s", sani.len(), sani); - } } + for ss.iter().advance |s| { + match *s { + path_name(s) | path_mod(s) => { + let sani = sanitize(sess.str_of(s)); + n.push_str(fmt!("%u%s", sani.len(), sani)); + } + } } - n += "E"; // End name-sequence. + n.push_char('E'); // End name-sequence. n } @@ -699,10 +699,10 @@ pub fn exported_name(sess: Session, path: path, hash: &str, vers: &str) -> ~str { - return mangle(sess, - vec::append_one( - vec::append_one(path, path_name(sess.ident_of(hash))), - path_name(sess.ident_of(vers)))); + mangle(sess, + vec::append_one( + vec::append_one(path, path_name(sess.ident_of(hash))), + path_name(sess.ident_of(vers)))) } pub fn mangle_exported_name(ccx: &mut CrateContext, @@ -733,22 +733,22 @@ pub fn mangle_internal_name_by_type_and_seq(ccx: &mut CrateContext, return mangle(ccx.sess, ~[path_name(ccx.sess.ident_of(s)), path_name(ccx.sess.ident_of(hash)), - path_name((ccx.names)(name))]); + path_name(gensym_name(name))]); } pub fn mangle_internal_name_by_path_and_seq(ccx: &mut CrateContext, - path: path, + mut path: path, flav: &str) -> ~str { - return mangle(ccx.sess, - vec::append_one(path, path_name((ccx.names)(flav)))); + path.push(path_name(gensym_name(flav))); + mangle(ccx.sess, path) } pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str { - return mangle(ccx.sess, path); + mangle(ccx.sess, path) } -pub fn mangle_internal_name_by_seq(ccx: &mut CrateContext, flav: &str) -> ~str { - return fmt!("%s_%u", flav, (ccx.names)(flav).name); +pub fn mangle_internal_name_by_seq(_ccx: &mut CrateContext, flav: &str) -> ~str { + return fmt!("%s_%u", flav, token::gensym(flav)); } @@ -776,8 +776,8 @@ pub fn link_binary(sess: Session, // so we add a condition to make it use gcc. let cc_prog: ~str = match sess.opts.linker { Some(ref linker) => copy *linker, - None => { - if sess.targ_cfg.os == session::os_android { + None => match sess.targ_cfg.os { + session::os_android => match &sess.opts.android_cross_path { &Some(ref path) => { fmt!("%s/bin/arm-linux-androideabi-gcc", *path) @@ -786,12 +786,9 @@ pub fn link_binary(sess: Session, sess.fatal("need Android NDK path for linking \ (--android-cross-path)") } - } - } else if sess.targ_cfg.os == session::os_win32 { - ~"gcc" - } else { - ~"cc" - } + }, + session::os_win32 => ~"gcc", + _ => ~"cc" } }; // The invocations of cc share some flags across platforms @@ -866,22 +863,20 @@ pub fn link_args(sess: Session, let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args); - args.push(~"-o"); - args.push(output.to_str()); - args.push(obj_filename.to_str()); + args.push_all([ + ~"-o", output.to_str(), + obj_filename.to_str()]); - let lib_cmd; - let os = sess.targ_cfg.os; - if os == session::os_macos { - lib_cmd = ~"-dynamiclib"; - } else { - lib_cmd = ~"-shared"; - } + let lib_cmd = match sess.targ_cfg.os { + session::os_macos => ~"-dynamiclib", + _ => ~"-shared" + }; // # Crate linking let cstore = sess.cstore; - for cstore::get_used_crate_files(cstore).each |cratepath| { + let r = cstore::get_used_crate_files(cstore); + for r.iter().advance |cratepath| { if cratepath.filetype() == Some(~".rlib") { args.push(cratepath.to_str()); loop; @@ -893,7 +888,7 @@ pub fn link_args(sess: Session, } let ula = cstore::get_used_link_args(cstore); - for ula.each |arg| { args.push(arg.to_owned()); } + for ula.iter().advance |arg| { args.push(arg.to_owned()); } // Add all the link args for external crates. do cstore::iter_crate_data(cstore) |crate_num, _| { @@ -911,13 +906,13 @@ pub fn link_args(sess: Session, // to be found at compile time so it is still entirely up to outside // forces to make sure that library can be found at runtime. - for sess.opts.addl_lib_search_paths.each |path| { + for sess.opts.addl_lib_search_paths.iter().advance |path| { args.push(~"-L" + path.to_str()); } // The names of the extern libraries let used_libs = cstore::get_used_libraries(cstore); - for used_libs.each |l| { args.push(~"-l" + *l); } + for used_libs.iter().advance |l| { args.push(~"-l" + *l); } if *sess.building_library { args.push(lib_cmd); diff --git a/src/librustc/back/passes.rs b/src/librustc/back/passes.rs index 987c76dccb4..c1192707c1c 100644 --- a/src/librustc/back/passes.rs +++ b/src/librustc/back/passes.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; -use core::str; -use core::io; +use std::str; +use std::io; use driver::session::{OptLevel, No, Less, Aggressive}; use driver::session::{Session}; @@ -23,7 +22,7 @@ pub struct PassManager { } impl Drop for PassManager { - fn finalize(&self) { + fn drop(&self) { unsafe { llvm::LLVMDisposePassManager(self.llpm); } @@ -60,94 +59,113 @@ impl PassManager { } } -pub fn create_standard_passes(level:OptLevel) -> ~[~str] { - let mut passes = ~[~"strip-dead-prototypes"]; - - if level == No { - passes.push(~"always-inline"); - return passes; +pub fn create_standard_passes(level: OptLevel) -> ~[~str] { + let mut passes = ~[]; + + // mostly identical to clang 3.3, all differences are documented with comments + + if level != No { + passes.push(~"targetlibinfo"); + passes.push(~"no-aa"); + // "tbaa" omitted, we don't emit clang-style type-based alias analysis information + passes.push(~"basicaa"); + passes.push(~"globalopt"); + passes.push(~"ipsccp"); + passes.push(~"deadargelim"); + passes.push(~"instcombine"); + passes.push(~"simplifycfg"); } - passes.push(~"targetlibinfo"); - - passes.push(~"scev-aa"); - passes.push(~"basicaa"); - - passes.push(~"instcombine"); - passes.push(~"simplifycfg"); - passes.push(~"scalarrepl-ssa"); - passes.push(~"early-cse"); - - passes.push(~"globalopt"); - passes.push(~"ipsccp"); - passes.push(~"deadargelim"); - passes.push(~"instcombine"); - passes.push(~"simplifycfg"); + passes.push(~"basiccg"); - passes.push(~"prune-eh"); - - passes.push(~"inline"); - - passes.push(~"functionattrs"); - - if level == Aggressive { - passes.push(~"argpromotion"); + if level != No { + passes.push(~"prune-eh"); } - passes.push(~"scalarrepl-ssa"); - passes.push(~"early-cse"); - passes.push(~"simplify-libcalls"); - passes.push(~"jump-threading"); - passes.push(~"correlated-propagation"); - passes.push(~"simplifycfg"); - passes.push(~"instcombine"); - - passes.push(~"tailcallelim"); - passes.push(~"simplifycfg"); - passes.push(~"reassociate"); - passes.push(~"loop-rotate"); - passes.push(~"licm"); - - passes.push(~"lcssa"); - passes.push(~"loop-unswitch"); + passes.push(~"inline-cost"); - passes.push(~"instcombine"); - passes.push(~"indvars"); - passes.push(~"loop-idiom"); - passes.push(~"loop-deletion"); - - if level == Aggressive { - passes.push(~"loop-vectorize"); + if level == No || level == Less { + passes.push(~"always-inline"); + } else { + passes.push(~"inline"); } - passes.push(~"loop-unroll"); - - if level != Less { - passes.push(~"gvn"); + if level != No { + passes.push(~"functionattrs"); + if level == Aggressive { + passes.push(~"argpromotion"); + } + passes.push(~"sroa"); + passes.push(~"domtree"); + passes.push(~"early-cse"); + passes.push(~"simplify-libcalls"); + passes.push(~"lazy-value-info"); + passes.push(~"jump-threading"); + passes.push(~"correlated-propagation"); + passes.push(~"simplifycfg"); + passes.push(~"instcombine"); + passes.push(~"tailcallelim"); + passes.push(~"simplifycfg"); + passes.push(~"reassociate"); + passes.push(~"domtree"); + passes.push(~"loops"); + passes.push(~"loop-simplify"); + passes.push(~"lcssa"); + passes.push(~"loop-rotate"); + passes.push(~"licm"); + passes.push(~"lcssa"); + passes.push(~"loop-unswitch"); + passes.push(~"instcombine"); + passes.push(~"scalar-evolution"); + passes.push(~"loop-simplify"); + passes.push(~"lcssa"); + passes.push(~"indvars"); + passes.push(~"loop-idiom"); + passes.push(~"loop-deletion"); + if level == Aggressive { + passes.push(~"loop-simplify"); + passes.push(~"lcssa"); + passes.push(~"loop-vectorize"); + passes.push(~"loop-simplify"); + passes.push(~"lcssa"); + passes.push(~"scalar-evolution"); + passes.push(~"loop-simplify"); + passes.push(~"lcssa"); + } + if level != Less { + passes.push(~"loop-unroll"); + passes.push(~"memdep"); + passes.push(~"gvn"); + } + passes.push(~"memdep"); + passes.push(~"memcpyopt"); + passes.push(~"sccp"); + passes.push(~"instcombine"); + passes.push(~"lazy-value-info"); + passes.push(~"jump-threading"); + passes.push(~"correlated-propagation"); + passes.push(~"domtree"); + passes.push(~"memdep"); + passes.push(~"dse"); + passes.push(~"adce"); + passes.push(~"simplifycfg"); + passes.push(~"instcombine"); + // clang does `strip-dead-prototypes` here, since it does not emit them } - passes.push(~"memcpyopt"); - passes.push(~"sccp"); - - passes.push(~"instcombine"); - passes.push(~"jump-threading"); - passes.push(~"correlated-propagation"); - passes.push(~"dse"); - - passes.push(~"adce"); - passes.push(~"simplifycfg"); - passes.push(~"instsimplify"); + // rustc emits dead prototypes, so always ask LLVM to strip them + passes.push(~"strip-dead-prototypes"); if level != Less { passes.push(~"globaldce"); passes.push(~"constmerge"); } - return passes; + passes } pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) { - for pass_list.each |&nm| { + for pass_list.iter().advance |&nm| { match create_pass(nm) { Some(p) => pm.add_pass(p), None => sess.warn(fmt!("Unknown pass %s", nm)) @@ -172,15 +190,15 @@ pub fn list_passes() { io::println("\nAvailable Passes:"); io::println("\nAnalysis Passes:"); - for analysis_passes.each |&(name, desc)| { + for analysis_passes.iter().advance |&(name, desc)| { io::println(fmt!(" %-30s -- %s", name, desc)); } io::println("\nTransformation Passes:"); - for transform_passes.each |&(name, desc)| { + for transform_passes.iter().advance |&(name, desc)| { io::println(fmt!(" %-30s -- %s", name, desc)); } io::println("\nUtility Passes:"); - for utility_passes.each |&(name, desc)| { + for utility_passes.iter().advance |&(name, desc)| { io::println(fmt!(" %-30s -- %s", name, desc)); } } @@ -298,7 +316,7 @@ static utility_passes : &'static [(&'static str, &'static str)] = &'static [ fn passes_exist() { let mut failed = ~[]; unsafe { llvm::LLVMInitializePasses(); } - for analysis_passes.each() |&(name,_)| { + for analysis_passes.iter().advance |&(name,_)| { let pass = create_pass(name); if !pass.is_some() { failed.push(name); @@ -306,7 +324,7 @@ fn passes_exist() { unsafe { llvm::LLVMDestroyPass(pass.get()) } } } - for transform_passes.each() |&(name,_)| { + for transform_passes.iter().advance |&(name,_)| { let pass = create_pass(name); if !pass.is_some() { failed.push(name); @@ -314,7 +332,7 @@ fn passes_exist() { unsafe { llvm::LLVMDestroyPass(pass.get()) } } } - for utility_passes.each() |&(name,_)| { + for utility_passes.iter().advance |&(name,_)| { let pass = create_pass(name); if !pass.is_some() { failed.push(name); @@ -325,7 +343,7 @@ fn passes_exist() { if failed.len() > 0 { io::println("Some passes don't exist:"); - for failed.each |&n| { + for failed.iter().advance |&n| { io::println(fmt!(" %s", n)); } fail!(); diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index fd22a7e79c6..19dbb941e55 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,23 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use driver::session; use metadata::cstore; use metadata::filesearch; -use core::hashmap::HashSet; -use core::os; -use core::uint; -use core::util; -use core::vec; +use std::hashmap::HashSet; +use std::os; +use std::uint; +use std::util; +use std::vec; fn not_win32(os: session::os) -> bool { - match os { - session::os_win32 => false, - _ => true - } + os != session::os_win32 } pub fn get_rpath_flags(sess: session::Session, out_filename: &Path) @@ -56,7 +52,7 @@ fn get_sysroot_absolute_rt_lib(sess: session::Session) -> Path { } pub fn rpaths_to_flags(rpaths: &[Path]) -> ~[~str] { - vec::map(rpaths, |rpath| fmt!("-Wl,-rpath,%s",rpath.to_str())) + rpaths.iter().transform(|rpath| fmt!("-Wl,-rpath,%s",rpath.to_str())).collect() } fn get_rpaths(os: session::os, @@ -67,7 +63,7 @@ fn get_rpaths(os: session::os, debug!("sysroot: %s", sysroot.to_str()); debug!("output: %s", output.to_str()); debug!("libs:"); - for libs.each |libpath| { + for libs.iter().advance |libpath| { debug!(" %s", libpath.to_str()); } debug!("target_triple: %s", target_triple); @@ -86,7 +82,7 @@ fn get_rpaths(os: session::os, fn log_rpaths(desc: &str, rpaths: &[Path]) { debug!("%s rpaths:", desc); - for rpaths.each |rpath| { + for rpaths.iter().advance |rpath| { debug!(" %s", rpath.to_str()); } } @@ -107,22 +103,20 @@ fn get_rpaths(os: session::os, fn get_rpaths_relative_to_output(os: session::os, output: &Path, libs: &[Path]) -> ~[Path] { - vec::map(libs, |a| { - get_rpath_relative_to_output(os, output, a) - }) + libs.iter().transform(|a| get_rpath_relative_to_output(os, output, a)).collect() } pub fn get_rpath_relative_to_output(os: session::os, output: &Path, lib: &Path) -> Path { - use core::os; + use std::os; assert!(not_win32(os)); // Mac doesn't appear to support $ORIGIN let prefix = match os { - session::os_android |session::os_linux | session::os_freebsd + session::os_android | session::os_linux | session::os_freebsd => "$ORIGIN", session::os_macos => "@executable_path", session::os_win32 => util::unreachable() @@ -157,17 +151,17 @@ pub fn get_relative_to(abs1: &Path, abs2: &Path) -> Path { let mut path = ~[]; for uint::range(start_idx, len1 - 1) |_i| { path.push(~".."); }; - path.push_all(vec::slice(split2, start_idx, len2 - 1)); + path.push_all(split2.slice(start_idx, len2 - 1)); - if !path.is_empty() { - return Path("").push_many(path); + return if !path.is_empty() { + Path("").push_many(path) } else { - return Path("."); + Path(".") } } fn get_absolute_rpaths(libs: &[Path]) -> ~[Path] { - vec::map(libs, |a| get_absolute_rpath(a) ) + libs.iter().transform(|a| get_absolute_rpath(a)).collect() } pub fn get_absolute_rpath(lib: &Path) -> Path { @@ -188,7 +182,7 @@ pub fn get_install_prefix_rpath(target_triple: &str) -> Path { pub fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] { let mut set = HashSet::new(); let mut minimized = ~[]; - for rpaths.each |rpath| { + for rpaths.iter().advance |rpath| { if set.insert(rpath.to_str()) { minimized.push(copy *rpath); } @@ -198,8 +192,7 @@ pub fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] { #[cfg(unix, test)] mod test { - use core::prelude::*; - use core::os; + use std::os; // FIXME(#2119): the outer attribute should be #[cfg(unix, test)], then // these redundant #[cfg(test)] blocks can be removed diff --git a/src/librustc/back/upcall.rs b/src/librustc/back/upcall.rs index 4d2ea4eb4a6..76bba481619 100644 --- a/src/librustc/back/upcall.rs +++ b/src/librustc/back/upcall.rs @@ -11,8 +11,8 @@ use driver::session; use middle::trans::base; -use middle::trans::common::{T_fn, T_i8, T_i32, T_int, T_ptr, T_void}; -use lib::llvm::{ModuleRef, ValueRef, TypeRef}; +use middle::trans::type_::Type; +use lib::llvm::{ModuleRef, ValueRef}; pub struct Upcalls { trace: ValueRef, @@ -22,40 +22,35 @@ pub struct Upcalls { reset_stack_limit: ValueRef } -pub fn declare_upcalls(targ_cfg: @session::config, - llmod: ModuleRef) -> @Upcalls { - fn decl(llmod: ModuleRef, prefix: ~str, name: ~str, - tys: ~[TypeRef], rv: TypeRef) -> - ValueRef { - let arg_tys = tys.map(|t| *t); - let fn_ty = T_fn(arg_tys, rv); - return base::decl_cdecl_fn(llmod, prefix + name, fn_ty); - } - fn nothrow(f: ValueRef) -> ValueRef { - base::set_no_unwind(f); f - } - let d: &fn(a: ~str, b: ~[TypeRef], c: TypeRef) -> ValueRef = - |a,b,c| decl(llmod, ~"upcall_", a, b, c); - let dv: &fn(a: ~str, b: ~[TypeRef]) -> ValueRef = - |a,b| decl(llmod, ~"upcall_", a, b, T_void()); +macro_rules! upcall ( + (fn $name:ident($($arg:expr),+) -> $ret:expr) => ({ + let fn_ty = Type::func([ $($arg),* ], &$ret); + base::decl_cdecl_fn(llmod, ~"upcall_" + stringify!($name), fn_ty) + }); + (nothrow fn $name:ident($($arg:expr),+) -> $ret:expr) => ({ + let fn_ty = Type::func([ $($arg),* ], &$ret); + let decl = base::decl_cdecl_fn(llmod, ~"upcall_" + stringify!($name), fn_ty); + base::set_no_unwind(decl); + decl + }); + (nothrow fn $name:ident -> $ret:expr) => ({ + let fn_ty = Type::func([], &$ret); + let decl = base::decl_cdecl_fn(llmod, ~"upcall_" + stringify!($name), fn_ty); + base::set_no_unwind(decl); + decl + }) +) - let int_t = T_int(targ_cfg); +pub fn declare_upcalls(targ_cfg: @session::config, llmod: ModuleRef) -> @Upcalls { + let opaque_ptr = Type::i8().ptr_to(); + let int_ty = Type::int(targ_cfg.arch); @Upcalls { - trace: dv(~"trace", ~[T_ptr(T_i8()), - T_ptr(T_i8()), - int_t]), - call_shim_on_c_stack: - d(~"call_shim_on_c_stack", - // arguments: void *args, void *fn_ptr - ~[T_ptr(T_i8()), T_ptr(T_i8())], - int_t), + trace: upcall!(fn trace(opaque_ptr, opaque_ptr, int_ty) -> Type::void()), + call_shim_on_c_stack: upcall!(fn call_shim_on_c_stack(opaque_ptr, opaque_ptr) -> int_ty), call_shim_on_rust_stack: - d(~"call_shim_on_rust_stack", - ~[T_ptr(T_i8()), T_ptr(T_i8())], int_t), - rust_personality: - nothrow(d(~"rust_personality", ~[], T_i32())), - reset_stack_limit: - nothrow(dv(~"reset_stack_limit", ~[])) + upcall!(fn call_shim_on_rust_stack(opaque_ptr, opaque_ptr) -> int_ty), + rust_personality: upcall!(nothrow fn rust_personality -> Type::i32()), + reset_stack_limit: upcall!(nothrow fn reset_stack_limit -> Type::void()) } } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 43b3397094b..a32f54fe7bb 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use back::link; use back::{arm, x86, x86_64, mips}; @@ -19,16 +18,16 @@ use front; use lib::llvm::llvm; use metadata::{creader, cstore, filesearch}; use metadata; -use middle::{trans, freevars, kind, ty, typeck, lint, astencode}; +use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable}; use middle; use util::common::time; use util::ppaux; -use core::hashmap::HashMap; -use core::int; -use core::io; -use core::os; -use core::vec; +use std::hashmap::HashMap; +use std::int; +use std::io; +use std::os; +use std::vec; use extra::getopts::groups::{optopt, optmulti, optflag, optflagopt}; use extra::getopts::{opt_present}; use extra::getopts; @@ -161,7 +160,7 @@ pub struct compile_upto { #[deriving(Eq)] pub enum compile_phase { cu_parse, - cu_expand, + cu_expand, // means "it's already expanded" cu_typeck, cu_no_trans, cu_everything, @@ -181,34 +180,40 @@ pub fn compile_rest(sess: Session, let time_passes = sess.time_passes(); - let mut crate_opt = curr; + let mut crate = curr.unwrap(); if phases.from == cu_parse || phases.from == cu_everything { *sess.building_library = session::building_library( - sess.opts.crate_type, crate_opt.unwrap(), sess.opts.test); - - crate_opt = Some(time(time_passes, ~"expansion", || + sess.opts.crate_type, crate, sess.opts.test); + + // strip before expansion to allow macros to depend on + // configuration variables e.g/ in + // + // #[macro_escape] #[cfg(foo)] + // mod bar { macro_rules! baz!(() => {{}}) } + // + // baz! should not use this definition unless foo is enabled. + crate = time(time_passes, ~"configuration 1", || + front::config::strip_unconfigured_items(crate)); + + crate = time(time_passes, ~"expansion", || syntax::ext::expand::expand_crate(sess.parse_sess, copy cfg, - crate_opt.unwrap()))); + crate)); - crate_opt = Some(time(time_passes, ~"configuration", || - front::config::strip_unconfigured_items(crate_opt.unwrap()))); + // strip again, in case expansion added anything with a #[cfg]. + crate = time(time_passes, ~"configuration 2", || + front::config::strip_unconfigured_items(crate)); - crate_opt = Some(time(time_passes, ~"maybe building test harness", || - front::test::modify_for_testing(sess, crate_opt.unwrap()))); + crate = time(time_passes, ~"maybe building test harness", || + front::test::modify_for_testing(sess, crate)); } - if phases.to == cu_expand { return (crate_opt, None); } + if phases.to == cu_expand { return (Some(crate), None); } assert!(phases.from != cu_no_trans); - let mut crate = crate_opt.unwrap(); - let (llcx, llmod, link_meta) = { - crate = time(time_passes, ~"intrinsic injection", || - front::intrinsic_inject::inject_intrinsic(sess, crate)); - crate = time(time_passes, ~"extra injection", || front::std_inject::maybe_inject_libstd_ref(sess, crate)); @@ -293,10 +298,16 @@ pub fn compile_rest(sess: Session, time(time_passes, ~"kind checking", || kind::check_crate(ty_cx, method_map, crate)); + let reachable_map = + time(time_passes, ~"reachability checking", || + reachable::find_reachable(ty_cx, method_map, crate)); + time(time_passes, ~"lint checking", || lint::check_crate(ty_cx, crate)); - if phases.to == cu_no_trans { return (Some(crate), Some(ty_cx)); } + if phases.to == cu_no_trans { + return (Some(crate), Some(ty_cx)); + } let maps = astencode::Maps { root_map: root_map, @@ -309,9 +320,13 @@ pub fn compile_rest(sess: Session, let outputs = outputs.get_ref(); time(time_passes, ~"translation", || - trans::base::trans_crate(sess, crate, ty_cx, + trans::base::trans_crate(sess, + crate, + ty_cx, &outputs.obj_filename, - exp_map2, maps)) + exp_map2, + reachable_map, + maps)) }; let outputs = outputs.get_ref(); @@ -453,7 +468,7 @@ pub fn pretty_print_input(sess: Session, cfg: ast::crate_cfg, input: &input, } pub fn get_os(triple: &str) -> Option<session::os> { - for os_names.each |&(name, os)| { + for os_names.iter().advance |&(name, os)| { if triple.contains(name) { return Some(os) } } None @@ -467,7 +482,7 @@ static os_names : &'static [(&'static str, session::os)] = &'static [ ("freebsd", session::os_freebsd)]; pub fn get_arch(triple: &str) -> Option<abi::Architecture> { - for architecture_abis.each |&(arch, abi)| { + for architecture_abis.iter().advance |&(arch, abi)| { if triple.contains(arch) { return Some(abi) } } None @@ -556,7 +571,7 @@ pub fn build_session_options(binary: @str, lint::deny, lint::forbid]; let mut lint_opts = ~[]; let lint_dict = lint::get_lint_dict(); - for lint_levels.each |level| { + for lint_levels.iter().advance |level| { let level_name = lint::level_to_str(*level); // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use @@ -565,7 +580,7 @@ pub fn build_session_options(binary: @str, let level_short = level_short.to_ascii().to_upper().to_str_ascii(); let flags = vec::append(getopts::opt_strs(matches, level_short), getopts::opt_strs(matches, level_name)); - for flags.each |lint_name| { + for flags.iter().advance |lint_name| { let lint_name = lint_name.replace("-", "_"); match lint_dict.find_equiv(&lint_name) { None => { @@ -582,9 +597,9 @@ pub fn build_session_options(binary: @str, let mut debugging_opts = 0u; let debug_flags = getopts::opt_strs(matches, "Z"); let debug_map = session::debugging_opts_map(); - for debug_flags.each |debug_flag| { + for debug_flags.iter().advance |debug_flag| { let mut this_bit = 0u; - for debug_map.each |tuple| { + for debug_map.iter().advance |tuple| { let (name, bit) = match *tuple { (ref a, _, b) => (a, b) }; if name == debug_flag { this_bit = bit; break; } } @@ -935,7 +950,6 @@ pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) { #[cfg(test)] mod test { - use core::prelude::*; use driver::driver::{build_configuration, build_session}; use driver::driver::{build_session_options, optgroups, str_input}; diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 73e8cfea8ca..ef0b6d64651 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use back::link; use back::target_strs; @@ -29,7 +28,7 @@ use syntax::abi; use syntax::parse::token; use syntax; -use core::hashmap::HashMap; +use std::hashmap::HashMap; #[deriving(Eq)] pub enum os { os_win32, os_macos, os_linux, os_android, os_freebsd, } @@ -45,32 +44,33 @@ pub struct config { float_type: float_ty } -pub static verbose: uint = 1 << 0; -pub static time_passes: uint = 1 << 1; -pub static count_llvm_insns: uint = 1 << 2; -pub static time_llvm_passes: uint = 1 << 3; -pub static trans_stats: uint = 1 << 4; -pub static asm_comments: uint = 1 << 5; -pub static no_verify: uint = 1 << 6; -pub static trace: uint = 1 << 7; -pub static coherence: uint = 1 << 8; -pub static borrowck_stats: uint = 1 << 9; -pub static borrowck_note_pure: uint = 1 << 10; -pub static borrowck_note_loan: uint = 1 << 11; -pub static no_landing_pads: uint = 1 << 12; -pub static debug_llvm: uint = 1 << 13; -pub static count_type_sizes: uint = 1 << 14; -pub static meta_stats: uint = 1 << 15; -pub static no_opt: uint = 1 << 16; +pub static verbose: uint = 1 << 0; +pub static time_passes: uint = 1 << 1; +pub static count_llvm_insns: uint = 1 << 2; +pub static time_llvm_passes: uint = 1 << 3; +pub static trans_stats: uint = 1 << 4; +pub static asm_comments: uint = 1 << 5; +pub static no_verify: uint = 1 << 6; +pub static trace: uint = 1 << 7; +pub static coherence: uint = 1 << 8; +pub static borrowck_stats: uint = 1 << 9; +pub static borrowck_note_pure: uint = 1 << 10; +pub static borrowck_note_loan: uint = 1 << 11; +pub static no_landing_pads: uint = 1 << 12; +pub static debug_llvm: uint = 1 << 13; +pub static count_type_sizes: uint = 1 << 14; +pub static meta_stats: uint = 1 << 15; +pub static no_opt: uint = 1 << 16; pub static no_monomorphic_collapse: uint = 1 << 17; -pub static gc: uint = 1 << 18; -pub static jit: uint = 1 << 19; -pub static debug_info: uint = 1 << 20; -pub static extra_debug_info: uint = 1 << 21; -pub static statik: uint = 1 << 22; -pub static print_link_args: uint = 1 << 23; -pub static no_debug_borrows: uint = 1 << 24; -pub static lint_llvm : uint = 1 << 25; +pub static gc: uint = 1 << 18; +pub static jit: uint = 1 << 19; +pub static debug_info: uint = 1 << 20; +pub static extra_debug_info: uint = 1 << 21; +pub static statik: uint = 1 << 22; +pub static print_link_args: uint = 1 << 23; +pub static no_debug_borrows: uint = 1 << 24; +pub static lint_llvm: uint = 1 << 25; +pub static once_fns: uint = 1 << 26; pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { ~[(~"verbose", ~"in general, enable more debug printouts", verbose), @@ -112,6 +112,9 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { (~"lint-llvm", ~"Run the LLVM lint pass on the pre-optimization IR", lint_llvm), + (~"once-fns", + ~"Allow 'once fn' closures to deinitialize captured variables", + once_fns), ] } @@ -293,6 +296,7 @@ impl Session_ { pub fn debug_borrows(@self) -> bool { self.opts.optimize == No && !self.debugging_opt(no_debug_borrows) } + pub fn once_fns(@self) -> bool { self.debugging_opt(once_fns) } // pointless function, now... pub fn str_of(@self, id: ast::ident) -> @str { @@ -349,7 +353,7 @@ pub fn expect<T:Copy>(sess: Session, } pub fn building_library(req_crate_type: crate_type, - crate: @ast::crate, + crate: &ast::crate, testing: bool) -> bool { match req_crate_type { bin_crate => false, @@ -403,8 +407,12 @@ mod test { fn make_crate(with_bin: bool, with_lib: bool) -> @ast::crate { let mut attrs = ~[]; - if with_bin { attrs += [make_crate_type_attr(@"bin")]; } - if with_lib { attrs += [make_crate_type_attr(@"lib")]; } + if with_bin { + attrs.push(make_crate_type_attr(@"bin")); + } + if with_lib { + attrs.push(make_crate_type_attr(@"lib")); + } @codemap::respan(codemap::dummy_sp(), ast::crate_ { module: ast::_mod { view_items: ~[], items: ~[] }, attrs: attrs, diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index 3e6ac283da0..b1d4820f062 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; -use core::option; -use core::vec; +use std::option; +use std::vec; use syntax::{ast, fold, attr}; type in_cfg_pred = @fn(attrs: ~[ast::attribute]) -> bool; @@ -24,11 +23,11 @@ struct Context { // any items that do not belong in the current configuration pub fn strip_unconfigured_items(crate: @ast::crate) -> @ast::crate { do strip_items(crate) |attrs| { - in_cfg(/*bad*/copy crate.node.config, attrs) + in_cfg(crate.node.config, attrs) } } -pub fn strip_items(crate: @ast::crate, in_cfg: in_cfg_pred) +pub fn strip_items(crate: &ast::crate, in_cfg: in_cfg_pred) -> @ast::crate { let ctxt = @Context { in_cfg: in_cfg }; @@ -44,8 +43,7 @@ pub fn strip_items(crate: @ast::crate, in_cfg: in_cfg_pred) .. *fold::default_ast_fold()}; let fold = fold::make_fold(precursor); - let res = @fold.fold_crate(&*crate); - return res; + @fold.fold_crate(crate) } fn filter_item(cx: @Context, item: @ast::item) -> @@ -92,7 +90,7 @@ fn fold_foreign_mod( ast::foreign_mod { sort: nm.sort, abis: nm.abis, - view_items: vec::map(filtered_view_items, |x| fld.fold_view_item(*x)), + view_items: filtered_view_items.iter().transform(|x| fld.fold_view_item(*x)).collect(), items: filtered_items } } @@ -143,7 +141,7 @@ fn fold_block( let filtered_view_items = filtered_view_items.map(|x| fld.fold_view_item(*x)); let mut resulting_stmts = ~[]; - for filtered_stmts.each |stmt| { + for filtered_stmts.iter().advance |stmt| { match fld.fold_stmt(*stmt) { None => {} Some(stmt) => resulting_stmts.push(stmt), @@ -183,12 +181,12 @@ fn trait_method_in_cfg(cx: @Context, meth: &ast::trait_method) -> bool { // Determine if an item should be translated in the current crate // configuration based on the item's attributes -fn in_cfg(cfg: ast::crate_cfg, attrs: ~[ast::attribute]) -> bool { +fn in_cfg(cfg: &[@ast::meta_item], attrs: &[ast::attribute]) -> bool { metas_in_cfg(cfg, attr::attr_metas(attrs)) } -pub fn metas_in_cfg(cfg: ast::crate_cfg, - metas: ~[@ast::meta_item]) -> bool { +pub fn metas_in_cfg(cfg: &[@ast::meta_item], + metas: &[@ast::meta_item]) -> bool { // The "cfg" attributes on the item let cfg_metas = attr::find_meta_items_by_name(metas, "cfg"); @@ -197,13 +195,13 @@ pub fn metas_in_cfg(cfg: ast::crate_cfg, // which the item is valid let cfg_metas = vec::filter_map(cfg_metas, |i| attr::get_meta_item_list(i)); - if cfg_metas.all(|c| c.is_empty()) { return true; } + if cfg_metas.iter().all(|c| c.is_empty()) { return true; } - cfg_metas.any(|cfg_meta| { - cfg_meta.all(|cfg_mi| { + cfg_metas.iter().any_(|cfg_meta| { + cfg_meta.iter().all(|cfg_mi| { match cfg_mi.node { ast::meta_list(s, ref it) if "not" == s - => it.all(|mi| !attr::contains(cfg, *mi)), + => it.iter().all(|mi| !attr::contains(cfg, *mi)), _ => attr::contains(cfg, *cfg_mi) } }) diff --git a/src/librustc/front/intrinsic.rs b/src/librustc/front/intrinsic.rs deleted file mode 100644 index fcb08180a5e..00000000000 --- a/src/librustc/front/intrinsic.rs +++ /dev/null @@ -1,140 +0,0 @@ -// 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. - -// NB: this file is include_str!'ed into the compiler, re-parsed -// and injected into each crate the compiler builds. Keep it small. - -pub mod intrinsic { - #[allow(missing_doc)]; - - pub use intrinsic::rusti::visit_tydesc; - - // FIXME (#3727): remove this when the interface has settled and the - // version in sys is no longer present. - pub fn get_tydesc<T>() -> *TyDesc { - unsafe { - rusti::get_tydesc::<T>() as *TyDesc - } - } - - pub struct TyDesc { - size: uint, - align: uint - // Remaining fields not listed - } - - pub enum Opaque { } - - pub trait TyVisitor { - fn visit_bot(&self) -> bool; - fn visit_nil(&self) -> bool; - fn visit_bool(&self) -> bool; - - fn visit_int(&self) -> bool; - fn visit_i8(&self) -> bool; - fn visit_i16(&self) -> bool; - fn visit_i32(&self) -> bool; - fn visit_i64(&self) -> bool; - - fn visit_uint(&self) -> bool; - fn visit_u8(&self) -> bool; - fn visit_u16(&self) -> bool; - fn visit_u32(&self) -> bool; - fn visit_u64(&self) -> bool; - - fn visit_float(&self) -> bool; - fn visit_f32(&self) -> bool; - fn visit_f64(&self) -> bool; - - fn visit_char(&self) -> bool; - fn visit_str(&self) -> bool; - - fn visit_estr_box(&self) -> bool; - fn visit_estr_uniq(&self) -> bool; - fn visit_estr_slice(&self) -> bool; - fn visit_estr_fixed(&self, n: uint, sz: uint, align: uint) -> bool; - - fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool; - - fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint, - mtbl: uint, inner: *TyDesc) -> bool; - - fn visit_enter_rec(&self, n_fields: uint, - sz: uint, align: uint) -> bool; - fn visit_rec_field(&self, i: uint, name: &str, - mtbl: uint, inner: *TyDesc) -> bool; - fn visit_leave_rec(&self, n_fields: uint, - sz: uint, align: uint) -> bool; - - fn visit_enter_class(&self, n_fields: uint, - sz: uint, align: uint) -> bool; - fn visit_class_field(&self, i: uint, name: &str, - mtbl: uint, inner: *TyDesc) -> bool; - fn visit_leave_class(&self, n_fields: uint, - sz: uint, align: uint) -> bool; - - fn visit_enter_tup(&self, n_fields: uint, - sz: uint, align: uint) -> bool; - fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool; - fn visit_leave_tup(&self, n_fields: uint, - sz: uint, align: uint) -> bool; - - fn visit_enter_enum(&self, n_variants: uint, - get_disr: extern unsafe fn(ptr: *Opaque) -> int, - sz: uint, align: uint) -> bool; - fn visit_enter_enum_variant(&self, variant: uint, - disr_val: int, - n_fields: uint, - name: &str) -> bool; - fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool; - fn visit_leave_enum_variant(&self, variant: uint, - disr_val: int, - n_fields: uint, - name: &str) -> bool; - fn visit_leave_enum(&self, n_variants: uint, - get_disr: extern unsafe fn(ptr: *Opaque) -> int, - sz: uint, align: uint) -> bool; - - fn visit_enter_fn(&self, purity: uint, proto: uint, - n_inputs: uint, retstyle: uint) -> bool; - fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool; - fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool; - fn visit_leave_fn(&self, purity: uint, proto: uint, - n_inputs: uint, retstyle: uint) -> bool; - - fn visit_trait(&self) -> bool; - fn visit_var(&self) -> bool; - fn visit_var_integral(&self) -> bool; - fn visit_param(&self, i: uint) -> bool; - fn visit_self(&self) -> bool; - fn visit_type(&self) -> bool; - fn visit_opaque_box(&self) -> bool; - fn visit_constr(&self, inner: *TyDesc) -> bool; - fn visit_closure_ptr(&self, ck: uint) -> bool; - } - - pub mod rusti { - use super::{TyDesc, TyVisitor}; - - #[abi = "rust-intrinsic"] - pub extern "rust-intrinsic" { - pub fn get_tydesc<T>() -> *(); - pub fn visit_tydesc(td: *TyDesc, tv: @TyVisitor); - } - } -} diff --git a/src/librustc/front/intrinsic_inject.rs b/src/librustc/front/intrinsic_inject.rs deleted file mode 100644 index 0caadc8572e..00000000000 --- a/src/librustc/front/intrinsic_inject.rs +++ /dev/null @@ -1,47 +0,0 @@ -// 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. - -use core::prelude::*; - -use core::vec; -use driver::session::Session; -use syntax::parse; -use syntax::ast; -use syntax::codemap::spanned; - -pub fn inject_intrinsic(sess: Session, crate: @ast::crate) -> @ast::crate { - let intrinsic_module = include_str!("intrinsic.rs").to_managed(); - - let item = parse::parse_item_from_source_str(@"<intrinsic>", - intrinsic_module, - /*bad*/copy sess.opts.cfg, - ~[], - sess.parse_sess); - let item = - match item { - Some(i) => i, - None => { - sess.fatal("no item found in intrinsic module"); - } - }; - - let items = vec::append(~[item], crate.node.module.items); - - @spanned { - node: ast::crate_ { - module: ast::_mod { - items: items, - .. /*bad*/copy crate.node.module - }, - .. /*bad*/copy crate.node - }, - .. /*bad*/copy *crate - } -} diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 38a21af65b9..735fe54f348 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -8,18 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use driver::session::Session; -use core::vec; +use std::vec; use syntax::ast; use syntax::attr; use syntax::codemap::dummy_sp; use syntax::codemap; use syntax::fold; -static STD_VERSION: &'static str = "0.7-pre"; +static STD_VERSION: &'static str = "0.7"; pub fn maybe_inject_libstd_ref(sess: Session, crate: @ast::crate) -> @ast::crate { @@ -30,11 +29,11 @@ pub fn maybe_inject_libstd_ref(sess: Session, crate: @ast::crate) } } -fn use_std(crate: @ast::crate) -> bool { +fn use_std(crate: &ast::crate) -> bool { !attr::attrs_contains_name(crate.node.attrs, "no_std") } -fn inject_libstd_ref(sess: Session, crate: @ast::crate) -> @ast::crate { +fn inject_libstd_ref(sess: Session, crate: &ast::crate) -> @ast::crate { fn spanned<T:Copy>(x: T) -> codemap::spanned<T> { codemap::spanned { node: x, span: dummy_sp() } } diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index de6fc322c63..41c70c4c5b4 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -10,12 +10,11 @@ // Code that generates a test runner to run all the tests in a crate -use core::prelude::*; use driver::session; use front::config; -use core::vec; +use std::vec; use syntax::ast_util::*; use syntax::attr; use syntax::codemap::{dummy_sp, span, ExpandedFrom, CallInfo, NameAndSpan}; @@ -92,7 +91,7 @@ fn generate_test_harness(sess: session::Session, return res; } -fn strip_test_functions(crate: @ast::crate) -> @ast::crate { +fn strip_test_functions(crate: &ast::crate) -> @ast::crate { // When not compiling with --test we should not compile the // #[test] functions do config::strip_items(crate) |attrs| { @@ -118,7 +117,7 @@ fn fold_mod(cx: @mut TestCtxt, let mod_nomain = ast::_mod { view_items: /*bad*/copy m.view_items, - items: vec::map(m.items, |i| nomain(cx, *i)), + items: m.items.iter().transform(|i| nomain(cx, *i)).collect(), }; fold::noop_fold_mod(&mod_nomain, fld) @@ -272,7 +271,7 @@ mod __test { */ fn mk_std(cx: &TestCtxt) -> @ast::view_item { - let vers = ast::lit_str(@"0.7-pre"); + let vers = ast::lit_str(@"0.7"); let vers = nospan(vers); let mi = ast::meta_name_value(@"vers", vers); let mi = nospan(mi); @@ -386,7 +385,7 @@ fn is_std(cx: &TestCtxt) -> bool { fn mk_test_descs(cx: &TestCtxt) -> @ast::expr { debug!("building test vector from %u tests", cx.testfns.len()); let mut descs = ~[]; - for cx.testfns.each |test| { + for cx.testfns.iter().advance |test| { descs.push(mk_test_desc_and_fn_rec(cx, test)); } diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 5d5a5e736bc..8ca8c12f412 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; -use core::hashmap::HashMap; -use core::libc::{c_uint, c_ushort}; -use core::option; -use core::ptr; -use core::str; -use core::vec; +use std::hashmap::HashMap; +use std::libc::{c_uint, c_ushort}; +use std::option; +use std::str; + +use middle::trans::type_::Type; pub type Opcode = u32; pub type Bool = c_uint; @@ -268,7 +267,7 @@ pub mod llvm { use super::{SectionIteratorRef, TargetDataRef, TypeKind, TypeRef, UseRef}; use super::{ValueRef, PassRef}; use super::debuginfo::*; - use core::libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong}; + use std::libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong}; #[link_args = "-Lrustllvm -lrustllvm"] #[link_name = "rustllvm"] @@ -2121,155 +2120,101 @@ pub fn ConstFCmp(Pred: RealPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef { /* Memory-managed object interface to type handles. */ pub struct TypeNames { - type_names: @mut HashMap<TypeRef, @str>, - named_types: @mut HashMap<@str, TypeRef> -} - -pub fn associate_type(tn: @TypeNames, s: @str, t: TypeRef) { - assert!(tn.type_names.insert(t, s)); - assert!(tn.named_types.insert(s, t)); -} - -pub fn type_has_name(tn: @TypeNames, t: TypeRef) -> Option<@str> { - return tn.type_names.find(&t).map_consume(|x| *x); -} - -pub fn name_has_type(tn: @TypeNames, s: @str) -> Option<TypeRef> { - return tn.named_types.find(&s).map_consume(|x| *x); + type_names: HashMap<TypeRef, ~str>, + named_types: HashMap<~str, TypeRef> } -pub fn mk_type_names() -> @TypeNames { - @TypeNames { - type_names: @mut HashMap::new(), - named_types: @mut HashMap::new() +impl TypeNames { + pub fn new() -> TypeNames { + TypeNames { + type_names: HashMap::new(), + named_types: HashMap::new() + } } -} -pub fn type_to_str(names: @TypeNames, ty: TypeRef) -> @str { - return type_to_str_inner(names, [], ty); -} + pub fn associate_type(&mut self, s: &str, t: &Type) { + assert!(self.type_names.insert(t.to_ref(), s.to_owned())); + assert!(self.named_types.insert(s.to_owned(), t.to_ref())); + } -pub fn type_to_str_inner(names: @TypeNames, outer0: &[TypeRef], ty: TypeRef) - -> @str { - unsafe { - match type_has_name(names, ty) { - option::Some(n) => return n, - _ => {} + pub fn find_name<'r>(&'r self, ty: &Type) -> Option<&'r str> { + match self.type_names.find(&ty.to_ref()) { + Some(a) => Some(a.slice(0, a.len())), + None => None } + } - let outer = vec::append_one(outer0.to_vec(), ty); + pub fn find_type(&self, s: &str) -> Option<Type> { + self.named_types.find_equiv(&s).map_consume(|x| Type::from_ref(*x)) + } - let kind = llvm::LLVMGetTypeKind(ty); + // We have a depth count, because we seem to make infinite types. + pub fn type_to_str_depth(&self, ty: Type, depth: int) -> ~str { + match self.find_name(&ty) { + option::Some(name) => return name.to_owned(), + None => () + } - fn tys_str(names: @TypeNames, outer: &[TypeRef], - tys: ~[TypeRef]) -> @str { - let mut s = ~""; - let mut first: bool = true; - for tys.each |t| { - if first { first = false; } else { s += ", "; } - s += type_to_str_inner(names, outer, *t); - } - // [Note at-str] FIXME #2543: Could rewrite this without the copy, - // but need better @str support. - return s.to_managed(); + if depth == 0 { + return ~"###"; } - match kind { - Void => return @"Void", - Half => return @"Half", - Float => return @"Float", - Double => return @"Double", - X86_FP80 => return @"X86_FP80", - FP128 => return @"FP128", - PPC_FP128 => return @"PPC_FP128", - Label => return @"Label", - Integer => { - // See [Note at-str] - return fmt!("i%d", llvm::LLVMGetIntTypeWidth(ty) - as int).to_managed(); - } - Function => { - let out_ty: TypeRef = llvm::LLVMGetReturnType(ty); - let n_args = llvm::LLVMCountParamTypes(ty) as uint; - let args = vec::from_elem(n_args, 0 as TypeRef); - llvm::LLVMGetParamTypes(ty, vec::raw::to_ptr(args)); - // See [Note at-str] - return fmt!("fn(%s) -> %s", - tys_str(names, outer, args), - type_to_str_inner(names, outer, out_ty)).to_managed(); - } - Struct => { - let elts = struct_tys(ty); - // See [Note at-str] - return fmt!("{%s}", tys_str(names, outer, elts)).to_managed(); - } - Array => { - let el_ty = llvm::LLVMGetElementType(ty); - // See [Note at-str] - return fmt!("[%s@ x %u", type_to_str_inner(names, outer, el_ty), - llvm::LLVMGetArrayLength(ty) as uint).to_managed(); - } - Pointer => { - let mut i = 0; - for outer0.each |tout| { - i += 1; - if *tout as int == ty as int { - let n = outer0.len() - i; - // See [Note at-str] - return fmt!("*\\%d", n as int).to_managed(); + unsafe { + let kind = ty.kind(); + + match kind { + Void => ~"Void", + Half => ~"Half", + Float => ~"Float", + Double => ~"Double", + X86_FP80 => ~"X86_FP80", + FP128 => ~"FP128", + PPC_FP128 => ~"PPC_FP128", + Label => ~"Label", + Vector => ~"Vector", + Metadata => ~"Metadata", + X86_MMX => ~"X86_MMAX", + Integer => { + fmt!("i%d", llvm::LLVMGetIntTypeWidth(ty.to_ref()) as int) } - } - let addrstr = { - let addrspace = llvm::LLVMGetPointerAddressSpace(ty) as uint; - if addrspace == 0 { - ~"" - } else { - fmt!("addrspace(%u)", addrspace) + Function => { + let out_ty = ty.return_type(); + let args = ty.func_params(); + let args = + args.map(|&ty| self.type_to_str_depth(ty, depth-1)).connect(", "); + let out_ty = self.type_to_str_depth(out_ty, depth-1); + fmt!("fn(%s) -> %s", args, out_ty) + } + Struct => { + let tys = ty.field_types(); + let tys = tys.map(|&ty| self.type_to_str_depth(ty, depth-1)).connect(", "); + fmt!("{%s}", tys) + } + Array => { + let el_ty = ty.element_type(); + let el_ty = self.type_to_str_depth(el_ty, depth-1); + let len = ty.array_length(); + fmt!("[%s x %u]", el_ty, len) } - }; - // See [Note at-str] - return fmt!("%s*%s", addrstr, type_to_str_inner(names, - outer, - llvm::LLVMGetElementType(ty))).to_managed(); - } - Vector => return @"Vector", - Metadata => return @"Metadata", - X86_MMX => return @"X86_MMAX", - _ => fail!() + Pointer => { + let el_ty = ty.element_type(); + let el_ty = self.type_to_str_depth(el_ty, depth-1); + fmt!("*%s", el_ty) + } + _ => fail!("Unknown Type Kind (%u)", kind as uint) + } } } -} -pub fn float_width(llt: TypeRef) -> uint { - unsafe { - return match llvm::LLVMGetTypeKind(llt) as int { - 1 => 32u, - 2 => 64u, - 3 => 80u, - 4 | 5 => 128u, - _ => fail!("llvm_float_width called on a non-float type") - }; + pub fn type_to_str(&self, ty: Type) -> ~str { + self.type_to_str_depth(ty, 30) } -} -pub fn fn_ty_param_tys(fn_ty: TypeRef) -> ~[TypeRef] { - unsafe { - let args = vec::from_elem(llvm::LLVMCountParamTypes(fn_ty) as uint, - 0 as TypeRef); - llvm::LLVMGetParamTypes(fn_ty, vec::raw::to_ptr(args)); - return args; - } -} - -pub fn struct_tys(struct_ty: TypeRef) -> ~[TypeRef] { - unsafe { - let n_elts = llvm::LLVMCountStructElementTypes(struct_ty) as uint; - if n_elts == 0 { - return ~[]; + pub fn val_to_str(&self, val: ValueRef) -> ~str { + unsafe { + let ty = Type::from_ref(llvm::LLVMTypeOf(val)); + self.type_to_str(ty) } - let mut elts = vec::from_elem(n_elts, ptr::null()); - llvm::LLVMGetStructElementTypes(struct_ty, &mut elts[0]); - return elts; } } @@ -2281,7 +2226,7 @@ pub struct target_data_res { } impl Drop for target_data_res { - fn finalize(&self) { + fn drop(&self) { unsafe { llvm::LLVMDisposeTargetData(self.TD); } @@ -2318,7 +2263,7 @@ pub struct pass_manager_res { } impl Drop for pass_manager_res { - fn finalize(&self) { + fn drop(&self) { unsafe { llvm::LLVMDisposePassManager(self.PM); } @@ -2354,7 +2299,7 @@ pub struct object_file_res { } impl Drop for object_file_res { - fn finalize(&self) { + fn drop(&self) { unsafe { llvm::LLVMDisposeObjectFile(self.ObjectFile); } @@ -2391,7 +2336,7 @@ pub struct section_iter_res { } impl Drop for section_iter_res { - fn finalize(&self) { + fn drop(&self) { unsafe { llvm::LLVMDisposeSectionIterator(self.SI); } diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 9426cd6041d..ddd07c2cb27 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -7,7 +7,7 @@ // <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. - +use std::cast; // EBML enum definitions and utils shared by the encoder and decoder @@ -111,6 +111,7 @@ pub static tag_items_data_item_reexport_def_id: uint = 0x4e; pub static tag_items_data_item_reexport_name: uint = 0x4f; // used to encode crate_ctxt side tables +#[deriving(Eq)] pub enum astencode_tag { // Reserves 0x50 -- 0x6f tag_ast = 0x50, @@ -136,6 +137,16 @@ pub enum astencode_tag { // Reserves 0x50 -- 0x6f tag_table_moves_map = 0x63, tag_table_capture_map = 0x64 } +static first_astencode_tag : uint = tag_ast as uint; +static last_astencode_tag : uint = tag_table_capture_map as uint; +impl astencode_tag { + pub fn from_uint(value : uint) -> Option<astencode_tag> { + let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag; + if !is_a_tag { None } else { + Some(unsafe { cast::transmute(value as int) }) + } + } +} pub static tag_item_trait_method_sort: uint = 0x70; @@ -164,6 +175,10 @@ pub static tag_item_method_tps: uint = 0x7b; pub static tag_item_method_fty: uint = 0x7c; pub static tag_item_method_transformed_self_ty: uint = 0x7d; +pub static tag_mod_child: uint = 0x7e; +pub static tag_misc_info: uint = 0x7f; +pub static tag_misc_info_crate_items: uint = 0x80; + pub struct LinkMeta { name: @str, vers: @str, diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index e95c841b9f7..2a712b07564 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -10,15 +10,13 @@ //! Validates all used crates and extern libraries and loads their metadata -use core::prelude::*; use metadata::cstore; use metadata::decoder; use metadata::filesearch::FileSearch; use metadata::loader; -use core::hashmap::HashMap; -use core::vec; +use std::hashmap::HashMap; use syntax::attr; use syntax::codemap::{span, dummy_sp}; use syntax::diagnostic::span_handler; @@ -30,7 +28,7 @@ use syntax::ast; // Traverses an AST, reading all the information about use'd crates and extern // libraries necessary for later resolving, typechecking, linking, etc. pub fn read_crates(diag: @span_handler, - crate: @ast::crate, + crate: &ast::crate, cstore: @mut cstore::CStore, filesearch: @FileSearch, os: loader::os, @@ -53,8 +51,8 @@ pub fn read_crates(diag: @span_handler, .. *visit::default_simple_visitor()}); visit_crate(e, crate); visit::visit_crate(crate, ((), v)); - dump_crates(e.crate_cache); - warn_if_multiple_versions(e, diag, e.crate_cache); + dump_crates(*e.crate_cache); + warn_if_multiple_versions(e, diag, *e.crate_cache); } struct cache_entry { @@ -64,9 +62,9 @@ struct cache_entry { metas: @~[@ast::meta_item] } -fn dump_crates(crate_cache: @mut ~[cache_entry]) { +fn dump_crates(crate_cache: &[cache_entry]) { debug!("resolved crates:"); - for crate_cache.each |entry| { + for crate_cache.iter().advance |entry| { debug!("cnum: %?", entry.cnum); debug!("span: %?", entry.span); debug!("hash: %?", entry.hash); @@ -75,33 +73,31 @@ fn dump_crates(crate_cache: @mut ~[cache_entry]) { fn warn_if_multiple_versions(e: @mut Env, diag: @span_handler, - crate_cache: @mut ~[cache_entry]) { - use core::either::*; - - let crate_cache = &mut *crate_cache; + crate_cache: &[cache_entry]) { + use std::either::*; if crate_cache.len() != 0u { let name = loader::crate_name_from_metas( *crate_cache[crate_cache.len() - 1].metas ); - let (matches, non_matches) = - partition(crate_cache.map_to_vec(|&entry| { - let othername = loader::crate_name_from_metas( - copy *entry.metas); - if name == othername { - Left(entry) - } else { - Right(entry) - } - })); + let vec: ~[Either<cache_entry, cache_entry>] = crate_cache.iter().transform(|&entry| { + let othername = loader::crate_name_from_metas( + copy *entry.metas); + if name == othername { + Left(entry) + } else { + Right(entry) + } + }).collect(); + let (matches, non_matches) = partition(vec); assert!(!matches.is_empty()); if matches.len() != 1u { diag.handler().warn( fmt!("using multiple versions of crate `%s`", name)); - for matches.each |match_| { + for matches.iter().advance |match_| { diag.span_note(match_.span, "used here"); let attrs = ~[ attr::mk_attr(attr::mk_list_item( @@ -111,7 +107,7 @@ fn warn_if_multiple_versions(e: @mut Env, } } - warn_if_multiple_versions(e, diag, @mut non_matches); + warn_if_multiple_versions(e, diag, non_matches); } } @@ -126,11 +122,11 @@ struct Env { intr: @ident_interner } -fn visit_crate(e: @mut Env, c: &ast::crate) { +fn visit_crate(e: &Env, c: &ast::crate) { let cstore = e.cstore; let link_args = attr::find_attrs_by_name(c.node.attrs, "link_args"); - for link_args.each |a| { + for link_args.iter().advance |a| { match attr::get_meta_item_value_str(attr::attr_meta(*a)) { Some(ref linkarg) => { cstore::add_used_link_args(cstore, *linkarg); @@ -152,7 +148,7 @@ fn visit_view_item(e: @mut Env, i: @ast::view_item) { } } -fn visit_item(e: @mut Env, i: @ast::item) { +fn visit_item(e: &Env, i: @ast::item) { match i.node { ast::item_foreign_mod(ref fm) => { if fm.abis.is_rust() || fm.abis.is_intrinsic() { @@ -191,7 +187,7 @@ fn visit_item(e: @mut Env, i: @ast::item) { ast::anonymous => { /* do nothing */ } } - for link_args.each |a| { + for link_args.iter().advance |a| { match attr::get_meta_item_value_str(attr::attr_meta(*a)) { Some(linkarg) => { cstore::add_used_link_args(cstore, linkarg); @@ -204,14 +200,13 @@ fn visit_item(e: @mut Env, i: @ast::item) { } } -fn metas_with(ident: @str, key: @str, metas: ~[@ast::meta_item]) +fn metas_with(ident: @str, key: @str, mut metas: ~[@ast::meta_item]) -> ~[@ast::meta_item] { let name_items = attr::find_meta_items_by_name(metas, key); if name_items.is_empty() { - vec::append_one(metas, attr::mk_name_value_item_str(key, ident)) - } else { - metas + metas.push(attr::mk_name_value_item_str(key, ident)); } + metas } fn metas_with_ident(ident: @str, metas: ~[@ast::meta_item]) @@ -219,11 +214,11 @@ fn metas_with_ident(ident: @str, metas: ~[@ast::meta_item]) metas_with(ident, @"name", metas) } -fn existing_match(e: @mut Env, metas: &[@ast::meta_item], hash: @str) +fn existing_match(e: &Env, metas: &[@ast::meta_item], hash: &str) -> Option<int> { - for e.crate_cache.each |c| { + for e.crate_cache.iter().advance |c| { if loader::metadata_matches(*c.metas, metas) - && (hash.is_empty() || c.hash == hash) { + && (hash.is_empty() || c.hash.as_slice() == hash) { return Some(c.cnum); } } @@ -303,7 +298,8 @@ fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { // The map from crate numbers in the crate we're resolving to local crate // numbers let mut cnum_map = HashMap::new(); - for decoder::get_crate_deps(cdata).each |dep| { + let r = decoder::get_crate_deps(cdata); + for r.iter().advance |dep| { let extrn_cnum = dep.cnum; let cname = dep.name; let cname_str = token::ident_to_str(&dep.name); diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 5b154f6836c..f336b0f4e4c 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -10,7 +10,6 @@ // Searching for information from the cstore -use core::prelude::*; use metadata::common::*; use metadata::cstore; @@ -18,17 +17,12 @@ use metadata::decoder; use metadata; use middle::{ty, resolve}; -use core::vec; +use std::vec; use reader = extra::ebml::reader; use syntax::ast; use syntax::ast_map; use syntax::diagnostic::expect; -pub struct ProvidedTraitMethodInfo { - ty: ty::Method, - def_id: ast::def_id -} - pub struct StaticMethodInfo { ident: ast::ident, def_id: ast::def_id, @@ -102,18 +96,14 @@ pub fn get_enum_variants(tcx: ty::ctxt, def: ast::def_id) return decoder::get_enum_variants(cstore.intr, cdata, def.node, tcx) } -pub fn get_impls_for_mod(cstore: @mut cstore::CStore, def: ast::def_id, - name: Option<ast::ident>) - -> @~[@resolve::Impl] { - let cdata = cstore::get_crate_data(cstore, def.crate); - do decoder::get_impls_for_mod(cstore.intr, cdata, def.node, name) |cnum| { - cstore::get_crate_data(cstore, cnum) - } +/// Returns information about the given implementation. +pub fn get_impl(cstore: @mut cstore::CStore, impl_def_id: ast::def_id) + -> resolve::Impl { + let cdata = cstore::get_crate_data(cstore, impl_def_id.crate); + decoder::get_impl(cstore.intr, cdata, impl_def_id.node) } -pub fn get_method(tcx: ty::ctxt, - def: ast::def_id) -> ty::Method -{ +pub fn get_method(tcx: ty::ctxt, def: ast::def_id) -> ty::Method { let cdata = cstore::get_crate_data(tcx.cstore, def.crate); decoder::get_method(tcx.cstore.intr, cdata, def.node, tcx) } @@ -134,7 +124,7 @@ pub fn get_trait_method_def_ids(cstore: @mut cstore::CStore, pub fn get_provided_trait_methods(tcx: ty::ctxt, def: ast::def_id) - -> ~[ProvidedTraitMethodInfo] { + -> ~[@ty::Method] { let cstore = tcx.cstore; let cdata = cstore::get_crate_data(cstore, def.crate); decoder::get_provided_trait_methods(cstore.intr, cdata, def.node, tcx) @@ -229,7 +219,7 @@ pub fn get_impl_trait(tcx: ty::ctxt, pub fn get_impl_method(cstore: @mut cstore::CStore, def: ast::def_id, mname: ast::ident) - -> ast::def_id { + -> Option<ast::def_id> { let cdata = cstore::get_crate_data(cstore, def.crate); decoder::get_impl_method(cstore.intr, cdata, def.node, mname) } diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 2819340ae45..3413cd341ba 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -12,13 +12,11 @@ // The crate store - a central repo for information collected about external // crates and libraries -use core::prelude::*; use metadata::cstore; use metadata::decoder; -use core::hashmap::HashMap; -use core::vec; +use std::hashmap::HashMap; use extra; use syntax::ast; use syntax::parse::token::ident_interner; @@ -86,13 +84,13 @@ pub fn have_crate_data(cstore: &CStore, cnum: ast::crate_num) -> bool { pub fn iter_crate_data(cstore: &CStore, i: &fn(ast::crate_num, @crate_metadata)) { - for cstore.metas.each |&k, &v| { + for cstore.metas.iter().advance |(&k, &v)| { i(k, v); } } pub fn add_used_crate_file(cstore: &mut CStore, lib: &Path) { - if !vec::contains(cstore.used_crate_files, lib) { + if !cstore.used_crate_files.contains(lib) { cstore.used_crate_files.push(copy *lib); } } @@ -104,7 +102,7 @@ pub fn get_used_crate_files(cstore: &CStore) -> ~[Path] { pub fn add_used_library(cstore: &mut CStore, lib: @str) -> bool { assert!(!lib.is_empty()); - if cstore.used_libraries.contains(&lib) { return false; } + if cstore.used_libraries.iter().any_(|x| x == &lib) { return false; } cstore.used_libraries.push(lib); true } @@ -160,7 +158,7 @@ pub fn get_dep_hashes(cstore: &CStore) -> ~[@str] { }; debug!("sorted:"); - for sorted.each |x| { + for sorted.iter().advance |x| { debug!(" hash[%s]: %s", x.name, x.hash); } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index fdef25b5e71..2c7a991f614 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -10,11 +10,10 @@ // Decoding metadata from a single crate's metadata -use core::prelude::*; use metadata::cstore::crate_metadata; use metadata::common::*; -use metadata::csearch::{ProvidedTraitMethodInfo, StaticMethodInfo}; +use metadata::csearch::StaticMethodInfo; use metadata::csearch; use metadata::cstore; use metadata::decoder; @@ -23,19 +22,18 @@ use metadata::tydecode::{parse_ty_data, parse_def_id, parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::{ty, resolve}; -use core::hash::HashUtil; -use core::int; -use core::io::WriterUtil; -use core::io; -use core::option; -use core::str; -use core::vec; +use std::hash::HashUtil; +use std::int; +use std::io::WriterUtil; +use std::io; +use std::option; +use std::str; +use std::vec; use extra::ebml::reader; use extra::ebml; use extra::serialize::Decodable; use syntax::ast_map; use syntax::attr; -use syntax::diagnostic::span_handler; use syntax::parse::token::{ident_interner, special_idents}; use syntax::print::pprust; use syntax::{ast, ast_util}; @@ -61,7 +59,7 @@ fn lookup_hash(d: ebml::Doc, eq_fn: &fn(x:&[u8]) -> bool, hash: uint) -> let belt = tag_index_buckets_bucket_elt; for reader::tagged_docs(tagged_doc.doc, belt) |elt| { let pos = io::u64_from_be_bytes(*elt.data, elt.start, 4u) as uint; - if eq_fn(vec::slice(*elt.data, elt.start + 4u, elt.end)) { + if eq_fn(elt.data.slice(elt.start + 4u, elt.end)) { return Some(reader::doc_at(d.data, pos).doc); } }; @@ -73,7 +71,7 @@ pub type GetCrateDataCb<'self> = &'self fn(ast::crate_num) -> cmd; pub fn maybe_find_item(item_id: int, items: ebml::Doc) -> Option<ebml::Doc> { fn eq_item(bytes: &[u8], item_id: int) -> bool { return io::u64_from_be_bytes( - vec::slice(bytes, 0u, 4u), 0u, 4u) as int + bytes.slice(0u, 4u), 0u, 4u) as int == item_id; } lookup_hash(items, @@ -97,13 +95,12 @@ fn lookup_item(item_id: int, data: @~[u8]) -> ebml::Doc { #[deriving(Eq)] enum Family { - Const, // c + ImmStatic, // c + MutStatic, // b Fn, // f UnsafeFn, // u - PureFn, // p StaticMethod, // F UnsafeStaticMethod, // U - PureStaticMethod, // P ForeignFn, // e Type, // y ForeignType, // T @@ -122,13 +119,12 @@ enum Family { fn item_family(item: ebml::Doc) -> Family { let fam = reader::get_doc(item, tag_items_data_item_family); match reader::doc_as_u8(fam) as char { - 'c' => Const, + 'c' => ImmStatic, + 'b' => MutStatic, 'f' => Fn, 'u' => UnsafeFn, - 'p' => PureFn, 'F' => StaticMethod, 'U' => UnsafeStaticMethod, - 'P' => PureStaticMethod, 'e' => ForeignFn, 'y' => Type, 'T' => ForeignType, @@ -321,11 +317,11 @@ fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num) -> def_like { let fam = item_family(item); match fam { - Const => dl_def(ast::def_const(did)), + ImmStatic => dl_def(ast::def_static(did, false)), + MutStatic => dl_def(ast::def_static(did, true)), Struct => dl_def(ast::def_struct(did)), UnsafeFn => dl_def(ast::def_fn(did, ast::unsafe_fn)), Fn => dl_def(ast::def_fn(did, ast::impure_fn)), - PureFn => dl_def(ast::def_fn(did, ast::pure_fn)), ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)), UnsafeStaticMethod => { let trait_did_opt = translated_parent_item_opt(cnum, item); @@ -335,10 +331,6 @@ fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num) let trait_did_opt = translated_parent_item_opt(cnum, item); dl_def(ast::def_static_method(did, trait_did_opt, ast::impure_fn)) } - PureStaticMethod => { - let trait_did_opt = translated_parent_item_opt(cnum, item); - dl_def(ast::def_static_method(did, trait_did_opt, ast::pure_fn)) - } Type | ForeignType => dl_def(ast::def_ty(did)), Mod => dl_def(ast::def_mod(did)), ForeignMod => dl_def(ast::def_foreign_mod(did)), @@ -415,7 +407,7 @@ pub fn get_impl_trait(cdata: cmd, } pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, - name: ast::ident) -> ast::def_id { + name: ast::ident) -> Option<ast::def_id> { let items = reader::get_doc(reader::Doc(cdata.data), tag_items); let mut found = None; for reader::tagged_docs(find_item(id, items), tag_item_impl_method) @@ -425,7 +417,7 @@ pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, found = Some(translate_def_id(cdata, m_did)); } } - found.get() + found } pub fn get_symbol(data: @~[u8], id: ast::node_id) -> ~str { @@ -465,64 +457,192 @@ pub fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) -> bool { return true; } -/// Iterates over all the paths in the given crate. -pub fn each_path(intr: @ident_interner, - cdata: cmd, - get_crate_data: GetCrateDataCb, - f: &fn(&str, def_like, ast::visibility) -> bool) - -> bool { - // FIXME #4572: This function needs to be nuked, as it's impossible to make fast. - // It's the source of most of the performance problems when compiling small crates. +struct EachItemContext<'self> { + intr: @ident_interner, + cdata: cmd, + get_crate_data: GetCrateDataCb<'self>, + path_builder: &'self mut ~str, + callback: &'self fn(&str, def_like, ast::visibility) -> bool, +} - let root = reader::Doc(cdata.data); - let items = reader::get_doc(root, tag_items); - let items_data = reader::get_doc(items, tag_items_data); - - // First, go through all the explicit items. - for reader::tagged_docs(items_data, tag_items_data_item) |item_doc| { - let path = ast_map::path_to_str(item_path(item_doc), intr); - let path_is_empty = path.is_empty(); - if !path_is_empty { - // Extract the def ID. - let def_id = item_def_id(item_doc, cdata); - - // Construct the def for this item. - debug!("(each_path) yielding explicit item: %s", path); - let def_like = item_to_def_like(item_doc, def_id, cdata.cnum); - - let vis = item_visibility(item_doc); - - // Hand the information off to the iteratee. - if !f(path, def_like, vis) { - return false; +impl<'self> EachItemContext<'self> { + // Pushes the given name and returns the old length. + fn push_name(&mut self, string: &str) -> uint { + let path_len = self.path_builder.len(); + if path_len != 0 { + self.path_builder.push_str("::") + } + self.path_builder.push_str(string); + path_len + } + + // Pops the given name. + fn pop_name(&mut self, old_len: uint) { + // XXX(pcwalton): There's no safe function to do this. :( + unsafe { + str::raw::set_len(self.path_builder, old_len) + } + } + + fn process_item_and_pop_name(&mut self, + doc: ebml::Doc, + def_id: ast::def_id, + old_len: uint) + -> bool { + let def_like = item_to_def_like(doc, def_id, self.cdata.cnum); + match def_like { + dl_def(def) => { + debug!("(iterating over each item of a module) processing \ + `%s` (def %?)", + *self.path_builder, + def); + } + _ => { + debug!("(iterating over each item of a module) processing \ + `%s` (%d:%d)", + *self.path_builder, + def_id.crate, + def_id.node); } } - // If this is a module, find the reexports. - for each_reexport(item_doc) |reexport_doc| { - let def_id_doc = - reader::get_doc(reexport_doc, - tag_items_data_item_reexport_def_id); - let def_id = reader::with_doc_data(def_id_doc, parse_def_id); - let def_id = translate_def_id(cdata, def_id); - - let reexport_name_doc = - reader::get_doc(reexport_doc, - tag_items_data_item_reexport_name); - let reexport_name = reexport_name_doc.as_str_slice(); - - let reexport_path; - if path_is_empty { - reexport_path = reexport_name.to_owned(); + let vis = item_visibility(doc); + + let mut continue = (self.callback)(*self.path_builder, def_like, vis); + + let family = item_family(doc); + if family == ForeignMod { + // These are unnamed; pop the name now. + self.pop_name(old_len) + } + + if continue { + // Recurse if necessary. + match family { + Mod | ForeignMod | Trait | Impl => { + continue = self.each_item_of_module(def_id); + } + ImmStatic | MutStatic | Struct | UnsafeFn | Fn | ForeignFn | + UnsafeStaticMethod | StaticMethod | Type | ForeignType | + Variant | Enum | PublicField | PrivateField | + InheritedField => {} + } + } + + if family != ForeignMod { + self.pop_name(old_len) + } + + continue + } + + fn each_item_of_module(&mut self, def_id: ast::def_id) -> bool { + // This item might not be in this crate. If it's not, look it up. + let (_cdata, items) = if def_id.crate == self.cdata.cnum { + let items = reader::get_doc(reader::Doc(self.cdata.data), + tag_items); + (self.cdata, items) + } else { + let crate_data = (self.get_crate_data)(def_id.crate); + let root = reader::Doc(crate_data.data); + (crate_data, reader::get_doc(root, tag_items)) + }; + + // Look up the item. + let item_doc = match maybe_find_item(def_id.node, items) { + None => return false, + Some(item_doc) => item_doc, + }; + + self.each_child_of_module_or_crate(item_doc) + } + + fn each_child_of_module_or_crate(&mut self, item_doc: ebml::Doc) -> bool { + let mut continue = true; + + // Iterate over all children. + for reader::tagged_docs(item_doc, tag_mod_child) |child_info_doc| { + let child_def_id = reader::with_doc_data(child_info_doc, + parse_def_id); + let child_def_id = translate_def_id(self.cdata, child_def_id); + + // This item may be in yet another crate, if it was the child of + // a reexport. + let other_crates_items = if child_def_id.crate == + self.cdata.cnum { + reader::get_doc(reader::Doc(self.cdata.data), tag_items) } else { - reexport_path = path + "::" + reexport_name; + let crate_data = (self.get_crate_data)(child_def_id.crate); + let root = reader::Doc(crate_data.data); + reader::get_doc(root, tag_items) + }; + + debug!("(iterating over each item of a module) looking up item \ + %d:%d in `%s`, crate %d", + child_def_id.crate, + child_def_id.node, + *self.path_builder, + self.cdata.cnum); + + // Get the item. + match maybe_find_item(child_def_id.node, other_crates_items) { + None => {} + Some(child_item_doc) => { + // Push the name. + let child_name = item_name(self.intr, child_item_doc); + debug!("(iterating over each item of a module) pushing \ + name `%s` onto `%s`", + token::ident_to_str(&child_name), + *self.path_builder); + let old_len = + self.push_name(token::ident_to_str(&child_name)); + + // Process this item. + continue = self.process_item_and_pop_name(child_item_doc, + child_def_id, + old_len); + + if !continue { + break + } + } } + } - // This reexport may be in yet another crate - let other_crates_items = if def_id.crate == cdata.cnum { - items + if !continue { + return false + } + + // Iterate over reexports. + for each_reexport(item_doc) |reexport_doc| { + let def_id_doc = reader::get_doc( + reexport_doc, + tag_items_data_item_reexport_def_id); + let orig_def_id = reader::with_doc_data(def_id_doc, parse_def_id); + + // NB: was "cdata" + let def_id = translate_def_id(self.cdata, orig_def_id); + + let name_doc = reader::get_doc(reexport_doc, + tag_items_data_item_reexport_name); + let name = name_doc.as_str_slice(); + + // Push the name. + debug!("(iterating over each item of a module) pushing \ + reexported name `%s` onto `%s` (crate %d, orig %d, \ + in crate %d)", + name, + *self.path_builder, + def_id.crate, + orig_def_id.crate, + self.cdata.cnum); + let old_len = self.push_name(name); + + // This reexport may be in yet another crate. + let other_crates_items = if def_id.crate == self.cdata.cnum { + reader::get_doc(reader::Doc(self.cdata.data), tag_items) } else { - let crate_data = get_crate_data(def_id.crate); + let crate_data = (self.get_crate_data)(def_id.crate); let root = reader::Doc(crate_data.data); reader::get_doc(root, tag_items) }; @@ -530,29 +650,53 @@ pub fn each_path(intr: @ident_interner, // Get the item. match maybe_find_item(def_id.node, other_crates_items) { None => {} - Some(item_doc) => { - // Construct the def for this item. - let def_like = item_to_def_like(item_doc, - def_id, - cdata.cnum); - - // Hand the information off to the iteratee. - debug!("(each_path) yielding reexported \ - item: %s", reexport_path); - - if (!f(reexport_path, def_like, ast::public)) { - return false; - } + Some(reexported_item_doc) => { + continue = self.process_item_and_pop_name( + reexported_item_doc, + def_id, + old_len); } } + + if !continue { + break + } } + + continue } +} - return true; +/// Iterates over all the paths in the given crate. +pub fn each_path(intr: @ident_interner, + cdata: cmd, + get_crate_data: GetCrateDataCb, + f: &fn(&str, def_like, ast::visibility) -> bool) + -> bool { + // FIXME #4572: This function needs to be nuked, as it's impossible to + // make fast. It's the source of most of the performance problems when + // compiling small crates. + + let root_doc = reader::Doc(cdata.data); + let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); + let crate_items_doc = reader::get_doc(misc_info_doc, + tag_misc_info_crate_items); + + let mut path_builder = ~""; + + let mut context = EachItemContext { + intr: intr, + cdata: cdata, + get_crate_data: get_crate_data, + path_builder: &mut path_builder, + callback: f, + }; + + // Iterate over all top-level crate items. + context.each_child_of_module_or_crate(crate_items_doc) } -pub fn get_item_path(cdata: cmd, id: ast::node_id) - -> ast_map::path { +pub fn get_item_path(cdata: cmd, id: ast::node_id) -> ast_map::path { item_path(lookup_item(id, cdata.data)) } @@ -598,7 +742,7 @@ pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::node_id, let mut infos: ~[ty::VariantInfo] = ~[]; let variant_ids = enum_variant_ids(item, cdata); let mut disr_val = 0; - for variant_ids.each |did| { + for variant_ids.iter().advance |did| { let item = find_item(did.node, items); let ctor_ty = item_type(ast::def_id { crate: cdata.cnum, node: id}, item, tcx, cdata); @@ -641,7 +785,7 @@ fn get_explicit_self(item: ebml::Doc) -> ast::explicit_self_ { 's' => { return ast::sty_static; } 'v' => { return ast::sty_value; } '@' => { return ast::sty_box(get_mutability(string[1])); } - '~' => { return ast::sty_uniq(get_mutability(string[1])); } + '~' => { return ast::sty_uniq; } '&' => { // FIXME(#4846) expl. region return ast::sty_region(None, get_mutability(string[1])); @@ -668,35 +812,20 @@ fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc, rslt } -pub fn get_impls_for_mod(intr: @ident_interner, - cdata: cmd, - m_id: ast::node_id, - name: Option<ast::ident>, - get_cdata: &fn(ast::crate_num) -> cmd) - -> @~[@resolve::Impl] { +/// Returns information about the given implementation. +pub fn get_impl(intr: @ident_interner, cdata: cmd, impl_id: ast::node_id) + -> resolve::Impl { let data = cdata.data; - let mod_item = lookup_item(m_id, data); - let mut result = ~[]; - for reader::tagged_docs(mod_item, tag_mod_impl) |doc| { - let did = reader::with_doc_data(doc, parse_def_id); - let local_did = translate_def_id(cdata, did); - debug!("(get impls for mod) getting did %? for '%?'", - local_did, name); - // The impl may be defined in a different crate. Ask the caller - // to give us the metadata - let impl_cdata = get_cdata(local_did.crate); - let impl_data = impl_cdata.data; - let item = lookup_item(local_did.node, impl_data); - let nm = item_name(intr, item); - if match name { Some(n) => { n == nm } None => { true } } { - let base_tps = item_ty_param_count(item); - result.push(@resolve::Impl { - did: local_did, ident: nm, - methods: item_impl_methods(intr, impl_cdata, item, base_tps) - }); - }; + let impl_item = lookup_item(impl_id, data); + let base_tps = item_ty_param_count(impl_item); + resolve::Impl { + did: ast::def_id { + crate: cdata.cnum, + node: impl_id, + }, + ident: item_name(intr, impl_item), + methods: item_impl_methods(intr, cdata, impl_item, base_tps), } - @result } pub fn get_method_name_and_explicit_self( @@ -750,51 +879,18 @@ pub fn get_trait_method_def_ids(cdata: cmd, pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, id: ast::node_id, tcx: ty::ctxt) -> - ~[ProvidedTraitMethodInfo] { + ~[@ty::Method] { let data = cdata.data; let item = lookup_item(id, data); let mut result = ~[]; - for reader::tagged_docs(item, tag_item_trait_method) |mth| { - if item_method_sort(mth) != 'p' { loop; } - - let did = item_def_id(mth, cdata); - - let type_param_defs = - item_ty_param_defs(mth, tcx, cdata, - tag_items_data_item_ty_param_bounds); - let name = item_name(intr, mth); - let ty = doc_type(mth, tcx, cdata); - - let fty = match ty::get(ty).sty { - ty::ty_bare_fn(ref f) => copy *f, - _ => { - tcx.diag.handler().bug("get_provided_trait_methods(): id \ - has non-function type"); - } - }; + for reader::tagged_docs(item, tag_item_trait_method) |mth_id| { + let did = item_def_id(mth_id, cdata); + let mth = lookup_item(did.node, data); - let transformed_self_ty = doc_transformed_self_ty(mth, tcx, cdata); - let explicit_self = get_explicit_self(mth); - - let ty_method = ty::Method::new( - name, - ty::Generics { - type_param_defs: type_param_defs, - region_param: None - }, - transformed_self_ty, - fty, - explicit_self, - ast::public, - did - ); - let provided_trait_method_info = ProvidedTraitMethodInfo { - ty: ty_method, - def_id: did - }; + if item_method_sort(mth) != 'p' { loop; } - vec::push(&mut result, provided_trait_method_info); + result.push(@get_method(intr, cdata, did.node, tcx)); } return result; @@ -845,16 +941,15 @@ pub fn get_static_methods_if_impl(intr: @ident_interner, } let mut static_impl_methods = ~[]; - for impl_method_ids.each |impl_method_id| { + for impl_method_ids.iter().advance |impl_method_id| { let impl_method_doc = lookup_item(impl_method_id.node, cdata.data); let family = item_family(impl_method_doc); match family { - StaticMethod | UnsafeStaticMethod | PureStaticMethod => { + StaticMethod | UnsafeStaticMethod => { let purity; match item_family(impl_method_doc) { StaticMethod => purity = ast::impure_fn, UnsafeStaticMethod => purity = ast::unsafe_fn, - PureStaticMethod => purity = ast::pure_fn, _ => fail!() } @@ -927,8 +1022,8 @@ pub fn get_item_visibility(cdata: cmd, id: ast::node_id) fn family_has_type_params(fam: Family) -> bool { match fam { - Const | ForeignType | Mod | ForeignMod | PublicField | PrivateField - | ForeignFn => false, + ImmStatic | ForeignType | Mod | ForeignMod | PublicField | PrivateField + | ForeignFn | MutStatic => false, _ => true } } @@ -958,13 +1053,12 @@ fn describe_def(items: ebml::Doc, id: ast::def_id) -> ~str { fn item_family_to_str(fam: Family) -> ~str { match fam { - Const => ~"const", + ImmStatic => ~"static", + MutStatic => ~"static mut", Fn => ~"fn", UnsafeFn => ~"unsafe fn", - PureFn => ~"pure fn", StaticMethod => ~"static method", UnsafeStaticMethod => ~"unsafe static method", - PureStaticMethod => ~"pure static method", ForeignFn => ~"foreign fn", Type => ~"type", ForeignType => ~"foreign type", @@ -1035,7 +1129,8 @@ fn get_attributes(md: ebml::Doc) -> ~[ast::attribute] { fn list_meta_items(intr: @ident_interner, meta_items: ebml::Doc, out: @io::Writer) { - for get_meta_items(meta_items).each |mi| { + let r = get_meta_items(meta_items); + for r.iter().advance |mi| { out.write_str(fmt!("%s\n", pprust::meta_item_to_str(*mi, intr))); } } @@ -1044,7 +1139,8 @@ fn list_crate_attributes(intr: @ident_interner, md: ebml::Doc, hash: &str, out: @io::Writer) { out.write_str(fmt!("=Crate Attributes (%s)=\n", hash)); - for get_attributes(md).each |attr| { + let r = get_attributes(md); + for r.iter().advance |attr| { out.write_str(fmt!("%s\n", pprust::attribute_to_str(*attr, intr))); } @@ -1084,7 +1180,8 @@ pub fn get_crate_deps(data: @~[u8]) -> ~[crate_dep] { fn list_crate_deps(data: @~[u8], out: @io::Writer) { out.write_str("=External Dependencies=\n"); - for get_crate_deps(data).each |dep| { + let r = get_crate_deps(data); + for r.iter().advance |dep| { out.write_str( fmt!("%d %s-%s-%s\n", dep.cnum, token::ident_to_str(&dep.name), dep.hash, dep.vers)); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 5d5d7582b5f..77a8d1792db 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -10,25 +10,23 @@ // Metadata encoding -use core::prelude::*; use metadata::common::*; use metadata::cstore; use metadata::decoder; use metadata::tyencode; -use middle::trans::reachable; use middle::ty::node_id_to_type; use middle::ty; use middle; use util::ppaux::ty_to_str; -use core::hash::HashUtil; -use core::hashmap::HashMap; -use core::int; -use core::io; -use core::str; -use core::uint; -use core::vec; +use std::hash::HashUtil; +use std::hashmap::{HashMap, HashSet}; +use std::int; +use std::io; +use std::str; +use std::uint; +use std::vec; use extra::flate; use extra::serialize::Encodable; use extra; @@ -47,7 +45,7 @@ use syntax::parse::token; use syntax; use writer = extra::ebml::writer; -use core::cast; +use std::cast; // used by astencode: type abbrev_map = @mut HashMap<ty::t, tyencode::ty_abbrev>; @@ -60,13 +58,13 @@ pub type encode_inlined_item<'self> = &'self fn(ecx: &EncodeContext, pub struct EncodeParams<'self> { diag: @span_handler, tcx: ty::ctxt, - reachable: reachable::map, reexports2: middle::resolve::ExportMap2, item_symbols: &'self HashMap<ast::node_id, ~str>, discrim_symbols: &'self HashMap<ast::node_id, @str>, link_meta: &'self LinkMeta, cstore: @mut cstore::CStore, - encode_inlined_item: encode_inlined_item<'self> + encode_inlined_item: encode_inlined_item<'self>, + reachable: @mut HashSet<ast::node_id>, } struct Stats { @@ -75,6 +73,7 @@ struct Stats { dep_bytes: uint, lang_item_bytes: uint, link_args_bytes: uint, + misc_bytes: uint, item_bytes: uint, index_bytes: uint, zero_bytes: uint, @@ -87,14 +86,14 @@ pub struct EncodeContext<'self> { diag: @span_handler, tcx: ty::ctxt, stats: @mut Stats, - reachable: reachable::map, reexports2: middle::resolve::ExportMap2, item_symbols: &'self HashMap<ast::node_id, ~str>, discrim_symbols: &'self HashMap<ast::node_id, @str>, link_meta: &'self LinkMeta, cstore: &'self cstore::CStore, encode_inlined_item: encode_inlined_item<'self>, - type_abbrevs: abbrev_map + type_abbrevs: abbrev_map, + reachable: @mut HashSet<ast::node_id>, } pub fn reachable(ecx: &EncodeContext, id: node_id) -> bool { @@ -152,13 +151,12 @@ fn encode_trait_ref(ebml_w: &mut writer::Encoder, ecx: &EncodeContext, trait_ref: &ty::TraitRef, tag: uint) { - let r = ecx.reachable; let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs) + }; ebml_w.start_tag(tag); tyencode::enc_trait_ref(ebml_w.writer, ty_str_ctxt, trait_ref); @@ -180,14 +178,13 @@ fn encode_ty_type_param_defs(ebml_w: &mut writer::Encoder, ecx: &EncodeContext, params: @~[ty::TypeParameterDef], tag: uint) { - let r = ecx.reachable; let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; - for params.each |param| { + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs) + }; + for params.iter().advance |param| { ebml_w.start_tag(tag); tyencode::enc_type_param_def(ebml_w.writer, ty_str_ctxt, param); ebml_w.end_tag(); @@ -213,26 +210,24 @@ fn encode_variant_id(ebml_w: &mut writer::Encoder, vid: def_id) { pub fn write_type(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, typ: ty::t) { - let r = ecx.reachable; let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs) + }; tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ); } pub fn write_vstore(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, vstore: ty::vstore) { - let r = ecx.reachable; let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs) + }; tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore); } @@ -259,13 +254,12 @@ fn encode_method_fty(ecx: &EncodeContext, typ: &ty::BareFnTy) { ebml_w.start_tag(tag_item_method_fty); - let r = ecx.reachable; let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs) + }; tyencode::enc_bare_fn_ty(ebml_w.writer, ty_str_ctxt, typ); ebml_w.end_tag(); @@ -325,7 +319,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext, let mut i = 0; let vi = ty::enum_variants(ecx.tcx, ast::def_id { crate: local_crate, node: id }); - for variants.each |variant| { + for variants.iter().advance |variant| { index.push(entry {val: variant.node.id, pos: ebml_w.writer.tell()}); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(variant.node.id)); @@ -373,7 +367,7 @@ fn encode_path(ecx: &EncodeContext, ebml_w.start_tag(tag_path); ebml_w.wr_tagged_u32(tag_path_len, (path.len() + 1) as u32); - for path.each |pe| { + for path.iter().advance |pe| { encode_path_elt(ecx, ebml_w, *pe); } encode_path_elt(ecx, ebml_w, name); @@ -403,8 +397,8 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext, -> bool { match ecx.tcx.base_impls.find(&exp.def_id) { Some(implementations) => { - for implementations.each |&base_impl| { - for base_impl.methods.each |&m| { + for implementations.iter().advance |&base_impl| { + for base_impl.methods.iter().advance |&m| { if m.explicit_self == ast::sty_static { encode_reexported_static_method(ecx, ebml_w, exp, m.did, m.ident); @@ -424,7 +418,7 @@ fn encode_reexported_static_trait_methods(ecx: &EncodeContext, -> bool { match ecx.tcx.trait_methods_cache.find(&exp.def_id) { Some(methods) => { - for methods.each |&m| { + for methods.iter().advance |&m| { if m.explicit_self == ast::sty_static { encode_reexported_static_method(ecx, ebml_w, exp, m.def_id, m.ident); @@ -473,12 +467,77 @@ fn encode_reexported_static_methods(ecx: &EncodeContext, } } +/// Iterates through "auxiliary node IDs", which are node IDs that describe +/// top-level items that are sub-items of the given item. Specifically: +/// +/// * For enums, iterates through the node IDs of the variants. +/// +/// * For newtype structs, iterates through the node ID of the constructor. +fn each_auxiliary_node_id(item: @item, callback: &fn(node_id) -> bool) + -> bool { + let mut continue = true; + match item.node { + item_enum(ref enum_def, _) => { + for enum_def.variants.iter().advance |variant| { + continue = callback(variant.node.id); + if !continue { + break + } + } + } + item_struct(struct_def, _) => { + // If this is a newtype struct, return the constructor. + match struct_def.ctor_id { + Some(ctor_id) if struct_def.fields.len() > 0 && + struct_def.fields[0].node.kind == + ast::unnamed_field => { + continue = callback(ctor_id); + } + _ => {} + } + } + _ => {} + } + + continue +} + +fn encode_reexports(ecx: &EncodeContext, + ebml_w: &mut writer::Encoder, + id: node_id, + path: &[ast_map::path_elt]) { + debug!("(encoding info for module) encoding reexports for %d", id); + match ecx.reexports2.find(&id) { + Some(ref exports) => { + debug!("(encoding info for module) found reexports for %d", id); + for exports.iter().advance |exp| { + debug!("(encoding info for module) reexport '%s' for %d", + exp.name, id); + ebml_w.start_tag(tag_items_data_item_reexport); + ebml_w.start_tag(tag_items_data_item_reexport_def_id); + ebml_w.wr_str(def_to_str(exp.def_id)); + ebml_w.end_tag(); + ebml_w.start_tag(tag_items_data_item_reexport_name); + ebml_w.wr_str(exp.name); + ebml_w.end_tag(); + ebml_w.end_tag(); + encode_reexported_static_methods(ecx, ebml_w, path, exp); + } + } + None => { + debug!("(encoding info for module) found no reexports for %d", + id); + } + } +} + fn encode_info_for_mod(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, md: &_mod, id: node_id, path: &[ast_map::path_elt], - name: ident) { + name: ident, + vis: visibility) { ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(id)); encode_family(ebml_w, 'm'); @@ -486,7 +545,17 @@ fn encode_info_for_mod(ecx: &EncodeContext, debug!("(encoding info for module) encoding info for module ID %d", id); // Encode info about all the module children. - for md.items.each |item| { + for md.items.iter().advance |item| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(item.id))); + ebml_w.end_tag(); + + for each_auxiliary_node_id(*item) |auxiliary_node_id| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(auxiliary_node_id))); + ebml_w.end_tag(); + } + match item.node { item_impl(*) => { let (ident, did) = (item.ident, item.id); @@ -500,35 +569,16 @@ fn encode_info_for_mod(ecx: &EncodeContext, ebml_w.wr_str(def_to_str(local_def(did))); ebml_w.end_tag(); } - _ => {} // FIXME #4573: Encode these too. + _ => {} } } encode_path(ecx, ebml_w, path, ast_map::path_mod(name)); - // Encode the reexports of this module. - debug!("(encoding info for module) encoding reexports for %d", id); - match ecx.reexports2.find(&id) { - Some(ref exports) => { - debug!("(encoding info for module) found reexports for %d", id); - for exports.each |exp| { - debug!("(encoding info for module) reexport '%s' for %d", - exp.name, id); - ebml_w.start_tag(tag_items_data_item_reexport); - ebml_w.start_tag(tag_items_data_item_reexport_def_id); - ebml_w.wr_str(def_to_str(exp.def_id)); - ebml_w.end_tag(); - ebml_w.start_tag(tag_items_data_item_reexport_name); - ebml_w.wr_str(exp.name); - ebml_w.end_tag(); - ebml_w.end_tag(); - encode_reexported_static_methods(ecx, ebml_w, path, exp); - } - } - None => { - debug!("(encoding info for module) found no reexports for %d", - id); - } + // Encode the reexports of this module, if this module is public. + if vis == public { + debug!("(encoding info for module) encoding reexports for %d", id); + encode_reexports(ecx, ebml_w, id, path); } ebml_w.end_tag(); @@ -574,9 +624,8 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::explic ebml_w.writer.write(&[ '@' as u8 ]); encode_mutability(ebml_w, m); } - sty_uniq(m) => { + sty_uniq => { ebml_w.writer.write(&[ '~' as u8 ]); - encode_mutability(ebml_w, m); } } @@ -617,7 +666,7 @@ fn encode_info_for_struct(ecx: &EncodeContext, let tcx = ecx.tcx; /* We encode both private and public fields -- need to include private fields to get the offsets right */ - for fields.each |field| { + for fields.iter().advance |field| { let (nm, vis) = match field.node.kind { named_field(nm, vis) => (nm, vis), unnamed_field => (special_idents::unnamed_field, inherited) @@ -731,8 +780,8 @@ fn encode_info_for_method(ecx: &EncodeContext, } let mut combined_ty_params = opt_vec::Empty; - combined_ty_params.push_all(&owner_generics.ty_params); - combined_ty_params.push_all(&method_generics.ty_params); + for owner_generics.ty_params.iter().advance |x| { combined_ty_params.push(copy *x) } + for method_generics.ty_params.iter().advance |x| { combined_ty_params.push(copy *x) } let len = combined_ty_params.len(); encode_type_param_bounds(ebml_w, ecx, &combined_ty_params); @@ -753,7 +802,6 @@ fn encode_info_for_method(ecx: &EncodeContext, fn purity_fn_family(p: purity) -> char { match p { unsafe_fn => 'u', - pure_fn => 'p', impure_fn => 'f', extern_fn => 'e' } @@ -762,7 +810,6 @@ fn purity_fn_family(p: purity) -> char { fn purity_static_method_family(p: purity) -> char { match p { unsafe_fn => 'U', - pure_fn => 'P', impure_fn => 'F', _ => fail!("extern fn can't be static") } @@ -782,13 +829,6 @@ fn encode_info_for_item(ecx: &EncodeContext, index: @mut ~[entry<int>], path: &[ast_map::path_elt]) { let tcx = ecx.tcx; - let must_write = - match item.node { - item_enum(_, _) | item_impl(*) | item_trait(*) | item_struct(*) | - item_mod(*) | item_foreign_mod(*) | item_const(*) => true, - _ => false - }; - if !must_write && !reachable(ecx, item.id) { return; } fn add_to_index_(item: @item, ebml_w: &writer::Encoder, index: @mut ~[entry<int>]) { @@ -800,13 +840,18 @@ fn encode_info_for_item(ecx: &EncodeContext, ecx.tcx.sess.codemap.span_to_str(item.span)); match item.node { - item_const(_, _) => { + item_static(_, m, _) => { add_to_index(); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'c'); + if m == ast::m_mutbl { + encode_family(ebml_w, 'b'); + } else { + encode_family(ebml_w, 'c'); + } encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_symbol(ecx, ebml_w, item.id); + encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); ebml_w.end_tag(); @@ -819,6 +864,7 @@ fn encode_info_for_item(ecx: &EncodeContext, let tps_len = generics.ty_params.len(); encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); encode_attributes(ebml_w, item.attrs); if tps_len > 0u || should_inline(item.attrs) { @@ -830,15 +876,29 @@ fn encode_info_for_item(ecx: &EncodeContext, } item_mod(ref m) => { add_to_index(); - encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident); + encode_info_for_mod(ecx, + ebml_w, + m, + item.id, + path, + item.ident, + item.vis); } - item_foreign_mod(_) => { + item_foreign_mod(ref fm) => { add_to_index(); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); encode_family(ebml_w, 'n'); encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + + // Encode all the items in this module. + for fm.items.iter().advance |foreign_item| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(foreign_item.id))); + ebml_w.end_tag(); + } + ebml_w.end_tag(); } item_ty(_, ref generics) => { @@ -862,7 +922,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_name(ecx, ebml_w, item.ident); - for (*enum_definition).variants.each |v| { + for (*enum_definition).variants.iter().advance |v| { encode_variant_id(ebml_w, local_def(v.node.id)); } (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); @@ -896,23 +956,6 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - // If this is a tuple- or enum-like struct, encode the type of the - // constructor. - if struct_def.fields.len() > 0 && - struct_def.fields[0].node.kind == ast::unnamed_field { - let ctor_id = match struct_def.ctor_id { - Some(ctor_id) => ctor_id, - None => ecx.tcx.sess.bug("struct def didn't have ctor id"), - }; - - encode_info_for_struct_ctor(ecx, - ebml_w, - path, - item.ident, - ctor_id, - index); - } - encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); @@ -921,7 +964,7 @@ fn encode_info_for_item(ecx: &EncodeContext, /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ - for struct_def.fields.each |f| { + for struct_def.fields.iter().advance |f| { match f.node.kind { named_field(ident, vis) => { ebml_w.start_tag(tag_item_field); @@ -942,6 +985,23 @@ fn encode_info_for_item(ecx: &EncodeContext, let bkts = create_index(idx); encode_index(ebml_w, bkts, write_int); ebml_w.end_tag(); + + // If this is a tuple- or enum-like struct, encode the type of the + // constructor. + if struct_def.fields.len() > 0 && + struct_def.fields[0].node.kind == ast::unnamed_field { + let ctor_id = match struct_def.ctor_id { + Some(ctor_id) => ctor_id, + None => ecx.tcx.sess.bug("struct def didn't have ctor id"), + }; + + encode_info_for_struct_ctor(ecx, + ebml_w, + path, + item.ident, + ctor_id, + index); + } } item_impl(ref generics, opt_trait, ty, ref methods) => { add_to_index(); @@ -954,13 +1014,14 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); match ty.node { - ast::ty_path(path, _) if path.idents.len() == 1 => { + ast::ty_path(path, bounds, _) if path.idents.len() == 1 => { + assert!(bounds.is_none()); encode_impl_type_basename(ecx, ebml_w, ast_util::path_to_ident(path)); } _ => {} } - for methods.each |m| { + for methods.iter().advance |m| { ebml_w.start_tag(tag_item_impl_method); let method_def_id = local_def(m.id); let s = def_to_str(method_def_id); @@ -976,9 +1037,9 @@ fn encode_info_for_item(ecx: &EncodeContext, // >:-< let mut impl_path = vec::append(~[], path); - impl_path += [ast_map::path_name(item.ident)]; + impl_path.push(ast_map::path_name(item.ident)); - for methods.each |m| { + for methods.iter().advance |m| { index.push(entry {val: m.id, pos: ebml_w.writer.tell()}); encode_info_for_method(ecx, ebml_w, @@ -1001,20 +1062,25 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_trait_ref(ebml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); - for ty::trait_method_def_ids(tcx, local_def(item.id)).each |&method_def_id| { + for ty::trait_method_def_ids(tcx, local_def(item.id)).iter().advance |&method_def_id| { ebml_w.start_tag(tag_item_trait_method); encode_def_id(ebml_w, method_def_id); ebml_w.end_tag(); + + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(method_def_id)); + ebml_w.end_tag(); } encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - for super_traits.each |ast_trait_ref| { + for super_traits.iter().advance |ast_trait_ref| { let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id); encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref); } ebml_w.end_tag(); // Now output the method info for each method. - for ty::trait_method_def_ids(tcx, local_def(item.id)).eachi |i, &method_def_id| { + let r = ty::trait_method_def_ids(tcx, local_def(item.id)); + for r.iter().enumerate().advance |(i, &method_def_id)| { assert_eq!(method_def_id.crate, ast::local_crate); let method_ty = ty::method(tcx, method_def_id); @@ -1088,7 +1154,6 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, index: @mut ~[entry<int>], path: ast_map::path, abi: AbiSet) { - if !reachable(ecx, nitem.id) { return; } index.push(entry { val: nitem.id, pos: ebml_w.writer.tell() }); ebml_w.start_tag(tag_items_data_item); @@ -1098,6 +1163,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, encode_family(ebml_w, purity_fn_family(purity)); encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); + encode_name(ecx, ebml_w, nitem.ident); if abi.is_intrinsic() { (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_foreign(nitem)); } else { @@ -1105,11 +1171,16 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, } encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident)); } - foreign_item_const(*) => { + foreign_item_static(_, mutbl) => { encode_def_id(ebml_w, local_def(nitem.id)); - encode_family(ebml_w, 'c'); + if mutbl { + encode_family(ebml_w, 'b'); + } else { + encode_family(ebml_w, 'c'); + } encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); encode_symbol(ecx, ebml_w, nitem.id); + encode_name(ecx, ebml_w, nitem.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident)); } } @@ -1123,9 +1194,13 @@ fn encode_info_for_items(ecx: &EncodeContext, let index = @mut ~[]; ebml_w.start_tag(tag_items_data); index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() }); - encode_info_for_mod(ecx, ebml_w, &crate.node.module, - crate_node_id, [], - syntax::parse::token::special_idents::invalid); + encode_info_for_mod(ecx, + ebml_w, + &crate.node.module, + crate_node_id, + [], + syntax::parse::token::special_idents::invalid, + public); let items = ecx.tcx.items; // See comment in `encode_side_tables_for_ii` in astencode @@ -1154,6 +1229,12 @@ fn encode_info_for_items(ecx: &EncodeContext, visit::visit_foreign_item(ni, (cx, v)); match items.get_copy(&ni.id) { ast_map::node_foreign_item(_, abi, _, pt) => { + debug!("writing foreign item %s::%s", + ast_map::path_to_str( + *pt, + token::get_ident_interner()), + token::ident_to_str(&ni.ident)); + let mut ebml_w = copy ebml_w; // See above let ecx : &EncodeContext = unsafe { cast::transmute(ecx_ptr) }; @@ -1182,13 +1263,13 @@ fn create_index<T:Copy + Hash + IterBytes>(index: ~[entry<T>]) -> ~[@~[entry<T>]] { let mut buckets: ~[@mut ~[entry<T>]] = ~[]; for uint::range(0u, 256u) |_i| { buckets.push(@mut ~[]); }; - for index.each |elt| { + for index.iter().advance |elt| { let h = elt.val.hash() as uint; buckets[h % 256].push(copy *elt); } let mut buckets_frozen = ~[]; - for buckets.each |bucket| { + for buckets.iter().advance |bucket| { buckets_frozen.push(@/*bad*/copy **bucket); } return buckets_frozen; @@ -1201,10 +1282,10 @@ fn encode_index<T>(ebml_w: &mut writer::Encoder, ebml_w.start_tag(tag_index); let mut bucket_locs: ~[uint] = ~[]; ebml_w.start_tag(tag_index_buckets); - for buckets.each |bucket| { + for buckets.iter().advance |bucket| { bucket_locs.push(ebml_w.writer.tell()); ebml_w.start_tag(tag_index_buckets_bucket); - for (**bucket).each |elt| { + for (**bucket).iter().advance |elt| { ebml_w.start_tag(tag_index_buckets_bucket_elt); assert!(elt.pos < 0xffff_ffff); writer.write_be_u32(elt.pos as u32); @@ -1215,7 +1296,7 @@ fn encode_index<T>(ebml_w: &mut writer::Encoder, } ebml_w.end_tag(); ebml_w.start_tag(tag_index_table); - for bucket_locs.each |pos| { + for bucket_locs.iter().advance |pos| { assert!(*pos < 0xffff_ffff); writer.write_be_u32(*pos as u32); } @@ -1261,7 +1342,7 @@ fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @meta_item) { ebml_w.start_tag(tag_meta_item_name); ebml_w.writer.write(name.as_bytes()); ebml_w.end_tag(); - for items.each |inner_item| { + for items.iter().advance |inner_item| { encode_meta_item(ebml_w, *inner_item); } ebml_w.end_tag(); @@ -1271,7 +1352,7 @@ fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @meta_item) { fn encode_attributes(ebml_w: &mut writer::Encoder, attrs: &[attribute]) { ebml_w.start_tag(tag_attributes); - for attrs.each |attr| { + for attrs.iter().advance |attr| { ebml_w.start_tag(tag_attribute); encode_meta_item(ebml_w, attr.node.value); ebml_w.end_tag(); @@ -1313,7 +1394,7 @@ fn synthesize_crate_attrs(ecx: &EncodeContext, let mut attrs: ~[attribute] = ~[]; let mut found_link_attr = false; - for crate.node.attrs.each |attr| { + for crate.node.attrs.iter().advance |attr| { attrs.push( if "link" != attr::get_attr_name(attr) { copy *attr @@ -1355,13 +1436,12 @@ fn encode_crate_deps(ecx: &EncodeContext, // Sanity-check the crate numbers let mut expected_cnum = 1; - for deps.each |n| { + for deps.iter().advance |n| { assert_eq!(n.cnum, expected_cnum); expected_cnum += 1; } - // mut -> immutable hack for vec::map - deps.slice(0, deps.len()).to_owned() + deps } // We're just going to write a list of crate 'name-hash-version's, with @@ -1369,7 +1449,8 @@ fn encode_crate_deps(ecx: &EncodeContext, // FIXME (#2166): This is not nearly enough to support correct versioning // but is enough to get transitive crate dependencies working. ebml_w.start_tag(tag_crate_deps); - for get_ordered_deps(ecx, cstore).each |dep| { + let r = get_ordered_deps(ecx, cstore); + for r.iter().advance |dep| { encode_crate_dep(ecx, ebml_w, *dep); } ebml_w.end_tag(); @@ -1403,7 +1484,7 @@ fn encode_link_args(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.start_tag(tag_link_args); let link_args = cstore::get_used_link_args(ecx.cstore); - for link_args.each |link_arg| { + for link_args.iter().advance |link_arg| { ebml_w.start_tag(tag_link_args_arg); ebml_w.writer.write_str(link_arg.to_str()); ebml_w.end_tag(); @@ -1412,6 +1493,30 @@ fn encode_link_args(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.end_tag(); } +fn encode_misc_info(ecx: &EncodeContext, + crate: &crate, + ebml_w: &mut writer::Encoder) { + ebml_w.start_tag(tag_misc_info); + ebml_w.start_tag(tag_misc_info_crate_items); + for crate.node.module.items.iter().advance |&item| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(item.id))); + ebml_w.end_tag(); + + for each_auxiliary_node_id(item) |auxiliary_node_id| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(auxiliary_node_id))); + ebml_w.end_tag(); + } + } + + // Encode reexports for the root module. + encode_reexports(ecx, ebml_w, 0, []); + + ebml_w.end_tag(); + ebml_w.end_tag(); +} + fn encode_crate_dep(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, dep: decoder::crate_dep) { @@ -1451,29 +1556,39 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { dep_bytes: 0, lang_item_bytes: 0, link_args_bytes: 0, + misc_bytes: 0, item_bytes: 0, index_bytes: 0, zero_bytes: 0, total_bytes: 0, n_inlines: 0 }; - let EncodeParams{item_symbols, diag, tcx, reachable, reexports2, - discrim_symbols, cstore, encode_inlined_item, - link_meta, _} = parms; + let EncodeParams { + item_symbols, + diag, + tcx, + reexports2, + discrim_symbols, + cstore, + encode_inlined_item, + link_meta, + reachable, + _ + } = parms; let type_abbrevs = @mut HashMap::new(); let stats = @mut stats; let ecx = EncodeContext { diag: diag, tcx: tcx, stats: stats, - reachable: reachable, reexports2: reexports2, item_symbols: item_symbols, discrim_symbols: discrim_symbols, link_meta: link_meta, cstore: cstore, encode_inlined_item: encode_inlined_item, - type_abbrevs: type_abbrevs + type_abbrevs: type_abbrevs, + reachable: reachable, }; let mut ebml_w = writer::Encoder(wr as @io::Writer); @@ -1499,6 +1614,11 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { encode_link_args(&ecx, &mut ebml_w); ecx.stats.link_args_bytes = *wr.pos - i; + // Encode miscellaneous info. + i = *wr.pos; + encode_misc_info(&ecx, crate, &mut ebml_w); + ecx.stats.misc_bytes = *wr.pos - i; + // Encode and index the items. ebml_w.start_tag(tag_items); i = *wr.pos; @@ -1514,7 +1634,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { ecx.stats.total_bytes = *wr.pos; if (tcx.sess.meta_stats()) { - for wr.bytes.each |e| { + for wr.bytes.iter().advance |e| { if *e == 0 { ecx.stats.zero_bytes += 1; } @@ -1526,6 +1646,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { io::println(fmt!(" dep bytes: %u", ecx.stats.dep_bytes)); io::println(fmt!(" lang item bytes: %u", ecx.stats.lang_item_bytes)); io::println(fmt!(" link args bytes: %u", ecx.stats.link_args_bytes)); + io::println(fmt!(" misc bytes: %u", ecx.stats.misc_bytes)); io::println(fmt!(" item bytes: %u", ecx.stats.item_bytes)); io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes)); io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes)); @@ -1548,7 +1669,6 @@ pub fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str { diag: tcx.diag, ds: def_to_str, tcx: tcx, - reachable: |_id| false, abbrevs: tyencode::ac_no_abbrevs}; do io::with_str_writer |wr| { tyencode::enc_ty(wr, cx, t); diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 6314cb62697..28866fd568a 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; -use core::option; -use core::os; -use core::result; -use core::str; +use std::option; +use std::os; +use std::result; +use std::str; // A module for searching for libraries // FIXME (#2658): I'm not happy how this module turned out. Should @@ -48,7 +47,7 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, debug!("filesearch: searching additional lib search paths [%?]", self.addl_lib_search_paths.len()); // a little weird - self.addl_lib_search_paths.each(f); + self.addl_lib_search_paths.iter().advance(|path| f(path)); debug!("filesearch: searching target lib path"); if !f(&make_target_lib_path(self.sysroot, @@ -89,7 +88,8 @@ pub fn search<T:Copy>(filesearch: @FileSearch, pick: pick<T>) -> Option<T> { let mut rslt = None; for filesearch.for_each_lib_search_path() |lib_search_path| { debug!("searching %s", lib_search_path.to_str()); - for os::list_dir_path(lib_search_path).each |path| { + let r = os::list_dir_path(lib_search_path); + for r.iter().advance |path| { debug!("testing %s", path.to_str()); let maybe_picked = pick(*path); if maybe_picked.is_some() { diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 585704381b6..31577e47267 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -10,7 +10,6 @@ //! Finds crate binaries and loads their metadata -use core::prelude::*; use lib::llvm::{False, llvm, mk_object_file, mk_section_iter}; use metadata::decoder; @@ -24,14 +23,14 @@ use syntax::parse::token::ident_interner; use syntax::print::pprust; use syntax::{ast, attr}; -use core::cast; -use core::io; -use core::option; -use core::os::consts::{macos, freebsd, linux, android, win32}; -use core::ptr; -use core::str; -use core::uint; -use core::vec; +use std::cast; +use std::io; +use std::option; +use std::os::consts::{macos, freebsd, linux, android, win32}; +use std::ptr; +use std::str; +use std::uint; +use std::vec; use extra::flate; pub enum os { @@ -89,78 +88,76 @@ fn find_library_crate_aux( filesearch: @filesearch::FileSearch ) -> Option<(~str, @~[u8])> { let crate_name = crate_name_from_metas(cx.metas); - let prefix: ~str = prefix + crate_name + "-"; - let suffix: ~str = /*bad*/copy suffix; + let prefix = prefix + crate_name + "-"; let mut matches = ~[]; - filesearch::search(filesearch, |path| { + filesearch::search(filesearch, |path| -> Option<()> { debug!("inspecting file %s", path.to_str()); - let f: ~str = path.filename().get(); - if !(f.starts_with(prefix) && f.ends_with(suffix)) { - debug!("skipping %s, doesn't look like %s*%s", path.to_str(), - prefix, suffix); - option::None::<()> - } else { - debug!("%s is a candidate", path.to_str()); - match get_metadata_section(cx.os, path) { - option::Some(cvec) => { - if !crate_matches(cvec, cx.metas, cx.hash) { - debug!("skipping %s, metadata doesn't match", - path.to_str()); - option::None::<()> - } else { - debug!("found %s with matching metadata", path.to_str()); - matches.push((path.to_str(), cvec)); - option::None::<()> + match path.filename() { + Some(ref f) if f.starts_with(prefix) && f.ends_with(suffix) => { + debug!("%s is a candidate", path.to_str()); + match get_metadata_section(cx.os, path) { + Some(cvec) => + if !crate_matches(cvec, cx.metas, cx.hash) { + debug!("skipping %s, metadata doesn't match", + path.to_str()); + None + } else { + debug!("found %s with matching metadata", path.to_str()); + matches.push((path.to_str(), cvec)); + None + }, + _ => { + debug!("could not load metadata for %s", path.to_str()); + None + } } - } - _ => { - debug!("could not load metadata for %s", path.to_str()); - option::None::<()> - } } - } - }); + _ => { + debug!("skipping %s, doesn't look like %s*%s", path.to_str(), + prefix, suffix); + None + } + }}); - if matches.is_empty() { - None - } else if matches.len() == 1u { - Some(/*bad*/copy matches[0]) - } else { - cx.diag.span_err( - cx.span, fmt!("multiple matching crates for `%s`", crate_name)); - cx.diag.handler().note("candidates:"); - for matches.each |&(ident, data)| { - cx.diag.handler().note(fmt!("path: %s", ident)); - let attrs = decoder::get_crate_attributes(data); - note_linkage_attrs(cx.intr, cx.diag, attrs); + match matches.len() { + 0 => None, + 1 => Some(matches[0]), + _ => { + cx.diag.span_err( + cx.span, fmt!("multiple matching crates for `%s`", crate_name)); + cx.diag.handler().note("candidates:"); + for matches.iter().advance |&(ident, data)| { + cx.diag.handler().note(fmt!("path: %s", ident)); + let attrs = decoder::get_crate_attributes(data); + note_linkage_attrs(cx.intr, cx.diag, attrs); + } + cx.diag.handler().abort_if_errors(); + None + } } - cx.diag.handler().abort_if_errors(); - None - } } pub fn crate_name_from_metas(metas: &[@ast::meta_item]) -> @str { - let name_items = attr::find_meta_items_by_name(metas, "name"); - match name_items.last_opt() { - Some(i) => { - match attr::get_meta_item_value_str(*i) { - Some(n) => n, - // FIXME (#2406): Probably want a warning here since the user - // is using the wrong type of meta item. - _ => fail!() - } + for metas.iter().advance |m| { + match m.node { + ast::meta_name_value(s, ref l) if s == @"name" => + match l.node { + ast::lit_str(s) => return s, + _ => () + }, + _ => () } - None => fail!("expected to find the crate name") } + fail!("expected to find the crate name") } pub fn note_linkage_attrs(intr: @ident_interner, diag: @span_handler, attrs: ~[ast::attribute]) { - for attr::find_linkage_metas(attrs).each |mi| { - diag.handler().note(fmt!("meta: %s", - pprust::meta_item_to_str(*mi,intr))); + let r = attr::find_linkage_metas(attrs); + for r.iter().advance |mi| { + diag.handler().note(fmt!("meta: %s", pprust::meta_item_to_str(*mi,intr))); } } @@ -182,7 +179,7 @@ pub fn metadata_matches(extern_metas: &[@ast::meta_item], debug!("matching %u metadata requirements against %u items", local_metas.len(), extern_metas.len()); - for local_metas.each |needed| { + for local_metas.iter().advance |needed| { if !attr::contains(extern_metas, *needed) { return false; } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index cf2a92b291f..c1fbde524c0 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -14,13 +14,11 @@ // tjc note: Would be great to have a `match check` macro equivalent // for some of these -use core::prelude::*; use middle::ty; -use core::str; -use core::uint; -use core::vec; +use std::str; +use std::uint; use syntax::abi::AbiSet; use syntax::abi; use syntax::ast; @@ -190,11 +188,11 @@ fn parse_trait_store(st: &mut PState) -> ty::TraitStore { fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs { let self_r = parse_opt(st, |st| parse_region(st) ); - let self_ty = parse_opt(st, |st| parse_ty(st, conv) ); + let self_ty = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)) ); assert_eq!(next(st), '['); let mut params: ~[ty::t] = ~[]; - while peek(st) != ']' { params.push(parse_ty(st, conv)); } + while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); } st.pos = st.pos + 1u; return ty::substs { @@ -262,15 +260,17 @@ fn parse_opt<T>(st: &mut PState, f: &fn(&mut PState) -> T) -> Option<T> { fn parse_str(st: &mut PState, term: char) -> ~str { let mut result = ~""; while peek(st) != term { - result += str::from_byte(next_byte(st)); + unsafe { + str::raw::push_byte(&mut result, next_byte(st)); + } } next(st); return result; } fn parse_trait_ref(st: &mut PState, conv: conv_did) -> ty::TraitRef { - let def = parse_def(st, NominalType, conv); - let substs = parse_substs(st, conv); + let def = parse_def(st, NominalType, |x,y| conv(x,y)); + let substs = parse_substs(st, |x,y| conv(x,y)); ty::TraitRef {def_id: def, substs: substs} } @@ -300,19 +300,20 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { 'c' => return ty::mk_char(), 't' => { assert_eq!(next(st), '['); - let def = parse_def(st, NominalType, conv); - let substs = parse_substs(st, conv); + let def = parse_def(st, NominalType, |x,y| conv(x,y)); + let substs = parse_substs(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_enum(st.tcx, def, substs); } 'x' => { assert_eq!(next(st), '['); - let def = parse_def(st, NominalType, conv); - let substs = parse_substs(st, conv); + let def = parse_def(st, NominalType, |x,y| conv(x,y)); + let substs = parse_substs(st, |x,y| conv(x,y)); let store = parse_trait_store(st); let mt = parse_mutability(st); + let bounds = parse_bounds(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); - return ty::mk_trait(st.tcx, def, substs, store, mt); + return ty::mk_trait(st.tcx, def, substs, store, mt, bounds.builtin_bounds); } 'p' => { let did = parse_def(st, TypeParameter, conv); @@ -344,7 +345,7 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { 'T' => { assert_eq!(next(st), '['); let mut params = ~[]; - while peek(st) != ']' { params.push(parse_ty(st, conv)); } + while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); } st.pos = st.pos + 1u; return ty::mk_tup(st.tcx, params); } @@ -378,15 +379,15 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { } } '"' => { - let _ = parse_def(st, TypeWithId, conv); - let inner = parse_ty(st, conv); + let _ = parse_def(st, TypeWithId, |x,y| conv(x,y)); + let inner = parse_ty(st, |x,y| conv(x,y)); inner } 'B' => ty::mk_opaque_box(st.tcx), 'a' => { assert_eq!(next(st), '['); - let did = parse_def(st, NominalType, conv); - let substs = parse_substs(st, conv); + let did = parse_def(st, NominalType, |x,y| conv(x,y)); + let substs = parse_substs(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_struct(st.tcx, did, substs); } @@ -439,10 +440,9 @@ fn parse_hex(st: &mut PState) -> uint { fn parse_purity(c: char) -> purity { match c { 'u' => unsafe_fn, - 'p' => pure_fn, 'i' => impure_fn, 'c' => extern_fn, - _ => fail!("parse_purity: bad purity") + _ => fail!("parse_purity: bad purity %c", c) } } @@ -472,8 +472,8 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy { let purity = parse_purity(next(st)); let onceness = parse_onceness(next(st)); let region = parse_region(st); - let bounds = parse_bounds(st, conv); - let sig = parse_sig(st, conv); + let bounds = parse_bounds(st, |x,y| conv(x,y)); + let sig = parse_sig(st, |x,y| conv(x,y)); ty::ClosureTy { purity: purity, sigil: sigil, @@ -499,7 +499,7 @@ fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig { assert_eq!(next(st), '['); let mut inputs = ~[]; while peek(st) != ']' { - inputs.push(parse_ty(st, conv)); + inputs.push(parse_ty(st, |x,y| conv(x,y))); } st.pos += 1u; // eat the ']' let ret_ty = parse_ty(st, conv); @@ -518,8 +518,8 @@ pub fn parse_def_id(buf: &[u8]) -> ast::def_id { fail!(); } - let crate_part = vec::slice(buf, 0u, colon_idx); - let def_part = vec::slice(buf, colon_idx + 1u, len); + let crate_part = buf.slice(0u, colon_idx); + let def_part = buf.slice(colon_idx + 1u, len); let crate_num = match uint::parse_bytes(crate_part, 10u) { Some(cn) => cn as int, @@ -543,8 +543,8 @@ pub fn parse_type_param_def_data(data: &[u8], start: uint, } fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef { - ty::TypeParameterDef {def_id: parse_def(st, NominalType, conv), - bounds: @parse_bounds(st, conv)} + ty::TypeParameterDef {def_id: parse_def(st, NominalType, |x,y| conv(x,y)), + bounds: @parse_bounds(st, |x,y| conv(x,y))} } fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds { @@ -555,13 +555,13 @@ fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds { loop { match next(st) { 'S' => { - param_bounds.builtin_bounds.add(ty::BoundOwned); + param_bounds.builtin_bounds.add(ty::BoundSend); } 'C' => { param_bounds.builtin_bounds.add(ty::BoundCopy); } 'K' => { - param_bounds.builtin_bounds.add(ty::BoundConst); + param_bounds.builtin_bounds.add(ty::BoundFreeze); } 'O' => { param_bounds.builtin_bounds.add(ty::BoundStatic); @@ -570,7 +570,7 @@ fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds { param_bounds.builtin_bounds.add(ty::BoundSized); } 'I' => { - param_bounds.trait_bounds.push(@parse_trait_ref(st, conv)); + param_bounds.trait_bounds.push(@parse_trait_ref(st, |x,y| conv(x,y))); } '.' => { return param_bounds; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index d9377afa9a5..1295653f806 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -10,15 +10,14 @@ // Type encoding -use core::prelude::*; use middle::ty::param_ty; use middle::ty; -use core::hashmap::HashMap; -use core::io::WriterUtil; -use core::io; -use core::uint; +use std::hashmap::HashMap; +use std::io::WriterUtil; +use std::io; +use std::uint; use syntax::abi::AbiSet; use syntax::ast; use syntax::ast::*; @@ -31,7 +30,6 @@ pub struct ctxt { ds: @fn(def_id) -> ~str, // The type context. tcx: ty::ctxt, - reachable: @fn(node_id) -> bool, abbrevs: abbrev_ctxt } @@ -125,7 +123,7 @@ fn enc_substs(w: @io::Writer, cx: @ctxt, substs: &ty::substs) { do enc_opt(w, substs.self_r) |r| { enc_region(w, cx, r) } do enc_opt(w, substs.self_ty) |t| { enc_ty(w, cx, t) } w.write_char('['); - for substs.tps.each |t| { enc_ty(w, cx, *t); } + for substs.tps.iter().advance |t| { enc_ty(w, cx, *t); } w.write_char(']'); } @@ -261,18 +259,21 @@ fn enc_sty(w: @io::Writer, cx: @ctxt, st: ty::sty) { enc_substs(w, cx, substs); w.write_char(']'); } - ty::ty_trait(def, ref substs, store, mt) => { + ty::ty_trait(def, ref substs, store, mt, bounds) => { w.write_str(&"x["); w.write_str((cx.ds)(def)); w.write_char('|'); enc_substs(w, cx, substs); enc_trait_store(w, cx, store); enc_mutability(w, mt); + let bounds = ty::ParamBounds {builtin_bounds: bounds, + trait_bounds: ~[]}; + enc_bounds(w, cx, &bounds); w.write_char(']'); } ty::ty_tup(ts) => { w.write_str(&"T["); - for ts.each |t| { enc_ty(w, cx, *t); } + for ts.iter().advance |t| { enc_ty(w, cx, *t); } w.write_char(']'); } ty::ty_box(mt) => { w.write_char('@'); enc_mt(w, cx, mt); } @@ -347,7 +348,6 @@ fn enc_sigil(w: @io::Writer, sigil: Sigil) { fn enc_purity(w: @io::Writer, p: purity) { match p { - pure_fn => w.write_char('p'), impure_fn => w.write_char('i'), unsafe_fn => w.write_char('u'), extern_fn => w.write_char('c') @@ -389,7 +389,7 @@ fn enc_closure_ty(w: @io::Writer, cx: @ctxt, ft: &ty::ClosureTy) { fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) { w.write_char('['); - for fsig.inputs.each |ty| { + for fsig.inputs.iter().advance |ty| { enc_ty(w, cx, *ty); } w.write_char(']'); @@ -399,15 +399,15 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) { fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: &ty::ParamBounds) { for bs.builtin_bounds.each |bound| { match bound { - ty::BoundOwned => w.write_char('S'), + ty::BoundSend => w.write_char('S'), ty::BoundCopy => w.write_char('C'), - ty::BoundConst => w.write_char('K'), + ty::BoundFreeze => w.write_char('K'), ty::BoundStatic => w.write_char('O'), ty::BoundSized => w.write_char('Z'), } } - for bs.trait_bounds.each |&tp| { + for bs.trait_bounds.iter().advance |&tp| { w.write_char('I'); enc_trait_ref(w, cx, tp); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 925b1f506d7..c6d7314f1cd 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use c = metadata::common; use cstore = metadata::cstore; @@ -24,8 +23,8 @@ use middle::{ty, typeck, moves}; use middle; use util::ppaux::ty_to_str; -use core::at_vec; -use core::uint; +use std::at_vec; +use std::uint; use extra::ebml::reader; use extra::ebml; use extra::serialize; @@ -43,7 +42,7 @@ use syntax::parse::token; use syntax; use writer = extra::ebml::writer; -use core::cast; +use std::cast; #[cfg(test)] use syntax::parse; #[cfg(test)] use syntax::print::pprust; @@ -319,15 +318,10 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item { }); match *ii { - ast::ii_item(i) => { - ast::ii_item(fld.fold_item(i).get()) //hack: we're not dropping items - } - ast::ii_method(d, m) => { - ast::ii_method(d, fld.fold_method(m)) - } - ast::ii_foreign(i) => { - ast::ii_foreign(fld.fold_foreign_item(i)) - } + //hack: we're not dropping items + ast::ii_item(i) => ast::ii_item(fld.fold_item(i).get()), + ast::ii_method(d, m) => ast::ii_method(d, fld.fold_method(m)), + ast::ii_foreign(i) => ast::ii_foreign(fld.fold_foreign_item(i)) } } @@ -346,16 +340,10 @@ fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item) }); match ii { - ast::ii_item(i) => { - ast::ii_item(fld.fold_item(i).get()) - } - ast::ii_method(d, m) => { - ast::ii_method(xcx.tr_def_id(d), fld.fold_method(m)) - } - ast::ii_foreign(i) => { - ast::ii_foreign(fld.fold_foreign_item(i)) - } - } + ast::ii_item(i) => ast::ii_item(fld.fold_item(i).get()), + ast::ii_method(d, m) => ast::ii_method(xcx.tr_def_id(d), fld.fold_method(m)), + ast::ii_foreign(i) => ast::ii_foreign(fld.fold_foreign_item(i)), + } } // ______________________________________________________________________ @@ -374,22 +362,25 @@ fn decode_def(xcx: @ExtendedDecodeContext, doc: ebml::Doc) -> ast::def { impl tr for ast::def { fn tr(&self, xcx: @ExtendedDecodeContext) -> ast::def { match *self { - ast::def_fn(did, p) => { ast::def_fn(did.tr(xcx), p) } + ast::def_fn(did, p) => ast::def_fn(did.tr(xcx), p), ast::def_static_method(did, did2_opt, p) => { ast::def_static_method(did.tr(xcx), did2_opt.map(|did2| did2.tr(xcx)), p) } + ast::def_method(did0, did1) => { + ast::def_method(did0.tr(xcx), did1.map(|did1| did1.tr(xcx))) + } ast::def_self_ty(nid) => { ast::def_self_ty(xcx.tr_id(nid)) } ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) } ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) } ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) } - ast::def_const(did) => { ast::def_const(did.tr(xcx)) } + ast::def_static(did, m) => { ast::def_static(did.tr(xcx), m) } ast::def_arg(nid, b) => { ast::def_arg(xcx.tr_id(nid), b) } ast::def_local(nid, b) => { ast::def_local(xcx.tr_id(nid), b) } ast::def_variant(e_did, v_did) => { ast::def_variant(e_did.tr(xcx), v_did.tr(xcx)) - } + }, ast::def_trait(did) => ast::def_trait(did.tr(xcx)), ast::def_ty(did) => ast::def_ty(did.tr(xcx)), ast::def_prim_ty(p) => ast::def_prim_ty(p), @@ -402,9 +393,7 @@ impl tr for ast::def { xcx.tr_id(nid2), xcx.tr_id(nid3)) } - ast::def_struct(did) => { - ast::def_struct(did.tr(xcx)) - } + ast::def_struct(did) => ast::def_struct(did.tr(xcx)), ast::def_region(nid) => ast::def_region(xcx.tr_id(nid)), ast::def_typaram_binder(nid) => { ast::def_typaram_binder(xcx.tr_id(nid)) @@ -419,12 +408,9 @@ impl tr for ast::def { impl tr for ty::AutoAdjustment { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::AutoAdjustment { - match self { - &ty::AutoAddEnv(r, s) => { - ty::AutoAddEnv(r.tr(xcx), s) - } - - &ty::AutoDerefRef(ref adr) => { + match *self { + ty::AutoAddEnv(r, s) => ty::AutoAddEnv(r.tr(xcx), s), + ty::AutoDerefRef(ref adr) => { ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: adr.autoderefs, autoref: adr.autoref.map(|ar| ar.tr(xcx)), @@ -612,8 +598,10 @@ fn encode_vtable_res(ecx: &e::EncodeContext, // ty::t doesn't work, and there is no way (atm) to have // hand-written encoding routines combine with auto-generated // ones. perhaps we should fix this. - do ebml_w.emit_from_vec(*dr) |ebml_w, vtable_origin| { - encode_vtable_origin(ecx, ebml_w, vtable_origin) + do ebml_w.emit_from_vec(*dr) |ebml_w, param_tables| { + do ebml_w.emit_from_vec(**param_tables) |ebml_w, vtable_origin| { + encode_vtable_origin(ecx, ebml_w, vtable_origin) + } } } @@ -645,6 +633,13 @@ fn encode_vtable_origin(ecx: &e::EncodeContext, } } } + typeck::vtable_self(def_id) => { + do ebml_w.emit_enum_variant("vtable_self", 2u, 1u) |ebml_w| { + do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { + ebml_w.emit_def_id(def_id) + } + } + } } } } @@ -659,13 +654,17 @@ trait vtable_decoder_helpers { impl vtable_decoder_helpers for reader::Decoder { fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_res { - @self.read_to_vec(|this| this.read_vtable_origin(xcx)) + @self.read_to_vec(|this| + @this.read_to_vec(|this| + this.read_vtable_origin(xcx))) } fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_origin { do self.read_enum("vtable_origin") |this| { - do this.read_enum_variant(["vtable_static", "vtable_param"]) + do this.read_enum_variant(["vtable_static", + "vtable_param", + "vtable_self"]) |this, i| { match i { 0 => { @@ -691,6 +690,13 @@ impl vtable_decoder_helpers for reader::Decoder { } ) } + 2 => { + typeck::vtable_self( + do this.read_enum_variant_arg(0u) |this| { + this.read_def_id(xcx) + } + ) + } // hard to avoid - user input _ => fail!("bad enum variant") } @@ -708,12 +714,12 @@ trait get_ty_str_ctxt { impl<'self> get_ty_str_ctxt for e::EncodeContext<'self> { fn ty_str_ctxt(&self) -> @tyencode::ctxt { - let r = self.reachable; - @tyencode::ctxt {diag: self.tcx.sess.diagnostic(), - ds: e::def_to_str, - tcx: self.tcx, - reachable: |a| r.contains(&a), - abbrevs: tyencode::ac_use_abbrevs(self.type_abbrevs)} + @tyencode::ctxt { + diag: self.tcx.sess.diagnostic(), + ds: e::def_to_str, + tcx: self.tcx, + abbrevs: tyencode::ac_use_abbrevs(self.type_abbrevs) + } } } @@ -1110,56 +1116,75 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, found for id %d (orig %d)", tag, id, id0); - if tag == (c::tag_table_moves_map as uint) { - dcx.maps.moves_map.insert(id); - } else { - let val_doc = entry_doc.get(c::tag_table_val as uint); - let mut val_dsr = reader::Decoder(val_doc); - let val_dsr = &mut val_dsr; - if tag == (c::tag_table_def as uint) { - let def = decode_def(xcx, val_doc); - dcx.tcx.def_map.insert(id, def); - } else if tag == (c::tag_table_node_type as uint) { - let ty = val_dsr.read_ty(xcx); - debug!("inserting ty for node %?: %s", - id, ty_to_str(dcx.tcx, ty)); - dcx.tcx.node_types.insert(id as uint, ty); - } else if tag == (c::tag_table_node_type_subst as uint) { - let tys = val_dsr.read_tys(xcx); - dcx.tcx.node_type_substs.insert(id, tys); - } else if tag == (c::tag_table_freevars as uint) { - let fv_info = @val_dsr.read_to_vec(|val_dsr| { - @val_dsr.read_freevar_entry(xcx) - }); - dcx.tcx.freevars.insert(id, fv_info); - } else if tag == (c::tag_table_tcache as uint) { - let tpbt = val_dsr.read_ty_param_bounds_and_ty(xcx); - let lid = ast::def_id { crate: ast::local_crate, node: id }; - dcx.tcx.tcache.insert(lid, tpbt); - } else if tag == (c::tag_table_param_defs as uint) { - let bounds = val_dsr.read_type_param_def(xcx); - dcx.tcx.ty_param_defs.insert(id, bounds); - } else if tag == (c::tag_table_method_map as uint) { - dcx.maps.method_map.insert( - id, - val_dsr.read_method_map_entry(xcx)); - } else if tag == (c::tag_table_vtable_map as uint) { - dcx.maps.vtable_map.insert(id, - val_dsr.read_vtable_res(xcx)); - } else if tag == (c::tag_table_adjustments as uint) { - let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr); - adj.tr(xcx); - dcx.tcx.adjustments.insert(id, adj); - } else if tag == (c::tag_table_capture_map as uint) { - let cvars = - at_vec::to_managed_consume( - val_dsr.read_to_vec( - |val_dsr| val_dsr.read_capture_var(xcx))); - dcx.maps.capture_map.insert(id, cvars); - } else { + match c::astencode_tag::from_uint(tag) { + None => { xcx.dcx.tcx.sess.bug( fmt!("unknown tag found in side tables: %x", tag)); } + Some(value) => if value == c::tag_table_moves_map { + dcx.maps.moves_map.insert(id); + } else { + let val_doc = entry_doc.get(c::tag_table_val as uint); + let mut val_dsr = reader::Decoder(val_doc); + let val_dsr = &mut val_dsr; + + match value { + c::tag_table_def => { + let def = decode_def(xcx, val_doc); + dcx.tcx.def_map.insert(id, def); + } + c::tag_table_node_type => { + let ty = val_dsr.read_ty(xcx); + debug!("inserting ty for node %?: %s", + id, ty_to_str(dcx.tcx, ty)); + dcx.tcx.node_types.insert(id as uint, ty); + } + c::tag_table_node_type_subst => { + let tys = val_dsr.read_tys(xcx); + dcx.tcx.node_type_substs.insert(id, tys); + } + c::tag_table_freevars => { + let fv_info = @val_dsr.read_to_vec(|val_dsr| { + @val_dsr.read_freevar_entry(xcx) + }); + dcx.tcx.freevars.insert(id, fv_info); + } + c::tag_table_tcache => { + let tpbt = val_dsr.read_ty_param_bounds_and_ty(xcx); + let lid = ast::def_id { crate: ast::local_crate, node: id }; + dcx.tcx.tcache.insert(lid, tpbt); + } + c::tag_table_param_defs => { + let bounds = val_dsr.read_type_param_def(xcx); + dcx.tcx.ty_param_defs.insert(id, bounds); + } + c::tag_table_method_map => { + dcx.maps.method_map.insert( + id, + val_dsr.read_method_map_entry(xcx)); + } + c::tag_table_vtable_map => { + dcx.maps.vtable_map.insert(id, + val_dsr.read_vtable_res(xcx)); + } + c::tag_table_adjustments => { + let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr); + adj.tr(xcx); + dcx.tcx.adjustments.insert(id, adj); + } + c::tag_table_capture_map => { + let cvars = + at_vec::to_managed_consume( + val_dsr.read_to_vec( + |val_dsr| val_dsr.read_capture_var(xcx))); + dcx.maps.capture_map.insert(id, cvars); + } + _ => { + xcx.dcx.tcx.sess.bug( + fmt!("unknown tag found in side tables: %x", tag)); + } + } + } } debug!(">< Side table doc loaded"); @@ -1217,7 +1242,7 @@ fn mk_ctxt() -> @fake_ext_ctxt { #[cfg(test)] fn roundtrip(in_item: Option<@ast::item>) { - use core::io; + use std::io; let in_item = in_item.get(); let bytes = do io::with_bytes_writer |wr| { diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index be87beba778..b2e303d40ee 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -17,10 +17,9 @@ // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way -use core::prelude::*; -use core::hashmap::HashSet; -use core::uint; +use std::hashmap::HashSet; +use std::uint; use mc = middle::mem_categorization; use middle::borrowck::*; use middle::moves; @@ -118,7 +117,7 @@ impl<'self> CheckLoanCtxt<'self> { //! given `loan_path` for self.each_in_scope_loan(scope_id) |loan| { - for loan.restrictions.each |restr| { + for loan.restrictions.iter().advance |restr| { if restr.loan_path == loan_path { if !op(loan, restr) { return false; @@ -152,7 +151,7 @@ impl<'self> CheckLoanCtxt<'self> { debug!("new_loan_indices = %?", new_loan_indices); for self.each_issued_loan(scope_id) |issued_loan| { - for new_loan_indices.each |&new_loan_index| { + for new_loan_indices.iter().advance |&new_loan_index| { let new_loan = &self.all_loans[new_loan_index]; self.report_error_if_loans_conflict(issued_loan, new_loan); } @@ -210,7 +209,7 @@ impl<'self> CheckLoanCtxt<'self> { }; debug!("illegal_if=%?", illegal_if); - for loan1.restrictions.each |restr| { + for loan1.restrictions.iter().advance |restr| { if !restr.set.intersects(illegal_if) { loop; } if restr.loan_path != loan2.loan_path { loop; } @@ -634,7 +633,7 @@ fn check_loans_in_fn<'a>(fk: &visit::fn_kind, closure_id: ast::node_id, span: span) { let cap_vars = this.bccx.capture_map.get(&closure_id); - for cap_vars.each |cap_var| { + for cap_vars.iter().advance |cap_var| { match cap_var.mode { moves::CapRef | moves::CapCopy => { let var_id = ast_util::def_id_of_def(cap_var.def).node; diff --git a/src/librustc/middle/borrowck/doc.rs b/src/librustc/middle/borrowck/doc.rs index cb3983117e9..8bb5c4620ef 100644 --- a/src/librustc/middle/borrowck/doc.rs +++ b/src/librustc/middle/borrowck/doc.rs @@ -359,7 +359,7 @@ of its owner: LIFETIME(LV.f, LT, MQ) // L-Field LIFETIME(LV, LT, MQ) - LIFETIME(*LV, LT, MQ) // L-Deref-Owned + LIFETIME(*LV, LT, MQ) // L-Deref-Send TYPE(LV) = ~Ty LIFETIME(LV, LT, MQ) @@ -504,7 +504,7 @@ must prevent the owned pointer `LV` from being mutated, which means that we always add `MUTATE` and `CLAIM` to the restriction set imposed on `LV`: - RESTRICTIONS(*LV, ACTIONS) = RS, (*LV, ACTIONS) // R-Deref-Owned-Pointer + RESTRICTIONS(*LV, ACTIONS) = RS, (*LV, ACTIONS) // R-Deref-Send-Pointer TYPE(LV) = ~Ty RESTRICTIONS(LV, ACTIONS|MUTATE|CLAIM) = RS @@ -539,14 +539,14 @@ mutable borrowed pointers. ### Restrictions for loans of const aliasable pointees -Const pointers are read-only. There may be `&mut` or `&` aliases, and +Freeze pointers are read-only. There may be `&mut` or `&` aliases, and we can not prevent *anything* but moves in that case. So the `RESTRICTIONS` function is only defined if `ACTIONS` is the empty set. Because moves from a `&const` or `@const` lvalue are never legal, it is not necessary to add any restrictions at all to the final result. - RESTRICTIONS(*LV, []) = [] // R-Deref-Const-Borrowed + RESTRICTIONS(*LV, []) = [] // R-Deref-Freeze-Borrowed TYPE(LV) = &const Ty or @const Ty ### Restrictions for loans of mutable borrowed pointees diff --git a/src/librustc/middle/borrowck/gather_loans/gather_moves.rs b/src/librustc/middle/borrowck/gather_loans/gather_moves.rs index 5431a0a2998..c9ea9e2be66 100644 --- a/src/librustc/middle/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc/middle/borrowck/gather_loans/gather_moves.rs @@ -12,7 +12,6 @@ * Computes moves. */ -use core::prelude::*; use mc = middle::mem_categorization; use middle::borrowck::*; use middle::borrowck::move_data::*; @@ -71,7 +70,7 @@ pub fn gather_captures(bccx: @BorrowckCtxt, move_data: &mut MoveData, closure_expr: @ast::expr) { let captured_vars = bccx.capture_map.get(&closure_expr.id); - for captured_vars.each |captured_var| { + for captured_vars.iter().advance |captured_var| { match captured_var.mode { moves::CapMove => { let fvar_id = ast_util::def_id_of_def(captured_var.def).node; @@ -101,9 +100,7 @@ fn check_is_legal_to_move_from(bccx: @BorrowckCtxt, cmt0: mc::cmt, cmt: mc::cmt) -> bool { match cmt.cat { - mc::cat_stack_upvar(*) | mc::cat_implicit_self(*) | - mc::cat_copied_upvar(*) | mc::cat_deref(_, _, mc::region_ptr(*)) | mc::cat_deref(_, _, mc::gc_ptr(*)) | mc::cat_deref(_, _, mc::unsafe_ptr(*)) => { @@ -114,6 +111,27 @@ fn check_is_legal_to_move_from(bccx: @BorrowckCtxt, false } + // These are separate from the above cases for a better error message. + mc::cat_stack_upvar(*) | + mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, _ }) => { + let once_hint = if bccx.tcx.sess.once_fns() { + " (unless the destination closure type is `once fn')" + } else { + "" + }; + bccx.span_err( + cmt0.span, + fmt!("cannot move out of %s%s", bccx.cmt_to_str(cmt), once_hint)); + false + } + + // Can move out of captured upvars only if the destination closure + // type is 'once'. 1-shot stack closures emit the copied_upvar form + // (see mem_categorization.rs). + mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Once, _ }) => { + true + } + // It seems strange to allow a move out of a static item, // but what happens in practice is that you have a // reference to a constant with a type that should be diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 9455340268e..05fc139305c 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -11,7 +11,6 @@ //! This module implements the check that the lifetime of a borrow //! does not exceed the lifetime of the value being borrowed. -use core::prelude::*; use middle::borrowck::*; use mc = middle::mem_categorization; @@ -109,7 +108,7 @@ impl GuaranteeLifetimeContext { } mc::cat_downcast(base) | - mc::cat_deref(base, _, mc::uniq_ptr(*)) | // L-Deref-Owned + mc::cat_deref(base, _, mc::uniq_ptr(*)) | // L-Deref-Send mc::cat_interior(base, _) => { // L-Field self.check(base, discr_scope) } diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 02b45995e43..26fa4924ccb 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -16,7 +16,6 @@ // their associated scopes. In phase two, checking loans, we will then make // sure that all of these loans are honored. -use core::prelude::*; use middle::borrowck::*; use middle::borrowck::move_data::MoveData; @@ -229,8 +228,8 @@ fn gather_loans_in_expr(ex: @ast::expr, ast::expr_match(ex_v, ref arms) => { let cmt = this.bccx.cat_expr(ex_v); - for arms.each |arm| { - for arm.pats.each |pat| { + for arms.iter().advance |arm| { + for arm.pats.iter().advance |pat| { this.gather_pat(cmt, *pat, arm.body.node.id, ex.id); } } diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index 6bd32f04ce5..d5377aeb618 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -10,9 +10,8 @@ //! Computes the restrictions that result from a borrow. -use core::prelude::*; -use core::vec; +use std::vec; use middle::borrowck::*; use mc = middle::mem_categorization; use middle::ty; @@ -103,7 +102,7 @@ impl RestrictionsContext { } mc::cat_deref(cmt_base, _, mc::uniq_ptr(*)) => { - // R-Deref-Owned-Pointer + // R-Deref-Send-Pointer // // When we borrow the interior of an owned pointer, we // cannot permit the base to be mutated, because that @@ -125,7 +124,7 @@ impl RestrictionsContext { mc::cat_deref(_, _, mc::region_ptr(m_const, _)) | mc::cat_deref(_, _, mc::gc_ptr(m_const)) => { - // R-Deref-Const-Borrowed + // R-Deref-Freeze-Borrowed self.check_no_mutability_control(cmt, restrictions); Safe } @@ -140,7 +139,7 @@ impl RestrictionsContext { // static errors. For example, if there is code like // // let v = @mut ~[1, 2, 3]; - // for v.each |e| { + // for v.iter().advance |e| { // v.push(e + 1); // } // @@ -152,7 +151,7 @@ impl RestrictionsContext { // // let v = @mut ~[1, 2, 3]; // let w = v; - // for v.each |e| { + // for v.iter().advance |e| { // w.push(e + 1); // } // @@ -165,7 +164,7 @@ impl RestrictionsContext { // } // ... // let v: &V = ...; - // for v.get_list().each |e| { + // for v.get_list().iter().advance |e| { // v.get_list().push(e + 1); // } match opt_loan_path(cmt_base) { diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index d7186ad9333..7d667c2043c 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -10,7 +10,6 @@ /*! See doc.rs for a thorough explanation of the borrow checker */ -use core::prelude::*; use mc = middle::mem_categorization; use middle::ty; @@ -21,10 +20,10 @@ use middle::dataflow::DataFlowOperator; use util::common::stmt_set; use util::ppaux::{note_and_explain_region, Repr, UserString}; -use core::hashmap::{HashSet, HashMap}; -use core::io; -use core::ops::{BitOr, BitAnd}; -use core::result::{Result}; +use std::hashmap::{HashSet, HashMap}; +use std::io; +use std::ops::{BitOr, BitAnd}; +use std::result::{Result}; use syntax::ast; use syntax::ast_map; use syntax::visit; @@ -58,7 +57,7 @@ pub fn check_crate( moves_map: moves::MovesMap, moved_variables_set: moves::MovedVariablesSet, capture_map: moves::CaptureMap, - crate: @ast::crate) -> (root_map, write_guard_map) + crate: &ast::crate) -> (root_map, write_guard_map) { let bccx = @BorrowckCtxt { tcx: tcx, @@ -132,7 +131,7 @@ fn borrowck_fn(fk: &visit::fn_kind, LoanDataFlowOperator, id_range, all_loans.len()); - for all_loans.eachi |loan_idx, loan| { + for all_loans.iter().enumerate().advance |(loan_idx, loan)| { loan_dfcx.add_gen(loan.gen_scope, loan_idx); loan_dfcx.add_kill(loan.kill_scope, loan_idx); } @@ -507,7 +506,7 @@ impl BorrowckCtxt { pub fn report_use_of_moved_value(&self, use_span: span, use_kind: MovedValueUseKind, - lp: @LoanPath, + lp: &LoanPath, move: &move_data::Move, moved_lp: @LoanPath) { let verb = match use_kind { @@ -570,7 +569,7 @@ impl BorrowckCtxt { pub fn report_reassigned_immutable_variable(&self, span: span, - lp: @LoanPath, + lp: &LoanPath, assign: &move_data::Assignment) { self.tcx.sess.span_err( diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index 3b1c451d0a6..97fd6ca5cc4 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -15,10 +15,9 @@ comments in the section "Moves and initialization" and in `doc.rs`. */ -use core::prelude::*; -use core::hashmap::{HashMap, HashSet}; -use core::uint; +use std::hashmap::{HashMap, HashSet}; +use std::uint; use middle::borrowck::*; use middle::dataflow::DataFlowContext; use middle::dataflow::DataFlowOperator; @@ -348,22 +347,22 @@ impl MoveData { * killed by scoping. See `doc.rs` for more details. */ - for self.moves.eachi |i, move| { + for self.moves.iter().enumerate().advance |(i, move)| { dfcx_moves.add_gen(move.id, i); } - for self.var_assignments.eachi |i, assignment| { + for self.var_assignments.iter().enumerate().advance |(i, assignment)| { dfcx_assign.add_gen(assignment.id, i); self.kill_moves(assignment.path, assignment.id, dfcx_moves); } - for self.path_assignments.each |assignment| { + for self.path_assignments.iter().advance |assignment| { self.kill_moves(assignment.path, assignment.id, dfcx_moves); } // Kill all moves related to a variable `x` when it goes out // of scope: - for self.paths.each |path| { + for self.paths.iter().advance |path| { match *path.loan_path { LpVar(id) => { let kill_id = tcx.region_maps.encl_scope(id); @@ -375,7 +374,7 @@ impl MoveData { } // Kill all assignments when the variable goes out of scope: - for self.var_assignments.eachi |assignment_index, assignment| { + for self.var_assignments.iter().enumerate().advance |(assignment_index, assignment)| { match *self.path(assignment.path).loan_path { LpVar(id) => { let kill_id = tcx.region_maps.encl_scope(id); @@ -411,7 +410,7 @@ impl MoveData { let mut p = self.path(index).first_child; while p != InvalidMovePathIndex { - if !self.each_extending_path(p, f) { + if !self.each_extending_path(p, |x| f(x)) { return false; } p = self.path(p).next_sibling; @@ -507,7 +506,7 @@ impl FlowedMoveData { for self.dfcx_moves.each_bit_on_entry_frozen(id) |index| { let move = &self.move_data.moves[index]; let moved_path = move.path; - if base_indices.contains(&moved_path) { + if base_indices.iter().any_(|x| x == &moved_path) { // Scenario 1 or 2: `loan_path` or some base path of // `loan_path` was moved. if !f(move, self.move_data.path(moved_path).loan_path) { @@ -536,7 +535,7 @@ impl FlowedMoveData { -> bool { //! True if `id` is the id of the LHS of an assignment - self.move_data.assignee_ids.contains(&id) + self.move_data.assignee_ids.iter().any_(|x| x == &id) } pub fn each_assignment_of(&self, diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index f44fb0e058b..59918137467 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use driver::session::Session; use middle::resolve; @@ -21,7 +20,7 @@ use syntax::codemap; use syntax::{visit, ast_util, ast_map}; pub fn check_crate(sess: Session, - crate: @crate, + crate: &crate, ast_map: ast_map::map, def_map: resolve::DefMap, method_map: typeck::method_map, @@ -43,12 +42,12 @@ pub fn check_item(sess: Session, (_is_const, v): (bool, visit::vt<bool>)) { match it.node { - item_const(_, ex) => { + item_static(_, _, ex) => { (v.visit_expr)(ex, (true, v)); check_item_recursion(sess, ast_map, def_map, it); } item_enum(ref enum_definition, _) => { - for (*enum_definition).variants.each |var| { + for (*enum_definition).variants.iter().advance |var| { for var.node.disr_expr.iter().advance |ex| { (v.visit_expr)(*ex, (true, v)); } @@ -92,7 +91,7 @@ pub fn check_expr(sess: Session, if is_const { match e.node { expr_unary(_, deref, _) => { } - expr_unary(_, box(_), _) | expr_unary(_, uniq(_), _) => { + expr_unary(_, box(_), _) | expr_unary(_, uniq, _) => { sess.span_err(e.span, "disallowed operator in constant expression"); return; @@ -124,7 +123,7 @@ pub fn check_expr(sess: Session, items without type parameters"); } match def_map.find(&e.id) { - Some(&def_const(_)) | + Some(&def_static(*)) | Some(&def_fn(_, _)) | Some(&def_variant(_, _)) | Some(&def_struct(_)) => { } @@ -225,7 +224,7 @@ pub fn check_item_recursion(sess: Session, (visitor.visit_item)(it, (env, visitor)); fn visit_item(it: @item, (env, v): (env, visit::vt<env>)) { - if env.idstack.contains(&(it.id)) { + if env.idstack.iter().any_(|x| x == &(it.id)) { env.sess.span_fatal(env.root_it.span, "recursive constant"); } env.idstack.push(it.id); @@ -235,22 +234,17 @@ pub fn check_item_recursion(sess: Session, fn visit_expr(e: @expr, (env, v): (env, visit::vt<env>)) { match e.node { - expr_path(*) => { - match env.def_map.find(&e.id) { - Some(&def_const(def_id)) => { - if ast_util::is_local(def_id) { - match env.ast_map.get_copy(&def_id.node) { - ast_map::node_item(it, _) => { - (v.visit_item)(it, (env, v)); - } - _ => fail!("const not bound to an item") - } - } - } - _ => () - } - } - _ => () + expr_path(*) => match env.def_map.find(&e.id) { + Some(&def_static(def_id, _)) if ast_util::is_local(def_id) => + match env.ast_map.get_copy(&def_id.node) { + ast_map::node_item(it, _) => { + (v.visit_item)(it, (env, v)); + } + _ => fail!("const not bound to an item") + }, + _ => () + }, + _ => () } visit::visit_expr(e, (env, v)); } diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index 2ed7b7adecc..190602e815d 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -19,7 +19,7 @@ pub struct Context { can_ret: bool } -pub fn check_crate(tcx: ty::ctxt, crate: @crate) { +pub fn check_crate(tcx: ty::ctxt, crate: &crate) { visit::visit_crate(crate, (Context { in_loop: false, can_ret: true }, visit::mk_vt(@visit::Visitor { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index ad89d790761..72896258b2d 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use middle::const_eval::{compare_const_vals, lookup_const_by_id}; use middle::const_eval::{eval_const_expr, const_val, const_bool}; @@ -19,8 +18,8 @@ use middle::typeck::method_map; use middle::moves; use util::ppaux::ty_to_str; -use core::uint; -use core::vec; +use std::uint; +use std::vec; use extra::sort; use syntax::ast::*; use syntax::ast_util::{unguarded_pat, walk_pat}; @@ -36,7 +35,7 @@ pub struct MatchCheckCtxt { pub fn check_crate(tcx: ty::ctxt, method_map: method_map, moves_map: moves::MovesMap, - crate: @crate) { + crate: &crate) { let cx = @MatchCheckCtxt {tcx: tcx, method_map: method_map, moves_map: moves_map}; @@ -50,7 +49,7 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.abort_if_errors(); } -pub fn expr_is_non_moving_lvalue(cx: @MatchCheckCtxt, expr: @expr) -> bool { +pub fn expr_is_non_moving_lvalue(cx: &MatchCheckCtxt, expr: &expr) -> bool { if !ty::expr_is_lval(cx.tcx, cx.method_map, expr) { return false; } @@ -64,7 +63,7 @@ pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, (s, v): ((), visit::vt<()>)) { expr_match(scrut, ref arms) => { // First, check legality of move bindings. let is_non_moving_lvalue = expr_is_non_moving_lvalue(cx, ex); - for arms.each |arm| { + for arms.iter().advance |arm| { check_legality_of_move_bindings(cx, is_non_moving_lvalue, arm.guard.is_some(), @@ -108,10 +107,10 @@ pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, (s, v): ((), visit::vt<()>)) { } // Check for unreachable patterns -pub fn check_arms(cx: @MatchCheckCtxt, arms: &[arm]) { +pub fn check_arms(cx: &MatchCheckCtxt, arms: &[arm]) { let mut seen = ~[]; - for arms.each |arm| { - for arm.pats.each |pat| { + for arms.iter().advance |arm| { + for arm.pats.iter().advance |pat| { let v = ~[*pat]; match is_useful(cx, &seen, v) { not_useful => { @@ -131,7 +130,7 @@ pub fn raw_pat(p: @pat) -> @pat { } } -pub fn check_exhaustive(cx: @MatchCheckCtxt, sp: span, pats: ~[@pat]) { +pub fn check_exhaustive(cx: &MatchCheckCtxt, sp: span, pats: ~[@pat]) { assert!((!pats.is_empty())); let ext = match is_useful(cx, &pats.map(|p| ~[*p]), [wild()]) { not_useful => { @@ -155,7 +154,7 @@ pub fn check_exhaustive(cx: @MatchCheckCtxt, sp: span, pats: ~[@pat]) { }; let variants = ty::enum_variants(cx.tcx, id); - match variants.find(|v| v.id == vid) { + match variants.iter().find_(|v| v.id == vid) { Some(v) => Some(cx.tcx.sess.str_of(v.name)), None => { fail!("check_exhaustive: bad variant in ctor") @@ -205,10 +204,10 @@ pub enum ctor { // Note: is_useful doesn't work on empty types, as the paper notes. // So it assumes that v is non-empty. -pub fn is_useful(cx: @MatchCheckCtxt, m: &matrix, v: &[@pat]) -> useful { +pub fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@pat]) -> useful { if m.len() == 0u { return useful_; } if m[0].len() == 0u { return not_useful; } - let real_pat = match m.find(|r| r[0].id != 0) { + let real_pat = match m.iter().find_(|r| r[0].id != 0) { Some(r) => r[0], None => v[0] }; let left_ty = if real_pat.id == 0 { ty::mk_nil() } @@ -232,7 +231,7 @@ pub fn is_useful(cx: @MatchCheckCtxt, m: &matrix, v: &[@pat]) -> useful { } } ty::ty_enum(eid, _) => { - for (*ty::enum_variants(cx.tcx, eid)).each |va| { + for (*ty::enum_variants(cx.tcx, eid)).iter().advance |va| { match is_useful_specialized(cx, m, v, variant(va.id), va.args.len(), left_ty) { not_useful => (), @@ -281,7 +280,7 @@ pub fn is_useful(cx: @MatchCheckCtxt, m: &matrix, v: &[@pat]) -> useful { } } -pub fn is_useful_specialized(cx: @MatchCheckCtxt, +pub fn is_useful_specialized(cx: &MatchCheckCtxt, m: &matrix, v: &[@pat], ctor: ctor, @@ -297,14 +296,14 @@ pub fn is_useful_specialized(cx: @MatchCheckCtxt, } } -pub fn pat_ctor_id(cx: @MatchCheckCtxt, p: @pat) -> Option<ctor> { +pub fn pat_ctor_id(cx: &MatchCheckCtxt, p: @pat) -> Option<ctor> { let pat = raw_pat(p); match pat.node { pat_wild => { None } pat_ident(_, _, _) | pat_enum(_, _) => { match cx.tcx.def_map.find(&pat.id) { Some(&def_variant(_, id)) => Some(variant(id)), - Some(&def_const(did)) => { + Some(&def_static(did, false)) => { let const_expr = lookup_const_by_id(cx.tcx, did).get(); Some(val(eval_const_expr(cx.tcx, const_expr))) } @@ -333,13 +332,13 @@ pub fn pat_ctor_id(cx: @MatchCheckCtxt, p: @pat) -> Option<ctor> { } } -pub fn is_wild(cx: @MatchCheckCtxt, p: @pat) -> bool { +pub fn is_wild(cx: &MatchCheckCtxt, p: @pat) -> bool { let pat = raw_pat(p); match pat.node { pat_wild => { true } pat_ident(_, _, _) => { match cx.tcx.def_map.find(&pat.id) { - Some(&def_variant(_, _)) | Some(&def_const(*)) => { false } + Some(&def_variant(_, _)) | Some(&def_static(*)) => { false } _ => { true } } } @@ -347,32 +346,32 @@ pub fn is_wild(cx: @MatchCheckCtxt, p: @pat) -> bool { } } -pub fn missing_ctor(cx: @MatchCheckCtxt, +pub fn missing_ctor(cx: &MatchCheckCtxt, m: &matrix, left_ty: ty::t) -> Option<ctor> { match ty::get(left_ty).sty { ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_rptr(*) | ty::ty_tup(_) | ty::ty_struct(*) => { - for m.each |r| { + for m.iter().advance |r| { if !is_wild(cx, r[0]) { return None; } } return Some(single); } ty::ty_enum(eid, _) => { let mut found = ~[]; - for m.each |r| { + for m.iter().advance |r| { let r = pat_ctor_id(cx, r[0]); for r.iter().advance |id| { - if !vec::contains(found, id) { + if !found.contains(id) { found.push(/*bad*/copy *id); } } } let variants = ty::enum_variants(cx.tcx, eid); if found.len() != (*variants).len() { - for (*variants).each |v| { - if !found.contains(&(variant(v.id))) { + for (*variants).iter().advance |v| { + if !found.iter().any_(|x| x == &(variant(v.id))) { return Some(variant(v.id)); } } @@ -383,7 +382,7 @@ pub fn missing_ctor(cx: @MatchCheckCtxt, ty::ty_bool => { let mut true_found = false; let mut false_found = false; - for m.each |r| { + for m.iter().advance |r| { match pat_ctor_id(cx, r[0]) { None => (), Some(val(const_bool(true))) => true_found = true, @@ -418,12 +417,12 @@ pub fn missing_ctor(cx: @MatchCheckCtxt, } } ); - vec::dedup(&mut sorted_vec_lens); + sorted_vec_lens.dedup(); let mut found_slice = false; let mut next = 0; let mut missing = None; - for sorted_vec_lens.each |&(length, slice)| { + for sorted_vec_lens.iter().advance |&(length, slice)| { if length != next { missing = Some(next); break; @@ -449,14 +448,14 @@ pub fn missing_ctor(cx: @MatchCheckCtxt, } } -pub fn ctor_arity(cx: @MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint { +pub fn ctor_arity(cx: &MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint { match ty::get(ty).sty { ty::ty_tup(ref fs) => fs.len(), ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_rptr(*) => 1u, ty::ty_enum(eid, _) => { let id = match *ctor { variant(id) => id, _ => fail!("impossible case") }; - match vec::find(*ty::enum_variants(cx.tcx, eid), |v| v.id == id ) { + match ty::enum_variants(cx.tcx, eid).iter().find_(|v| v.id == id ) { Some(v) => v.args.len(), None => fail!("impossible case") } @@ -476,7 +475,7 @@ pub fn wild() -> @pat { @pat {id: 0, node: pat_wild, span: dummy_sp()} } -pub fn specialize(cx: @MatchCheckCtxt, +pub fn specialize(cx: &MatchCheckCtxt, r: &[@pat], ctor_id: &ctor, arity: uint, @@ -499,7 +498,7 @@ pub fn specialize(cx: @MatchCheckCtxt, None } } - Some(&def_const(did)) => { + Some(&def_static(did, _)) => { let const_expr = lookup_const_by_id(cx.tcx, did).get(); let e_v = eval_const_expr(cx.tcx, const_expr); @@ -549,7 +548,7 @@ pub fn specialize(cx: @MatchCheckCtxt, } pat_enum(_, args) => { match cx.tcx.def_map.get_copy(&pat_id) { - def_const(did) => { + def_static(did, _) => { let const_expr = lookup_const_by_id(cx.tcx, did).get(); let e_v = eval_const_expr(cx.tcx, const_expr); @@ -613,7 +612,7 @@ pub fn specialize(cx: @MatchCheckCtxt, if variant(variant_id) == *ctor_id { // FIXME #4731: Is this right? --pcw let args = flds.map(|ty_field| { - match flds.find(|f| + match flds.iter().find_(|f| f.ident == ty_field.ident) { Some(f) => f.pat, _ => wild() @@ -643,13 +642,13 @@ pub fn specialize(cx: @MatchCheckCtxt, ty_to_str(cx.tcx, left_ty))); } } - let args = vec::map(class_fields, |class_field| { - match flds.find(|f| + let args = class_fields.iter().transform(|class_field| { + match flds.iter().find_(|f| f.ident == class_field.ident) { Some(f) => f.pat, _ => wild() } - }); + }).collect(); Some(vec::append(args, vec::to_owned(r.tail()))) } } @@ -743,12 +742,12 @@ pub fn specialize(cx: @MatchCheckCtxt, } } -pub fn default(cx: @MatchCheckCtxt, r: &[@pat]) -> Option<~[@pat]> { +pub fn default(cx: &MatchCheckCtxt, r: &[@pat]) -> Option<~[@pat]> { if is_wild(cx, r[0]) { Some(vec::to_owned(r.tail())) } else { None } } -pub fn check_local(cx: @MatchCheckCtxt, +pub fn check_local(cx: &MatchCheckCtxt, loc: @local, (s, v): ((), visit::vt<()>)) { @@ -766,7 +765,7 @@ pub fn check_local(cx: @MatchCheckCtxt, check_legality_of_move_bindings(cx, is_lvalue, false, [ loc.node.pat ]); } -pub fn check_fn(cx: @MatchCheckCtxt, +pub fn check_fn(cx: &MatchCheckCtxt, kind: &visit::fn_kind, decl: &fn_decl, body: &blk, @@ -775,7 +774,7 @@ pub fn check_fn(cx: @MatchCheckCtxt, (s, v): ((), visit::vt<()>)) { visit::visit_fn(kind, decl, body, sp, id, (s, v)); - for decl.inputs.each |input| { + for decl.inputs.iter().advance |input| { if is_refutable(cx, input.pat) { cx.tcx.sess.span_err(input.pat.span, "refutable pattern in function argument"); @@ -783,14 +782,14 @@ pub fn check_fn(cx: @MatchCheckCtxt, } } -pub fn is_refutable(cx: @MatchCheckCtxt, pat: &pat) -> bool { +pub fn is_refutable(cx: &MatchCheckCtxt, pat: &pat) -> bool { match cx.tcx.def_map.find(&pat.id) { Some(&def_variant(enum_id, _)) => { if ty::enum_variants(cx.tcx, enum_id).len() != 1u { return true; } } - Some(&def_const(*)) => return true, + Some(&def_static(*)) => return true, _ => () } @@ -806,13 +805,13 @@ pub fn is_refutable(cx: @MatchCheckCtxt, pat: &pat) -> bool { } pat_lit(_) | pat_range(_, _) => { true } pat_struct(_, ref fields, _) => { - fields.any(|f| is_refutable(cx, f.pat)) + fields.iter().any_(|f| is_refutable(cx, f.pat)) } pat_tup(ref elts) => { - elts.any(|elt| is_refutable(cx, *elt)) + elts.iter().any_(|elt| is_refutable(cx, *elt)) } pat_enum(_, Some(ref args)) => { - args.any(|a| is_refutable(cx, *a)) + args.iter().any_(|a| is_refutable(cx, *a)) } pat_enum(_,_) => { false } pat_vec(*) => { true } @@ -821,7 +820,7 @@ pub fn is_refutable(cx: @MatchCheckCtxt, pat: &pat) -> bool { // Legality of move bindings checking -pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt, +pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, is_lvalue: bool, has_guard: bool, pats: &[@pat]) { @@ -829,7 +828,7 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt, let def_map = tcx.def_map; let mut by_ref_span = None; let mut any_by_move = false; - for pats.each |pat| { + for pats.iter().advance |pat| { do pat_bindings(def_map, *pat) |bm, id, span, _path| { match bm { bind_by_ref(_) => { @@ -871,7 +870,7 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt, }; if !any_by_move { return; } // pointless micro-optimization - for pats.each |pat| { + for pats.iter().advance |pat| { for walk_pat(*pat) |p| { if pat_is_binding(def_map, p) { match p.node { diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 988ad519f42..bf91b6771dc 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use metadata::csearch; use middle::astencode; @@ -18,9 +17,8 @@ use middle; use syntax::{ast, ast_map, ast_util, visit}; use syntax::ast::*; -use core::float; -use core::hashmap::{HashMap, HashSet}; -use core::vec; +use std::float; +use std::hashmap::{HashMap, HashSet}; // // This pass classifies expressions by their constant-ness. @@ -71,11 +69,11 @@ pub fn join(a: constness, b: constness) -> constness { } } -pub fn join_all(cs: &[constness]) -> constness { - cs.iter().fold(integral_const, |a, b| join(a, *b)) +pub fn join_all<It: Iterator<constness>>(mut cs: It) -> constness { + cs.fold(integral_const, |a, b| join(a, b)) } -pub fn classify(e: @expr, +pub fn classify(e: &expr, tcx: ty::ctxt) -> constness { let did = ast_util::local_def(e.id); @@ -105,7 +103,7 @@ pub fn classify(e: @expr, ast::expr_tup(ref es) | ast::expr_vec(ref es, ast::m_imm) => { - join_all(vec::map(*es, |e| classify(*e, tcx))) + join_all(es.iter().transform(|e| classify(*e, tcx))) } ast::expr_vstore(e, vstore) => { @@ -119,7 +117,7 @@ pub fn classify(e: @expr, } ast::expr_struct(_, ref fs, None) => { - let cs = do vec::map((*fs)) |f| { + let cs = do fs.iter().transform |f| { classify(f.node.expr, tcx) }; join_all(cs) @@ -164,9 +162,9 @@ pub fn classify(e: @expr, } } -pub fn lookup_const(tcx: ty::ctxt, e: @expr) -> Option<@expr> { +pub fn lookup_const(tcx: ty::ctxt, e: &expr) -> Option<@expr> { match tcx.def_map.find(&e.id) { - Some(&ast::def_const(def_id)) => lookup_const_by_id(tcx, def_id), + Some(&ast::def_static(def_id, false)) => lookup_const_by_id(tcx, def_id), _ => None } } @@ -178,7 +176,7 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, match tcx.items.find(&def_id.node) { None => None, Some(&ast_map::node_item(it, _)) => match it.node { - item_const(_, const_expr) => Some(const_expr), + item_static(_, ast::m_imm, const_expr) => Some(const_expr), _ => None }, Some(_) => None @@ -195,7 +193,7 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, match csearch::maybe_get_item_ast(tcx, def_id, |a, b, c, d| astencode::decode_inlined_item(a, b, maps, /*bar*/ copy c, d)) { csearch::found(ast::ii_item(item)) => match item.node { - item_const(_, const_expr) => Some(const_expr), + item_static(_, ast::m_imm, const_expr) => Some(const_expr), _ => None }, _ => None @@ -203,7 +201,7 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, } } -pub fn lookup_constness(tcx: ty::ctxt, e: @expr) -> constness { +pub fn lookup_constness(tcx: ty::ctxt, e: &expr) -> constness { match lookup_const(tcx, e) { Some(rhs) => { let ty = ty::expr_ty(tcx, rhs); @@ -217,7 +215,7 @@ pub fn lookup_constness(tcx: ty::ctxt, e: @expr) -> constness { } } -pub fn process_crate(crate: @ast::crate, +pub fn process_crate(crate: &ast::crate, tcx: ty::ctxt) { let v = visit::mk_simple_visitor(@visit::SimpleVisitor { visit_expr_post: |e| { classify(e, tcx); }, @@ -239,14 +237,14 @@ pub enum const_val { const_bool(bool) } -pub fn eval_const_expr(tcx: middle::ty::ctxt, e: @expr) -> const_val { +pub fn eval_const_expr(tcx: middle::ty::ctxt, e: &expr) -> const_val { match eval_const_expr_partial(tcx, e) { Ok(r) => r, Err(s) => tcx.sess.span_fatal(e.span, s) } } -pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: @expr) +pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: &expr) -> Result<const_val, ~str> { use middle::ty; fn fromb(b: bool) -> Result<const_val, ~str> { Ok(const_int(b as i64)) } @@ -406,7 +404,7 @@ pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: @expr) } } -pub fn lit_to_const(lit: @lit) -> const_val { +pub fn lit_to_const(lit: &lit) -> const_val { match lit.node { lit_str(s) => const_str(s), lit_int(n, _) => const_int(n), @@ -420,73 +418,28 @@ pub fn lit_to_const(lit: @lit) -> const_val { } } +fn compare_vals<T : Eq + Ord>(a: T, b: T) -> Option<int> { + Some(if a == b { 0 } else if a < b { -1 } else { 1 }) +} pub fn compare_const_vals(a: &const_val, b: &const_val) -> Option<int> { - match (a, b) { - (&const_int(a), &const_int(b)) => { - if a == b { - Some(0) - } else if a < b { - Some(-1) - } else { - Some(1) - } - } - (&const_uint(a), &const_uint(b)) => { - if a == b { - Some(0) - } else if a < b { - Some(-1) - } else { - Some(1) - } - } - (&const_float(a), &const_float(b)) => { - if a == b { - Some(0) - } else if a < b { - Some(-1) - } else { - Some(1) - } - } - (&const_str(ref a), &const_str(ref b)) => { - if (*a) == (*b) { - Some(0) - } else if (*a) < (*b) { - Some(-1) - } else { - Some(1) - } - } - (&const_bool(a), &const_bool(b)) => { - if a == b { - Some(0) - } else if a < b { - Some(-1) - } else { - Some(1) - } - } - _ => { - None + match (a, b) { + (&const_int(a), &const_int(b)) => compare_vals(a, b), + (&const_uint(a), &const_uint(b)) => compare_vals(a, b), + (&const_float(a), &const_float(b)) => compare_vals(a, b), + (&const_str(a), &const_str(b)) => compare_vals(a, b), + (&const_bool(a), &const_bool(b)) => compare_vals(a, b), + _ => None } - } } -pub fn compare_lit_exprs(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> Option<int> { +pub fn compare_lit_exprs(tcx: middle::ty::ctxt, a: &expr, b: &expr) -> Option<int> { compare_const_vals(&eval_const_expr(tcx, a), &eval_const_expr(tcx, b)) } -pub fn lit_expr_eq(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> Option<bool> { - match compare_lit_exprs(tcx, a, b) { - Some(val) => Some(val == 0), - None => None, - } +pub fn lit_expr_eq(tcx: middle::ty::ctxt, a: &expr, b: &expr) -> Option<bool> { + compare_lit_exprs(tcx, a, b).map(|&val| val == 0) } -pub fn lit_eq(a: @lit, b: @lit) -> Option<bool> { - match compare_const_vals(&lit_to_const(a), &lit_to_const(b)) { - Some(val) => Some(val == 0), - None => None, - } +pub fn lit_eq(a: &lit, b: &lit) -> Option<bool> { + compare_const_vals(&lit_to_const(a), &lit_to_const(b)).map(|&val| val == 0) } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index b4942fba05d..ac18a9b76cf 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -16,13 +16,12 @@ * GEN and KILL bits for each expression. */ -use core::prelude::*; -use core::cast; -use core::io; -use core::uint; -use core::vec; -use core::hashmap::HashMap; +use std::cast; +use std::io; +use std::uint; +use std::vec; +use std::hashmap::HashMap; use syntax::ast; use syntax::ast_util; use syntax::ast_util::id_range; @@ -132,7 +131,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { debug!("add_gen(id=%?, bit=%?)", id, bit); let (start, end) = self.compute_id_range(id); { - let gens = vec::mut_slice(self.gens, start, end); + let gens = self.gens.mut_slice(start, end); set_bit(gens, bit); } } @@ -143,7 +142,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { debug!("add_kill(id=%?, bit=%?)", id, bit); let (start, end) = self.compute_id_range(id); { - let kills = vec::mut_slice(self.kills, start, end); + let kills = self.kills.mut_slice(start, end); set_bit(kills, bit); } } @@ -216,7 +215,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { return true; } let (start, end) = self.compute_id_range_frozen(id); - let on_entry = vec::slice(self.on_entry, start, end); + let on_entry = self.on_entry.slice(start, end); debug!("each_bit_on_entry_frozen(id=%?, on_entry=%s)", id, bits_to_str(on_entry)); self.each_bit(on_entry, f) @@ -229,7 +228,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { //! Only useful after `propagate()` has been called. let (start, end) = self.compute_id_range(id); - let on_entry = vec::slice(self.on_entry, start, end); + let on_entry = self.on_entry.slice(start, end); debug!("each_bit_on_entry(id=%?, on_entry=%s)", id, bits_to_str(on_entry)); self.each_bit(on_entry, f) @@ -241,7 +240,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { //! Iterates through each bit in the gen set for `id`. let (start, end) = self.compute_id_range(id); - let gens = vec::slice(self.gens, start, end); + let gens = self.gens.slice(start, end); debug!("each_gen_bit(id=%?, gens=%s)", id, bits_to_str(gens)); self.each_bit(gens, f) @@ -255,7 +254,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { return true; } let (start, end) = self.compute_id_range_frozen(id); - let gens = vec::slice(self.gens, start, end); + let gens = self.gens.slice(start, end); debug!("each_gen_bit(id=%?, gens=%s)", id, bits_to_str(gens)); self.each_bit(gens, f) @@ -266,7 +265,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> { f: &fn(uint) -> bool) -> bool { //! Helper for iterating over the bits in a bit set. - for words.eachi |word_index, &word| { + for words.iter().enumerate().advance |(word_index, &word)| { if word != 0 { let base_index = word_index * uint::bits; for uint::range(0, uint::bits) |offset| { @@ -338,18 +337,18 @@ impl<O:DataFlowOperator+Copy+'static> DataFlowContext<O> { if self.nodeid_to_bitset.contains_key(&id) { let (start, end) = self.compute_id_range_frozen(id); - let on_entry = vec::slice(self.on_entry, start, end); + let on_entry = self.on_entry.slice(start, end); let entry_str = bits_to_str(on_entry); - let gens = vec::slice(self.gens, start, end); - let gens_str = if gens.any(|&u| u != 0) { + let gens = self.gens.slice(start, end); + let gens_str = if gens.iter().any_(|&u| u != 0) { fmt!(" gen: %s", bits_to_str(gens)) } else { ~"" }; - let kills = vec::slice(self.kills, start, end); - let kills_str = if kills.any(|&u| u != 0) { + let kills = self.kills.slice(start, end); + let kills_str = if kills.iter().any_(|&u| u != 0) { fmt!(" kill: %s", bits_to_str(kills)) } else { ~"" @@ -389,7 +388,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { self.merge_with_entry_set(blk.node.id, in_out); - for blk.node.stmts.each |&stmt| { + for blk.node.stmts.iter().advance |&stmt| { self.walk_stmt(stmt, in_out, loop_scopes); } @@ -503,14 +502,14 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { // func_bits represents the state when the function // returns - let mut func_bits = reslice(in_out).to_vec(); + let mut func_bits = reslice(in_out).to_owned(); loop_scopes.push(LoopScope { loop_id: expr.id, loop_kind: ForLoop, - break_bits: reslice(in_out).to_vec() + break_bits: reslice(in_out).to_owned() }); - for decl.inputs.each |input| { + for decl.inputs.iter().advance |input| { self.walk_pat(input.pat, func_bits, loop_scopes); } self.walk_block(body, func_bits, loop_scopes); @@ -547,7 +546,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { // self.walk_expr(cond, in_out, loop_scopes); - let mut then_bits = reslice(in_out).to_vec(); + let mut then_bits = reslice(in_out).to_owned(); self.walk_block(then, then_bits, loop_scopes); self.walk_opt_expr(els, in_out, loop_scopes); @@ -569,11 +568,11 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { self.walk_expr(cond, in_out, loop_scopes); - let mut body_bits = reslice(in_out).to_vec(); + let mut body_bits = reslice(in_out).to_owned(); loop_scopes.push(LoopScope { loop_id: expr.id, loop_kind: TrueLoop, - break_bits: reslice(in_out).to_vec() + break_bits: reslice(in_out).to_owned() }); self.walk_block(blk, body_bits, loop_scopes); self.add_to_entry_set(expr.id, body_bits); @@ -591,12 +590,12 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { // <--+ (break) // - let mut body_bits = reslice(in_out).to_vec(); + let mut body_bits = reslice(in_out).to_owned(); self.reset(in_out); loop_scopes.push(LoopScope { loop_id: expr.id, loop_kind: TrueLoop, - break_bits: reslice(in_out).to_vec() + break_bits: reslice(in_out).to_owned() }); self.walk_block(blk, body_bits, loop_scopes); self.add_to_entry_set(expr.id, body_bits); @@ -620,20 +619,20 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { // self.walk_expr(discr, in_out, loop_scopes); - let mut guards = reslice(in_out).to_vec(); + let mut guards = reslice(in_out).to_owned(); // We know that exactly one arm will be taken, so we // can start out with a blank slate and just union // together the bits from each arm: self.reset(in_out); - for arms.each |arm| { + for arms.iter().advance |arm| { // in_out reflects the discr and all guards to date self.walk_opt_expr(arm.guard, guards, loop_scopes); // determine the bits for the body and then union // them into `in_out`, which reflects all bodies to date - let mut body = reslice(guards).to_vec(); + let mut body = reslice(guards).to_owned(); self.walk_pat_alternatives(arm.pats, body, loop_scopes); self.walk_block(&arm.body, body, loop_scopes); join_bits(&self.dfcx.oper, body, in_out); @@ -644,7 +643,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { self.walk_opt_expr(o_e, in_out, loop_scopes); // is this a return from a `for`-loop closure? - match loop_scopes.position(|s| s.loop_kind == ForLoop) { + match loop_scopes.iter().position_(|s| s.loop_kind == ForLoop) { Some(i) => { // if so, add the in_out bits to the state // upon exit. Remember that we cannot count @@ -702,7 +701,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { } ast::expr_struct(_, ref fields, with_expr) => { - for fields.each |field| { + for fields.iter().advance |field| { self.walk_expr(field.node.expr, in_out, loop_scopes); } self.walk_opt_expr(with_expr, in_out, loop_scopes); @@ -735,7 +734,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { ast::expr_binary(_, op, l, r) if ast_util::lazy_binop(op) => { self.walk_expr(l, in_out, loop_scopes); - let temp = reslice(in_out).to_vec(); + let temp = reslice(in_out).to_owned(); self.walk_expr(r, in_out, loop_scopes); join_bits(&self.dfcx.oper, temp, in_out); } @@ -764,10 +763,10 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { } ast::expr_inline_asm(ref inline_asm) => { - for inline_asm.inputs.each |&(_, expr)| { + for inline_asm.inputs.iter().advance |&(_, expr)| { self.walk_expr(expr, in_out, loop_scopes); } - for inline_asm.outputs.each |&(_, expr)| { + for inline_asm.outputs.iter().advance |&(_, expr)| { self.walk_expr(expr, in_out, loop_scopes); } } @@ -835,7 +834,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { exprs: &[@ast::expr], in_out: &mut [uint], loop_scopes: &mut ~[LoopScope]) { - for exprs.each |&expr| { + for exprs.iter().advance |&expr| { self.walk_expr(expr, in_out, loop_scopes); } } @@ -896,8 +895,8 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { // In the general case, the patterns in `pats` are // alternatives, so we must treat this like an N-way select // statement. - let initial_state = reslice(in_out).to_vec(); - for pats.each |&pat| { + let initial_state = reslice(in_out).to_owned(); + for pats.iter().advance |&pat| { let mut temp = copy initial_state; self.walk_pat(pat, temp, loop_scopes); join_bits(&self.dfcx.oper, temp, in_out); @@ -917,7 +916,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { Some(_) => { match self.tcx().def_map.find(&expr.id) { Some(&ast::def_label(loop_id)) => { - match loop_scopes.position(|l| l.loop_id == loop_id) { + match loop_scopes.iter().position_(|l| l.loop_id == loop_id) { Some(i) => i, None => { self.tcx().sess.span_bug( @@ -953,7 +952,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { id, bits_to_str(pred_bits)); let (start, end) = self.dfcx.compute_id_range(id); let changed = { // FIXME(#5074) awkward construction - let on_entry = vec::mut_slice(self.dfcx.on_entry, start, end); + let on_entry = self.dfcx.on_entry.mut_slice(start, end); join_bits(&self.dfcx.oper, pred_bits, on_entry) }; if changed { @@ -970,7 +969,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { id, mut_bits_to_str(pred_bits)); let (start, end) = self.dfcx.compute_id_range(id); let changed = { // FIXME(#5074) awkward construction - let on_entry = vec::mut_slice(self.dfcx.on_entry, start, end); + let on_entry = self.dfcx.on_entry.mut_slice(start, end); let changed = join_bits(&self.dfcx.oper, reslice(pred_bits), on_entry); copy_bits(reslice(on_entry), pred_bits); changed @@ -993,7 +992,7 @@ fn bits_to_str(words: &[uint]) -> ~str { // Note: this is a little endian printout of bytes. - for words.each |&word| { + for words.iter().advance |&word| { let mut v = word; for uint::range(0, uint::bytes) |_| { result.push_char(sep); diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index d9481c26dad..654cc25c15e 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -17,7 +17,7 @@ use middle::typeck::method_map; use util::ppaux; use syntax::ast::{deref, expr_call, expr_inline_asm, expr_method_call}; -use syntax::ast::{expr_unary, node_id, unsafe_blk, unsafe_fn}; +use syntax::ast::{expr_unary, node_id, unsafe_blk, unsafe_fn, expr_path}; use syntax::ast; use syntax::codemap::span; use syntax::visit::{fk_item_fn, fk_method}; @@ -47,7 +47,7 @@ fn type_is_unsafe_function(ty: ty::t) -> bool { pub fn check_crate(tcx: ty::ctxt, method_map: method_map, - crate: @ast::crate) { + crate: &ast::crate) { let context = @mut Context { method_map: method_map, unsafe_context: SafeContext, @@ -143,6 +143,14 @@ pub fn check_crate(tcx: ty::ctxt, expr_inline_asm(*) => { require_unsafe(expr.span, "use of inline assembly") } + expr_path(*) => { + match ty::resolve_expr(tcx, expr) { + ast::def_static(_, true) => { + require_unsafe(expr.span, "use of mutable static") + } + _ => {} + } + } _ => {} } diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index a93aea983fb..9bcfab0773f 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use driver::session; use driver::session::Session; @@ -18,7 +17,7 @@ use syntax::codemap::span; use syntax::visit::{default_visitor, mk_vt, vt, Visitor, visit_crate, visit_item}; use syntax::attr::{attrs_contains_name}; use syntax::ast_map; -use core::util; +use std::util; struct EntryContext { session: Session, @@ -41,7 +40,7 @@ struct EntryContext { type EntryVisitor = vt<@mut EntryContext>; -pub fn find_entry_point(session: Session, crate: @crate, ast_map: ast_map::map) { +pub fn find_entry_point(session: Session, crate: &crate, ast_map: ast_map::map) { // FIXME #4404 android JNI hacks if *session.building_library && @@ -138,7 +137,7 @@ fn configure_main(ctxt: @mut EntryContext) { but you have one or more functions named 'main' that are not \ defined at the crate level. Either move the definition or \ attach the `#[main]` attribute to override this behavior."); - for this.non_main_fns.each |&(_, span)| { + for this.non_main_fns.iter().advance |&(_, span)| { this.session.span_note(span, "here is a function named 'main'"); } } diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs index e18143042b0..ee7c35fb3d5 100644 --- a/src/librustc/middle/freevars.rs +++ b/src/librustc/middle/freevars.rs @@ -11,12 +11,11 @@ // A pass that annotates for each loops and functions with the free // variables that they contain. -use core::prelude::*; use middle::resolve; use middle::ty; -use core::hashmap::HashMap; +use std::hashmap::HashMap; use syntax::codemap::span; use syntax::{ast, ast_util, visit}; @@ -88,7 +87,7 @@ fn collect_freevars(def_map: resolve::DefMap, blk: &ast::blk) // efficient as it fully recomputes the free variables at every // node of interest rather than building up the free variables in // one pass. This could be improved upon if it turns out to matter. -pub fn annotate_freevars(def_map: resolve::DefMap, crate: @ast::crate) -> +pub fn annotate_freevars(def_map: resolve::DefMap, crate: &ast::crate) -> freevar_map { let freevars = @mut HashMap::new(); diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 70ad0e1c3a9..a207985e64c 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use middle::freevars::freevar_entry; use middle::freevars; @@ -17,7 +16,6 @@ use middle::typeck; use util::ppaux::{Repr, ty_to_str}; use util::ppaux::UserString; -use core::vec; use syntax::ast::*; use syntax::attr::attrs_contains_name; use syntax::codemap::span; @@ -32,21 +30,21 @@ use syntax::{visit, ast_util}; // // send: Things that can be sent on channels or included in spawned closures. // copy: Things that can be copied. -// const: Things thare are deeply immutable. They are guaranteed never to +// freeze: Things thare are deeply immutable. They are guaranteed never to // change, and can be safely shared without copying between tasks. -// owned: Things that do not contain borrowed pointers. +// 'static: Things that do not contain borrowed pointers. // // Send includes scalar types as well as classes and unique types containing // only sendable types. // // Copy includes boxes, closure and unique types containing copyable types. // -// Const include scalar types, things without non-const fields, and pointers -// to const things. +// Freeze include scalar types, things without non-const fields, and pointers +// to freezable things. // // This pass ensures that type parameters are only instantiated with types // whose kinds are equal or less general than the way the type parameter was -// annotated (with the `send`, `copy` or `const` keyword). +// annotated (with the `Send`, `Copy` or `Freeze` bound). // // It also verifies that noncopyable kinds are not copied. Sendability is not // applied, since none of our language primitives send. Instead, the sending @@ -63,7 +61,7 @@ pub struct Context { pub fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, - crate: @crate) { + crate: &crate) { let ctx = Context { tcx: tcx, method_map: method_map, @@ -81,8 +79,6 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.abort_if_errors(); } -type check_fn = @fn(Context, @freevar_entry); - fn check_struct_safe_for_destructor(cx: Context, span: span, struct_did: def_id) { @@ -93,10 +89,10 @@ fn check_struct_safe_for_destructor(cx: Context, self_ty: None, tps: ~[] }); - if !ty::type_is_owned(cx.tcx, struct_ty) { + if !ty::type_is_sendable(cx.tcx, struct_ty) { cx.tcx.sess.span_err(span, - "cannot implement a destructor on a struct \ - that is not Owned"); + "cannot implement a destructor on a \ + structure that does not satisfy Send"); cx.tcx.sess.span_note(span, "use \"#[unsafe_destructor]\" on the \ implementation to force the compiler to \ @@ -104,7 +100,7 @@ fn check_struct_safe_for_destructor(cx: Context, } } else { cx.tcx.sess.span_err(span, - "cannot implement a destructor on a struct \ + "cannot implement a destructor on a structure \ with type parameters"); cx.tcx.sess.span_note(span, "use \"#[unsafe_destructor]\" on the \ @@ -129,7 +125,8 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) { if cx.tcx.lang_items.drop_trait() == trait_def_id { // Yes, it's a destructor. match self_type.node { - ty_path(_, path_node_id) => { + ty_path(_, bounds, path_node_id) => { + assert!(bounds.is_none()); let struct_def = cx.tcx.def_map.get_copy( &path_node_id); let struct_did = @@ -162,30 +159,40 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) { // Yields the appropriate function to check the kind of closed over // variables. `id` is the node_id for some expression that creates the // closure. -fn with_appropriate_checker(cx: Context, id: node_id, b: &fn(check_fn)) { - fn check_for_uniq(cx: Context, fv: @freevar_entry) { +fn with_appropriate_checker(cx: Context, id: node_id, + b: &fn(checker: &fn(Context, @freevar_entry))) { + fn check_for_uniq(cx: Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) { // all captured data must be owned, regardless of whether it is // moved in or copied in. let id = ast_util::def_id_of_def(fv.def).node; let var_t = ty::node_id_to_type(cx.tcx, id); - if !check_owned(cx, var_t, fv.span) { return; } // check that only immutable variables are implicitly copied in check_imm_free_var(cx, fv.def, fv.span); + + check_freevar_bounds(cx, fv.span, var_t, bounds, None); } - fn check_for_box(cx: Context, fv: @freevar_entry) { + fn check_for_box(cx: Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) { // all captured data must be owned let id = ast_util::def_id_of_def(fv.def).node; let var_t = ty::node_id_to_type(cx.tcx, id); - if !check_durable(cx.tcx, var_t, fv.span) { return; } // check that only immutable variables are implicitly copied in check_imm_free_var(cx, fv.def, fv.span); + + check_freevar_bounds(cx, fv.span, var_t, bounds, None); } - fn check_for_block(_cx: Context, _fv: @freevar_entry) { - // no restrictions + fn check_for_block(cx: Context, fv: &freevar_entry, + bounds: ty::BuiltinBounds, region: ty::Region) { + let id = ast_util::def_id_of_def(fv.def).node; + let var_t = ty::node_id_to_type(cx.tcx, id); + // FIXME(#3569): Figure out whether the implicit borrow is actually + // mutable. Currently we assume all upvars are referenced mutably. + let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, region, var_t); + check_freevar_bounds(cx, fv.span, implicit_borrowed_type, + bounds, Some(var_t)); } fn check_for_bare(cx: Context, fv: @freevar_entry) { @@ -196,14 +203,15 @@ fn with_appropriate_checker(cx: Context, id: node_id, b: &fn(check_fn)) { let fty = ty::node_id_to_type(cx.tcx, id); match ty::get(fty).sty { - ty::ty_closure(ty::ClosureTy {sigil: OwnedSigil, _}) => { - b(check_for_uniq) + ty::ty_closure(ty::ClosureTy {sigil: OwnedSigil, bounds: bounds, _}) => { + b(|cx, fv| check_for_uniq(cx, fv, bounds)) } - ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, _}) => { - b(check_for_box) + ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, bounds: bounds, _}) => { + b(|cx, fv| check_for_box(cx, fv, bounds)) } - ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, _}) => { - b(check_for_block) + ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, bounds: bounds, + region: region, _}) => { + b(|cx, fv| check_for_block(cx, fv, bounds, region)) } ty::ty_bare_fn(_) => { b(check_for_bare) @@ -228,7 +236,8 @@ fn check_fn( // Check kinds on free variables: do with_appropriate_checker(cx, fn_id) |chk| { - for vec::each(*freevars::get_freevars(cx.tcx, fn_id)) |fv| { + let r = freevars::get_freevars(cx.tcx, fn_id); + for r.iter().advance |fv| { chk(cx, *fv); } } @@ -271,7 +280,7 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) { type_param_defs.repr(cx.tcx)); } for ts.iter().zip(type_param_defs.iter()).advance |(&ty, type_param_def)| { - check_bounds(cx, type_parameter_id, e.span, ty, type_param_def) + check_typaram_bounds(cx, type_parameter_id, e.span, ty, type_param_def) } } } @@ -279,7 +288,13 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) { match e.node { expr_cast(source, _) => { check_cast_for_escaping_regions(cx, source, e); - check_kind_bounds_of_cast(cx, source, e); + match ty::get(ty::expr_ty(cx.tcx, e)).sty { + ty::ty_trait(_, _, _, _, bounds) => { + let source_ty = ty::expr_ty(cx.tcx, source); + check_trait_cast_bounds(cx, e.span, source_ty, bounds) + } + _ => { } + } } expr_copy(expr) => { // Note: This is the only place where we must check whether the @@ -307,14 +322,14 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) { fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) { match aty.node { - ty_path(_, id) => { + ty_path(_, _, id) => { let r = cx.tcx.node_type_substs.find(&id); for r.iter().advance |ts| { let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&id)); let type_param_defs = ty::lookup_item_type(cx.tcx, did).generics.type_param_defs; for ts.iter().zip(type_param_defs.iter()).advance |(&ty, type_param_def)| { - check_bounds(cx, aty.id, aty.span, ty, type_param_def) + check_typaram_bounds(cx, aty.id, aty.span, ty, type_param_def) } } } @@ -323,20 +338,29 @@ fn check_ty(aty: @Ty, (cx, v): (Context, visit::vt<Context>)) { visit::visit_ty(aty, (cx, v)); } -pub fn check_bounds(cx: Context, - _type_parameter_id: node_id, - sp: span, - ty: ty::t, - type_param_def: &ty::TypeParameterDef) +// Calls "any_missing" if any bounds were missing. +pub fn check_builtin_bounds(cx: Context, ty: ty::t, bounds: ty::BuiltinBounds, + any_missing: &fn(ty::BuiltinBounds)) { let kind = ty::type_contents(cx.tcx, ty); let mut missing = ty::EmptyBuiltinBounds(); - for type_param_def.bounds.builtin_bounds.each |bound| { + for bounds.each |bound| { if !kind.meets_bound(cx.tcx, bound) { missing.add(bound); } } if !missing.is_empty() { + any_missing(missing); + } +} + +pub fn check_typaram_bounds(cx: Context, + _type_parameter_id: node_id, + sp: span, + ty: ty::t, + type_param_def: &ty::TypeParameterDef) +{ + do check_builtin_bounds(cx, ty, type_param_def.bounds.builtin_bounds) |missing| { cx.tcx.sess.span_err( sp, fmt!("instantiating a type parameter with an incompatible type \ @@ -346,6 +370,40 @@ pub fn check_bounds(cx: Context, } } +pub fn check_freevar_bounds(cx: Context, sp: span, ty: ty::t, + bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>) +{ + do check_builtin_bounds(cx, ty, bounds) |missing| { + // Will be Some if the freevar is implicitly borrowed (stack closure). + // Emit a less mysterious error message in this case. + match referenced_ty { + Some(rty) => cx.tcx.sess.span_err(sp, + fmt!("cannot implicitly borrow variable of type `%s` in a bounded \ + stack closure (implicit reference does not fulfill `%s`)", + ty_to_str(cx.tcx, rty), missing.user_string(cx.tcx))), + None => cx.tcx.sess.span_err(sp, + fmt!("cannot capture variable of type `%s`, which does \ + not fulfill `%s`, in a bounded closure", + ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx))), + } + cx.tcx.sess.span_note( + sp, + fmt!("this closure's environment must satisfy `%s`", + bounds.user_string(cx.tcx))); + } +} + +pub fn check_trait_cast_bounds(cx: Context, sp: span, ty: ty::t, + bounds: ty::BuiltinBounds) { + do check_builtin_bounds(cx, ty, bounds) |missing| { + cx.tcx.sess.span_err(sp, + fmt!("cannot pack type `%s`, which does not fulfill \ + `%s`, as a trait bounded by %s", + ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx), + bounds.user_string(cx.tcx))); + } +} + fn is_nullary_variant(cx: Context, ex: @expr) -> bool { match ex.node { expr_path(_) => { @@ -392,10 +450,10 @@ fn check_copy(cx: Context, ty: ty::t, sp: span, reason: &str) { } } -pub fn check_owned(cx: Context, ty: ty::t, sp: span) -> bool { - if !ty::type_is_owned(cx.tcx, ty) { +pub fn check_send(cx: Context, ty: ty::t, sp: span) -> bool { + if !ty::type_is_sendable(cx.tcx, ty) { cx.tcx.sess.span_err( - sp, fmt!("value has non-owned type `%s`", + sp, fmt!("value has non-sendable type `%s`", ty_to_str(cx.tcx, ty))); false } else { @@ -443,14 +501,14 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool { /// `deque<T>`, then whatever borrowed ptrs may appear in `T` also /// appear in `deque<T>`. /// -/// (3) The type parameter is owned (and therefore does not contain +/// (3) The type parameter is sendable (and therefore does not contain /// borrowed ptrs). /// /// FIXME(#5723)---This code should probably move into regionck. pub fn check_cast_for_escaping_regions( cx: Context, - source: @expr, - target: @expr) + source: &expr, + target: &expr) { // Determine what type we are casting to; if it is not an trait, then no // worries. @@ -477,12 +535,12 @@ pub fn check_cast_for_escaping_regions( // Check, based on the region associated with the trait, whether it can // possibly escape the enclosing fn item (note that all type parameters // must have been declared on the enclosing fn item). - if target_regions.any(|r| is_re_scope(*r)) { + if target_regions.iter().any_(|r| is_re_scope(*r)) { return; /* case (1) */ } // Assuming the trait instance can escape, then ensure that each parameter - // either appears in the trait type or is owned. + // either appears in the trait type or is sendable. let target_params = ty::param_tys_in_type(target_ty); let source_ty = ty::expr_ty(cx.tcx, source); ty::walk_regions_and_ty( @@ -492,7 +550,7 @@ pub fn check_cast_for_escaping_regions( |_r| { // FIXME(#5723) --- turn this check on once &Objects are usable // - // if !target_regions.any(|t_r| is_subregion_of(cx, *t_r, r)) { + // if !target_regions.iter().any_(|t_r| is_subregion_of(cx, *t_r, r)) { // cx.tcx.sess.span_err( // source.span, // fmt!("source contains borrowed pointer with lifetime \ @@ -506,7 +564,7 @@ pub fn check_cast_for_escaping_regions( |ty| { match ty::get(ty).sty { ty::ty_param(source_param) => { - if target_params.contains(&source_param) { + if target_params.iter().any_(|x| x == &source_param) { /* case (2) */ } else { check_durable(cx.tcx, ty, source.span); /* case (3) */ @@ -529,18 +587,3 @@ pub fn check_cast_for_escaping_regions( } } -/// Ensures that values placed into a ~Trait are copyable and sendable. -pub fn check_kind_bounds_of_cast(cx: Context, source: @expr, target: @expr) { - let target_ty = ty::expr_ty(cx.tcx, target); - match ty::get(target_ty).sty { - ty::ty_trait(_, _, ty::UniqTraitStore, _) => { - let source_ty = ty::expr_ty(cx.tcx, source); - if !ty::type_is_owned(cx.tcx, source_ty) { - cx.tcx.sess.span_err( - target.span, - "uniquely-owned trait objects must be sendable"); - } - } - _ => {} // Nothing to do. - } -} diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 7f54e265b7b..0e9361193b0 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -13,13 +13,12 @@ // Language items are items that represent concepts intrinsic to the language // itself. Examples are: // -// * Traits that specify "kinds"; e.g. "const", "copy", "owned". +// * Traits that specify "kinds"; e.g. "Freeze", "Copy", "Send". // -// * Traits that represent operators; e.g. "add", "sub", "index". +// * Traits that represent operators; e.g. "Add", "Sub", "Index". // // * Functions called by the compiler itself. -use core::prelude::*; use driver::session::Session; use metadata::csearch::each_lang_item; @@ -30,74 +29,79 @@ use syntax::ast_util::local_def; use syntax::visit::{default_simple_visitor, mk_simple_visitor, SimpleVisitor}; use syntax::visit::visit_crate; -use core::hashmap::HashMap; +use std::hashmap::HashMap; pub enum LangItem { - ConstTraitLangItem, // 0 - CopyTraitLangItem, // 1 - OwnedTraitLangItem, // 2 - SizedTraitLangItem, // 3 - - DropTraitLangItem, // 4 - - AddTraitLangItem, // 5 - SubTraitLangItem, // 6 - MulTraitLangItem, // 7 - DivTraitLangItem, // 8 - RemTraitLangItem, // 9 - NegTraitLangItem, // 10 - NotTraitLangItem, // 11 - BitXorTraitLangItem, // 11 - BitAndTraitLangItem, // 13 - BitOrTraitLangItem, // 14 - ShlTraitLangItem, // 15 - ShrTraitLangItem, // 16 - IndexTraitLangItem, // 17 - - EqTraitLangItem, // 18 - OrdTraitLangItem, // 19 - - StrEqFnLangItem, // 20 - UniqStrEqFnLangItem, // 21 - AnnihilateFnLangItem, // 22 - LogTypeFnLangItem, // 23 - FailFnLangItem, // 24 - FailBoundsCheckFnLangItem, // 25 - ExchangeMallocFnLangItem, // 26 - ExchangeFreeFnLangItem, // 27 - MallocFnLangItem, // 28 - FreeFnLangItem, // 29 - BorrowAsImmFnLangItem, // 30 - BorrowAsMutFnLangItem, // 31 - ReturnToMutFnLangItem, // 32 - CheckNotBorrowedFnLangItem, // 33 - StrDupUniqFnLangItem, // 34 - RecordBorrowFnLangItem, // 35 - UnrecordBorrowFnLangItem, // 36 - - StartFnLangItem, // 37 + FreezeTraitLangItem, // 0 + CopyTraitLangItem, // 1 + SendTraitLangItem, // 2 + SizedTraitLangItem, // 3 + + DropTraitLangItem, // 4 + + AddTraitLangItem, // 5 + SubTraitLangItem, // 6 + MulTraitLangItem, // 7 + DivTraitLangItem, // 8 + RemTraitLangItem, // 9 + NegTraitLangItem, // 10 + NotTraitLangItem, // 11 + BitXorTraitLangItem, // 11 + BitAndTraitLangItem, // 13 + BitOrTraitLangItem, // 14 + ShlTraitLangItem, // 15 + ShrTraitLangItem, // 16 + IndexTraitLangItem, // 17 + + EqTraitLangItem, // 18 + OrdTraitLangItem, // 19 + + StrEqFnLangItem, // 20 + UniqStrEqFnLangItem, // 21 + AnnihilateFnLangItem, // 22 + LogTypeFnLangItem, // 23 + FailFnLangItem, // 24 + FailBoundsCheckFnLangItem, // 25 + ExchangeMallocFnLangItem, // 26 + ClosureExchangeMallocFnLangItem, // 27 + ExchangeFreeFnLangItem, // 28 + MallocFnLangItem, // 29 + FreeFnLangItem, // 30 + BorrowAsImmFnLangItem, // 31 + BorrowAsMutFnLangItem, // 32 + ReturnToMutFnLangItem, // 33 + CheckNotBorrowedFnLangItem, // 34 + StrDupUniqFnLangItem, // 35 + RecordBorrowFnLangItem, // 36 + UnrecordBorrowFnLangItem, // 37 + + StartFnLangItem, // 38 + + TyDescStructLangItem, // 39 + TyVisitorTraitLangItem, // 40 + OpaqueStructLangItem, // 41 } pub struct LanguageItems { - items: [Option<def_id>, ..38] + items: [Option<def_id>, ..42] } impl LanguageItems { pub fn new() -> LanguageItems { LanguageItems { - items: [ None, ..38 ] + items: [ None, ..42 ] } } pub fn each_item(&self, f: &fn(def_id: def_id, i: uint) -> bool) -> bool { - self.items.eachi(|i, &item| f(item.get(), i)) + self.items.iter().enumerate().advance(|(i, &item)| f(item.get(), i)) } pub fn item_name(index: uint) -> &'static str { match index { - 0 => "const", + 0 => "freeze", 1 => "copy", - 2 => "owned", + 2 => "send", 3 => "sized", 4 => "drop", @@ -125,18 +129,23 @@ impl LanguageItems { 24 => "fail_", 25 => "fail_bounds_check", 26 => "exchange_malloc", - 27 => "exchange_free", - 28 => "malloc", - 29 => "free", - 30 => "borrow_as_imm", - 31 => "borrow_as_mut", - 32 => "return_to_mut", - 33 => "check_not_borrowed", - 34 => "strdup_uniq", - 35 => "record_borrow", - 36 => "unrecord_borrow", - - 37 => "start", + 27 => "closure_exchange_malloc", + 28 => "exchange_free", + 29 => "malloc", + 30 => "free", + 31 => "borrow_as_imm", + 32 => "borrow_as_mut", + 33 => "return_to_mut", + 34 => "check_not_borrowed", + 35 => "strdup_uniq", + 36 => "record_borrow", + 37 => "unrecord_borrow", + + 38 => "start", + + 39 => "ty_desc", + 40 => "ty_visitor", + 41 => "opaque", _ => "???" } @@ -144,197 +153,212 @@ impl LanguageItems { // FIXME #4621: Method macros sure would be nice here. - pub fn const_trait(&const self) -> def_id { - self.items[ConstTraitLangItem as uint].get() + pub fn freeze_trait(&self) -> def_id { + self.items[FreezeTraitLangItem as uint].get() } - pub fn copy_trait(&const self) -> def_id { + pub fn copy_trait(&self) -> def_id { self.items[CopyTraitLangItem as uint].get() } - pub fn owned_trait(&const self) -> def_id { - self.items[OwnedTraitLangItem as uint].get() + pub fn send_trait(&self) -> def_id { + self.items[SendTraitLangItem as uint].get() } - pub fn sized_trait(&const self) -> def_id { + pub fn sized_trait(&self) -> def_id { self.items[SizedTraitLangItem as uint].get() } - pub fn drop_trait(&const self) -> def_id { + pub fn drop_trait(&self) -> def_id { self.items[DropTraitLangItem as uint].get() } - pub fn add_trait(&const self) -> def_id { + pub fn add_trait(&self) -> def_id { self.items[AddTraitLangItem as uint].get() } - pub fn sub_trait(&const self) -> def_id { + pub fn sub_trait(&self) -> def_id { self.items[SubTraitLangItem as uint].get() } - pub fn mul_trait(&const self) -> def_id { + pub fn mul_trait(&self) -> def_id { self.items[MulTraitLangItem as uint].get() } - pub fn div_trait(&const self) -> def_id { + pub fn div_trait(&self) -> def_id { self.items[DivTraitLangItem as uint].get() } - pub fn rem_trait(&const self) -> def_id { + pub fn rem_trait(&self) -> def_id { self.items[RemTraitLangItem as uint].get() } - pub fn neg_trait(&const self) -> def_id { + pub fn neg_trait(&self) -> def_id { self.items[NegTraitLangItem as uint].get() } - pub fn not_trait(&const self) -> def_id { + pub fn not_trait(&self) -> def_id { self.items[NotTraitLangItem as uint].get() } - pub fn bitxor_trait(&const self) -> def_id { + pub fn bitxor_trait(&self) -> def_id { self.items[BitXorTraitLangItem as uint].get() } - pub fn bitand_trait(&const self) -> def_id { + pub fn bitand_trait(&self) -> def_id { self.items[BitAndTraitLangItem as uint].get() } - pub fn bitor_trait(&const self) -> def_id { + pub fn bitor_trait(&self) -> def_id { self.items[BitOrTraitLangItem as uint].get() } - pub fn shl_trait(&const self) -> def_id { + pub fn shl_trait(&self) -> def_id { self.items[ShlTraitLangItem as uint].get() } - pub fn shr_trait(&const self) -> def_id { + pub fn shr_trait(&self) -> def_id { self.items[ShrTraitLangItem as uint].get() } - pub fn index_trait(&const self) -> def_id { + pub fn index_trait(&self) -> def_id { self.items[IndexTraitLangItem as uint].get() } - pub fn eq_trait(&const self) -> def_id { + pub fn eq_trait(&self) -> def_id { self.items[EqTraitLangItem as uint].get() } - pub fn ord_trait(&const self) -> def_id { + pub fn ord_trait(&self) -> def_id { self.items[OrdTraitLangItem as uint].get() } - pub fn str_eq_fn(&const self) -> def_id { + pub fn str_eq_fn(&self) -> def_id { self.items[StrEqFnLangItem as uint].get() } - pub fn uniq_str_eq_fn(&const self) -> def_id { + pub fn uniq_str_eq_fn(&self) -> def_id { self.items[UniqStrEqFnLangItem as uint].get() } - pub fn annihilate_fn(&const self) -> def_id { + pub fn annihilate_fn(&self) -> def_id { self.items[AnnihilateFnLangItem as uint].get() } - pub fn log_type_fn(&const self) -> def_id { + pub fn log_type_fn(&self) -> def_id { self.items[LogTypeFnLangItem as uint].get() } - pub fn fail_fn(&const self) -> def_id { + pub fn fail_fn(&self) -> def_id { self.items[FailFnLangItem as uint].get() } - pub fn fail_bounds_check_fn(&const self) -> def_id { + pub fn fail_bounds_check_fn(&self) -> def_id { self.items[FailBoundsCheckFnLangItem as uint].get() } - pub fn exchange_malloc_fn(&const self) -> def_id { + pub fn exchange_malloc_fn(&self) -> def_id { self.items[ExchangeMallocFnLangItem as uint].get() } - pub fn exchange_free_fn(&const self) -> def_id { + pub fn closure_exchange_malloc_fn(&self) -> def_id { + self.items[ClosureExchangeMallocFnLangItem as uint].get() + } + pub fn exchange_free_fn(&self) -> def_id { self.items[ExchangeFreeFnLangItem as uint].get() } - pub fn malloc_fn(&const self) -> def_id { + pub fn malloc_fn(&self) -> def_id { self.items[MallocFnLangItem as uint].get() } - pub fn free_fn(&const self) -> def_id { + pub fn free_fn(&self) -> def_id { self.items[FreeFnLangItem as uint].get() } - pub fn borrow_as_imm_fn(&const self) -> def_id { + pub fn borrow_as_imm_fn(&self) -> def_id { self.items[BorrowAsImmFnLangItem as uint].get() } - pub fn borrow_as_mut_fn(&const self) -> def_id { + pub fn borrow_as_mut_fn(&self) -> def_id { self.items[BorrowAsMutFnLangItem as uint].get() } - pub fn return_to_mut_fn(&const self) -> def_id { + pub fn return_to_mut_fn(&self) -> def_id { self.items[ReturnToMutFnLangItem as uint].get() } - pub fn check_not_borrowed_fn(&const self) -> def_id { + pub fn check_not_borrowed_fn(&self) -> def_id { self.items[CheckNotBorrowedFnLangItem as uint].get() } - pub fn strdup_uniq_fn(&const self) -> def_id { + pub fn strdup_uniq_fn(&self) -> def_id { self.items[StrDupUniqFnLangItem as uint].get() } - pub fn record_borrow_fn(&const self) -> def_id { + pub fn record_borrow_fn(&self) -> def_id { self.items[RecordBorrowFnLangItem as uint].get() } - pub fn unrecord_borrow_fn(&const self) -> def_id { + pub fn unrecord_borrow_fn(&self) -> def_id { self.items[UnrecordBorrowFnLangItem as uint].get() } - pub fn start_fn(&const self) -> def_id { + pub fn start_fn(&self) -> def_id { self.items[StartFnLangItem as uint].get() } -} - -fn LanguageItemCollector(crate: @crate, - session: Session) - -> LanguageItemCollector { - let mut item_refs = HashMap::new(); - - item_refs.insert(@"const", ConstTraitLangItem as uint); - item_refs.insert(@"copy", CopyTraitLangItem as uint); - item_refs.insert(@"owned", OwnedTraitLangItem as uint); - item_refs.insert(@"sized", SizedTraitLangItem as uint); - - item_refs.insert(@"drop", DropTraitLangItem as uint); - - item_refs.insert(@"add", AddTraitLangItem as uint); - item_refs.insert(@"sub", SubTraitLangItem as uint); - item_refs.insert(@"mul", MulTraitLangItem as uint); - item_refs.insert(@"div", DivTraitLangItem as uint); - item_refs.insert(@"rem", RemTraitLangItem as uint); - item_refs.insert(@"neg", NegTraitLangItem as uint); - item_refs.insert(@"not", NotTraitLangItem as uint); - item_refs.insert(@"bitxor", BitXorTraitLangItem as uint); - item_refs.insert(@"bitand", BitAndTraitLangItem as uint); - item_refs.insert(@"bitor", BitOrTraitLangItem as uint); - item_refs.insert(@"shl", ShlTraitLangItem as uint); - item_refs.insert(@"shr", ShrTraitLangItem as uint); - item_refs.insert(@"index", IndexTraitLangItem as uint); - - item_refs.insert(@"eq", EqTraitLangItem as uint); - item_refs.insert(@"ord", OrdTraitLangItem as uint); - - item_refs.insert(@"str_eq", StrEqFnLangItem as uint); - item_refs.insert(@"uniq_str_eq", UniqStrEqFnLangItem as uint); - item_refs.insert(@"annihilate", AnnihilateFnLangItem as uint); - item_refs.insert(@"log_type", LogTypeFnLangItem as uint); - item_refs.insert(@"fail_", FailFnLangItem as uint); - item_refs.insert(@"fail_bounds_check", - FailBoundsCheckFnLangItem as uint); - item_refs.insert(@"exchange_malloc", ExchangeMallocFnLangItem as uint); - item_refs.insert(@"exchange_free", ExchangeFreeFnLangItem as uint); - item_refs.insert(@"malloc", MallocFnLangItem as uint); - item_refs.insert(@"free", FreeFnLangItem as uint); - item_refs.insert(@"borrow_as_imm", BorrowAsImmFnLangItem as uint); - item_refs.insert(@"borrow_as_mut", BorrowAsMutFnLangItem as uint); - item_refs.insert(@"return_to_mut", ReturnToMutFnLangItem as uint); - item_refs.insert(@"check_not_borrowed", - CheckNotBorrowedFnLangItem as uint); - item_refs.insert(@"strdup_uniq", StrDupUniqFnLangItem as uint); - item_refs.insert(@"record_borrow", RecordBorrowFnLangItem as uint); - item_refs.insert(@"unrecord_borrow", UnrecordBorrowFnLangItem as uint); - item_refs.insert(@"start", StartFnLangItem as uint); - - LanguageItemCollector { - crate: crate, - session: session, - items: LanguageItems::new(), - item_refs: item_refs + pub fn ty_desc(&const self) -> def_id { + self.items[TyDescStructLangItem as uint].get() + } + pub fn ty_visitor(&const self) -> def_id { + self.items[TyVisitorTraitLangItem as uint].get() + } + pub fn opaque(&const self) -> def_id { + self.items[OpaqueStructLangItem as uint].get() } } -struct LanguageItemCollector { +struct LanguageItemCollector<'self> { items: LanguageItems, - crate: @crate, + crate: &'self crate, session: Session, item_refs: HashMap<@str, uint>, } -impl LanguageItemCollector { +impl<'self> LanguageItemCollector<'self> { + pub fn new<'a>(crate: &'a crate, session: Session) + -> LanguageItemCollector<'a> { + let mut item_refs = HashMap::new(); + + item_refs.insert(@"freeze", FreezeTraitLangItem as uint); + item_refs.insert(@"copy", CopyTraitLangItem as uint); + item_refs.insert(@"send", SendTraitLangItem as uint); + item_refs.insert(@"sized", SizedTraitLangItem as uint); + + item_refs.insert(@"drop", DropTraitLangItem as uint); + + item_refs.insert(@"add", AddTraitLangItem as uint); + item_refs.insert(@"sub", SubTraitLangItem as uint); + item_refs.insert(@"mul", MulTraitLangItem as uint); + item_refs.insert(@"div", DivTraitLangItem as uint); + item_refs.insert(@"rem", RemTraitLangItem as uint); + item_refs.insert(@"neg", NegTraitLangItem as uint); + item_refs.insert(@"not", NotTraitLangItem as uint); + item_refs.insert(@"bitxor", BitXorTraitLangItem as uint); + item_refs.insert(@"bitand", BitAndTraitLangItem as uint); + item_refs.insert(@"bitor", BitOrTraitLangItem as uint); + item_refs.insert(@"shl", ShlTraitLangItem as uint); + item_refs.insert(@"shr", ShrTraitLangItem as uint); + item_refs.insert(@"index", IndexTraitLangItem as uint); + + item_refs.insert(@"eq", EqTraitLangItem as uint); + item_refs.insert(@"ord", OrdTraitLangItem as uint); + + item_refs.insert(@"str_eq", StrEqFnLangItem as uint); + item_refs.insert(@"uniq_str_eq", UniqStrEqFnLangItem as uint); + item_refs.insert(@"annihilate", AnnihilateFnLangItem as uint); + item_refs.insert(@"log_type", LogTypeFnLangItem as uint); + item_refs.insert(@"fail_", FailFnLangItem as uint); + item_refs.insert(@"fail_bounds_check", + FailBoundsCheckFnLangItem as uint); + item_refs.insert(@"exchange_malloc", ExchangeMallocFnLangItem as uint); + item_refs.insert(@"closure_exchange_malloc", ClosureExchangeMallocFnLangItem as uint); + item_refs.insert(@"exchange_free", ExchangeFreeFnLangItem as uint); + item_refs.insert(@"malloc", MallocFnLangItem as uint); + item_refs.insert(@"free", FreeFnLangItem as uint); + item_refs.insert(@"borrow_as_imm", BorrowAsImmFnLangItem as uint); + item_refs.insert(@"borrow_as_mut", BorrowAsMutFnLangItem as uint); + item_refs.insert(@"return_to_mut", ReturnToMutFnLangItem as uint); + item_refs.insert(@"check_not_borrowed", + CheckNotBorrowedFnLangItem as uint); + item_refs.insert(@"strdup_uniq", StrDupUniqFnLangItem as uint); + item_refs.insert(@"record_borrow", RecordBorrowFnLangItem as uint); + item_refs.insert(@"unrecord_borrow", UnrecordBorrowFnLangItem as uint); + item_refs.insert(@"start", StartFnLangItem as uint); + item_refs.insert(@"ty_desc", TyDescStructLangItem as uint); + item_refs.insert(@"ty_visitor", TyVisitorTraitLangItem as uint); + item_refs.insert(@"opaque", OpaqueStructLangItem as uint); + + LanguageItemCollector { + crate: crate, + session: session, + items: LanguageItems::new(), + item_refs: item_refs + } + } + pub fn match_and_collect_meta_item(&mut self, item_def_id: def_id, - meta_item: @meta_item) { + meta_item: &meta_item) { match meta_item.node { meta_name_value(key, literal) => { match literal.node { @@ -366,7 +390,7 @@ impl LanguageItemCollector { pub fn match_and_collect_item(&mut self, item_def_id: def_id, - key: @str, + key: &str, value: @str) { if "lang" != key { return; // Didn't match. @@ -391,7 +415,7 @@ impl LanguageItemCollector { let this: *mut LanguageItemCollector = &mut *self; visit_crate(self.crate, ((), mk_simple_visitor(@SimpleVisitor { visit_item: |item| { - for item.attrs.each |attribute| { + for item.attrs.iter().advance |attribute| { unsafe { (*this).match_and_collect_meta_item( local_def(item.id), @@ -416,7 +440,7 @@ impl LanguageItemCollector { } pub fn check_completeness(&self) { - for self.item_refs.each |&key, &item_ref| { + for self.item_refs.iter().advance |(&key, &item_ref)| { match self.items.items[item_ref] { None => { self.session.err(fmt!("no item found for `%s`", key)); @@ -435,10 +459,10 @@ impl LanguageItemCollector { } } -pub fn collect_language_items(crate: @crate, +pub fn collect_language_items(crate: &crate, session: Session) -> LanguageItems { - let mut collector = LanguageItemCollector(crate, session); + let mut collector = LanguageItemCollector::new(crate, session); collector.collect(); let LanguageItemCollector { items, _ } = collector; session.abort_if_errors(); diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index c0421b2d474..ce09f790ef4 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -8,25 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use driver::session; use middle::ty; use middle::pat_util; use util::ppaux::{ty_to_str}; -use core::char; -use core::cmp; -use core::hashmap::HashMap; -use core::i16; -use core::i32; -use core::i64; -use core::i8; -use core::u16; -use core::u32; -use core::u64; -use core::u8; -use core::vec; +use std::char; +use std::cmp; +use std::hashmap::HashMap; +use std::i16; +use std::i32; +use std::i64; +use std::i8; +use std::u16; +use std::u32; +use std::u64; +use std::u8; +use std::vec; use extra::smallintmap::SmallIntMap; use syntax::attr; use syntax::codemap::span; @@ -96,6 +95,8 @@ pub enum lint { missing_doc, unreachable_code, + + warnings, } pub fn level_to_str(lv: level) -> &'static str { @@ -137,7 +138,7 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ ("ctypes", LintSpec { lint: ctypes, - desc: "proper use of core::libc types in foreign modules", + desc: "proper use of std::libc types in foreign modules", default: warn }), @@ -280,6 +281,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ desc: "detects unreachable code", default: warn }), + + ("warnings", + LintSpec { + lint: warnings, + desc: "mass-change the level for lints which produce warnings", + default: warn + }), ]; /* @@ -288,7 +296,7 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ */ pub fn get_lint_dict() -> LintDict { let mut map = HashMap::new(); - for lint_table.each|&(k, v)| { + for lint_table.iter().advance |&(k, v)| { map.insert(k, v); } return map; @@ -352,7 +360,7 @@ impl Context { } fn lint_to_str(&self, lint: lint) -> &'static str { - for self.dict.each |k, v| { + for self.dict.iter().advance |(k, v)| { if v.lint == lint { return *k; } @@ -362,10 +370,11 @@ impl Context { fn span_lint(&self, lint: lint, span: span, msg: &str) { let (level, src) = match self.curr.find(&(lint as uint)) { + None => { return } + Some(&(warn, src)) => (self.get_level(warnings), src), Some(&pair) => pair, - None => { return; } }; - if level == allow { return; } + if level == allow { return } let mut note = None; let msg = match src { @@ -435,7 +444,8 @@ impl Context { // detect doc(hidden) let mut doc_hidden = false; - for attr::find_attrs_by_name(attrs, "doc").each |attr| { + let r = attr::find_attrs_by_name(attrs, "doc"); + for r.iter().advance |attr| { match attr::get_meta_item_list(attr.node.value) { Some(s) => { if attr::find_meta_items_by_name(s, "hidden").len() > 0 { @@ -472,12 +482,12 @@ impl Context { // pair instead of just one visitor. match n { Item(it) => { - for self.visitors.each |&(orig, stopping)| { + for self.visitors.iter().advance |&(orig, stopping)| { (orig.visit_item)(it, (self, stopping)); } } Crate(c) => { - for self.visitors.each |&(_, stopping)| { + for self.visitors.iter().advance |&(_, stopping)| { visit::visit_crate(c, (self, stopping)); } } @@ -486,7 +496,7 @@ impl Context { // to be a no-op, so manually invoke visit_fn. Method(m) => { let fk = visit::fk_method(copy m.ident, &m.generics, m); - for self.visitors.each |&(orig, stopping)| { + for self.visitors.iter().advance |&(orig, stopping)| { (orig.visit_fn)(&fk, &m.decl, &m.body, m.span, m.id, (self, stopping)); } @@ -497,12 +507,12 @@ impl Context { pub fn each_lint(sess: session::Session, attrs: &[ast::attribute], - f: &fn(@ast::meta_item, level, @str) -> bool) -> bool -{ - for [allow, warn, deny, forbid].each |&level| { + f: &fn(@ast::meta_item, level, @str) -> bool) -> bool { + let xs = [allow, warn, deny, forbid]; + for xs.iter().advance |&level| { let level_name = level_to_str(level); let attrs = attr::find_attrs_by_name(attrs, level_name); - for attrs.each |attr| { + for attrs.iter().advance |attr| { let meta = attr.node.value; let metas = match meta.node { ast::meta_list(_, ref metas) => metas, @@ -511,7 +521,7 @@ pub fn each_lint(sess: session::Session, loop; } }; - for metas.each |meta| { + for metas.iter().advance |meta| { match meta.node { ast::meta_word(lintname) => { if !f(*meta, level, lintname) { @@ -525,7 +535,7 @@ pub fn each_lint(sess: session::Session, } } } - return true; + true } // Take a visitor, and modify it so that it will not proceed past subitems. @@ -690,10 +700,10 @@ fn lint_type_limits() -> visit::vt<@mut Context> { }) } -fn check_item_default_methods(cx: &Context, item: @ast::item) { +fn check_item_default_methods(cx: &Context, item: &ast::item) { match item.node { ast::item_trait(_, _, ref methods) => { - for methods.each |method| { + for methods.iter().advance |method| { match *method { ast::required(*) => {} ast::provided(*) => { @@ -707,41 +717,43 @@ fn check_item_default_methods(cx: &Context, item: @ast::item) { } } -fn check_item_ctypes(cx: &Context, it: @ast::item) { - - fn check_foreign_fn(cx: &Context, decl: &ast::fn_decl) { - let tys = vec::map(decl.inputs, |a| a.ty ); - for vec::each(vec::append_one(tys, decl.output)) |ty| { - match ty.node { - ast::ty_path(_, id) => { +fn check_item_ctypes(cx: &Context, it: &ast::item) { + fn check_ty(cx: &Context, ty: &ast::Ty) { + match ty.node { + ast::ty_path(_, _, id) => { match cx.tcx.def_map.get_copy(&id) { - ast::def_prim_ty(ast::ty_int(ast::ty_i)) => { - cx.span_lint(ctypes, ty.span, - "found rust type `int` in foreign module, while \ - libc::c_int or libc::c_long should be used"); - } - ast::def_prim_ty(ast::ty_uint(ast::ty_u)) => { - cx.span_lint(ctypes, ty.span, - "found rust type `uint` in foreign module, while \ - libc::c_uint or libc::c_ulong should be used"); - } - _ => () + ast::def_prim_ty(ast::ty_int(ast::ty_i)) => { + cx.span_lint(ctypes, ty.span, + "found rust type `int` in foreign module, while \ + libc::c_int or libc::c_long should be used"); + } + ast::def_prim_ty(ast::ty_uint(ast::ty_u)) => { + cx.span_lint(ctypes, ty.span, + "found rust type `uint` in foreign module, while \ + libc::c_uint or libc::c_ulong should be used"); + } + _ => () } - } - _ => () } + _ => () + } + } + + fn check_foreign_fn(cx: &Context, decl: &ast::fn_decl) { + for decl.inputs.iter().advance |in| { + check_ty(cx, in.ty); } + check_ty(cx, decl.output) } match it.node { ast::item_foreign_mod(ref nmod) if !nmod.abis.is_intrinsic() => { - for nmod.items.each |ni| { + for nmod.items.iter().advance |ni| { match ni.node { - ast::foreign_item_fn(ref decl, _, _) => { - check_foreign_fn(cx, decl); - } - // FIXME #4622: Not implemented. - ast::foreign_item_const(*) => {} + ast::foreign_item_fn(ref decl, _, _) => { + check_foreign_fn(cx, decl); + } + ast::foreign_item_static(t, _) => { check_ty(cx, t); } } } } @@ -777,12 +789,13 @@ fn check_type_for_lint(cx: &Context, lint: lint, span: span, ty: ty::t) { } fn check_type(cx: &Context, span: span, ty: ty::t) { - for [managed_heap_memory, owned_heap_memory, heap_memory].each |lint| { + let xs = [managed_heap_memory, owned_heap_memory, heap_memory]; + for xs.iter().advance |lint| { check_type_for_lint(cx, *lint, span, ty); } } -fn check_item_heap(cx: &Context, it: @ast::item) { +fn check_item_heap(cx: &Context, it: &ast::item) { match it.node { ast::item_fn(*) | ast::item_ty(*) | @@ -796,7 +809,7 @@ fn check_item_heap(cx: &Context, it: @ast::item) { // If it's a struct, we also have to check the fields' types match it.node { ast::item_struct(struct_def, _) => { - for struct_def.fields.each |struct_field| { + for struct_def.fields.iter().advance |struct_field| { check_type(cx, struct_field.span, ty::node_id_to_type(cx.tcx, struct_field.node.id)); @@ -836,7 +849,7 @@ fn lint_path_statement() -> visit::vt<@mut Context> { }) } -fn check_item_non_camel_case_types(cx: &Context, it: @ast::item) { +fn check_item_non_camel_case_types(cx: &Context, it: &ast::item) { fn is_camel_case(cx: ty::ctxt, ident: ast::ident) -> bool { let ident = cx.sess.str_of(ident); assert!(!ident.is_empty()); @@ -860,7 +873,7 @@ fn check_item_non_camel_case_types(cx: &Context, it: @ast::item) { } ast::item_enum(ref enum_definition, _) => { check_case(cx, it.ident, it.span); - for enum_definition.variants.each |variant| { + for enum_definition.variants.iter().advance |variant| { check_case(cx, variant.node.name, variant.span); } } @@ -905,7 +918,7 @@ fn lint_unused_mut() -> visit::vt<@mut Context> { } fn visit_fn_decl(cx: &Context, fd: &ast::fn_decl) { - for fd.inputs.each |arg| { + for fd.inputs.iter().advance |arg| { if arg.is_mutbl { check_pat(cx, arg.pat); } @@ -958,7 +971,7 @@ fn lint_session() -> visit::vt<@mut Context> { fn lint_unnecessary_allocations() -> visit::vt<@mut Context> { // Warn if string and vector literals with sigils are immediately borrowed. // Those can have the sigil removed. - fn check(cx: &Context, e: @ast::expr) { + fn check(cx: &Context, e: &ast::expr) { match e.node { ast::expr_vstore(e2, ast::expr_vstore_uniq) | ast::expr_vstore(e2, ast::expr_vstore_box) => { @@ -1003,7 +1016,7 @@ fn lint_missing_doc() -> visit::vt<@mut Context> { // If we have doc(hidden), nothing to do if cx.doc_hidden { return } // If we're documented, nothing to do - if attrs.any(|a| a.node.is_sugared_doc) { return } + if attrs.iter().any_(|a| a.node.is_sugared_doc) { return } // otherwise, warn! cx.span_lint(missing_doc, sp, msg); @@ -1052,7 +1065,7 @@ fn lint_missing_doc() -> visit::vt<@mut Context> { ast::item_struct(sdef, _) if it.vis == ast::public => { check_attrs(cx, it.attrs, it.span, "missing documentation for a struct"); - for sdef.fields.each |field| { + for sdef.fields.iter().advance |field| { match field.node.kind { ast::named_field(_, vis) if vis != ast::private => { check_attrs(cx, field.node.attrs, field.span, @@ -1100,7 +1113,7 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) { } // Install command-line options, overriding defaults. - for tcx.sess.opts.lint_opts.each |&(lint, level)| { + for tcx.sess.opts.lint_opts.iter().advance |&(lint, level)| { cx.set_level(lint, level, CommandLine); } @@ -1157,8 +1170,8 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) { // If we missed any lints added to the session, then there's a bug somewhere // in the iteration code. - for tcx.sess.lints.each |_, v| { - for v.each |t| { + for tcx.sess.lints.iter().advance |(_, v)| { + for v.iter().advance |t| { match *t { (lint, span, ref msg) => tcx.sess.span_bug(span, fmt!("unprocessed lint %?: %s", diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 08cba4d51cd..83f8b161b75 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -102,7 +102,6 @@ * to return explicitly. */ -use core::prelude::*; use middle::lint::{unused_variable, dead_assignment}; use middle::pat_util; @@ -110,12 +109,12 @@ use middle::ty; use middle::typeck; use middle::moves; -use core::cast::transmute; -use core::hashmap::HashMap; -use core::io; -use core::to_str; -use core::uint; -use core::vec; +use std::cast::transmute; +use std::hashmap::HashMap; +use std::io; +use std::to_str; +use std::uint; +use std::vec; use syntax::ast::*; use syntax::codemap::span; use syntax::parse::token::special_idents; @@ -150,7 +149,7 @@ fn live_node_kind_to_str(lnk: LiveNodeKind, cx: ty::ctxt) -> ~str { pub fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, capture_map: moves::CaptureMap, - crate: @crate) { + crate: &crate) { let visitor = visit::mk_vt(@visit::Visitor { visit_fn: visit_fn, visit_local: visit_local, @@ -322,7 +321,7 @@ impl IrMaps { self.capture_info_map.insert(node_id, @cs); } - pub fn captures(&mut self, expr: @expr) -> @~[CaptureInfo] { + pub fn captures(&mut self, expr: &expr) -> @~[CaptureInfo] { match self.capture_info_map.find(&expr.id) { Some(&caps) => caps, None => { @@ -355,7 +354,7 @@ fn visit_fn(fk: &visit::fn_kind, debug!("creating fn_maps: %x", transmute(&*fn_maps)); } - for decl.inputs.each |arg| { + for decl.inputs.iter().advance |arg| { do pat_util::pat_bindings(this.tcx.def_map, arg.pat) |_bm, arg_id, _x, path| { debug!("adding argument %d", arg_id); @@ -368,7 +367,7 @@ fn visit_fn(fk: &visit::fn_kind, match *fk { fk_method(_, _, method) => { match method.explicit_self.node { - sty_value | sty_region(*) | sty_box(_) | sty_uniq(_) => { + sty_value | sty_region(*) | sty_box(_) | sty_uniq => { fn_maps.add_variable(Arg(method.self_id, special_idents::self_)); } @@ -431,7 +430,7 @@ fn visit_local(local: @local, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) { fn visit_arm(arm: &arm, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) { let def_map = this.tcx.def_map; - for arm.pats.each |pat| { + for arm.pats.iter().advance |pat| { do pat_util::pat_bindings(def_map, *pat) |bm, p_id, sp, path| { debug!("adding local variable %d from match with bm %?", p_id, bm); @@ -470,7 +469,7 @@ fn visit_expr(expr: @expr, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) { // construction site. let cvs = this.capture_map.get(&expr.id); let mut call_caps = ~[]; - for cvs.each |cv| { + for cvs.iter().advance |cv| { match moves::moved_variable_node_id_from_def(cv.def) { Some(rv) => { let cv_ln = this.add_live_node(FreeVarNode(cv.span)); @@ -596,7 +595,7 @@ impl Liveness { } } - pub fn variable_from_path(&self, expr: @expr) -> Option<Variable> { + pub fn variable_from_path(&self, expr: &expr) -> Option<Variable> { match expr.node { expr_path(_) => { let def = self.tcx.def_map.get_copy(&expr.id); @@ -923,7 +922,7 @@ impl Liveness { } } - pub fn propagate_through_stmt(&self, stmt: @stmt, succ: LiveNode) + pub fn propagate_through_stmt(&self, stmt: &stmt, succ: LiveNode) -> LiveNode { match stmt.node { stmt_decl(decl, _) => { @@ -940,7 +939,7 @@ impl Liveness { } } - pub fn propagate_through_decl(&self, decl: @decl, succ: LiveNode) + pub fn propagate_through_decl(&self, decl: &decl, succ: LiveNode) -> LiveNode { match decl.node { decl_local(ref local) => { @@ -950,7 +949,7 @@ impl Liveness { } } - pub fn propagate_through_local(&self, local: @local, succ: LiveNode) + pub fn propagate_through_local(&self, local: &local, succ: LiveNode) -> LiveNode { // Note: we mark the variable as defined regardless of whether // there is an initializer. Initially I had thought to only mark @@ -1075,7 +1074,7 @@ impl Liveness { let ln = self.live_node(expr.id, expr.span); self.init_empty(ln, succ); let mut first_merge = true; - for arms.each |arm| { + for arms.iter().advance |arm| { let body_succ = self.propagate_through_block(&arm.body, succ); let guard_succ = @@ -1293,7 +1292,7 @@ impl Liveness { } // see comment on propagate_through_lvalue() - pub fn write_lvalue(&self, expr: @expr, succ: LiveNode, acc: uint) + pub fn write_lvalue(&self, expr: &expr, succ: LiveNode, acc: uint) -> LiveNode { match expr.node { expr_path(_) => self.access_path(expr, succ, acc), @@ -1306,7 +1305,7 @@ impl Liveness { } } - pub fn access_path(&self, expr: @expr, succ: LiveNode, acc: uint) + pub fn access_path(&self, expr: &expr, succ: LiveNode, acc: uint) -> LiveNode { let def = self.tcx.def_map.get_copy(&expr.id); match moves::moved_variable_node_id_from_def(def) { @@ -1324,7 +1323,7 @@ impl Liveness { } pub fn propagate_through_loop(&self, - expr: @expr, + expr: &expr, cond: Option<@expr>, body: &blk, succ: LiveNode) @@ -1453,12 +1452,12 @@ fn check_expr(expr: @expr, (this, vt): (@Liveness, vt<@Liveness>)) { } expr_inline_asm(ref ia) => { - for ia.inputs.each |&(_, in)| { + for ia.inputs.iter().advance |&(_, in)| { (vt.visit_expr)(in, (this, vt)); } // Output operands must be lvalues - for ia.outputs.each |&(_, out)| { + for ia.outputs.iter().advance |&(_, out)| { match out.node { expr_addr_of(_, inner) => { this.check_lvalue(inner, vt); @@ -1594,7 +1593,7 @@ impl Liveness { } pub fn warn_about_unused_args(&self, decl: &fn_decl, entry_ln: LiveNode) { - for decl.inputs.each |arg| { + for decl.inputs.iter().advance |arg| { do pat_util::pat_bindings(self.tcx.def_map, arg.pat) |_bm, p_id, sp, _n| { let var = self.variable(p_id, sp); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 14764e7bc37..fd36858ba68 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -46,14 +46,13 @@ * then an index to jump forward to the relevant item. */ -use core::prelude::*; use middle::ty; use middle::typeck; -use util::ppaux::{ty_to_str, region_to_str, Repr}; +use util::ppaux::{ty_to_str, region_ptr_to_str, Repr}; use util::common::indenter; -use core::uint; +use std::uint; use syntax::ast::{m_imm, m_const, m_mutbl}; use syntax::ast; use syntax::codemap::span; @@ -78,7 +77,7 @@ pub enum categorization { } #[deriving(Eq)] -struct CopiedUpvar { +pub struct CopiedUpvar { upvar_id: ast::node_id, onceness: ast::Onceness, } @@ -447,19 +446,29 @@ impl mem_categorization_ctxt { -> cmt { match def { ast::def_fn(*) | ast::def_static_method(*) | ast::def_mod(_) | - ast::def_foreign_mod(_) | ast::def_const(_) | + ast::def_foreign_mod(_) | ast::def_static(_, false) | ast::def_use(_) | ast::def_variant(*) | ast::def_trait(_) | ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty_param(*) | ast::def_struct(*) | ast::def_typaram_binder(*) | ast::def_region(_) | - ast::def_label(_) | ast::def_self_ty(*) => { - @cmt_ { - id:id, - span:span, - cat:cat_static_item, - mutbl: McImmutable, - ty:expr_ty - } + ast::def_label(_) | ast::def_self_ty(*) | ast::def_method(*) => { + @cmt_ { + id:id, + span:span, + cat:cat_static_item, + mutbl: McImmutable, + ty:expr_ty + } + } + + ast::def_static(_, true) => { + @cmt_ { + id:id, + span:span, + cat:cat_static_item, + mutbl: McDeclared, + ty:expr_ty + } } ast::def_arg(vid, mutbl) => { @@ -497,30 +506,41 @@ impl mem_categorization_ctxt { let ty = ty::node_id_to_type(self.tcx, fn_node_id); match ty::get(ty).sty { ty::ty_closure(ref closure_ty) => { - let sigil = closure_ty.sigil; - match sigil { - ast::BorrowedSigil => { - let upvar_cmt = - self.cat_def(id, span, expr_ty, *inner); - @cmt_ { - id:id, - span:span, - cat:cat_stack_upvar(upvar_cmt), - mutbl:upvar_cmt.mutbl.inherit(), - ty:upvar_cmt.ty - } + // Decide whether to use implicit reference or by copy/move + // capture for the upvar. This, combined with the onceness, + // determines whether the closure can move out of it. + let var_is_refd = match (closure_ty.sigil, closure_ty.onceness) { + // Many-shot stack closures can never move out. + (ast::BorrowedSigil, ast::Many) => true, + // 1-shot stack closures can move out with "-Z once-fns". + (ast::BorrowedSigil, ast::Once) + if self.tcx.sess.once_fns() => false, + (ast::BorrowedSigil, ast::Once) => true, + // Heap closures always capture by copy/move, and can + // move out iff they are once. + (ast::OwnedSigil, _) | (ast::ManagedSigil, _) => false, + + }; + if var_is_refd { + let upvar_cmt = + self.cat_def(id, span, expr_ty, *inner); + @cmt_ { + id:id, + span:span, + cat:cat_stack_upvar(upvar_cmt), + mutbl:upvar_cmt.mutbl.inherit(), + ty:upvar_cmt.ty } - ast::OwnedSigil | ast::ManagedSigil => { - // FIXME #2152 allow mutation of moved upvars - @cmt_ { - id:id, - span:span, - cat:cat_copied_upvar(CopiedUpvar { - upvar_id: upvar_id, - onceness: closure_ty.onceness}), - mutbl:McImmutable, - ty:expr_ty - } + } else { + // FIXME #2152 allow mutation of moved upvars + @cmt_ { + id:id, + span:span, + cat:cat_copied_upvar(CopiedUpvar { + upvar_id: upvar_id, + onceness: closure_ty.onceness}), + mutbl:McImmutable, + ty:expr_ty } } } @@ -872,7 +892,7 @@ impl mem_categorization_ctxt { } }; - for subpats.eachi |i, &subpat| { + for subpats.iter().enumerate().advance |(i, &subpat)| { let subpat_ty = self.pat_ty(subpat); // see (*) let subcmt = @@ -880,23 +900,23 @@ impl mem_categorization_ctxt { pat, downcast_cmt, subpat_ty, InteriorField(PositionalField(i))); - self.cat_pattern(subcmt, subpat, op); + self.cat_pattern(subcmt, subpat, |x,y| op(x,y)); } } Some(&ast::def_fn(*)) | Some(&ast::def_struct(*)) => { - for subpats.eachi |i, &subpat| { + for subpats.iter().enumerate().advance |(i, &subpat)| { let subpat_ty = self.pat_ty(subpat); // see (*) let cmt_field = self.cat_imm_interior( pat, cmt, subpat_ty, InteriorField(PositionalField(i))); - self.cat_pattern(cmt_field, subpat, op); + self.cat_pattern(cmt_field, subpat, |x,y| op(x,y)); } } - Some(&ast::def_const(*)) => { - for subpats.each |&subpat| { - self.cat_pattern(cmt, subpat, op); + Some(&ast::def_static(*)) => { + for subpats.iter().advance |&subpat| { + self.cat_pattern(cmt, subpat, |x,y| op(x,y)); } } _ => { @@ -917,22 +937,22 @@ impl mem_categorization_ctxt { ast::pat_struct(_, ref field_pats, _) => { // {f1: p1, ..., fN: pN} - for field_pats.each |fp| { + for field_pats.iter().advance |fp| { let field_ty = self.pat_ty(fp.pat); // see (*) let cmt_field = self.cat_field(pat, cmt, fp.ident, field_ty); - self.cat_pattern(cmt_field, fp.pat, op); + self.cat_pattern(cmt_field, fp.pat, |x,y| op(x,y)); } } ast::pat_tup(ref subpats) => { // (p1, ..., pN) - for subpats.eachi |i, &subpat| { + for subpats.iter().enumerate().advance |(i, &subpat)| { let subpat_ty = self.pat_ty(subpat); // see (*) let subcmt = self.cat_imm_interior( pat, cmt, subpat_ty, InteriorField(PositionalField(i))); - self.cat_pattern(subcmt, subpat, op); + self.cat_pattern(subcmt, subpat, |x,y| op(x,y)); } } @@ -945,16 +965,16 @@ impl mem_categorization_ctxt { ast::pat_vec(ref before, slice, ref after) => { let elt_cmt = self.cat_index(pat, cmt, 0); - for before.each |&before_pat| { - self.cat_pattern(elt_cmt, before_pat, op); + for before.iter().advance |&before_pat| { + self.cat_pattern(elt_cmt, before_pat, |x,y| op(x,y)); } for slice.iter().advance |&slice_pat| { let slice_ty = self.pat_ty(slice_pat); let slice_cmt = self.cat_rvalue(pat, slice_ty); - self.cat_pattern(slice_cmt, slice_pat, op); + self.cat_pattern(slice_cmt, slice_pat, |x,y| op(x,y)); } - for after.each |&after_pat| { - self.cat_pattern(elt_cmt, after_pat, op); + for after.iter().advance |&after_pat| { + self.cat_pattern(elt_cmt, after_pat, |x,y| op(x,y)); } } @@ -1026,7 +1046,7 @@ impl mem_categorization_ctxt { } pub fn region_to_str(&self, r: ty::Region) -> ~str { - region_to_str(self.tcx, r) + region_ptr_to_str(self.tcx, r) } } @@ -1041,7 +1061,8 @@ pub fn field_mutbl(tcx: ty::ctxt, // Need to refactor so that struct/enum fields can be treated uniformly. match ty::get(base_ty).sty { ty::ty_struct(did, _) => { - for ty::lookup_struct_fields(tcx, did).each |fld| { + let r = ty::lookup_struct_fields(tcx, did); + for r.iter().advance |fld| { if fld.ident == f_name { return Some(ast::m_imm); } @@ -1050,7 +1071,8 @@ pub fn field_mutbl(tcx: ty::ctxt, ty::ty_enum(*) => { match tcx.def_map.get_copy(&node_id) { ast::def_variant(_, variant_id) => { - for ty::lookup_struct_fields(tcx, variant_id).each |fld| { + let r = ty::lookup_struct_fields(tcx, variant_id); + for r.iter().advance |fld| { if fld.ident == f_name { return Some(ast::m_imm); } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index 2217e632d14..c7d338b1976 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -126,7 +126,6 @@ and so on. */ -use core::prelude::*; use middle::pat_util::{pat_bindings}; use middle::freevars; @@ -136,8 +135,8 @@ use util::ppaux; use util::ppaux::Repr; use util::common::indenter; -use core::at_vec; -use core::hashmap::{HashSet, HashMap}; +use std::at_vec; +use std::hashmap::{HashSet, HashMap}; use syntax::ast::*; use syntax::ast_util; use syntax::visit; @@ -183,6 +182,7 @@ struct VisitContext { move_maps: MoveMaps } +#[deriving(Eq)] enum UseMode { Move, // This value or something owned by it is moved. Read // Read no matter what the type. @@ -190,7 +190,7 @@ enum UseMode { pub fn compute_moves(tcx: ty::ctxt, method_map: method_map, - crate: @crate) -> MoveMaps + crate: &crate) -> MoveMaps { let visitor = visit::mk_vt(@visit::Visitor { visit_expr: compute_modes_for_expr, @@ -232,7 +232,7 @@ fn compute_modes_for_expr(expr: @expr, impl VisitContext { pub fn consume_exprs(&self, exprs: &[@expr], visitor: vt<VisitContext>) { - for exprs.each |expr| { + for exprs.iter().advance |expr| { self.consume_expr(*expr, visitor); } } @@ -263,7 +263,7 @@ impl VisitContext { debug!("consume_block(blk.id=%?)", blk.node.id); - for blk.node.stmts.each |stmt| { + for blk.node.stmts.iter().advance |stmt| { (visitor.visit_stmt)(*stmt, (*self, visitor)); } @@ -335,7 +335,27 @@ impl VisitContext { } expr_call(callee, ref args, _) => { // callee(args) - self.use_expr(callee, Read, visitor); + // Figure out whether the called function is consumed. + let mode = match ty::get(ty::expr_ty(self.tcx, callee)).sty { + ty::ty_closure(ref cty) => { + match cty.onceness { + Once => Move, + Many => Read, + } + }, + ty::ty_bare_fn(*) => Read, + ref x => + self.tcx.sess.span_bug(callee.span, + fmt!("non-function type in moves for expr_call: %?", x)), + }; + // Note we're not using consume_expr, which uses type_moves_by_default + // to determine the mode, for this. The reason is that while stack + // closures should be noncopyable, they shouldn't move by default; + // calling a closure should only consume it if it's once. + if mode == Move { + self.move_maps.moves_map.insert(callee.id); + } + self.use_expr(callee, mode, visitor); self.use_fn_args(callee.id, *args, visitor); } @@ -347,7 +367,7 @@ impl VisitContext { } expr_struct(_, ref fields, opt_with) => { - for fields.each |field| { + for fields.iter().advance |field| { self.consume_expr(field.node.expr, visitor); } @@ -370,8 +390,8 @@ impl VisitContext { // any fields which (1) were not explicitly // specified and (2) have a type that // moves-by-default: - let consume_with = with_fields.any(|tf| { - !fields.any(|f| f.node.ident == tf.ident) && + let consume_with = with_fields.iter().any_(|tf| { + !fields.iter().any_(|f| f.node.ident == tf.ident) && ty::type_moves_by_default(self.tcx, tf.mt.ty) }); @@ -398,7 +418,7 @@ impl VisitContext { expr_match(discr, ref arms) => { // We must do this first so that `arms_have_by_move_bindings` // below knows which bindings are moves. - for arms.each |arm| { + for arms.iter().advance |arm| { self.consume_arm(arm, visitor); } @@ -521,7 +541,7 @@ impl VisitContext { } pub fn use_overloaded_operator(&self, - expr: @expr, + expr: &expr, receiver_expr: @expr, arg_exprs: &[@expr], visitor: vt<VisitContext>) @@ -534,7 +554,7 @@ impl VisitContext { // for overloaded operatrs, we are always passing in a // borrowed pointer, so it's always read mode: - for arg_exprs.each |arg_expr| { + for arg_exprs.iter().advance |arg_expr| { self.use_expr(*arg_expr, Read, visitor); } @@ -591,7 +611,7 @@ impl VisitContext { arg_exprs: &[@expr], visitor: vt<VisitContext>) { //! Uses the argument expressions. - for arg_exprs.each |arg_expr| { + for arg_exprs.iter().advance |arg_expr| { self.use_fn_arg(*arg_expr, visitor); } } @@ -605,8 +625,8 @@ impl VisitContext { moves_map: MovesMap, arms: &[arm]) -> Option<@pat> { - for arms.each |arm| { - for arm.pats.each |&pat| { + for arms.iter().advance |arm| { + for arm.pats.iter().advance |&pat| { for ast_util::walk_pat(pat) |p| { if moves_map.contains(&p.id) { return Some(p); diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 1237e9fb4a2..f6da8f392cc 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use middle::resolve; -use core::hashmap::HashMap; +use std::hashmap::HashMap; use syntax::ast::*; use syntax::ast_util::{path_to_ident, walk_pat}; use syntax::codemap::span; @@ -29,7 +28,7 @@ pub fn pat_id_map(dm: resolve::DefMap, pat: @pat) -> PatIdMap { map } -pub fn pat_is_variant_or_struct(dm: resolve::DefMap, pat: @pat) -> bool { +pub fn pat_is_variant_or_struct(dm: resolve::DefMap, pat: &pat) -> bool { match pat.node { pat_enum(_, _) | pat_ident(_, _, None) | pat_struct(*) => { match dm.find(&pat.id) { @@ -45,7 +44,7 @@ pub fn pat_is_const(dm: resolve::DefMap, pat: &pat) -> bool { match pat.node { pat_ident(_, _, None) | pat_enum(*) => { match dm.find(&pat.id) { - Some(&def_const(*)) => true, + Some(&def_static(_, false)) => true, _ => false } } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 60193f3fe5d..5e544dc06e3 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -11,7 +11,6 @@ // A pass that checks to make sure private fields and methods aren't used // outside their scopes. -use core::prelude::*; use metadata::csearch; use middle::ty::{ty_struct, ty_enum}; @@ -20,7 +19,7 @@ use middle::typeck::{method_map, method_origin, method_param, method_self}; use middle::typeck::{method_super}; use middle::typeck::{method_static, method_trait}; -use core::util::ignore; +use std::util::ignore; use syntax::ast::{decl_item, def, def_fn, def_id, def_static_method}; use syntax::ast::{def_variant, expr_field, expr_method_call, expr_path}; use syntax::ast::{expr_struct, expr_unary, ident, inherited, item_enum}; @@ -40,7 +39,7 @@ use syntax::visit; pub fn check_crate<'mm>(tcx: ty::ctxt, method_map: &'mm method_map, - crate: @ast::crate) { + crate: &ast::crate) { let privileged_items = @mut ~[]; // Adds an item to its scope. @@ -52,7 +51,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, *count += 1; } item_impl(_, _, _, ref methods) => { - for methods.each |method| { + for methods.iter().advance |method| { privileged_items.push(method.id); *count += 1; } @@ -60,7 +59,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, *count += 1; } item_foreign_mod(ref foreign_mod) => { - for foreign_mod.items.each |foreign_item| { + for foreign_mod.items.iter().advance |foreign_item| { privileged_items.push(foreign_item.id); *count += 1; } @@ -72,7 +71,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, // Adds items that are privileged to this scope. let add_privileged_items: @fn(&[@ast::item]) -> uint = |items| { let mut count = 0; - for items.each |&item| { + for items.iter().advance |&item| { add_privileged_item(item, &mut count); } count @@ -231,7 +230,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, let check_field: @fn(span: span, id: ast::def_id, ident: ast::ident) = |span, id, ident| { let fields = ty::lookup_struct_fields(tcx, id); - for fields.each |field| { + for fields.iter().advance |field| { if field.ident != ident { loop; } if field.vis == private { tcx.sess.span_err(span, fmt!("field `%s` is private", @@ -252,7 +251,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, method_id.node); if is_private && (container_id.crate != local_crate || - !privileged_items.contains(&(container_id.node))) { + !privileged_items.iter().any_(|x| x == &(container_id.node))) { tcx.sess.span_err(span, fmt!("method `%s` is private", token::ident_to_str(name))); @@ -280,7 +279,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, def_fn(def_id, _) => { if def_id.crate == local_crate { if local_item_is_private(span, def_id.node) && - !privileged_items.contains(&def_id.node) { + !privileged_items.iter().any_(|x| x == &def_id.node) { tcx.sess.span_err(span, fmt!("function `%s` is private", token::ident_to_str(path.idents.last()))); @@ -324,8 +323,8 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, match (*methods)[method_num] { provided(method) if method.vis == private && - !privileged_items - .contains(&(trait_id.node)) => { + !privileged_items.iter() + .any_(|x| x == &(trait_id.node)) => { tcx.sess.span_err(span, fmt!("method `%s` is private", token::ident_to_str(&method @@ -377,7 +376,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, visit_block: |block, (method_map, visitor)| { // Gather up all the privileged items. let mut n_added = 0; - for block.node.stmts.each |stmt| { + for block.node.stmts.iter().advance |stmt| { match stmt.node { stmt_decl(decl, _) => { match decl.node { @@ -409,7 +408,8 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx, base))).sty { ty_struct(id, _) - if id.crate != local_crate || !privileged_items.contains(&(id.node)) => { + if id.crate != local_crate || !privileged_items.iter() + .any_(|x| x == &(id.node)) => { debug!("(privacy checking) checking field access"); check_field(expr.span, id, ident); } @@ -422,7 +422,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, base))).sty { ty_struct(id, _) if id.crate != local_crate || - !privileged_items.contains(&(id.node)) => { + !privileged_items.iter().any_(|x| x == &(id.node)) => { match method_map.find(&expr.id) { None => { tcx.sess.span_bug(expr.span, @@ -448,8 +448,8 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, match ty::get(ty::expr_ty(tcx, expr)).sty { ty_struct(id, _) => { if id.crate != local_crate || - !privileged_items.contains(&(id.node)) { - for (*fields).each |field| { + !privileged_items.iter().any_(|x| x == &(id.node)) { + for (*fields).iter().advance |field| { debug!("(privacy checking) checking \ field in struct literal"); check_field(expr.span, id, @@ -459,10 +459,10 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } ty_enum(id, _) => { if id.crate != local_crate || - !privileged_items.contains(&(id.node)) { + !privileged_items.iter().any_(|x| x == &(id.node)) { match tcx.def_map.get_copy(&expr.id) { def_variant(_, variant_id) => { - for (*fields).each |field| { + for (*fields).iter().advance |field| { debug!("(privacy checking) \ checking field in \ struct variant \ @@ -496,7 +496,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, match ty::get(ty::expr_ty(tcx, operand)).sty { ty_enum(id, _) => { if id.crate != local_crate || - !privileged_items.contains(&(id.node)) { + !privileged_items.iter().any_(|x| x == &(id.node)) { check_variant(expr.span, id); } } @@ -514,8 +514,8 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, match ty::get(ty::pat_ty(tcx, pattern)).sty { ty_struct(id, _) => { if id.crate != local_crate || - !privileged_items.contains(&(id.node)) { - for fields.each |field| { + !privileged_items.iter().any_(|x| x == &(id.node)) { + for fields.iter().advance |field| { debug!("(privacy checking) checking \ struct pattern"); check_field(pattern.span, id, @@ -525,11 +525,10 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } ty_enum(enum_id, _) => { if enum_id.crate != local_crate || - !privileged_items.contains( - &enum_id.node) { + !privileged_items.iter().any_(|x| x == &enum_id.node) { match tcx.def_map.find(&pattern.id) { Some(&def_variant(_, variant_id)) => { - for fields.each |field| { + for fields.iter().advance |field| { debug!("(privacy checking) \ checking field in \ struct variant pattern"); diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs new file mode 100644 index 00000000000..97bad93dc35 --- /dev/null +++ b/src/librustc/middle/reachable.rs @@ -0,0 +1,434 @@ +// 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. + +// Finds items that are externally reachable, to determine which items +// need to have their metadata (and possibly their AST) serialized. +// All items that can be referred to through an exported name are +// reachable, and when a reachable thing is inline or generic, it +// makes all other generics or inline functions that it references +// reachable as well. + +use std::iterator::IteratorUtil; + +use middle::ty; +use middle::typeck; + +use std::hashmap::HashSet; +use syntax::ast::*; +use syntax::ast_map; +use syntax::ast_util::def_id_of_def; +use syntax::attr; +use syntax::parse::token; +use syntax::visit::Visitor; +use syntax::visit; + +// Returns true if the given set of attributes contains the `#[inline]` +// attribute. +fn attributes_specify_inlining(attrs: &[attribute]) -> bool { + attr::attrs_contains_name(attrs, "inline") +} + +// Returns true if the given set of generics implies that the item it's +// associated with must be inlined. +fn generics_require_inlining(generics: &Generics) -> bool { + !generics.ty_params.is_empty() +} + +// Returns true if the given item must be inlined because it may be +// monomorphized or it was marked with `#[inline]`. This will only return +// true for functions. +fn item_might_be_inlined(item: @item) -> bool { + if attributes_specify_inlining(item.attrs) { + return true + } + + match item.node { + item_fn(_, _, _, ref generics, _) => { + generics_require_inlining(generics) + } + _ => false, + } +} + +// Returns true if the given type method must be inlined because it may be +// monomorphized or it was marked with `#[inline]`. +fn ty_method_might_be_inlined(ty_method: &ty_method) -> bool { + attributes_specify_inlining(ty_method.attrs) || + generics_require_inlining(&ty_method.generics) +} + +// Returns true if the given trait method must be inlined because it may be +// monomorphized or it was marked with `#[inline]`. +fn trait_method_might_be_inlined(trait_method: &trait_method) -> bool { + match *trait_method { + required(ref ty_method) => ty_method_might_be_inlined(ty_method), + provided(_) => true + } +} + +// The context we're in. If we're in a public context, then public symbols are +// marked reachable. If we're in a private context, then only trait +// implementations are marked reachable. +#[deriving(Eq)] +enum PrivacyContext { + PublicContext, + PrivateContext, +} + +// Information needed while computing reachability. +struct ReachableContext { + // The type context. + tcx: ty::ctxt, + // The method map, which links node IDs of method call expressions to the + // methods they've been resolved to. + method_map: typeck::method_map, + // The set of items which must be exported in the linkage sense. + reachable_symbols: @mut HashSet<node_id>, + // A worklist of item IDs. Each item ID in this worklist will be inlined + // and will be scanned for further references. + worklist: @mut ~[node_id], +} + +impl ReachableContext { + // Creates a new reachability computation context. + fn new(tcx: ty::ctxt, method_map: typeck::method_map) + -> ReachableContext { + ReachableContext { + tcx: tcx, + method_map: method_map, + reachable_symbols: @mut HashSet::new(), + worklist: @mut ~[], + } + } + + // Step 1: Mark all public symbols, and add all public symbols that might + // be inlined to a worklist. + fn mark_public_symbols(&self, crate: @crate) { + let reachable_symbols = self.reachable_symbols; + let worklist = self.worklist; + let visitor = visit::mk_vt(@Visitor { + visit_item: |item, (privacy_context, visitor): + (PrivacyContext, visit::vt<PrivacyContext>)| { + match item.node { + item_fn(*) => { + if privacy_context == PublicContext { + reachable_symbols.insert(item.id); + } + if item_might_be_inlined(item) { + worklist.push(item.id) + } + } + item_struct(ref struct_def, _) => { + match struct_def.ctor_id { + Some(ctor_id) if + privacy_context == PublicContext => { + reachable_symbols.insert(ctor_id); + } + Some(_) | None => {} + } + } + item_enum(ref enum_def, _) => { + if privacy_context == PublicContext { + for enum_def.variants.iter().advance |variant| { + reachable_symbols.insert(variant.node.id); + } + } + } + item_impl(ref generics, trait_ref, _, ref methods) => { + // XXX(pcwalton): We conservatively assume any methods + // on a trait implementation are reachable, when this + // is not the case. We could be more precise by only + // treating implementations of reachable or cross- + // crate traits as reachable. + + let should_be_considered_public = |method: @method| { + (method.vis == public && + privacy_context == PublicContext) || + trait_ref.is_some() + }; + + // Mark all public methods as reachable. + for methods.iter().advance |&method| { + if should_be_considered_public(method) { + reachable_symbols.insert(method.id); + } + } + + if generics_require_inlining(generics) { + // If the impl itself has generics, add all public + // symbols to the worklist. + for methods.iter().advance |&method| { + if should_be_considered_public(method) { + worklist.push(method.id) + } + } + } else { + // Otherwise, add only public methods that have + // generics to the worklist. + for methods.iter().advance |method| { + let generics = &method.generics; + let attrs = &method.attrs; + if generics_require_inlining(generics) || + attributes_specify_inlining(*attrs) || + should_be_considered_public(*method) { + worklist.push(method.id) + } + } + } + } + item_trait(_, _, ref trait_methods) => { + // Mark all provided methods as reachable. + if privacy_context == PublicContext { + for trait_methods.iter().advance |trait_method| { + match *trait_method { + provided(method) => { + reachable_symbols.insert(method.id); + worklist.push(method.id) + } + required(_) => {} + } + } + } + } + _ => {} + } + + if item.vis == public && privacy_context == PublicContext { + visit::visit_item(item, (PublicContext, visitor)) + } else { + visit::visit_item(item, (PrivateContext, visitor)) + } + }, + .. *visit::default_visitor() + }); + + visit::visit_crate(crate, (PublicContext, visitor)) + } + + // Returns true if the given def ID represents a local item that is + // eligible for inlining and false otherwise. + fn def_id_represents_local_inlined_item(tcx: ty::ctxt, def_id: def_id) + -> bool { + if def_id.crate != local_crate { + return false + } + + let node_id = def_id.node; + match tcx.items.find(&node_id) { + Some(&ast_map::node_item(item, _)) => { + match item.node { + item_fn(*) => item_might_be_inlined(item), + _ => false, + } + } + Some(&ast_map::node_trait_method(trait_method, _, _)) => { + match *trait_method { + required(_) => false, + provided(_) => true, + } + } + Some(&ast_map::node_method(method, impl_did, _)) => { + if generics_require_inlining(&method.generics) || + attributes_specify_inlining(method.attrs) { + true + } else { + // Check the impl. If the generics on the self type of the + // impl require inlining, this method does too. + assert!(impl_did.crate == local_crate); + match tcx.items.find(&impl_did.node) { + Some(&ast_map::node_item(item, _)) => { + match item.node { + item_impl(ref generics, _, _, _) => { + generics_require_inlining(generics) + } + _ => false + } + } + Some(_) => { + tcx.sess.span_bug(method.span, + "method is not inside an \ + impl?!") + } + None => { + tcx.sess.span_bug(method.span, + "the impl that this method is \ + supposedly inside of doesn't \ + exist in the AST map?!") + } + } + } + } + Some(_) => false, + None => false // This will happen for default methods. + } + } + + // Helper function to set up a visitor for `propagate()` below. + fn init_visitor(&self) -> visit::vt<()> { + let (worklist, method_map) = (self.worklist, self.method_map); + let (tcx, reachable_symbols) = (self.tcx, self.reachable_symbols); + visit::mk_vt(@visit::Visitor { + visit_expr: |expr, (_, visitor)| { + match expr.node { + expr_path(_) => { + let def = match tcx.def_map.find(&expr.id) { + Some(&def) => def, + None => { + tcx.sess.span_bug(expr.span, + "def ID not in def map?!") + } + }; + + let def_id = def_id_of_def(def); + if ReachableContext:: + def_id_represents_local_inlined_item(tcx, + def_id) { + worklist.push(def_id.node) + } + reachable_symbols.insert(def_id.node); + } + expr_method_call(*) => { + match method_map.find(&expr.id) { + Some(&typeck::method_map_entry { + origin: typeck::method_static(def_id), + _ + }) => { + if ReachableContext:: + def_id_represents_local_inlined_item( + tcx, + def_id) { + worklist.push(def_id.node) + } + reachable_symbols.insert(def_id.node); + } + Some(_) => {} + None => { + tcx.sess.span_bug(expr.span, + "method call expression \ + not in method map?!") + } + } + } + _ => {} + } + + visit::visit_expr(expr, ((), visitor)) + }, + ..*visit::default_visitor() + }) + } + + // Step 2: Mark all symbols that the symbols on the worklist touch. + fn propagate(&self) { + let visitor = self.init_visitor(); + let mut scanned = HashSet::new(); + while self.worklist.len() > 0 { + let search_item = self.worklist.pop(); + if scanned.contains(&search_item) { + loop + } + scanned.insert(search_item); + self.reachable_symbols.insert(search_item); + + // Find the AST block corresponding to the item and visit it, + // marking all path expressions that resolve to something + // interesting. + match self.tcx.items.find(&search_item) { + Some(&ast_map::node_item(item, _)) => { + match item.node { + item_fn(_, _, _, _, ref search_block) => { + visit::visit_block(search_block, ((), visitor)) + } + _ => { + self.tcx.sess.span_bug(item.span, + "found non-function item \ + in worklist?!") + } + } + } + Some(&ast_map::node_trait_method(trait_method, _, _)) => { + match *trait_method { + required(ref ty_method) => { + self.tcx.sess.span_bug(ty_method.span, + "found required method in \ + worklist?!") + } + provided(ref method) => { + visit::visit_block(&method.body, ((), visitor)) + } + } + } + Some(&ast_map::node_method(ref method, _, _)) => { + visit::visit_block(&method.body, ((), visitor)) + } + Some(_) => { + let ident_interner = token::get_ident_interner(); + let desc = ast_map::node_id_to_str(self.tcx.items, + search_item, + ident_interner); + self.tcx.sess.bug(fmt!("found unexpected thingy in \ + worklist: %s", + desc)) + } + None => { + self.tcx.sess.bug(fmt!("found unmapped ID in worklist: \ + %d", + search_item)) + } + } + } + } + + // Step 3: Mark all destructors as reachable. + // + // XXX(pcwalton): This is a conservative overapproximation, but fixing + // this properly would result in the necessity of computing *type* + // reachability, which might result in a compile time loss. + fn mark_destructors_reachable(&self) { + for self.tcx.destructor_for_type.iter().advance + |(_, destructor_def_id)| { + if destructor_def_id.crate == local_crate { + self.reachable_symbols.insert(destructor_def_id.node); + } + } + } +} + +pub fn find_reachable(tcx: ty::ctxt, + method_map: typeck::method_map, + crate: @crate) + -> @mut HashSet<node_id> { + // XXX(pcwalton): We only need to mark symbols that are exported. But this + // is more complicated than just looking at whether the symbol is `pub`, + // because it might be the target of a `pub use` somewhere. For now, I + // think we are fine, because you can't `pub use` something that wasn't + // exported due to the bug whereby `use` only looks through public + // modules even if you're inside the module the `use` appears in. When + // this bug is fixed, however, this code will need to be updated. Probably + // the easiest way to fix this (although a conservative overapproximation) + // is to have the name resolution pass mark all targets of a `pub use` as + // "must be reachable". + + let reachable_context = ReachableContext::new(tcx, method_map); + + // Step 1: Mark all public symbols, and add all public symbols that might + // be inlined to a worklist. + reachable_context.mark_public_symbols(crate); + + // Step 2: Mark all symbols that the symbols on the worklist touch. + reachable_context.propagate(); + + // Step 3: Mark all destructors as reachable. + reachable_context.mark_destructors_reachable(); + + // Return the set of reachable symbols. + reachable_context.reachable_symbols +} + diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index f8d0b19922e..f65d3ad464c 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -15,9 +15,11 @@ pass builds up the `scope_map`, which describes the parent links in the region hierarchy. The second pass infers which types must be region parameterized. +Most of the documentation on regions can be found in +`middle/typeck/infer/region_inference.rs` + */ -use core::prelude::*; use driver::session::Session; use metadata::csearch; @@ -26,7 +28,7 @@ use middle::ty::{region_variance, rv_covariant, rv_invariant}; use middle::ty::{rv_contravariant, FreeRegion}; use middle::ty; -use core::hashmap::{HashMap, HashSet}; +use std::hashmap::{HashMap, HashSet}; use syntax::ast_map; use syntax::codemap::span; use syntax::print::pprust; @@ -34,8 +36,6 @@ use syntax::parse::token; use syntax::parse::token::special_idents; use syntax::{ast, visit}; -pub type parent = Option<ast::node_id>; - /** The region maps encode information about region relationships. @@ -68,17 +68,17 @@ pub struct Context { region_maps: @mut RegionMaps, // Scope where variables should be parented to - var_parent: parent, + var_parent: Option<ast::node_id>, // Innermost enclosing expression - parent: parent, + parent: Option<ast::node_id>, } impl RegionMaps { pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) { match self.free_region_map.find_mut(&sub) { Some(sups) => { - if !sups.contains(&sup) { + if !sups.iter().any_(|x| x == &sup) { sups.push(sup); } return; @@ -197,12 +197,12 @@ impl RegionMaps { while i < queue.len() { match self.free_region_map.find(&queue[i]) { Some(parents) => { - for parents.each |parent| { + for parents.iter().advance |parent| { if *parent == sup { return true; } - if !queue.contains(parent) { + if !queue.iter().any_(|x| x == parent) { queue.push(*parent); } } @@ -313,20 +313,8 @@ impl RegionMaps { } } -/// Extracts that current parent from cx, failing if there is none. -pub fn parent_id(cx: Context, span: span) -> ast::node_id { - match cx.parent { - None => { - cx.sess.span_bug(span, "crate should not be parent here"); - } - Some(parent_id) => { - parent_id - } - } -} - /// Records the current parent (if any) as the parent of `child_id`. -pub fn parent_to_expr(cx: Context, child_id: ast::node_id, sp: span) { +fn parent_to_expr(cx: Context, child_id: ast::node_id, sp: span) { debug!("region::parent_to_expr(span=%?)", cx.sess.codemap.span_to_str(sp)); for cx.parent.iter().advance |parent_id| { @@ -334,7 +322,7 @@ pub fn parent_to_expr(cx: Context, child_id: ast::node_id, sp: span) { } } -pub fn resolve_block(blk: &ast::blk, (cx, visitor): (Context, visit::vt<Context>)) { +fn resolve_block(blk: &ast::blk, (cx, visitor): (Context, visit::vt<Context>)) { // Record the parent of this block. parent_to_expr(cx, blk.node.id, blk.span); @@ -345,17 +333,17 @@ pub fn resolve_block(blk: &ast::blk, (cx, visitor): (Context, visit::vt<Context> visit::visit_block(blk, (new_cx, visitor)); } -pub fn resolve_arm(arm: &ast::arm, (cx, visitor): (Context, visit::vt<Context>)) { +fn resolve_arm(arm: &ast::arm, (cx, visitor): (Context, visit::vt<Context>)) { visit::visit_arm(arm, (cx, visitor)); } -pub fn resolve_pat(pat: @ast::pat, (cx, visitor): (Context, visit::vt<Context>)) { +fn resolve_pat(pat: @ast::pat, (cx, visitor): (Context, visit::vt<Context>)) { assert_eq!(cx.var_parent, cx.parent); parent_to_expr(cx, pat.id, pat.span); visit::visit_pat(pat, (cx, visitor)); } -pub fn resolve_stmt(stmt: @ast::stmt, (cx, visitor): (Context, visit::vt<Context>)) { +fn resolve_stmt(stmt: @ast::stmt, (cx, visitor): (Context, visit::vt<Context>)) { match stmt.node { ast::stmt_decl(*) => { visit::visit_stmt(stmt, (cx, visitor)); @@ -370,7 +358,7 @@ pub fn resolve_stmt(stmt: @ast::stmt, (cx, visitor): (Context, visit::vt<Context } } -pub fn resolve_expr(expr: @ast::expr, (cx, visitor): (Context, visit::vt<Context>)) { +fn resolve_expr(expr: @ast::expr, (cx, visitor): (Context, visit::vt<Context>)) { parent_to_expr(cx, expr.id, expr.span); let mut new_cx = cx; @@ -409,27 +397,27 @@ pub fn resolve_expr(expr: @ast::expr, (cx, visitor): (Context, visit::vt<Context visit::visit_expr(expr, (new_cx, visitor)); } -pub fn resolve_local(local: @ast::local, - (cx, visitor) : (Context, - visit::vt<Context>)) { +fn resolve_local(local: @ast::local, + (cx, visitor) : (Context, + visit::vt<Context>)) { assert_eq!(cx.var_parent, cx.parent); parent_to_expr(cx, local.node.id, local.span); visit::visit_local(local, (cx, visitor)); } -pub fn resolve_item(item: @ast::item, (cx, visitor): (Context, visit::vt<Context>)) { +fn resolve_item(item: @ast::item, (cx, visitor): (Context, visit::vt<Context>)) { // Items create a new outer block scope as far as we're concerned. let new_cx = Context {var_parent: None, parent: None, ..cx}; visit::visit_item(item, (new_cx, visitor)); } -pub fn resolve_fn(fk: &visit::fn_kind, - decl: &ast::fn_decl, - body: &ast::blk, - sp: span, - id: ast::node_id, - (cx, visitor): (Context, - visit::vt<Context>)) { +fn resolve_fn(fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::blk, + sp: span, + id: ast::node_id, + (cx, visitor): (Context, + visit::vt<Context>)) { debug!("region::resolve_fn(id=%?, \ span=%?, \ body.node.id=%?, \ @@ -468,7 +456,7 @@ pub fn resolve_fn(fk: &visit::fn_kind, pub fn resolve_crate(sess: Session, def_map: resolve::DefMap, - crate: @ast::crate) -> @mut RegionMaps + crate: &ast::crate) -> @mut RegionMaps { let region_maps = @mut RegionMaps { scope_map: HashMap::new(), @@ -522,14 +510,12 @@ pub struct region_dep { id: ast::node_id } -pub type dep_map = @mut HashMap<ast::node_id, @mut ~[region_dep]>; - pub struct DetermineRpCtxt { sess: Session, ast_map: ast_map::map, def_map: resolve::DefMap, region_paramd_items: region_paramd_items, - dep_map: dep_map, + dep_map: @mut HashMap<ast::node_id, @mut ~[region_dep]>, worklist: ~[ast::node_id], // the innermost enclosing item id @@ -619,20 +605,14 @@ impl DetermineRpCtxt { ast_map::node_id_to_str(self.ast_map, self.item_id, token::get_ident_interner()), copy self.ambient_variance); - let vec = match self.dep_map.find(&from) { - Some(&vec) => vec, - None => { - let vec = @mut ~[]; - let dep_map = self.dep_map; - dep_map.insert(from, vec); - vec - } + let vec = do self.dep_map.find_or_insert_with(from) |_| { + @mut ~[] }; let dep = region_dep { ambient_variance: self.ambient_variance, id: self.item_id }; - if !vec.contains(&dep) { vec.push(dep); } + if !vec.iter().any_(|x| x == &dep) { vec.push(dep); } } // Determines whether a reference to a region that appears in the @@ -715,24 +695,24 @@ impl DetermineRpCtxt { } } -pub fn determine_rp_in_item(item: @ast::item, - (cx, visitor): (@mut DetermineRpCtxt, - visit::vt<@mut DetermineRpCtxt>)) { +fn determine_rp_in_item(item: @ast::item, + (cx, visitor): (@mut DetermineRpCtxt, + visit::vt<@mut DetermineRpCtxt>)) { do cx.with(item.id, true) { visit::visit_item(item, (cx, visitor)); } } -pub fn determine_rp_in_fn(fk: &visit::fn_kind, - decl: &ast::fn_decl, - body: &ast::blk, - _: span, - _: ast::node_id, - (cx, visitor): (@mut DetermineRpCtxt, - visit::vt<@mut DetermineRpCtxt>)) { +fn determine_rp_in_fn(fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::blk, + _: span, + _: ast::node_id, + (cx, visitor): (@mut DetermineRpCtxt, + visit::vt<@mut DetermineRpCtxt>)) { do cx.with(cx.item_id, false) { do cx.with_ambient_variance(rv_contravariant) { - for decl.inputs.each |a| { + for decl.inputs.iter().advance |a| { (visitor.visit_ty)(a.ty, (cx, visitor)); } } @@ -743,17 +723,17 @@ pub fn determine_rp_in_fn(fk: &visit::fn_kind, } } -pub fn determine_rp_in_ty_method(ty_m: &ast::ty_method, - (cx, visitor): (@mut DetermineRpCtxt, - visit::vt<@mut DetermineRpCtxt>)) { +fn determine_rp_in_ty_method(ty_m: &ast::ty_method, + (cx, visitor): (@mut DetermineRpCtxt, + visit::vt<@mut DetermineRpCtxt>)) { do cx.with(cx.item_id, false) { visit::visit_ty_method(ty_m, (cx, visitor)); } } -pub fn determine_rp_in_ty(ty: @ast::Ty, - (cx, visitor): (@mut DetermineRpCtxt, - visit::vt<@mut DetermineRpCtxt>)) { +fn determine_rp_in_ty(ty: @ast::Ty, + (cx, visitor): (@mut DetermineRpCtxt, + visit::vt<@mut DetermineRpCtxt>)) { // we are only interested in types that will require an item to // be region-parameterized. if cx.item_id is zero, then this type // is not a member of a type defn nor is it a constitutent of an @@ -804,7 +784,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, // then check whether it is region-parameterized and consider // that as a direct dependency. match ty.node { - ast::ty_path(path, id) => { + ast::ty_path(path, _bounds, id) => { match cx.def_map.find(&id) { Some(&ast::def_ty(did)) | Some(&ast::def_trait(did)) | @@ -840,10 +820,10 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, visit_mt(mt, (cx, visitor)); } - ast::ty_path(path, _) => { + ast::ty_path(path, _bounds, _) => { // type parameters are---for now, anyway---always invariant do cx.with_ambient_variance(rv_invariant) { - for path.types.each |tp| { + for path.types.iter().advance |tp| { (visitor.visit_ty)(*tp, (cx, visitor)); } } @@ -856,7 +836,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, do cx.with(cx.item_id, false) { // parameters are contravariant do cx.with_ambient_variance(rv_contravariant) { - for decl.inputs.each |a| { + for decl.inputs.iter().advance |a| { (visitor.visit_ty)(a.ty, (cx, visitor)); } } @@ -883,7 +863,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, } } -pub fn determine_rp_in_struct_field( +fn determine_rp_in_struct_field( cm: @ast::struct_field, (cx, visitor): (@mut DetermineRpCtxt, visit::vt<@mut DetermineRpCtxt>)) { @@ -893,7 +873,7 @@ pub fn determine_rp_in_struct_field( pub fn determine_rp_in_crate(sess: Session, ast_map: ast_map::map, def_map: resolve::DefMap, - crate: @ast::crate) + crate: &ast::crate) -> region_paramd_items { let cx = @mut DetermineRpCtxt { sess: sess, @@ -936,7 +916,7 @@ pub fn determine_rp_in_crate(sess: Session, match cx.dep_map.find(&c_id) { None => {} Some(deps) => { - for deps.each |dep| { + for deps.iter().advance |dep| { let v = add_variance(dep.ambient_variance, c_variance); cx.add_rp(dep.id, v); } @@ -948,7 +928,7 @@ pub fn determine_rp_in_crate(sess: Session, debug!("%s", { debug!("Region variance results:"); let region_paramd_items = cx.region_paramd_items; - for region_paramd_items.each |&key, &value| { + for region_paramd_items.iter().advance |(&key, &value)| { debug!("item %? (%s) is parameterized with variance %?", key, ast_map::node_id_to_str(ast_map, key, diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 3e656b3e594..0cbba6b1c36 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use driver::session::Session; use metadata::csearch::{each_path, get_trait_method_def_ids}; @@ -40,11 +39,11 @@ use syntax::visit::{visit_foreign_item, visit_item}; use syntax::visit::{visit_mod, visit_ty, vt}; use syntax::opt_vec::OptVec; -use core::str; -use core::uint; -use core::vec; -use core::hashmap::{HashMap, HashSet}; -use core::util; +use std::str; +use std::uint; +use std::vec; +use std::hashmap::{HashMap, HashSet}; +use std::util; // Definition mapping pub type DefMap = @mut HashMap<node_id,def>; @@ -101,6 +100,14 @@ pub enum Namespace { ValueNS } +#[deriving(Eq)] +pub 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. @@ -644,19 +651,17 @@ impl NameBindings { match self.type_def { None => None, Some(ref type_def) => { - // FIXME (#3784): This is reallllly questionable. - // Perhaps the right thing to do is to merge def_mod - // and def_ty. match (*type_def).type_def { Some(type_def) => Some(type_def), None => { - match (*type_def).module_def { - Some(module_def) => { - let module_def = &mut *module_def; - module_def.def_id.map(|def_id| - def_mod(*def_id)) + match type_def.module_def { + Some(module) => { + match module.def_id { + Some(did) => Some(def_mod(did)), + None => None, + } } - None => None + None => None, } } } @@ -759,10 +764,12 @@ pub fn PrimitiveTypeTable() -> PrimitiveTypeTable { } -pub fn namespace_to_str(ns: Namespace) -> ~str { +pub fn namespace_error_to_str(ns: NamespaceError) -> &'static str { match ns { - TypeNS => ~"type", - ValueNS => ~"value", + NoError => "", + ModuleError => "module", + TypeError => "type", + ValueError => "value", } } @@ -993,21 +1000,25 @@ impl Resolver { // * If no duplicate checking was requested at all, do // nothing. - let mut is_duplicate = false; + let mut duplicate_type = NoError; let ns = match duplicate_checking_mode { ForbidDuplicateModules => { - is_duplicate = child.get_module_if_available().is_some(); + if (child.get_module_if_available().is_some()) { + duplicate_type = ModuleError; + } Some(TypeNS) } ForbidDuplicateTypes => { match child.def_for_namespace(TypeNS) { Some(def_mod(_)) | None => {} - Some(_) => is_duplicate = true + Some(_) => duplicate_type = TypeError } Some(TypeNS) } ForbidDuplicateValues => { - is_duplicate = child.defined_in_namespace(ValueNS); + if child.defined_in_namespace(ValueNS) { + duplicate_type = ValueError; + } Some(ValueNS) } ForbidDuplicateTypesAndValues => { @@ -1016,31 +1027,31 @@ impl Resolver { Some(def_mod(_)) | None => {} Some(_) => { n = Some(TypeNS); - is_duplicate = true; + duplicate_type = TypeError; } }; if child.defined_in_namespace(ValueNS) { - is_duplicate = true; + duplicate_type = ValueError; n = Some(ValueNS); } n } OverwriteDuplicates => None }; - if is_duplicate { + if (duplicate_type != NoError) { // Return an error here by looking up the namespace that // had the duplicate. let ns = ns.unwrap(); self.session.span_err(sp, fmt!("duplicate definition of %s `%s`", - namespace_to_str(ns), + namespace_error_to_str(duplicate_type), self.session.str_of(name))); { let r = child.span_for_namespace(ns); for r.iter().advance |sp| { self.session.span_note(*sp, - fmt!("first definition of %s %s here:", - namespace_to_str(ns), + fmt!("first definition of %s `%s` here", + namespace_error_to_str(duplicate_type), self.session.str_of(name))); } } @@ -1057,7 +1068,7 @@ impl Resolver { } // Check each statement. - for block.node.stmts.each |statement| { + for block.node.stmts.iter().advance |statement| { match statement.node { stmt_decl(declaration, _) => { match declaration.node { @@ -1146,12 +1157,13 @@ impl Resolver { } // These items live in the value namespace. - item_const(*) => { + item_static(_, m, _) => { let (name_bindings, _) = self.add_child(ident, parent, ForbidDuplicateValues, sp); + let mutbl = m == ast::m_mutbl; name_bindings.define_value - (privacy, def_const(local_def(item.id)), sp); + (privacy, def_static(local_def(item.id), mutbl), sp); } item_fn(_, purity, _, _, _) => { let (name_bindings, new_parent) = @@ -1178,7 +1190,7 @@ impl Resolver { name_bindings.define_type (privacy, def_ty(local_def(item.id)), sp); - for (*enum_definition).variants.each |variant| { + for (*enum_definition).variants.iter().advance |variant| { self.build_reduced_graph_for_variant( variant, local_def(item.id), @@ -1215,49 +1227,29 @@ impl Resolver { visit_item(item, (new_parent, visitor)); } - item_impl(_, trait_ref_opt, ty, ref methods) => { - // If this implements an anonymous trait and it has static - // methods, then add all the static methods within to a new - // module, if the type was defined within this module. + item_impl(_, None, ty, ref methods) => { + // If this implements an anonymous trait, then add all the + // methods within to a new module, if the type was defined + // within this module. // // FIXME (#3785): This is quite unsatisfactory. Perhaps we // should modify anonymous traits to only be implementable in // the same module that declared the type. - // Bail out early if there are no static methods. - let mut methods_seen = HashMap::new(); - let mut has_static_methods = false; - for methods.each |method| { - match method.explicit_self.node { - sty_static => has_static_methods = true, - _ => { - // Make sure you can't define duplicate methods - let ident = method.ident; - let span = method.span; - let old_sp = methods_seen.find_or_insert(ident, span); - if *old_sp != span { - self.session.span_err(span, - fmt!("duplicate definition of method `%s`", - self.session.str_of(ident))); - self.session.span_note(*old_sp, - fmt!("first definition of method `%s` here", - self.session.str_of(ident))); - } - } - } - } - - // If there are static methods, then create the module - // and add them. - match (trait_ref_opt, ty) { - (None, @Ty { node: ty_path(path, _), _ }) if - has_static_methods && path.idents.len() == 1 => { + // Create the module and add all methods. + match *ty { + Ty { + node: ty_path(path, _, _), + _ + } if path.idents.len() == 1 => { let name = path_to_ident(path); let new_parent = match parent.children.find(&name) { // It already exists - Some(&child) if child.get_module_if_available().is_some() && - child.get_module().kind == ImplModuleKind => { + Some(&child) if child.get_module_if_available() + .is_some() && + child.get_module().kind == + ImplModuleKind => { ModuleReducedGraphParent(child.get_module()) } // Create the module @@ -1268,8 +1260,8 @@ impl Resolver { ForbidDuplicateModules, sp); - let parent_link = self.get_parent_link(new_parent, - ident); + let parent_link = + self.get_parent_link(new_parent, ident); let def_id = local_def(item.id); name_bindings.define_module(Public, parent_link, @@ -1277,30 +1269,36 @@ impl Resolver { ImplModuleKind, sp); - ModuleReducedGraphParent(name_bindings.get_module()) + ModuleReducedGraphParent( + name_bindings.get_module()) } }; - // For each static method... - for methods.each |method| { - match method.explicit_self.node { + // For each method... + for methods.iter().advance |method| { + // Add the method to the module. + let ident = method.ident; + let (method_name_bindings, _) = + self.add_child(ident, + new_parent, + ForbidDuplicateValues, + method.span); + let def = match method.explicit_self.node { sty_static => { - // Add the static method to the - // module. - let ident = method.ident; - let (method_name_bindings, _) = - self.add_child( - ident, - new_parent, - ForbidDuplicateValues, - method.span); - let def = def_fn(local_def(method.id), - method.purity); - method_name_bindings.define_value( - Public, def, method.span); + // Static methods become `def_fn`s. + def_fn(local_def(method.id), + method.purity) } - _ => {} - } + _ => { + // Non-static methods become + // `def_method`s. + def_method(local_def(method.id), None) + } + }; + + method_name_bindings.define_value(Public, + def, + method.span); } } _ => {} @@ -1309,83 +1307,64 @@ impl Resolver { visit_item(item, (parent, visitor)); } + item_impl(_, Some(_), _ty, ref _methods) => { + visit_item(item, (parent, visitor)); + } + item_trait(_, _, ref methods) => { let (name_bindings, new_parent) = self.add_child(ident, parent, ForbidDuplicateTypes, sp); - // If the trait has static methods, then add all the static - // methods within to a new module. - // - // We only need to create the module if the trait has static - // methods, so check that first. - let mut has_static_methods = false; - for (*methods).each |method| { - let ty_m = trait_method_to_ty_method(method); - match ty_m.explicit_self.node { - sty_static => { - has_static_methods = true; - break; - } - _ => {} - } - } - - // Create the module if necessary. - let module_parent_opt; - if has_static_methods { - let parent_link = self.get_parent_link(parent, ident); - name_bindings.define_module(privacy, - parent_link, - Some(local_def(item.id)), - TraitModuleKind, - sp); - module_parent_opt = Some(ModuleReducedGraphParent( - name_bindings.get_module())); - } else { - module_parent_opt = None; - } + // Add all the methods within to a new module. + let parent_link = self.get_parent_link(parent, ident); + name_bindings.define_module(privacy, + parent_link, + Some(local_def(item.id)), + TraitModuleKind, + sp); + let module_parent = ModuleReducedGraphParent(name_bindings. + get_module()); // Add the names of all the methods to the trait info. let mut method_names = HashMap::new(); - for methods.each |method| { + for methods.iter().advance |method| { let ty_m = trait_method_to_ty_method(method); let ident = ty_m.ident; - // Add it to the trait info if not static, - // add it as a name in the trait module otherwise. - match ty_m.explicit_self.node { - sty_static => { - let def = def_static_method( - local_def(ty_m.id), - Some(local_def(item.id)), - ty_m.purity); - let (method_name_bindings, _) = - self.add_child(ident, - module_parent_opt.get(), - ForbidDuplicateValues, - ty_m.span); - method_name_bindings.define_value(Public, - def, - ty_m.span); + // Add it as a name in the trait module. + let def = match ty_m.explicit_self.node { + sty_static => { + // Static methods become `def_static_method`s. + def_static_method(local_def(ty_m.id), + Some(local_def(item.id)), + ty_m.purity) } _ => { - // Make sure you can't define duplicate methods - let old_sp = method_names.find_or_insert(ident, ty_m.span); - if *old_sp != ty_m.span { - self.session.span_err(ty_m.span, - fmt!("duplicate definition of method `%s`", - self.session.str_of(ident))); - self.session.span_note(*old_sp, - fmt!("first definition of method `%s` here", - self.session.str_of(ident))); - } + // Non-static methods become `def_method`s. + def_method(local_def(ty_m.id), + Some(local_def(item.id))) + } + }; + + let (method_name_bindings, _) = + self.add_child(ident, + module_parent, + ForbidDuplicateValues, + ty_m.span); + method_name_bindings.define_value(Public, def, ty_m.span); + + // Add it to the trait info if not static. + match ty_m.explicit_self.node { + sty_static => {} + _ => { + method_names.insert(ident, ()); } } } let def_id = local_def(item.id); - for method_names.each |name, _| { + for method_names.iter().advance |(name, _)| { if !self.method_map.contains_key(name) { self.method_map.insert(*name, HashSet::new()); } @@ -1415,24 +1394,26 @@ impl Resolver { (ReducedGraphParent, vt<ReducedGraphParent>)) { let ident = variant.node.name; - let (child, _) = self.add_child(ident, parent, ForbidDuplicateValues, - variant.span); - - let privacy; - match variant.node.vis { - public => privacy = Public, - private => privacy = Private, - inherited => privacy = parent_privacy - } + + let privacy = + match variant.node.vis { + public => Public, + private => Private, + inherited => parent_privacy + }; match variant.node.kind { tuple_variant_kind(_) => { + let (child, _) = self.add_child(ident, parent, ForbidDuplicateValues, + variant.span); child.define_value(privacy, def_variant(item_id, local_def(variant.node.id)), variant.span); } struct_variant_kind(_) => { + let (child, _) = self.add_child(ident, parent, ForbidDuplicateTypesAndValues, + variant.span); child.define_type(privacy, def_variant(item_id, local_def(variant.node.id)), @@ -1452,7 +1433,7 @@ impl Resolver { let privacy = visibility_to_privacy(view_item.vis); match view_item.node { view_item_use(ref view_paths) => { - for view_paths.each |view_path| { + for view_paths.iter().advance |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. @@ -1463,7 +1444,7 @@ impl Resolver { let path_len = full_path.idents.len(); assert!(path_len != 0); - for full_path.idents.eachi |i, ident| { + for full_path.idents.iter().enumerate().advance |(i, ident)| { if i != path_len - 1 { module_path.push(*ident); } @@ -1472,7 +1453,7 @@ impl Resolver { view_path_glob(module_ident_path, _) | view_path_list(module_ident_path, _, _) => { - for module_ident_path.idents.each |ident| { + for module_ident_path.idents.iter().advance |ident| { module_path.push(*ident); } } @@ -1493,7 +1474,7 @@ impl Resolver { id); } view_path_list(_, ref source_idents, _) => { - for source_idents.each |source_ident| { + for source_idents.iter().advance |source_ident| { let name = source_ident.node.name; let subclass = @SingleImport(name, name); self.build_import_directive(privacy, @@ -1563,8 +1544,8 @@ impl Resolver { visit_foreign_item(foreign_item, (new_parent, visitor)); } } - foreign_item_const(*) => { - let def = def_const(local_def(foreign_item.id)); + foreign_item_static(_, m) => { + let def = def_static(local_def(foreign_item.id), m); name_bindings.define_value(Public, def, foreign_item.span); visit_foreign_item(foreign_item, (new_parent, visitor)); @@ -1671,7 +1652,7 @@ impl Resolver { let privacy = variant_visibility_to_privacy(visibility, true); child_name_bindings.define_value(privacy, def, dummy_sp()); } - def_fn(*) | def_static_method(*) | def_const(*) => { + def_fn(*) | def_static_method(*) | def_static(*) => { debug!("(building reduced graph for external \ crate) building value %s", final_ident); child_name_bindings.define_value(privacy, def, dummy_sp()); @@ -1686,7 +1667,7 @@ impl Resolver { let method_def_ids = get_trait_method_def_ids(self.session.cstore, def_id); let mut interned_method_names = HashSet::new(); - for method_def_ids.each |&method_def_id| { + for method_def_ids.iter().advance |&method_def_id| { let (method_name, explicit_self) = get_method_name_and_explicit_self(self.session.cstore, method_def_id); @@ -1701,7 +1682,7 @@ impl Resolver { interned_method_names.insert(method_name); } } - for interned_method_names.each |name| { + for interned_method_names.iter().advance |name| { if !self.method_map.contains_key(name) { self.method_map.insert(*name, HashSet::new()); } @@ -1734,6 +1715,9 @@ impl Resolver { child_name_bindings.define_type(privacy, def, dummy_sp()); self.structs.insert(def_id); } + def_method(*) => { + // Ignored; handled elsewhere. + } def_self(*) | def_arg(*) | def_local(*) | def_prim_ty(*) | def_ty_param(*) | def_binding(*) | def_use(*) | def_upvar(*) | def_region(*) | @@ -1767,7 +1751,7 @@ impl Resolver { // need to. let mut current_module = root; - for pieces.each |ident_str| { + for pieces.iter().advance |ident_str| { let ident = self.session.ident_of(*ident_str); // Create or reuse a graph node for the child. let (child_name_bindings, new_parent) = @@ -1887,8 +1871,7 @@ impl Resolver { // Add each static method to the module. let new_parent = ModuleReducedGraphParent( type_module); - for static_methods.each - |static_method_info| { + for static_methods.iter().advance |static_method_info| { let ident = static_method_info.ident; debug!("(building reduced graph for \ external crate) creating \ @@ -2074,9 +2057,13 @@ impl Resolver { pub fn idents_to_str(@mut self, idents: &[ident]) -> ~str { let mut first = true; let mut result = ~""; - for idents.each |ident| { - if first { first = false; } else { result += "::" }; - result += self.session.str_of(*ident); + for idents.iter().advance |ident| { + if first { + first = false + } else { + result.push_str("::") + } + result.push_str(self.session.str_of(*ident)); }; return result; } @@ -2371,7 +2358,8 @@ impl Resolver { } match type_result { BoundResult(target_module, name_bindings) => { - debug!("(resolving single import) found type target"); + debug!("(resolving single import) found type target: %?", + name_bindings.type_def.get().type_def); import_resolution.type_target = Some(Target(target_module, name_bindings)); import_resolution.type_id = directive.id; @@ -2468,8 +2456,8 @@ impl Resolver { assert_eq!(containing_module.glob_count, 0); // Add all resolved imports from the containing module. - for containing_module.import_resolutions.each - |ident, target_import_resolution| { + for containing_module.import_resolutions.iter().advance + |(ident, target_import_resolution)| { debug!("(resolving glob import) writing module resolution \ %? into `%s`", @@ -2553,13 +2541,13 @@ impl Resolver { }; // Add all children from the containing module. - for containing_module.children.each |&ident, name_bindings| { + for containing_module.children.iter().advance |(&ident, name_bindings)| { merge_import_resolution(ident, *name_bindings); } // Add external module children from the containing module. - for containing_module.external_module_children.each - |&ident, module| { + for containing_module.external_module_children.iter().advance + |(&ident, module)| { let name_bindings = @mut Resolver::create_name_bindings_from_module(*module); merge_import_resolution(ident, name_bindings); @@ -3170,12 +3158,14 @@ impl Resolver { Some(def_id) if def_id.crate == local_crate => { // OK. Continue. debug!("(recording exports for module subtree) recording \ - exports for local module"); + exports for local module `%s`", + self.module_to_str(module_)); } None => { // Record exports for the root module. debug!("(recording exports for module subtree) recording \ - exports for root module"); + exports for root module `%s`", + self.module_to_str(module_)); } Some(_) => { // Bail out. @@ -3249,28 +3239,15 @@ impl Resolver { pub fn add_exports_for_module(@mut self, exports2: &mut ~[Export2], module_: @mut Module) { - for module_.children.each |ident, namebindings| { - debug!("(computing exports) maybe export '%s'", - self.session.str_of(*ident)); - self.add_exports_of_namebindings(&mut *exports2, - *ident, - *namebindings, - TypeNS, - false); - self.add_exports_of_namebindings(&mut *exports2, - *ident, - *namebindings, - ValueNS, - false); - } - - for module_.import_resolutions.each |ident, importresolution| { + for module_.import_resolutions.iter().advance |(ident, + importresolution)| { if importresolution.privacy != Public { debug!("(computing exports) not reexporting private `%s`", self.session.str_of(*ident)); loop; } - for [ TypeNS, ValueNS ].each |ns| { + let xs = [TypeNS, ValueNS]; + for xs.iter().advance |ns| { match importresolution.target_for_namespace(*ns) { Some(target) => { debug!("(computing exports) maybe reexport '%s'", @@ -3517,7 +3494,7 @@ impl Resolver { // enum item: resolve all the variants' discrs, // then resolve the ty params item_enum(ref enum_def, ref generics) => { - for (*enum_def).variants.each() |variant| { + for (*enum_def).variants.iter().advance |variant| { for variant.node.disr_expr.iter().advance |dis_expr| { // resolve the discriminator expr // as a constant @@ -3575,7 +3552,7 @@ impl Resolver { visitor); // Resolve derived traits. - for traits.each |trt| { + for traits.iter().advance |trt| { match self.resolve_path(trt.path, TypeNS, true, visitor) { None => @@ -3595,7 +3572,7 @@ impl Resolver { } } - for (*methods).each |method| { + for (*methods).iter().advance |method| { // Create a new rib for the method-specific type // parameters. // @@ -3615,7 +3592,7 @@ impl Resolver { &ty_m.generics.ty_params, visitor); - for ty_m.decl.inputs.each |argument| { + for ty_m.decl.inputs.iter().advance |argument| { self.resolve_type(argument.ty, visitor); } @@ -3652,7 +3629,7 @@ impl Resolver { item_foreign_mod(ref foreign_module) => { do self.with_scope(Some(item.ident)) { - for foreign_module.items.each |foreign_item| { + for foreign_module.items.iter().advance |foreign_item| { match foreign_item.node { foreign_item_fn(_, _, ref generics) => { self.with_type_parameter_rib( @@ -3662,7 +3639,7 @@ impl Resolver { || visit_foreign_item(*foreign_item, ((), visitor))); } - foreign_item_const(_) => { + foreign_item_static(*) => { visit_foreign_item(*foreign_item, ((), visitor)); } @@ -3684,7 +3661,7 @@ impl Resolver { visitor); } - item_const(*) => { + item_static(*) => { self.with_constant_rib(|| { visit_item(item, ((), visitor)); }); @@ -3708,7 +3685,7 @@ impl Resolver { let function_type_rib = @Rib(rib_kind); self.type_ribs.push(function_type_rib); - for generics.ty_params.eachi |index, type_parameter| { + for generics.ty_params.iter().enumerate().advance |(index, type_parameter)| { let name = type_parameter.ident; debug!("with_type_parameter_rib: %d %d", node_id, type_parameter.id); @@ -3799,7 +3776,7 @@ impl Resolver { // Nothing to do. } Some(declaration) => { - for declaration.inputs.each |argument| { + for declaration.inputs.iter().advance |argument| { let binding_mode = ArgumentIrrefutableMode; let mutability = if argument.is_mutbl {Mutable} else {Immutable}; @@ -3831,8 +3808,8 @@ impl Resolver { pub fn resolve_type_parameters(@mut self, type_parameters: &OptVec<TyParam>, visitor: ResolveVisitor) { - for type_parameters.each |type_parameter| { - for type_parameter.bounds.each |bound| { + for type_parameters.iter().advance |type_parameter| { + for type_parameter.bounds.iter().advance |bound| { self.resolve_type_parameter_bound(bound, visitor); } } @@ -3869,6 +3846,27 @@ impl Resolver { generics: &Generics, fields: &[@struct_field], visitor: ResolveVisitor) { + let mut ident_map = HashMap::new::<ast::ident, @struct_field>(); + for fields.iter().advance |&field| { + match field.node.kind { + named_field(ident, _) => { + match ident_map.find(&ident) { + Some(&prev_field) => { + let ident_str = self.session.str_of(ident); + self.session.span_err(field.span, + fmt!("field `%s` is already declared", ident_str)); + self.session.span_note(prev_field.span, + "Previously declared here"); + }, + None => { + ident_map.insert(ident, field); + } + } + } + _ => () + } + } + // If applicable, create a rib for the type parameters. do self.with_type_parameter_rib(HasTypeParameters (generics, id, 0, @@ -3878,7 +3876,7 @@ impl Resolver { self.resolve_type_parameters(&generics.ty_params, visitor); // Resolve fields. - for fields.each |field| { + for fields.iter().advance |field| { self.resolve_type(field.node.ty, visitor); } } @@ -3953,7 +3951,7 @@ impl Resolver { // Resolve the self type. self.resolve_type(self_type, visitor); - for methods.each |method| { + for methods.iter().advance |method| { // We also need a new scope for the method-specific // type parameters. self.resolve_method(MethodRibKind( @@ -4033,10 +4031,10 @@ impl Resolver { pub 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 arm.pats.eachi() |i, p| { + for arm.pats.iter().enumerate().advance |(i, p)| { let map_i = self.binding_mode_map(*p); - for map_0.each |&key, &binding_0| { + for map_0.iter().advance |(&key, &binding_0)| { match map_i.find(&key) { None => { self.session.span_err( @@ -4057,7 +4055,7 @@ impl Resolver { } } - for map_i.each |&key, &binding| { + for map_i.iter().advance |(&key, &binding)| { if !map_0.contains_key(&key) { self.session.span_err( binding.span, @@ -4073,7 +4071,7 @@ impl Resolver { self.value_ribs.push(@Rib(NormalRibKind)); let bindings_list = @mut HashMap::new(); - for arm.pats.each |pattern| { + for arm.pats.iter().advance |pattern| { self.resolve_pattern(*pattern, RefutableMode, Immutable, Some(bindings_list), visitor); } @@ -4118,7 +4116,7 @@ impl Resolver { // Like path expressions, the interpretation of path types depends // on whether the path has multiple elements in it or not. - ty_path(path, path_id) => { + ty_path(path, bounds, path_id) => { // This is a path in the type namespace. Walk through scopes // scopes looking for it. let mut result_def = None; @@ -4177,12 +4175,20 @@ impl Resolver { self.idents_to_str(path.idents))); } } + + do bounds.map |bound_vec| { + for bound_vec.iter().advance |bound| { + self.resolve_type_parameter_bound(bound, visitor); + } + }; } ty_closure(c) => { - for c.bounds.each |bound| { - self.resolve_type_parameter_bound(bound, visitor); - } + do c.bounds.map |bounds| { + for bounds.iter().advance |bound| { + self.resolve_type_parameter_bound(bound, visitor); + } + }; visit_ty(ty, ((), visitor)); } @@ -4326,7 +4332,7 @@ impl Resolver { } // Check the types in the path pattern. - for path.types.each |ty| { + for path.types.iter().advance |ty| { self.resolve_type(*ty, visitor); } } @@ -4338,7 +4344,7 @@ impl Resolver { Some(def @ def_struct(*)) => { self.record_def(pattern.id, def); } - Some(def @ def_const(*)) => { + Some(def @ def_static(*)) => { self.enforce_default_binding_mode( pattern, binding_mode, @@ -4359,7 +4365,7 @@ impl Resolver { } // Check the types in the path pattern. - for path.types.each |ty| { + for path.types.iter().advance |ty| { self.resolve_type(*ty, visitor); } } @@ -4370,7 +4376,7 @@ impl Resolver { Some(def @ def_fn(*)) | Some(def @ def_variant(*)) | Some(def @ def_struct(*)) | - Some(def @ def_const(*)) => { + Some(def @ def_static(*)) => { self.record_def(pattern.id, def); } Some(_) => { @@ -4388,7 +4394,7 @@ impl Resolver { } // Check the types in the path pattern. - for path.types.each |ty| { + for path.types.iter().advance |ty| { self.resolve_type(*ty, visitor); } } @@ -4453,7 +4459,7 @@ impl Resolver { def @ def_variant(*) | def @ def_struct(*) => { return FoundStructOrEnumVariant(def); } - def @ def_const(*) => { + def @ def_static(_, false) => { return FoundConst(def); } _ => { @@ -4483,14 +4489,14 @@ impl Resolver { visitor: ResolveVisitor) -> Option<def> { // First, resolve the types. - for path.types.each |ty| { + for path.types.iter().advance |ty| { self.resolve_type(*ty, visitor); } if path.global { return self.resolve_crate_relative_path(path, - self.xray_context, - namespace); + self.xray_context, + namespace); } if path.idents.len() > 1 { @@ -4605,7 +4611,7 @@ impl Resolver { pub fn intern_module_part_of_path(@mut self, path: @Path) -> ~[ident] { let mut module_path_idents = ~[]; - for path.idents.eachi |index, ident| { + for path.idents.iter().enumerate().advance |(index, ident)| { if index == path.idents.len() - 1 { break; } @@ -4837,14 +4843,13 @@ impl Resolver { while j != 0 { j -= 1; for this.value_ribs[j].bindings.each_key |&k| { - vec::push(&mut maybes, this.session.str_of(k)); - vec::push(&mut values, uint::max_value); + maybes.push(this.session.str_of(k)); + values.push(uint::max_value); } } let mut smallest = 0; - for maybes.eachi |i, &other| { - + for maybes.iter().enumerate().advance |(i, &other)| { values[i] = name.lev_distance(other); if values[i] <= values[smallest] { @@ -4858,7 +4863,7 @@ impl Resolver { values[smallest] <= max_distance && name != maybes[smallest] { - Some(vec::swap_remove(&mut maybes, smallest)) + Some(maybes.swap_remove(smallest)) } else { None @@ -4873,11 +4878,11 @@ impl Resolver { i -= 1; match this.type_ribs[i].kind { MethodRibKind(node_id, _) => - for this.crate.node.module.items.each |item| { + for this.crate.node.module.items.iter().advance |item| { if item.id == node_id { match item.node { item_struct(class_def, _) => { - for class_def.fields.each |field| { + for class_def.fields.iter().advance |field| { match field.node.kind { unnamed_field => {}, named_field(ident, _) => { @@ -4919,6 +4924,22 @@ impl Resolver { // Write the result into the def map. debug!("(resolving expr) resolved `%s`", self.idents_to_str(path.idents)); + + // First-class methods are not supported yet; error + // out here. + match def { + def_method(*) => { + self.session.span_err(expr.span, + "first-class methods \ + are not supported"); + self.session.span_note(expr.span, + "call the method \ + using the `.` \ + syntax"); + } + _ => {} + } + self.record_def(expr.id, def); } None => { @@ -5048,6 +5069,9 @@ impl Resolver { self.trait_map.insert(expr.id, @mut traits); } expr_method_call(_, _, ident, _, _, _) => { + debug!("(recording candidate traits for expr) recording \ + traits for %d", + expr.id); let traits = self.search_for_traits_containing_method(ident); self.trait_map.insert(expr.id, @mut traits); } @@ -5123,7 +5147,6 @@ impl Resolver { debug!("(searching for traits containing method) looking for '%s'", self.session.str_of(name)); - let mut found_traits = ~[]; let mut search_module = self.current_module; match self.method_map.find(&name) { @@ -5131,7 +5154,7 @@ impl Resolver { // Look for the current trait. match /*bad*/copy self.current_trait_refs { Some(trait_def_ids) => { - for trait_def_ids.each |trait_def_id| { + for trait_def_ids.iter().advance |trait_def_id| { if candidate_traits.contains(trait_def_id) { self.add_trait_info( &mut found_traits, @@ -5282,7 +5305,7 @@ impl Resolver { match vi.node { view_item_extern_mod(*) => {} // ignore view_item_use(ref path) => { - for path.each |p| { + for path.iter().advance |p| { match p.node { view_path_simple(_, _, id) | view_path_glob(_, id) => { if !self.used_imports.contains(&id) { @@ -5293,7 +5316,7 @@ impl Resolver { } view_path_list(_, ref list, _) => { - for list.each |i| { + for list.iter().advance |i| { if !self.used_imports.contains(&i.node.id) { self.session.add_lint(unused_imports, i.node.id, i.span, @@ -5349,7 +5372,7 @@ impl Resolver { } debug!("Import resolutions:"); - for module_.import_resolutions.each |name, import_resolution| { + for module_.import_resolutions.iter().advance |(name, import_resolution)| { let value_repr; match import_resolution.target_for_namespace(ValueNS) { None => { value_repr = ~""; } @@ -5387,7 +5410,7 @@ pub fn resolve_crate(session: Session, -> CrateMap { let resolver = @mut Resolver(session, lang_items, crate); resolver.resolve(); - let Resolver{def_map, export_map2, trait_map, _} = copy *resolver; + let Resolver { def_map, export_map2, trait_map, _ } = copy *resolver; CrateMap { def_map: def_map, exp_map2: export_map2, diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index fba174c6840..e5f5315a19c 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -10,7 +10,6 @@ // Type substitutions. -use core::prelude::*; use middle::ty; use util::ppaux::Repr; diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 029063b8c0d..1d69b20f5c4 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -147,7 +147,6 @@ * */ -use core::prelude::*; use back::abi; use lib::llvm::{llvm, ValueRef, BasicBlockRef}; @@ -172,8 +171,8 @@ use middle::trans::type_of; use middle::ty; use util::common::indenter; -use core::hashmap::HashMap; -use core::vec; +use std::hashmap::HashMap; +use std::vec; use syntax::ast; use syntax::ast::ident; use syntax::ast_util::path_to_ident; @@ -259,7 +258,7 @@ pub enum opt_result { range_result(Result, Result), } pub fn trans_opt(bcx: block, o: &Opt) -> opt_result { - let _icx = bcx.insn_ctxt("match::trans_opt"); + let _icx = push_ctxt("match::trans_opt"); let ccx = bcx.ccx(); let bcx = bcx; match *o { @@ -298,13 +297,13 @@ pub fn variant_opt(bcx: block, pat_id: ast::node_id) match ccx.tcx.def_map.get_copy(&pat_id) { ast::def_variant(enum_id, var_id) => { let variants = ty::enum_variants(ccx.tcx, enum_id); - for (*variants).each |v| { + for (*variants).iter().advance |v| { if var_id == v.id { return var(v.disr_val, adt::represent_node(bcx, pat_id)) } } - ::core::util::unreachable(); + ::std::util::unreachable(); } ast::def_fn(*) | ast::def_struct(_) => { @@ -363,7 +362,7 @@ pub fn matches_to_str(bcx: block, m: &[@Match]) -> ~str { } pub fn has_nested_bindings(m: &[@Match], col: uint) -> bool { - for m.each |br| { + for m.iter().advance |br| { match br.pats[col].node { ast::pat_ident(_, _, Some(_)) => return true, _ => () @@ -381,16 +380,16 @@ pub fn expand_nested_bindings<'r>(bcx: block, bcx.to_str(), matches_to_str(bcx, m), col, - bcx.val_str(val)); + bcx.val_to_str(val)); let _indenter = indenter(); do m.map |br| { match br.pats[col].node { ast::pat_ident(_, path, Some(inner)) => { let pats = vec::append( - vec::slice(br.pats, 0u, col).to_vec(), + br.pats.slice(0u, col).to_owned(), vec::append(~[inner], - vec::slice(br.pats, col + 1u, + br.pats.slice(col + 1u, br.pats.len()))); let binding_info = @@ -406,8 +405,6 @@ pub fn expand_nested_bindings<'r>(bcx: block, } } -pub type enter_pat<'self> = &'self fn(@ast::pat) -> Option<~[@ast::pat]>; - pub fn assert_is_binding_or_wild(bcx: block, p: @ast::pat) { if !pat_is_binding_or_wild(bcx.tcx().def_map, p) { bcx.sess().span_bug( @@ -417,6 +414,8 @@ pub fn assert_is_binding_or_wild(bcx: block, p: @ast::pat) { } } +pub type enter_pat<'self> = &'self fn(@ast::pat) -> Option<~[@ast::pat]>; + pub fn enter_match<'r>(bcx: block, dm: DefMap, m: &[@Match<'r>], @@ -428,17 +427,17 @@ pub fn enter_match<'r>(bcx: block, bcx.to_str(), matches_to_str(bcx, m), col, - bcx.val_str(val)); + bcx.val_to_str(val)); let _indenter = indenter(); let mut result = ~[]; - for m.each |br| { + for m.iter().advance |br| { match e(br.pats[col]) { Some(sub) => { let pats = vec::append( - vec::append(sub, vec::slice(br.pats, 0u, col)), - vec::slice(br.pats, col + 1u, br.pats.len())); + vec::append(sub, br.pats.slice(0u, col)), + br.pats.slice(col + 1u, br.pats.len())); let this = br.pats[col]; match this.node { @@ -474,7 +473,7 @@ pub fn enter_default<'r>(bcx: block, bcx.to_str(), matches_to_str(bcx, m), col, - bcx.val_str(val)); + bcx.val_to_str(val)); let _indenter = indenter(); do enter_match(bcx, dm, m, col, val) |p| { @@ -521,7 +520,7 @@ pub fn enter_opt<'r>(bcx: block, bcx.to_str(), matches_to_str(bcx, m), col, - bcx.val_str(val)); + bcx.val_to_str(val)); let _indenter = indenter(); let tcx = bcx.tcx(); @@ -579,10 +578,9 @@ pub fn enter_opt<'r>(bcx: block, // specified in the struct definition. Also fill in // unspecified fields with dummy. let mut reordered_patterns = ~[]; - for ty::lookup_struct_fields(tcx, struct_id).each - |field| { - match field_pats.find(|p| - p.ident == field.ident) { + let r = ty::lookup_struct_fields(tcx, struct_id); + for r.iter().advance |field| { + match field_pats.iter().find_(|p| p.ident == field.ident) { None => reordered_patterns.push(dummy), Some(fp) => reordered_patterns.push(fp.pat) } @@ -633,7 +631,7 @@ pub fn enter_rec_or_struct<'r>(bcx: block, bcx.to_str(), matches_to_str(bcx, m), col, - bcx.val_str(val)); + bcx.val_to_str(val)); let _indenter = indenter(); let dummy = @ast::pat {id: 0, node: ast::pat_wild, span: dummy_sp()}; @@ -641,8 +639,8 @@ pub fn enter_rec_or_struct<'r>(bcx: block, match p.node { ast::pat_struct(_, ref fpats, _) => { let mut pats = ~[]; - for fields.each |fname| { - match fpats.find(|p| p.ident == *fname) { + for fields.iter().advance |fname| { + match fpats.iter().find_(|p| p.ident == *fname) { None => pats.push(dummy), Some(pat) => pats.push(pat.pat) } @@ -668,7 +666,7 @@ pub fn enter_tup<'r>(bcx: block, bcx.to_str(), matches_to_str(bcx, m), col, - bcx.val_str(val)); + bcx.val_to_str(val)); let _indenter = indenter(); let dummy = @ast::pat {id: 0, node: ast::pat_wild, span: dummy_sp()}; @@ -696,7 +694,7 @@ pub fn enter_tuple_struct<'r>(bcx: block, bcx.to_str(), matches_to_str(bcx, m), col, - bcx.val_str(val)); + bcx.val_to_str(val)); let _indenter = indenter(); let dummy = @ast::pat {id: 0, node: ast::pat_wild, span: dummy_sp()}; @@ -721,7 +719,7 @@ pub fn enter_box<'r>(bcx: block, bcx.to_str(), matches_to_str(bcx, m), col, - bcx.val_str(val)); + bcx.val_to_str(val)); let _indenter = indenter(); let dummy = @ast::pat {id: 0, node: ast::pat_wild, span: dummy_sp()}; @@ -748,7 +746,7 @@ pub fn enter_uniq<'r>(bcx: block, bcx.to_str(), matches_to_str(bcx, m), col, - bcx.val_str(val)); + bcx.val_to_str(val)); let _indenter = indenter(); let dummy = @ast::pat {id: 0, node: ast::pat_wild, span: dummy_sp()}; @@ -775,7 +773,7 @@ pub fn enter_region<'r>(bcx: block, bcx.to_str(), matches_to_str(bcx, m), col, - bcx.val_str(val)); + bcx.val_to_str(val)); let _indenter = indenter(); let dummy = @ast::pat { id: 0, node: ast::pat_wild, span: dummy_sp() }; @@ -803,7 +801,7 @@ pub fn get_options(bcx: block, m: &[@Match], col: uint) -> ~[Opt] { } let mut found = ~[]; - for m.each |br| { + for m.iter().advance |br| { let cur = br.pats[col]; match cur.node { ast::pat_lit(l) => { @@ -821,7 +819,7 @@ pub fn get_options(bcx: block, m: &[@Match], col: uint) -> ~[Opt] { add_to_set(ccx.tcx, &mut found, lit(UnitLikeStructLit(cur.id))); } - Some(&ast::def_const(const_did)) => { + Some(&ast::def_static(const_did, false)) => { add_to_set(ccx.tcx, &mut found, lit(ConstLit(const_did))); } @@ -837,7 +835,7 @@ pub fn get_options(bcx: block, m: &[@Match], col: uint) -> ~[Opt] { add_to_set(ccx.tcx, &mut found, variant_opt(bcx, cur.id)); } - Some(&ast::def_const(const_did)) => { + Some(&ast::def_static(const_did, false)) => { add_to_set(ccx.tcx, &mut found, lit(ConstLit(const_did))); } @@ -871,7 +869,7 @@ pub fn extract_variant_args(bcx: block, disr_val: int, val: ValueRef) -> ExtractedBlock { - let _icx = bcx.insn_ctxt("match::extract_variant_args"); + let _icx = push_ctxt("match::extract_variant_args"); let args = do vec::from_fn(adt::num_args(repr, disr_val)) |i| { adt::trans_field_ptr(bcx, repr, val, disr_val, i) }; @@ -897,7 +895,7 @@ pub fn extract_vec_elems(bcx: block, val: ValueRef, count: ValueRef) -> ExtractedBlock { - let _icx = bcx.insn_ctxt("match::extract_vec_elems"); + let _icx = push_ctxt("match::extract_vec_elems"); let vec_datum = match_datum(bcx, val, pat_id); let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span, pat_id, 0); @@ -912,7 +910,7 @@ pub fn extract_vec_elems(bcx: block, Sub(bcx, count, C_int(bcx.ccx(), (elem_count - i) as int))]) } - _ => unsafe { llvm::LLVMGetUndef(vt.llunit_ty) } + _ => unsafe { llvm::LLVMGetUndef(vt.llunit_ty.to_ref()) } } }; if slice.is_some() { @@ -949,7 +947,7 @@ pub fn collect_record_or_struct_fields(bcx: block, col: uint) -> ~[ast::ident] { let mut fields: ~[ast::ident] = ~[]; - for m.each |br| { + for m.iter().advance |br| { match br.pats[col].node { ast::pat_struct(_, ref fs, _) => { match ty::get(node_id_type(bcx, br.pats[col].id)).sty { @@ -963,7 +961,7 @@ pub fn collect_record_or_struct_fields(bcx: block, return fields; fn extend(idents: &mut ~[ast::ident], field_pats: &[ast::field_pat]) { - for field_pats.each |field_pat| { + for field_pats.iter().advance |field_pat| { let field_ident = field_pat.ident; if !idents.iter().any_(|x| *x == field_ident) { idents.push(field_ident); @@ -988,7 +986,7 @@ pub fn root_pats_as_necessary(mut bcx: block, col: uint, val: ValueRef) -> block { - for m.each |br| { + for m.iter().advance |br| { let pat_id = br.pats[col].id; if pat_id != 0 { let datum = Datum {val: val, ty: node_id_type(bcx, pat_id), @@ -1049,7 +1047,7 @@ pub fn any_tuple_struct_pat(bcx: block, m: &[@Match], col: uint) -> bool { pub type mk_fail = @fn() -> BasicBlockRef; pub fn pick_col(m: &[@Match]) -> uint { - fn score(p: @ast::pat) -> uint { + fn score(p: &ast::pat) -> uint { match p.node { ast::pat_lit(_) | ast::pat_enum(_, _) | ast::pat_range(_, _) => 1u, ast::pat_ident(_, _, Some(p)) => score(p), @@ -1057,14 +1055,14 @@ pub fn pick_col(m: &[@Match]) -> uint { } } let mut scores = vec::from_elem(m[0].pats.len(), 0u); - for m.each |br| { + for m.iter().advance |br| { let mut i = 0u; - for br.pats.each |p| { scores[i] += score(*p); i += 1u; } + for br.pats.iter().advance |p| { scores[i] += score(*p); i += 1u; } } let mut max_score = 0u; let mut best_col = 0u; let mut i = 0u; - for scores.each |score| { + for scores.iter().advance |score| { let score = *score; // Irrefutable columns always go first, they'd only be duplicated in @@ -1089,7 +1087,7 @@ pub fn compare_values(cx: block, rhs: ValueRef, rhs_t: ty::t) -> Result { - let _icx = cx.insn_ctxt("compare_values"); + let _icx = push_ctxt("compare_values"); if ty::type_is_scalar(rhs_t) { let rs = compare_scalar_types(cx, lhs, rhs, rhs_t, ast::eq); return rslt(rs.bcx, rs.val); @@ -1203,9 +1201,7 @@ fn insert_lllocals(bcx: block, } }; - debug!("binding %? to %s", - binding_info.id, - val_str(bcx.ccx().tn, llval)); + debug!("binding %? to %s", binding_info.id, bcx.val_to_str(llval)); llmap.insert(binding_info.id, llval); } return bcx; @@ -1222,7 +1218,7 @@ pub fn compile_guard(bcx: block, bcx.to_str(), bcx.expr_to_str(guard_expr), matches_to_str(bcx, m), - vals.map(|v| bcx.val_str(*v))); + vals.map(|v| bcx.val_to_str(*v))); let _indenter = indenter(); let mut bcx = bcx; @@ -1239,7 +1235,7 @@ pub fn compile_guard(bcx: block, let val = bool_to_i1(bcx, val); // Revoke the temp cleanups now that the guard successfully executed. - for temp_cleanups.each |llval| { + for temp_cleanups.iter().advance |llval| { revoke_clean(bcx, *llval); } @@ -1273,14 +1269,14 @@ pub fn compile_submatch(bcx: block, debug!("compile_submatch(bcx=%s, m=%s, vals=%?)", bcx.to_str(), matches_to_str(bcx, m), - vals.map(|v| bcx.val_str(*v))); + vals.map(|v| bcx.val_to_str(*v))); let _indenter = indenter(); /* For an empty match, a fall-through case must exist */ assert!((m.len() > 0u || chk.is_some())); - let _icx = bcx.insn_ctxt("match::compile_submatch"); + let _icx = push_ctxt("match::compile_submatch"); let mut bcx = bcx; let tcx = bcx.tcx(); let dm = tcx.def_map; @@ -1293,7 +1289,7 @@ pub fn compile_submatch(bcx: block, match data.arm.guard { Some(guard_expr) => { bcx = compile_guard(bcx, guard_expr, m[0].data, - vec::slice(m, 1, m.len()), + m.slice(1, m.len()), vals, chk); } _ => () @@ -1308,16 +1304,16 @@ pub fn compile_submatch(bcx: block, if has_nested_bindings(m, col) { expand_nested_bindings(bcx, m, col, val) } else { - m.to_vec() + m.to_owned() } }; - let vals_left = vec::append(vec::slice(vals, 0u, col).to_vec(), - vec::slice(vals, col + 1u, vals.len())); + let vals_left = vec::append(vals.slice(0u, col).to_owned(), + vals.slice(col + 1u, vals.len())); let ccx = bcx.fcx.ccx; let mut pat_id = 0; let mut pat_span = dummy_sp(); - for m.each |br| { + for m.iter().advance |br| { // Find a real id (we're adding placeholder wildcard patterns, but // each column is guaranteed to have at least one real pattern) if pat_id == 0 { @@ -1392,9 +1388,7 @@ pub fn compile_submatch(bcx: block, if any_box_pat(m, col) { bcx = root_pats_as_necessary(bcx, m, col, val); let llbox = Load(bcx, val); - let box_no_addrspace = non_gc_box_cast(bcx, llbox); - let unboxed = - GEPi(bcx, box_no_addrspace, [0u, abi::box_field_body]); + let unboxed = GEPi(bcx, llbox, [0u, abi::box_field_body]); compile_submatch(bcx, enter_box(bcx, dm, m, col, val), vec::append(~[unboxed], vals_left), chk); return; @@ -1402,9 +1396,7 @@ pub fn compile_submatch(bcx: block, if any_uniq_pat(m, col) { let llbox = Load(bcx, val); - let box_no_addrspace = non_gc_box_cast(bcx, llbox); - let unboxed = - GEPi(bcx, box_no_addrspace, [0u, abi::box_field_body]); + let unboxed = GEPi(bcx, llbox, [0u, abi::box_field_body]); compile_submatch(bcx, enter_uniq(bcx, dm, m, col, val), vec::append(~[unboxed], vals_left), chk); return; @@ -1449,7 +1441,7 @@ pub fn compile_submatch(bcx: block, } } } - for opts.each |o| { + for opts.iter().advance |o| { match *o { range(_, _) => { kind = compare; break } _ => () @@ -1471,7 +1463,7 @@ pub fn compile_submatch(bcx: block, let mut i = 0u; // Compile subtrees for each option - for opts.each |opt| { + for opts.iter().advance |opt| { i += 1u; let mut opt_cx = else_cx; if !exhaustive || i < len { @@ -1616,11 +1608,11 @@ pub fn compile_submatch(bcx: block, } pub fn trans_match(bcx: block, - match_expr: @ast::expr, + match_expr: &ast::expr, discr_expr: @ast::expr, arms: ~[ast::arm], dest: Dest) -> block { - let _icx = bcx.insn_ctxt("match::trans_match"); + let _icx = push_ctxt("match::trans_match"); do with_scope(bcx, match_expr.info(), "match") |bcx| { trans_match_inner(bcx, discr_expr, arms, dest) } @@ -1647,7 +1639,7 @@ fn create_bindings_map(bcx: block, pat: @ast::pat) -> BindingsMap { // but during matching we need to store a *T as explained // above let is_move = ccx.maps.moves_map.contains(&p_id); - llmatch = alloca(bcx, T_ptr(llvariable_ty)); + llmatch = alloca(bcx, llvariable_ty.ptr_to()); trmode = TrByValue(is_move, alloca(bcx, llvariable_ty)); } ast::bind_by_ref(_) => { @@ -1667,7 +1659,7 @@ pub fn trans_match_inner(scope_cx: block, discr_expr: @ast::expr, arms: &[ast::arm], dest: Dest) -> block { - let _icx = scope_cx.insn_ctxt("match::trans_match_inner"); + let _icx = push_ctxt("match::trans_match_inner"); let mut bcx = scope_cx; let tcx = bcx.tcx(); @@ -1680,14 +1672,14 @@ pub fn trans_match_inner(scope_cx: block, let mut arm_datas = ~[]; let mut matches = ~[]; - for vec::each(arms) |arm| { + for arms.iter().advance |arm| { let body = scope_block(bcx, arm.body.info(), "case_body"); let bindings_map = create_bindings_map(bcx, arm.pats[0]); let arm_data = @ArmData {bodycx: body, arm: arm, bindings_map: bindings_map}; arm_datas.push(arm_data); - for arm.pats.each |p| { + for arm.pats.iter().advance |p| { matches.push(@Match {pats: ~[*p], data: arm_data}); } } @@ -1708,7 +1700,7 @@ pub fn trans_match_inner(scope_cx: block, compile_submatch(bcx, matches, [lldiscr], chk); let mut arm_cxs = ~[]; - for arm_datas.each |arm_data| { + for arm_datas.iter().advance |arm_data| { let mut bcx = arm_data.bodycx; // If this arm has a guard, then the various by-value bindings have @@ -1754,7 +1746,7 @@ pub fn bind_irrefutable_pat(bcx: block, make_copy: bool, binding_mode: IrrefutablePatternBindingMode) -> block { - let _icx = bcx.insn_ctxt("match::bind_irrefutable_pat"); + let _icx = push_ctxt("match::bind_irrefutable_pat"); let ccx = bcx.fcx.ccx; let mut bcx = bcx; @@ -1808,7 +1800,7 @@ pub fn bind_irrefutable_pat(bcx: block, vinfo.disr_val, val); for sub_pats.iter().advance |sub_pat| { - for args.vals.eachi |i, argval| { + for args.vals.iter().enumerate().advance |(i, argval)| { bcx = bind_irrefutable_pat(bcx, sub_pat[i], *argval, @@ -1826,7 +1818,7 @@ pub fn bind_irrefutable_pat(bcx: block, Some(ref elems) => { // This is the tuple struct case. let repr = adt::represent_node(bcx, pat.id); - for elems.eachi |i, elem| { + for elems.iter().enumerate().advance |(i, elem)| { let fldptr = adt::trans_field_ptr(bcx, repr, val, 0, i); bcx = bind_irrefutable_pat(bcx, @@ -1838,8 +1830,9 @@ pub fn bind_irrefutable_pat(bcx: block, } } } - Some(&ast::def_const(*)) => { - bcx = bind_irrefutable_pat(bcx, pat, val, make_copy, binding_mode); + Some(&ast::def_static(_, false)) => { + bcx = bind_irrefutable_pat(bcx, pat, val, make_copy, + binding_mode); } _ => { // Nothing to do here. @@ -1851,7 +1844,7 @@ pub fn bind_irrefutable_pat(bcx: block, let pat_ty = node_id_type(bcx, pat.id); let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { - for fields.each |f| { + for fields.iter().advance |f| { let ix = ty::field_idx_strict(tcx, f.ident, field_tys); let fldptr = adt::trans_field_ptr(bcx, pat_repr, val, discr, ix); @@ -1865,7 +1858,7 @@ pub fn bind_irrefutable_pat(bcx: block, } ast::pat_tup(ref elems) => { let repr = adt::represent_node(bcx, pat.id); - for elems.eachi |i, elem| { + for elems.iter().enumerate().advance |(i, elem)| { let fldptr = adt::trans_field_ptr(bcx, repr, val, 0, i); bcx = bind_irrefutable_pat(bcx, *elem, diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 0976407b0bd..ab813c0ffc5 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -44,12 +44,12 @@ * taken to it, implementing them for Rust seems difficult. */ -use core::container::Map; -use core::libc::c_ulonglong; -use core::option::{Option, Some, None}; -use core::vec; +use std::container::Map; +use std::libc::c_ulonglong; +use std::option::{Option, Some, None}; +use std::vec; -use lib::llvm::{ValueRef, TypeRef, True, IntEQ, IntNE}; +use lib::llvm::{ValueRef, True, IntEQ, IntNE}; use middle::trans::_match; use middle::trans::build::*; use middle::trans::common::*; @@ -59,6 +59,8 @@ use middle::ty; use syntax::ast; use util::ppaux::ty_to_str; +use middle::trans::type_::Type; + /// Representations. pub enum Repr { @@ -84,7 +86,7 @@ pub enum Repr { * it represents the other case, which is inhabited by at most one value * (and all other fields are undefined/unused). * - * For example, `core::option::Option` instantiated at a safe pointer type + * For example, `std::option::Option` instantiated at a safe pointer type * is represented such that `None` is a null pointer and `Some` is the * identity function. */ @@ -133,7 +135,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr { ty::lookup_field_type(cx.tcx, def_id, field.id, substs) }; let packed = ty::lookup_packed(cx.tcx, def_id); - let dtor = ty::ty_dtor(cx.tcx, def_id).is_present(); + let dtor = ty::ty_dtor(cx.tcx, def_id).has_drop_flag(); let ftys = if dtor { ftys + [ty::mk_bool()] } else { ftys }; return Univariant(mk_struct(cx, ftys, packed), dtor) @@ -145,7 +147,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr { mk_struct(cx, self.tys, false).size == 0 } fn find_ptr(&self) -> Option<uint> { - self.tys.position(|&ty| mono_data_classify(ty) == MonoNonNull) + self.tys.iter().position_(|&ty| mono_data_classify(ty) == MonoNonNull) } } @@ -161,7 +163,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr { return Univariant(mk_struct(cx, [], false), false); } - if cases.all(|c| c.tys.len() == 0) { + if cases.iter().all(|c| c.tys.len() == 0) { // All bodies empty -> intlike let discrs = cases.map(|c| c.discr); return CEnum(*discrs.iter().min().unwrap(), *discrs.iter().max().unwrap()); @@ -212,7 +214,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr { fn mk_struct(cx: &mut CrateContext, tys: &[ty::t], packed: bool) -> Struct { let lltys = tys.map(|&ty| type_of::sizing_type_of(cx, ty)); - let llty_rec = T_struct(lltys, packed); + let llty_rec = Type::struct_(lltys, packed); Struct { size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64, align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64, @@ -226,17 +228,16 @@ fn mk_struct(cx: &mut CrateContext, tys: &[ty::t], packed: bool) -> Struct { * All nominal types are LLVM structs, in order to be able to use * forward-declared opaque types to prevent circularity in `type_of`. */ -pub fn fields_of(cx: &mut CrateContext, r: &Repr) -> ~[TypeRef] { +pub fn fields_of(cx: &mut CrateContext, r: &Repr) -> ~[Type] { generic_fields_of(cx, r, false) } /// Like `fields_of`, but for `type_of::sizing_type_of` (q.v.). -pub fn sizing_fields_of(cx: &mut CrateContext, r: &Repr) -> ~[TypeRef] { +pub fn sizing_fields_of(cx: &mut CrateContext, r: &Repr) -> ~[Type] { generic_fields_of(cx, r, true) } -fn generic_fields_of(cx: &mut CrateContext, r: &Repr, sizing: bool) - -> ~[TypeRef] { +fn generic_fields_of(cx: &mut CrateContext, r: &Repr, sizing: bool) -> ~[Type] { match *r { - CEnum(*) => ~[T_enum_discrim(cx)], + CEnum(*) => ~[Type::enum_discrim(cx)], Univariant(ref st, _dtor) => struct_llfields(cx, st, sizing), NullablePointer{ nonnull: ref st, _ } => struct_llfields(cx, st, sizing), General(ref sts) => { @@ -247,7 +248,7 @@ fn generic_fields_of(cx: &mut CrateContext, r: &Repr, sizing: bool) let mut most_aligned = None; let mut largest_align = 0; let mut largest_size = 0; - for sts.each |st| { + for sts.iter().advance |st| { if largest_size < st.size { largest_size = st.size; } @@ -262,13 +263,12 @@ fn generic_fields_of(cx: &mut CrateContext, r: &Repr, sizing: bool) let padding = largest_size - most_aligned.size; struct_llfields(cx, most_aligned, sizing) - + [T_array(T_i8(), padding /*bad*/as uint)] + + [Type::array(&Type::i8(), padding)] } } } -fn struct_llfields(cx: &mut CrateContext, st: &Struct, sizing: bool) - -> ~[TypeRef] { +fn struct_llfields(cx: &mut CrateContext, st: &Struct, sizing: bool) -> ~[Type] { if sizing { st.fields.map(|&ty| type_of::sizing_type_of(cx, ty)) } else { @@ -309,7 +309,7 @@ pub fn trans_get_discr(bcx: block, r: &Repr, scrutinee: ValueRef) (cases.len() - 1) as int), NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => { ZExt(bcx, nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee), - T_enum_discrim(bcx.ccx())) + Type::enum_discrim(bcx.ccx())) } } } @@ -438,11 +438,11 @@ pub fn trans_field_ptr(bcx: block, r: &Repr, val: ValueRef, discr: int, } else { // The unit-like case might have a nonzero number of unit-like fields. // (e.g., Result or Either with () as one side.) - let llty = type_of::type_of(bcx.ccx(), nullfields[ix]); - assert_eq!(machine::llsize_of_alloc(bcx.ccx(), llty), 0); + let ty = type_of::type_of(bcx.ccx(), nullfields[ix]); + assert_eq!(machine::llsize_of_alloc(bcx.ccx(), ty), 0); // The contents of memory at this pointer can't matter, but use // the value that's "reasonable" in case of pointer comparison. - PointerCast(bcx, val, T_ptr(llty)) + PointerCast(bcx, val, ty.ptr_to()) } } } @@ -456,8 +456,8 @@ fn struct_field_ptr(bcx: block, st: &Struct, val: ValueRef, ix: uint, let fields = do st.fields.map |&ty| { type_of::type_of(ccx, ty) }; - let real_llty = T_struct(fields, st.packed); - PointerCast(bcx, val, T_ptr(real_llty)) + let real_ty = Type::struct_(fields, st.packed); + PointerCast(bcx, val, real_ty.ptr_to()) } else { val }; @@ -519,10 +519,10 @@ pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: int, C_struct(build_const_struct(ccx, nonnull, vals)) } else { assert_eq!(vals.len(), 0); - let vals = do nonnull.fields.mapi |i, &ty| { + let vals = do nonnull.fields.iter().enumerate().transform |(i, &ty)| { let llty = type_of::sizing_type_of(ccx, ty); if i == ptrfield { C_null(llty) } else { C_undef(llty) } - }; + }.collect::<~[ValueRef]>(); C_struct(build_const_struct(ccx, nonnull, vals)) } } @@ -545,7 +545,7 @@ fn build_const_struct(ccx: &mut CrateContext, st: &Struct, vals: &[ValueRef]) let mut offset = 0; let mut cfields = ~[]; - for st.fields.eachi |i, &ty| { + for st.fields.iter().enumerate().advance |(i, &ty)| { let llty = type_of::sizing_type_of(ccx, ty); let type_align = machine::llalign_of_min(ccx, llty) /*bad*/as u64; @@ -572,7 +572,7 @@ fn build_const_struct(ccx: &mut CrateContext, st: &Struct, vals: &[ValueRef]) } fn padding(size: u64) -> ValueRef { - C_undef(T_array(T_i8(), size /*bad*/as uint)) + C_undef(Type::array(&Type::i8(), size)) } // XXX this utility routine should be somewhere more general diff --git a/src/librustc/middle/trans/asm.rs b/src/librustc/middle/trans/asm.rs index d73d57efbbf..fadeab0f1f7 100644 --- a/src/librustc/middle/trans/asm.rs +++ b/src/librustc/middle/trans/asm.rs @@ -12,7 +12,6 @@ # Translation of inline assembly. */ -use core::prelude::*; use lib; use middle::trans::build::*; @@ -20,7 +19,9 @@ use middle::trans::callee; use middle::trans::common::*; use middle::ty; -use core::str; +use middle::trans::type_::Type; + +use std::str; use syntax::ast; // Take an inline assembly expression and splat it out via LLVM @@ -62,7 +63,7 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block { }; - for cleanups.each |c| { + for cleanups.iter().advance |c| { revoke_clean(bcx, *c); } cleanups.clear(); @@ -83,7 +84,7 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block { }; - for cleanups.each |c| { + for cleanups.iter().advance |c| { revoke_clean(bcx, *c); } @@ -93,15 +94,15 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block { if !ia.clobbers.is_empty() && !clobbers.is_empty() { clobbers = fmt!("%s,%s", ia.clobbers, clobbers); } else { - clobbers += ia.clobbers; + clobbers.push_str(ia.clobbers); }; // Add the clobbers to our constraints list - if !clobbers.is_empty() && !constraints.is_empty() { - constraints += ","; - constraints += clobbers; + if clobbers.len() != 0 && constraints.len() != 0 { + constraints.push_char(','); + constraints.push_str(clobbers); } else { - constraints += clobbers; + constraints.push_str(clobbers); } debug!("Asm Constraints: %?", constraints); @@ -110,11 +111,11 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block { // Depending on how many outputs we have, the return type is different let output = if numOutputs == 0 { - T_void() + Type::void() } else if numOutputs == 1 { val_ty(outputs[0]) } else { - T_struct(outputs.map(|o| val_ty(*o)), false) + Type::struct_(outputs.map(|o| val_ty(*o)), false) }; let dialect = match ia.dialect { @@ -130,12 +131,12 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block { // Again, based on how many outputs we have if numOutputs == 1 { - let op = PointerCast(bcx, aoutputs[0], T_ptr(val_ty(outputs[0]))); + let op = PointerCast(bcx, aoutputs[0], val_ty(outputs[0]).ptr_to()); Store(bcx, r, op); } else { - for aoutputs.eachi |i, o| { + for aoutputs.iter().enumerate().advance |(i, o)| { let v = ExtractValue(bcx, r, i); - let op = PointerCast(bcx, *o, T_ptr(val_ty(outputs[i]))); + let op = PointerCast(bcx, *o, val_ty(outputs[i]).ptr_to()); Store(bcx, v, op); } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index d7d21707f40..d598a6fbcf9 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -23,14 +23,13 @@ // but many TypeRefs correspond to one ty::t; for instance, tup(int, int, // int) and rec(x=int, y=int, z=int) will have the same TypeRef. -use core::prelude::*; use back::link::{mangle_exported_name}; use back::{link, abi}; use driver::session; use driver::session::Session; -use lib::llvm::{ContextRef, ModuleRef, ValueRef, TypeRef, BasicBlockRef}; -use lib::llvm::{llvm, True, False}; +use lib::llvm::{ContextRef, ModuleRef, ValueRef, BasicBlockRef}; +use lib::llvm::{llvm, True}; use lib; use metadata::common::LinkMeta; use metadata::{csearch, cstore, encoder}; @@ -54,8 +53,6 @@ use middle::trans::machine; use middle::trans::machine::{llalign_of_min, llsize_of}; use middle::trans::meth; use middle::trans::monomorphize; -use middle::trans::reachable; -use middle::trans::shape::*; use middle::trans::tvec; use middle::trans::type_of; use middle::trans::type_of::*; @@ -63,14 +60,17 @@ use middle::ty; use util::common::indenter; use util::ppaux::{Repr, ty_to_str}; -use core::hash; -use core::hashmap::{HashMap}; -use core::int; -use core::io; -use core::libc::c_uint; -use core::str; -use core::uint; -use core::vec; +use middle::trans::type_::Type; + +use std::hash; +use std::hashmap::{HashMap, HashSet}; +use std::int; +use std::io; +use std::libc::c_uint; +use std::str; +use std::uint; +use std::vec; +use std::local_data; use extra::time; use syntax::ast::ident; use syntax::ast_map::{path, path_elt_to_str, path_name}; @@ -86,49 +86,52 @@ use syntax::abi::{X86, X86_64, Arm, Mips}; pub use middle::trans::context::task_llcx; -pub struct icx_popper { - ccx: @mut CrateContext, -} +fn task_local_insn_key(_v: @~[&'static str]) {} -#[unsafe_destructor] -impl Drop for icx_popper { - fn finalize(&self) { - if self.ccx.sess.count_llvm_insns() { - self.ccx.stats.llvm_insn_ctxt.pop(); +pub fn with_insn_ctxt(blk: &fn(&[&'static str])) { + unsafe { + let opt = local_data::local_data_get(task_local_insn_key); + if opt.is_some() { + blk(*opt.unwrap()); } } } -pub fn icx_popper(ccx: @mut CrateContext) -> icx_popper { - icx_popper { - ccx: ccx +pub fn init_insn_ctxt() { + unsafe { + local_data::local_data_set(task_local_insn_key, @~[]); } } -pub trait get_insn_ctxt { - fn insn_ctxt(&self, s: &str) -> icx_popper; -} +pub struct _InsnCtxt { _x: () } -impl get_insn_ctxt for @mut CrateContext { - fn insn_ctxt(&self, s: &str) -> icx_popper { - debug!("new insn_ctxt: %s", s); - if self.sess.count_llvm_insns() { - self.stats.llvm_insn_ctxt.push(str::to_owned(s)); +#[unsafe_destructor] +impl Drop for _InsnCtxt { + fn drop(&self) { + unsafe { + do local_data::local_data_modify(task_local_insn_key) |c| { + do c.map_consume |@ctx| { + let mut ctx = ctx; + ctx.pop(); + @ctx + } + } } - icx_popper(*self) } } -impl get_insn_ctxt for block { - fn insn_ctxt(&self, s: &str) -> icx_popper { - self.ccx().insn_ctxt(s) - } -} - -impl get_insn_ctxt for fn_ctxt { - fn insn_ctxt(&self, s: &str) -> icx_popper { - self.ccx.insn_ctxt(s) +pub fn push_ctxt(s: &'static str) -> _InsnCtxt { + debug!("new InsnCtxt: %s", s); + unsafe { + do local_data::local_data_modify(task_local_insn_key) |c| { + do c.map_consume |@ctx| { + let mut ctx = ctx; + ctx.push(s); + @ctx + } + } } + _InsnCtxt { _x: () } } fn fcx_has_nonzero_span(fcx: fn_ctxt) -> bool { @@ -138,49 +141,33 @@ fn fcx_has_nonzero_span(fcx: fn_ctxt) -> bool { } } -pub fn log_fn_time(ccx: @mut CrateContext, name: ~str, start: time::Timespec, - end: time::Timespec) { - let elapsed = 1000 * ((end.sec - start.sec) as int) + - ((end.nsec as int) - (start.nsec as int)) / 1000000; - ccx.stats.fn_times.push((name, elapsed)); -} - -pub fn decl_fn(llmod: ModuleRef, - name: &str, - cc: lib::llvm::CallConv, - llty: TypeRef) - -> ValueRef { - let llfn: ValueRef = str::as_c_str(name, |buf| { +pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef { + let llfn: ValueRef = do name.as_c_str |buf| { unsafe { - llvm::LLVMGetOrInsertFunction(llmod, buf, llty) + llvm::LLVMGetOrInsertFunction(llmod, buf, ty.to_ref()) } - }); + }; lib::llvm::SetFunctionCallConv(llfn, cc); return llfn; } -pub fn decl_cdecl_fn(llmod: ModuleRef, name: &str, llty: TypeRef) - -> ValueRef { - return decl_fn(llmod, name, lib::llvm::CCallConv, llty); +pub fn decl_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef { + return decl_fn(llmod, name, lib::llvm::CCallConv, ty); } // Only use this if you are going to actually define the function. It's // not valid to simply declare a function as internal. -pub fn decl_internal_cdecl_fn(llmod: ModuleRef, name: ~str, llty: TypeRef) -> - ValueRef { - let llfn = decl_cdecl_fn(llmod, name, llty); +pub fn decl_internal_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef { + let llfn = decl_cdecl_fn(llmod, name, ty); lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage); return llfn; } -pub fn get_extern_fn(externs: &mut ExternMap, - llmod: ModuleRef, - name: @str, - cc: lib::llvm::CallConv, - ty: TypeRef) -> ValueRef { - match externs.find(&name) { - Some(n) => return copy *n, +pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: @str, + cc: lib::llvm::CallConv, ty: Type) -> ValueRef { + match externs.find_copy(&name) { + Some(n) => return n, None => () } let f = decl_fn(llmod, name, cc, ty); @@ -189,51 +176,27 @@ pub fn get_extern_fn(externs: &mut ExternMap, } pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef, - name: @str, ty: TypeRef) -> ValueRef { - match externs.find(&name) { - Some(n) => return copy *n, + name: @str, ty: Type) -> ValueRef { + match externs.find_copy(&name) { + Some(n) => return n, None => () } unsafe { - let c = str::as_c_str(name, |buf| { - llvm::LLVMAddGlobal(llmod, ty, buf) - }); + let c = do name.as_c_str |buf| { + llvm::LLVMAddGlobal(llmod, ty.to_ref(), buf) + }; externs.insert(name, c); return c; } } - -fn get_simple_extern_fn(cx: block, - externs: &mut ExternMap, - llmod: ModuleRef, - name: @str, - n_args: int) -> ValueRef { - let _icx = cx.insn_ctxt("get_simple_extern_fn"); - let ccx = cx.fcx.ccx; - let inputs = vec::from_elem(n_args as uint, ccx.int_type); - let output = ccx.int_type; - let t = T_fn(inputs, output); - return get_extern_fn(externs, llmod, name, lib::llvm::CCallConv, t); -} - -pub fn trans_foreign_call(cx: block, externs: &mut ExternMap, - llmod: ModuleRef, name: @str, args: &[ValueRef]) -> - ValueRef { - let _icx = cx.insn_ctxt("trans_foreign_call"); - let n = args.len() as int; - let llforeign: ValueRef = - get_simple_extern_fn(cx, externs, llmod, name, n); - return Call(cx, llforeign, args); -} - pub fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef { - let _icx = cx.insn_ctxt("umax"); + let _icx = push_ctxt("umax"); let cond = ICmp(cx, lib::llvm::IntULT, a, b); return Select(cx, cond, b, a); } pub fn umin(cx: block, a: ValueRef, b: ValueRef) -> ValueRef { - let _icx = cx.insn_ctxt("umin"); + let _icx = push_ctxt("umin"); let cond = ICmp(cx, lib::llvm::IntULT, a, b); return Select(cx, cond, a, b); } @@ -242,8 +205,8 @@ pub fn umin(cx: block, a: ValueRef, b: ValueRef) -> ValueRef { // The type of the returned pointer is always i8*. If you care about the // return type, use bump_ptr(). pub fn ptr_offs(bcx: block, base: ValueRef, sz: ValueRef) -> ValueRef { - let _icx = bcx.insn_ctxt("ptr_offs"); - let raw = PointerCast(bcx, base, T_ptr(T_i8())); + let _icx = push_ctxt("ptr_offs"); + let raw = PointerCast(bcx, base, Type::i8p()); InBoundsGEP(bcx, raw, [sz]) } @@ -251,10 +214,10 @@ pub fn ptr_offs(bcx: block, base: ValueRef, sz: ValueRef) -> ValueRef { // to a given type. pub fn bump_ptr(bcx: block, t: ty::t, base: ValueRef, sz: ValueRef) -> ValueRef { - let _icx = bcx.insn_ctxt("bump_ptr"); + let _icx = push_ctxt("bump_ptr"); let ccx = bcx.ccx(); let bumped = ptr_offs(bcx, base, sz); - let typ = T_ptr(type_of(ccx, t)); + let typ = type_of(ccx, t).ptr_to(); PointerCast(bcx, bumped, typ) } @@ -266,11 +229,11 @@ pub fn bump_ptr(bcx: block, t: ty::t, base: ValueRef, sz: ValueRef) -> pub fn opaque_box_body(bcx: block, body_t: ty::t, boxptr: ValueRef) -> ValueRef { - let _icx = bcx.insn_ctxt("opaque_box_body"); + let _icx = push_ctxt("opaque_box_body"); let ccx = bcx.ccx(); let ty = type_of(ccx, body_t); - let ty = T_box(ccx, ty); - let boxptr = PointerCast(bcx, boxptr, T_ptr(ty)); + let ty = Type::box(ccx, &ty); + let boxptr = PointerCast(bcx, boxptr, ty.ptr_to()); GEPi(bcx, boxptr, [0u, abi::box_field_body]) } @@ -280,7 +243,7 @@ pub fn malloc_raw_dyn(bcx: block, t: ty::t, heap: heap, size: ValueRef) -> Result { - let _icx = bcx.insn_ctxt("malloc_raw"); + let _icx = push_ctxt("malloc_raw"); let ccx = bcx.ccx(); let (mk_fn, langcall) = match heap { @@ -290,45 +253,47 @@ pub fn malloc_raw_dyn(bcx: block, heap_exchange => { (ty::mk_imm_uniq, bcx.tcx().lang_items.exchange_malloc_fn()) } + heap_exchange_closure => { + (ty::mk_imm_uniq, bcx.tcx().lang_items.closure_exchange_malloc_fn()) + } }; - // Grab the TypeRef type of box_ptr_ty. - let box_ptr_ty = mk_fn(bcx.tcx(), t); - let llty = type_of(ccx, box_ptr_ty); - - // Get the tydesc for the body: - let static_ti = get_tydesc(ccx, t); - glue::lazily_emit_all_tydesc_glue(ccx, static_ti); - - // Allocate space: - let tydesc = PointerCast(bcx, static_ti.tydesc, T_ptr(T_i8())); - let rval = alloca(bcx, T_ptr(T_i8())); - let bcx = callee::trans_lang_call( - bcx, - langcall, - [tydesc, size], - expr::SaveIn(rval)); - let r = rslt(bcx, PointerCast(bcx, Load(bcx, rval), llty)); - maybe_set_managed_unique_rc(r.bcx, r.val, heap); - r -} - -/** -* Get the type of a box in the default address space. -* -* Shared box pointers live in address space 1 so the GC strategy can find -* them. Before taking a pointer to the inside of a box it should be cast into -* address space 0. Otherwise the resulting (non-box) pointer will be in the -* wrong address space and thus be the wrong type. -*/ -pub fn non_gc_box_cast(bcx: block, val: ValueRef) -> ValueRef { - unsafe { - debug!("non_gc_box_cast"); - add_comment(bcx, "non_gc_box_cast"); - assert!(llvm::LLVMGetPointerAddressSpace(val_ty(val)) == - gc_box_addrspace || bcx.unreachable); - let non_gc_t = T_ptr(llvm::LLVMGetElementType(val_ty(val))); - PointerCast(bcx, val, non_gc_t) + if heap == heap_exchange { + // Grab the TypeRef type of box_ptr_ty. + let box_ptr_ty = mk_fn(bcx.tcx(), t); + let llty = type_of(ccx, box_ptr_ty); + + let llty_value = type_of::type_of(ccx, t); + let llalign = llalign_of_min(ccx, llty_value); + + // Allocate space: + let rval = alloca(bcx, Type::i8p()); + let bcx = callee::trans_lang_call( + bcx, + langcall, + [C_i32(llalign as i32), size], + expr::SaveIn(rval)); + rslt(bcx, PointerCast(bcx, Load(bcx, rval), llty)) + } else { + // Grab the TypeRef type of box_ptr_ty. + let box_ptr_ty = mk_fn(bcx.tcx(), t); + let llty = type_of(ccx, box_ptr_ty); + + // Get the tydesc for the body: + let static_ti = get_tydesc(ccx, t); + glue::lazily_emit_all_tydesc_glue(ccx, static_ti); + + // Allocate space: + let tydesc = PointerCast(bcx, static_ti.tydesc, Type::i8p()); + let rval = alloca(bcx, Type::i8p()); + let bcx = callee::trans_lang_call( + bcx, + langcall, + [tydesc, size], + expr::SaveIn(rval)); + let r = rslt(bcx, PointerCast(bcx, Load(bcx, rval), llty)); + maybe_set_managed_unique_rc(r.bcx, r.val, heap); + r } } @@ -351,10 +316,9 @@ pub struct MallocResult { // and pulls out the body pub fn malloc_general_dyn(bcx: block, t: ty::t, heap: heap, size: ValueRef) -> MallocResult { - let _icx = bcx.insn_ctxt("malloc_general"); + let _icx = push_ctxt("malloc_general"); let Result {bcx: bcx, val: llbox} = malloc_raw_dyn(bcx, t, heap, size); - let non_gc_box = non_gc_box_cast(bcx, llbox); - let body = GEPi(bcx, non_gc_box, [0u, abi::box_field_body]); + let body = GEPi(bcx, llbox, [0u, abi::box_field_body]); MallocResult { bcx: bcx, box: llbox, body: body } } @@ -502,7 +466,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext, parent_id: ast::def_id, substs: &[ty::t]) -> ValueRef { - let _icx = ccx.insn_ctxt("trans_res_dtor"); + let _icx = push_ctxt("trans_res_dtor"); if !substs.is_empty() { let did = if did.crate != ast::local_crate { inline::maybe_instantiate_inline(ccx, did, true) @@ -517,6 +481,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext, &tsubsts, None, None, + None, None); val @@ -592,7 +557,7 @@ pub fn compare_scalar_values(cx: block, nt: scalar_type, op: ast::binop) -> ValueRef { - let _icx = cx.insn_ctxt("compare_scalar_values"); + let _icx = push_ctxt("compare_scalar_values"); fn die(cx: block) -> ! { cx.tcx().sess.bug("compare_scalar_values: must be a\ comparison operator"); @@ -647,8 +612,7 @@ pub fn compare_scalar_values(cx: block, } } -pub type val_pair_fn = @fn(block, ValueRef, ValueRef) -> block; -pub type val_and_ty_fn = @fn(block, ValueRef, ty::t) -> block; +pub type val_and_ty_fn<'self> = &'self fn(block, ValueRef, ty::t) -> block; pub fn load_inbounds(cx: block, p: ValueRef, idxs: &[uint]) -> ValueRef { return Load(cx, GEPi(cx, p, idxs)); @@ -661,16 +625,16 @@ pub fn store_inbounds(cx: block, v: ValueRef, p: ValueRef, idxs: &[uint]) { // Iterates through the elements of a structural type. pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, f: val_and_ty_fn) -> block { - let _icx = cx.insn_ctxt("iter_structural_ty"); + let _icx = push_ctxt("iter_structural_ty"); fn iter_variant(cx: block, repr: &adt::Repr, av: ValueRef, variant: ty::VariantInfo, tps: &[ty::t], f: val_and_ty_fn) -> block { - let _icx = cx.insn_ctxt("iter_variant"); + let _icx = push_ctxt("iter_variant"); let tcx = cx.tcx(); let mut cx = cx; - for variant.args.eachi |i, &arg| { + for variant.args.iter().enumerate().advance |(i, &arg)| { cx = f(cx, adt::trans_field_ptr(cx, repr, av, variant.disr_val, i), ty::subst_tps(tcx, tps, None, arg)); @@ -683,7 +647,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, ty::ty_struct(*) => { let repr = adt::represent_type(cx.ccx(), t); do expr::with_field_tys(cx.tcx(), t, None) |discr, field_tys| { - for field_tys.eachi |i, field_ty| { + for field_tys.iter().enumerate().advance |(i, field_ty)| { let llfld_a = adt::trans_field_ptr(cx, repr, av, discr, i); cx = f(cx, llfld_a, field_ty.mt.ty); } @@ -696,7 +660,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, } ty::ty_tup(ref args) => { let repr = adt::represent_type(cx.ccx(), t); - for args.eachi |i, arg| { + for args.iter().enumerate().advance |(i, arg)| { let llfld_a = adt::trans_field_ptr(cx, repr, av, 0, i); cx = f(cx, llfld_a, *arg); } @@ -724,13 +688,13 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, n_variants); let next_cx = sub_block(cx, "enum-iter-next"); - for (*variants).each |variant| { + for (*variants).iter().advance |variant| { let variant_cx = sub_block(cx, ~"enum-iter-variant-" + int::to_str(variant.disr_val)); let variant_cx = iter_variant(variant_cx, repr, av, *variant, - substs.tps, f); + substs.tps, |x,y,z| f(x,y,z)); match adt::trans_case(cx, repr, variant.disr_val) { _match::single_result(r) => { AddCase(llswitch, r.val, variant_cx.llbb) @@ -761,22 +725,22 @@ pub fn cast_shift_expr_rhs(cx: block, op: ast::binop, pub fn cast_shift_const_rhs(op: ast::binop, lhs: ValueRef, rhs: ValueRef) -> ValueRef { cast_shift_rhs(op, lhs, rhs, - |a, b| unsafe { llvm::LLVMConstTrunc(a, b) }, - |a, b| unsafe { llvm::LLVMConstZExt(a, b) }) + |a, b| unsafe { llvm::LLVMConstTrunc(a, b.to_ref()) }, + |a, b| unsafe { llvm::LLVMConstZExt(a, b.to_ref()) }) } pub fn cast_shift_rhs(op: ast::binop, lhs: ValueRef, rhs: ValueRef, - trunc: &fn(ValueRef, TypeRef) -> ValueRef, - zext: &fn(ValueRef, TypeRef) -> ValueRef) + trunc: &fn(ValueRef, Type) -> ValueRef, + zext: &fn(ValueRef, Type) -> ValueRef) -> ValueRef { // Shifts may have any size int on the rhs unsafe { if ast_util::is_shift_binop(op) { let rhs_llty = val_ty(rhs); let lhs_llty = val_ty(lhs); - let rhs_sz = llvm::LLVMGetIntTypeWidth(rhs_llty); - let lhs_sz = llvm::LLVMGetIntTypeWidth(lhs_llty); + let rhs_sz = llvm::LLVMGetIntTypeWidth(rhs_llty.to_ref()); + let lhs_sz = llvm::LLVMGetIntTypeWidth(lhs_llty.to_ref()); if lhs_sz < rhs_sz { trunc(rhs, lhs_llty) } else if lhs_sz > rhs_sz { @@ -801,11 +765,11 @@ pub fn fail_if_zero(cx: block, span: span, divrem: ast::binop, }; let is_zero = match ty::get(rhs_t).sty { ty::ty_int(t) => { - let zero = C_integral(T_int_ty(cx.ccx(), t), 0u64, False); + let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0u64, false); ICmp(cx, lib::llvm::IntEQ, rhs, zero) } ty::ty_uint(t) => { - let zero = C_integral(T_uint_ty(cx.ccx(), t), 0u64, False); + let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0u64, false); ICmp(cx, lib::llvm::IntEQ, rhs, zero) } _ => { @@ -819,7 +783,7 @@ pub fn fail_if_zero(cx: block, span: span, divrem: ast::binop, } pub fn null_env_ptr(bcx: block) -> ValueRef { - C_null(T_opaque_box_ptr(bcx.ccx())) + C_null(Type::opaque_box(bcx.ccx()).ptr_to()) } pub fn trans_external_path(ccx: &mut CrateContext, did: ast::def_id, t: ty::t) @@ -840,9 +804,9 @@ pub fn trans_external_path(ccx: &mut CrateContext, did: ast::def_id, t: ty::t) pub fn invoke(bcx: block, llfn: ValueRef, llargs: ~[ValueRef]) -> (ValueRef, block) { - let _icx = bcx.insn_ctxt("invoke_"); + let _icx = push_ctxt("invoke_"); if bcx.unreachable { - return (C_null(T_i8()), bcx); + return (C_null(Type::i8()), bcx); } match bcx.node_info { @@ -856,10 +820,10 @@ pub fn invoke(bcx: block, llfn: ValueRef, llargs: ~[ValueRef]) if need_invoke(bcx) { unsafe { debug!("invoking %x at %x", - ::core::cast::transmute(llfn), - ::core::cast::transmute(bcx.llbb)); - for llargs.each |&llarg| { - debug!("arg: %x", ::core::cast::transmute(llarg)); + ::std::cast::transmute(llfn), + ::std::cast::transmute(bcx.llbb)); + for llargs.iter().advance |&llarg| { + debug!("arg: %x", ::std::cast::transmute(llarg)); } } let normal_bcx = sub_block(bcx, "normal return"); @@ -872,10 +836,10 @@ pub fn invoke(bcx: block, llfn: ValueRef, llargs: ~[ValueRef]) } else { unsafe { debug!("calling %x at %x", - ::core::cast::transmute(llfn), - ::core::cast::transmute(bcx.llbb)); - for llargs.each |&llarg| { - debug!("arg: %x", ::core::cast::transmute(llarg)); + ::std::cast::transmute(llfn), + ::std::cast::transmute(bcx.llbb)); + for llargs.iter().advance |&llarg| { + debug!("arg: %x", ::std::cast::transmute(llarg)); } } let llresult = Call(bcx, llfn, llargs); @@ -903,7 +867,7 @@ pub fn need_invoke(bcx: block) -> bool { match cur.kind { block_scope(inf) => { let inf = &mut *inf; // FIXME(#5074) workaround old borrowck - for inf.cleanups.each |cleanup| { + for inf.cleanups.iter().advance |cleanup| { match *cleanup { clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) => { if cleanup_type == normal_exit_and_unwind { @@ -956,7 +920,7 @@ pub fn in_lpad_scope_cx(bcx: block, f: &fn(si: &mut scope_info)) { } pub fn get_landing_pad(bcx: block) -> BasicBlockRef { - let _icx = bcx.insn_ctxt("get_landing_pad"); + let _icx = push_ctxt("get_landing_pad"); let mut cached = None; let mut pad_bcx = bcx; // Guaranteed to be set below @@ -975,7 +939,7 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef { // The landing pad return type (the type being propagated). Not sure what // this represents but it's determined by the personality function and // this is what the EH proposal example uses. - let llretty = T_struct([T_ptr(T_i8()), T_i32()], false); + let llretty = Type::struct_([Type::i8p(), Type::i32()], false); // The exception handling personality function. This is the C++ // personality function __gxx_personality_v0, wrapped in our naming // convention. @@ -1033,7 +997,7 @@ pub fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block { pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef { if ty::type_is_bot(t) { - return C_null(T_ptr(T_i8())); + return C_null(Type::i8p()); } let llptr = alloc_ty(bcx, t); Store(bcx, v, llptr); @@ -1049,20 +1013,20 @@ pub fn do_spill_noroot(cx: block, v: ValueRef) -> ValueRef { } pub fn spill_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef { - let _icx = cx.insn_ctxt("spill_if_immediate"); + let _icx = push_ctxt("spill_if_immediate"); if ty::type_is_immediate(t) { return do_spill(cx, v, t); } return v; } pub fn load_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef { - let _icx = cx.insn_ctxt("load_if_immediate"); + let _icx = push_ctxt("load_if_immediate"); if ty::type_is_immediate(t) { return Load(cx, v); } return v; } pub fn trans_trace(bcx: block, sp_opt: Option<span>, trace_str: @str) { if !bcx.sess().trace() { return; } - let _icx = bcx.insn_ctxt("trans_trace"); + let _icx = push_ctxt("trans_trace"); add_comment(bcx, trace_str); let V_trace_str = C_cstr(bcx.ccx(), trace_str); let (V_filename, V_line) = match sp_opt { @@ -1076,30 +1040,30 @@ pub fn trans_trace(bcx: block, sp_opt: Option<span>, trace_str: @str) { } }; let ccx = bcx.ccx(); - let V_trace_str = PointerCast(bcx, V_trace_str, T_ptr(T_i8())); - let V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8())); + let V_trace_str = PointerCast(bcx, V_trace_str, Type::i8p()); + let V_filename = PointerCast(bcx, V_filename, Type::i8p()); let args = ~[V_trace_str, V_filename, C_int(ccx, V_line)]; Call(bcx, ccx.upcalls.trace, args); } pub fn build_return(bcx: block) { - let _icx = bcx.insn_ctxt("build_return"); + let _icx = push_ctxt("build_return"); Br(bcx, bcx.fcx.llreturn); } -pub fn ignore_lhs(_bcx: block, local: @ast::local) -> bool { +pub fn ignore_lhs(_bcx: block, local: &ast::local) -> bool { match local.node.pat.node { ast::pat_wild => true, _ => false } } -pub fn init_local(bcx: block, local: @ast::local) -> block { +pub fn init_local(bcx: block, local: &ast::local) -> block { debug!("init_local(bcx=%s, local.id=%?)", bcx.to_str(), local.node.id); let _indenter = indenter(); - let _icx = bcx.insn_ctxt("init_local"); + let _icx = push_ctxt("init_local"); let ty = node_id_type(bcx, local.node.id); debug!("ty=%s", bcx.ty_to_str(ty)); @@ -1147,7 +1111,7 @@ pub fn init_local(bcx: block, local: @ast::local) -> block { } pub fn trans_stmt(cx: block, s: &ast::stmt) -> block { - let _icx = cx.insn_ctxt("trans_stmt"); + let _icx = push_ctxt("trans_stmt"); debug!("trans_stmt(%s)", stmt_to_str(s, cx.tcx().sess.intr())); if cx.sess().asm_comments() { @@ -1185,15 +1149,10 @@ pub fn new_block(cx: fn_ctxt, parent: Option<block>, kind: block_kind, is_lpad: bool, name: &str, opt_node_info: Option<NodeInfo>) -> block { - let s = if cx.ccx.sess.opts.save_temps || cx.ccx.sess.opts.debuginfo { - (cx.ccx.names)(name) - } else { - special_idents::invalid - }; unsafe { - let llbb = str::as_c_str(cx.ccx.sess.str_of(s), |buf| { + let llbb = do name.as_c_str |buf| { llvm::LLVMAppendBasicBlockInContext(cx.ccx.llcx, cx.llfn, buf) - }); + }; let bcx = mk_block(llbb, parent, kind, @@ -1201,8 +1160,11 @@ pub fn new_block(cx: fn_ctxt, parent: Option<block>, kind: block_kind, opt_node_info, cx); for parent.iter().advance |cx| { - if cx.unreachable { Unreachable(bcx); } - }; + if cx.unreachable { + Unreachable(bcx); + break; + } + } bcx } } @@ -1275,7 +1237,7 @@ pub fn trans_block_cleanups_(bcx: block, cleanups: &[cleanup], /* cleanup_cx: block, */ is_lpad: bool) -> block { - let _icx = bcx.insn_ctxt("trans_block_cleanups"); + let _icx = push_ctxt("trans_block_cleanups"); // NB: Don't short-circuit even if this block is unreachable because // GC-based cleanup needs to the see that the roots are live. let no_lpads = @@ -1302,7 +1264,7 @@ pub fn trans_block_cleanups_(bcx: block, pub fn cleanup_and_leave(bcx: block, upto: Option<BasicBlockRef>, leave: Option<BasicBlockRef>) { - let _icx = bcx.insn_ctxt("cleanup_and_leave"); + let _icx = push_ctxt("cleanup_and_leave"); let mut cur = bcx; let mut bcx = bcx; let is_lpad = leave == None; @@ -1322,7 +1284,7 @@ pub fn cleanup_and_leave(bcx: block, let mut skip = 0; let mut dest = None; { - let r = vec::rfind((*inf).cleanup_paths, |cp| cp.target == leave); + let r = (*inf).cleanup_paths.rev_iter().find_(|cp| cp.target == leave); for r.iter().advance |cp| { if cp.size == inf.cleanups.len() { Br(bcx, cp.dest); @@ -1369,12 +1331,12 @@ pub fn cleanup_and_leave(bcx: block, } pub fn cleanup_and_Br(bcx: block, upto: block, target: BasicBlockRef) { - let _icx = bcx.insn_ctxt("cleanup_and_Br"); + let _icx = push_ctxt("cleanup_and_Br"); cleanup_and_leave(bcx, Some(upto.llbb), Some(target)); } pub fn leave_block(bcx: block, out_of: block) -> block { - let _icx = bcx.insn_ctxt("leave_block"); + let _icx = push_ctxt("leave_block"); let next_cx = sub_block(block_parent(out_of), "next"); if bcx.unreachable { Unreachable(next_cx); } cleanup_and_Br(bcx, out_of, next_cx.llbb); @@ -1385,7 +1347,7 @@ pub fn with_scope(bcx: block, opt_node_info: Option<NodeInfo>, name: &str, f: &fn(block) -> block) -> block { - let _icx = bcx.insn_ctxt("with_scope"); + let _icx = push_ctxt("with_scope"); debug!("with_scope(bcx=%s, opt_node_info=%?, name=%s)", bcx.to_str(), opt_node_info, name); @@ -1400,7 +1362,7 @@ pub fn with_scope_result(bcx: block, opt_node_info: Option<NodeInfo>, name: &str, f: &fn(block) -> Result) -> Result { - let _icx = bcx.insn_ctxt("with_scope_result"); + let _icx = push_ctxt("with_scope_result"); let scope_cx = scope_block(bcx, opt_node_info, name); Br(bcx, scope_cx.llbb); let Result {bcx, val} = f(scope_cx); @@ -1412,7 +1374,7 @@ pub fn with_scope_datumblock(bcx: block, opt_node_info: Option<NodeInfo>, -> datum::DatumBlock { use middle::trans::datum::DatumBlock; - let _icx = bcx.insn_ctxt("with_scope_result"); + let _icx = push_ctxt("with_scope_result"); let scope_cx = scope_block(bcx, opt_node_info, name); Br(bcx, scope_cx.llbb); let DatumBlock {bcx, datum} = f(scope_cx); @@ -1420,7 +1382,7 @@ pub fn with_scope_datumblock(bcx: block, opt_node_info: Option<NodeInfo>, } pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) { - for b.node.stmts.each |s| { + for b.node.stmts.iter().advance |s| { match s.node { ast::stmt_decl(d, _) => { match d.node { @@ -1433,8 +1395,8 @@ pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) { } } -pub fn alloc_local(cx: block, local: @ast::local) -> block { - let _icx = cx.insn_ctxt("alloc_local"); +pub fn alloc_local(cx: block, local: &ast::local) -> block { + let _icx = push_ctxt("alloc_local"); let t = node_id_type(cx, local.node.id); let simple_name = match local.node.pat.node { ast::pat_ident(_, pth, None) => Some(path_to_ident(pth)), @@ -1456,7 +1418,7 @@ pub fn alloc_local(cx: block, local: @ast::local) -> block { pub fn with_cond(bcx: block, val: ValueRef, f: &fn(block) -> block) -> block { - let _icx = bcx.insn_ctxt("with_cond"); + let _icx = push_ctxt("with_cond"); let next_cx = base::sub_block(bcx, "next"); let cond_cx = base::sub_block(bcx, "cond"); CondBr(bcx, val, cond_cx.llbb, next_cx.llbb); @@ -1466,15 +1428,15 @@ pub fn with_cond(bcx: block, val: ValueRef, f: &fn(block) -> block) -> block { } pub fn call_memcpy(cx: block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) { - let _icx = cx.insn_ctxt("call_memcpy"); + let _icx = push_ctxt("call_memcpy"); let ccx = cx.ccx(); let key = match ccx.sess.targ_cfg.arch { X86 | Arm | Mips => "llvm.memcpy.p0i8.p0i8.i32", X86_64 => "llvm.memcpy.p0i8.p0i8.i64" }; let memcpy = ccx.intrinsics.get_copy(&key); - let src_ptr = PointerCast(cx, src, T_ptr(T_i8())); - let dst_ptr = PointerCast(cx, dst, T_ptr(T_i8())); + let src_ptr = PointerCast(cx, src, Type::i8p()); + let dst_ptr = PointerCast(cx, dst, Type::i8p()); let size = IntCast(cx, n_bytes, ccx.int_type); let align = C_i32(align as i32); let volatile = C_i1(false); @@ -1482,7 +1444,7 @@ pub fn call_memcpy(cx: block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, a } pub fn memcpy_ty(bcx: block, dst: ValueRef, src: ValueRef, t: ty::t) { - let _icx = bcx.insn_ctxt("memcpy_ty"); + let _icx = push_ctxt("memcpy_ty"); let ccx = bcx.ccx(); if ty::type_is_structural(t) { let llty = type_of::type_of(ccx, t); @@ -1495,7 +1457,7 @@ pub fn memcpy_ty(bcx: block, dst: ValueRef, src: ValueRef, t: ty::t) { } pub fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) { - let _icx = cx.insn_ctxt("zero_mem"); + let _icx = push_ctxt("zero_mem"); let bcx = cx; let ccx = cx.ccx(); let llty = type_of::type_of(ccx, t); @@ -1507,8 +1469,8 @@ pub fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) { // allocation for large data structures, and the generated code will be // awful. (A telltale sign of this is large quantities of // `mov [byte ptr foo],0` in the generated code.) -pub fn memzero(cx: block, llptr: ValueRef, llty: TypeRef) { - let _icx = cx.insn_ctxt("memzero"); +pub fn memzero(cx: block, llptr: ValueRef, ty: Type) { + let _icx = push_ctxt("memzero"); let ccx = cx.ccx(); let intrinsic_key = match ccx.sess.targ_cfg.arch { @@ -1517,50 +1479,48 @@ pub fn memzero(cx: block, llptr: ValueRef, llty: TypeRef) { }; let llintrinsicfn = ccx.intrinsics.get_copy(&intrinsic_key); - let llptr = PointerCast(cx, llptr, T_ptr(T_i8())); + let llptr = PointerCast(cx, llptr, Type::i8().ptr_to()); let llzeroval = C_u8(0); - let size = IntCast(cx, machine::llsize_of(ccx, llty), ccx.int_type); - let align = C_i32(llalign_of_min(ccx, llty) as i32); + let size = IntCast(cx, machine::llsize_of(ccx, ty), ccx.int_type); + let align = C_i32(llalign_of_min(ccx, ty) as i32); let volatile = C_i1(false); Call(cx, llintrinsicfn, [llptr, llzeroval, size, align, volatile]); } pub fn alloc_ty(bcx: block, t: ty::t) -> ValueRef { - let _icx = bcx.insn_ctxt("alloc_ty"); + let _icx = push_ctxt("alloc_ty"); let ccx = bcx.ccx(); - let llty = type_of::type_of(ccx, t); - if ty::type_has_params(t) { debug!("%s", ty_to_str(ccx.tcx, t)); } - assert!(!ty::type_has_params(t)); - let val = alloca(bcx, llty); + let ty = type_of::type_of(ccx, t); + assert!(!ty::type_has_params(t), "Type has params: %s", ty_to_str(ccx.tcx, t)); + let val = alloca(bcx, ty); return val; } -pub fn alloca(cx: block, t: TypeRef) -> ValueRef { - alloca_maybe_zeroed(cx, t, false) +pub fn alloca(cx: block, ty: Type) -> ValueRef { + alloca_maybe_zeroed(cx, ty, false) } -pub fn alloca_maybe_zeroed(cx: block, t: TypeRef, zero: bool) -> ValueRef { - let _icx = cx.insn_ctxt("alloca"); +pub fn alloca_maybe_zeroed(cx: block, ty: Type, zero: bool) -> ValueRef { + let _icx = push_ctxt("alloca"); if cx.unreachable { unsafe { - return llvm::LLVMGetUndef(t); + return llvm::LLVMGetUndef(ty.to_ref()); } } let initcx = base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas); - let p = Alloca(initcx, t); - if zero { memzero(initcx, p, t); } - return p; + let p = Alloca(initcx, ty); + if zero { memzero(initcx, p, ty); } + p } -pub fn arrayalloca(cx: block, t: TypeRef, v: ValueRef) -> ValueRef { - let _icx = cx.insn_ctxt("arrayalloca"); +pub fn arrayalloca(cx: block, ty: Type, v: ValueRef) -> ValueRef { + let _icx = push_ctxt("arrayalloca"); if cx.unreachable { unsafe { - return llvm::LLVMGetUndef(t); + return llvm::LLVMGetUndef(ty.to_ref()); } } - return ArrayAlloca( - base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas), t, v); + return ArrayAlloca(base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas), ty, v); } pub struct BasicBlocks { @@ -1605,17 +1565,15 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, llfndecl: ValueRef, id: ast::node_id, output_type: ty::t, - impl_id: Option<ast::def_id>, param_substs: Option<@param_substs>, sp: Option<span>) -> fn_ctxt { for param_substs.iter().advance |p| { p.validate(); } - debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \ + debug!("new_fn_ctxt_w_id(path=%s, id=%?, \ param_substs=%s)", path_str(ccx.sess, path), id, - impl_id, param_substs.repr(ccx.tcx)); let llbbs = mk_standard_basic_blocks(llfndecl); @@ -1630,7 +1588,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, let fcx = @mut fn_ctxt_ { llfn: llfndecl, llenv: unsafe { - llvm::LLVMGetUndef(T_ptr(T_i8())) + llvm::LLVMGetUndef(Type::i8p().to_ref()) }, llretptr: None, llstaticallocas: llbbs.sa, @@ -1644,7 +1602,6 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, lllocals: @mut HashMap::new(), llupvars: @mut HashMap::new(), id: id, - impl_id: impl_id, param_substs: param_substs, span: sp, path: path, @@ -1653,7 +1610,9 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, fcx.llenv = unsafe { llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint) }; - fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type)); + if !ty::type_is_nil(substd_output_type) { + fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type)); + } fcx } @@ -1663,7 +1622,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext, output_type: ty::t, sp: Option<span>) -> fn_ctxt { - new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, None, sp) + new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, sp) } // NB: must keep 4 fns in sync: @@ -1684,21 +1643,14 @@ pub fn create_llargs_for_fn_args(cx: fn_ctxt, self_arg: self_arg, args: &[ast::arg]) -> ~[ValueRef] { - let _icx = cx.insn_ctxt("create_llargs_for_fn_args"); + let _icx = push_ctxt("create_llargs_for_fn_args"); match self_arg { - impl_self(tt) => { + impl_self(tt, self_mode) => { cx.llself = Some(ValSelfData { v: cx.llenv, t: tt, - is_owned: false - }); - } - impl_owned_self(tt) => { - cx.llself = Some(ValSelfData { - v: cx.llenv, - t: tt, - is_owned: true + is_copy: self_mode == ty::ByCopy }); } no_self => () @@ -1732,28 +1684,25 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, args: &[ast::arg], raw_llargs: &[ValueRef], arg_tys: &[ty::t]) -> block { - let _icx = fcx.insn_ctxt("copy_args_to_allocas"); + let _icx = push_ctxt("copy_args_to_allocas"); let mut bcx = bcx; match fcx.llself { - Some(slf) => { - // We really should do this regardless of whether self is owned, but - // it doesn't work right with default method impls yet. (FIXME: #2794) - if slf.is_owned { - let self_val = if datum::appropriate_mode(slf.t).is_by_value() { + Some(slf) => { + let self_val = if slf.is_copy + && datum::appropriate_mode(slf.t).is_by_value() { let tmp = BitCast(bcx, slf.v, type_of(bcx.ccx(), slf.t)); let alloc = alloc_ty(bcx, slf.t); Store(bcx, tmp, alloc); alloc } else { - PointerCast(bcx, slf.v, T_ptr(type_of(bcx.ccx(), slf.t))) + PointerCast(bcx, slf.v, type_of(bcx.ccx(), slf.t).ptr_to()) }; fcx.llself = Some(ValSelfData {v: self_val, ..slf}); add_clean(bcx, self_val, slf.t); } - } - _ => {} + _ => {} } for uint::range(0, arg_tys.len()) |arg_n| { @@ -1798,7 +1747,7 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, // Ties up the llstaticallocas -> llloadenv -> lltop edges, // and builds the return block. pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) { - let _icx = fcx.insn_ctxt("finish_fn"); + let _icx = push_ctxt("finish_fn"); tie_up_header_blocks(fcx, lltop); build_return_block(fcx); } @@ -1808,7 +1757,7 @@ pub fn build_return_block(fcx: fn_ctxt) { let ret_cx = raw_block(fcx, false, fcx.llreturn); // Return the value if this function immediate; otherwise, return void. - if fcx.has_immediate_return_value { + if fcx.llretptr.is_some() && fcx.has_immediate_return_value { Ret(ret_cx, Load(ret_cx, fcx.llretptr.get())) } else { RetVoid(ret_cx) @@ -1816,7 +1765,7 @@ pub fn build_return_block(fcx: fn_ctxt) { } pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) { - let _icx = fcx.insn_ctxt("tie_up_header_blocks"); + let _icx = push_ctxt("tie_up_header_blocks"); match fcx.llloadenv { Some(ll) => { Br(raw_block(fcx, false, fcx.llstaticallocas), ll); @@ -1828,7 +1777,7 @@ pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) { } } -pub enum self_arg { impl_self(ty::t), impl_owned_self(ty::t), no_self, } +pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, } // trans_closure: Builds an LLVM function out of a source function. // If the function closes over its environment a closure will be @@ -1841,13 +1790,12 @@ pub fn trans_closure(ccx: @mut CrateContext, self_arg: self_arg, param_substs: Option<@param_substs>, id: ast::node_id, - impl_id: Option<ast::def_id>, attributes: &[ast::attribute], output_type: ty::t, maybe_load_env: &fn(fn_ctxt), finish: &fn(block)) { ccx.stats.n_closures += 1; - let _icx = ccx.insn_ctxt("trans_closure"); + let _icx = push_ctxt("trans_closure"); set_uwtable(llfndecl); debug!("trans_closure(..., param_substs=%s)", @@ -1859,7 +1807,6 @@ pub fn trans_closure(ccx: @mut CrateContext, llfndecl, id, output_type, - impl_id, param_substs, Some(body.span)); let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs); @@ -1870,16 +1817,6 @@ pub fn trans_closure(ccx: @mut CrateContext, set_fixed_stack_segment(fcx.llfn); } - // Set GC for function. - if ccx.sess.opts.gc { - do str::as_c_str("generic") |strategy| { - unsafe { - llvm::LLVMSetGC(fcx.llfn, strategy); - } - } - ccx.uses_gc = true; - } - // Create the first basic block in the function and keep a handle on it to // pass to finish_fn later. let bcx_top = top_scope_block(fcx, body.info()); @@ -1928,7 +1865,6 @@ pub fn trans_fn(ccx: @mut CrateContext, self_arg: self_arg, param_substs: Option<@param_substs>, id: ast::node_id, - impl_id: Option<ast::def_id>, attrs: &[ast::attribute]) { let do_time = ccx.sess.trans_stats(); let start = if do_time { time::get_time() } @@ -1936,7 +1872,7 @@ pub fn trans_fn(ccx: @mut CrateContext, debug!("trans_fn(self_arg=%?, param_substs=%s)", self_arg, param_substs.repr(ccx.tcx)); - let _icx = ccx.insn_ctxt("trans_fn"); + let _icx = push_ctxt("trans_fn"); ccx.stats.n_fns += 1; let the_path_str = path_str(ccx.sess, path); let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id)); @@ -1948,7 +1884,6 @@ pub fn trans_fn(ccx: @mut CrateContext, self_arg, param_substs, id, - impl_id, attrs, output_type, |fcx| { @@ -1960,7 +1895,7 @@ pub fn trans_fn(ccx: @mut CrateContext, |_bcx| { }); if do_time { let end = time::get_time(); - log_fn_time(ccx, the_path_str, start, end); + ccx.log_fn_time(the_path_str, start, end); } } @@ -1971,7 +1906,7 @@ pub fn trans_enum_variant(ccx: @mut CrateContext, disr: int, param_substs: Option<@param_substs>, llfndecl: ValueRef) { - let _icx = ccx.insn_ctxt("trans_enum_variant"); + let _icx = push_ctxt("trans_enum_variant"); // Translate variant arguments to function arguments. let fn_args = do args.map |varg| { ast::arg { @@ -1998,7 +1933,6 @@ pub fn trans_enum_variant(ccx: @mut CrateContext, llfndecl, variant.node.id, enum_ty, - None, param_substs, None); @@ -2017,7 +1951,7 @@ pub fn trans_enum_variant(ccx: @mut CrateContext, repr, ty_to_str(ccx.tcx, enum_ty)); adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr); - for args.eachi |i, va| { + for args.iter().enumerate().advance |(i, va)| { let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr.get(), @@ -2045,7 +1979,7 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, ctor_id: ast::node_id, param_substs: Option<@param_substs>, llfndecl: ValueRef) { - let _icx = ccx.insn_ctxt("trans_tuple_struct"); + let _icx = push_ctxt("trans_tuple_struct"); // Translate struct fields to function arguments. let fn_args = do fields.map |field| { @@ -2078,7 +2012,6 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, llfndecl, ctor_id, tup_ty, - None, param_substs, None); @@ -2092,7 +2025,7 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, let repr = adt::represent_type(ccx, tup_ty); adt::trans_start_init(bcx, repr, fcx.llretptr.get(), 0); - for fields.eachi |i, field| { + for fields.iter().enumerate().advance |(i, field)| { let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr.get(), @@ -2110,7 +2043,7 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def, id: ast::node_id, vi: @~[ty::VariantInfo], i: &mut uint) { - for enum_definition.variants.each |variant| { + for enum_definition.variants.iter().advance |variant| { let disr_val = vi[*i].disr_val; *i += 1; @@ -2131,7 +2064,7 @@ pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def, } pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) { - let _icx = ccx.insn_ctxt("trans_item"); + let _icx = push_ctxt("trans_item"); let path = match ccx.tcx.items.get_copy(&item.id) { ast_map::node_item(_, p) => p, // tjc: ? @@ -2158,10 +2091,9 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) { no_self, None, item.id, - None, item.attrs); } else { - for body.node.stmts.each |stmt| { + for body.node.stmts.iter().advance |stmt| { match stmt.node { ast::stmt_decl(@codemap::spanned { node: ast::decl_item(i), _ }, _) => { @@ -2174,7 +2106,7 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) { } ast::item_impl(ref generics, _, _, ref ms) => { meth::trans_impl(ccx, /*bad*/copy *path, item.ident, *ms, - generics, None, item.id); + generics, item.id); } ast::item_mod(ref m) => { trans_mod(ccx, m); @@ -2186,14 +2118,19 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) { trans_enum_def(ccx, enum_definition, item.id, vi, &mut i); } } - ast::item_const(_, expr) => { - consts::trans_const(ccx, expr, item.id); + ast::item_static(_, m, expr) => { + consts::trans_const(ccx, m, item.id); // Do static_assert checking. It can't really be done much earlier because we need to get // the value of the bool out of LLVM - for item.attrs.each |attr| { + for item.attrs.iter().advance |attr| { match attr.node.value.node { ast::meta_word(x) => { if x.slice(0, x.len()) == "static_assert" { + if m == ast::m_mutbl { + ccx.sess.span_fatal(expr.span, + "cannot have static_assert \ + on a mutable static"); + } let v = ccx.const_values.get_copy(&item.id); unsafe { if !(llvm::LLVMConstIntGetZExtValue(v) as bool) { @@ -2238,8 +2175,8 @@ pub fn trans_struct_def(ccx: @mut CrateContext, struct_def: @ast::struct_def) { // only as a convenience for humans working with the code, to organize names // and control visibility. pub fn trans_mod(ccx: @mut CrateContext, m: &ast::_mod) { - let _icx = ccx.insn_ctxt("trans_mod"); - for m.items.each |item| { + let _icx = push_ctxt("trans_mod"); + for m.items.iter().advance |item| { trans_item(ccx, *item); } } @@ -2273,7 +2210,7 @@ pub fn register_fn_fuller(ccx: @mut CrateContext, attrs: &[ast::attribute], node_type: ty::t, cc: lib::llvm::CallConv, - llfty: TypeRef) + fn_ty: Type) -> ValueRef { debug!("register_fn_fuller creating fn for item %d with path %s", node_id, @@ -2285,12 +2222,11 @@ pub fn register_fn_fuller(ccx: @mut CrateContext, mangle_exported_name(ccx, /*bad*/copy path, node_type) }; - let llfn: ValueRef = decl_fn(ccx.llmod, ps, cc, llfty); + let llfn = decl_fn(ccx.llmod, ps, cc, fn_ty); ccx.item_symbols.insert(node_id, ps); // FIXME #4404 android JNI hacks - let is_entry = is_entry_fn(&ccx.sess, node_id) && - (!*ccx.sess.building_library || + let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library || (*ccx.sess.building_library && ccx.sess.targ_cfg.os == session::os_android)); if is_entry { @@ -2340,8 +2276,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, llvm::LLVMGetParam(llfdecl, env_arg as c_uint) }; let args = ~[llenvarg]; - let llresult = Call(bcx, main_llfn, args); - Store(bcx, llresult, fcx.llretptr.get()); + Call(bcx, main_llfn, args); build_return(bcx); finish_fn(fcx, lltop); @@ -2351,7 +2286,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, fn create_entry_fn(ccx: @mut CrateContext, rust_main: ValueRef, use_start_lang_item: bool) { - let llfty = T_fn([ccx.int_type, T_ptr(T_ptr(T_i8()))], ccx.int_type); + let llfty = Type::func([ccx.int_type, Type::i8().ptr_to().ptr_to()], &ccx.int_type); // FIXME #4404 android JNI hacks let llfn = if *ccx.sess.building_library { @@ -2380,10 +2315,9 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, } let crate_map = ccx.crate_map; - let opaque_crate_map = llvm::LLVMBuildPointerCast(bld, - crate_map, - T_ptr(T_i8()), - noname()); + let opaque_crate_map = do "crate_map".as_c_str |buf| { + llvm::LLVMBuildPointerCast(bld, crate_map, Type::i8p().to_ref(), buf) + }; let (start_fn, args) = if use_start_lang_item { let start_def_id = ccx.tcx.lang_items.start_fn(); @@ -2396,11 +2330,12 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, }; let args = { - let opaque_rust_main = llvm::LLVMBuildPointerCast( - bld, rust_main, T_ptr(T_i8()), noname()); + let opaque_rust_main = do "rust_main".as_c_str |buf| { + llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p().to_ref(), buf) + }; ~[ - C_null(T_opaque_box_ptr(ccx)), + C_null(Type::opaque_box(ccx).ptr_to()), opaque_rust_main, llvm::LLVMGetParam(llfn, 0), llvm::LLVMGetParam(llfn, 1), @@ -2412,7 +2347,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, debug!("using user-defined start fn"); let args = { ~[ - C_null(T_opaque_box_ptr(ccx)), + C_null(Type::opaque_box(ccx).ptr_to()), llvm::LLVMGetParam(llfn, 0 as c_uint), llvm::LLVMGetParam(llfn, 1 as c_uint), opaque_crate_map @@ -2438,11 +2373,11 @@ pub fn fill_fn_pair(bcx: block, pair: ValueRef, llfn: ValueRef, let code_cell = GEPi(bcx, pair, [0u, abi::fn_field_code]); Store(bcx, llfn, code_cell); let env_cell = GEPi(bcx, pair, [0u, abi::fn_field_box]); - let llenvblobptr = PointerCast(bcx, llenvptr, T_opaque_box_ptr(ccx)); + let llenvblobptr = PointerCast(bcx, llenvptr, Type::opaque_box(ccx).ptr_to()); Store(bcx, llenvblobptr, env_cell); } -pub fn item_path(ccx: &CrateContext, i: @ast::item) -> path { +pub fn item_path(ccx: &CrateContext, i: &ast::item) -> path { let base = match ccx.tcx.items.get_copy(&i.id) { ast_map::node_item(_, p) => p, // separate map for paths? @@ -2464,13 +2399,14 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef { let my_path = vec::append(/*bad*/copy *pth, [path_name(i.ident)]); match i.node { - ast::item_const(_, expr) => { + ast::item_static(_, m, expr) => { let typ = ty::node_id_to_type(ccx.tcx, i.id); let s = mangle_exported_name(ccx, my_path, typ); // We need the translated value here, because for enums the // LLVM type is not fully determined by the Rust type. let v = consts::const_expr(ccx, expr); ccx.const_values.insert(id, v); + exprt = m == ast::m_mutbl; unsafe { let llty = llvm::LLVMTypeOf(v); let g = str::as_c_str(s, |buf| { @@ -2510,7 +2446,6 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef { } } ast_map::node_method(m, _, pth) => { - exprt = true; register_method(ccx, id, pth, m) } ast_map::node_foreign_item(ni, _, _, pth) => { @@ -2523,13 +2458,13 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef { ni.id, ni.attrs) } - ast::foreign_item_const(*) => { + ast::foreign_item_static(*) => { let typ = ty::node_id_to_type(ccx.tcx, ni.id); let ident = token::ident_to_str(&ni.ident); let g = do str::as_c_str(ident) |buf| { unsafe { let ty = type_of(ccx, typ); - llvm::LLVMAddGlobal(ccx.llmod, ty, buf) + llvm::LLVMAddGlobal(ccx.llmod, ty.to_ref(), buf) } }; g @@ -2584,7 +2519,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef { variant)) } }; - if !(exprt || ccx.reachable.contains(&id)) { + if !exprt && !ccx.reachable.contains(&id) { lib::llvm::SetLinkage(val, lib::llvm::InternalLinkage); } ccx.item_vals.insert(id, val); @@ -2595,19 +2530,22 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef { pub fn register_method(ccx: @mut CrateContext, id: ast::node_id, - pth: @ast_map::path, + path: @ast_map::path, m: @ast::method) -> ValueRef { let mty = ty::node_id_to_type(ccx.tcx, id); - let pth = vec::append(/*bad*/copy *pth, [path_name((ccx.names)("meth")), - path_name(m.ident)]); - let llfn = register_fn_full(ccx, m.span, pth, id, m.attrs, mty); + + let mut path = /*bad*/ copy *path; + path.push(path_name(gensym_name("meth"))); + path.push(path_name(m.ident)); + + let llfn = register_fn_full(ccx, m.span, path, id, m.attrs, mty); set_inline_hint_if_appr(m.attrs, llfn); llfn } // The constant translation pass. -pub fn trans_constant(ccx: @mut CrateContext, it: @ast::item) { - let _icx = ccx.insn_ctxt("trans_constant"); +pub fn trans_constant(ccx: &mut CrateContext, it: @ast::item) { + let _icx = push_ctxt("trans_constant"); match it.node { ast::item_enum(ref enum_definition, _) => { let vi = ty::enum_variants(ccx.tcx, @@ -2615,7 +2553,7 @@ pub fn trans_constant(ccx: @mut CrateContext, it: @ast::item) { node: it.id }); let mut i = 0; let path = item_path(ccx, it); - for (*enum_definition).variants.each |variant| { + for (*enum_definition).variants.iter().advance |variant| { let p = vec::append(/*bad*/copy path, [ path_name(variant.node.name), path_name(special_idents::descrim) @@ -2625,7 +2563,7 @@ pub fn trans_constant(ccx: @mut CrateContext, it: @ast::item) { note_unique_llvm_symbol(ccx, s); let discrim_gvar = str::as_c_str(s, |buf| { unsafe { - llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf) + llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf) } }); unsafe { @@ -2658,219 +2596,102 @@ pub fn vp2i(cx: block, v: ValueRef) -> ValueRef { pub fn p2i(ccx: &CrateContext, v: ValueRef) -> ValueRef { unsafe { - return llvm::LLVMConstPtrToInt(v, ccx.int_type); + return llvm::LLVMConstPtrToInt(v, ccx.int_type.to_ref()); } } -pub fn declare_intrinsics(llmod: ModuleRef) -> HashMap<&'static str, ValueRef> { - let T_memcpy32_args: ~[TypeRef] = - ~[T_ptr(T_i8()), T_ptr(T_i8()), T_i32(), T_i32(), T_i1()]; - let T_memcpy64_args: ~[TypeRef] = - ~[T_ptr(T_i8()), T_ptr(T_i8()), T_i64(), T_i32(), T_i1()]; - let T_memset32_args: ~[TypeRef] = - ~[T_ptr(T_i8()), T_i8(), T_i32(), T_i32(), T_i1()]; - let T_memset64_args: ~[TypeRef] = - ~[T_ptr(T_i8()), T_i8(), T_i64(), T_i32(), T_i1()]; - let T_trap_args: ~[TypeRef] = ~[]; - let T_frameaddress_args: ~[TypeRef] = ~[T_i32()]; - let gcroot = - decl_cdecl_fn(llmod, "llvm.gcroot", - T_fn([T_ptr(T_ptr(T_i8())), T_ptr(T_i8())], - T_void())); - let gcread = - decl_cdecl_fn(llmod, "llvm.gcread", - T_fn([T_ptr(T_i8()), T_ptr(T_ptr(T_i8()))], - T_void())); - let memcpy32 = - decl_cdecl_fn(llmod, "llvm.memcpy.p0i8.p0i8.i32", - T_fn(T_memcpy32_args, T_void())); - let memcpy64 = - decl_cdecl_fn(llmod, "llvm.memcpy.p0i8.p0i8.i64", - T_fn(T_memcpy64_args, T_void())); - let memmove32 = - decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i32", - T_fn(T_memcpy32_args, T_void())); - let memmove64 = - decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i64", - T_fn(T_memcpy64_args, T_void())); - let memset32 = - decl_cdecl_fn(llmod, "llvm.memset.p0i8.i32", - T_fn(T_memset32_args, T_void())); - let memset64 = - decl_cdecl_fn(llmod, "llvm.memset.p0i8.i64", - T_fn(T_memset64_args, T_void())); - let trap = decl_cdecl_fn(llmod, "llvm.trap", T_fn(T_trap_args, - T_void())); - let frameaddress = decl_cdecl_fn(llmod, "llvm.frameaddress", - T_fn(T_frameaddress_args, - T_ptr(T_i8()))); - let sqrtf32 = decl_cdecl_fn(llmod, "llvm.sqrt.f32", - T_fn([T_f32()], T_f32())); - let sqrtf64 = decl_cdecl_fn(llmod, "llvm.sqrt.f64", - T_fn([T_f64()], T_f64())); - let powif32 = decl_cdecl_fn(llmod, "llvm.powi.f32", - T_fn([T_f32(), T_i32()], T_f32())); - let powif64 = decl_cdecl_fn(llmod, "llvm.powi.f64", - T_fn([T_f64(), T_i32()], T_f64())); - let sinf32 = decl_cdecl_fn(llmod, "llvm.sin.f32", - T_fn([T_f32()], T_f32())); - let sinf64 = decl_cdecl_fn(llmod, "llvm.sin.f64", - T_fn([T_f64()], T_f64())); - let cosf32 = decl_cdecl_fn(llmod, "llvm.cos.f32", - T_fn([T_f32()], T_f32())); - let cosf64 = decl_cdecl_fn(llmod, "llvm.cos.f64", - T_fn([T_f64()], T_f64())); - let powf32 = decl_cdecl_fn(llmod, "llvm.pow.f32", - T_fn([T_f32(), T_f32()], T_f32())); - let powf64 = decl_cdecl_fn(llmod, "llvm.pow.f64", - T_fn([T_f64(), T_f64()], T_f64())); - let expf32 = decl_cdecl_fn(llmod, "llvm.exp.f32", - T_fn([T_f32()], T_f32())); - let expf64 = decl_cdecl_fn(llmod, "llvm.exp.f64", - T_fn([T_f64()], T_f64())); - let exp2f32 = decl_cdecl_fn(llmod, "llvm.exp2.f32", - T_fn([T_f32()], T_f32())); - let exp2f64 = decl_cdecl_fn(llmod, "llvm.exp2.f64", - T_fn([T_f64()], T_f64())); - let logf32 = decl_cdecl_fn(llmod, "llvm.log.f32", - T_fn([T_f32()], T_f32())); - let logf64 = decl_cdecl_fn(llmod, "llvm.log.f64", - T_fn([T_f64()], T_f64())); - let log10f32 = decl_cdecl_fn(llmod, "llvm.log10.f32", - T_fn([T_f32()], T_f32())); - let log10f64 = decl_cdecl_fn(llmod, "llvm.log10.f64", - T_fn([T_f64()], T_f64())); - let log2f32 = decl_cdecl_fn(llmod, "llvm.log2.f32", - T_fn([T_f32()], T_f32())); - let log2f64 = decl_cdecl_fn(llmod, "llvm.log2.f64", - T_fn([T_f64()], T_f64())); - let fmaf32 = decl_cdecl_fn(llmod, "llvm.fma.f32", - T_fn([T_f32(), T_f32(), T_f32()], T_f32())); - let fmaf64 = decl_cdecl_fn(llmod, "llvm.fma.f64", - T_fn([T_f64(), T_f64(), T_f64()], T_f64())); - let fabsf32 = decl_cdecl_fn(llmod, "llvm.fabs.f32", - T_fn([T_f32()], T_f32())); - let fabsf64 = decl_cdecl_fn(llmod, "llvm.fabs.f64", - T_fn([T_f64()], T_f64())); - let floorf32 = decl_cdecl_fn(llmod, "llvm.floor.f32", - T_fn([T_f32()], T_f32())); - let floorf64 = decl_cdecl_fn(llmod, "llvm.floor.f64", - T_fn([T_f64()], T_f64())); - let ceilf32 = decl_cdecl_fn(llmod, "llvm.ceil.f32", - T_fn([T_f32()], T_f32())); - let ceilf64 = decl_cdecl_fn(llmod, "llvm.ceil.f64", - T_fn([T_f64()], T_f64())); - let truncf32 = decl_cdecl_fn(llmod, "llvm.trunc.f32", - T_fn([T_f32()], T_f32())); - let truncf64 = decl_cdecl_fn(llmod, "llvm.trunc.f64", - T_fn([T_f64()], T_f64())); - let ctpop8 = decl_cdecl_fn(llmod, "llvm.ctpop.i8", - T_fn([T_i8()], T_i8())); - let ctpop16 = decl_cdecl_fn(llmod, "llvm.ctpop.i16", - T_fn([T_i16()], T_i16())); - let ctpop32 = decl_cdecl_fn(llmod, "llvm.ctpop.i32", - T_fn([T_i32()], T_i32())); - let ctpop64 = decl_cdecl_fn(llmod, "llvm.ctpop.i64", - T_fn([T_i64()], T_i64())); - let ctlz8 = decl_cdecl_fn(llmod, "llvm.ctlz.i8", - T_fn([T_i8(), T_i1()], T_i8())); - let ctlz16 = decl_cdecl_fn(llmod, "llvm.ctlz.i16", - T_fn([T_i16(), T_i1()], T_i16())); - let ctlz32 = decl_cdecl_fn(llmod, "llvm.ctlz.i32", - T_fn([T_i32(), T_i1()], T_i32())); - let ctlz64 = decl_cdecl_fn(llmod, "llvm.ctlz.i64", - T_fn([T_i64(), T_i1()], T_i64())); - let cttz8 = decl_cdecl_fn(llmod, "llvm.cttz.i8", - T_fn([T_i8(), T_i1()], T_i8())); - let cttz16 = decl_cdecl_fn(llmod, "llvm.cttz.i16", - T_fn([T_i16(), T_i1()], T_i16())); - let cttz32 = decl_cdecl_fn(llmod, "llvm.cttz.i32", - T_fn([T_i32(), T_i1()], T_i32())); - let cttz64 = decl_cdecl_fn(llmod, "llvm.cttz.i64", - T_fn([T_i64(), T_i1()], T_i64())); - let bswap16 = decl_cdecl_fn(llmod, "llvm.bswap.i16", - T_fn([T_i16()], T_i16())); - let bswap32 = decl_cdecl_fn(llmod, "llvm.bswap.i32", - T_fn([T_i32()], T_i32())); - let bswap64 = decl_cdecl_fn(llmod, "llvm.bswap.i64", - T_fn([T_i64()], T_i64())); +macro_rules! ifn ( + ($name:expr, $args:expr, $ret:expr) => ({ + let name = $name; + let f = decl_cdecl_fn(llmod, name, Type::func($args, &$ret)); + intrinsics.insert(name, f); + }) +) +pub fn declare_intrinsics(llmod: ModuleRef) -> HashMap<&'static str, ValueRef> { + let i8p = Type::i8p(); let mut intrinsics = HashMap::new(); - intrinsics.insert("llvm.gcroot", gcroot); - intrinsics.insert("llvm.gcread", gcread); - intrinsics.insert("llvm.memcpy.p0i8.p0i8.i32", memcpy32); - intrinsics.insert("llvm.memcpy.p0i8.p0i8.i64", memcpy64); - intrinsics.insert("llvm.memmove.p0i8.p0i8.i32", memmove32); - intrinsics.insert("llvm.memmove.p0i8.p0i8.i64", memmove64); - intrinsics.insert("llvm.memset.p0i8.i32", memset32); - intrinsics.insert("llvm.memset.p0i8.i64", memset64); - intrinsics.insert("llvm.trap", trap); - intrinsics.insert("llvm.frameaddress", frameaddress); - intrinsics.insert("llvm.sqrt.f32", sqrtf32); - intrinsics.insert("llvm.sqrt.f64", sqrtf64); - intrinsics.insert("llvm.powi.f32", powif32); - intrinsics.insert("llvm.powi.f64", powif64); - intrinsics.insert("llvm.sin.f32", sinf32); - intrinsics.insert("llvm.sin.f64", sinf64); - intrinsics.insert("llvm.cos.f32", cosf32); - intrinsics.insert("llvm.cos.f64", cosf64); - intrinsics.insert("llvm.pow.f32", powf32); - intrinsics.insert("llvm.pow.f64", powf64); - intrinsics.insert("llvm.exp.f32", expf32); - intrinsics.insert("llvm.exp.f64", expf64); - intrinsics.insert("llvm.exp2.f32", exp2f32); - intrinsics.insert("llvm.exp2.f64", exp2f64); - intrinsics.insert("llvm.log.f32", logf32); - intrinsics.insert("llvm.log.f64", logf64); - intrinsics.insert("llvm.log10.f32", log10f32); - intrinsics.insert("llvm.log10.f64", log10f64); - intrinsics.insert("llvm.log2.f32", log2f32); - intrinsics.insert("llvm.log2.f64", log2f64); - intrinsics.insert("llvm.fma.f32", fmaf32); - intrinsics.insert("llvm.fma.f64", fmaf64); - intrinsics.insert("llvm.fabs.f32", fabsf32); - intrinsics.insert("llvm.fabs.f64", fabsf64); - intrinsics.insert("llvm.floor.f32", floorf32); - intrinsics.insert("llvm.floor.f64", floorf64); - intrinsics.insert("llvm.ceil.f32", ceilf32); - intrinsics.insert("llvm.ceil.f64", ceilf64); - intrinsics.insert("llvm.trunc.f32", truncf32); - intrinsics.insert("llvm.trunc.f64", truncf64); - intrinsics.insert("llvm.ctpop.i8", ctpop8); - intrinsics.insert("llvm.ctpop.i16", ctpop16); - intrinsics.insert("llvm.ctpop.i32", ctpop32); - intrinsics.insert("llvm.ctpop.i64", ctpop64); - intrinsics.insert("llvm.ctlz.i8", ctlz8); - intrinsics.insert("llvm.ctlz.i16", ctlz16); - intrinsics.insert("llvm.ctlz.i32", ctlz32); - intrinsics.insert("llvm.ctlz.i64", ctlz64); - intrinsics.insert("llvm.cttz.i8", cttz8); - intrinsics.insert("llvm.cttz.i16", cttz16); - intrinsics.insert("llvm.cttz.i32", cttz32); - intrinsics.insert("llvm.cttz.i64", cttz64); - intrinsics.insert("llvm.bswap.i16", bswap16); - intrinsics.insert("llvm.bswap.i32", bswap32); - intrinsics.insert("llvm.bswap.i64", bswap64); + + ifn!("llvm.memcpy.p0i8.p0i8.i32", + [i8p, i8p, Type::i32(), Type::i32(), Type::i1()], Type::void()); + ifn!("llvm.memcpy.p0i8.p0i8.i64", + [i8p, i8p, Type::i64(), Type::i32(), Type::i1()], Type::void()); + ifn!("llvm.memmove.p0i8.p0i8.i32", + [i8p, i8p, Type::i32(), Type::i32(), Type::i1()], Type::void()); + ifn!("llvm.memmove.p0i8.p0i8.i64", + [i8p, i8p, Type::i64(), Type::i32(), Type::i1()], Type::void()); + ifn!("llvm.memset.p0i8.i32", + [i8p, Type::i8(), Type::i32(), Type::i32(), Type::i1()], Type::void()); + ifn!("llvm.memset.p0i8.i64", + [i8p, Type::i8(), Type::i64(), Type::i32(), Type::i1()], Type::void()); + + ifn!("llvm.trap", [], Type::void()); + ifn!("llvm.frameaddress", [Type::i32()], i8p); + + ifn!("llvm.powi.f32", [Type::f32(), Type::i32()], Type::f32()); + ifn!("llvm.powi.f64", [Type::f64(), Type::i32()], Type::f64()); + ifn!("llvm.pow.f32", [Type::f32(), Type::f32()], Type::f32()); + ifn!("llvm.pow.f64", [Type::f64(), Type::f64()], Type::f64()); + + ifn!("llvm.sqrt.f32", [Type::f32()], Type::f32()); + ifn!("llvm.sqrt.f64", [Type::f64()], Type::f64()); + ifn!("llvm.sin.f32", [Type::f32()], Type::f32()); + ifn!("llvm.sin.f64", [Type::f64()], Type::f64()); + ifn!("llvm.cos.f32", [Type::f32()], Type::f32()); + ifn!("llvm.cos.f64", [Type::f64()], Type::f64()); + ifn!("llvm.exp.f32", [Type::f32()], Type::f32()); + ifn!("llvm.exp.f64", [Type::f64()], Type::f64()); + ifn!("llvm.exp2.f32", [Type::f32()], Type::f32()); + ifn!("llvm.exp2.f64", [Type::f64()], Type::f64()); + ifn!("llvm.log.f32", [Type::f32()], Type::f32()); + ifn!("llvm.log.f64", [Type::f64()], Type::f64()); + ifn!("llvm.log10.f32",[Type::f32()], Type::f32()); + ifn!("llvm.log10.f64",[Type::f64()], Type::f64()); + ifn!("llvm.log2.f32", [Type::f32()], Type::f32()); + ifn!("llvm.log2.f64", [Type::f64()], Type::f64()); + + ifn!("llvm.fma.f32", [Type::f32(), Type::f32(), Type::f32()], Type::f32()); + ifn!("llvm.fma.f64", [Type::f64(), Type::f64(), Type::f64()], Type::f64()); + + ifn!("llvm.fabs.f32", [Type::f32()], Type::f32()); + ifn!("llvm.fabs.f64", [Type::f64()], Type::f64()); + ifn!("llvm.floor.f32",[Type::f32()], Type::f32()); + ifn!("llvm.floor.f64",[Type::f64()], Type::f64()); + ifn!("llvm.ceil.f32", [Type::f32()], Type::f32()); + ifn!("llvm.ceil.f64", [Type::f64()], Type::f64()); + ifn!("llvm.trunc.f32",[Type::f32()], Type::f32()); + ifn!("llvm.trunc.f64",[Type::f64()], Type::f64()); + + ifn!("llvm.ctpop.i8", [Type::i8()], Type::i8()); + ifn!("llvm.ctpop.i16",[Type::i16()], Type::i16()); + ifn!("llvm.ctpop.i32",[Type::i32()], Type::i32()); + ifn!("llvm.ctpop.i64",[Type::i64()], Type::i64()); + + ifn!("llvm.ctlz.i8", [Type::i8() , Type::i1()], Type::i8()); + ifn!("llvm.ctlz.i16", [Type::i16(), Type::i1()], Type::i16()); + ifn!("llvm.ctlz.i32", [Type::i32(), Type::i1()], Type::i32()); + ifn!("llvm.ctlz.i64", [Type::i64(), Type::i1()], Type::i64()); + + ifn!("llvm.cttz.i8", [Type::i8() , Type::i1()], Type::i8()); + ifn!("llvm.cttz.i16", [Type::i16(), Type::i1()], Type::i16()); + ifn!("llvm.cttz.i32", [Type::i32(), Type::i1()], Type::i32()); + ifn!("llvm.cttz.i64", [Type::i64(), Type::i1()], Type::i64()); + + ifn!("llvm.bswap.i16",[Type::i16()], Type::i16()); + ifn!("llvm.bswap.i32",[Type::i32()], Type::i32()); + ifn!("llvm.bswap.i64",[Type::i64()], Type::i64()); return intrinsics; } -pub fn declare_dbg_intrinsics(llmod: ModuleRef, - intrinsics: &mut HashMap<&'static str, ValueRef>) { - let declare = - decl_cdecl_fn(llmod, "llvm.dbg.declare", - T_fn([T_metadata(), T_metadata()], T_void())); - let value = - decl_cdecl_fn(llmod, "llvm.dbg.value", - T_fn([T_metadata(), T_i64(), T_metadata()], T_void())); - intrinsics.insert("llvm.dbg.declare", declare); - intrinsics.insert("llvm.dbg.value", value); +pub fn declare_dbg_intrinsics(llmod: ModuleRef, intrinsics: &mut HashMap<&'static str, ValueRef>) { + ifn!("llvm.dbg.declare", [Type::metadata(), Type::metadata()], Type::void()); + ifn!("llvm.dbg.value", [Type::metadata(), Type::i64(), Type::metadata()], Type::void()); } pub fn trap(bcx: block) { - let v: ~[ValueRef] = ~[]; - match bcx.ccx().intrinsics.find(& &"llvm.trap") { - Some(&x) => { Call(bcx, x, v); }, + match bcx.ccx().intrinsics.find_equiv(& &"llvm.trap") { + Some(&x) => { Call(bcx, x, []); }, _ => bcx.sess().bug("unbound llvm.trap in trap") } } @@ -2883,7 +2704,7 @@ pub fn decl_gc_metadata(ccx: &mut CrateContext, llmod_id: &str) { let gc_metadata_name = ~"_gc_module_metadata_" + llmod_id; let gc_metadata = do str::as_c_str(gc_metadata_name) |buf| { unsafe { - llvm::LLVMAddGlobal(ccx.llmod, T_i32(), buf) + llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf) } }; unsafe { @@ -2894,13 +2715,13 @@ pub fn decl_gc_metadata(ccx: &mut CrateContext, llmod_id: &str) { } pub fn create_module_map(ccx: &mut CrateContext) -> ValueRef { - let elttype = T_struct([ccx.int_type, ccx.int_type], false); - let maptype = T_array(elttype, ccx.module_data.len() + 1); - let map = str::as_c_str("_rust_mod_map", |buf| { + let elttype = Type::struct_([ccx.int_type, ccx.int_type], false); + let maptype = Type::array(&elttype, (ccx.module_data.len() + 1) as u64); + let map = do "_rust_mod_map".as_c_str |buf| { unsafe { - llvm::LLVMAddGlobal(ccx.llmod, maptype, buf) + llvm::LLVMAddGlobal(ccx.llmod, maptype.to_ref(), buf) } - }); + }; lib::llvm::SetLinkage(map, lib::llvm::InternalLinkage); let mut elts: ~[ValueRef] = ~[]; @@ -2912,7 +2733,7 @@ pub fn create_module_map(ccx: &mut CrateContext) -> ValueRef { keys.push(k.to_managed()); } - for keys.each |key| { + for keys.iter().advance |key| { let val = *ccx.module_data.find_equiv(key).get(); let s_const = C_cstr(ccx, *key); let s_ptr = p2i(ccx, s_const); @@ -2932,7 +2753,7 @@ pub fn create_module_map(ccx: &mut CrateContext) -> ValueRef { pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta, llmod: ModuleRef) -> ValueRef { let targ_cfg = sess.targ_cfg; - let int_type = T_int(targ_cfg); + let int_type = Type::int(targ_cfg.arch); let mut n_subcrates = 1; let cstore = sess.cstore; while cstore::have_crate_data(cstore, n_subcrates) { n_subcrates += 1; } @@ -2942,11 +2763,11 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta, ~"toplevel" }; let sym_name = ~"_rust_crate_map_" + mapname; - let arrtype = T_array(int_type, n_subcrates as uint); - let maptype = T_struct([T_i32(), T_ptr(T_i8()), int_type, arrtype], false); + let arrtype = Type::array(&int_type, n_subcrates as u64); + let maptype = Type::struct_([Type::i32(), Type::i8p(), int_type, arrtype], false); let map = str::as_c_str(sym_name, |buf| { unsafe { - llvm::LLVMAddGlobal(llmod, maptype, buf) + llvm::LLVMAddGlobal(llmod, maptype.to_ref(), buf) } }); lib::llvm::SetLinkage(map, lib::llvm::ExternalLinkage); @@ -2965,7 +2786,7 @@ pub fn fill_crate_map(ccx: @mut CrateContext, map: ValueRef) { cstore::get_crate_hash(cstore, i)); let cr = str::as_c_str(nm, |buf| { unsafe { - llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf) + llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf) } }); subcrates.push(p2i(ccx, cr)); @@ -2989,8 +2810,7 @@ pub fn fill_crate_map(ccx: @mut CrateContext, map: ValueRef) { let mod_map = create_module_map(ccx); llvm::LLVMSetInitializer(map, C_struct( [C_i32(1), - lib::llvm::llvm::LLVMConstPointerCast(llannihilatefn, - T_ptr(T_i8())), + lib::llvm::llvm::LLVMConstPointerCast(llannihilatefn, Type::i8p().to_ref()), p2i(ccx, mod_map), C_array(ccx.int_type, subcrates)])); } @@ -3006,13 +2826,13 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::encode_ encoder::EncodeParams { diag: diag, tcx: cx.tcx, - reachable: cx.reachable, reexports2: cx.exp_map2, item_symbols: item_symbols, discrim_symbols: discrim_symbols, link_meta: link_meta, cstore: cx.sess.cstore, - encode_inlined_item: ie + encode_inlined_item: ie, + reachable: cx.reachable, } } @@ -3028,7 +2848,7 @@ pub fn write_metadata(cx: &mut CrateContext, crate: &ast::crate) { let llconst = C_struct([llmeta]); let mut llglobal = str::as_c_str("rust_metadata", |buf| { unsafe { - llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst), buf) + llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst).to_ref(), buf) } }); unsafe { @@ -3038,37 +2858,56 @@ pub fn write_metadata(cx: &mut CrateContext, crate: &ast::crate) { }); lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage); - let t_ptr_i8 = T_ptr(T_i8()); - llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8); - let llvm_used = str::as_c_str("llvm.used", |buf| { - llvm::LLVMAddGlobal(cx.llmod, T_array(t_ptr_i8, 1u), buf) - }); + let t_ptr_i8 = Type::i8p(); + llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8.to_ref()); + let llvm_used = do "llvm.used".as_c_str |buf| { + llvm::LLVMAddGlobal(cx.llmod, Type::array(&t_ptr_i8, 1).to_ref(), buf) + }; lib::llvm::SetLinkage(llvm_used, lib::llvm::AppendingLinkage); llvm::LLVMSetInitializer(llvm_used, C_array(t_ptr_i8, [llglobal])); } } +fn mk_global(ccx: &CrateContext, + name: &str, + llval: ValueRef, + internal: bool) + -> ValueRef { + unsafe { + let llglobal = do str::as_c_str(name) |buf| { + llvm::LLVMAddGlobal(ccx.llmod, val_ty(llval).to_ref(), buf) + }; + llvm::LLVMSetInitializer(llglobal, llval); + llvm::LLVMSetGlobalConstant(llglobal, True); + + if internal { + lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage); + } + + return llglobal; + } +} + // Writes the current ABI version into the crate. pub fn write_abi_version(ccx: &mut CrateContext) { - mk_global(ccx, "rust_abi_version", C_uint(ccx, abi::abi_version), - false); + mk_global(ccx, "rust_abi_version", C_uint(ccx, abi::abi_version), false); } pub fn trans_crate(sess: session::Session, - crate: @ast::crate, + crate: &ast::crate, tcx: ty::ctxt, output: &Path, emap2: resolve::ExportMap2, - maps: astencode::Maps) -> (ContextRef, ModuleRef, LinkMeta) { + reachable_map: @mut HashSet<ast::node_id>, + maps: astencode::Maps) + -> (ContextRef, ModuleRef, LinkMeta) { + // Before we touch LLVM, make sure that multithreading is enabled. + if unsafe { !llvm::LLVMRustStartMultithreading() } { + sess.bug("couldn't enable multi-threaded LLVM"); + } let mut symbol_hasher = hash::default_state(); let link_meta = link::build_link_meta(sess, crate, output, &mut symbol_hasher); - let reachable = reachable::find_reachable( - &crate.node.module, - emap2, - tcx, - maps.method_map - ); // Append ".rc" to crate name as LLVM module identifier. // @@ -3080,27 +2919,22 @@ pub fn trans_crate(sess: session::Session, // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 let llmod_id = link_meta.name.to_owned() + ".rc"; - // FIXME(#6511): get LLVM building with --enable-threads so this - // function can be called - // if !llvm::LLVMRustStartMultithreading() { - // sess.bug("couldn't enable multi-threaded LLVM"); - // } - - let ccx = @mut CrateContext::new(sess, llmod_id, tcx, emap2, maps, - symbol_hasher, link_meta, reachable); - // FIXME(#6511): get LLVM building with --enable-threads so this - // function can be called - // if !llvm::LLVMRustStartMultithreading() { - // sess.bug("couldn't enable multi-threaded LLVM"); - // } + let ccx = @mut CrateContext::new(sess, + llmod_id, + tcx, + emap2, + maps, + symbol_hasher, + link_meta, + reachable_map); { - let _icx = ccx.insn_ctxt("data"); + let _icx = push_ctxt("data"); trans_constants(ccx, crate); } { - let _icx = ccx.insn_ctxt("text"); + let _icx = push_ctxt("text"); trans_mod(ccx, &crate.node.module); } @@ -3130,10 +2964,11 @@ pub fn trans_crate(sess: session::Session, } if ccx.sess.count_llvm_insns() { - for ccx.stats.llvm_insns.each |&k, &v| { + for ccx.stats.llvm_insns.iter().advance |(&k, &v)| { io::println(fmt!("%-7u %s", v, k)); } } + let llcx = ccx.llcx; let link_meta = ccx.link_meta; let llmod = ccx.llmod; diff --git a/src/librustc/middle/trans/block.rs b/src/librustc/middle/trans/block.rs deleted file mode 100644 index e69de29bb2d..00000000000 --- a/src/librustc/middle/trans/block.rs +++ /dev/null diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index a55e89747f5..8535c84c5cb 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -8,22 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use lib::llvm::llvm; use lib::llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect}; use lib::llvm::{Opcode, IntPredicate, RealPredicate, False}; -use lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, ModuleRef}; +use lib::llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef}; use lib; use middle::trans::common::*; use middle::trans::machine::llalign_of_min; use syntax::codemap::span; -use core::cast; -use core::hashmap::HashMap; -use core::libc::{c_uint, c_ulonglong, c_char}; -use core::str; -use core::vec; +use middle::trans::base; +use middle::trans::type_::Type; + +use std::cast; +use std::libc::{c_uint, c_ulonglong, c_char}; +use std::hashmap::HashMap; +use std::str; +use std::vec; pub fn terminate(cx: block, _: &str) { cx.terminated = true; @@ -44,10 +46,8 @@ pub fn B(cx: block) -> BuilderRef { } pub fn count_insn(cx: block, category: &str) { - if cx.ccx().sess.count_llvm_insns() { - + do base::with_insn_ctxt |v| { let h = &mut cx.ccx().stats.llvm_insns; - let v : &[~str] = cx.ccx().stats.llvm_insn_ctxt; // Build version of path with cycles removed. @@ -67,13 +67,13 @@ pub fn count_insn(cx: block, category: &str) { i = 0u; while i < len { i = *mm.get(&v[i]); - s += "/"; - s += v[i]; + s.push_char('/'); + s.push_str(v[i]); i += 1u; } - s += "/"; - s += category; + s.push_char('/'); + s.push_str(category); let n = match h.find(&s) { Some(&n) => n, @@ -186,13 +186,13 @@ pub fn Invoke(cx: block, Catch: BasicBlockRef) -> ValueRef { if cx.unreachable { - return C_null(T_i8()); + return C_null(Type::i8()); } check_not_terminated(cx); terminate(cx, "Invoke"); debug!("Invoke(%s with arguments (%s))", - val_str(cx.ccx().tn, Fn), - Args.map(|a| val_str(cx.ccx().tn, *a).to_owned()).connect(", ")); + cx.val_to_str(Fn), + Args.map(|a| cx.val_to_str(*a)).connect(", ")); unsafe { count_insn(cx, "invoke"); llvm::LLVMBuildInvoke(B(cx), @@ -232,7 +232,7 @@ pub fn Unreachable(cx: block) { pub fn _Undef(val: ValueRef) -> ValueRef { unsafe { - return llvm::LLVMGetUndef(val_ty(val)); + return llvm::LLVMGetUndef(val_ty(val).to_ref()); } } @@ -486,35 +486,35 @@ pub fn Not(cx: block, V: ValueRef) -> ValueRef { } /* Memory */ -pub fn Malloc(cx: block, Ty: TypeRef) -> ValueRef { +pub fn Malloc(cx: block, Ty: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); } count_insn(cx, "malloc"); - return llvm::LLVMBuildMalloc(B(cx), Ty, noname()); + return llvm::LLVMBuildMalloc(B(cx), Ty.to_ref(), noname()); } } -pub fn ArrayMalloc(cx: block, Ty: TypeRef, Val: ValueRef) -> ValueRef { +pub fn ArrayMalloc(cx: block, Ty: Type, Val: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); } count_insn(cx, "arraymalloc"); - return llvm::LLVMBuildArrayMalloc(B(cx), Ty, Val, noname()); + return llvm::LLVMBuildArrayMalloc(B(cx), Ty.to_ref(), Val, noname()); } } -pub fn Alloca(cx: block, Ty: TypeRef) -> ValueRef { +pub fn Alloca(cx: block, Ty: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(Ty)); } + if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); } count_insn(cx, "alloca"); - return llvm::LLVMBuildAlloca(B(cx), Ty, noname()); + return llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), noname()); } } -pub fn ArrayAlloca(cx: block, Ty: TypeRef, Val: ValueRef) -> ValueRef { +pub fn ArrayAlloca(cx: block, Ty: Type, Val: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(Ty)); } + if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); } count_insn(cx, "arrayalloca"); - return llvm::LLVMBuildArrayAlloca(B(cx), Ty, Val, noname()); + return llvm::LLVMBuildArrayAlloca(B(cx), Ty.to_ref(), Val, noname()); } } @@ -531,9 +531,12 @@ pub fn Load(cx: block, PointerVal: ValueRef) -> ValueRef { let ccx = cx.fcx.ccx; if cx.unreachable { let ty = val_ty(PointerVal); - let eltty = if llvm::LLVMGetTypeKind(ty) == lib::llvm::Array { - llvm::LLVMGetElementType(ty) } else { ccx.int_type }; - return llvm::LLVMGetUndef(eltty); + let eltty = if ty.kind() == lib::llvm::Array { + ty.element_type() + } else { + ccx.int_type + }; + return llvm::LLVMGetUndef(eltty.to_ref()); } count_insn(cx, "load"); return llvm::LLVMBuildLoad(B(cx), PointerVal, noname()); @@ -544,7 +547,7 @@ pub fn AtomicLoad(cx: block, PointerVal: ValueRef, order: AtomicOrdering) -> Val unsafe { let ccx = cx.fcx.ccx; if cx.unreachable { - return llvm::LLVMGetUndef(ccx.int_type); + return llvm::LLVMGetUndef(ccx.int_type.to_ref()); } count_insn(cx, "load.atomic"); let align = llalign_of_min(ccx, ccx.int_type); @@ -576,8 +579,8 @@ pub fn Store(cx: block, Val: ValueRef, Ptr: ValueRef) { unsafe { if cx.unreachable { return; } debug!("Store %s -> %s", - val_str(cx.ccx().tn, Val), - val_str(cx.ccx().tn, Ptr)); + cx.val_to_str(Val), + cx.val_to_str(Ptr)); count_insn(cx, "store"); llvm::LLVMBuildStore(B(cx), Val, Ptr); } @@ -587,8 +590,8 @@ pub fn AtomicStore(cx: block, Val: ValueRef, Ptr: ValueRef, order: AtomicOrderin unsafe { if cx.unreachable { return; } debug!("Store %s -> %s", - val_str(cx.ccx().tn, Val), - val_str(cx.ccx().tn, Ptr)); + cx.val_to_str(Val), + cx.val_to_str(Ptr)); count_insn(cx, "store.atomic"); let align = llalign_of_min(cx.ccx(), cx.ccx().int_type); llvm::LLVMBuildAtomicStore(B(cx), Val, Ptr, order, align as c_uint); @@ -597,7 +600,7 @@ pub fn AtomicStore(cx: block, Val: ValueRef, Ptr: ValueRef, order: AtomicOrderin pub fn GEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_nil())); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); } count_insn(cx, "gep"); return llvm::LLVMBuildGEP(B(cx), Pointer, vec::raw::to_ptr(Indices), Indices.len() as c_uint, noname()); @@ -606,29 +609,35 @@ pub fn GEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef { // Simple wrapper around GEP that takes an array of ints and wraps them // in C_i32() -// -// FIXME #6571: Use a small-vector optimization to avoid allocations here. +#[inline] pub fn GEPi(cx: block, base: ValueRef, ixs: &[uint]) -> ValueRef { - let v = do vec::map(ixs) |i| { C_i32(*i as i32) }; - count_insn(cx, "gepi"); - return InBoundsGEP(cx, base, v); + // Small vector optimization. This should catch 100% of the cases that + // we care about. + if ixs.len() < 16 { + let mut small_vec = [ C_i32(0), ..16 ]; + for small_vec.mut_iter().zip(ixs.iter()).advance |(small_vec_e, &ix)| { + *small_vec_e = C_i32(ix as i32); + } + InBoundsGEP(cx, base, small_vec.slice(0, ixs.len())) + } else { + let v = do ixs.iter().transform |i| { C_i32(*i as i32) }.collect::<~[ValueRef]>(); + count_insn(cx, "gepi"); + InBoundsGEP(cx, base, v) + } } -pub fn InBoundsGEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> - ValueRef { +pub fn InBoundsGEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_nil())); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); } count_insn(cx, "inboundsgep"); - return llvm::LLVMBuildInBoundsGEP(B(cx), Pointer, - vec::raw::to_ptr(Indices), - Indices.len() as c_uint, - noname()); + return llvm::LLVMBuildInBoundsGEP( + B(cx), Pointer, vec::raw::to_ptr(Indices), Indices.len() as c_uint, noname()); } } pub fn StructGEP(cx: block, Pointer: ValueRef, Idx: uint) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_nil())); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); } count_insn(cx, "structgep"); return llvm::LLVMBuildStructGEP(B(cx), Pointer, @@ -639,7 +648,7 @@ pub fn StructGEP(cx: block, Pointer: ValueRef, Idx: uint) -> ValueRef { pub fn GlobalString(cx: block, _Str: *c_char) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); } count_insn(cx, "globalstring"); return llvm::LLVMBuildGlobalString(B(cx), _Str, noname()); } @@ -647,163 +656,163 @@ pub fn GlobalString(cx: block, _Str: *c_char) -> ValueRef { pub fn GlobalStringPtr(cx: block, _Str: *c_char) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_ptr(T_i8())); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); } count_insn(cx, "globalstringptr"); return llvm::LLVMBuildGlobalStringPtr(B(cx), _Str, noname()); } } /* Casts */ -pub fn Trunc(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn Trunc(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "trunc"); - return llvm::LLVMBuildTrunc(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildTrunc(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn ZExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn ZExt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "zext"); - return llvm::LLVMBuildZExt(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildZExt(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn SExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn SExt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "sext"); - return llvm::LLVMBuildSExt(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildSExt(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn FPToUI(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn FPToUI(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "fptoui"); - return llvm::LLVMBuildFPToUI(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildFPToUI(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn FPToSI(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn FPToSI(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "fptosi"); - return llvm::LLVMBuildFPToSI(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildFPToSI(B(cx), Val, DestTy.to_ref(),noname()); } } -pub fn UIToFP(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn UIToFP(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "uitofp"); - return llvm::LLVMBuildUIToFP(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildUIToFP(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn SIToFP(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn SIToFP(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "sitofp"); - return llvm::LLVMBuildSIToFP(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildSIToFP(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn FPTrunc(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn FPTrunc(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "fptrunc"); - return llvm::LLVMBuildFPTrunc(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildFPTrunc(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn FPExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn FPExt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "fpext"); - return llvm::LLVMBuildFPExt(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildFPExt(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn PtrToInt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn PtrToInt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "ptrtoint"); - return llvm::LLVMBuildPtrToInt(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildPtrToInt(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn IntToPtr(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn IntToPtr(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "inttoptr"); - return llvm::LLVMBuildIntToPtr(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildIntToPtr(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn BitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn BitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "bitcast"); - return llvm::LLVMBuildBitCast(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildBitCast(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn ZExtOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn ZExtOrBitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "zextorbitcast"); - return llvm::LLVMBuildZExtOrBitCast(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildZExtOrBitCast(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn SExtOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn SExtOrBitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "sextorbitcast"); - return llvm::LLVMBuildSExtOrBitCast(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildSExtOrBitCast(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn TruncOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn TruncOrBitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "truncorbitcast"); - return llvm::LLVMBuildTruncOrBitCast(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildTruncOrBitCast(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn Cast(cx: block, Op: Opcode, Val: ValueRef, DestTy: TypeRef, _: *u8) +pub fn Cast(cx: block, Op: Opcode, Val: ValueRef, DestTy: Type, _: *u8) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } count_insn(cx, "cast"); - return llvm::LLVMBuildCast(B(cx), Op, Val, DestTy, noname()); + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } + return llvm::LLVMBuildCast(B(cx), Op, Val, DestTy.to_ref(), noname()); } } -pub fn PointerCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn PointerCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "pointercast"); - return llvm::LLVMBuildPointerCast(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildPointerCast(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn IntCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn IntCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "intcast"); - return llvm::LLVMBuildIntCast(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildIntCast(B(cx), Val, DestTy.to_ref(), noname()); } } -pub fn FPCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { +pub fn FPCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(DestTy); } + if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); } count_insn(cx, "fpcast"); - return llvm::LLVMBuildFPCast(B(cx), Val, DestTy, noname()); + return llvm::LLVMBuildFPCast(B(cx), Val, DestTy.to_ref(), noname()); } } @@ -812,7 +821,7 @@ pub fn FPCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { pub fn ICmp(cx: block, Op: IntPredicate, LHS: ValueRef, RHS: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_i1()); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); } count_insn(cx, "icmp"); return llvm::LLVMBuildICmp(B(cx), Op as c_uint, LHS, RHS, noname()); } @@ -821,25 +830,25 @@ pub fn ICmp(cx: block, Op: IntPredicate, LHS: ValueRef, RHS: ValueRef) pub fn FCmp(cx: block, Op: RealPredicate, LHS: ValueRef, RHS: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_i1()); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); } count_insn(cx, "fcmp"); return llvm::LLVMBuildFCmp(B(cx), Op as c_uint, LHS, RHS, noname()); } } /* Miscellaneous instructions */ -pub fn EmptyPhi(cx: block, Ty: TypeRef) -> ValueRef { +pub fn EmptyPhi(cx: block, Ty: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(Ty); } + if cx.unreachable { return llvm::LLVMGetUndef(Ty.to_ref()); } count_insn(cx, "emptyphi"); - return llvm::LLVMBuildPhi(B(cx), Ty, noname()); + return llvm::LLVMBuildPhi(B(cx), Ty.to_ref(), noname()); } } -pub fn Phi(cx: block, Ty: TypeRef, vals: &[ValueRef], bbs: &[BasicBlockRef]) +pub fn Phi(cx: block, Ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(Ty); } + if cx.unreachable { return llvm::LLVMGetUndef(Ty.to_ref()); } assert_eq!(vals.len(), bbs.len()); let phi = EmptyPhi(cx, Ty); count_insn(cx, "addincoming"); @@ -863,10 +872,13 @@ pub fn _UndefReturn(cx: block, Fn: ValueRef) -> ValueRef { unsafe { let ccx = cx.fcx.ccx; let ty = val_ty(Fn); - let retty = if llvm::LLVMGetTypeKind(ty) == lib::llvm::Integer { - llvm::LLVMGetReturnType(ty) } else { ccx.int_type }; - count_insn(cx, ""); - return llvm::LLVMGetUndef(retty); + let retty = if ty.kind() == lib::llvm::Integer { + ty.return_type() + } else { + ccx.int_type + }; + count_insn(cx, "ret_undef"); + return llvm::LLVMGetUndef(retty.to_ref()); } } @@ -886,20 +898,18 @@ pub fn add_comment(bcx: block, text: &str) { let sanitized = text.replace("$", ""); let comment_text = ~"# " + sanitized.replace("\n", "\n\t# "); - let asm = str::as_c_str(comment_text, |c| { - str::as_c_str("", |e| { - count_insn(bcx, "inlineasm"); - llvm::LLVMConstInlineAsm(T_fn([], T_void()), c, e, - False, False) - }) - }); + count_insn(bcx, "inlineasm"); + let asm = do comment_text.as_c_str |c| { + llvm::LLVMConstInlineAsm(Type::func([], &Type::void()).to_ref(), + c, noname(), False, False) + }; Call(bcx, asm, []); } } } pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char, - inputs: &[ValueRef], output: TypeRef, + inputs: &[ValueRef], output: Type, volatile: bool, alignstack: bool, dia: AsmDialect) -> ValueRef { unsafe { @@ -911,14 +921,13 @@ pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char, else { lib::llvm::False }; let argtys = do inputs.map |v| { - debug!("Asm Input Type: %?", val_str(cx.ccx().tn, *v)); + debug!("Asm Input Type: %?", cx.val_to_str(*v)); val_ty(*v) }; - debug!("Asm Output Type: %?", ty_str(cx.ccx().tn, output)); - let llfty = T_fn(argtys, output); - let v = llvm::LLVMInlineAsm(llfty, asm, cons, volatile, - alignstack, dia as c_uint); + debug!("Asm Output Type: %?", cx.ccx().tn.type_to_str(output)); + let fty = Type::func(argtys, &output); + let v = llvm::LLVMInlineAsm(fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint); Call(cx, v, inputs) } @@ -930,8 +939,8 @@ pub fn Call(cx: block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef { count_insn(cx, "call"); debug!("Call(Fn=%s, Args=%?)", - val_str(cx.ccx().tn, Fn), - Args.map(|arg| val_str(cx.ccx().tn, *arg))); + cx.val_to_str(Fn), + Args.map(|arg| cx.val_to_str(*arg))); do vec::as_imm_buf(Args) |ptr, len| { llvm::LLVMBuildCall(B(cx), Fn, ptr, len as c_uint, noname()) @@ -971,18 +980,18 @@ pub fn Select(cx: block, If: ValueRef, Then: ValueRef, Else: ValueRef) -> } } -pub fn VAArg(cx: block, list: ValueRef, Ty: TypeRef) -> ValueRef { +pub fn VAArg(cx: block, list: ValueRef, Ty: Type) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(Ty); } + if cx.unreachable { return llvm::LLVMGetUndef(Ty.to_ref()); } count_insn(cx, "vaarg"); - return llvm::LLVMBuildVAArg(B(cx), list, Ty, noname()); + return llvm::LLVMBuildVAArg(B(cx), list, Ty.to_ref(), noname()); } } pub fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); } count_insn(cx, "extractelement"); return llvm::LLVMBuildExtractElement(B(cx), VecVal, Index, noname()); } @@ -991,7 +1000,7 @@ pub fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) -> pub fn InsertElement(cx: block, VecVal: ValueRef, EltVal: ValueRef, Index: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); } count_insn(cx, "insertelement"); llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname()) } @@ -1000,7 +1009,7 @@ pub fn InsertElement(cx: block, VecVal: ValueRef, EltVal: ValueRef, pub fn ShuffleVector(cx: block, V1: ValueRef, V2: ValueRef, Mask: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); } count_insn(cx, "shufflevector"); llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname()) } @@ -1008,15 +1017,16 @@ pub fn ShuffleVector(cx: block, V1: ValueRef, V2: ValueRef, pub fn VectorSplat(cx: block, NumElts: uint, EltVal: ValueRef) -> ValueRef { unsafe { - let Undef = llvm::LLVMGetUndef(T_vector(val_ty(EltVal), NumElts)); + let elt_ty = val_ty(EltVal); + let Undef = llvm::LLVMGetUndef(Type::vector(&elt_ty, NumElts as u64).to_ref()); let VecVal = InsertElement(cx, Undef, EltVal, C_i32(0)); - ShuffleVector(cx, VecVal, Undef, C_null(T_vector(T_i32(), NumElts))) + ShuffleVector(cx, VecVal, Undef, C_null(Type::vector(&Type::i32(), NumElts as u64))) } } pub fn ExtractValue(cx: block, AggVal: ValueRef, Index: uint) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); } count_insn(cx, "extractvalue"); return llvm::LLVMBuildExtractValue( B(cx), AggVal, Index as c_uint, noname()); @@ -1035,7 +1045,7 @@ pub fn InsertValue(cx: block, AggVal: ValueRef, EltVal: ValueRef, pub fn IsNull(cx: block, Val: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_i1()); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); } count_insn(cx, "isnull"); return llvm::LLVMBuildIsNull(B(cx), Val, noname()); } @@ -1043,7 +1053,7 @@ pub fn IsNull(cx: block, Val: ValueRef) -> ValueRef { pub fn IsNotNull(cx: block, Val: ValueRef) -> ValueRef { unsafe { - if cx.unreachable { return llvm::LLVMGetUndef(T_i1()); } + if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); } count_insn(cx, "isnotnull"); return llvm::LLVMBuildIsNotNull(B(cx), Val, noname()); } @@ -1052,7 +1062,7 @@ pub fn IsNotNull(cx: block, Val: ValueRef) -> ValueRef { pub fn PtrDiff(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { unsafe { let ccx = cx.fcx.ccx; - if cx.unreachable { return llvm::LLVMGetUndef(ccx.int_type); } + if cx.unreachable { return llvm::LLVMGetUndef(ccx.int_type.to_ref()); } count_insn(cx, "ptrdiff"); return llvm::LLVMBuildPtrDiff(B(cx), LHS, RHS, noname()); } @@ -1071,19 +1081,18 @@ pub fn Trap(cx: block) { assert!((T as int != 0)); let Args: ~[ValueRef] = ~[]; count_insn(cx, "trap"); - llvm::LLVMBuildCall(b, T, vec::raw::to_ptr(Args), - Args.len() as c_uint, noname()); + llvm::LLVMBuildCall(b, T, vec::raw::to_ptr(Args), Args.len() as c_uint, noname()); } } -pub fn LandingPad(cx: block, Ty: TypeRef, PersFn: ValueRef, +pub fn LandingPad(cx: block, Ty: Type, PersFn: ValueRef, NumClauses: uint) -> ValueRef { unsafe { check_not_terminated(cx); assert!(!cx.unreachable); count_insn(cx, "landingpad"); - return llvm::LLVMBuildLandingPad(B(cx), Ty, PersFn, - NumClauses as c_uint, noname()); + return llvm::LLVMBuildLandingPad( + B(cx), Ty.to_ref(), PersFn, NumClauses as c_uint, noname()); } } diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs index acc3293f267..d0047919430 100644 --- a/src/librustc/middle/trans/cabi.rs +++ b/src/librustc/middle/trans/cabi.rs @@ -8,25 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use lib::llvm::{llvm, TypeRef, ValueRef, Attribute, Void}; +use lib::llvm::{llvm, ValueRef, Attribute, Void}; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::common::*; -use core::libc::c_uint; -use core::option; -use core::vec; +use middle::trans::type_::Type; + +use std::libc::c_uint; +use std::option; pub trait ABIInfo { - fn compute_info(&self, - atys: &[TypeRef], - rty: TypeRef, - ret_def: bool) -> FnType; + fn compute_info(&self, atys: &[Type], rty: Type, ret_def: bool) -> FnType; } pub struct LLVMType { cast: bool, - ty: TypeRef + ty: Type } pub struct FnType { @@ -37,13 +35,13 @@ pub struct FnType { } impl FnType { - pub fn decl_fn(&self, decl: &fn(fnty: TypeRef) -> ValueRef) -> ValueRef { - let atys = vec::map(self.arg_tys, |t| t.ty); + pub fn decl_fn(&self, decl: &fn(fnty: Type) -> ValueRef) -> ValueRef { + let atys = self.arg_tys.iter().transform(|t| t.ty).collect::<~[Type]>(); let rty = self.ret_ty.ty; - let fnty = T_fn(atys, rty); + let fnty = Type::func(atys, &rty); let llfn = decl(fnty); - for vec::eachi(self.attrs) |i, a| { + for self.attrs.iter().enumerate().advance |(i, a)| { match *a { option::Some(attr) => { unsafe { @@ -57,10 +55,7 @@ impl FnType { return llfn; } - pub fn build_shim_args(&self, - bcx: block, - arg_tys: &[TypeRef], - llargbundle: ValueRef) + pub fn build_shim_args(&self, bcx: block, arg_tys: &[Type], llargbundle: ValueRef) -> ~[ValueRef] { let mut atys: &[LLVMType] = self.arg_tys; let mut attrs: &[option::Option<Attribute>] = self.attrs; @@ -80,7 +75,7 @@ impl FnType { while i < n { let llargval = if atys[i].cast { let arg_ptr = GEPi(bcx, llargbundle, [0u, i]); - let arg_ptr = BitCast(bcx, arg_ptr, T_ptr(atys[i].ty)); + let arg_ptr = BitCast(bcx, arg_ptr, atys[i].ty.ptr_to()); Load(bcx, arg_ptr) } else if attrs[i].is_some() { GEPi(bcx, llargbundle, [0u, i]) @@ -94,19 +89,13 @@ impl FnType { return llargvals; } - pub fn build_shim_ret(&self, - bcx: block, - arg_tys: &[TypeRef], - ret_def: bool, - llargbundle: ValueRef, - llretval: ValueRef) { - for vec::eachi(self.attrs) |i, a| { + pub fn build_shim_ret(&self, bcx: block, arg_tys: &[Type], ret_def: bool, + llargbundle: ValueRef, llretval: ValueRef) { + for self.attrs.iter().enumerate().advance |(i, a)| { match *a { option::Some(attr) => { unsafe { - llvm::LLVMAddInstrAttribute(llretval, - (i + 1u) as c_uint, - attr as c_uint); + llvm::LLVMAddInstrAttribute(llretval, (i + 1u) as c_uint, attr as c_uint); } } _ => () @@ -121,7 +110,7 @@ impl FnType { // R* llretloc = *llretptr; /* (args->r) */ let llretloc = Load(bcx, llretptr); if self.ret_ty.cast { - let tmp_ptr = BitCast(bcx, llretloc, T_ptr(self.ret_ty.ty)); + let tmp_ptr = BitCast(bcx, llretloc, self.ret_ty.ty.ptr_to()); // *args->r = r; Store(bcx, llretval, tmp_ptr); } else { @@ -130,11 +119,8 @@ impl FnType { }; } - pub fn build_wrap_args(&self, - bcx: block, - ret_ty: TypeRef, - llwrapfn: ValueRef, - llargbundle: ValueRef) { + pub fn build_wrap_args(&self, bcx: block, ret_ty: Type, + llwrapfn: ValueRef, llargbundle: ValueRef) { let mut atys: &[LLVMType] = self.arg_tys; let mut attrs: &[option::Option<Attribute>] = self.attrs; let mut j = 0u; @@ -145,7 +131,7 @@ impl FnType { get_param(llwrapfn, 0u) } else if self.ret_ty.cast { let retptr = alloca(bcx, self.ret_ty.ty); - BitCast(bcx, retptr, T_ptr(ret_ty)) + BitCast(bcx, retptr, ret_ty.ptr_to()) } else { alloca(bcx, ret_ty) }; @@ -159,7 +145,7 @@ impl FnType { store_inbounds(bcx, argval, llargbundle, [0u, i]); } else if atys[i].cast { let argptr = GEPi(bcx, llargbundle, [0u, i]); - let argptr = BitCast(bcx, argptr, T_ptr(atys[i].ty)); + let argptr = BitCast(bcx, argptr, atys[i].ty.ptr_to()); Store(bcx, argval, argptr); } else { store_inbounds(bcx, argval, llargbundle, [0u, i]); @@ -169,26 +155,21 @@ impl FnType { store_inbounds(bcx, llretptr, llargbundle, [0u, n]); } - pub fn build_wrap_ret(&self, - bcx: block, - arg_tys: &[TypeRef], - llargbundle: ValueRef) { - unsafe { - if llvm::LLVMGetTypeKind(self.ret_ty.ty) == Void { - return; - } + pub fn build_wrap_ret(&self, bcx: block, arg_tys: &[Type], llargbundle: ValueRef) { + if self.ret_ty.ty.kind() == Void { + return; } - let llretval = load_inbounds(bcx, llargbundle, [ 0, arg_tys.len() ]); - let llretval = if self.ret_ty.cast { - let retptr = BitCast(bcx, llretval, T_ptr(self.ret_ty.ty)); - Load(bcx, retptr) - } else { - Load(bcx, llretval) - }; - let llretptr = BitCast(bcx, - bcx.fcx.llretptr.get(), - T_ptr(self.ret_ty.ty)); - Store(bcx, llretval, llretptr); + if bcx.fcx.llretptr.is_some() { + let llretval = load_inbounds(bcx, llargbundle, [ 0, arg_tys.len() ]); + let llretval = if self.ret_ty.cast { + let retptr = BitCast(bcx, llretval, self.ret_ty.ty.ptr_to()); + Load(bcx, retptr) + } else { + Load(bcx, llretval) + }; + let llretptr = BitCast(bcx, bcx.fcx.llretptr.get(), self.ret_ty.ty.ptr_to()); + Store(bcx, llretval, llretptr); + } } } diff --git a/src/librustc/middle/trans/cabi_arm.rs b/src/librustc/middle/trans/cabi_arm.rs index 9ad66c06671..7eac2df10b6 100644 --- a/src/librustc/middle/trans/cabi_arm.rs +++ b/src/librustc/middle/trans/cabi_arm.rs @@ -9,123 +9,118 @@ // except according to those terms. use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array}; -use lib::llvm::struct_tys; -use lib::llvm::TypeRef; use lib::llvm::{Attribute, StructRetAttribute}; -use lib::llvm::True; use middle::trans::cabi::{ABIInfo, FnType, LLVMType}; -use middle::trans::common::{T_i8, T_i16, T_i32, T_i64}; -use middle::trans::common::{T_array, T_ptr, T_void}; -use core::option::{Option, None, Some}; -use core::uint; +use middle::trans::type_::Type; + +use std::option::{Option, None, Some}; +use std::uint; fn align_up_to(off: uint, a: uint) -> uint { return (off + a - 1u) / a * a; } -fn align(off: uint, ty: TypeRef) -> uint { +fn align(off: uint, ty: Type) -> uint { let a = ty_align(ty); return align_up_to(off, a); } -fn ty_align(ty: TypeRef) -> uint { - unsafe { - return match llvm::LLVMGetTypeKind(ty) { - Integer => { - ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 - } - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if llvm::LLVMIsPackedStruct(ty) == True { - 1 - } else { - let str_tys = struct_tys(ty); - str_tys.iter().fold(1, |a, t| uint::max(a, ty_align(*t))) - } +fn ty_align(ty: Type) -> uint { + match ty.kind() { + Integer => { + unsafe { + ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 } - Array => { - let elt = llvm::LLVMGetElementType(ty); - ty_align(elt) + } + Pointer => 4, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + 1 + } else { + let str_tys = ty.field_types(); + str_tys.iter().fold(1, |a, t| uint::max(a, ty_align(*t))) } - _ => fail!("ty_align: unhandled type") - }; + } + Array => { + let elt = ty.element_type(); + ty_align(elt) + } + _ => fail!("ty_align: unhandled type") } } -fn ty_size(ty: TypeRef) -> uint { - unsafe { - return match llvm::LLVMGetTypeKind(ty) { - Integer => { - ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 - } - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if llvm::LLVMIsPackedStruct(ty) == True { - let str_tys = struct_tys(ty); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let str_tys = struct_tys(ty); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } +fn ty_size(ty: Type) -> uint { + match ty.kind() { + Integer => { + unsafe { + ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 } - Array => { - let len = llvm::LLVMGetArrayLength(ty) as uint; - let elt = llvm::LLVMGetElementType(ty); - let eltsz = ty_size(elt); - len * eltsz + } + Pointer => 4, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + let str_tys = ty.field_types(); + str_tys.iter().fold(0, |s, t| s + ty_size(*t)) + } else { + let str_tys = ty.field_types(); + let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); + align(size, ty) } - _ => fail!("ty_size: unhandled type") - }; + } + Array => { + let len = ty.array_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + _ => fail!("ty_size: unhandled type") } } -fn classify_ret_ty(ty: TypeRef) -> (LLVMType, Option<Attribute>) { +fn classify_ret_ty(ty: Type) -> (LLVMType, Option<Attribute>) { if is_reg_ty(ty) { return (LLVMType { cast: false, ty: ty }, None); } let size = ty_size(ty); if size <= 4 { let llty = if size <= 1 { - T_i8() + Type::i8() } else if size <= 2 { - T_i16() + Type::i16() } else { - T_i32() + Type::i32() }; return (LLVMType { cast: true, ty: llty }, None); } - (LLVMType { cast: false, ty: T_ptr(ty) }, Some(StructRetAttribute)) + (LLVMType { cast: false, ty: ty.ptr_to() }, Some(StructRetAttribute)) } -fn classify_arg_ty(ty: TypeRef) -> (LLVMType, Option<Attribute>) { +fn classify_arg_ty(ty: Type) -> (LLVMType, Option<Attribute>) { if is_reg_ty(ty) { return (LLVMType { cast: false, ty: ty }, None); } let align = ty_align(ty); let size = ty_size(ty); let llty = if align <= 4 { - T_array(T_i32(), (size + 3) / 4) + Type::array(&Type::i32(), (size + 3) / 4 as u64) } else { - T_array(T_i64(), (size + 7) / 8) + Type::array(&Type::i64(), (size + 7) / 8 as u64) }; (LLVMType { cast: true, ty: llty }, None) } -fn is_reg_ty(ty: TypeRef) -> bool { - unsafe { - return match llvm::LLVMGetTypeKind(ty) { - Integer - | Pointer - | Float - | Double => true, - _ => false - }; +fn is_reg_ty(ty: Type) -> bool { + match ty.kind() { + Integer + | Pointer + | Float + | Double => true, + _ => false } } @@ -133,28 +128,30 @@ enum ARM_ABIInfo { ARM_ABIInfo } impl ABIInfo for ARM_ABIInfo { fn compute_info(&self, - atys: &[TypeRef], - rty: TypeRef, + atys: &[Type], + rty: Type, ret_def: bool) -> FnType { let mut arg_tys = ~[]; let mut attrs = ~[]; - for atys.each |&aty| { + for atys.iter().advance |&aty| { let (ty, attr) = classify_arg_ty(aty); arg_tys.push(ty); attrs.push(attr); } - let mut (ret_ty, ret_attr) = if ret_def { + let (ret_ty, ret_attr) = if ret_def { classify_ret_ty(rty) } else { - (LLVMType { cast: false, ty: T_void() }, None) + (LLVMType { cast: false, ty: Type::void() }, None) }; + let mut ret_ty = ret_ty; + let sret = ret_attr.is_some(); if sret { arg_tys.unshift(ret_ty); attrs.unshift(ret_attr); - ret_ty = LLVMType { cast: false, ty: T_void() }; + ret_ty = LLVMType { cast: false, ty: Type::void() }; } return FnType { diff --git a/src/librustc/middle/trans/cabi_mips.rs b/src/librustc/middle/trans/cabi_mips.rs index 0c771d21da5..c95ae994ceb 100644 --- a/src/librustc/middle/trans/cabi_mips.rs +++ b/src/librustc/middle/trans/cabi_mips.rs @@ -8,107 +8,91 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - -use core::libc::c_uint; -use core::ptr; -use core::uint; -use core::vec; -use lib::llvm::{llvm, TypeRef, Integer, Pointer, Float, Double}; -use lib::llvm::{Struct, Array, Attribute}; -use lib::llvm::{StructRetAttribute}; -use lib::llvm::True; + +use std::libc::c_uint; +use std::uint; +use std::vec; +use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array}; +use lib::llvm::{Attribute, StructRetAttribute}; use middle::trans::context::task_llcx; -use middle::trans::common::*; use middle::trans::cabi::*; +use middle::trans::type_::Type; + fn align_up_to(off: uint, a: uint) -> uint { return (off + a - 1u) / a * a; } -fn align(off: uint, ty: TypeRef) -> uint { +fn align(off: uint, ty: Type) -> uint { let a = ty_align(ty); return align_up_to(off, a); } -fn struct_tys(ty: TypeRef) -> ~[TypeRef] { - unsafe { - let n = llvm::LLVMCountStructElementTypes(ty); - if (n == 0) { - return ~[]; - } - let mut elts = vec::from_elem(n as uint, ptr::null()); - llvm::LLVMGetStructElementTypes(ty, &mut elts[0]); - return elts; - } -} - -fn ty_align(ty: TypeRef) -> uint { - unsafe { - return match llvm::LLVMGetTypeKind(ty) { - Integer => { - ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 +fn ty_align(ty: Type) -> uint { + match ty.kind() { + Integer => { + unsafe { + ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 } - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if llvm::LLVMIsPackedStruct(ty) == True { - 1 - } else { - let str_tys = struct_tys(ty); - str_tys.iter().fold(1, |a, t| uint::max(a, ty_align(*t))) - } - } - Array => { - let elt = llvm::LLVMGetElementType(ty); - ty_align(elt) - } - _ => fail!("ty_size: unhandled type") - }; + } + Pointer => 4, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + 1 + } else { + let str_tys = ty.field_types(); + str_tys.iter().fold(1, |a, t| uint::max(a, ty_align(*t))) + } + } + Array => { + let elt = ty.element_type(); + ty_align(elt) + } + _ => fail!("ty_size: unhandled type") } } -fn ty_size(ty: TypeRef) -> uint { - unsafe { - return match llvm::LLVMGetTypeKind(ty) { - Integer => { - ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 - } - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if llvm::LLVMIsPackedStruct(ty) == True { - let str_tys = struct_tys(ty); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let str_tys = struct_tys(ty); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } +fn ty_size(ty: Type) -> uint { + match ty.kind() { + Integer => { + unsafe { + ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 } - Array => { - let len = llvm::LLVMGetArrayLength(ty) as uint; - let elt = llvm::LLVMGetElementType(ty); - let eltsz = ty_size(elt); - len * eltsz + } + Pointer => 4, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + let str_tys = ty.field_types(); + str_tys.iter().fold(0, |s, t| s + ty_size(*t)) + } else { + let str_tys = ty.field_types(); + let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); + align(size, ty) } - _ => fail!("ty_size: unhandled type") - }; + } + Array => { + let len = ty.array_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + _ => fail!("ty_size: unhandled type") } } -fn classify_ret_ty(ty: TypeRef) -> (LLVMType, Option<Attribute>) { +fn classify_ret_ty(ty: Type) -> (LLVMType, Option<Attribute>) { return if is_reg_ty(ty) { (LLVMType { cast: false, ty: ty }, None) } else { - (LLVMType { cast: false, ty: T_ptr(ty) }, Some(StructRetAttribute)) + (LLVMType { cast: false, ty: ty.ptr_to() }, Some(StructRetAttribute)) }; } -fn classify_arg_ty(ty: TypeRef, - offset: &mut uint) -> (LLVMType, Option<Attribute>) { +fn classify_arg_ty(ty: Type, offset: &mut uint) -> (LLVMType, Option<Attribute>) { let orig_offset = *offset; let size = ty_size(ty) * 8; let mut align = ty_align(ty); @@ -133,28 +117,26 @@ fn classify_arg_ty(ty: TypeRef, }; } -fn is_reg_ty(ty: TypeRef) -> bool { - unsafe { - return match llvm::LLVMGetTypeKind(ty) { - Integer - | Pointer - | Float - | Double => true, - _ => false - }; - } +fn is_reg_ty(ty: Type) -> bool { + return match ty.kind() { + Integer + | Pointer + | Float + | Double => true, + _ => false + }; } -fn padding_ty(align: uint, offset: uint) -> Option<TypeRef> { +fn padding_ty(align: uint, offset: uint) -> Option<Type> { if ((align - 1 ) & offset) > 0 { - return Some(T_i32()); + return Some(Type::i32()); } return None; } -fn coerce_to_int(size: uint) -> ~[TypeRef] { - let int_ty = T_i32(); +fn coerce_to_int(size: uint) -> ~[Type] { + let int_ty = Type::i32(); let mut args = ~[]; let mut n = size / 32; @@ -166,16 +148,16 @@ fn coerce_to_int(size: uint) -> ~[TypeRef] { let r = size % 32; if r > 0 { unsafe { - args.push(llvm::LLVMIntTypeInContext(task_llcx(), r as c_uint)) + args.push(Type::from_ref(llvm::LLVMIntTypeInContext(task_llcx(), r as c_uint))); } } - return args; + args } -fn struct_ty(ty: TypeRef, - padding: Option<TypeRef>, - coerce: bool) -> TypeRef { +fn struct_ty(ty: Type, + padding: Option<Type>, + coerce: bool) -> Type { let size = ty_size(ty) * 8; let mut fields = padding.map_default(~[], |p| ~[*p]); @@ -185,28 +167,30 @@ fn struct_ty(ty: TypeRef, fields.push(ty); } - return T_struct(fields, false); + return Type::struct_(fields, false); } enum MIPS_ABIInfo { MIPS_ABIInfo } impl ABIInfo for MIPS_ABIInfo { fn compute_info(&self, - atys: &[TypeRef], - rty: TypeRef, + atys: &[Type], + rty: Type, ret_def: bool) -> FnType { - let mut (ret_ty, ret_attr) = if ret_def { + let (ret_ty, ret_attr) = if ret_def { classify_ret_ty(rty) } else { - (LLVMType { cast: false, ty: T_void() }, None) + (LLVMType { cast: false, ty: Type::void() }, None) }; + let mut ret_ty = ret_ty; + let sret = ret_attr.is_some(); let mut arg_tys = ~[]; let mut attrs = ~[]; let mut offset = if sret { 4 } else { 0 }; - for atys.each() |aty| { + for atys.iter().advance |aty| { let (ty, attr) = classify_arg_ty(*aty, &mut offset); arg_tys.push(ty); attrs.push(attr); @@ -215,7 +199,7 @@ impl ABIInfo for MIPS_ABIInfo { if sret { arg_tys = vec::append(~[ret_ty], arg_tys); attrs = vec::append(~[ret_attr], attrs); - ret_ty = LLVMType { cast: false, ty: T_void() }; + ret_ty = LLVMType { cast: false, ty: Type::void() }; } return FnType { diff --git a/src/librustc/middle/trans/cabi_x86.rs b/src/librustc/middle/trans/cabi_x86.rs index 53af55bca6c..8c5a2e70484 100644 --- a/src/librustc/middle/trans/cabi_x86.rs +++ b/src/librustc/middle/trans/cabi_x86.rs @@ -8,23 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use driver::session::{os_win32, os_macos}; use lib::llvm::*; -use lib::llvm::llvm::*; use super::cabi::*; use super::common::*; use super::machine::*; +use middle::trans::type_::Type; + struct X86_ABIInfo { ccx: @mut CrateContext } impl ABIInfo for X86_ABIInfo { fn compute_info(&self, - atys: &[TypeRef], - rty: TypeRef, + atys: &[Type], + rty: Type, ret_def: bool) -> FnType { let mut arg_tys = do atys.map |a| { LLVMType { cast: false, ty: *a } @@ -41,7 +41,7 @@ impl ABIInfo for X86_ABIInfo { // http://www.angelcode.com/dev/callconv/callconv.html // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp let sret = { - let returning_a_struct = unsafe { LLVMGetTypeKind(rty) == Struct && ret_def }; + let returning_a_struct = rty.kind() == Struct && ret_def; let big_struct = match self.ccx.sess.targ_cfg.os { os_win32 | os_macos => llsize_of_alloc(self.ccx, rty) > 8, _ => true @@ -52,13 +52,18 @@ impl ABIInfo for X86_ABIInfo { if sret { let ret_ptr_ty = LLVMType { cast: false, - ty: T_ptr(ret_ty.ty) + ty: ret_ty.ty.ptr_to() }; arg_tys = ~[ret_ptr_ty] + arg_tys; attrs = ~[Some(StructRetAttribute)] + attrs; ret_ty = LLVMType { cast: false, - ty: T_void(), + ty: Type::void(), + }; + } else if !ret_def { + ret_ty = LLVMType { + cast: false, + ty: Type::void() }; } diff --git a/src/librustc/middle/trans/cabi_x86_64.rs b/src/librustc/middle/trans/cabi_x86_64.rs index 3ff54e9d3d8..8fa86ea77ab 100644 --- a/src/librustc/middle/trans/cabi_x86_64.rs +++ b/src/librustc/middle/trans/cabi_x86_64.rs @@ -11,265 +11,279 @@ // The classification code for the x86_64 ABI is taken from the clay language // https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp -use lib::llvm::{llvm, TypeRef, Integer, Pointer, Float, Double}; +use lib::llvm::{llvm, Integer, Pointer, Float, Double}; use lib::llvm::{Struct, Array, Attribute}; use lib::llvm::{StructRetAttribute, ByValAttribute}; -use lib::llvm::struct_tys; -use lib::llvm::True; -use middle::trans::common::*; use middle::trans::cabi::*; -use core::libc::c_uint; -use core::option; -use core::option::Option; -use core::uint; -use core::vec; +use middle::trans::type_::Type; + +use std::option; +use std::option::Option; +use std::uint; +use std::vec; #[deriving(Eq)] -enum x86_64_reg_class { - no_class, - integer_class, - sse_fs_class, - sse_fv_class, - sse_ds_class, - sse_dv_class, - sse_int_class, - sseup_class, - x87_class, - x87up_class, - complex_x87_class, - memory_class +enum RegClass { + NoClass, + Int, + SSEFs, + SSEFv, + SSEDs, + SSEDv, + SSEInt, + SSEUp, + X87, + X87Up, + ComplexX87, + Memory } -fn is_sse(c: x86_64_reg_class) -> bool { - return match c { - sse_fs_class | sse_fv_class | - sse_ds_class | sse_dv_class => true, - _ => false - }; +trait TypeMethods { + fn is_reg_ty(&self) -> bool; +} + +impl TypeMethods for Type { + fn is_reg_ty(&self) -> bool { + match self.kind() { + Integer | Pointer | Float | Double => true, + _ => false + } + } +} + +impl RegClass { + fn is_sse(&self) -> bool { + match *self { + SSEFs | SSEFv | SSEDs | SSEDv => true, + _ => false + } + } +} + +trait ClassList { + fn is_pass_byval(&self) -> bool; + fn is_ret_bysret(&self) -> bool; } -fn is_ymm(cls: &[x86_64_reg_class]) -> bool { - let len = cls.len(); - return (len > 2u && - is_sse(cls[0]) && - cls[1] == sseup_class && - cls[2] == sseup_class) || - (len > 3u && - is_sse(cls[1]) && - cls[2] == sseup_class && - cls[3] == sseup_class); +impl<'self> ClassList for &'self [RegClass] { + fn is_pass_byval(&self) -> bool { + if self.len() == 0 { return false; } + + let class = self[0]; + class == Memory + || class == X87 + || class == ComplexX87 + } + + fn is_ret_bysret(&self) -> bool { + if self.len() == 0 { return false; } + + self[0] == Memory + } } -fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { - fn align(off: uint, ty: TypeRef) -> uint { +fn classify_ty(ty: Type) -> ~[RegClass] { + fn align(off: uint, ty: Type) -> uint { let a = ty_align(ty); return (off + a - 1u) / a * a; } - fn ty_align(ty: TypeRef) -> uint { - unsafe { - return match llvm::LLVMGetTypeKind(ty) { - Integer => { - ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 + fn ty_align(ty: Type) -> uint { + match ty.kind() { + Integer => { + unsafe { + ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 } - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if llvm::LLVMIsPackedStruct(ty) == True { - 1 - } else { - let str_tys = struct_tys(ty); - str_tys.iter().fold(1, |a, t| uint::max(a, ty_align(*t))) - } - } - Array => { - let elt = llvm::LLVMGetElementType(ty); - ty_align(elt) - } - _ => fail!("ty_size: unhandled type") - }; + } + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + 1 + } else { + let str_tys = ty.field_types(); + str_tys.iter().fold(1, |a, t| uint::max(a, ty_align(*t))) + } + } + Array => { + let elt = ty.element_type(); + ty_align(elt) + } + _ => fail!("ty_size: unhandled type") } } - fn ty_size(ty: TypeRef) -> uint { - unsafe { - return match llvm::LLVMGetTypeKind(ty) { - Integer => { - ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 + fn ty_size(ty: Type) -> uint { + match ty.kind() { + Integer => { + unsafe { + ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 } - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if llvm::LLVMIsPackedStruct(ty) == True { - let str_tys = struct_tys(ty); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let str_tys = struct_tys(ty); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } - } - Array => { - let len = llvm::LLVMGetArrayLength(ty) as uint; - let elt = llvm::LLVMGetElementType(ty); - let eltsz = ty_size(elt); - len * eltsz + } + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + let str_tys = ty.field_types(); + if ty.is_packed() { + str_tys.iter().fold(0, |s, t| s + ty_size(*t)) + } else { + let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); + align(size, ty) } - _ => fail!("ty_size: unhandled type") - }; + } + Array => { + let len = ty.array_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + _ => fail!("ty_size: unhandled type") } } - fn all_mem(cls: &mut [x86_64_reg_class]) { + fn all_mem(cls: &mut [RegClass]) { for uint::range(0, cls.len()) |i| { - cls[i] = memory_class; + cls[i] = Memory; } } - fn unify(cls: &mut [x86_64_reg_class], + fn unify(cls: &mut [RegClass], i: uint, - newv: x86_64_reg_class) { + newv: RegClass) { if cls[i] == newv { return; - } else if cls[i] == no_class { + } else if cls[i] == NoClass { cls[i] = newv; - } else if newv == no_class { + } else if newv == NoClass { return; - } else if cls[i] == memory_class || newv == memory_class { - cls[i] = memory_class; - } else if cls[i] == integer_class || newv == integer_class { - cls[i] = integer_class; - } else if cls[i] == x87_class || - cls[i] == x87up_class || - cls[i] == complex_x87_class || - newv == x87_class || - newv == x87up_class || - newv == complex_x87_class { - cls[i] = memory_class; + } else if cls[i] == Memory || newv == Memory { + cls[i] = Memory; + } else if cls[i] == Int || newv == Int { + cls[i] = Int; + } else if cls[i] == X87 || + cls[i] == X87Up || + cls[i] == ComplexX87 || + newv == X87 || + newv == X87Up || + newv == ComplexX87 { + cls[i] = Memory; } else { cls[i] = newv; } } - fn classify_struct(tys: &[TypeRef], - cls: &mut [x86_64_reg_class], i: uint, + fn classify_struct(tys: &[Type], + cls: &mut [RegClass], i: uint, off: uint) { let mut field_off = off; - for tys.each |ty| { + for tys.iter().advance |ty| { field_off = align(field_off, *ty); classify(*ty, cls, i, field_off); field_off += ty_size(*ty); } } - fn classify(ty: TypeRef, - cls: &mut [x86_64_reg_class], ix: uint, + fn classify(ty: Type, + cls: &mut [RegClass], ix: uint, off: uint) { - unsafe { - let t_align = ty_align(ty); - let t_size = ty_size(ty); - - let misalign = off % t_align; - if misalign != 0u { - let mut i = off / 8u; - let e = (off + t_size + 7u) / 8u; - while i < e { - unify(cls, ix + i, memory_class); - i += 1u; - } - return; + let t_align = ty_align(ty); + let t_size = ty_size(ty); + + let misalign = off % t_align; + if misalign != 0u { + let mut i = off / 8u; + let e = (off + t_size + 7u) / 8u; + while i < e { + unify(cls, ix + i, Memory); + i += 1u; } + return; + } - match llvm::LLVMGetTypeKind(ty) as int { - 8 /* integer */ | - 12 /* pointer */ => { - unify(cls, ix + off / 8u, integer_class); - } - 2 /* float */ => { - if off % 8u == 4u { - unify(cls, ix + off / 8u, sse_fv_class); - } else { - unify(cls, ix + off / 8u, sse_fs_class); - } - } - 3 /* double */ => { - unify(cls, ix + off / 8u, sse_ds_class); - } - 10 /* struct */ => { - classify_struct(struct_tys(ty), cls, ix, off); + match ty.kind() { + Integer | + Pointer => { + unify(cls, ix + off / 8u, Int); + } + Float => { + if off % 8u == 4u { + unify(cls, ix + off / 8u, SSEFv); + } else { + unify(cls, ix + off / 8u, SSEFs); } - 11 /* array */ => { - let elt = llvm::LLVMGetElementType(ty); - let eltsz = ty_size(elt); - let len = llvm::LLVMGetArrayLength(ty) as uint; - let mut i = 0u; - while i < len { - classify(elt, cls, ix, off + i * eltsz); - i += 1u; - } + } + Double => { + unify(cls, ix + off / 8u, SSEDs); + } + Struct => { + classify_struct(ty.field_types(), cls, ix, off); + } + Array => { + let len = ty.array_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + let mut i = 0u; + while i < len { + classify(elt, cls, ix, off + i * eltsz); + i += 1u; } - _ => fail!("classify: unhandled type") } + _ => fail!("classify: unhandled type") } } - fn fixup(ty: TypeRef, cls: &mut [x86_64_reg_class]) { - unsafe { - let mut i = 0u; - let llty = llvm::LLVMGetTypeKind(ty) as int; - let e = cls.len(); - if cls.len() > 2u && - (llty == 10 /* struct */ || - llty == 11 /* array */) { - if is_sse(cls[i]) { - i += 1u; - while i < e { - if cls[i] != sseup_class { - all_mem(cls); - return; - } - i += 1u; - } - } else { - all_mem(cls); - return - } - } else { + fn fixup(ty: Type, cls: &mut [RegClass]) { + let mut i = 0u; + let ty_kind = ty.kind(); + let e = cls.len(); + if cls.len() > 2u && (ty_kind == Struct || ty_kind == Array) { + if cls[i].is_sse() { + i += 1u; while i < e { - if cls[i] == memory_class { - all_mem(cls); - return; - } - if cls[i] == x87up_class { - // for darwin - // cls[i] = sse_ds_class; + if cls[i] != SSEUp { all_mem(cls); return; } - if cls[i] == sseup_class { - cls[i] = sse_int_class; - } else if is_sse(cls[i]) { - i += 1; - while i != e && cls[i] == sseup_class { i += 1u; } - } else if cls[i] == x87_class { - i += 1; - while i != e && cls[i] == x87up_class { i += 1u; } - } else { - i += 1; - } + i += 1u; + } + } else { + all_mem(cls); + return + } + } else { + while i < e { + if cls[i] == Memory { + all_mem(cls); + return; + } + if cls[i] == X87Up { + // for darwin + // cls[i] = SSEDs; + all_mem(cls); + return; + } + if cls[i] == SSEUp { + cls[i] = SSEDv; + } else if cls[i].is_sse() { + i += 1; + while i != e && cls[i] == SSEUp { i += 1u; } + } else if cls[i] == X87 { + i += 1; + while i != e && cls[i] == X87Up { i += 1u; } + } else { + i += 1; } } } } let words = (ty_size(ty) + 7) / 8; - let mut cls = vec::from_elem(words, no_class); + let mut cls = vec::from_elem(words, NoClass); if words > 4 { all_mem(cls); - let cls = cls; return cls; } classify(ty, cls, 0, 0); @@ -277,11 +291,11 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { return cls; } -fn llreg_ty(cls: &[x86_64_reg_class]) -> TypeRef { - fn llvec_len(cls: &[x86_64_reg_class]) -> uint { +fn llreg_ty(cls: &[RegClass]) -> Type { + fn llvec_len(cls: &[RegClass]) -> uint { let mut len = 1u; - for cls.each |c| { - if *c != sseup_class { + for cls.iter().advance |c| { + if *c != SSEUp { break; } len += 1u; @@ -289,103 +303,78 @@ fn llreg_ty(cls: &[x86_64_reg_class]) -> TypeRef { return len; } - unsafe { - let mut tys = ~[]; - let mut i = 0u; - let e = cls.len(); - while i < e { - match cls[i] { - integer_class => { - tys.push(T_i64()); - } - sse_fv_class => { - let vec_len = llvec_len(vec::tailn(cls, i + 1u)) * 2u; - let vec_ty = llvm::LLVMVectorType(T_f32(), - vec_len as c_uint); - tys.push(vec_ty); - i += vec_len; - loop; - } - sse_fs_class => { - tys.push(T_f32()); - } - sse_ds_class => { - tys.push(T_f64()); - } - _ => fail!("llregtype: unhandled class") + let mut tys = ~[]; + let mut i = 0u; + let e = cls.len(); + while i < e { + match cls[i] { + Int => { + tys.push(Type::i64()); + } + SSEFv => { + let vec_len = llvec_len(cls.tailn(i + 1u)); + let vec_ty = Type::vector(&Type::f32(), (vec_len * 2u) as u64); + tys.push(vec_ty); + i += vec_len; + loop; + } + SSEFs => { + tys.push(Type::f32()); + } + SSEDs => { + tys.push(Type::f64()); } - i += 1u; + _ => fail!("llregtype: unhandled class") } - return T_struct(tys, false); + i += 1u; } + return Type::struct_(tys, false); } -fn x86_64_tys(atys: &[TypeRef], - rty: TypeRef, +fn x86_64_tys(atys: &[Type], + rty: Type, ret_def: bool) -> FnType { - fn is_reg_ty(ty: TypeRef) -> bool { - unsafe { - return match llvm::LLVMGetTypeKind(ty) as int { - 8 /* integer */ | - 12 /* pointer */ | - 2 /* float */ | - 3 /* double */ => true, - _ => false - }; - } - } - - fn is_pass_byval(cls: &[x86_64_reg_class]) -> bool { - return cls.len() > 0 && - (cls[0] == memory_class || - cls[0] == x87_class || - cls[0] == complex_x87_class); - } - - fn is_ret_bysret(cls: &[x86_64_reg_class]) -> bool { - return cls.len() > 0 && cls[0] == memory_class; - } - fn x86_64_ty(ty: TypeRef, - is_mem_cls: &fn(cls: &[x86_64_reg_class]) -> bool, + fn x86_64_ty(ty: Type, + is_mem_cls: &fn(cls: &[RegClass]) -> bool, attr: Attribute) -> (LLVMType, Option<Attribute>) { - let mut cast = false; - let mut ty_attr = option::None; - let mut llty = ty; - if !is_reg_ty(ty) { + + let (cast, attr, ty) = if !ty.is_reg_ty() { let cls = classify_ty(ty); if is_mem_cls(cls) { - llty = T_ptr(ty); - ty_attr = option::Some(attr); + (false, option::Some(attr), ty.ptr_to()) } else { - cast = true; - llty = llreg_ty(cls); + (true, option::None, llreg_ty(cls)) } - } - return (LLVMType { cast: cast, ty: llty }, ty_attr); + } else { + (false, option::None, ty) + }; + + (LLVMType { cast: cast, ty: ty }, attr) } let mut arg_tys = ~[]; let mut attrs = ~[]; - for atys.each |t| { - let (ty, attr) = x86_64_ty(*t, is_pass_byval, ByValAttribute); + for atys.iter().advance |t| { + let (ty, attr) = x86_64_ty(*t, |cls| cls.is_pass_byval(), ByValAttribute); arg_tys.push(ty); attrs.push(attr); } - let mut (ret_ty, ret_attr) = x86_64_ty(rty, is_ret_bysret, + let (ret_ty, ret_attr) = x86_64_ty(rty, |cls| cls.is_ret_bysret(), StructRetAttribute); + let mut ret_ty = ret_ty; let sret = ret_attr.is_some(); if sret { arg_tys = vec::append(~[ret_ty], arg_tys); ret_ty = LLVMType { cast: false, - ty: T_void() + ty: Type::void() }; attrs = vec::append(~[ret_attr], attrs); } else if !ret_def { ret_ty = LLVMType { cast: false, - ty: T_void() + ty: Type::void() }; } return FnType { @@ -400,8 +389,8 @@ enum X86_64_ABIInfo { X86_64_ABIInfo } impl ABIInfo for X86_64_ABIInfo { fn compute_info(&self, - atys: &[TypeRef], - rty: TypeRef, + atys: &[Type], + rty: Type, ret_def: bool) -> FnType { return x86_64_tys(atys, rty, ret_def); } diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index bfbe078c4f5..41f1d0e61e5 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! -// -// Handles translation of callees as well as other call-related -// things. Callees are a superset of normal rust values and sometimes -// have different representations. In particular, top-level fn items -// and methods are represented as just a fn ptr and not a full -// closure. +/*! + * Handles translation of callees as well as other call-related + * things. Callees are a superset of normal rust values and sometimes + * have different representations. In particular, top-level fn items + * and methods are represented as just a fn ptr and not a full + * closure. + */ -use core::prelude::*; +use std::vec; use back::abi; use driver::session; @@ -42,9 +42,11 @@ use middle::trans::type_of; use middle::ty; use middle::subst::Subst; use middle::typeck; +use middle::typeck::coherence::make_substs_for_receiver_types; use util::ppaux::Repr; -use core::vec; +use middle::trans::type_::Type; + use syntax::ast; use syntax::ast_map; use syntax::visit; @@ -59,6 +61,7 @@ pub struct FnData { pub struct MethodData { llfn: ValueRef, llself: ValueRef, + temp_cleanup: Option<ValueRef>, self_ty: ty::t, self_mode: ty::SelfMode, } @@ -75,7 +78,7 @@ pub struct Callee { } pub fn trans(bcx: block, expr: @ast::expr) -> Callee { - let _icx = bcx.insn_ctxt("trans_callee"); + let _icx = push_ctxt("trans_callee"); debug!("callee::trans(expr=%s)", expr.repr(bcx.tcx())); // pick out special kinds of expressions that can be called: @@ -140,10 +143,10 @@ pub fn trans(bcx: block, expr: @ast::expr) -> Callee { datum_callee(bcx, ref_expr) } ast::def_mod(*) | ast::def_foreign_mod(*) | ast::def_trait(*) | - ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) | + ast::def_static(*) | ast::def_ty(*) | ast::def_prim_ty(*) | ast::def_use(*) | ast::def_typaram_binder(*) | ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) | - ast::def_self_ty(*) => { + ast::def_self_ty(*) | ast::def_method(*) => { bcx.tcx().sess.span_bug( ref_expr.span, fmt!("Cannot translate def %? \ @@ -169,7 +172,7 @@ pub fn trans_fn_ref(bcx: block, * with id `def_id` into a function pointer. This may require * monomorphization or inlining. */ - let _icx = bcx.insn_ctxt("trans_fn_ref"); + let _icx = push_ctxt("trans_fn_ref"); let type_params = node_id_type_params(bcx, ref_id); let vtables = node_vtables(bcx, ref_id); @@ -191,6 +194,58 @@ pub fn trans_fn_ref_with_vtables_to_callee( type_params, vtables))} } +fn get_impl_resolutions(bcx: block, + impl_id: ast::def_id) + -> typeck::vtable_res { + if impl_id.crate == ast::local_crate { + *bcx.ccx().maps.vtable_map.get(&impl_id.node) + } else { + // XXX: This is a temporary hack to work around not properly + // exporting information about resolutions for impls. + // This doesn't actually work if the trait has param bounds, + // but it does allow us to survive the case when it does not. + let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get(); + @vec::from_elem(trait_ref.substs.tps.len(), @~[]) + } +} + +fn resolve_default_method_vtables(bcx: block, + impl_id: ast::def_id, + method: &ty::Method, + substs: &ty::substs, + impl_vtables: Option<typeck::vtable_res>) + -> typeck::vtable_res { + + // Get the vtables that the impl implements the trait at + let trait_vtables = get_impl_resolutions(bcx, impl_id); + + // Build up a param_substs that we are going to resolve the + // trait_vtables under. + let param_substs = Some(@param_substs { + tys: copy substs.tps, + self_ty: substs.self_ty, + vtables: impl_vtables, + self_vtable: None + }); + + let trait_vtables_fixed = resolve_vtables_under_param_substs( + bcx.tcx(), param_substs, trait_vtables); + + // Now we pull any vtables for parameters on the actual method. + let num_method_vtables = method.generics.type_param_defs.len(); + let method_vtables = match impl_vtables { + Some(vtables) => { + let num_impl_type_parameters = + vtables.len() - num_method_vtables; + vtables.tailn(num_impl_type_parameters).to_owned() + }, + None => vec::from_elem(num_method_vtables, @~[]) + }; + + @(*trait_vtables_fixed + method_vtables) +} + + pub fn trans_fn_ref_with_vtables( bcx: block, // def_id: ast::def_id, // def id of fn @@ -213,7 +268,7 @@ pub fn trans_fn_ref_with_vtables( // - `type_params`: values for each of the fn/method's type parameters // - `vtables`: values for each bound on each of the type parameters - let _icx = bcx.insn_ctxt("trans_fn_ref_with_vtables"); + let _icx = push_ctxt("trans_fn_ref_with_vtables"); let ccx = bcx.ccx(); let tcx = ccx.tcx; @@ -225,20 +280,26 @@ pub fn trans_fn_ref_with_vtables( type_params.repr(bcx.tcx()), vtables.repr(bcx.tcx())); - assert!(type_params.all(|t| !ty::type_needs_infer(*t))); + assert!(type_params.iter().all(|t| !ty::type_needs_infer(*t))); // Polytype of the function item (may have type params) let fn_tpt = ty::lookup_item_type(tcx, def_id); - let substs = ty::substs { self_r: None, self_ty: None, + // For simplicity, we want to use the Subst trait when composing + // substitutions for default methods. The subst trait does + // substitutions with regions, though, so we put a dummy self + // region parameter in to keep it from failing. This is a hack. + let substs = ty::substs { self_r: Some(ty::re_empty), + self_ty: None, tps: /*bad*/ type_params.to_owned() }; // We need to do a bunch of special handling for default methods. // We need to modify the def_id and our substs in order to monomorphize // the function. - let (def_id, opt_impl_did, substs) = match tcx.provided_method_sources.find(&def_id) { - None => (def_id, None, substs), + let (def_id, opt_impl_did, substs, self_vtable, vtables) = + match tcx.provided_method_sources.find(&def_id) { + None => (def_id, None, substs, None, vtables), Some(source) => { // There are two relevant substitutions when compiling // default methods. First, there is the substitution for @@ -253,51 +314,47 @@ pub fn trans_fn_ref_with_vtables( // So, what we need to do is find this substitution and // compose it with the one we already have. - // In order to find the substitution for the trait params, - // we look up the impl in the ast map, find its trait_ref - // id, then look up its trait ref. I feel like there - // should be a better way. - let map_node = session::expect( - ccx.sess, - ccx.tcx.items.find_copy(&source.impl_id.node), - || fmt!("couldn't find node while monomorphizing \ - default method: %?", source.impl_id.node)); - let item = match map_node { - ast_map::node_item(item, _) => item, - _ => ccx.tcx.sess.bug("Not an item") - }; - let ast_trait_ref = match copy item.node { - ast::item_impl(_, Some(tr), _, _) => tr, - _ => ccx.tcx.sess.bug("Not an impl with trait_ref") - }; - let trait_ref = ccx.tcx.trait_refs.get(&ast_trait_ref.ref_id); - - // The substs from the trait_ref only substitues for the - // trait parameters. Our substitution also needs to be - // able to substitute for the actual method type - // params. To do this, we figure out how many method - // parameters there are and pad out the substitution with - // substitution for the variables. - let item_ty = ty::lookup_item_type(tcx, source.method_id); - let num_params = item_ty.generics.type_param_defs.len() - - trait_ref.substs.tps.len(); - let id_subst = do vec::from_fn(num_params) |i| { - ty::mk_param(tcx, i, ast::def_id {crate: 0, node: 0}) + let trait_ref = ty::impl_trait_ref(tcx, source.impl_id) + .expect("could not find trait_ref for impl with \ + default methods"); + let method = ty::method(tcx, source.method_id); + + // Get all of the type params for the receiver + let param_defs = method.generics.type_param_defs; + let receiver_substs = + type_params.initn(param_defs.len()).to_owned(); + let receiver_vtables = match vtables { + None => @~[], + Some(call_vtables) => { + @call_vtables.initn(param_defs.len()).to_owned() + } }; - // Merge the two substitions together now. - let first_subst = ty::substs {tps: trait_ref.substs.tps + id_subst, - .. trait_ref.substs}; - // And compose them. + let self_vtable = + typeck::vtable_static(source.impl_id, receiver_substs, + receiver_vtables); + // Compute the first substitution + let first_subst = make_substs_for_receiver_types( + tcx, source.impl_id, trait_ref, method); + + // And compose them let new_substs = first_subst.subst(tcx, &substs); - debug!("trans_fn_with_vtables - default method: \ - substs = %s, id_subst = %s, trait_subst = %s, \ - first_subst = %s, new_subst = %s", - substs.repr(tcx), - id_subst.repr(tcx), trait_ref.substs.repr(tcx), - first_subst.repr(tcx), new_substs.repr(tcx)); - (source.method_id, Some(source.impl_id), new_substs) + + let vtables = + resolve_default_method_vtables(bcx, source.impl_id, + method, &new_substs, vtables); + + debug!("trans_fn_with_vtables - default method: \ + substs = %s, trait_subst = %s, \ + first_subst = %s, new_subst = %s, \ + self_vtable = %s, vtables = %s", + substs.repr(tcx), trait_ref.substs.repr(tcx), + first_subst.repr(tcx), new_substs.repr(tcx), + self_vtable.repr(tcx), vtables.repr(tcx)); + + (source.method_id, Some(source.impl_id), + new_substs, Some(self_vtable), Some(vtables)) } }; @@ -342,16 +399,18 @@ pub fn trans_fn_ref_with_vtables( // Should be either intra-crate or inlined. assert_eq!(def_id.crate, ast::local_crate); - let mut (val, must_cast) = + let (val, must_cast) = monomorphize::monomorphic_fn(ccx, def_id, &substs, - vtables, opt_impl_did, Some(ref_id)); + vtables, self_vtable, + opt_impl_did, Some(ref_id)); + let mut val = val; if must_cast && ref_id != 0 { // Monotype of the REFERENCE to the function (type params // are subst'd) let ref_ty = common::node_id_type(bcx, ref_id); val = PointerCast( - bcx, val, T_ptr(type_of::type_of_fn_from_ty(ccx, ref_ty))); + bcx, val, type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to()); } return FnData {llfn: val}; } @@ -380,7 +439,7 @@ pub fn trans_call(in_cx: block, id: ast::node_id, dest: expr::Dest) -> block { - let _icx = in_cx.insn_ctxt("trans_call"); + let _icx = push_ctxt("trans_call"); trans_call_inner(in_cx, call_ex.info(), expr_ty(in_cx, f), @@ -398,7 +457,7 @@ pub fn trans_method_call(in_cx: block, args: CallArgs, dest: expr::Dest) -> block { - let _icx = in_cx.insn_ctxt("trans_method_call"); + let _icx = push_ctxt("trans_method_call"); debug!("trans_method_call(call_ex=%s, rcvr=%s)", call_ex.repr(in_cx.tcx()), rcvr.repr(in_cx.tcx())); @@ -526,7 +585,7 @@ pub fn trans_call_inner(in_cx: block, do base::with_scope(in_cx, call_info, "call") |cx| { let ret_in_loop = match args { ArgExprs(args) => { - args.len() > 0u && match vec::last(args).node { + args.len() > 0u && match args.last().node { ast::expr_loop_body(@ast::expr { node: ast::expr_fn_block(_, ref body), _ @@ -541,7 +600,7 @@ pub fn trans_call_inner(in_cx: block, let mut bcx = callee.bcx; let ccx = cx.ccx(); let ret_flag = if ret_in_loop { - let flag = alloca(bcx, T_bool()); + let flag = alloca(bcx, Type::bool()); Store(bcx, C_bool(false), flag); Some(flag) } else { @@ -551,14 +610,11 @@ pub fn trans_call_inner(in_cx: block, let (llfn, llenv) = unsafe { match callee.data { Fn(d) => { - (d.llfn, llvm::LLVMGetUndef(T_opaque_box_ptr(ccx))) + (d.llfn, llvm::LLVMGetUndef(Type::opaque_box(ccx).ptr_to().to_ref())) } Method(d) => { // Weird but true: we pass self in the *environment* slot! - let llself = PointerCast(bcx, - d.llself, - T_opaque_box_ptr(ccx)); - (d.llfn, llself) + (d.llfn, d.llself) } Closure(d) => { // Closures are represented as (llfn, llclosure) pair: @@ -587,19 +643,21 @@ pub fn trans_call_inner(in_cx: block, // Now that the arguments have finished evaluating, we need to revoke - // the cleanup for the self argument, if it exists + // the cleanup for the self argument match callee.data { - Method(d) if d.self_mode == ty::ByCopy => { - revoke_clean(bcx, d.llself); + Method(d) => { + for d.temp_cleanup.iter().advance |&v| { + revoke_clean(bcx, v); + } } _ => {} } // Uncomment this to debug calls. /* - io::println(fmt!("calling: %s", bcx.val_str(llfn))); - for llargs.each |llarg| { - io::println(fmt!("arg: %s", bcx.val_str(*llarg))); + io::println(fmt!("calling: %s", bcx.val_to_str(llfn))); + for llargs.iter().advance |llarg| { + io::println(fmt!("arg: %s", bcx.val_to_str(*llarg))); } io::println("---"); */ @@ -678,7 +736,7 @@ pub fn trans_ret_slot(bcx: block, fn_ty: ty::t, dest: expr::Dest) expr::Ignore => { if ty::type_is_nil(retty) { unsafe { - llvm::LLVMGetUndef(T_ptr(T_nil())) + llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()) } } else { alloc_ty(bcx, retty) @@ -694,7 +752,7 @@ pub fn trans_args(cx: block, autoref_arg: AutorefArg, llargs: &mut ~[ValueRef]) -> block { - let _icx = cx.insn_ctxt("trans_args"); + let _icx = push_ctxt("trans_args"); let mut temp_cleanups = ~[]; let arg_tys = ty::ty_fn_args(fn_ty); @@ -706,7 +764,7 @@ pub fn trans_args(cx: block, match args { ArgExprs(arg_exprs) => { let last = arg_exprs.len() - 1u; - for arg_exprs.eachi |i, arg_expr| { + for arg_exprs.iter().enumerate().advance |(i, arg_expr)| { let arg_val = unpack_result!(bcx, { trans_arg_expr(bcx, arg_tys[i], @@ -727,11 +785,11 @@ pub fn trans_args(cx: block, // now that all arguments have been successfully built, we can revoke any // temporary cleanups, as they are only needed if argument construction // should fail (for example, cleanup of copy mode args). - for vec::each(temp_cleanups) |c| { + for temp_cleanups.iter().advance |c| { revoke_clean(bcx, *c) } - return bcx; + bcx } pub enum AutorefArg { @@ -748,7 +806,7 @@ pub fn trans_arg_expr(bcx: block, temp_cleanups: &mut ~[ValueRef], ret_flag: Option<ValueRef>, autoref_arg: AutorefArg) -> Result { - let _icx = bcx.insn_ctxt("trans_arg_expr"); + let _icx = push_ctxt("trans_arg_expr"); let ccx = bcx.ccx(); debug!("trans_arg_expr(formal_arg_ty=(%s), self_mode=%?, arg_expr=%s, \ @@ -756,7 +814,7 @@ pub fn trans_arg_expr(bcx: block, formal_arg_ty.repr(bcx.tcx()), self_mode, arg_expr.repr(bcx.tcx()), - ret_flag.map(|v| bcx.val_str(*v))); + ret_flag.map(|v| bcx.val_to_str(*v))); // translate the arg expr to a datum let arg_datumblock = match ret_flag { @@ -802,7 +860,7 @@ pub fn trans_arg_expr(bcx: block, // to have type lldestty (the callee's expected type). let llformal_arg_ty = type_of::type_of(ccx, formal_arg_ty); unsafe { - val = llvm::LLVMGetUndef(llformal_arg_ty); + val = llvm::LLVMGetUndef(llformal_arg_ty.to_ref()); } } else { // FIXME(#3548) use the adjustments table @@ -821,12 +879,7 @@ pub fn trans_arg_expr(bcx: block, // //assert !bcx.ccx().maps.moves_map.contains_key( // &arg_expr.id); - debug!("by ref arg with type %s", - bcx.ty_to_str(arg_datum.ty)); - val = arg_datum.to_ref_llval(bcx); - } - ty::ByCopy => { - debug!("by copy arg with type %s, storing to scratch", + debug!("by ref arg with type %s, storing to scratch", bcx.ty_to_str(arg_datum.ty)); let scratch = scratch_datum(bcx, arg_datum.ty, false); @@ -841,9 +894,36 @@ pub fn trans_arg_expr(bcx: block, scratch.add_clean(bcx); temp_cleanups.push(scratch.val); - match arg_datum.appropriate_mode() { - ByValue => val = Load(bcx, scratch.val), - ByRef(_) => val = scratch.val, + val = scratch.to_ref_llval(bcx); + } + ty::ByCopy => { + if ty::type_needs_drop(bcx.tcx(), arg_datum.ty) || + arg_datum.appropriate_mode().is_by_ref() { + debug!("by copy arg with type %s, storing to scratch", + bcx.ty_to_str(arg_datum.ty)); + let scratch = scratch_datum(bcx, arg_datum.ty, false); + + arg_datum.store_to_datum(bcx, + arg_expr.id, + INIT, + scratch); + + // Technically, ownership of val passes to the callee. + // However, we must cleanup should we fail before the + // callee is actually invoked. + scratch.add_clean(bcx); + temp_cleanups.push(scratch.val); + + match scratch.appropriate_mode() { + ByValue => val = Load(bcx, scratch.val), + ByRef(_) => val = scratch.val, + } + } else { + debug!("by copy arg with type %s", bcx.ty_to_str(arg_datum.ty)); + match arg_datum.mode { + ByRef(_) => val = Load(bcx, arg_datum.val), + ByValue => val = arg_datum.val, + } } } } @@ -853,16 +933,12 @@ pub fn trans_arg_expr(bcx: block, if formal_arg_ty != arg_datum.ty { // this could happen due to e.g. subtyping let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, &formal_arg_ty); - let llformal_arg_ty = match self_mode { - ty::ByRef => T_ptr(llformal_arg_ty), - ty::ByCopy => llformal_arg_ty, - }; debug!("casting actual type (%s) to match formal (%s)", - bcx.val_str(val), bcx.llty_str(llformal_arg_ty)); + bcx.val_to_str(val), bcx.llty_str(llformal_arg_ty)); val = PointerCast(bcx, val, llformal_arg_ty); } } - debug!("--- trans_arg_expr passing %s", val_str(bcx.ccx().tn, val)); + debug!("--- trans_arg_expr passing %s", bcx.val_to_str(val)); return rslt(bcx, val); } diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index c368ab5c9bd..3478925753e 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use back::abi; use back::link::{mangle_internal_name_by_path_and_seq}; @@ -26,8 +25,10 @@ use middle::trans::type_of::*; use middle::ty; use util::ppaux::ty_to_str; -use core::str; -use core::vec; +use middle::trans::type_::Type; + +use std::str; +use std::vec; use syntax::ast; use syntax::ast_map::path_name; use syntax::ast_util; @@ -72,7 +73,7 @@ use syntax::parse::token::special_idents; // closure". // // Typically an opaque closure suffices because we only manipulate it -// by ptr. The routine common::T_opaque_box_ptr() returns an +// by ptr. The routine Type::opaque_box().ptr_to() returns an // appropriate type for such an opaque closure; it allows access to // the box fields, but not the closure_data itself. // @@ -158,17 +159,25 @@ pub fn mk_closure_tys(tcx: ty::ctxt, return cdata_ty; } +fn heap_for_unique_closure(bcx: block, t: ty::t) -> heap { + if ty::type_contents(bcx.tcx(), t).contains_managed() { + heap_managed_unique + } else { + heap_exchange_closure + } +} + pub fn allocate_cbox(bcx: block, sigil: ast::Sigil, cdata_ty: ty::t) -> Result { - let _icx = bcx.insn_ctxt("closure::allocate_cbox"); + let _icx = push_ctxt("closure::allocate_cbox"); let ccx = bcx.ccx(); let tcx = ccx.tcx; fn nuke_ref_count(bcx: block, llbox: ValueRef) { - let _icx = bcx.insn_ctxt("closure::nuke_ref_count"); + let _icx = push_ctxt("closure::nuke_ref_count"); // Initialize ref count to arbitrary value for debugging: let ccx = bcx.ccx(); - let llbox = PointerCast(bcx, llbox, T_opaque_box_ptr(ccx)); + let llbox = PointerCast(bcx, llbox, Type::opaque_box(ccx).ptr_to()); let ref_cnt = GEPi(bcx, llbox, [0u, abi::box_field_refcnt]); let rc = C_int(ccx, 0x12345678); Store(bcx, rc, ref_cnt); @@ -180,7 +189,7 @@ pub fn allocate_cbox(bcx: block, sigil: ast::Sigil, cdata_ty: ty::t) malloc_raw(bcx, cdata_ty, heap_managed) } ast::OwnedSigil => { - malloc_raw(bcx, cdata_ty, heap_for_unique(bcx, cdata_ty)) + malloc_raw(bcx, cdata_ty, heap_for_unique_closure(bcx, cdata_ty)) } ast::BorrowedSigil => { let cbox_ty = tuplify_box_ty(tcx, cdata_ty); @@ -204,11 +213,11 @@ pub struct ClosureResult { pub fn store_environment(bcx: block, bound_values: ~[EnvValue], sigil: ast::Sigil) -> ClosureResult { - let _icx = bcx.insn_ctxt("closure::store_environment"); + let _icx = push_ctxt("closure::store_environment"); let ccx = bcx.ccx(); let tcx = ccx.tcx; - // compute the shape of the closure + // compute the type of the closure let cdata_ty = mk_closure_tys(tcx, bound_values); // allocate closure in the heap @@ -225,7 +234,7 @@ pub fn store_environment(bcx: block, // Copy expr values into boxed bindings. let mut bcx = bcx; - for vec::eachi(bound_values) |i, bv| { + for bound_values.iter().enumerate().advance |(i, bv)| { debug!("Copy %s into closure", bv.to_str(ccx)); if ccx.sess.asm_comments() { @@ -258,13 +267,13 @@ pub fn build_closure(bcx0: block, cap_vars: &[moves::CaptureVar], sigil: ast::Sigil, include_ret_handle: Option<ValueRef>) -> ClosureResult { - let _icx = bcx0.insn_ctxt("closure::build_closure"); + let _icx = push_ctxt("closure::build_closure"); // If we need to, package up the iterator body to call let bcx = bcx0; // Package up the captured upvars let mut env_vals = ~[]; - for cap_vars.each |cap_var| { + for cap_vars.iter().advance |cap_var| { debug!("Building closure: captured variable %?", *cap_var); let datum = expr::trans_local_var(bcx, cap_var.def); match cap_var.mode { @@ -297,10 +306,12 @@ pub fn build_closure(bcx0: block, // the right thing): let ret_true = match bcx.fcx.loop_ret { Some((_, retptr)) => retptr, - None => bcx.fcx.llretptr.get() + None => match bcx.fcx.llretptr { + None => C_null(Type::nil().ptr_to()), + Some(retptr) => PointerCast(bcx, retptr, Type::nil().ptr_to()), + } }; - let ret_casted = PointerCast(bcx, ret_true, T_ptr(T_nil())); - let ret_datum = Datum {val: ret_casted, ty: ty::mk_nil(), + let ret_datum = Datum {val: ret_true, ty: ty::mk_nil(), mode: ByRef(ZeroMem)}; env_vals.push(EnvValue {action: EnvRef, datum: ret_datum}); @@ -317,7 +328,7 @@ pub fn load_environment(fcx: fn_ctxt, cap_vars: &[moves::CaptureVar], load_ret_handle: bool, sigil: ast::Sigil) { - let _icx = fcx.insn_ctxt("closure::load_environment"); + let _icx = push_ctxt("closure::load_environment"); let llloadenv = match fcx.llloadenv { Some(ll) => ll, @@ -342,7 +353,7 @@ pub fn load_environment(fcx: fn_ctxt, // Populate the upvars from the environment. let mut i = 0u; - for cap_vars.each |cap_var| { + for cap_vars.iter().advance |cap_var| { let mut upvarptr = GEPi(bcx, llcdata, [0u, i]); match sigil { ast::BorrowedSigil => { upvarptr = Load(bcx, upvarptr); } @@ -388,7 +399,7 @@ pub fn trans_expr_fn(bcx: block, (fn ptr, env) pair */ - let _icx = bcx.insn_ctxt("closure::trans_expr_fn"); + let _icx = push_ctxt("closure::trans_expr_fn"); let dest_addr = match dest { expr::SaveIn(p) => p, @@ -440,7 +451,6 @@ pub fn trans_expr_fn(bcx: block, no_self, /*bad*/ copy bcx.fcx.param_substs, user_id, - None, [], real_return_type, |fcx| load_environment(fcx, cdata_ty, cap_vars, @@ -464,8 +474,8 @@ pub fn make_closure_glue( cx: block, v: ValueRef, t: ty::t, - glue_fn: @fn(block, v: ValueRef, t: ty::t) -> block) -> block { - let _icx = cx.insn_ctxt("closure::make_closure_glue"); + glue_fn: &fn(block, v: ValueRef, t: ty::t) -> block) -> block { + let _icx = push_ctxt("closure::make_closure_glue"); let bcx = cx; let tcx = cx.tcx(); @@ -489,7 +499,7 @@ pub fn make_opaque_cbox_take_glue( cboxptr: ValueRef) // ptr to ptr to the opaque closure -> block { // Easy cases: - let _icx = bcx.insn_ctxt("closure::make_opaque_cbox_take_glue"); + let _icx = push_ctxt("closure::make_opaque_cbox_take_glue"); match sigil { ast::BorrowedSigil => { return bcx; @@ -506,25 +516,25 @@ pub fn make_opaque_cbox_take_glue( // ~fn requires a deep copy. let ccx = bcx.ccx(); let tcx = ccx.tcx; - let llopaquecboxty = T_opaque_box_ptr(ccx); + let llopaquecboxty = Type::opaque_box(ccx).ptr_to(); let cbox_in = Load(bcx, cboxptr); do with_cond(bcx, IsNotNull(bcx, cbox_in)) |bcx| { // Load the size from the type descr found in the cbox let cbox_in = PointerCast(bcx, cbox_in, llopaquecboxty); let tydescptr = GEPi(bcx, cbox_in, [0u, abi::box_field_tydesc]); let tydesc = Load(bcx, tydescptr); - let tydesc = PointerCast(bcx, tydesc, T_ptr(ccx.tydesc_type)); + let tydesc = PointerCast(bcx, tydesc, ccx.tydesc_type.ptr_to()); let sz = Load(bcx, GEPi(bcx, tydesc, [0u, abi::tydesc_field_size])); // Adjust sz to account for the rust_opaque_box header fields - let sz = Add(bcx, sz, machine::llsize_of(ccx, T_box_header(ccx))); + let sz = Add(bcx, sz, machine::llsize_of(ccx, Type::box_header(ccx))); // Allocate memory, update original ptr, and copy existing data - let opaque_tydesc = PointerCast(bcx, tydesc, T_ptr(T_i8())); - let rval = alloca(bcx, T_ptr(T_i8())); + let opaque_tydesc = PointerCast(bcx, tydesc, Type::i8p()); + let rval = alloca(bcx, Type::i8p()); let bcx = callee::trans_lang_call( bcx, - bcx.tcx().lang_items.exchange_malloc_fn(), + bcx.tcx().lang_items.closure_exchange_malloc_fn(), [opaque_tydesc, sz], expr::SaveIn(rval)); let cbox_out = PointerCast(bcx, Load(bcx, rval), llopaquecboxty); @@ -548,7 +558,7 @@ pub fn make_opaque_cbox_drop_glue( sigil: ast::Sigil, cboxptr: ValueRef) // ptr to the opaque closure -> block { - let _icx = bcx.insn_ctxt("closure::make_opaque_cbox_drop_glue"); + let _icx = push_ctxt("closure::make_opaque_cbox_drop_glue"); match sigil { ast::BorrowedSigil => bcx, ast::ManagedSigil => { @@ -569,7 +579,7 @@ pub fn make_opaque_cbox_free_glue( sigil: ast::Sigil, cbox: ValueRef) // ptr to ptr to the opaque closure -> block { - let _icx = bcx.insn_ctxt("closure::make_opaque_cbox_free_glue"); + let _icx = push_ctxt("closure::make_opaque_cbox_free_glue"); match sigil { ast::BorrowedSigil => { return bcx; @@ -582,7 +592,7 @@ pub fn make_opaque_cbox_free_glue( let ccx = bcx.ccx(); do with_cond(bcx, IsNotNull(bcx, cbox)) |bcx| { // Load the type descr found in the cbox - let lltydescty = T_ptr(ccx.tydesc_type); + let lltydescty = ccx.tydesc_type.ptr_to(); let cbox = Load(bcx, cbox); let tydescptr = GEPi(bcx, cbox, [0u, abi::box_field_tydesc]); let tydesc = Load(bcx, tydescptr); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index ff98e5a177f..5b3052a1e1f 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -10,20 +10,17 @@ //! Code that is useful in various trans modules. -use core::prelude::*; -use back::{abi}; use driver::session; use driver::session::Session; -use lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef}; +use lib::llvm::{ValueRef, BasicBlockRef, BuilderRef}; use lib::llvm::{True, False, Bool}; -use lib::llvm::{llvm, TypeNames, associate_type, name_has_type}; +use lib::llvm::{llvm}; use lib; use middle::trans::base; use middle::trans::build; use middle::trans::datum; use middle::trans::glue; -use middle::trans::type_of; use middle::trans::write_guard; use middle::ty::substs; use middle::ty; @@ -31,50 +28,26 @@ use middle::typeck; use middle::borrowck::root_map_key; use util::ppaux::{Repr}; -use core::cast::transmute; -use core::cast; -use core::hashmap::{HashMap}; -use core::libc::{c_uint, c_longlong, c_ulonglong}; -use core::str; -use core::to_bytes; -use core::vec::raw::to_ptr; -use core::vec; +use middle::trans::type_::Type; + +use std::cast::transmute; +use std::cast; +use std::hashmap::{HashMap}; +use std::libc::{c_uint, c_longlong, c_ulonglong}; +use std::to_bytes; +use std::str; +use std::vec::raw::to_ptr; +use std::vec; use syntax::ast::ident; use syntax::ast_map::{path, path_elt}; use syntax::codemap::span; use syntax::parse::token; use syntax::{ast, ast_map}; -use syntax::abi::{X86, X86_64, Arm, Mips}; pub use middle::trans::context::CrateContext; -// NOTE: this thunk is totally pointless now that we're not passing -// interners around... -pub type namegen = @fn(s: &str) -> ident; -pub fn new_namegen() -> namegen { - let f: @fn(s: &str) -> ident = |prefix| { - token::str_to_ident(fmt!("%s_%u", - prefix, - token::gensym(prefix))) - }; - f -} - -pub type addrspace = c_uint; - -// Address spaces communicate to LLVM which destructors need to run for -// specific types. -// 0 is ignored by the GC, and is used for all non-GC'd pointers. -// 1 is for opaque GC'd boxes. -// >= 2 are for specific types (e.g. resources). -pub static default_addrspace: addrspace = 0; -pub static gc_box_addrspace: addrspace = 1; - -pub type addrspace_gen = @fn() -> addrspace; -pub fn new_addrspace_gen() -> addrspace_gen { - let i = @mut 1; - let result: addrspace_gen = || { *i += 1; *i }; - result +pub fn gensym_name(name: &str) -> ident { + token::str_to_ident(fmt!("%s_%u", name, token::gensym(name))) } pub struct tydesc_info { @@ -82,7 +55,6 @@ pub struct tydesc_info { tydesc: ValueRef, size: ValueRef, align: ValueRef, - addrspace: addrspace, take_glue: Option<ValueRef>, drop_glue: Option<ValueRef>, free_glue: Option<ValueRef>, @@ -124,7 +96,6 @@ pub struct Stats { n_monos: uint, n_inlines: uint, n_closures: uint, - llvm_insn_ctxt: ~[~str], llvm_insns: HashMap<~str, uint>, fn_times: ~[(~str, int)] // (ident, time) } @@ -134,7 +105,7 @@ pub struct BuilderRef_res { } impl Drop for BuilderRef_res { - fn finalize(&self) { + fn drop(&self) { unsafe { llvm::LLVMDisposeBuilder(self.B); } @@ -153,30 +124,29 @@ pub type ExternMap = HashMap<@str, ValueRef>; pub struct ValSelfData { v: ValueRef, t: ty::t, - is_owned: bool + is_copy: bool, } // Here `self_ty` is the real type of the self parameter to this method. It // will only be set in the case of default methods. pub struct param_substs { tys: ~[ty::t], + self_ty: Option<ty::t>, vtables: Option<typeck::vtable_res>, - type_param_defs: @~[ty::TypeParameterDef], - self_ty: Option<ty::t> + self_vtable: Option<typeck::vtable_origin> } impl param_substs { pub fn validate(&self) { - for self.tys.each |t| { assert!(!ty::type_needs_infer(*t)); } + for self.tys.iter().advance |t| { assert!(!ty::type_needs_infer(*t)); } for self.self_ty.iter().advance |t| { assert!(!ty::type_needs_infer(*t)); } } } fn param_substs_to_str(this: ¶m_substs, tcx: ty::ctxt) -> ~str { - fmt!("param_substs {tys:%s, vtables:%s, type_param_defs:%s}", + fmt!("param_substs {tys:%s, vtables:%s}", this.tys.repr(tcx), - this.vtables.repr(tcx), - this.type_param_defs.repr(tcx)) + this.vtables.repr(tcx)) } impl Repr for param_substs { @@ -253,9 +223,6 @@ pub struct fn_ctxt_ { // a user-defined function. id: ast::node_id, - // The def_id of the impl we're inside, or None if we aren't inside one. - impl_id: Option<ast::def_id>, - // If this function is being monomorphized, this contains the type // substitutions used. param_substs: Option<@param_substs>, @@ -308,6 +275,7 @@ pub enum heap { heap_managed, heap_managed_unique, heap_exchange, + heap_exchange_closure } #[deriving(Eq)] @@ -347,39 +315,14 @@ pub fn cleanup_type(cx: ty::ctxt, ty: ty::t) -> cleantype { } } -// This is not the same as datum::Datum::root(), which is used to keep copies -// of @ values live for as long as a borrowed pointer to the interior exists. -// In the new GC, we can identify immediates on the stack without difficulty, -// but have trouble knowing where non-immediates are on the stack. For -// non-immediates, we must add an additional level of indirection, which -// allows us to alloca a pointer with the right addrspace. -pub fn root_for_cleanup(bcx: block, v: ValueRef, t: ty::t) - -> (ValueRef, bool) { - let ccx = bcx.ccx(); - - let addrspace = base::get_tydesc(ccx, t).addrspace; - if addrspace > gc_box_addrspace { - let llty = type_of::type_of_rooted(ccx, t); - let root = base::alloca(bcx, llty); - build::Store(bcx, build::PointerCast(bcx, v, llty), root); - (root, true) - } else { - (v, false) - } -} - pub fn add_clean(bcx: block, val: ValueRef, t: ty::t) { if !ty::type_needs_drop(bcx.tcx(), t) { return; } - debug!("add_clean(%s, %s, %s)", - bcx.to_str(), - val_str(bcx.ccx().tn, val), - t.repr(bcx.tcx())); - let (root, rooted) = root_for_cleanup(bcx, val, t); + + debug!("add_clean(%s, %s, %s)", bcx.to_str(), bcx.val_to_str(val), t.repr(bcx.tcx())); + let cleanup_type = cleanup_type(bcx.tcx(), t); do in_scope_cx(bcx) |scope_info| { - scope_info.cleanups.push( - clean(|a| glue::drop_ty_root(a, root, rooted, t), - cleanup_type)); + scope_info.cleanups.push(clean(|a| glue::drop_ty(a, val, t), cleanup_type)); grow_scope_clean(scope_info); } } @@ -387,7 +330,7 @@ pub fn add_clean(bcx: block, val: ValueRef, t: ty::t) { pub fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) { if !ty::type_needs_drop(cx.tcx(), ty) { return; } debug!("add_clean_temp_immediate(%s, %s, %s)", - cx.to_str(), val_str(cx.ccx().tn, val), + cx.to_str(), cx.val_to_str(val), ty.repr(cx.tcx())); let cleanup_type = cleanup_type(cx.tcx(), ty); do in_scope_cx(cx) |scope_info| { @@ -400,14 +343,11 @@ pub fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) { pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { if !ty::type_needs_drop(bcx.tcx(), t) { return; } debug!("add_clean_temp_mem(%s, %s, %s)", - bcx.to_str(), val_str(bcx.ccx().tn, val), + bcx.to_str(), bcx.val_to_str(val), t.repr(bcx.tcx())); - let (root, rooted) = root_for_cleanup(bcx, val, t); let cleanup_type = cleanup_type(bcx.tcx(), t); do in_scope_cx(bcx) |scope_info| { - scope_info.cleanups.push( - clean_temp(val, |a| glue::drop_ty_root(a, root, rooted, t), - cleanup_type)); + scope_info.cleanups.push(clean_temp(val, |a| glue::drop_ty(a, val, t), cleanup_type)); grow_scope_clean(scope_info); } } @@ -427,18 +367,14 @@ pub fn add_clean_return_to_mut(bcx: block, debug!("add_clean_return_to_mut(%s, %s, %s)", bcx.to_str(), - val_str(bcx.ccx().tn, frozen_val_ref), - val_str(bcx.ccx().tn, bits_val_ref)); + bcx.val_to_str(frozen_val_ref), + bcx.val_to_str(bits_val_ref)); do in_scope_cx(bcx) |scope_info| { scope_info.cleanups.push( clean_temp( frozen_val_ref, - |bcx| write_guard::return_to_mut(bcx, - root_key, - frozen_val_ref, - bits_val_ref, - filename_val, - line_val), + |bcx| write_guard::return_to_mut(bcx, root_key, frozen_val_ref, bits_val_ref, + filename_val, line_val), normal_exit_only)); grow_scope_clean(scope_info); } @@ -449,7 +385,7 @@ pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { let f: @fn(block) -> block = |a| glue::trans_free(a, ptr); f } - heap_exchange => { + heap_exchange | heap_exchange_closure => { let f: @fn(block) -> block = |a| glue::trans_exchange_free(a, ptr); f } @@ -467,19 +403,16 @@ pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { // drop glue checks whether it is zero. pub fn revoke_clean(cx: block, val: ValueRef) { do in_scope_cx(cx) |scope_info| { - let scope_info = &mut *scope_info; // FIXME(#5074) workaround borrowck - let cleanup_pos = vec::position( - scope_info.cleanups, + let cleanup_pos = scope_info.cleanups.iter().position_( |cu| match *cu { clean_temp(v, _, _) if v == val => true, _ => false }); for cleanup_pos.iter().advance |i| { scope_info.cleanups = - vec::append(vec::slice(scope_info.cleanups, 0u, *i).to_vec(), - vec::slice(scope_info.cleanups, - *i + 1u, - scope_info.cleanups.len())); + vec::append(scope_info.cleanups.slice(0u, *i).to_owned(), + scope_info.cleanups.slice(*i + 1u, + scope_info.cleanups.len())); shrink_scope_clean(scope_info, *i); } } @@ -530,7 +463,7 @@ pub trait get_node_info { fn info(&self) -> Option<NodeInfo>; } -impl get_node_info for @ast::expr { +impl get_node_info for ast::expr { fn info(&self) -> Option<NodeInfo> { Some(NodeInfo {id: self.id, callee_id: self.get_callee_id(), @@ -624,21 +557,13 @@ impl Result { } } -pub fn ty_str(tn: @TypeNames, t: TypeRef) -> @str { - return lib::llvm::type_to_str(tn, t); -} - -pub fn val_ty(v: ValueRef) -> TypeRef { +pub fn val_ty(v: ValueRef) -> Type { unsafe { - return llvm::LLVMTypeOf(v); + Type::from_ref(llvm::LLVMTypeOf(v)) } } -pub fn val_str(tn: @TypeNames, v: ValueRef) -> @str { - return ty_str(tn, val_ty(v)); -} - -pub fn in_scope_cx(cx: block, f: &fn(si: @mut scope_info)) { +pub fn in_scope_cx(cx: block, f: &fn(si: &mut scope_info)) { let mut cur = cx; loop { match cur.kind { @@ -665,27 +590,27 @@ pub fn block_parent(cx: block) -> block { // Accessors impl block_ { - pub fn ccx(@mut self) -> @mut CrateContext { self.fcx.ccx } - pub fn tcx(@mut self) -> ty::ctxt { self.fcx.ccx.tcx } - pub fn sess(@mut self) -> Session { self.fcx.ccx.sess } + pub fn ccx(&self) -> @mut CrateContext { self.fcx.ccx } + pub fn tcx(&self) -> ty::ctxt { self.fcx.ccx.tcx } + pub fn sess(&self) -> Session { self.fcx.ccx.sess } - pub fn node_id_to_str(@mut self, id: ast::node_id) -> ~str { + pub fn node_id_to_str(&self, id: ast::node_id) -> ~str { ast_map::node_id_to_str(self.tcx().items, id, self.sess().intr()) } - pub fn expr_to_str(@mut self, e: @ast::expr) -> ~str { + pub fn expr_to_str(&self, e: @ast::expr) -> ~str { e.repr(self.tcx()) } - pub fn expr_is_lval(@mut self, e: @ast::expr) -> bool { + pub fn expr_is_lval(&self, e: &ast::expr) -> bool { ty::expr_is_lval(self.tcx(), self.ccx().maps.method_map, e) } - pub fn expr_kind(@mut self, e: @ast::expr) -> ty::ExprKind { + pub fn expr_kind(&self, e: &ast::expr) -> ty::ExprKind { ty::expr_kind(self.tcx(), self.ccx().maps.method_map, e) } - pub fn def(@mut self, nid: ast::node_id) -> ast::def { + pub fn def(&self, nid: ast::node_id) -> ast::def { match self.tcx().def_map.find(&nid) { Some(&v) => v, None => { @@ -695,19 +620,19 @@ impl block_ { } } - pub fn val_str(@mut self, val: ValueRef) -> @str { - val_str(self.ccx().tn, val) + pub fn val_to_str(&self, val: ValueRef) -> ~str { + self.ccx().tn.val_to_str(val) } - pub fn llty_str(@mut self, llty: TypeRef) -> @str { - ty_str(self.ccx().tn, llty) + pub fn llty_str(&self, ty: Type) -> ~str { + self.ccx().tn.type_to_str(ty) } - pub fn ty_to_str(@mut self, t: ty::t) -> ~str { + pub fn ty_to_str(&self, t: ty::t) -> ~str { t.repr(self.tcx()) } - pub fn to_str(@mut self) -> ~str { + pub fn to_str(&self) -> ~str { unsafe { match self.node_info { Some(node_info) => fmt!("[block %d]", node_info.id), @@ -717,347 +642,44 @@ impl block_ { } } -// LLVM type constructors. -pub fn T_void() -> TypeRef { - unsafe { return llvm::LLVMVoidTypeInContext(base::task_llcx()); } -} - -pub fn T_nil() -> TypeRef { - return T_struct([], false) -} - -pub fn T_metadata() -> TypeRef { - unsafe { return llvm::LLVMMetadataTypeInContext(base::task_llcx()); } -} - -pub fn T_i1() -> TypeRef { - unsafe { return llvm::LLVMInt1TypeInContext(base::task_llcx()); } -} - -pub fn T_i8() -> TypeRef { - unsafe { return llvm::LLVMInt8TypeInContext(base::task_llcx()); } -} - -pub fn T_i16() -> TypeRef { - unsafe { return llvm::LLVMInt16TypeInContext(base::task_llcx()); } -} - -pub fn T_i32() -> TypeRef { - unsafe { return llvm::LLVMInt32TypeInContext(base::task_llcx()); } -} - -pub fn T_i64() -> TypeRef { - unsafe { return llvm::LLVMInt64TypeInContext(base::task_llcx()); } -} - -pub fn T_f32() -> TypeRef { - unsafe { return llvm::LLVMFloatTypeInContext(base::task_llcx()); } -} - -pub fn T_f64() -> TypeRef { - unsafe { return llvm::LLVMDoubleTypeInContext(base::task_llcx()); } -} - -pub fn T_bool() -> TypeRef { return T_i8(); } - -pub fn T_int(targ_cfg: &session::config) -> TypeRef { - return match targ_cfg.arch { - X86 => T_i32(), - X86_64 => T_i64(), - Arm => T_i32(), - Mips => T_i32() - }; -} - -pub fn T_int_ty(cx: &CrateContext, t: ast::int_ty) -> TypeRef { - match t { - ast::ty_i => cx.int_type, - ast::ty_char => T_char(), - ast::ty_i8 => T_i8(), - ast::ty_i16 => T_i16(), - ast::ty_i32 => T_i32(), - ast::ty_i64 => T_i64() - } -} - -pub fn T_uint_ty(cx: &CrateContext, t: ast::uint_ty) -> TypeRef { - match t { - ast::ty_u => cx.int_type, - ast::ty_u8 => T_i8(), - ast::ty_u16 => T_i16(), - ast::ty_u32 => T_i32(), - ast::ty_u64 => T_i64() - } -} - -pub fn T_float_ty(cx: &CrateContext, t: ast::float_ty) -> TypeRef { - match t { - ast::ty_f => cx.float_type, - ast::ty_f32 => T_f32(), - ast::ty_f64 => T_f64() - } -} - -pub fn T_float(targ_cfg: &session::config) -> TypeRef { - return match targ_cfg.arch { - X86 => T_f64(), - X86_64 => T_f64(), - Arm => T_f64(), - Mips => T_f64() - }; -} - -pub fn T_char() -> TypeRef { return T_i32(); } - -pub fn T_size_t(targ_cfg: &session::config) -> TypeRef { - return T_int(targ_cfg); -} - -pub fn T_fn(inputs: &[TypeRef], output: TypeRef) -> TypeRef { - unsafe { - return llvm::LLVMFunctionType(output, to_ptr(inputs), - inputs.len() as c_uint, - False); - } -} - -pub fn T_fn_pair(cx: &CrateContext, tfn: TypeRef) -> TypeRef { - return T_struct([T_ptr(tfn), T_opaque_cbox_ptr(cx)], false); -} - -pub fn T_ptr(t: TypeRef) -> TypeRef { - unsafe { - return llvm::LLVMPointerType(t, default_addrspace); - } -} - -pub fn T_root(t: TypeRef, addrspace: addrspace) -> TypeRef { - unsafe { - return llvm::LLVMPointerType(t, addrspace); - } -} - -pub fn T_struct(elts: &[TypeRef], packed: bool) -> TypeRef { - unsafe { - return llvm::LLVMStructTypeInContext(base::task_llcx(), - to_ptr(elts), - elts.len() as c_uint, - packed as Bool); - } -} - -pub fn T_named_struct(name: &str) -> TypeRef { - unsafe { - return str::as_c_str(name, |buf| { - llvm::LLVMStructCreateNamed(base::task_llcx(), buf) - }); - } -} - -pub fn set_struct_body(t: TypeRef, elts: &[TypeRef], packed: bool) { - unsafe { - llvm::LLVMStructSetBody(t, - to_ptr(elts), - elts.len() as c_uint, - packed as Bool); - } -} - -pub fn T_empty_struct() -> TypeRef { return T_struct([], false); } - -// A vtable is, in reality, a vtable pointer followed by zero or more pointers -// to tydescs and other vtables that it closes over. But the types and number -// of those are rarely known to the code that needs to manipulate them, so -// they are described by this opaque type. -pub fn T_vtable() -> TypeRef { T_array(T_ptr(T_i8()), 1u) } - -pub fn T_tydesc_field(cx: &CrateContext, field: uint) -> TypeRef { - // Bit of a kludge: pick the fn typeref out of the tydesc.. - - unsafe { - let mut tydesc_elts: ~[TypeRef] = - vec::from_elem::<TypeRef>(abi::n_tydesc_fields, - T_nil()); - llvm::LLVMGetStructElementTypes(cx.tydesc_type, &mut tydesc_elts[0]); - let t = llvm::LLVMGetElementType(tydesc_elts[field]); - return t; - } -} - -pub fn T_generic_glue_fn(cx: &mut CrateContext) -> TypeRef { - let s = @"glue_fn"; - match name_has_type(cx.tn, s) { - Some(t) => return t, - _ => () - } - let t = T_tydesc_field(cx, abi::tydesc_field_drop_glue); - associate_type(cx.tn, s, t); - return t; -} - -pub fn T_tydesc(targ_cfg: @session::config) -> TypeRef { - let tydesc = T_named_struct("tydesc"); - let tydescpp = T_ptr(T_ptr(tydesc)); - let pvoid = T_ptr(T_i8()); - let glue_fn_ty = - T_ptr(T_fn([T_ptr(T_nil()), tydescpp, pvoid], T_void())); - - let int_type = T_int(targ_cfg); - let elems = - ~[int_type, int_type, - glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty, - T_ptr(T_i8()), T_ptr(T_i8())]; - set_struct_body(tydesc, elems, false); - return tydesc; -} - -pub fn T_array(t: TypeRef, n: uint) -> TypeRef { - unsafe { - return llvm::LLVMArrayType(t, n as c_uint); - } -} - -pub fn T_vector(t: TypeRef, n: uint) -> TypeRef { - unsafe { - return llvm::LLVMVectorType(t, n as c_uint); - } -} - -// Interior vector. -pub fn T_vec2(targ_cfg: &session::config, t: TypeRef) -> TypeRef { - return T_struct([T_int(targ_cfg), // fill - T_int(targ_cfg), // alloc - T_array(t, 0u)], // elements - false); -} - -pub fn T_vec(ccx: &CrateContext, t: TypeRef) -> TypeRef { - return T_vec2(ccx.sess.targ_cfg, t); -} - -// Note that the size of this one is in bytes. -pub fn T_opaque_vec(targ_cfg: @session::config) -> TypeRef { - return T_vec2(targ_cfg, T_i8()); -} - // Let T be the content of a box @T. tuplify_box_ty(t) returns the // representation of @T as a tuple (i.e., the ty::t version of what T_box() // returns). pub fn tuplify_box_ty(tcx: ty::ctxt, t: ty::t) -> ty::t { let ptr = ty::mk_ptr( tcx, - ty::mt {ty: ty::mk_nil(), mutbl: ast::m_imm} + ty::mt {ty: ty::mk_i8(), mutbl: ast::m_imm} ); return ty::mk_tup(tcx, ~[ty::mk_uint(), ty::mk_type(tcx), ptr, ptr, t]); } -pub fn T_box_header_fields(cx: &CrateContext) -> ~[TypeRef] { - let ptr = T_ptr(T_i8()); - return ~[cx.int_type, T_ptr(cx.tydesc_type), ptr, ptr]; -} - -pub fn T_box_header(cx: &CrateContext) -> TypeRef { - return T_struct(T_box_header_fields(cx), false); -} - -pub fn T_box(cx: &CrateContext, t: TypeRef) -> TypeRef { - return T_struct(vec::append(T_box_header_fields(cx), [t]), false); -} - -pub fn T_box_ptr(t: TypeRef) -> TypeRef { - unsafe { - return llvm::LLVMPointerType(t, gc_box_addrspace); - } -} - -pub fn T_opaque_box(cx: &CrateContext) -> TypeRef { - return T_box(cx, T_i8()); -} - -pub fn T_opaque_box_ptr(cx: &CrateContext) -> TypeRef { - return T_box_ptr(T_opaque_box(cx)); -} - -pub fn T_unique(cx: &CrateContext, t: TypeRef) -> TypeRef { - return T_struct(vec::append(T_box_header_fields(cx), [t]), false); -} - -pub fn T_unique_ptr(t: TypeRef) -> TypeRef { - unsafe { - return llvm::LLVMPointerType(t, gc_box_addrspace); - } -} - -pub fn T_port(cx: &CrateContext, _t: TypeRef) -> TypeRef { - return T_struct([cx.int_type], false); // Refcount - -} - -pub fn T_chan(cx: &CrateContext, _t: TypeRef) -> TypeRef { - return T_struct([cx.int_type], false); // Refcount - -} - - -pub fn T_opaque_cbox_ptr(cx: &CrateContext) -> TypeRef { - // closures look like boxes (even when they are ~fn or &fn) - // see trans_closure.rs - return T_opaque_box_ptr(cx); -} - -pub fn T_enum_discrim(cx: &CrateContext) -> TypeRef { - return cx.int_type; -} - -pub fn T_captured_tydescs(cx: &CrateContext, n: uint) -> TypeRef { - return T_struct(vec::from_elem::<TypeRef>(n, T_ptr(cx.tydesc_type)), false); -} - -pub fn T_opaque_trait(cx: &CrateContext, store: ty::TraitStore) -> TypeRef { - match store { - ty::BoxTraitStore => { - T_struct([T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)], false) - } - ty::UniqTraitStore => { - T_struct([T_ptr(cx.tydesc_type), - T_unique_ptr(T_unique(cx, T_i8()))], - false) - } - ty::RegionTraitStore(_) => { - T_struct([T_ptr(cx.tydesc_type), T_ptr(T_i8())], false) - } - } -} - -pub fn T_opaque_port_ptr() -> TypeRef { return T_ptr(T_i8()); } - -pub fn T_opaque_chan_ptr() -> TypeRef { return T_ptr(T_i8()); } - // LLVM constant constructors. -pub fn C_null(t: TypeRef) -> ValueRef { +pub fn C_null(t: Type) -> ValueRef { unsafe { - return llvm::LLVMConstNull(t); + llvm::LLVMConstNull(t.to_ref()) } } -pub fn C_undef(t: TypeRef) -> ValueRef { +pub fn C_undef(t: Type) -> ValueRef { unsafe { - return llvm::LLVMGetUndef(t); + llvm::LLVMGetUndef(t.to_ref()) } } -pub fn C_integral(t: TypeRef, u: u64, sign_extend: Bool) -> ValueRef { +pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { unsafe { - return llvm::LLVMConstInt(t, u, sign_extend); + llvm::LLVMConstInt(t.to_ref(), u, sign_extend as Bool) } } -pub fn C_floating(s: &str, t: TypeRef) -> ValueRef { +pub fn C_floating(s: &str, t: Type) -> ValueRef { unsafe { - return str::as_c_str(s, |buf| llvm::LLVMConstRealOfString(t, buf)); + do s.as_c_str |buf| { + llvm::LLVMConstRealOfString(t.to_ref(), buf) + } } } @@ -1065,32 +687,32 @@ pub fn C_nil() -> ValueRef { return C_struct([]); } -pub fn C_bool(b: bool) -> ValueRef { - C_integral(T_bool(), if b { 1u64 } else { 0u64 }, False) +pub fn C_bool(val: bool) -> ValueRef { + C_integral(Type::bool(), val as u64, false) } -pub fn C_i1(b: bool) -> ValueRef { - return C_integral(T_i1(), if b { 1 } else { 0 }, False); +pub fn C_i1(val: bool) -> ValueRef { + C_integral(Type::i1(), val as u64, false) } pub fn C_i32(i: i32) -> ValueRef { - return C_integral(T_i32(), i as u64, True); + return C_integral(Type::i32(), i as u64, true); } pub fn C_i64(i: i64) -> ValueRef { - return C_integral(T_i64(), i as u64, True); + return C_integral(Type::i64(), i as u64, true); } pub fn C_int(cx: &CrateContext, i: int) -> ValueRef { - return C_integral(cx.int_type, i as u64, True); + return C_integral(cx.int_type, i as u64, true); } pub fn C_uint(cx: &CrateContext, i: uint) -> ValueRef { - return C_integral(cx.int_type, i as u64, False); + return C_integral(cx.int_type, i as u64, false); } pub fn C_u8(i: uint) -> ValueRef { - return C_integral(T_i8(), i as u64, False); + return C_integral(Type::i8(), i as u64, false); } @@ -1098,18 +720,19 @@ pub fn C_u8(i: uint) -> ValueRef { // our boxed-and-length-annotated strings. pub fn C_cstr(cx: &mut CrateContext, s: @str) -> ValueRef { unsafe { - match cx.const_cstr_cache.find(&s) { + match cx.const_cstr_cache.find_equiv(&s) { Some(&llval) => return llval, None => () } - let sc = do str::as_c_str(s) |buf| { - llvm::LLVMConstStringInContext(cx.llcx, buf, s.len() as c_uint, - False) + let sc = do s.as_c_str |buf| { + llvm::LLVMConstStringInContext(cx.llcx, buf, s.len() as c_uint, False) + }; + + let gsym = token::gensym("str"); + let g = do fmt!("str%u", gsym).as_c_str |buf| { + llvm::LLVMAddGlobal(cx.llmod, val_ty(sc).to_ref(), buf) }; - let g = - str::as_c_str(fmt!("str%u", (cx.names)("str").name), - |buf| llvm::LLVMAddGlobal(cx.llmod, val_ty(sc), buf)); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage); @@ -1125,7 +748,7 @@ pub fn C_cstr(cx: &mut CrateContext, s: @str) -> ValueRef { pub fn C_estr_slice(cx: &mut CrateContext, s: @str) -> ValueRef { unsafe { let len = s.len(); - let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s), T_ptr(T_i8())); + let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s), Type::i8p().to_ref()); C_struct([cs, C_uint(cx, len + 1u /* +1 for null */)]) } } @@ -1133,10 +756,9 @@ pub fn C_estr_slice(cx: &mut CrateContext, s: @str) -> ValueRef { // Returns a Plain Old LLVM String: pub fn C_postr(s: &str) -> ValueRef { unsafe { - return do str::as_c_str(s) |buf| { - llvm::LLVMConstStringInContext(base::task_llcx(), - buf, s.len() as c_uint, False) - }; + do s.as_c_str |buf| { + llvm::LLVMConstStringInContext(base::task_llcx(), buf, s.len() as c_uint, False) + } } } @@ -1145,17 +767,15 @@ pub fn C_zero_byte_arr(size: uint) -> ValueRef { let mut i = 0u; let mut elts: ~[ValueRef] = ~[]; while i < size { elts.push(C_u8(0u)); i += 1u; } - return llvm::LLVMConstArray(T_i8(), - vec::raw::to_ptr(elts), - elts.len() as c_uint); + return llvm::LLVMConstArray(Type::i8().to_ref(), + vec::raw::to_ptr(elts), elts.len() as c_uint); } } pub fn C_struct(elts: &[ValueRef]) -> ValueRef { unsafe { do vec::as_imm_buf(elts) |ptr, len| { - llvm::LLVMConstStructInContext(base::task_llcx(), - ptr, len as c_uint, False) + llvm::LLVMConstStructInContext(base::task_llcx(), ptr, len as c_uint, False) } } } @@ -1163,32 +783,29 @@ pub fn C_struct(elts: &[ValueRef]) -> ValueRef { pub fn C_packed_struct(elts: &[ValueRef]) -> ValueRef { unsafe { do vec::as_imm_buf(elts) |ptr, len| { - llvm::LLVMConstStructInContext(base::task_llcx(), - ptr, len as c_uint, True) + llvm::LLVMConstStructInContext(base::task_llcx(), ptr, len as c_uint, True) } } } -pub fn C_named_struct(T: TypeRef, elts: &[ValueRef]) -> ValueRef { +pub fn C_named_struct(T: Type, elts: &[ValueRef]) -> ValueRef { unsafe { do vec::as_imm_buf(elts) |ptr, len| { - llvm::LLVMConstNamedStruct(T, ptr, len as c_uint) + llvm::LLVMConstNamedStruct(T.to_ref(), ptr, len as c_uint) } } } -pub fn C_array(ty: TypeRef, elts: &[ValueRef]) -> ValueRef { +pub fn C_array(ty: Type, elts: &[ValueRef]) -> ValueRef { unsafe { - return llvm::LLVMConstArray(ty, vec::raw::to_ptr(elts), - elts.len() as c_uint); + return llvm::LLVMConstArray(ty.to_ref(), vec::raw::to_ptr(elts), elts.len() as c_uint); } } pub fn C_bytes(bytes: &[u8]) -> ValueRef { unsafe { - return llvm::LLVMConstStringInContext(base::task_llcx(), - cast::transmute(vec::raw::to_ptr(bytes)), - bytes.len() as c_uint, True); + let ptr = cast::transmute(vec::raw::to_ptr(bytes)); + return llvm::LLVMConstStringInContext(base::task_llcx(), ptr, bytes.len() as c_uint, True); } } @@ -1200,20 +817,6 @@ pub fn C_bytes_plus_null(bytes: &[u8]) -> ValueRef { } } -pub fn C_shape(ccx: &CrateContext, bytes: ~[u8]) -> ValueRef { - unsafe { - let llshape = C_bytes_plus_null(bytes); - let name = fmt!("shape%u", (ccx.names)("shape").name); - let llglobal = str::as_c_str(name, |buf| { - llvm::LLVMAddGlobal(ccx.llmod, val_ty(llshape), buf) - }); - llvm::LLVMSetInitializer(llglobal, llshape); - llvm::LLVMSetGlobalConstant(llglobal, True); - lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage); - return llvm::LLVMConstPointerCast(llglobal, T_ptr(T_i8())); - } -} - pub fn get_param(fndecl: ValueRef, param: uint) -> ValueRef { unsafe { llvm::LLVMGetParam(fndecl, param as c_uint) @@ -1228,7 +831,7 @@ pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint]) }; debug!("const_get_elt(v=%s, us=%?, r=%s)", - val_str(cx.tn, v), us, val_str(cx.tn, r)); + cx.tn.val_to_str(v), us, cx.tn.val_to_str(r)); return r; } @@ -1259,7 +862,7 @@ pub fn is_null(val: ValueRef) -> bool { } // Used to identify cached monomorphized functions and vtables -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub enum mono_param_id { mono_precise(ty::t, Option<@~[mono_id]>), mono_any, @@ -1269,7 +872,7 @@ pub enum mono_param_id { datum::DatumMode), } -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub enum MonoDataClass { MonoBits, // Anything not treated differently from arbitrary integer data MonoNonNull, // Non-null pointers (used for optional-pointer optimization) @@ -1294,7 +897,7 @@ pub fn mono_data_classify(t: ty::t) -> MonoDataClass { } -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct mono_id_ { def: ast::def_id, params: ~[mono_param_id], @@ -1303,40 +906,6 @@ pub struct mono_id_ { pub type mono_id = @mono_id_; -impl to_bytes::IterBytes for mono_param_id { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - mono_precise(t, ref mids) => { - 0u8.iter_bytes(lsb0, f) && - ty::type_id(t).iter_bytes(lsb0, f) && - mids.iter_bytes(lsb0, f) - } - - mono_any => 1u8.iter_bytes(lsb0, f), - - mono_repr(ref a, ref b, ref c, ref d) => { - 2u8.iter_bytes(lsb0, f) && - a.iter_bytes(lsb0, f) && - b.iter_bytes(lsb0, f) && - c.iter_bytes(lsb0, f) && - d.iter_bytes(lsb0, f) - } - } - } -} - -impl to_bytes::IterBytes for MonoDataClass { - fn iter_bytes(&self, lsb0: bool, f:to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for mono_id_ { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.def.iter_bytes(lsb0, f) && self.params.iter_bytes(lsb0, f) - } -} - pub fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef { let cond = build::ICmp(cx, lib::llvm::IntULT, a, b); return build::Select(cx, cond, b, a); @@ -1356,12 +925,15 @@ pub fn align_to(cx: block, off: ValueRef, align: ValueRef) -> ValueRef { pub fn path_str(sess: session::Session, p: &[path_elt]) -> ~str { let mut r = ~""; let mut first = true; - for p.each |e| { + for p.iter().advance |e| { match *e { ast_map::path_name(s) | ast_map::path_mod(s) => { - if first { first = false; } - else { r += "::"; } - r += sess.str_of(s); + if first { + first = false + } else { + r.push_str("::") + } + r.push_str(sess.str_of(s)); } } } @@ -1373,7 +945,11 @@ pub fn monomorphize_type(bcx: block, t: ty::t) -> ty::t { Some(substs) => { ty::subst_tps(bcx.tcx(), substs.tys, substs.self_ty, t) } - _ => { assert!(!ty::type_has_params(t)); t } + _ => { + assert!(!ty::type_has_params(t)); + assert!(!ty::type_has_self(t)); + t + } } } @@ -1383,11 +959,11 @@ pub fn node_id_type(bcx: block, id: ast::node_id) -> ty::t { monomorphize_type(bcx, t) } -pub fn expr_ty(bcx: block, ex: @ast::expr) -> ty::t { +pub fn expr_ty(bcx: block, ex: &ast::expr) -> ty::t { node_id_type(bcx, ex.id) } -pub fn expr_ty_adjusted(bcx: block, ex: @ast::expr) -> ty::t { +pub fn expr_ty_adjusted(bcx: block, ex: &ast::expr) -> ty::t { let tcx = bcx.tcx(); let t = ty::expr_ty_adjusted(tcx, ex); monomorphize_type(bcx, t) @@ -1397,7 +973,7 @@ pub fn node_id_type_params(bcx: block, id: ast::node_id) -> ~[ty::t] { let tcx = bcx.tcx(); let params = ty::node_id_to_type_params(tcx, id); - if !params.all(|t| !ty::type_needs_infer(*t)) { + if !params.iter().all(|t| !ty::type_needs_infer(*t)) { bcx.sess().bug( fmt!("Type parameters for node %d include inference types: %s", id, params.map(|t| bcx.ty_to_str(*t)).connect(","))); @@ -1405,9 +981,9 @@ pub fn node_id_type_params(bcx: block, id: ast::node_id) -> ~[ty::t] { match bcx.fcx.param_substs { Some(substs) => { - do vec::map(params) |t| { + do params.iter().transform |t| { ty::subst_tps(tcx, substs.tys, substs.self_ty, *t) - } + }.collect() } _ => params } @@ -1422,29 +998,52 @@ pub fn node_vtables(bcx: block, id: ast::node_id) pub fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res) -> typeck::vtable_res { - @vec::map(*vts, |d| resolve_vtable_in_fn_ctxt(fcx, copy *d)) + resolve_vtables_under_param_substs(fcx.ccx.tcx, + fcx.param_substs, + vts) } +pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt, + param_substs: Option<@param_substs>, + vts: typeck::vtable_res) + -> typeck::vtable_res { + @vts.iter().transform(|ds| + @ds.iter().transform( + |d| resolve_vtable_under_param_substs(tcx, param_substs, copy *d)) + .collect::<~[typeck::vtable_origin]>()) + .collect::<~[typeck::vtable_param_res]>() +} + + // Apply the typaram substitutions in the fn_ctxt to a vtable. This should // eliminate any vtable_params. pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin) -> typeck::vtable_origin { - let tcx = fcx.ccx.tcx; + resolve_vtable_under_param_substs(fcx.ccx.tcx, + fcx.param_substs, + vt) +} + +pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt, + param_substs: Option<@param_substs>, + vt: typeck::vtable_origin) + -> typeck::vtable_origin { match vt { typeck::vtable_static(trait_id, tys, sub) => { - let tys = match fcx.param_substs { + let tys = match param_substs { Some(substs) => { - do vec::map(tys) |t| { + do tys.iter().transform |t| { ty::subst_tps(tcx, substs.tys, substs.self_ty, *t) - } + }.collect() } _ => tys }; - typeck::vtable_static(trait_id, tys, - resolve_vtables_in_fn_ctxt(fcx, sub)) + typeck::vtable_static( + trait_id, tys, + resolve_vtables_under_param_substs(tcx, param_substs, sub)) } typeck::vtable_param(n_param, n_bound) => { - match fcx.param_substs { + match param_substs { Some(substs) => { find_vtable(tcx, substs, n_param, n_bound) } @@ -1455,6 +1054,19 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin) } } } + typeck::vtable_self(_trait_id) => { + match param_substs { + Some(@param_substs + {self_vtable: Some(ref self_vtable), _}) => { + copy *self_vtable + } + _ => { + tcx.sess.bug(fmt!( + "resolve_vtable_in_fn_ctxt: asked to lookup but \ + no self_vtable in the fn_ctxt!")) + } + } + } } } @@ -1464,13 +1076,7 @@ pub fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)", n_param, n_bound, ps.repr(tcx)); - // Vtables are stored in a flat array, finding the right one is - // somewhat awkward - let first_n_type_param_defs = ps.type_param_defs.slice(0, n_param); - let vtables_to_skip = - ty::count_traits_and_supertraits(tcx, first_n_type_param_defs); - let vtable_off = vtables_to_skip + n_bound; - /*bad*/ copy ps.vtables.get()[vtable_off] + /*bad*/ copy ps.vtables.get()[n_param][n_bound] } pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs { @@ -1485,7 +1091,7 @@ pub fn filename_and_line_num_from_span(bcx: block, span: span) -> (ValueRef, ValueRef) { let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo); let filename_cstr = C_cstr(bcx.ccx(), loc.file.name); - let filename = build::PointerCast(bcx, filename_cstr, T_ptr(T_i8())); + let filename = build::PointerCast(bcx, filename_cstr, Type::i8p()); let line = C_int(bcx.ccx(), loc.line as int); (filename, line) } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index f6b1ba0ffe4..9566f41a45f 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use back::abi; -use lib::llvm::{llvm, ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, TypeRef, Bool, - True, False}; +use lib::llvm::{llvm, ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True}; use lib::llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE, RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE}; @@ -20,7 +18,7 @@ use metadata::csearch; use middle::const_eval; use middle::trans::adt; use middle::trans::base; -use middle::trans::base::get_insn_ctxt; +use middle::trans::base::push_ctxt; use middle::trans::common::*; use middle::trans::consts; use middle::trans::expr; @@ -30,36 +28,38 @@ use middle::trans::type_of; use middle::ty; use util::ppaux::{Repr, ty_to_str}; -use core::libc::c_uint; -use core::str; +use middle::trans::type_::Type; + +use std::libc::c_uint; +use std::str; use syntax::{ast, ast_util, ast_map}; -pub fn const_lit(cx: @mut CrateContext, e: @ast::expr, lit: ast::lit) +pub fn const_lit(cx: &mut CrateContext, e: &ast::expr, lit: ast::lit) -> ValueRef { - let _icx = cx.insn_ctxt("trans_lit"); + let _icx = push_ctxt("trans_lit"); match lit.node { - ast::lit_int(i, t) => C_integral(T_int_ty(cx, t), i as u64, True), - ast::lit_uint(u, t) => C_integral(T_uint_ty(cx, t), u, False), + ast::lit_int(i, t) => C_integral(Type::int_from_ty(cx, t), i as u64, true), + ast::lit_uint(u, t) => C_integral(Type::uint_from_ty(cx, t), u, false), ast::lit_int_unsuffixed(i) => { let lit_int_ty = ty::node_id_to_type(cx.tcx, e.id); match ty::get(lit_int_ty).sty { ty::ty_int(t) => { - C_integral(T_int_ty(cx, t), i as u64, True) + C_integral(Type::int_from_ty(cx, t), i as u64, true) } ty::ty_uint(t) => { - C_integral(T_uint_ty(cx, t), i as u64, False) + C_integral(Type::uint_from_ty(cx, t), i as u64, false) } _ => cx.sess.span_bug(lit.span, fmt!("integer literal has type %s (expected int or uint)", ty_to_str(cx.tcx, lit_int_ty))) } } - ast::lit_float(fs, t) => C_floating(fs, T_float_ty(cx, t)), + ast::lit_float(fs, t) => C_floating(fs, Type::float_from_ty(cx, t)), ast::lit_float_unsuffixed(fs) => { let lit_float_ty = ty::node_id_to_type(cx.tcx, e.id); match ty::get(lit_float_ty).sty { ty::ty_float(t) => { - C_floating(fs, T_float_ty(cx, t)) + C_floating(fs, Type::float_from_ty(cx, t)) } _ => { cx.sess.span_bug(lit.span, @@ -73,16 +73,16 @@ pub fn const_lit(cx: @mut CrateContext, e: @ast::expr, lit: ast::lit) } } -pub fn const_ptrcast(cx: &mut CrateContext, a: ValueRef, t: TypeRef) -> ValueRef { +pub fn const_ptrcast(cx: &mut CrateContext, a: ValueRef, t: Type) -> ValueRef { unsafe { - let b = llvm::LLVMConstPointerCast(a, T_ptr(t)); + let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref()); assert!(cx.const_globals.insert(b as int, a)); b } } -pub fn const_vec(cx: @mut CrateContext, e: @ast::expr, es: &[@ast::expr]) - -> (ValueRef, ValueRef, TypeRef) { +pub fn const_vec(cx: @mut CrateContext, e: &ast::expr, es: &[@ast::expr]) + -> (ValueRef, ValueRef, Type) { unsafe { let vec_ty = ty::expr_ty(cx.tcx, e); let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty); @@ -91,7 +91,7 @@ pub fn const_vec(cx: @mut CrateContext, e: @ast::expr, es: &[@ast::expr]) let sz = llvm::LLVMConstMul(C_uint(cx, es.len()), unit_sz); let vs = es.map(|e| const_expr(cx, *e)); // If the vector contains enums, an LLVM array won't work. - let v = if vs.any(|vi| val_ty(*vi) != llunitty) { + let v = if vs.iter().any_(|vi| val_ty(*vi) != llunitty) { C_struct(vs) } else { C_array(llunitty, vs) @@ -100,10 +100,10 @@ pub fn const_vec(cx: @mut CrateContext, e: @ast::expr, es: &[@ast::expr]) } } -fn const_addr_of(cx: @mut CrateContext, cv: ValueRef) -> ValueRef { +fn const_addr_of(cx: &mut CrateContext, cv: ValueRef) -> ValueRef { unsafe { - let gv = do str::as_c_str("const") |name| { - llvm::LLVMAddGlobal(cx.llmod, val_ty(cv), name) + let gv = do "const".as_c_str |name| { + llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name) }; llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetGlobalConstant(gv, True); @@ -112,7 +112,7 @@ fn const_addr_of(cx: @mut CrateContext, cv: ValueRef) -> ValueRef { } } -fn const_deref_ptr(cx: @mut CrateContext, v: ValueRef) -> ValueRef { +fn const_deref_ptr(cx: &mut CrateContext, v: ValueRef) -> ValueRef { let v = match cx.const_globals.find(&(v as int)) { Some(&v) => v, None => v @@ -123,13 +123,13 @@ fn const_deref_ptr(cx: @mut CrateContext, v: ValueRef) -> ValueRef { } } -fn const_deref_newtype(cx: @mut CrateContext, v: ValueRef, t: ty::t) +fn const_deref_newtype(cx: &mut CrateContext, v: ValueRef, t: ty::t) -> ValueRef { let repr = adt::represent_type(cx, t); adt::const_get_field(cx, repr, v, 0, 0) } -fn const_deref(cx: @mut CrateContext, v: ValueRef, t: ty::t, explicit: bool) +fn const_deref(cx: &mut CrateContext, v: ValueRef, t: ty::t, explicit: bool) -> (ValueRef, ty::t) { match ty::deref(cx.tcx, t, explicit) { Some(ref mt) => { @@ -163,9 +163,9 @@ pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::def_id) -> ValueRef } match cx.tcx.items.get_copy(&def_id.node) { ast_map::node_item(@ast::item { - node: ast::item_const(_, subexpr), _ + node: ast::item_static(_, ast::m_imm, _), _ }, _) => { - trans_const(cx, subexpr, def_id.node); + trans_const(cx, ast::m_imm, def_id.node); } _ => cx.tcx.sess.bug("expected a const to be an item") } @@ -180,7 +180,7 @@ pub fn const_expr(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { match adjustment { None => { } Some(@ty::AutoAddEnv(ty::re_static, ast::BorrowedSigil)) => { - llconst = C_struct([llconst, C_null(T_opaque_box_ptr(cx))]) + llconst = C_struct([llconst, C_null(Type::opaque_box(cx).ptr_to())]) } Some(@ty::AutoAddEnv(ref r, ref s)) => { cx.sess.span_bug(e.span, fmt!("unexpected static function: \ @@ -246,9 +246,9 @@ pub fn const_expr(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { llconst } -fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { +fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef { unsafe { - let _icx = cx.insn_ctxt("const_expr"); + let _icx = push_ctxt("const_expr"); return match e.node { ast::expr_lit(lit) => consts::const_lit(cx, e, *lit), ast::expr_binary(_, b, e1, e2) => { @@ -339,7 +339,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { let is_float = ty::type_is_fp(ty); return match u { ast::box(_) | - ast::uniq(_) | + ast::uniq | ast::deref => { let (dv, _dt) = const_deref(cx, te, ty, true); dv @@ -349,9 +349,9 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { ty::ty_bool => { // Somewhat questionable, but I believe this is // correct. - let te = llvm::LLVMConstTrunc(te, T_i1()); + let te = llvm::LLVMConstTrunc(te, Type::i1().to_ref()); let te = llvm::LLVMConstNot(te); - llvm::LLVMConstZExt(te, T_bool()) + llvm::LLVMConstZExt(te, Type::bool().to_ref()) } _ => llvm::LLVMConstNot(te), } @@ -392,7 +392,8 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { let llunitty = type_of::type_of(cx, unit_ty); let unit_sz = machine::llsize_of(cx, llunitty); - (const_deref_ptr(cx, const_get_elt(cx, bv, [0])), + let e1 = const_get_elt(cx, bv, [0]); + (const_deref_ptr(cx, e1), llvm::LLVMConstUDiv(const_get_elt(cx, bv, [1]), unit_sz)) }, @@ -426,21 +427,21 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { (expr::cast_integral, expr::cast_integral) => { let s = ty::type_is_signed(basety) as Bool; - llvm::LLVMConstIntCast(v, llty, s) + llvm::LLVMConstIntCast(v, llty.to_ref(), s) } (expr::cast_integral, expr::cast_float) => { if ty::type_is_signed(basety) { - llvm::LLVMConstSIToFP(v, llty) + llvm::LLVMConstSIToFP(v, llty.to_ref()) } else { - llvm::LLVMConstUIToFP(v, llty) + llvm::LLVMConstUIToFP(v, llty.to_ref()) } } (expr::cast_float, expr::cast_float) => { - llvm::LLVMConstFPCast(v, llty) + llvm::LLVMConstFPCast(v, llty.to_ref()) } (expr::cast_float, expr::cast_integral) => { - if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty) } - else { llvm::LLVMConstFPToUI(v, llty) } + if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty.to_ref()) } + else { llvm::LLVMConstFPToUI(v, llty.to_ref()) } } (expr::cast_enum, expr::cast_integral) | (expr::cast_enum, expr::cast_float) => { @@ -451,18 +452,18 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { match ety_cast { expr::cast_integral => { let s = ty::type_is_signed(ety) as Bool; - llvm::LLVMConstIntCast(iv, llty, s) + llvm::LLVMConstIntCast(iv, llty.to_ref(), s) } - expr::cast_float => llvm::LLVMConstUIToFP(iv, llty), + expr::cast_float => llvm::LLVMConstUIToFP(iv, llty.to_ref()), _ => cx.sess.bug("enum cast destination is not \ integral or float") } } (expr::cast_pointer, expr::cast_pointer) => { - llvm::LLVMConstPointerCast(v, llty) + llvm::LLVMConstPointerCast(v, llty.to_ref()) } (expr::cast_integral, expr::cast_pointer) => { - llvm::LLVMConstIntToPtr(v, llty) + llvm::LLVMConstIntToPtr(v, llty.to_ref()) } _ => { cx.sess.impossible_case(e.span, @@ -487,8 +488,8 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { do expr::with_field_tys(tcx, ety, Some(e.id)) |discr, field_tys| { let cs = field_tys.map(|field_ty| { - match fs.find(|f| field_ty.ident == f.node.ident) { - Some(ref f) => const_expr(cx, (*f).node.expr), + match fs.iter().find_(|f| field_ty.ident == f.node.ident) { + Some(f) => const_expr(cx, (*f).node.expr), None => { cx.tcx.sess.span_bug(e.span, "missing struct field"); } @@ -513,7 +514,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { let (cv, sz, llunitty) = const_vec(cx, e, *es); let llty = val_ty(cv); let gv = do str::as_c_str("const") |name| { - llvm::LLVMAddGlobal(cx.llmod, llty, name) + llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name) }; llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetGlobalConstant(gv, True); @@ -537,7 +538,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { base::get_item_val(cx, def_id.node) } } - Some(&ast::def_const(def_id)) => { + Some(&ast::def_static(def_id, false)) => { get_const_val(cx, def_id) } Some(&ast::def_variant(enum_did, variant_did)) => { @@ -586,14 +587,16 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef { } } -pub fn trans_const(ccx: @mut CrateContext, _e: @ast::expr, id: ast::node_id) { +pub fn trans_const(ccx: @mut CrateContext, m: ast::mutability, id: ast::node_id) { unsafe { - let _icx = ccx.insn_ctxt("trans_const"); + let _icx = push_ctxt("trans_const"); let g = base::get_item_val(ccx, id); // At this point, get_item_val has already translated the // constant's initializer to determine its LLVM type. let v = ccx.const_values.get_copy(&id); llvm::LLVMSetInitializer(g, v); - llvm::LLVMSetGlobalConstant(g, True); + if m != ast::m_mutbl { + llvm::LLVMSetGlobalConstant(g, True); + } } } diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index d6c7472424f..c2a32ae041e 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -8,50 +8,45 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use back::{upcall}; use driver::session; -use lib::llvm::{ContextRef, ModuleRef, ValueRef, TypeRef}; +use lib::llvm::{ContextRef, ModuleRef, ValueRef}; use lib::llvm::{llvm, TargetData, TypeNames}; -use lib::llvm::{mk_target_data, mk_type_names}; -use lib; +use lib::llvm::{mk_target_data}; use metadata::common::LinkMeta; use middle::astencode; use middle::resolve; use middle::trans::adt; use middle::trans::base; use middle::trans::debuginfo; -use middle::trans::reachable; -use middle::trans::shape; use middle::trans::type_use; use middle::ty; -use core::hash; -use core::hashmap::{HashMap, HashSet}; -use core::str; -use core::local_data; +use middle::trans::type_::Type; + +use std::hash; +use std::hashmap::{HashMap, HashSet}; +use std::str; +use std::local_data; +use extra::time; use syntax::ast; -use middle::trans::common::{ExternMap,tydesc_info,BuilderRef_res,Stats,namegen,addrspace_gen}; -use middle::trans::common::{mono_id,T_int,T_float,T_tydesc,T_opaque_vec}; -use middle::trans::common::{new_namegen,new_addrspace_gen}; +use middle::trans::common::{mono_id,ExternMap,tydesc_info,BuilderRef_res,Stats}; use middle::trans::base::{decl_crate_map}; -use middle::trans::shape::{mk_ctxt}; - pub struct CrateContext { sess: session::Session, llmod: ModuleRef, llcx: ContextRef, td: TargetData, - tn: @TypeNames, + tn: TypeNames, externs: ExternMap, intrinsics: HashMap<&'static str, ValueRef>, item_vals: HashMap<ast::node_id, ValueRef>, exp_map2: resolve::ExportMap2, - reachable: reachable::map, + reachable: @mut HashSet<ast::node_id>, item_symbols: HashMap<ast::node_id, ~str>, link_meta: LinkMeta, enum_sizes: HashMap<ty::t, uint>, @@ -92,11 +87,9 @@ pub struct CrateContext { impl_method_cache: HashMap<(ast::def_id, ast::ident), ast::def_id>, module_data: HashMap<~str, ValueRef>, - lltypes: HashMap<ty::t, TypeRef>, - llsizingtypes: HashMap<ty::t, TypeRef>, + lltypes: HashMap<ty::t, Type>, + llsizingtypes: HashMap<ty::t, Type>, adt_reprs: HashMap<ty::t, @adt::Repr>, - names: namegen, - next_addrspace: addrspace_gen, symbol_hasher: hash::State, type_hashcodes: HashMap<ty::t, @str>, type_short_names: HashMap<ty::t, ~str>, @@ -105,12 +98,11 @@ pub struct CrateContext { maps: astencode::Maps, stats: Stats, upcalls: @upcall::Upcalls, - tydesc_type: TypeRef, - int_type: TypeRef, - float_type: TypeRef, - opaque_vec_type: TypeRef, + tydesc_type: Type, + int_type: Type, + float_type: Type, + opaque_vec_type: Type, builder: BuilderRef_res, - shape_cx: shape::Ctxt, crate_map: ValueRef, // Set when at least one function uses GC. Needed so that // decl_gc_metadata knows whether to link to the module metadata, which @@ -121,10 +113,15 @@ pub struct CrateContext { } impl CrateContext { - pub fn new(sess: session::Session, name: &str, tcx: ty::ctxt, - emap2: resolve::ExportMap2, maps: astencode::Maps, - symbol_hasher: hash::State, link_meta: LinkMeta, - reachable: reachable::map) -> CrateContext { + pub fn new(sess: session::Session, + name: &str, + tcx: ty::ctxt, + emap2: resolve::ExportMap2, + maps: astencode::Maps, + symbol_hasher: hash::State, + link_meta: LinkMeta, + reachable: @mut HashSet<ast::node_id>) + -> CrateContext { unsafe { let llcx = llvm::LLVMContextCreate(); set_task_llcx(llcx); @@ -136,16 +133,25 @@ impl CrateContext { str::as_c_str(data_layout, |buf| llvm::LLVMSetDataLayout(llmod, buf)); str::as_c_str(targ_triple, |buf| llvm::LLVMSetTarget(llmod, buf)); let targ_cfg = sess.targ_cfg; + let td = mk_target_data(sess.targ_cfg.target_strs.data_layout); - let tn = mk_type_names(); + let mut tn = TypeNames::new(); + let mut intrinsics = base::declare_intrinsics(llmod); if sess.opts.extra_debuginfo { base::declare_dbg_intrinsics(llmod, &mut intrinsics); } - let int_type = T_int(targ_cfg); - let float_type = T_float(targ_cfg); - let tydesc_type = T_tydesc(targ_cfg); - lib::llvm::associate_type(tn, @"tydesc", tydesc_type); + let int_type = Type::int(targ_cfg.arch); + let float_type = Type::float(targ_cfg.arch); + let tydesc_type = Type::tydesc(targ_cfg.arch); + let opaque_vec_type = Type::opaque_vec(targ_cfg.arch); + + let mut str_slice_ty = Type::named_struct("str_slice"); + str_slice_ty.set_struct_body([Type::i8p(), int_type], false); + + tn.associate_type("tydesc", &tydesc_type); + tn.associate_type("str_slice", &str_slice_ty); + let crate_map = decl_crate_map(sess, link_meta, llmod); let dbg_cx = if sess.opts.debuginfo { Some(debuginfo::DebugContext::new(llmod, name.to_owned())) @@ -153,6 +159,10 @@ impl CrateContext { None }; + if sess.count_llvm_insns() { + base::init_insn_ctxt() + } + CrateContext { sess: sess, llmod: llmod, @@ -185,8 +195,6 @@ impl CrateContext { lltypes: HashMap::new(), llsizingtypes: HashMap::new(), adt_reprs: HashMap::new(), - names: new_namegen(), - next_addrspace: new_addrspace_gen(), symbol_hasher: symbol_hasher, type_hashcodes: HashMap::new(), type_short_names: HashMap::new(), @@ -202,7 +210,6 @@ impl CrateContext { n_monos: 0u, n_inlines: 0u, n_closures: 0u, - llvm_insn_ctxt: ~[], llvm_insns: HashMap::new(), fn_times: ~[] }, @@ -210,9 +217,8 @@ impl CrateContext { tydesc_type: tydesc_type, int_type: int_type, float_type: float_type, - opaque_vec_type: T_opaque_vec(targ_cfg), + opaque_vec_type: opaque_vec_type, builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), - shape_cx: mk_ctxt(llmod), crate_map: crate_map, uses_gc: false, dbg_cx: dbg_cx, @@ -220,11 +226,17 @@ impl CrateContext { } } } + + pub fn log_fn_time(&mut self, name: ~str, start: time::Timespec, end: time::Timespec) { + let elapsed = 1000 * ((end.sec - start.sec) as int) + + ((end.nsec as int) - (start.nsec as int)) / 1000000; + self.stats.fn_times.push((name, elapsed)); + } } #[unsafe_destructor] impl Drop for CrateContext { - fn finalize(&self) { + fn drop(&self) { unsafe { unset_task_llcx(); } @@ -232,7 +244,6 @@ impl Drop for CrateContext { } fn task_local_llcx_key(_v: @ContextRef) {} - pub fn task_llcx() -> ContextRef { let opt = unsafe { local_data::local_data_get(task_local_llcx_key) }; *opt.expect("task-local LLVMContextRef wasn't ever set!") diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index fe3e2940907..dc88ecbe936 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use back::link; use lib; @@ -24,8 +23,10 @@ use middle::ty; use util::common::indenter; use util::ppaux; -use core::str; -use core::vec; +use middle::trans::type_::Type; + +use std::str; +use std::vec; use syntax::ast; use syntax::ast::ident; use syntax::ast_map::path_mod; @@ -33,12 +34,12 @@ use syntax::ast_util; use syntax::codemap::span; pub fn trans_block(bcx: block, b: &ast::blk, dest: expr::Dest) -> block { - let _icx = bcx.insn_ctxt("trans_block"); + let _icx = push_ctxt("trans_block"); let mut bcx = bcx; do block_locals(b) |local| { bcx = alloc_local(bcx, local); }; - for b.node.stmts.each |s| { + for b.node.stmts.iter().advance |s| { debuginfo::update_source_pos(bcx, b.span); bcx = trans_stmt(bcx, *s); } @@ -65,7 +66,7 @@ pub fn trans_if(bcx: block, dest.to_str(bcx.ccx())); let _indenter = indenter(); - let _icx = bcx.insn_ctxt("trans_if"); + let _icx = push_ctxt("trans_if"); let Result {bcx, val: cond_val} = expr::trans_to_datum(bcx, cond).to_result(); @@ -111,7 +112,7 @@ pub fn trans_if(bcx: block, pub fn join_blocks(parent_bcx: block, in_cxs: &[block]) -> block { let out = sub_block(parent_bcx, "join"); let mut reachable = false; - for in_cxs.each |bcx| { + for in_cxs.iter().advance |bcx| { if !bcx.unreachable { Br(*bcx, out.llbb); reachable = true; @@ -124,7 +125,7 @@ pub fn join_blocks(parent_bcx: block, in_cxs: &[block]) -> block { } pub fn trans_while(bcx: block, cond: @ast::expr, body: &ast::blk) -> block { - let _icx = bcx.insn_ctxt("trans_while"); + let _icx = push_ctxt("trans_while"); let next_bcx = sub_block(bcx, "while next"); // bcx @@ -166,7 +167,7 @@ pub fn trans_loop(bcx:block, body: &ast::blk, opt_label: Option<ident>) -> block { - let _icx = bcx.insn_ctxt("trans_loop"); + let _icx = push_ctxt("trans_loop"); let next_bcx = sub_block(bcx, "next"); let body_bcx_in = loop_scope_block(bcx, next_bcx, opt_label, "`loop`", body.info()); @@ -176,11 +177,11 @@ pub fn trans_loop(bcx:block, return next_bcx; } -pub fn trans_log(log_ex: @ast::expr, +pub fn trans_log(log_ex: &ast::expr, lvl: @ast::expr, bcx: block, e: @ast::expr) -> block { - let _icx = bcx.insn_ctxt("trans_log"); + let _icx = push_ctxt("trans_log"); let ccx = bcx.ccx(); let mut bcx = bcx; if ty::type_is_bot(expr_ty(bcx, lvl)) { @@ -204,10 +205,10 @@ pub fn trans_log(log_ex: @ast::expr, let global; unsafe { global = str::as_c_str(s, |buf| { - llvm::LLVMAddGlobal(ccx.llmod, T_i32(), buf) + llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf) }); llvm::LLVMSetGlobalConstant(global, False); - llvm::LLVMSetInitializer(global, C_null(T_i32())); + llvm::LLVMSetInitializer(global, C_null(Type::i32())); lib::llvm::SetLinkage(global, lib::llvm::InternalLinkage); } ccx.module_data.insert(modname, global); @@ -242,7 +243,7 @@ pub fn trans_break_cont(bcx: block, opt_label: Option<ident>, to_end: bool) -> block { - let _icx = bcx.insn_ctxt("trans_break_cont"); + let _icx = push_ctxt("trans_break_cont"); // Locate closest loop block, outputting cleanup as we go. let mut unwind = bcx; let mut target; @@ -296,26 +297,29 @@ pub fn trans_cont(bcx: block, label_opt: Option<ident>) -> block { } pub fn trans_ret(bcx: block, e: Option<@ast::expr>) -> block { - let _icx = bcx.insn_ctxt("trans_ret"); + let _icx = push_ctxt("trans_ret"); let mut bcx = bcx; - let retptr = match copy bcx.fcx.loop_ret { + let dest = match copy bcx.fcx.loop_ret { Some((flagptr, retptr)) => { // This is a loop body return. Must set continue flag (our retptr) // to false, return flag to true, and then store the value in the // parent's retptr. Store(bcx, C_bool(true), flagptr); Store(bcx, C_bool(false), bcx.fcx.llretptr.get()); - match e { + expr::SaveIn(match e { Some(x) => PointerCast(bcx, retptr, - T_ptr(type_of(bcx.ccx(), expr_ty(bcx, x)))), + type_of(bcx.ccx(), expr_ty(bcx, x)).ptr_to()), None => retptr - } + }) + } + None => match bcx.fcx.llretptr { + None => expr::Ignore, + Some(retptr) => expr::SaveIn(retptr), } - None => bcx.fcx.llretptr.get() }; match e { Some(x) => { - bcx = expr::trans_into(bcx, x, expr::SaveIn(retptr)); + bcx = expr::trans_into(bcx, x, dest); } _ => () } @@ -328,7 +332,7 @@ pub fn trans_fail_expr(bcx: block, sp_opt: Option<span>, fail_expr: Option<@ast::expr>) -> block { - let _icx = bcx.insn_ctxt("trans_fail_expr"); + let _icx = push_ctxt("trans_fail_expr"); let mut bcx = bcx; match fail_expr { Some(arg_expr) => { @@ -356,7 +360,7 @@ pub fn trans_fail(bcx: block, sp_opt: Option<span>, fail_str: @str) -> block { - let _icx = bcx.insn_ctxt("trans_fail"); + let _icx = push_ctxt("trans_fail"); let V_fail_str = C_cstr(bcx.ccx(), fail_str); return trans_fail_value(bcx, sp_opt, V_fail_str); } @@ -365,7 +369,7 @@ fn trans_fail_value(bcx: block, sp_opt: Option<span>, V_fail_str: ValueRef) -> block { - let _icx = bcx.insn_ctxt("trans_fail_value"); + let _icx = push_ctxt("trans_fail_value"); let ccx = bcx.ccx(); let (V_filename, V_line) = match sp_opt { Some(sp) => { @@ -378,8 +382,8 @@ fn trans_fail_value(bcx: block, (C_cstr(bcx.ccx(), @"<runtime>"), 0) } }; - let V_str = PointerCast(bcx, V_fail_str, T_ptr(T_i8())); - let V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8())); + let V_str = PointerCast(bcx, V_fail_str, Type::i8p()); + let V_filename = PointerCast(bcx, V_filename, Type::i8p()); let args = ~[V_str, V_filename, C_int(ccx, V_line)]; let bcx = callee::trans_lang_call( bcx, bcx.tcx().lang_items.fail_fn(), args, expr::Ignore); @@ -389,7 +393,7 @@ fn trans_fail_value(bcx: block, pub fn trans_fail_bounds_check(bcx: block, sp: span, index: ValueRef, len: ValueRef) -> block { - let _icx = bcx.insn_ctxt("trans_fail_bounds_check"); + let _icx = push_ctxt("trans_fail_bounds_check"); let (filename, line) = filename_and_line_num_from_span(bcx, sp); let args = ~[filename, line, index, len]; let bcx = callee::trans_lang_call( diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index b0276cf0e29..0fe3dfe80c8 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -87,7 +87,6 @@ * methods themselves. Most are only suitable for some types of * values. */ -use core::prelude::*; use lib; use lib::llvm::ValueRef; @@ -105,7 +104,7 @@ use middle::ty; use util::common::indenter; use util::ppaux::ty_to_str; -use core::uint; +use std::uint; use syntax::ast; use syntax::codemap::span; use syntax::parse::token::special_idents; @@ -273,14 +272,14 @@ impl Datum { * `store_to()` instead, which will move if possible but copy if * neccessary. */ - let _icx = bcx.insn_ctxt("copy_to"); + let _icx = push_ctxt("copy_to"); if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) { return bcx; } debug!("copy_to(self=%s, action=%?, dst=%s)", - self.to_str(bcx.ccx()), action, bcx.val_str(dst)); + self.to_str(bcx.ccx()), action, bcx.val_to_str(dst)); // Watch out for the case where we are writing the copying the // value into the same location we read it out from. We want @@ -317,7 +316,7 @@ impl Datum { * A helper for `copy_to()` which does not check to see if we * are copying to/from the same value. */ - let _icx = bcx.insn_ctxt("copy_to_no_check"); + let _icx = push_ctxt("copy_to_no_check"); let mut bcx = bcx; if action == DROP_EXISTING { @@ -341,11 +340,11 @@ impl Datum { // pub fn move_to(&self, bcx: block, action: CopyAction, dst: ValueRef) -> block { - let _icx = bcx.insn_ctxt("move_to"); + let _icx = push_ctxt("move_to"); let mut bcx = bcx; debug!("move_to(self=%s, action=%?, dst=%s)", - self.to_str(bcx.ccx()), action, bcx.val_str(dst)); + self.to_str(bcx.ccx()), action, bcx.val_to_str(dst)); if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) { return bcx; @@ -409,7 +408,7 @@ impl Datum { pub fn to_str(&self, ccx: &CrateContext) -> ~str { fmt!("Datum { val=%s, ty=%s, mode=%? }", - val_str(ccx.tn, self.val), + ccx.tn.val_to_str(self.val), ty_to_str(ccx.tcx, self.ty), self.mode) } @@ -474,7 +473,7 @@ impl Datum { ByRef(_) => self.val, ByValue => { if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) { - C_null(T_ptr(type_of::type_of(bcx.ccx(), self.ty))) + C_null(type_of::type_of(bcx.ccx(), self.ty).ptr_to()) } else { let slot = alloc_ty(bcx, self.ty); Store(bcx, self.val, slot); @@ -723,7 +722,7 @@ impl Datum { } /// expr: The deref expression. - pub fn deref(&self, bcx: block, expr: @ast::expr, derefs: uint) + pub fn deref(&self, bcx: block, expr: &ast::expr, derefs: uint) -> DatumBlock { match self.try_deref(bcx, expr.span, expr.id, derefs, false) { (Some(lvres), bcx) => DatumBlock { bcx: bcx, datum: lvres }, @@ -740,7 +739,7 @@ impl Datum { expr_id: ast::node_id, max: uint) -> DatumBlock { - let _icx = bcx.insn_ctxt("autoderef"); + let _icx = push_ctxt("autoderef"); debug!("autoderef(expr_id=%d, max=%?, self=%?)", expr_id, max, self.to_str(bcx.ccx())); diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 269451b1307..ac5eb6b067c 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -8,7 +8,39 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; +/*! +# Debug Info Module + +This module serves the purpose of generating debug symbols. We use LLVM's +[source level debugging](http://llvm.org/docs/SourceLevelDebugging.html) features for generating +the debug information. The general principle is this: + +Given the right metadata in the LLVM IR, the LLVM code generator is able to create DWARF debug +symbols for the given code. The [metadata](http://llvm.org/docs/LangRef.html#metadata-type) is +structured much like DWARF *debugging information entries* (DIE), representing type information +such as datatype layout, function signatures, block layout, variable location and scope information, +etc. It is the purpose of this module to generate correct metadata and insert it into the LLVM IR. + +As the exact format of metadata trees may change between different LLVM versions, we now use LLVM +[DIBuilder](http://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) to create metadata +where possible. This will hopefully ease the adaption of this module to future LLVM versions. + +The public API of the module is a set of functions that will insert the correct metadata into the +LLVM IR when called with the right parameters. The module is thus driven from an outside client with +functions like `debuginfo::create_local_var(bcx: block, local: @ast::local)`. + +Internally the module will try to reuse already created metadata by utilizing a cache. All private +state used by the module is stored within a DebugContext struct, which in turn is contained in the +CrateContext. + + +This file consists of three conceptual sections: +1. The public interface of the module +2. Module-internal metadata creation functions +3. Minor utility functions + +*/ + use driver::session; use lib::llvm::llvm; @@ -21,33 +53,22 @@ use middle::trans; use middle::ty; use util::ppaux::ty_to_str; -use core::hashmap::HashMap; -use core::libc; -use core::libc::c_uint; -use core::cmp; -use core::ptr; -use core::str::as_c_str; -use core::sys; -use core::vec; +use std::hashmap::HashMap; +use std::libc; +use std::libc::{c_uint, c_ulonglong}; +use std::cmp; +use std::ptr; +use std::str::as_c_str; +use std::sys; +use std::vec; use syntax::codemap::span; use syntax::{ast, codemap, ast_util, ast_map}; +use syntax::parse::token; static DW_LANG_RUST: int = 0x9000; -static CompileUnitTag: int = 17; -static FileDescriptorTag: int = 41; -static SubprogramTag: int = 46; -static SubroutineTag: int = 21; -static BasicTypeDescriptorTag: int = 36; static AutoVariableTag: int = 256; static ArgVariableTag: int = 257; -static ReturnVariableTag: int = 258; -static LexicalBlockTag: int = 11; -static PointerTypeTag: int = 15; -static StructureTypeTag: int = 19; -static MemberTag: int = 13; -static ArrayTypeTag: int = 1; -static SubrangeTag: int = 33; static DW_ATE_boolean: int = 0x02; static DW_ATE_float: int = 0x04; @@ -56,10 +77,15 @@ static DW_ATE_signed_char: int = 0x06; static DW_ATE_unsigned: int = 0x07; static DW_ATE_unsigned_char: int = 0x08; -//////////////// + + +//=------------------------------------------------------------------------------------------------- +// Public Interface of debuginfo module +//=------------------------------------------------------------------------------------------------- + +/// A context object for maintaining all state needed by the debuginfo module. pub struct DebugContext { - names: namegen, crate_file: ~str, llcontext: ContextRef, builder: DIBuilderRef, @@ -77,7 +103,6 @@ impl DebugContext { // DIBuilder inherits context from the module, so we'd better use the same one let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; return DebugContext { - names: new_namegen(), crate_file: crate, llcontext: llcontext, builder: builder, @@ -90,16 +115,6 @@ impl DebugContext { } } -#[inline] -fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext { - cx.dbg_cx.get_mut_ref() -} - -#[inline] -fn DIB(cx: &CrateContext) -> DIBuilderRef { - cx.dbg_cx.get_ref().builder -} - /// Create any deferred debug metadata nodes pub fn finalize(cx: @mut CrateContext) { debug!("finalize"); @@ -110,6 +125,223 @@ pub fn finalize(cx: @mut CrateContext) { }; } +/// Creates debug information for the given local variable. +/// +/// Adds the created metadata nodes directly to the crate's IR. +/// The return value should be ignored if called from outside of the debuginfo module. +pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable { + let cx = bcx.ccx(); + + let ident = match local.node.pat.node { + ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth), + // FIXME this should be handled (#2533) + _ => { + bcx.sess().span_note(local.span, "debuginfo for pattern bindings NYI"); + return ptr::null(); + } + }; + let name: &str = cx.sess.str_of(ident); + debug!("create_local_var: %s", name); + + let loc = span_start(cx, local.span); + let ty = node_id_type(bcx, local.node.id); + let tymd = create_ty(cx, ty, local.node.ty.span); + let filemd = create_file(cx, loc.file.name); + let context = match bcx.parent { + None => create_function(bcx.fcx), + Some(_) => create_block(bcx) + }; + + let var_md = do as_c_str(name) |name| { unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), AutoVariableTag as u32, + context, name, filemd, + loc.line as c_uint, tymd, false, 0, 0) + }}; + + // FIXME(#6814) Should use `pat_util::pat_bindings` for pats like (a, b) etc + let llptr = match bcx.fcx.lllocals.find_copy(&local.node.pat.id) { + Some(v) => v, + None => { + bcx.tcx().sess.span_bug( + local.span, + fmt!("No entry in lllocals table for %?", local.node.id)); + } + }; + + set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint()); + unsafe { + let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_md, bcx.llbb); + llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr); + } + + return var_md; +} + +/// Creates debug information for the given function argument. +/// +/// Adds the created metadata nodes directly to the crate's IR. +/// The return value should be ignored if called from outside of the debuginfo module. +pub fn create_arg(bcx: block, arg: ast::arg, span: span) -> Option<DIVariable> { + debug!("create_arg"); + if true { + // XXX create_arg disabled for now because "node_id_type(bcx, arg.id)" below blows + // up: "error: internal compiler error: node_id_to_type: no type for node `arg (id=10)`" + return None; + } + + let fcx = bcx.fcx; + let cx = fcx.ccx; + + let loc = span_start(cx, span); + if "<intrinsic>" == loc.file.name { + return None; + } + + let ty = node_id_type(bcx, arg.id); + let tymd = create_ty(cx, ty, arg.ty.span); + let filemd = create_file(cx, loc.file.name); + let context = create_function(fcx); + + match arg.pat.node { + ast::pat_ident(_, path, _) => { + // XXX: This is wrong; it should work for multiple bindings. + let ident = path.idents.last(); + let name: &str = cx.sess.str_of(*ident); + let mdnode = do as_c_str(name) |name| { unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), + ArgVariableTag as u32, + context, + name, + filemd, + loc.line as c_uint, + tymd, + false, + 0, + 0) + // XXX need to pass in a real argument number + }}; + + let llptr = fcx.llargs.get_copy(&arg.id); + set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint()); + unsafe { + let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( + DIB(cx), llptr, mdnode, bcx.llbb); + llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr); + } + return Some(mdnode); + } + _ => { + return None; + } + } +} + +/// Sets the current debug location at the beginning of the span +/// +/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...) +pub fn update_source_pos(bcx: block, span: span) { + if !bcx.sess().opts.debuginfo || (*span.lo == 0 && *span.hi == 0) { + return; + } + debug!("update_source_pos: %s", bcx.sess().codemap.span_to_str(span)); + let loc = span_start(bcx.ccx(), span); + set_debug_location(bcx.ccx(), create_block(bcx), loc.line, loc.col.to_uint()) +} + +/// Creates debug information for the given function. +/// +/// Adds the created metadata nodes directly to the crate's IR. +/// The return value should be ignored if called from outside of the debuginfo module. +pub fn create_function(fcx: fn_ctxt) -> DISubprogram { + let cx = fcx.ccx; + let fcx = &mut *fcx; + let span = fcx.span.get(); + + let (ident, ret_ty, id) = match cx.tcx.items.get_copy(&fcx.id) { + ast_map::node_item(item, _) => { + match item.node { + ast::item_fn(ref decl, _, _, _, _) => { + (item.ident, decl.output, item.id) + } + _ => fcx.ccx.sess.span_bug(item.span, "create_function: item bound to non-function") + } + } + ast_map::node_method(method, _, _) => { + (method.ident, method.decl.output, method.id) + } + ast_map::node_expr(expr) => { + match expr.node { + ast::expr_fn_block(ref decl, _) => { + let name = gensym_name("fn"); + (name, decl.output, expr.id) + } + _ => fcx.ccx.sess.span_bug(expr.span, + "create_function: expected an expr_fn_block here") + } + } + _ => fcx.ccx.sess.bug("create_function: unexpected sort of node") + }; + + match dbg_cx(cx).created_functions.find(&id) { + Some(fn_md) => return *fn_md, + None => () + } + + debug!("create_function: %s, %s", cx.sess.str_of(ident), cx.sess.codemap.span_to_str(span)); + + let loc = span_start(cx, span); + let file_md = create_file(cx, loc.file.name); + + let ret_ty_md = if cx.sess.opts.extra_debuginfo { + match ret_ty.node { + ast::ty_nil => ptr::null(), + _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id), ret_ty.span) + } + } else { + ptr::null() + }; + + let fn_ty = unsafe { + llvm::LLVMDIBuilderCreateSubroutineType( + DIB(cx), + file_md, + create_DIArray(DIB(cx), [ret_ty_md])) + }; + + let fn_md = + do as_c_str(cx.sess.str_of(ident)) |name| { + do as_c_str(cx.sess.str_of(ident)) |linkage| { unsafe { + llvm::LLVMDIBuilderCreateFunction( + DIB(cx), + file_md, + name, + linkage, + file_md, + loc.line as c_uint, + fn_ty, + false, + true, + loc.line as c_uint, + FlagPrototyped as c_uint, + cx.sess.opts.optimize != session::No, + fcx.llfn, + ptr::null(), + ptr::null()) + }}}; + + dbg_cx(cx).created_functions.insert(id, fn_md); + return fn_md; +} + + + + +//=------------------------------------------------------------------------------------------------- +// Module-Internal debug info creation functions +//=------------------------------------------------------------------------------------------------- + fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { return unsafe { llvm::LLVMDIBuilderGetOrCreateArray(builder, vec::raw::to_ptr(arr), arr.len() as u32) @@ -119,6 +351,9 @@ fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { fn create_compile_unit(cx: @mut CrateContext) { let dcx = dbg_cx(cx); let crate_name: &str = dcx.crate_file; + + debug!("create_compile_unit: %?", crate_name); + let work_dir = cx.sess.working_dir.to_str(); let producer = fmt!("rustc version %s", env!("CFG_VERSION")); @@ -134,7 +369,7 @@ fn create_compile_unit(cx: @mut CrateContext) { }}}}}}; } -fn create_file(cx: @mut CrateContext, full_path: &str) -> DIFile { +fn create_file(cx: &mut CrateContext, full_path: &str) -> DIFile { match dbg_cx(cx).created_files.find_equiv(&full_path) { Some(file_md) => return *file_md, None => () @@ -160,10 +395,7 @@ fn create_file(cx: @mut CrateContext, full_path: &str) -> DIFile { return file_md; } -/// Return codemap::Loc corresponding to the beginning of the span -fn span_start(cx: &CrateContext, span: span) -> codemap::Loc { - return cx.sess.codemap.lookup_char_pos(span.lo); -} + fn create_block(bcx: block) -> DILexicalBlock { let mut bcx = bcx; @@ -205,12 +437,9 @@ fn create_block(bcx: block) -> DILexicalBlock { return block_md; } -fn size_and_align_of(cx: @mut CrateContext, t: ty::t) -> (uint, uint) { - let llty = type_of::type_of(cx, t); - (machine::llsize_of_real(cx, llty), machine::llalign_of_min(cx, llty)) -} -fn create_basic_type(cx: @mut CrateContext, t: ty::t, _span: span) -> DIType { + +fn create_basic_type(cx: &mut CrateContext, t: ty::t, _span: span) -> DIType { let ty_id = ty::type_id(t); match dbg_cx(cx).created_types.find(&ty_id) { Some(ty_md) => return *ty_md, @@ -248,20 +477,30 @@ fn create_basic_type(cx: @mut CrateContext, t: ty::t, _span: span) -> DIType { let (size, align) = size_and_align_of(cx, t); let ty_md = do as_c_str(name) |name| { unsafe { llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), name, - size * 8 as u64, align * 8 as u64, encoding as c_uint) + DIB(cx), + name, + bytes_to_bits(size), + bytes_to_bits(align), + encoding as c_uint) }}; + // One could think that this call is not necessary, as the create_ty() function will insert the + // type descriptor into the cache anyway. Mind, however, that create_basic_type() is also called + // directly from other functions (e.g. create_boxed_type()). dbg_cx(cx).created_types.insert(ty_id, ty_md); return ty_md; } -fn create_pointer_type(cx: @mut CrateContext, t: ty::t, _span: span, pointee: DIType) -> DIType { +fn create_pointer_type(cx: &mut CrateContext, t: ty::t, _span: span, pointee: DIType) -> DIType { let (size, align) = size_and_align_of(cx, t); let name = ty_to_str(cx.tcx, t); let ptr_md = do as_c_str(name) |name| { unsafe { - llvm::LLVMDIBuilderCreatePointerType(DIB(cx), - pointee, size * 8 as u64, align * 8 as u64, name) + llvm::LLVMDIBuilderCreatePointerType( + DIB(cx), + pointee, + bytes_to_bits(size), + bytes_to_bits(align), + name) }}; return ptr_md; } @@ -277,9 +516,9 @@ struct StructContext { } impl StructContext { - fn new(cx: &CrateContext, name: ~str, file: DIFile, line: uint) -> ~StructContext { + fn new(cx: &CrateContext, name: ~str, file: DIFile, line: uint) -> StructContext { debug!("StructContext::create: %s", name); - let scx = ~StructContext { + return StructContext { builder: DIB(cx), file: file, name: name, @@ -288,18 +527,26 @@ impl StructContext { total_size: 0, align: 1 }; - return scx; } fn add_member(&mut self, name: &str, line: uint, size: uint, align: uint, ty: DIType) { - debug!("StructContext(%s)::add_member: %s, size=%u, align=%u", - self.name, name, size, align); let offset = roundup(self.total_size, align); + + debug!("StructContext(%s)::add_member: %s, size=%u, align=%u, offset=%u", + self.name, name, size, align, offset); + let mem_t = do as_c_str(name) |name| { unsafe { llvm::LLVMDIBuilderCreateMemberType( - self.builder, ptr::null(), name, self.file, line as c_uint, - size * 8 as u64, align * 8 as u64, offset * 8 as u64, - 0, ty) + self.builder, + self.file, + name, + self.file, + line as c_uint, + bytes_to_bits(size), + bytes_to_bits(align), + bytes_to_bits(offset), + 0, + ty) }}; self.members.push(mem_t); self.total_size = offset + size; @@ -307,35 +554,49 @@ impl StructContext { self.align = cmp::max(self.align, align); } + fn get_total_size_with_alignment(&self) -> uint { + roundup(self.total_size, self.align) + } + fn finalize(&self) -> DICompositeType { debug!("StructContext(%s)::finalize: total_size=%u, align=%u", self.name, self.total_size, self.align); let members_md = create_DIArray(self.builder, self.members); + // The size of the struct/tuple must be rounded to the next multiple of its alignment. + // Otherwise gdb has trouble reading the struct correctly when it is embedded into another + // data structure. This is also the value `sizeof` in C would give. + let actual_total_size = self.get_total_size_with_alignment(); + let struct_md = do as_c_str(self.name) |name| { unsafe { llvm::LLVMDIBuilderCreateStructType( - self.builder, self.file, name, - self.file, self.line as c_uint, - self.total_size * 8 as u64, self.align * 8 as u64, 0, ptr::null(), - members_md, 0, ptr::null()) + self.builder, + self.file, + name, + self.file, + self.line as c_uint, + bytes_to_bits(actual_total_size), + bytes_to_bits(self.align), + 0, + ptr::null(), + members_md, + 0, + ptr::null()) }}; return struct_md; } } -#[inline] -fn roundup(x: uint, a: uint) -> uint { - ((x + (a - 1)) / a) * a -} - -fn create_struct(cx: @mut CrateContext, t: ty::t, fields: ~[ty::field], span: span) +fn create_struct(cx: &mut CrateContext, struct_type: ty::t, fields: ~[ty::field], span: span) -> DICompositeType { + debug!("create_struct: %?", ty::get(struct_type)); + let loc = span_start(cx, span); let file_md = create_file(cx, loc.file.name); - let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, t), file_md, loc.line); - for fields.each |field| { + let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, struct_type), file_md, loc.line); + for fields.iter().advance |field| { let field_t = field.mt.ty; let ty_md = create_ty(cx, field_t, span); let (size, align) = size_and_align_of(cx, field_t); @@ -345,24 +606,30 @@ fn create_struct(cx: @mut CrateContext, t: ty::t, fields: ~[ty::field], span: sp } // returns (void* type as a ValueRef, size in bytes, align in bytes) -fn voidptr(cx: @mut CrateContext) -> (DIDerivedType, uint, uint) { +fn voidptr(cx: &mut CrateContext) -> (DIDerivedType, uint, uint) { let size = sys::size_of::<ValueRef>(); let align = sys::min_align_of::<ValueRef>(); let vp = do as_c_str("*void") |name| { unsafe { - llvm::LLVMDIBuilderCreatePointerType(DIB(cx), ptr::null(), - size*8 as u64, align*8 as u64, name) + llvm::LLVMDIBuilderCreatePointerType( + DIB(cx), + ptr::null(), + bytes_to_bits(size), + bytes_to_bits(align), + name) }}; return (vp, size, align); } -fn create_tuple(cx: @mut CrateContext, _t: ty::t, elements: &[ty::t], span: span) +fn create_tuple(cx: &mut CrateContext, tuple_type: ty::t, elements: &[ty::t], span: span) -> DICompositeType { + debug!("create_tuple: %?", ty::get(tuple_type)); + let loc = span_start(cx, span); let file_md = create_file(cx, loc.file.name); - let name = (cx.sess.str_of((dbg_cx(cx).names)("tuple"))).to_owned(); + let name = fmt!("tuple_%u", token::gensym("tuple")); let mut scx = StructContext::new(cx, name, file_md, loc.line); - for elements.each |element| { + for elements.iter().advance |element| { let ty_md = create_ty(cx, *element, span); let (size, align) = size_and_align_of(cx, *element); scx.add_member("", loc.line, size, align, ty_md); @@ -370,8 +637,10 @@ fn create_tuple(cx: @mut CrateContext, _t: ty::t, elements: &[ty::t], span: span return scx.finalize(); } -fn create_boxed_type(cx: @mut CrateContext, contents: ty::t, +fn create_boxed_type(cx: &mut CrateContext, contents: ty::t, span: span, boxed: DIType) -> DICompositeType { + debug!("create_boxed_type: %?", ty::get(contents)); + let loc = span_start(cx, span); let file_md = create_file(cx, loc.file.name); let int_t = ty::mk_int(); @@ -392,8 +661,10 @@ fn create_boxed_type(cx: @mut CrateContext, contents: ty::t, return scx.finalize(); } -fn create_fixed_vec(cx: @mut CrateContext, _vec_t: ty::t, elem_t: ty::t, +fn create_fixed_vec(cx: &mut CrateContext, _vec_t: ty::t, elem_t: ty::t, len: uint, span: span) -> DIType { + debug!("create_fixed_vec: %?", ty::get(_vec_t)); + let elem_ty_md = create_ty(cx, elem_t, span); let (size, align) = size_and_align_of(cx, elem_t); @@ -403,23 +674,40 @@ fn create_fixed_vec(cx: @mut CrateContext, _vec_t: ty::t, elem_t: ty::t, let subscripts = create_DIArray(DIB(cx), [subrange]); return unsafe { - llvm::LLVMDIBuilderCreateArrayType(DIB(cx), - size * len * 8 as u64, align * 8 as u64, elem_ty_md, subscripts) + llvm::LLVMDIBuilderCreateArrayType( + DIB(cx), + bytes_to_bits(size * len), + bytes_to_bits(align), + elem_ty_md, + subscripts) }; } -fn create_boxed_vec(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, +fn create_boxed_vec(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, vec_ty_span: span) -> DICompositeType { + debug!("create_boxed_vec: %?", ty::get(vec_t)); + let loc = span_start(cx, vec_ty_span); let file_md = create_file(cx, loc.file.name); let elem_ty_md = create_ty(cx, elem_t, vec_ty_span); let mut vec_scx = StructContext::new(cx, ty_to_str(cx.tcx, vec_t), file_md, 0); let size_t_type = create_basic_type(cx, ty::mk_uint(), vec_ty_span); - vec_scx.add_member("fill", 0, sys::size_of::<libc::size_t>(), - sys::min_align_of::<libc::size_t>(), size_t_type); - vec_scx.add_member("alloc", 0, sys::size_of::<libc::size_t>(), - sys::min_align_of::<libc::size_t>(), size_t_type); + + vec_scx.add_member( + "fill", + 0, + sys::size_of::<libc::size_t>(), + sys::min_align_of::<libc::size_t>(), + size_t_type); + + vec_scx.add_member( + "alloc", + 0, + sys::size_of::<libc::size_t>(), + sys::min_align_of::<libc::size_t>(), + size_t_type); + let subrange = unsafe { llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0_i64, 0_i64) }; @@ -428,18 +716,32 @@ fn create_boxed_vec(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, let subscripts = create_DIArray(DIB(cx), [subrange]); let data_ptr = unsafe { - llvm::LLVMDIBuilderCreateArrayType(DIB(cx), - arr_size * 8 as u64, arr_align * 8 as u64, elem_ty_md, subscripts) + llvm::LLVMDIBuilderCreateArrayType( + DIB(cx), + bytes_to_bits(arr_size), + bytes_to_bits(arr_align), + elem_ty_md, + subscripts) }; - vec_scx.add_member("data", 0, 0, // clang says the size should be 0 - sys::min_align_of::<u8>(), data_ptr); + vec_scx.add_member( + "data", + 0, + 0, // clang says the size should be 0 + sys::min_align_of::<u8>(), data_ptr); + let vec_md = vec_scx.finalize(); let mut box_scx = StructContext::new(cx, fmt!("box<%s>", name), file_md, 0); let int_t = ty::mk_int(); let refcount_type = create_basic_type(cx, int_t, vec_ty_span); - box_scx.add_member("refcnt", 0, sys::size_of::<uint>(), - sys::min_align_of::<uint>(), refcount_type); + + box_scx.add_member( + "refcnt", + 0, + sys::size_of::<uint>(), + sys::min_align_of::<uint>(), + refcount_type); + let (vp, vpsize, vpalign) = voidptr(cx); box_scx.add_member("tydesc", 0, vpsize, vpalign, vp); box_scx.add_member("prev", 0, vpsize, vpalign, vp); @@ -451,8 +753,10 @@ fn create_boxed_vec(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, return mdval; } -fn create_vec_slice(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: span) +fn create_vec_slice(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: span) -> DICompositeType { + debug!("create_vec_slice: %?", ty::get(vec_t)); + let loc = span_start(cx, span); let file_md = create_file(cx, loc.file.name); let elem_ty_md = create_ty(cx, elem_t, span); @@ -462,13 +766,14 @@ fn create_vec_slice(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: sp let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, vec_t), file_md, 0); let (_, ptr_size, ptr_align) = voidptr(cx); scx.add_member("vec", 0, ptr_size, ptr_align, elem_ptr); - scx.add_member("length", 0, sys::size_of::<uint>(), - sys::min_align_of::<uint>(), uint_type); + scx.add_member("length", 0, sys::size_of::<uint>(), sys::min_align_of::<uint>(), uint_type); return scx.finalize(); } -fn create_fn_ty(cx: @mut CrateContext, _fn_ty: ty::t, inputs: ~[ty::t], output: ty::t, +fn create_fn_ty(cx: &mut CrateContext, _fn_ty: ty::t, inputs: ~[ty::t], output: ty::t, span: span) -> DICompositeType { + debug!("create_fn_ty: %?", ty::get(_fn_ty)); + let loc = span_start(cx, span); let file_md = create_file(cx, loc.file.name); let (vp, _, _) = voidptr(cx); @@ -478,22 +783,29 @@ fn create_fn_ty(cx: @mut CrateContext, _fn_ty: ty::t, inputs: ~[ty::t], output: let members = ~[output_ptr_md, vp] + inputs_vals; return unsafe { - llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_md, + llvm::LLVMDIBuilderCreateSubroutineType( + DIB(cx), + file_md, create_DIArray(DIB(cx), members)) }; } -fn create_unimpl_ty(cx: @mut CrateContext, t: ty::t) -> DIType { +fn create_unimpl_ty(cx: &mut CrateContext, t: ty::t) -> DIType { + debug!("create_unimpl_ty: %?", ty::get(t)); + let name = ty_to_str(cx.tcx, t); let md = do as_c_str(fmt!("NYI<%s>", name)) |name| { unsafe { llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), name, - 0_u64, 8_u64, DW_ATE_unsigned as c_uint) + DIB(cx), + name, + 0_u64, + 8_u64, + DW_ATE_unsigned as c_uint) }}; return md; } -fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType { +fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) -> DIType { let ty_id = ty::type_id(t); match dbg_cx(cx).created_types.find(&ty_id) { Some(ty_md) => return *ty_md, @@ -548,9 +860,9 @@ fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType { let pointee = create_ty(cx, mt.ty, span); create_pointer_type(cx, t, span, pointee) }, - ty::ty_rptr(ref _region, ref _mt) => { - cx.sess.span_note(span, "debuginfo for rptr NYI"); - create_unimpl_ty(cx, t) + ty::ty_rptr(_, ref mt) => { + let pointee = create_ty(cx, mt.ty, span); + create_pointer_type(cx, t, span, pointee) }, ty::ty_bare_fn(ref barefnty) => { let inputs = barefnty.sig.inputs.map(|a| *a); @@ -561,7 +873,7 @@ fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType { cx.sess.span_note(span, "debuginfo for closure NYI"); create_unimpl_ty(cx, t) }, - ty::ty_trait(_did, ref _substs, ref _vstore, _) => { + ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => { cx.sess.span_note(span, "debuginfo for trait NYI"); create_unimpl_ty(cx, t) }, @@ -579,103 +891,6 @@ fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType { return ty_md; } -pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable { - let cx = bcx.ccx(); - - let ident = match local.node.pat.node { - ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth), - // FIXME this should be handled (#2533) - _ => { - bcx.sess().span_note(local.span, "debuginfo for pattern bindings NYI"); - return ptr::null(); - } - }; - let name: &str = cx.sess.str_of(ident); - debug!("create_local_var: %s", name); - - let loc = span_start(cx, local.span); - let ty = node_id_type(bcx, local.node.id); - let tymd = create_ty(cx, ty, local.node.ty.span); - let filemd = create_file(cx, loc.file.name); - let context = match bcx.parent { - None => create_function(bcx.fcx), - Some(_) => create_block(bcx) - }; - - let var_md = do as_c_str(name) |name| { unsafe { - llvm::LLVMDIBuilderCreateLocalVariable( - DIB(cx), AutoVariableTag as u32, - context, name, filemd, - loc.line as c_uint, tymd, false, 0, 0) - }}; - - // FIXME(#6814) Should use `pat_util::pat_bindings` for pats like (a, b) etc - let llptr = match bcx.fcx.lllocals.find_copy(&local.node.pat.id) { - Some(v) => v, - None => { - bcx.tcx().sess.span_bug( - local.span, - fmt!("No entry in lllocals table for %?", local.node.id)); - } - }; - - set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint()); - unsafe { - let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_md, bcx.llbb); - llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr); - } - - return var_md; -} - -pub fn create_arg(bcx: block, arg: ast::arg, span: span) -> Option<DIVariable> { - debug!("create_arg"); - if true { - // XXX create_arg disabled for now because "node_id_type(bcx, arg.id)" below blows - // up: "error: internal compiler error: node_id_to_type: no type for node `arg (id=10)`" - return None; - } - - let fcx = bcx.fcx; - let cx = fcx.ccx; - - let loc = span_start(cx, span); - if "<intrinsic>" == loc.file.name { - return None; - } - - let ty = node_id_type(bcx, arg.id); - let tymd = create_ty(cx, ty, arg.ty.span); - let filemd = create_file(cx, loc.file.name); - let context = create_function(fcx); - - match arg.pat.node { - ast::pat_ident(_, path, _) => { - // XXX: This is wrong; it should work for multiple bindings. - let ident = path.idents.last(); - let name: &str = cx.sess.str_of(*ident); - let mdnode = do as_c_str(name) |name| { unsafe { - llvm::LLVMDIBuilderCreateLocalVariable(DIB(cx), - ArgVariableTag as u32, context, name, - filemd, loc.line as c_uint, tymd, false, 0, 0) - // XXX need to pass in a real argument number - }}; - - let llptr = fcx.llargs.get_copy(&arg.id); - set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint()); - unsafe { - let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( - DIB(cx), llptr, mdnode, bcx.llbb); - llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr); - } - return Some(mdnode); - } - _ => { - return None; - } - } -} - fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: uint) { if dbg_cx(cx).curr_loc == (line, col) { return; @@ -686,91 +901,44 @@ fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: ui let elems = ~[C_i32(line as i32), C_i32(col as i32), scope, ptr::null()]; unsafe { let dbg_loc = llvm::LLVMMDNodeInContext( - dbg_cx(cx).llcontext, vec::raw::to_ptr(elems), - elems.len() as libc::c_uint); - llvm::LLVMSetCurrentDebugLocation(cx.builder.B, dbg_loc); - } -} + dbg_cx(cx).llcontext, + vec::raw::to_ptr(elems), + elems.len() as c_uint); -/// Set current debug location at the beginning of the span -pub fn update_source_pos(bcx: block, span: span) { - if !bcx.sess().opts.debuginfo || (*span.lo == 0 && *span.hi == 0) { - return; + llvm::LLVMSetCurrentDebugLocation(cx.builder.B, dbg_loc); } - debug!("update_source_pos: %s", bcx.sess().codemap.span_to_str(span)); - let loc = span_start(bcx.ccx(), span); - set_debug_location(bcx.ccx(), create_block(bcx), loc.line, loc.col.to_uint()) } -pub fn create_function(fcx: fn_ctxt) -> DISubprogram { - let cx = fcx.ccx; - let fcx = &mut *fcx; - let span = fcx.span.get(); - - let (ident, ret_ty, id) = match cx.tcx.items.get_copy(&fcx.id) { - ast_map::node_item(item, _) => { - match item.node { - ast::item_fn(ref decl, _, _, _, _) => { - (item.ident, decl.output, item.id) - } - _ => fcx.ccx.sess.span_bug(item.span, "create_function: item bound to non-function") - } - } - ast_map::node_method(method, _, _) => { - (method.ident, method.decl.output, method.id) - } - ast_map::node_expr(expr) => { - match expr.node { - ast::expr_fn_block(ref decl, _) => { - ((dbg_cx(cx).names)("fn"), decl.output, expr.id) - } - _ => fcx.ccx.sess.span_bug(expr.span, - "create_function: expected an expr_fn_block here") - } - } - _ => fcx.ccx.sess.bug("create_function: unexpected sort of node") - }; - match dbg_cx(cx).created_functions.find(&id) { - Some(fn_md) => return *fn_md, - None => () - } +//=------------------------------------------------------------------------------------------------- +// Utility Functions +//=------------------------------------------------------------------------------------------------- - debug!("create_function: %s, %s", cx.sess.str_of(ident), cx.sess.codemap.span_to_str(span)); +#[inline] +fn roundup(x: uint, a: uint) -> uint { + ((x + (a - 1)) / a) * a +} - let loc = span_start(cx, span); - let file_md = create_file(cx, loc.file.name); +/// Return codemap::Loc corresponding to the beginning of the span +fn span_start(cx: &CrateContext, span: span) -> codemap::Loc { + cx.sess.codemap.lookup_char_pos(span.lo) +} - let ret_ty_md = if cx.sess.opts.extra_debuginfo { - match ret_ty.node { - ast::ty_nil => ptr::null(), - _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id), - ret_ty.span) - } - } else { - ptr::null() - }; +fn size_and_align_of(cx: &mut CrateContext, t: ty::t) -> (uint, uint) { + let llty = type_of::type_of(cx, t); + (machine::llsize_of_real(cx, llty), machine::llalign_of_min(cx, llty)) +} - let fn_ty = unsafe { - llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), - file_md, create_DIArray(DIB(cx), [ret_ty_md])) - }; +fn bytes_to_bits(bytes: uint) -> c_ulonglong { + (bytes * 8) as c_ulonglong +} - let fn_md = - do as_c_str(cx.sess.str_of(ident)) |name| { - do as_c_str(cx.sess.str_of(ident)) |linkage| { unsafe { - llvm::LLVMDIBuilderCreateFunction( - DIB(cx), - file_md, - name, linkage, - file_md, loc.line as c_uint, - fn_ty, false, true, - loc.line as c_uint, - FlagPrototyped as c_uint, - cx.sess.opts.optimize != session::No, - fcx.llfn, ptr::null(), ptr::null()) - }}}; +#[inline] +fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext { + cx.dbg_cx.get_mut_ref() +} - dbg_cx(cx).created_functions.insert(id, fn_md); - return fn_md; +#[inline] +fn DIB(cx: &CrateContext) -> DIBuilderRef { + cx.dbg_cx.get_ref().builder } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index cbe20afe919..df197ded629 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -119,10 +119,9 @@ lvalues are *never* stored by value. */ -use core::prelude::*; use back::abi; -use lib::llvm::{ValueRef, TypeRef, llvm}; +use lib::llvm::{ValueRef, llvm}; use lib; use metadata::csearch; use middle::trans::_match; @@ -152,9 +151,11 @@ use middle::ty; use util::common::indenter; use util::ppaux::Repr; -use core::cast::transmute; -use core::hashmap::HashMap; -use core::vec; +use middle::trans::type_::Type; + +use std::cast::transmute; +use std::hashmap::HashMap; +use std::vec; use syntax::print::pprust::{expr_to_str}; use syntax::ast; use syntax::codemap; @@ -173,7 +174,7 @@ pub enum Dest { impl Dest { pub fn to_str(&self, ccx: &CrateContext) -> ~str { match *self { - SaveIn(v) => fmt!("SaveIn(%s)", val_str(ccx.tn, v)), + SaveIn(v) => fmt!("SaveIn(%s)", ccx.tn.val_to_str(v)), Ignore => ~"Ignore" } } @@ -252,7 +253,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { fn auto_slice(bcx: block, autoderefs: uint, - expr: @ast::expr, + expr: &ast::expr, datum: Datum) -> DatumBlock { // This is not the most efficient thing possible; since slices // are two words it'd be better if this were compiled in @@ -278,7 +279,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { DatumBlock {bcx: bcx, datum: scratch} } - fn add_env(bcx: block, expr: @ast::expr, datum: Datum) -> DatumBlock { + fn add_env(bcx: block, expr: &ast::expr, datum: Datum) -> DatumBlock { // This is not the most efficient thing possible; since closures // are two words it'd be better if this were compiled in // 'dest' mode, but I can't find a nice way to structure the @@ -299,7 +300,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { fn auto_slice_and_ref(bcx: block, autoderefs: uint, - expr: @ast::expr, + expr: &ast::expr, datum: Datum) -> DatumBlock { let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum); auto_ref(bcx, datum) @@ -449,7 +450,7 @@ fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { } fn trans_rvalue_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { - let _icx = bcx.insn_ctxt("trans_rvalue_datum_unadjusted"); + let _icx = push_ctxt("trans_rvalue_datum_unadjusted"); trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr))); @@ -500,7 +501,7 @@ fn trans_rvalue_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block { let mut bcx = bcx; - let _icx = bcx.insn_ctxt("trans_rvalue_stmt"); + let _icx = push_ctxt("trans_rvalue_stmt"); if bcx.unreachable { return bcx; @@ -556,7 +557,7 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block { fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, dest: Dest) -> block { - let _icx = bcx.insn_ctxt("trans_rvalue_dps_unadjusted"); + let _icx = push_ctxt("trans_rvalue_dps_unadjusted"); let tcx = bcx.tcx(); trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr))); @@ -587,8 +588,9 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, } ast::expr_tup(ref args) => { let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr)); - return trans_adt(bcx, repr, 0, args.mapi(|i, arg| (i, *arg)), - None, dest); + let numbered_fields: ~[(uint, @ast::expr)] = + args.iter().enumerate().transform(|(i, arg)| (i, *arg)).collect(); + return trans_adt(bcx, repr, 0, numbered_fields, None, dest); } ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), _}) => { return tvec::trans_lit_str(bcx, expr, s, dest); @@ -681,7 +683,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, } ast::expr_cast(val, _) => { match ty::get(node_id_type(bcx, expr.id)).sty { - ty::ty_trait(_, _, store, _) => { + ty::ty_trait(_, _, store, _, _) => { return meth::trans_trait_cast(bcx, val, expr.id, dest, store); } @@ -703,9 +705,9 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, } } -fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, +fn trans_def_dps_unadjusted(bcx: block, ref_expr: &ast::expr, def: ast::def, dest: Dest) -> block { - let _icx = bcx.insn_ctxt("trans_def_dps_unadjusted"); + let _icx = push_ctxt("trans_def_dps_unadjusted"); let ccx = bcx.ccx(); let lldest = match dest { @@ -750,10 +752,10 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, } fn trans_def_datum_unadjusted(bcx: block, - ref_expr: @ast::expr, + ref_expr: &ast::expr, def: ast::def) -> DatumBlock { - let _icx = bcx.insn_ctxt("trans_def_datum_unadjusted"); + let _icx = push_ctxt("trans_def_datum_unadjusted"); match def { ast::def_fn(did, _) | ast::def_static_method(did, None, _) => { @@ -774,7 +776,7 @@ fn trans_def_datum_unadjusted(bcx: block, } fn fn_data_to_datum(bcx: block, - ref_expr: @ast::expr, + ref_expr: &ast::expr, def_id: ast::def_id, fn_data: callee::FnData) -> DatumBlock { /*! @@ -794,7 +796,7 @@ fn trans_def_datum_unadjusted(bcx: block, ty: ty::mk_mach_uint(ast::ty_u8), mutbl: ast::m_imm }); // *u8 - (rust_ty, PointerCast(bcx, fn_data.llfn, T_ptr(T_i8()))) + (rust_ty, PointerCast(bcx, fn_data.llfn, Type::i8p())) } else { let fn_ty = expr_ty(bcx, ref_expr); (fn_ty, fn_data.llfn) @@ -814,7 +816,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { * Translates an lvalue expression, always yielding a by-ref * datum. Does not apply any adjustments. */ - let _icx = bcx.insn_ctxt("trans_lval"); + let _icx = push_ctxt("trans_lval"); let mut bcx = bcx; debug!("trans_lvalue(expr=%s)", bcx.expr_to_str(expr)); @@ -853,7 +855,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { //! Translates `base.field`. let mut bcx = bcx; - let _icx = bcx.insn_ctxt("trans_rec_field"); + let _icx = push_ctxt("trans_rec_field"); let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base)); let repr = adt::represent_type(bcx.ccx(), base_datum.ty); @@ -871,12 +873,12 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { } fn trans_index(bcx: block, - index_expr: @ast::expr, + index_expr: &ast::expr, base: @ast::expr, idx: @ast::expr) -> DatumBlock { //! Translates `base[idx]`. - let _icx = bcx.insn_ctxt("trans_index"); + let _icx = push_ctxt("trans_index"); let ccx = bcx.ccx(); let base_ty = expr_ty(bcx, base); let mut bcx = bcx; @@ -905,17 +907,18 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { let scaled_ix = Mul(bcx, ix_val, vt.llunit_size); base::maybe_name_value(bcx.ccx(), scaled_ix, "scaled_ix"); - let mut (bcx, base, len) = + let (bcx, base, len) = base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id, 0); + let mut len = len; if ty::type_is_str(base_ty) { // acccount for null terminator in the case of string len = Sub(bcx, len, C_uint(bcx.ccx(), 1u)); } - debug!("trans_index: base %s", val_str(bcx.ccx().tn, base)); - debug!("trans_index: len %s", val_str(bcx.ccx().tn, len)); + debug!("trans_index: base %s", bcx.val_to_str(base)); + debug!("trans_index: len %s", bcx.val_to_str(len)); let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len); let bcx = do with_cond(bcx, bounds_check) |bcx| { @@ -924,7 +927,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { ix_val, unscaled_len) }; let elt = InBoundsGEP(bcx, base, [ix_val]); - let elt = PointerCast(bcx, elt, T_ptr(vt.llunit_ty)); + let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to()); return DatumBlock { bcx: bcx, datum: Datum {val: elt, @@ -934,16 +937,16 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { } fn trans_def_lvalue(bcx: block, - ref_expr: @ast::expr, + ref_expr: &ast::expr, def: ast::def) -> DatumBlock { //! Translates a reference to a path. - let _icx = bcx.insn_ctxt("trans_def_lvalue"); + let _icx = push_ctxt("trans_def_lvalue"); let ccx = bcx.ccx(); match def { - ast::def_const(did) => { + ast::def_static(did, _) => { let const_ty = expr_ty(bcx, ref_expr); fn get_did(ccx: @mut CrateContext, did: ast::def_id) @@ -963,7 +966,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { // which may not be equal to the enum's type for // non-C-like enums. let val = base::get_item_val(bcx.ccx(), did.node); - let pty = T_ptr(type_of(bcx.ccx(), const_ty)); + let pty = type_of(bcx.ccx(), const_ty).ptr_to(); PointerCast(bcx, val, pty) } else { { @@ -981,9 +984,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { let symbol = csearch::get_symbol( bcx.ccx().sess.cstore, did); - let llval = llvm::LLVMAddGlobal( - bcx.ccx().llmod, - llty, + let llval = llvm::LLVMAddGlobal( bcx.ccx().llmod, llty.to_ref(), transmute::<&u8,*i8>(&symbol[0])); let extern_const_values = &mut bcx.ccx().extern_const_values; extern_const_values.insert(did, llval); @@ -1012,7 +1013,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { } pub fn trans_local_var(bcx: block, def: ast::def) -> Datum { - let _icx = bcx.insn_ctxt("trans_local_var"); + let _icx = push_ctxt("trans_local_var"); return match def { ast::def_upvar(nid, _, _, _) => { @@ -1051,14 +1052,8 @@ pub fn trans_local_var(bcx: block, def: ast::def) -> Datum { debug!("def_self() reference, self_info.t=%s", self_info.t.repr(bcx.tcx())); - // This cast should not be necessary. We should cast self *once*, - // but right now this conflicts with default methods. - let real_self_ty = monomorphize_type(bcx, self_info.t); - let llselfty = T_ptr(type_of::type_of(bcx.ccx(), real_self_ty)); - - let casted_val = PointerCast(bcx, self_info.v, llselfty); Datum { - val: casted_val, + val: self_info.v, ty: self_info.t, mode: ByRef(ZeroMem) } @@ -1081,7 +1076,7 @@ pub fn trans_local_var(bcx: block, def: ast::def) -> Datum { }; let ty = node_id_type(bcx, nid); debug!("take_local(nid=%?, v=%s, ty=%s)", - nid, bcx.val_str(v), bcx.ty_to_str(ty)); + nid, bcx.val_to_str(v), bcx.ty_to_str(ty)); Datum { val: v, ty: ty, @@ -1143,7 +1138,7 @@ fn trans_rec_or_struct(bcx: block, id: ast::node_id, dest: Dest) -> block { - let _icx = bcx.insn_ctxt("trans_rec"); + let _icx = push_ctxt("trans_rec"); let bcx = bcx; let ty = node_id_type(bcx, id); @@ -1152,8 +1147,7 @@ fn trans_rec_or_struct(bcx: block, let mut need_base = vec::from_elem(field_tys.len(), true); let numbered_fields = do fields.map |field| { - let opt_pos = vec::position(field_tys, |field_ty| - field_ty.ident == field.node.ident); + let opt_pos = field_tys.iter().position_(|field_ty| field_ty.ident == field.node.ident); match opt_pos { Some(i) => { need_base[i] = false; @@ -1168,7 +1162,7 @@ fn trans_rec_or_struct(bcx: block, let optbase = match base { Some(base_expr) => { let mut leftovers = ~[]; - for need_base.eachi |i, b| { + for need_base.iter().enumerate().advance |(i, b)| { if *b { leftovers.push((i, field_tys[i].mt.ty)) } @@ -1177,7 +1171,7 @@ fn trans_rec_or_struct(bcx: block, fields: leftovers }) } None => { - if need_base.any(|b| *b) { + if need_base.iter().any_(|b| *b) { tcx.sess.span_bug(expr_span, "missing fields and no base expr") } None @@ -1218,11 +1212,11 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, fields: &[(uint, @ast::expr)], optbase: Option<StructBaseInfo>, dest: Dest) -> block { - let _icx = bcx.insn_ctxt("trans_adt"); + let _icx = push_ctxt("trans_adt"); let mut bcx = bcx; let addr = match dest { Ignore => { - for fields.each |&(_i, e)| { + for fields.iter().advance |&(_i, e)| { bcx = trans_into(bcx, e, Ignore); } for optbase.iter().advance |sbi| { @@ -1234,7 +1228,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, }; let mut temp_cleanups = ~[]; adt::trans_start_init(bcx, repr, addr, discr); - for fields.each |&(i, e)| { + for fields.iter().advance |&(i, e)| { let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i); let e_ty = expr_ty(bcx, e); bcx = trans_into(bcx, e, SaveIn(dest)); @@ -1254,7 +1248,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, } } - for temp_cleanups.each |cleanup| { + for temp_cleanups.iter().advance |cleanup| { revoke_clean(bcx, *cleanup); } return bcx; @@ -1264,16 +1258,16 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, fn trans_immediate_lit(bcx: block, expr: @ast::expr, lit: ast::lit) -> DatumBlock { // must not be a string constant, that is a RvalueDpsExpr - let _icx = bcx.insn_ctxt("trans_immediate_lit"); + let _icx = push_ctxt("trans_immediate_lit"); let ty = expr_ty(bcx, expr); immediate_rvalue_bcx(bcx, consts::const_lit(bcx.ccx(), expr, lit), ty) } fn trans_unary_datum(bcx: block, - un_expr: @ast::expr, + un_expr: &ast::expr, op: ast::unop, sub_expr: @ast::expr) -> DatumBlock { - let _icx = bcx.insn_ctxt("trans_unary_datum"); + let _icx = push_ctxt("trans_unary_datum"); // if deref, would be LvalueExpr assert!(op != ast::deref); @@ -1318,7 +1312,7 @@ fn trans_unary_datum(bcx: block, trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap_managed) } - ast::uniq(_) => { + ast::uniq => { let heap = heap_for_unique(bcx, un_ty); trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap) } @@ -1334,7 +1328,7 @@ fn trans_unary_datum(bcx: block, contents: @ast::expr, contents_ty: ty::t, heap: heap) -> DatumBlock { - let _icx = bcx.insn_ctxt("trans_boxed_expr"); + let _icx = push_ctxt("trans_boxed_expr"); let base::MallocResult { bcx, box: bx, body } = base::malloc_general(bcx, contents_ty, heap); add_clean_free(bcx, bx, heap); @@ -1344,9 +1338,9 @@ fn trans_unary_datum(bcx: block, } } -fn trans_addr_of(bcx: block, expr: @ast::expr, +fn trans_addr_of(bcx: block, expr: &ast::expr, subexpr: @ast::expr) -> DatumBlock { - let _icx = bcx.insn_ctxt("trans_addr_of"); + let _icx = push_ctxt("trans_addr_of"); let mut bcx = bcx; let sub_datum = unpack_datum!(bcx, trans_to_datum(bcx, subexpr)); let llval = sub_datum.to_ref_llval(bcx); @@ -1356,13 +1350,13 @@ fn trans_addr_of(bcx: block, expr: @ast::expr, // Important to get types for both lhs and rhs, because one might be _|_ // and the other not. fn trans_eager_binop(bcx: block, - binop_expr: @ast::expr, + binop_expr: &ast::expr, binop_ty: ty::t, op: ast::binop, lhs_datum: &Datum, rhs_datum: &Datum) -> DatumBlock { - let _icx = bcx.insn_ctxt("trans_eager_binop"); + let _icx = push_ctxt("trans_eager_binop"); let lhs = lhs_datum.to_appropriate_llval(bcx); let lhs_t = lhs_datum.ty; @@ -1439,7 +1433,7 @@ fn trans_eager_binop(bcx: block, } let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op); bcx = cmpr.bcx; - ZExt(bcx, cmpr.val, T_i8()) + ZExt(bcx, cmpr.val, Type::i8()) } } _ => { @@ -1454,11 +1448,11 @@ fn trans_eager_binop(bcx: block, enum lazy_binop_ty { lazy_and, lazy_or } fn trans_lazy_binop(bcx: block, - binop_expr: @ast::expr, + binop_expr: &ast::expr, op: lazy_binop_ty, a: @ast::expr, b: @ast::expr) -> DatumBlock { - let _icx = bcx.insn_ctxt("trans_lazy_binop"); + let _icx = push_ctxt("trans_lazy_binop"); let binop_ty = expr_ty(bcx, binop_expr); let bcx = bcx; @@ -1492,19 +1486,19 @@ fn trans_lazy_binop(bcx: block, } Br(past_rhs, join.llbb); - let phi = Phi(join, T_bool(), [lhs, rhs], [past_lhs.llbb, + let phi = Phi(join, Type::bool(), [lhs, rhs], [past_lhs.llbb, past_rhs.llbb]); return immediate_rvalue_bcx(join, phi, binop_ty); } fn trans_binary(bcx: block, - binop_expr: @ast::expr, + binop_expr: &ast::expr, op: ast::binop, lhs: @ast::expr, rhs: @ast::expr) -> DatumBlock { - let _icx = bcx.insn_ctxt("trans_binary"); + let _icx = push_ctxt("trans_binary"); match op { ast::and => { @@ -1525,7 +1519,7 @@ fn trans_binary(bcx: block, } fn trans_overloaded_op(bcx: block, - expr: @ast::expr, + expr: &ast::expr, callee_id: ast::node_id, rcvr: @ast::expr, args: ~[@ast::expr], @@ -1549,12 +1543,12 @@ fn trans_overloaded_op(bcx: block, DoAutorefArg) } -fn int_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef, +fn int_cast(bcx: block, lldsttype: Type, llsrctype: Type, llsrc: ValueRef, signed: bool) -> ValueRef { - let _icx = bcx.insn_ctxt("int_cast"); + let _icx = push_ctxt("int_cast"); unsafe { - let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype); - let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype); + let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref()); + let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref()); return if dstsz == srcsz { BitCast(bcx, llsrc, lldsttype) } else if srcsz > dstsz { @@ -1567,11 +1561,11 @@ fn int_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef, } } -fn float_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef, +fn float_cast(bcx: block, lldsttype: Type, llsrctype: Type, llsrc: ValueRef) -> ValueRef { - let _icx = bcx.insn_ctxt("float_cast"); - let srcsz = lib::llvm::float_width(llsrctype); - let dstsz = lib::llvm::float_width(lldsttype); + let _icx = push_ctxt("float_cast"); + let srcsz = llsrctype.float_width(); + let dstsz = lldsttype.float_width(); return if dstsz > srcsz { FPExt(bcx, llsrc, lldsttype) } else if srcsz > dstsz { @@ -1603,7 +1597,7 @@ pub fn cast_type_kind(t: ty::t) -> cast_kind { fn trans_imm_cast(bcx: block, expr: @ast::expr, id: ast::node_id) -> DatumBlock { - let _icx = bcx.insn_ctxt("trans_cast"); + let _icx = push_ctxt("trans_cast"); let ccx = bcx.ccx(); let t_out = node_id_type(bcx, id); @@ -1670,7 +1664,7 @@ fn trans_assign_op(bcx: block, dst: @ast::expr, src: @ast::expr) -> block { - let _icx = bcx.insn_ctxt("trans_assign_op"); + let _icx = push_ctxt("trans_assign_op"); let mut bcx = bcx; debug!("trans_assign_op(expr=%s)", bcx.expr_to_str(expr)); diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 40fa44d92ba..c01f01db5fd 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use back::{link, abi}; -use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg}; -use lib::llvm::{TypeRef, ValueRef}; +use lib::llvm::{ValueRef}; use lib; use middle::trans::base::*; use middle::trans::cabi; @@ -34,8 +32,8 @@ use middle::ty; use middle::ty::FnSig; use util::ppaux::ty_to_str; -use core::uint; -use core::vec; +use std::uint; +use std::vec; use syntax::codemap::span; use syntax::{ast, ast_util}; use syntax::{attr, ast_map}; @@ -45,6 +43,7 @@ use syntax::parse::token; use syntax::abi::{X86, X86_64, Arm, Mips}; use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, Cdecl, Aapcs, C}; +use middle::trans::type_::Type; fn abi_info(ccx: @mut CrateContext) -> @cabi::ABIInfo { return match ccx.sess.targ_cfg.arch { @@ -55,7 +54,7 @@ fn abi_info(ccx: @mut CrateContext) -> @cabi::ABIInfo { } } -pub fn link_name(ccx: &CrateContext, i: @ast::foreign_item) -> @str { +pub fn link_name(ccx: &CrateContext, i: &ast::foreign_item) -> @str { match attr::first_attr_value_str_by_name(i.attrs, "link_name") { None => ccx.sess.str_of(i.ident), Some(ln) => ln, @@ -73,10 +72,10 @@ struct ShimTypes { /// Type of the struct we will use to shuttle values back and forth. /// This is always derived from the llsig. - bundle_ty: TypeRef, + bundle_ty: Type, /// Type of the shim function itself. - shim_fn_ty: TypeRef, + shim_fn_ty: Type, /// Adapter object for handling native ABI rules (trust me, you /// don't want to know). @@ -84,12 +83,12 @@ struct ShimTypes { } struct LlvmSignature { - llarg_tys: ~[TypeRef], - llret_ty: TypeRef, + llarg_tys: ~[Type], + llret_ty: Type, sret: bool, } -fn foreign_signature(ccx: @mut CrateContext, fn_sig: &ty::FnSig) +fn foreign_signature(ccx: &mut CrateContext, fn_sig: &ty::FnSig) -> LlvmSignature { /*! * The ForeignSignature is the LLVM types of the arguments/return type @@ -114,20 +113,16 @@ fn shim_types(ccx: @mut CrateContext, id: ast::node_id) -> ShimTypes { _ => ccx.sess.bug("c_arg_and_ret_lltys called on non-function type") }; let llsig = foreign_signature(ccx, &fn_sig); - let bundle_ty = T_struct(vec::append_one(copy llsig.llarg_tys, - T_ptr(llsig.llret_ty)), - false); + let bundle_ty = Type::struct_(llsig.llarg_tys + [llsig.llret_ty.ptr_to()], false); let ret_def = !ty::type_is_bot(fn_sig.output) && !ty::type_is_nil(fn_sig.output); - let fn_ty = abi_info(ccx).compute_info(llsig.llarg_tys, - llsig.llret_ty, - ret_def); + let fn_ty = abi_info(ccx).compute_info(llsig.llarg_tys, llsig.llret_ty, ret_def); ShimTypes { fn_sig: fn_sig, llsig: llsig, ret_def: ret_def, bundle_ty: bundle_ty, - shim_fn_ty: T_fn([T_ptr(bundle_ty)], T_nil()), + shim_fn_ty: Type::func([bundle_ty.ptr_to()], &Type::void()), fn_ty: fn_ty } } @@ -142,7 +137,7 @@ type shim_ret_builder<'self> = llretval: ValueRef); fn build_shim_fn_(ccx: @mut CrateContext, - shim_name: ~str, + shim_name: &str, llbasefn: ValueRef, tys: &ShimTypes, cc: lib::llvm::CallConv, @@ -170,7 +165,7 @@ fn build_shim_fn_(ccx: @mut CrateContext, tie_up_header_blocks(fcx, lltop); let ret_cx = raw_block(fcx, false, fcx.llreturn); - Ret(ret_cx, C_null(T_nil())); + RetVoid(ret_cx); return llshimfn; } @@ -192,7 +187,7 @@ fn build_wrap_fn_(ccx: @mut CrateContext, needs_c_return: bool, arg_builder: wrap_arg_builder, ret_builder: wrap_ret_builder) { - let _icx = ccx.insn_ctxt("foreign::build_wrap_fn_"); + let _icx = push_ctxt("foreign::build_wrap_fn_"); let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, tys.fn_sig.output, None); // Patch up the return type if it's not immediate and we're returning via @@ -211,8 +206,8 @@ fn build_wrap_fn_(ccx: @mut CrateContext, arg_builder(bcx, tys, llwrapfn, llargbundle); // Create call itself. - let llshimfnptr = PointerCast(bcx, llshimfn, T_ptr(T_i8())); - let llrawargbundle = PointerCast(bcx, llargbundle, T_ptr(T_i8())); + let llshimfnptr = PointerCast(bcx, llshimfn, Type::i8p()); + let llrawargbundle = PointerCast(bcx, llargbundle, Type::i8p()); Call(bcx, shim_upcall, [llrawargbundle, llshimfnptr]); ret_builder(bcx, tys, llargbundle); @@ -221,28 +216,21 @@ fn build_wrap_fn_(ccx: @mut CrateContext, tie_up_header_blocks(fcx, lltop); // Then return according to the C ABI. - unsafe { - let return_context = raw_block(fcx, false, fcx.llreturn); - - let llfunctiontype = val_ty(llwrapfn); - let llfunctiontype = - ::lib::llvm::llvm::LLVMGetElementType(llfunctiontype); - let llfunctionreturntype = - ::lib::llvm::llvm::LLVMGetReturnType(llfunctiontype); - if ::lib::llvm::llvm::LLVMGetTypeKind(llfunctionreturntype) == - ::lib::llvm::Void { - // XXX: This might be wrong if there are any functions for which - // the C ABI specifies a void output pointer and the Rust ABI - // does not. - RetVoid(return_context); - } else { - // Cast if we have to... - // XXX: This is ugly. - let llretptr = BitCast(return_context, - fcx.llretptr.get(), - T_ptr(llfunctionreturntype)); - Ret(return_context, Load(return_context, llretptr)); - } + let return_context = raw_block(fcx, false, fcx.llreturn); + + let llfunctiontype = val_ty(llwrapfn); + let llfunctiontype = llfunctiontype.element_type(); + let return_type = llfunctiontype.return_type(); + if return_type.kind() == ::lib::llvm::Void { + // XXX: This might be wrong if there are any functions for which + // the C ABI specifies a void output pointer and the Rust ABI + // does not. + RetVoid(return_context); + } else { + // Cast if we have to... + // XXX: This is ugly. + let llretptr = BitCast(return_context, fcx.llretptr.get(), return_type.ptr_to()); + Ret(return_context, Load(return_context, llretptr)); } } @@ -285,7 +273,7 @@ fn build_wrap_fn_(ccx: @mut CrateContext, pub fn trans_foreign_mod(ccx: @mut CrateContext, path: &ast_map::path, foreign_mod: &ast::foreign_mod) { - let _icx = ccx.insn_ctxt("foreign::trans_foreign_mod"); + let _icx = push_ctxt("foreign::trans_foreign_mod"); let arch = ccx.sess.targ_cfg.arch; let abi = match foreign_mod.abis.for_arch(arch) { @@ -300,7 +288,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, Some(abi) => abi, }; - for foreign_mod.items.each |&foreign_item| { + for foreign_mod.items.iter().advance |&foreign_item| { match foreign_item.node { ast::foreign_item_fn(*) => { let id = foreign_item.id; @@ -343,7 +331,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, } } } - ast::foreign_item_const(*) => { + ast::foreign_item_static(*) => { let ident = token::ident_to_str(&foreign_item.ident); ccx.item_symbols.insert(foreign_item.id, /* bad */ident.to_owned()); } @@ -368,7 +356,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, } fn build_shim_fn(ccx: @mut CrateContext, - foreign_item: @ast::foreign_item, + foreign_item: &ast::foreign_item, tys: &ShimTypes, cc: lib::llvm::CallConv) -> ValueRef { @@ -381,11 +369,11 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, * } */ - let _icx = ccx.insn_ctxt("foreign::build_shim_fn"); + let _icx = push_ctxt("foreign::build_shim_fn"); fn build_args(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) -> ~[ValueRef] { - let _icx = bcx.insn_ctxt("foreign::shim::build_args"); + let _icx = push_ctxt("foreign::shim::build_args"); tys.fn_ty.build_shim_args(bcx, tys.llsig.llarg_tys, llargbundle) } @@ -393,7 +381,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, tys: &ShimTypes, llargbundle: ValueRef, llretval: ValueRef) { - let _icx = bcx.insn_ctxt("foreign::shim::build_ret"); + let _icx = push_ctxt("foreign::shim::build_ret"); tys.fn_ty.build_shim_ret(bcx, tys.llsig.llarg_tys, tys.ret_def, @@ -430,7 +418,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, // over the place fn build_direct_fn(ccx: @mut CrateContext, decl: ValueRef, - item: @ast::foreign_item, + item: &ast::foreign_item, tys: &ShimTypes, cc: lib::llvm::CallConv) { debug!("build_direct_fn(%s)", link_name(ccx, item)); @@ -457,7 +445,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, // over the place fn build_fast_ffi_fn(ccx: @mut CrateContext, decl: ValueRef, - item: @ast::foreign_item, + item: &ast::foreign_item, tys: &ShimTypes, cc: lib::llvm::CallConv) { debug!("build_fast_ffi_fn(%s)", link_name(ccx, item)); @@ -499,7 +487,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, * account for the Rust modes. */ - let _icx = ccx.insn_ctxt("foreign::build_wrap_fn"); + let _icx = push_ctxt("foreign::build_wrap_fn"); build_wrap_fn_(ccx, tys, @@ -514,7 +502,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, tys: &ShimTypes, llwrapfn: ValueRef, llargbundle: ValueRef) { - let _icx = bcx.insn_ctxt("foreign::wrap::build_args"); + let _icx = push_ctxt("foreign::wrap::build_args"); let ccx = bcx.ccx(); let n = tys.llsig.llarg_tys.len(); for uint::range(0, n) |i| { @@ -530,17 +518,21 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, store_inbounds(bcx, llargval, llargbundle, [0u, i]); } - let llretptr = bcx.fcx.llretptr.get(); - store_inbounds(bcx, llretptr, llargbundle, [0u, n]); + + for bcx.fcx.llretptr.iter().advance |&retptr| { + store_inbounds(bcx, retptr, llargbundle, [0u, n]); + } } fn build_ret(bcx: block, shim_types: &ShimTypes, llargbundle: ValueRef) { - let _icx = bcx.insn_ctxt("foreign::wrap::build_ret"); + let _icx = push_ctxt("foreign::wrap::build_ret"); let arg_count = shim_types.fn_sig.inputs.len(); - let llretptr = load_inbounds(bcx, llargbundle, [0, arg_count]); - Store(bcx, Load(bcx, llretptr), bcx.fcx.llretptr.get()); + for bcx.fcx.llretptr.iter().advance |&retptr| { + let llretptr = load_inbounds(bcx, llargbundle, [0, arg_count]); + Store(bcx, Load(bcx, llretptr), retptr); + } build_return(bcx); } } @@ -548,7 +540,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext, pub fn trans_intrinsic(ccx: @mut CrateContext, decl: ValueRef, - item: @ast::foreign_item, + item: &ast::foreign_item, path: ast_map::path, substs: @param_substs, attributes: &[ast::attribute], @@ -562,7 +554,6 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, decl, item.id, output_type, - None, Some(substs), Some(item.span)); @@ -574,118 +565,76 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let mut bcx = top_scope_block(fcx, None); let lltop = bcx.llbb; let first_real_arg = fcx.arg_pos(0u); - match ccx.sess.str_of(item.ident).as_slice() { - "atomic_cxchg" => { - let old = AtomicCmpXchg(bcx, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - get_param(decl, first_real_arg + 2u), - SequentiallyConsistent); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_cxchg_acq" => { - let old = AtomicCmpXchg(bcx, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - get_param(decl, first_real_arg + 2u), - Acquire); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_cxchg_rel" => { - let old = AtomicCmpXchg(bcx, - get_param(decl, first_real_arg), + + let nm = ccx.sess.str_of(item.ident); + let name = nm.as_slice(); + + // This requires that atomic intrinsics follow a specific naming pattern: + // "atomic_<operation>[_<ordering>], and no ordering means SeqCst + if name.starts_with("atomic_") { + let split : ~[&str] = name.split_iter('_').collect(); + assert!(split.len() >= 2, "Atomic intrinsic not correct format"); + let order = if split.len() == 2 { + lib::llvm::SequentiallyConsistent + } else { + match split[2] { + "relaxed" => lib::llvm::Monotonic, + "acq" => lib::llvm::Acquire, + "rel" => lib::llvm::Release, + "acqrel" => lib::llvm::AcquireRelease, + _ => ccx.sess.fatal("Unknown ordering in atomic intrinsic") + } + }; + + match split[1] { + "cxchg" => { + let old = AtomicCmpXchg(bcx, get_param(decl, first_real_arg), + get_param(decl, first_real_arg + 1u), + get_param(decl, first_real_arg + 2u), + order); + Store(bcx, old, fcx.llretptr.get()); + } + "load" => { + let old = AtomicLoad(bcx, get_param(decl, first_real_arg), + order); + Store(bcx, old, fcx.llretptr.get()); + } + "store" => { + AtomicStore(bcx, get_param(decl, first_real_arg + 1u), + get_param(decl, first_real_arg), + order); + } + op => { + // These are all AtomicRMW ops + let atom_op = match op { + "xchg" => lib::llvm::Xchg, + "xadd" => lib::llvm::Add, + "xsub" => lib::llvm::Sub, + "and" => lib::llvm::And, + "nand" => lib::llvm::Nand, + "or" => lib::llvm::Or, + "xor" => lib::llvm::Xor, + "max" => lib::llvm::Max, + "min" => lib::llvm::Min, + "umax" => lib::llvm::UMax, + "umin" => lib::llvm::UMin, + _ => ccx.sess.fatal("Unknown atomic operation") + }; + + let old = AtomicRMW(bcx, atom_op, get_param(decl, first_real_arg), get_param(decl, first_real_arg + 1u), - get_param(decl, first_real_arg + 2u), - Release); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_load" => { - let old = AtomicLoad(bcx, - get_param(decl, first_real_arg), - SequentiallyConsistent); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_load_acq" => { - let old = AtomicLoad(bcx, - get_param(decl, first_real_arg), - Acquire); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_store" => { - AtomicStore(bcx, - get_param(decl, first_real_arg + 1u), - get_param(decl, first_real_arg), - SequentiallyConsistent); - } - "atomic_store_rel" => { - AtomicStore(bcx, - get_param(decl, first_real_arg + 1u), - get_param(decl, first_real_arg), - Release); - } - "atomic_xchg" => { - let old = AtomicRMW(bcx, Xchg, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - SequentiallyConsistent); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_xchg_acq" => { - let old = AtomicRMW(bcx, Xchg, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - Acquire); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_xchg_rel" => { - let old = AtomicRMW(bcx, Xchg, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - Release); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_xadd" => { - let old = AtomicRMW(bcx, lib::llvm::Add, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - SequentiallyConsistent); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_xadd_acq" => { - let old = AtomicRMW(bcx, lib::llvm::Add, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - Acquire); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_xadd_rel" => { - let old = AtomicRMW(bcx, lib::llvm::Add, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - Release); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_xsub" => { - let old = AtomicRMW(bcx, lib::llvm::Sub, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - SequentiallyConsistent); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_xsub_acq" => { - let old = AtomicRMW(bcx, lib::llvm::Sub, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - Acquire); - Store(bcx, old, fcx.llretptr.get()); - } - "atomic_xsub_rel" => { - let old = AtomicRMW(bcx, lib::llvm::Sub, - get_param(decl, first_real_arg), - get_param(decl, first_real_arg + 1u), - Release); - Store(bcx, old, fcx.llretptr.get()); + order); + Store(bcx, old, fcx.llretptr.get()); + } } + + build_return(bcx); + finish_fn(fcx, lltop); + + return; + } + + match name { "size_of" => { let tp_ty = substs.tys[0]; let lltp_ty = type_of::type_of(ccx, tp_ty); @@ -730,9 +679,12 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let static_ti = get_tydesc(ccx, tp_ty); glue::lazily_emit_all_tydesc_glue(ccx, static_ti); - // FIXME (#3727): change this to T_ptr(ccx.tydesc_ty) when the - // core::sys copy of the get_tydesc interface dies off. - let td = PointerCast(bcx, static_ti.tydesc, T_ptr(T_nil())); + // FIXME (#3730): ideally this shouldn't need a cast, + // but there's a circularity between translating rust types to llvm + // types and having a tydesc type available. So I can't directly access + // the llvm type of intrinsic::TyDesc struct. + let userland_tydesc_ty = type_of::type_of(ccx, output_type); + let td = PointerCast(bcx, static_ti.tydesc, userland_tydesc_ty); Store(bcx, td, fcx.llretptr.get()); } "init" => { @@ -776,7 +728,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, // code bloat when `transmute` is used on large structural // types. let lldestptr = fcx.llretptr.get(); - let lldestptr = PointerCast(bcx, lldestptr, T_ptr(T_i8())); + let lldestptr = PointerCast(bcx, lldestptr, Type::i8p()); let llsrcval = get_param(decl, first_real_arg); let llsrcptr = if ty::type_is_immediate(in_type) { @@ -786,7 +738,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, } else { llsrcval }; - let llsrcptr = PointerCast(bcx, llsrcptr, T_ptr(T_i8())); + let llsrcptr = PointerCast(bcx, llsrcptr, Type::i8p()); let llsize = llsize_of(ccx, llintype); call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1); @@ -798,17 +750,20 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)), fcx.llretptr.get()); } + "contains_managed" => { + let tp_ty = substs.tys[0]; + Store(bcx, + C_bool(ty::type_contents(ccx.tcx, tp_ty).contains_managed()), + fcx.llretptr.get()); + } "visit_tydesc" => { let td = get_param(decl, first_real_arg); let visitor = get_param(decl, first_real_arg + 1u); //let llvisitorptr = alloca(bcx, val_ty(visitor)); //Store(bcx, visitor, llvisitorptr); - let td = PointerCast(bcx, td, T_ptr(ccx.tydesc_type)); - glue::call_tydesc_glue_full(bcx, - visitor, - td, - abi::tydesc_field_visit_glue, - None); + let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to()); + glue::call_tydesc_glue_full(bcx, visitor, td, + abi::tydesc_field_visit_glue, None); } "frame_address" => { let frameaddress = ccx.intrinsics.get_copy(& &"llvm.frameaddress"); @@ -843,8 +798,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let llfty = type_of_fn(bcx.ccx(), [], ty::mk_nil()); let morestack_addr = decl_cdecl_fn( bcx.ccx().llmod, "__morestack", llfty); - let morestack_addr = PointerCast(bcx, morestack_addr, - T_ptr(T_nil())); + let morestack_addr = PointerCast(bcx, morestack_addr, Type::nil().ptr_to()); Store(bcx, morestack_addr, fcx.llretptr.get()); } "memcpy32" => { @@ -853,8 +807,8 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32); let size = C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32); - let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), T_ptr(T_i8())); - let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), T_ptr(T_i8())); + let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p()); + let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p()); let count = get_param(decl, first_real_arg + 2); let volatile = C_i1(false); let llfn = bcx.ccx().intrinsics.get_copy(& &"llvm.memcpy.p0i8.p0i8.i32"); @@ -866,8 +820,8 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32); let size = C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64); - let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), T_ptr(T_i8())); - let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), T_ptr(T_i8())); + let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p()); + let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p()); let count = get_param(decl, first_real_arg + 2); let volatile = C_i1(false); let llfn = bcx.ccx().intrinsics.get_copy(& &"llvm.memcpy.p0i8.p0i8.i64"); @@ -879,8 +833,8 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32); let size = C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32); - let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), T_ptr(T_i8())); - let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), T_ptr(T_i8())); + let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p()); + let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p()); let count = get_param(decl, first_real_arg + 2); let volatile = C_i1(false); let llfn = bcx.ccx().intrinsics.get_copy(& &"llvm.memmove.p0i8.p0i8.i32"); @@ -892,8 +846,8 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32); let size = C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64); - let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), T_ptr(T_i8())); - let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), T_ptr(T_i8())); + let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p()); + let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p()); let count = get_param(decl, first_real_arg + 2); let volatile = C_i1(false); let llfn = bcx.ccx().intrinsics.get_copy(& &"llvm.memmove.p0i8.p0i8.i64"); @@ -905,7 +859,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32); let size = C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32); - let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), T_ptr(T_i8())); + let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p()); let val = get_param(decl, first_real_arg + 1); let count = get_param(decl, first_real_arg + 2); let volatile = C_i1(false); @@ -918,7 +872,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32); let size = C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64); - let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), T_ptr(T_i8())); + let dst_ptr = PointerCast(bcx, get_param(decl, first_real_arg), Type::i8p()); let val = get_param(decl, first_real_arg + 1); let count = get_param(decl, first_real_arg + 2); let volatile = C_i1(false); @@ -1208,7 +1162,7 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, body: &ast::blk, llwrapfn: ValueRef, id: ast::node_id) { - let _icx = ccx.insn_ctxt("foreign::build_foreign_fn"); + let _icx = push_ctxt("foreign::build_foreign_fn"); fn build_rust_fn(ccx: @mut CrateContext, path: ast_map::path, @@ -1216,7 +1170,7 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, body: &ast::blk, id: ast::node_id) -> ValueRef { - let _icx = ccx.insn_ctxt("foreign::foreign::build_rust_fn"); + let _icx = push_ctxt("foreign::foreign::build_rust_fn"); let t = ty::node_id_to_type(ccx.tcx, id); // XXX: Bad copy. let ps = link::mangle_internal_name_by_path( @@ -1233,7 +1187,6 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, no_self, None, id, - None, []); return llfndecl; } @@ -1258,11 +1211,11 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, * one of those types that is passed by pointer in Rust. */ - let _icx = ccx.insn_ctxt("foreign::foreign::build_shim_fn"); + let _icx = push_ctxt("foreign::foreign::build_shim_fn"); fn build_args(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) -> ~[ValueRef] { - let _icx = bcx.insn_ctxt("foreign::extern::shim::build_args"); + let _icx = push_ctxt("foreign::extern::shim::build_args"); let ccx = bcx.ccx(); let mut llargvals = ~[]; let mut i = 0u; @@ -1273,7 +1226,7 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, llargvals.push(llretptr); } - let llenvptr = C_null(T_opaque_box_ptr(bcx.ccx())); + let llenvptr = C_null(Type::opaque_box(bcx.ccx()).ptr_to()); llargvals.push(llenvptr); while i < n { // Get a pointer to the argument: @@ -1294,7 +1247,7 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, shim_types: &ShimTypes, llargbundle: ValueRef, llretval: ValueRef) { - if ty::type_is_immediate(shim_types.fn_sig.output) { + if bcx.fcx.llretptr.is_some() && ty::type_is_immediate(shim_types.fn_sig.output) { // Write the value into the argument bundle. let arg_count = shim_types.fn_sig.inputs.len(); let llretptr = load_inbounds(bcx, @@ -1337,7 +1290,7 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, * } */ - let _icx = ccx.insn_ctxt("foreign::foreign::build_wrap_fn"); + let _icx = push_ctxt("foreign::foreign::build_wrap_fn"); build_wrap_fn_(ccx, tys, @@ -1352,7 +1305,7 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, tys: &ShimTypes, llwrapfn: ValueRef, llargbundle: ValueRef) { - let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_args"); + let _icx = push_ctxt("foreign::foreign::wrap::build_args"); tys.fn_ty.build_wrap_args(bcx, tys.llsig.llret_ty, llwrapfn, @@ -1360,7 +1313,7 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, } fn build_ret(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) { - let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_ret"); + let _icx = push_ctxt("foreign::foreign::wrap::build_ret"); tys.fn_ty.build_wrap_ret(bcx, tys.llsig.llarg_tys, llargbundle); build_return(bcx); } @@ -1382,7 +1335,7 @@ pub fn register_foreign_fn(ccx: @mut CrateContext, node_id: ast::node_id, attrs: &[ast::attribute]) -> ValueRef { - let _icx = ccx.insn_ctxt("foreign::register_foreign_fn"); + let _icx = push_ctxt("foreign::register_foreign_fn"); let t = ty::node_id_to_type(ccx.tcx, node_id); diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 05461c93631..68cf66789bf 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -12,13 +12,12 @@ // // Code relating to taking, dropping, etc as well as type descriptors. -use core::prelude::*; use back::abi; use back::link::*; use driver::session; use lib; -use lib::llvm::{llvm, ValueRef, TypeRef, True}; +use lib::llvm::{llvm, ValueRef, True}; use middle::trans::adt; use middle::trans::base::*; use middle::trans::callee; @@ -29,40 +28,39 @@ use middle::trans::expr; use middle::trans::machine::*; use middle::trans::reflect; use middle::trans::tvec; -use middle::trans::type_of::{type_of, type_of_glue_fn}; +use middle::trans::type_of::type_of; use middle::trans::uniq; use middle::ty; use util::ppaux; use util::ppaux::ty_to_short_str; -use core::io; -use core::libc::c_uint; -use core::str; -use core::vec; +use middle::trans::type_::Type; + +use std::io; +use std::libc::c_uint; +use std::str; use extra::time; use syntax::ast; pub fn trans_free(cx: block, v: ValueRef) -> block { - let _icx = cx.insn_ctxt("trans_free"); - callee::trans_lang_call( - cx, + let _icx = push_ctxt("trans_free"); + callee::trans_lang_call(cx, cx.tcx().lang_items.free_fn(), - [PointerCast(cx, v, T_ptr(T_i8()))], + [PointerCast(cx, v, Type::i8p())], expr::Ignore) } pub fn trans_exchange_free(cx: block, v: ValueRef) -> block { - let _icx = cx.insn_ctxt("trans_exchange_free"); - callee::trans_lang_call( - cx, + let _icx = push_ctxt("trans_exchange_free"); + callee::trans_lang_call(cx, cx.tcx().lang_items.exchange_free_fn(), - [PointerCast(cx, v, T_ptr(T_i8()))], + [PointerCast(cx, v, Type::i8p())], expr::Ignore) } pub fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block { // NB: v is an *alias* of type t here, not a direct value. - let _icx = cx.insn_ctxt("take_ty"); + let _icx = push_ctxt("take_ty"); if ty::type_needs_drop(cx.tcx(), t) { return call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue); } @@ -71,38 +69,24 @@ pub fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block { pub fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block { // NB: v is an *alias* of type t here, not a direct value. - let _icx = cx.insn_ctxt("drop_ty"); + let _icx = push_ctxt("drop_ty"); if ty::type_needs_drop(cx.tcx(), t) { return call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue); } return cx; } -pub fn drop_ty_root(bcx: block, - v: ValueRef, - rooted: bool, - t: ty::t) - -> block { - if rooted { - // NB: v is a raw ptr to an addrspace'd ptr to the value. - let v = PointerCast(bcx, Load(bcx, v), T_ptr(type_of(bcx.ccx(), t))); - drop_ty(bcx, v, t) - } else { - drop_ty(bcx, v, t) - } -} - pub fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block { - let _icx = bcx.insn_ctxt("drop_ty_immediate"); + let _icx = push_ctxt("drop_ty_immediate"); match ty::get(t).sty { - ty::ty_uniq(_) | - ty::ty_evec(_, ty::vstore_uniq) | - ty::ty_estr(ty::vstore_uniq) => { + ty::ty_uniq(_) + | ty::ty_evec(_, ty::vstore_uniq) + | ty::ty_estr(ty::vstore_uniq) => { free_ty_immediate(bcx, v, t) } - ty::ty_box(_) | ty::ty_opaque_box | - ty::ty_evec(_, ty::vstore_box) | - ty::ty_estr(ty::vstore_box) => { + ty::ty_box(_) | ty::ty_opaque_box + | ty::ty_evec(_, ty::vstore_box) + | ty::ty_estr(ty::vstore_box) => { decr_refcnt_maybe_free(bcx, v, None, t) } _ => bcx.tcx().sess.bug("drop_ty_immediate: non-box ty") @@ -110,7 +94,7 @@ pub fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block { } pub fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> Result { - let _icx = bcx.insn_ctxt("take_ty_immediate"); + let _icx = push_ctxt("take_ty_immediate"); match ty::get(t).sty { ty::ty_box(_) | ty::ty_opaque_box | ty::ty_evec(_, ty::vstore_box) | @@ -131,7 +115,7 @@ pub fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> Result { pub fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block { // NB: v is an *alias* of type t here, not a direct value. - let _icx = cx.insn_ctxt("free_ty"); + let _icx = push_ctxt("free_ty"); if ty::type_needs_drop(cx.tcx(), t) { return call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue); } @@ -139,7 +123,7 @@ pub fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block { } pub fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block { - let _icx = bcx.insn_ctxt("free_ty_immediate"); + let _icx = push_ctxt("free_ty_immediate"); match ty::get(t).sty { ty::ty_uniq(_) | ty::ty_evec(_, ty::vstore_uniq) | @@ -220,8 +204,8 @@ pub fn simplified_glue_type(tcx: ty::ctxt, field: uint, t: ty::t) -> ty::t { pub fn lazily_emit_simplified_tydesc_glue(ccx: @mut CrateContext, field: uint, - ti: @mut tydesc_info) -> bool { - let _icx = ccx.insn_ctxt("lazily_emit_simplified_tydesc_glue"); + ti: &mut tydesc_info) -> bool { + let _icx = push_ctxt("lazily_emit_simplified_tydesc_glue"); let simpl = simplified_glue_type(ccx.tcx, field, ti.ty); if simpl != ti.ty { let simpl_ti = get_tydesc(ccx, simpl); @@ -246,8 +230,8 @@ pub fn lazily_emit_simplified_tydesc_glue(ccx: @mut CrateContext, pub fn lazily_emit_tydesc_glue(ccx: @mut CrateContext, field: uint, ti: @mut tydesc_info) { - let _icx = ccx.insn_ctxt("lazily_emit_tydesc_glue"); - let llfnty = type_of_glue_fn(ccx); + let _icx = push_ctxt("lazily_emit_tydesc_glue"); + let llfnty = Type::glue_fn(); if lazily_emit_simplified_tydesc_glue(ccx, field, ti) { return; @@ -259,7 +243,7 @@ pub fn lazily_emit_tydesc_glue(ccx: @mut CrateContext, None => { debug!("+++ lazily_emit_tydesc_glue TAKE %s", ppaux::ty_to_str(ccx.tcx, ti.ty)); - let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"take"); + let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "take"); ti.take_glue = Some(glue_fn); make_generic_glue(ccx, ti.ty, glue_fn, make_take_glue, "take"); debug!("--- lazily_emit_tydesc_glue TAKE %s", @@ -272,7 +256,7 @@ pub fn lazily_emit_tydesc_glue(ccx: @mut CrateContext, None => { debug!("+++ lazily_emit_tydesc_glue DROP %s", ppaux::ty_to_str(ccx.tcx, ti.ty)); - let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"drop"); + let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "drop"); ti.drop_glue = Some(glue_fn); make_generic_glue(ccx, ti.ty, glue_fn, make_drop_glue, "drop"); debug!("--- lazily_emit_tydesc_glue DROP %s", @@ -285,7 +269,7 @@ pub fn lazily_emit_tydesc_glue(ccx: @mut CrateContext, None => { debug!("+++ lazily_emit_tydesc_glue FREE %s", ppaux::ty_to_str(ccx.tcx, ti.ty)); - let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"free"); + let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "free"); ti.free_glue = Some(glue_fn); make_generic_glue(ccx, ti.ty, glue_fn, make_free_glue, "free"); debug!("--- lazily_emit_tydesc_glue FREE %s", @@ -298,7 +282,7 @@ pub fn lazily_emit_tydesc_glue(ccx: @mut CrateContext, None => { debug!("+++ lazily_emit_tydesc_glue VISIT %s", ppaux::ty_to_str(ccx.tcx, ti.ty)); - let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, ~"visit"); + let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "visit"); ti.visit_glue = Some(glue_fn); make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit"); debug!("--- lazily_emit_tydesc_glue VISIT %s", @@ -314,7 +298,7 @@ pub fn call_tydesc_glue_full(bcx: block, tydesc: ValueRef, field: uint, static_ti: Option<@mut tydesc_info>) { - let _icx = bcx.insn_ctxt("call_tydesc_glue_full"); + let _icx = push_ctxt("call_tydesc_glue_full"); let ccx = bcx.ccx(); // NB: Don't short-circuit even if this block is unreachable because // GC-based cleanup needs to the see that the roots are live. @@ -340,7 +324,7 @@ pub fn call_tydesc_glue_full(bcx: block, } }; - let llrawptr = PointerCast(bcx, v, T_ptr(T_i8())); + let llrawptr = PointerCast(bcx, v, Type::i8p()); let llfn = { match static_glue_fn { @@ -353,26 +337,24 @@ pub fn call_tydesc_glue_full(bcx: block, } }; - Call(bcx, llfn, [C_null(T_ptr(T_nil())), - C_null(T_ptr(T_ptr(bcx.ccx().tydesc_type))), - llrawptr]); + Call(bcx, llfn, [C_null(Type::nil().ptr_to()), llrawptr]); } // See [Note-arg-mode] pub fn call_tydesc_glue(cx: block, v: ValueRef, t: ty::t, field: uint) -> block { - let _icx = cx.insn_ctxt("call_tydesc_glue"); + let _icx = push_ctxt("call_tydesc_glue"); let ti = get_tydesc(cx.ccx(), t); call_tydesc_glue_full(cx, v, ti.tydesc, field, Some(ti)); return cx; } pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) { - let _icx = bcx.insn_ctxt("make_visit_glue"); + let _icx = push_ctxt("make_visit_glue"); let bcx = do with_scope(bcx, None, "visitor cleanup") |bcx| { let mut bcx = bcx; let (visitor_trait, object_ty) = ty::visitor_object_ty(bcx.tcx()); - let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), object_ty))); + let v = PointerCast(bcx, v, type_of::type_of(bcx.ccx(), object_ty).ptr_to()); bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id); // The visitor is a boxed object and needs to be dropped add_clean(bcx, v, object_ty); @@ -383,14 +365,11 @@ pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) { pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { // NB: v0 is an *alias* of type t here, not a direct value. - let _icx = bcx.insn_ctxt("make_free_glue"); - let ccx = bcx.ccx(); + let _icx = push_ctxt("make_free_glue"); let bcx = match ty::get(t).sty { ty::ty_box(body_mt) => { let v = Load(bcx, v); let body = GEPi(bcx, v, [0u, abi::box_field_body]); - // Cast away the addrspace of the box pointer. - let body = PointerCast(bcx, body, T_ptr(type_of(ccx, body_mt.ty))); let bcx = drop_ty(bcx, body, body_mt.ty); trans_free(bcx, v) } @@ -424,13 +403,8 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { build_return(bcx); } -pub fn trans_struct_drop(bcx: block, - t: ty::t, - v0: ValueRef, - dtor_did: ast::def_id, - class_did: ast::def_id, - substs: &ty::substs) - -> block { +pub fn trans_struct_drop_flag(bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id, + class_did: ast::def_id, substs: &ty::substs) -> block { let repr = adt::represent_type(bcx.ccx(), t); let drop_flag = adt::trans_drop_flag_ptr(bcx, repr, v0); do with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) |cx| { @@ -442,27 +416,22 @@ pub fn trans_struct_drop(bcx: block, // The second argument is the "self" argument for drop let params = unsafe { - lib::llvm::fn_ty_param_tys( - llvm::LLVMGetElementType(llvm::LLVMTypeOf(dtor_addr))) + let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr)); + ty.element_type().func_params() }; // Class dtors have no explicit args, so the params should // just consist of the environment (self) assert_eq!(params.len(), 1); - // Take a reference to the class (because it's using the Drop trait), - // do so now. - let llval = alloca(bcx, val_ty(v0)); - Store(bcx, v0, llval); - - let self_arg = PointerCast(bcx, llval, params[0]); + let self_arg = PointerCast(bcx, v0, params[0]); let args = ~[self_arg]; Call(bcx, dtor_addr, args); // Drop the fields let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs); - for vec::eachi(field_tys) |i, fld| { + for field_tys.iter().enumerate().advance |(i, fld)| { let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i); bcx = drop_ty(bcx, llfld_a, fld.mt.ty); } @@ -472,10 +441,42 @@ pub fn trans_struct_drop(bcx: block, } } +pub fn trans_struct_drop(mut bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id, + class_did: ast::def_id, substs: &ty::substs) -> block { + let repr = adt::represent_type(bcx.ccx(), t); + + // Find and call the actual destructor + let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, + class_did, /*bad*/copy substs.tps); + + // The second argument is the "self" argument for drop + let params = unsafe { + let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr)); + ty.element_type().func_params() + }; + + // Class dtors have no explicit args, so the params should + // just consist of the environment (self) + assert_eq!(params.len(), 1); + + let self_arg = PointerCast(bcx, v0, params[0]); + let args = ~[self_arg]; + + Call(bcx, dtor_addr, args); + + // Drop the fields + let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs); + for field_tys.iter().enumerate().advance |(i, fld)| { + let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i); + bcx = drop_ty(bcx, llfld_a, fld.mt.ty); + } + + bcx +} pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { // NB: v0 is an *alias* of type t here, not a direct value. - let _icx = bcx.insn_ctxt("make_drop_glue"); + let _icx = push_ctxt("make_drop_glue"); let ccx = bcx.ccx(); let bcx = match ty::get(t).sty { ty::ty_box(_) | ty::ty_opaque_box | @@ -492,7 +493,10 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { ty::ty_struct(did, ref substs) => { let tcx = bcx.tcx(); match ty::ty_dtor(tcx, did) { - ty::TraitDtor(dtor) => { + ty::TraitDtor(dtor, true) => { + trans_struct_drop_flag(bcx, t, v0, dtor, did, substs) + } + ty::TraitDtor(dtor, false) => { trans_struct_drop(bcx, t, v0, dtor, did, substs) } ty::NoDtor => { @@ -504,22 +508,21 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { ty::ty_closure(_) => { closure::make_closure_glue(bcx, v0, t, drop_ty) } - ty::ty_trait(_, _, ty::BoxTraitStore, _) => { + ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => { let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]); let llbox = Load(bcx, llbox_ptr); decr_refcnt_maybe_free(bcx, llbox, Some(llbox_ptr), ty::mk_opaque_box(ccx.tcx)) } - ty::ty_trait(_, _, ty::UniqTraitStore, _) => { + ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => { let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]); // Only drop the value when it is non-null do with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue))) |bcx| { let llvtable = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable])); // Cast the vtable to a pointer to a pointer to a tydesc. - let llvtable = PointerCast(bcx, - llvtable, - T_ptr(T_ptr(ccx.tydesc_type))); + let llvtable = PointerCast(bcx, llvtable, + ccx.tydesc_type.ptr_to().ptr_to()); let lltydesc = Load(bcx, llvtable); call_tydesc_glue_full(bcx, lluniquevalue, @@ -547,7 +550,7 @@ pub fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef, box_ptr_ptr: Option<ValueRef>, t: ty::t) -> block { - let _icx = bcx.insn_ctxt("decr_refcnt_maybe_free"); + let _icx = push_ctxt("decr_refcnt_maybe_free"); let ccx = bcx.ccx(); do with_cond(bcx, IsNotNull(bcx, box_ptr)) |bcx| { @@ -566,7 +569,7 @@ pub fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef, pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) { - let _icx = bcx.insn_ctxt("make_take_glue"); + let _icx = push_ctxt("make_take_glue"); // NB: v is a *pointer* to type t here, not a direct value. let bcx = match ty::get(t).sty { ty::ty_box(_) | ty::ty_opaque_box | @@ -590,21 +593,46 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) { ty::ty_closure(_) => { closure::make_closure_glue(bcx, v, t, take_ty) } - ty::ty_trait(_, _, ty::BoxTraitStore, _) => { + ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => { let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box])); incr_refcnt_of_boxed(bcx, llbox); bcx } - ty::ty_trait(_, _, ty::UniqTraitStore, _) => { - let llval = GEPi(bcx, v, [0, abi::trt_field_box]); - let lltydesc = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_tydesc])); - call_tydesc_glue_full(bcx, llval, lltydesc, - abi::tydesc_field_take_glue, None); - bcx + ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => { + let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]); + let llvtable = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_vtable])); + + // Cast the vtable to a pointer to a pointer to a tydesc. + let llvtable = PointerCast(bcx, llvtable, + bcx.ccx().tydesc_type.ptr_to().ptr_to()); + let lltydesc = Load(bcx, llvtable); + call_tydesc_glue_full(bcx, + lluniquevalue, + lltydesc, + abi::tydesc_field_take_glue, + None); + bcx } ty::ty_opaque_closure_ptr(ck) => { closure::make_opaque_cbox_take_glue(bcx, ck, v) } + ty::ty_struct(did, _) => { + let tcx = bcx.tcx(); + let bcx = iter_structural_ty(bcx, v, t, take_ty); + + match ty::ty_dtor(tcx, did) { + ty::TraitDtor(_, false) => { + // Zero out the struct + unsafe { + let ty = Type::from_ref(llvm::LLVMTypeOf(v)); + memzero(bcx, v, ty); + } + + } + _ => { } + } + bcx + } _ if ty::type_is_structural(t) => { iter_structural_ty(bcx, v, t, take_ty) } @@ -615,7 +643,7 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) { } pub fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) { - let _icx = cx.insn_ctxt("incr_refcnt_of_boxed"); + let _icx = push_ctxt("incr_refcnt_of_boxed"); let ccx = cx.ccx(); let rc_ptr = GEPi(cx, box_ptr, [0u, abi::box_field_refcnt]); let rc = Load(cx, rc_ptr); @@ -624,20 +652,6 @@ pub fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) { } -// Chooses the addrspace for newly declared types. -pub fn declare_tydesc_addrspace(ccx: &CrateContext, t: ty::t) -> addrspace { - if !ty::type_needs_drop(ccx.tcx, t) { - return default_addrspace; - } else if ty::type_is_immediate(t) { - // For immediate types, we don't actually need an addrspace, because - // e.g. boxed types include pointers to their contents which are - // already correctly tagged with addrspaces. - return default_addrspace; - } else { - return (ccx.next_addrspace)(); - } -} - // Generates the declaration for (but doesn't emit) a type descriptor. pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info { // If emit_tydescs already ran, then we shouldn't be creating any new @@ -647,20 +661,18 @@ pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info { let llty = type_of(ccx, t); if ccx.sess.count_type_sizes() { - io::println(fmt!("%u\t%s", - llsize_of_real(ccx, llty), + io::println(fmt!("%u\t%s", llsize_of_real(ccx, llty), ppaux::ty_to_str(ccx.tcx, t))); } let llsize = llsize_of(ccx, llty); let llalign = llalign_of(ccx, llty); - let addrspace = declare_tydesc_addrspace(ccx, t); let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc").to_managed(); note_unique_llvm_symbol(ccx, name); debug!("+++ declare_tydesc %s %s", ppaux::ty_to_str(ccx.tcx, t), name); let gvar = str::as_c_str(name, |buf| { unsafe { - llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type, buf) + llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type.to_ref(), buf) } }); let inf = @mut tydesc_info { @@ -668,7 +680,6 @@ pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info { tydesc: gvar, size: llsize, align: llalign, - addrspace: addrspace, take_glue: None, drop_glue: None, free_glue: None, @@ -678,12 +689,11 @@ pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info { return inf; } -pub type glue_helper = @fn(block, ValueRef, ty::t); +pub type glue_helper<'self> = &'self fn(block, ValueRef, ty::t); -pub fn declare_generic_glue(ccx: @mut CrateContext, t: ty::t, llfnty: TypeRef, - name: ~str) -> ValueRef { - let _icx = ccx.insn_ctxt("declare_generic_glue"); - let name = name; +pub fn declare_generic_glue(ccx: &mut CrateContext, t: ty::t, llfnty: Type, + name: &str) -> ValueRef { + let _icx = push_ctxt("declare_generic_glue"); let fn_nm = mangle_internal_name_by_type_and_seq(ccx, t, (~"glue_" + name)).to_managed(); debug!("%s is for type %s", fn_nm, ppaux::ty_to_str(ccx.tcx, t)); note_unique_llvm_symbol(ccx, fn_nm); @@ -697,7 +707,7 @@ pub fn make_generic_glue_inner(ccx: @mut CrateContext, llfn: ValueRef, helper: glue_helper) -> ValueRef { - let _icx = ccx.insn_ctxt("make_generic_glue_inner"); + let _icx = push_ctxt("make_generic_glue_inner"); let fcx = new_fn_ctxt(ccx, ~[], llfn, ty::mk_nil(), None); lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage); ccx.stats.n_glues_created += 1u; @@ -708,12 +718,16 @@ pub fn make_generic_glue_inner(ccx: @mut CrateContext, let bcx = top_scope_block(fcx, None); let lltop = bcx.llbb; - let rawptr0_arg = fcx.arg_pos(1u); + let rawptr0_arg = fcx.arg_pos(0u); let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, rawptr0_arg as c_uint) }; let llty = type_of(ccx, t); - let llrawptr0 = PointerCast(bcx, llrawptr0, T_ptr(llty)); + let llrawptr0 = PointerCast(bcx, llrawptr0, llty.ptr_to()); helper(bcx, llrawptr0, t); - finish_fn(fcx, lltop); + + // This is from the general finish fn, but that emits a ret {} that we don't want + Br(raw_block(fcx, false, fcx.llstaticallocas), lltop); + RetVoid(raw_block(fcx, false, fcx.llreturn)); + return llfn; } @@ -723,7 +737,7 @@ pub fn make_generic_glue(ccx: @mut CrateContext, helper: glue_helper, name: &str) -> ValueRef { - let _icx = ccx.insn_ctxt("make_generic_glue"); + let _icx = push_ctxt("make_generic_glue"); if !ccx.sess.trans_stats() { return make_generic_glue_inner(ccx, t, llfn, helper); } @@ -731,18 +745,15 @@ pub fn make_generic_glue(ccx: @mut CrateContext, let start = time::get_time(); let llval = make_generic_glue_inner(ccx, t, llfn, helper); let end = time::get_time(); - log_fn_time(ccx, - fmt!("glue %s %s", name, ty_to_short_str(ccx.tcx, t)), - start, - end); + ccx.log_fn_time(fmt!("glue %s %s", name, ty_to_short_str(ccx.tcx, t)), start, end); return llval; } pub fn emit_tydescs(ccx: &mut CrateContext) { - //let _icx = ccx.insn_ctxt("emit_tydescs"); + let _icx = push_ctxt("emit_tydescs"); // As of this point, allow no more tydescs to be created. ccx.finished_tydescs = true; - let glue_fn_ty = T_ptr(T_generic_glue_fn(ccx)); + let glue_fn_ty = Type::generic_glue_fn(ccx).ptr_to(); let tyds = &mut ccx.tydescs; for tyds.each_value |&val| { let ti = val; @@ -757,7 +768,7 @@ pub fn emit_tydescs(ccx: &mut CrateContext) { Some(v) => { unsafe { ccx.stats.n_real_glues += 1u; - llvm::LLVMConstPointerCast(v, glue_fn_ty) + llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref()) } } }; @@ -767,7 +778,7 @@ pub fn emit_tydescs(ccx: &mut CrateContext) { Some(v) => { unsafe { ccx.stats.n_real_glues += 1u; - llvm::LLVMConstPointerCast(v, glue_fn_ty) + llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref()) } } }; @@ -777,7 +788,7 @@ pub fn emit_tydescs(ccx: &mut CrateContext) { Some(v) => { unsafe { ccx.stats.n_real_glues += 1u; - llvm::LLVMConstPointerCast(v, glue_fn_ty) + llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref()) } } }; @@ -787,24 +798,18 @@ pub fn emit_tydescs(ccx: &mut CrateContext) { Some(v) => { unsafe { ccx.stats.n_real_glues += 1u; - llvm::LLVMConstPointerCast(v, glue_fn_ty) + llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref()) } } }; - let shape = C_null(T_ptr(T_i8())); - let shape_tables = C_null(T_ptr(T_i8())); - - let tydesc = - C_named_struct(ccx.tydesc_type, - [ti.size, // size - ti.align, // align - take_glue, // take_glue - drop_glue, // drop_glue - free_glue, // free_glue - visit_glue, // visit_glue - shape, // shape - shape_tables]); // shape_tables + let tydesc = C_named_struct(ccx.tydesc_type, + [ti.size, // size + ti.align, // align + take_glue, // take_glue + drop_glue, // drop_glue + free_glue, // free_glue + visit_glue]); // visit_glue unsafe { let gvar = ti.tydesc; @@ -812,18 +817,6 @@ pub fn emit_tydescs(ccx: &mut CrateContext) { llvm::LLVMSetGlobalConstant(gvar, True); lib::llvm::SetLinkage(gvar, lib::llvm::InternalLinkage); - // Index tydesc by addrspace. - if ti.addrspace > gc_box_addrspace { - let llty = T_ptr(ccx.tydesc_type); - let addrspace_name = fmt!("_gc_addrspace_metadata_%u", - ti.addrspace as uint); - let addrspace_gvar = str::as_c_str(addrspace_name, |buf| { - llvm::LLVMAddGlobal(ccx.llmod, llty, buf) - }); - lib::llvm::SetLinkage(addrspace_gvar, - lib::llvm::InternalLinkage); - llvm::LLVMSetInitializer(addrspace_gvar, gvar); - } } }; } diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index b0aedbae79b..893ef3feb56 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -8,18 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use metadata::csearch; use middle::astencode; -use middle::trans::base::{get_insn_ctxt}; -use middle::trans::base::{impl_owned_self, impl_self, no_self}; +use middle::trans::base::{push_ctxt, impl_self, no_self}; use middle::trans::base::{trans_item, get_item_val, trans_fn}; use middle::trans::common::*; use middle::ty; use util::ppaux::ty_to_str; -use core::vec; +use std::vec; use syntax::ast; use syntax::ast_map::path_name; use syntax::ast_util::local_def; @@ -30,7 +28,7 @@ use syntax::ast_util::local_def; pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id, translate: bool) -> ast::def_id { - let _icx = ccx.insn_ctxt("maybe_instantiate_inline"); + let _icx = push_ctxt("maybe_instantiate_inline"); match ccx.external.find(&fn_id) { Some(&Some(node_id)) => { // Already inline @@ -93,11 +91,16 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id, csearch::found(ast::ii_method(impl_did, mth)) => { ccx.stats.n_inlines += 1; ccx.external.insert(fn_id, Some(mth.id)); - let impl_tpt = ty::lookup_item_type(ccx.tcx, impl_did); - let num_type_params = - impl_tpt.generics.type_param_defs.len() + - mth.generics.ty_params.len(); - if translate && num_type_params == 0 { + // If this is a default method, we can't look up the + // impl type. But we aren't going to translate anyways, so don't. + if !translate { return local_def(mth.id); } + + let impl_tpt = ty::lookup_item_type(ccx.tcx, impl_did); + let num_type_params = + impl_tpt.generics.type_param_defs.len() + + mth.generics.ty_params.len(); + + if num_type_params == 0 { let llfn = get_item_val(ccx, mth.id); let path = vec::append( ty::item_path(ccx.tcx, impl_did), @@ -110,8 +113,8 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id, debug!("calling inline trans_fn with self_ty %s", ty_to_str(ccx.tcx, self_ty)); match mth.explicit_self.node { - ast::sty_value => impl_owned_self(self_ty), - _ => impl_self(self_ty), + ast::sty_value => impl_self(self_ty, ty::ByRef), + _ => impl_self(self_ty, ty::ByCopy), } } }; @@ -123,7 +126,6 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id, self_kind, None, mth.id, - Some(impl_did), []); } local_def(mth.id) diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs index fb94fe4752a..f55523b2841 100644 --- a/src/librustc/middle/trans/machine.rs +++ b/src/librustc/middle/trans/machine.rs @@ -10,7 +10,7 @@ // Information concerning the machine representation of various types. -use lib::llvm::{ValueRef, TypeRef}; +use lib::llvm::{ValueRef}; use lib::llvm::False; use lib::llvm::llvm; use middle::trans::common::*; @@ -18,21 +18,23 @@ use middle::trans::type_of; use middle::ty; use util::ppaux::ty_to_str; +use middle::trans::type_::Type; + // ______________________________________________________________________ // compute sizeof / alignof // Returns the number of bytes clobbered by a Store to this type. -pub fn llsize_of_store(cx: &CrateContext, t: TypeRef) -> uint { +pub fn llsize_of_store(cx: &CrateContext, ty: Type) -> uint { unsafe { - return llvm::LLVMStoreSizeOfType(cx.td.lltd, t) as uint; + return llvm::LLVMStoreSizeOfType(cx.td.lltd, ty.to_ref()) as uint; } } // Returns the number of bytes between successive elements of type T in an // array of T. This is the "ABI" size. It includes any ABI-mandated padding. -pub fn llsize_of_alloc(cx: &CrateContext, t: TypeRef) -> uint { +pub fn llsize_of_alloc(cx: &CrateContext, ty: Type) -> uint { unsafe { - return llvm::LLVMABISizeOfType(cx.td.lltd, t) as uint; + return llvm::LLVMABISizeOfType(cx.td.lltd, ty.to_ref()) as uint; } } @@ -44,9 +46,9 @@ pub fn llsize_of_alloc(cx: &CrateContext, t: TypeRef) -> uint { // that LLVM *does* distinguish between e.g. a 1-bit value and an 8-bit value // at the codegen level! In general you should prefer `llbitsize_of_real` // below. -pub fn llsize_of_real(cx: &CrateContext, t: TypeRef) -> uint { +pub fn llsize_of_real(cx: &CrateContext, ty: Type) -> uint { unsafe { - let nbits = llvm::LLVMSizeOfTypeInBits(cx.td.lltd, t) as uint; + let nbits = llvm::LLVMSizeOfTypeInBits(cx.td.lltd, ty.to_ref()) as uint; if nbits & 7u != 0u { // Not an even number of bytes, spills into "next" byte. 1u + (nbits >> 3) @@ -57,14 +59,14 @@ pub fn llsize_of_real(cx: &CrateContext, t: TypeRef) -> uint { } /// Returns the "real" size of the type in bits. -pub fn llbitsize_of_real(cx: &CrateContext, t: TypeRef) -> uint { +pub fn llbitsize_of_real(cx: &CrateContext, ty: Type) -> uint { unsafe { - llvm::LLVMSizeOfTypeInBits(cx.td.lltd, t) as uint + llvm::LLVMSizeOfTypeInBits(cx.td.lltd, ty.to_ref()) as uint } } /// Returns the size of the type as an LLVM constant integer value. -pub fn llsize_of(cx: &CrateContext, t: TypeRef) -> ValueRef { +pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef { // Once upon a time, this called LLVMSizeOf, which does a // getelementptr(1) on a null pointer and casts to an int, in // order to obtain the type size as a value without requiring the @@ -72,17 +74,17 @@ pub fn llsize_of(cx: &CrateContext, t: TypeRef) -> ValueRef { // there's no need for that contrivance. The instruction // selection DAG generator would flatten that GEP(1) node into a // constant of the type's alloc size, so let's save it some work. - return C_uint(cx, llsize_of_alloc(cx, t)); + return C_uint(cx, llsize_of_alloc(cx, ty)); } // Returns the "default" size of t (see above), or 1 if the size would // be zero. This is important for things like vectors that expect // space to be consumed. -pub fn nonzero_llsize_of(cx: &CrateContext, t: TypeRef) -> ValueRef { - if llbitsize_of_real(cx, t) == 0 { - unsafe { llvm::LLVMConstInt(cx.int_type, 1, False) } +pub fn nonzero_llsize_of(cx: &CrateContext, ty: Type) -> ValueRef { + if llbitsize_of_real(cx, ty) == 0 { + unsafe { llvm::LLVMConstInt(cx.int_type.to_ref(), 1, False) } } else { - llsize_of(cx, t) + llsize_of(cx, ty) } } @@ -90,28 +92,28 @@ pub fn nonzero_llsize_of(cx: &CrateContext, t: TypeRef) -> ValueRef { // The preferred alignment may be larger than the alignment used when // packing the type into structs. This will be used for things like // allocations inside a stack frame, which LLVM has a free hand in. -pub fn llalign_of_pref(cx: &CrateContext, t: TypeRef) -> uint { +pub fn llalign_of_pref(cx: &CrateContext, ty: Type) -> uint { unsafe { - return llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, t) as uint; + return llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, ty.to_ref()) as uint; } } // Returns the minimum alignment of a type required by the platform. // This is the alignment that will be used for struct fields, arrays, // and similar ABI-mandated things. -pub fn llalign_of_min(cx: &CrateContext, t: TypeRef) -> uint { +pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> uint { unsafe { - return llvm::LLVMABIAlignmentOfType(cx.td.lltd, t) as uint; + return llvm::LLVMABIAlignmentOfType(cx.td.lltd, ty.to_ref()) as uint; } } // Returns the "default" alignment of t, which is calculated by casting // null to a record containing a single-bit followed by a t value, then // doing gep(0,1) to get at the trailing (and presumably padded) t cell. -pub fn llalign_of(cx: &CrateContext, t: TypeRef) -> ValueRef { +pub fn llalign_of(cx: &CrateContext, ty: Type) -> ValueRef { unsafe { return llvm::LLVMConstIntCast( - llvm::LLVMAlignOf(t), cx.int_type, False); + llvm::LLVMAlignOf(ty.to_ref()), cx.int_type.to_ref(), False); } } @@ -128,7 +130,7 @@ pub fn static_size_of_enum(cx: &mut CrateContext, t: ty::t) -> uint { // Compute max(variant sizes). let mut max_size = 0; let variants = ty::enum_variants(cx.tcx, tid); - for variants.each |variant| { + for variants.iter().advance |variant| { if variant.args.len() == 0 { loop; } @@ -140,9 +142,9 @@ pub fn static_size_of_enum(cx: &mut CrateContext, t: ty::t) -> uint { debug!("static_size_of_enum: variant %s type %s", cx.tcx.sess.str_of(variant.name), - ty_str(cx.tn, T_struct(lltypes, false))); + cx.tn.type_to_str(Type::struct_(lltypes, false))); - let this_size = llsize_of_real(cx, T_struct(lltypes, false)); + let this_size = llsize_of_real(cx, Type::struct_(lltypes, false)); if max_size < this_size { max_size = this_size; } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index c59b3f36779..9792e623388 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use back::abi; use lib::llvm::llvm; @@ -20,6 +19,7 @@ use middle::trans::build::*; use middle::trans::callee::*; use middle::trans::callee; use middle::trans::common::*; +use middle::trans::datum::*; use middle::trans::expr::{SaveIn, Ignore}; use middle::trans::expr; use middle::trans::glue; @@ -30,8 +30,9 @@ use middle::typeck; use util::common::indenter; use util::ppaux::Repr; -use core::str; -use core::vec; +use middle::trans::type_::Type; + +use std::vec; use syntax::ast_map::{path, path_mod, path_name}; use syntax::ast_util; use syntax::{ast, ast_map}; @@ -47,42 +48,26 @@ pub fn trans_impl(ccx: @mut CrateContext, name: ast::ident, methods: &[@ast::method], generics: &ast::Generics, - self_ty: Option<ty::t>, id: ast::node_id) { - let _icx = ccx.insn_ctxt("impl::trans_impl"); + let _icx = push_ctxt("impl::trans_impl"); let tcx = ccx.tcx; - debug!("trans_impl(path=%s, name=%s, self_ty=%s, id=%?)", - path.repr(tcx), name.repr(tcx), self_ty.repr(tcx), id); + debug!("trans_impl(path=%s, name=%s, id=%?)", + path.repr(tcx), name.repr(tcx), id); if !generics.ty_params.is_empty() { return; } let sub_path = vec::append_one(path, path_name(name)); - for methods.each |method| { + for methods.iter().advance |method| { if method.generics.ty_params.len() == 0u { let llfn = get_item_val(ccx, method.id); let path = vec::append_one(/*bad*/copy sub_path, path_name(method.ident)); - let param_substs_opt; - match self_ty { - None => param_substs_opt = None, - Some(self_ty) => { - param_substs_opt = Some(@param_substs { - tys: ~[], - vtables: None, - type_param_defs: @~[], - self_ty: Some(self_ty) - }); - } - } - trans_method(ccx, path, *method, - param_substs_opt, - self_ty, - llfn, - ast_util::local_def(id)); + None, + llfn); } } } @@ -96,9 +81,6 @@ Translates a (possibly monomorphized) method body. - `method`: the AST node for the method - `param_substs`: if this is a generic method, the current values for type parameters and so forth, else none -- `base_self_ty`: optionally, the explicit self type for this method. This - will be none if this is not a default method and must always be present - if this is a default method. - `llfn`: the LLVM ValueRef for the method - `impl_id`: the node ID of the impl this method is inside */ @@ -106,9 +88,7 @@ pub fn trans_method(ccx: @mut CrateContext, path: path, method: &ast::method, param_substs: Option<@param_substs>, - base_self_ty: Option<ty::t>, - llfn: ValueRef, - impl_id: ast::def_id) { + llfn: ValueRef) { // figure out how self is being passed let self_arg = match method.explicit_self.node { ast::sty_static => { @@ -117,26 +97,18 @@ pub fn trans_method(ccx: @mut CrateContext, _ => { // determine the (monomorphized) type that `self` maps to for // this method - let self_ty = match base_self_ty { - None => ty::node_id_to_type(ccx.tcx, method.self_id), - Some(provided_self_ty) => provided_self_ty, - }; + let self_ty = ty::node_id_to_type(ccx.tcx, method.self_id); let self_ty = match param_substs { None => self_ty, - Some(@param_substs {tys: ref tys, _}) => { - ty::subst_tps(ccx.tcx, *tys, None, self_ty) + Some(@param_substs {tys: ref tys, self_ty: ref self_sub, _}) => { + ty::subst_tps(ccx.tcx, *tys, *self_sub, self_ty) } }; - debug!("calling trans_fn with base_self_ty %s, self_ty %s", - base_self_ty.repr(ccx.tcx), + debug!("calling trans_fn with self_ty %s", self_ty.repr(ccx.tcx)); match method.explicit_self.node { - ast::sty_value => { - impl_owned_self(self_ty) - } - _ => { - impl_self(self_ty) - } + ast::sty_value => impl_self(self_ty, ty::ByRef), + _ => impl_self(self_ty, ty::ByCopy), } } }; @@ -150,34 +122,24 @@ pub fn trans_method(ccx: @mut CrateContext, self_arg, param_substs, method.id, - Some(impl_id), []); } pub fn trans_self_arg(bcx: block, base: @ast::expr, + temp_cleanups: &mut ~[ValueRef], mentry: typeck::method_map_entry) -> Result { - let _icx = bcx.insn_ctxt("impl::trans_self_arg"); - let mut temp_cleanups = ~[]; - - // Compute the type of self. - let self_ty = monomorphize_type(bcx, mentry.self_ty); - - let result = trans_arg_expr(bcx, - self_ty, - mentry.self_mode, - base, - &mut temp_cleanups, - None, - DontAutorefArg); - - // FIXME(#3446)---this is wrong, actually. The temp_cleanups - // should be revoked only after all arguments have been passed. - for temp_cleanups.each |c| { - revoke_clean(bcx, *c) - } - - return result; + let _icx = push_ctxt("impl::trans_self_arg"); + + // self is passed as an opaque box in the environment slot + let self_ty = ty::mk_opaque_box(bcx.tcx()); + trans_arg_expr(bcx, + self_ty, + mentry.self_mode, + base, + temp_cleanups, + None, + DontAutorefArg) } pub fn trans_method_callee(bcx: block, @@ -185,7 +147,7 @@ pub fn trans_method_callee(bcx: block, this: @ast::expr, mentry: typeck::method_map_entry) -> Callee { - let _icx = bcx.insn_ctxt("impl::trans_method_callee"); + let _icx = push_ctxt("impl::trans_method_callee"); let tcx = bcx.tcx(); debug!("trans_method_callee(callee_id=%?, this=%s, mentry=%s)", @@ -196,21 +158,6 @@ pub fn trans_method_callee(bcx: block, // Replace method_self with method_static here. let mut origin = mentry.origin; match origin { - typeck::method_self(trait_id, method_index) => { - // Get the ID of the impl we're inside. - let impl_def_id = bcx.fcx.impl_id.get(); - - debug!("impl_def_id is %?", impl_def_id); - - // Get the ID of the method we're calling. - let method_name = - ty::trait_method(tcx, trait_id, method_index).ident; - let method_id = - method_with_name_or_default(bcx.ccx(), - impl_def_id, - method_name); - origin = typeck::method_static(method_id); - } typeck::method_super(trait_id, method_index) => { // <self_ty> is the self type for this method call let self_ty = node_id_type(bcx, this.id); @@ -235,6 +182,7 @@ pub fn trans_method_callee(bcx: block, impl_id, method_name)); } + typeck::method_self(*) | typeck::method_static(*) | typeck::method_param(*) | typeck::method_trait(*) => {} } @@ -244,12 +192,14 @@ pub fn trans_method_callee(bcx: block, match origin { typeck::method_static(did) => { let callee_fn = callee::trans_fn_ref(bcx, did, callee_id); - let Result {bcx, val} = trans_self_arg(bcx, this, mentry); + let mut temp_cleanups = ~[]; + let Result {bcx, val} = trans_self_arg(bcx, this, &mut temp_cleanups, mentry); Callee { bcx: bcx, data: Method(MethodData { llfn: callee_fn.llfn, llself: val, + temp_cleanup: temp_cleanups.head_opt().map(|&v| *v), self_ty: node_id_type(bcx, this.id), self_mode: mentry.self_mode, }) @@ -271,6 +221,21 @@ pub fn trans_method_callee(bcx: block, None => fail!("trans_method_callee: missing param_substs") } } + + typeck::method_self(trait_id, method_index) => { + match bcx.fcx.param_substs { + Some(@param_substs + {self_vtable: Some(ref vtbl), _}) => { + trans_monomorphized_callee(bcx, callee_id, this, mentry, + trait_id, method_index, + copy *vtbl) + } + _ => { + fail!("trans_method_callee: missing self_vtable") + } + } + } + typeck::method_trait(_, off, store) => { trans_trait_callee(bcx, callee_id, @@ -279,9 +244,8 @@ pub fn trans_method_callee(bcx: block, store, mentry.explicit_self) } - typeck::method_self(*) | typeck::method_super(*) => { - fail!("method_self or method_super should have been handled \ - above") + typeck::method_super(*) => { + fail!("method_super should have been handled above") } } } @@ -291,7 +255,7 @@ pub fn trans_static_method_callee(bcx: block, trait_id: ast::def_id, callee_id: ast::node_id) -> FnData { - let _icx = bcx.insn_ctxt("impl::trans_static_method_callee"); + let _icx = push_ctxt("impl::trans_static_method_callee"); let ccx = bcx.ccx(); debug!("trans_static_method_callee(method_id=%?, trait_id=%s, \ @@ -313,15 +277,9 @@ pub fn trans_static_method_callee(bcx: block, // // So when we see a call to this function foo, we have to figure // out which impl the `Trait<T1...Tn>` bound on the type `self` was - // bound to. Due to the fact that we use a flattened list of - // impls, one per bound, this means we have to total up the bounds - // found on the type parametesr T1...Tn to find the index of the - // one we are interested in. - let bound_index = { - let trait_def = ty::lookup_trait_def(bcx.tcx(), trait_id); - ty::count_traits_and_supertraits( - bcx.tcx(), *trait_def.generics.type_param_defs) - }; + // bound to. + let bound_index = ty::lookup_trait_def(bcx.tcx(), trait_id). + generics.type_param_defs.len(); let mname = if method_id.crate == ast::local_crate { match bcx.tcx().items.get_copy(&method_id.node) { @@ -343,17 +301,17 @@ pub fn trans_static_method_callee(bcx: block, let vtbls = resolve_vtables_in_fn_ctxt( bcx.fcx, ccx.maps.vtable_map.get_copy(&callee_id)); - match vtbls[bound_index] { + match vtbls[bound_index][0] { typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => { - assert!(rcvr_substs.all(|t| !ty::type_needs_infer(*t))); + assert!(rcvr_substs.iter().all(|t| !ty::type_needs_infer(*t))); let mth_id = method_with_name_or_default(bcx.ccx(), impl_did, mname); - let callee_substs = combine_impl_and_methods_tps( - bcx, mth_id, impl_did, callee_id, *rcvr_substs); - let callee_origins = combine_impl_and_methods_origins( - bcx, mth_id, impl_did, callee_id, rcvr_origins); + let (callee_substs, callee_origins) = + combine_impl_and_methods_tps( + bcx, mth_id, impl_did, callee_id, + *rcvr_substs, rcvr_origins); let FnData {llfn: lval} = trans_fn_ref_with_vtables(bcx, @@ -363,7 +321,7 @@ pub fn trans_static_method_callee(bcx: block, Some(callee_origins)); let callee_ty = node_id_type(bcx, callee_id); - let llty = T_ptr(type_of_fn_from_ty(ccx, callee_ty)); + let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to(); FnData {llfn: PointerCast(bcx, lval, llty)} } _ => { @@ -375,79 +333,56 @@ pub fn trans_static_method_callee(bcx: block, pub fn method_from_methods(ms: &[@ast::method], name: ast::ident) -> Option<ast::def_id> { - ms.find(|m| m.ident == name).map(|m| ast_util::local_def(m.id)) + ms.iter().find_(|m| m.ident == name).map(|m| ast_util::local_def(m.id)) } -pub fn method_with_name_or_default(ccx: @mut CrateContext, +pub fn method_with_name_or_default(ccx: &mut CrateContext, impl_id: ast::def_id, name: ast::ident) -> ast::def_id { let imp = ccx.impl_method_cache.find_copy(&(impl_id, name)); match imp { - Some(m) => m, - None => { - let imp = if impl_id.crate == ast::local_crate { - match ccx.tcx.items.get_copy(&impl_id.node) { - ast_map::node_item(@ast::item { - node: ast::item_impl(_, _, _, ref ms), _ - }, _) => { - let did = method_from_methods(*ms, name); - if did.is_some() { - did.get() - } else { - // Look for a default method - let pmm = ccx.tcx.provided_methods; - match pmm.find(&impl_id) { - Some(pmis) => { - for pmis.each |pmi| { - if pmi.method_info.ident == name { - debug!("pmi.method_info.did = %?", pmi.method_info.did); - return pmi.method_info.did; - } - } - fail!() - } - None => fail!() - } - } - } - _ => fail!("method_with_name") - } - } else { - csearch::get_impl_method(ccx.sess.cstore, impl_id, name) - }; + Some(m) => return m, + None => {} + } - ccx.impl_method_cache.insert((impl_id, name), imp); + // None of this feels like it should be the best way to do this. + let mut did = if impl_id.crate == ast::local_crate { + match ccx.tcx.items.get_copy(&impl_id.node) { + ast_map::node_item(@ast::item { + node: ast::item_impl(_, _, _, ref ms), _ + }, _) => { method_from_methods(*ms, name) }, + _ => fail!("method_with_name") + } + } else { + csearch::get_impl_method(ccx.sess.cstore, impl_id, name) + }; - imp + if did.is_none() { + // Look for a default method + let pmm = ccx.tcx.provided_methods; + match pmm.find(&impl_id) { + Some(pmis) => { + for pmis.iter().advance |pmi| { + if pmi.method_info.ident == name { + debug!("pmi.method_info.did = %?", + pmi.method_info.did); + did = Some(pmi.method_info.did); + } + } + } + None => {} } } + + let imp = did.expect("could not find method while translating"); + ccx.impl_method_cache.insert((impl_id, name), imp); + imp } pub fn method_ty_param_count(ccx: &CrateContext, m_id: ast::def_id, i_id: ast::def_id) -> uint { debug!("method_ty_param_count: m_id: %?, i_id: %?", m_id, i_id); - if m_id.crate == ast::local_crate { - match ccx.tcx.items.find(&m_id.node) { - Some(&ast_map::node_method(m, _, _)) => m.generics.ty_params.len(), - None => { - match ccx.tcx.provided_method_sources.find(&m_id) { - Some(source) => { - method_ty_param_count( - ccx, source.method_id, source.impl_id) - } - None => fail!() - } - } - Some(&ast_map::node_trait_method(@ast::provided(@ref m), - _, _)) => { - m.generics.ty_params.len() - } - ref e => fail!("method_ty_param_count %?", *e) - } - } else { - csearch::get_type_param_count(ccx.sess.cstore, m_id) - - csearch::get_type_param_count(ccx.sess.cstore, i_id) - } + ty::method(ccx.tcx, m_id).generics.type_param_defs.len() } pub fn trans_monomorphized_callee(bcx: block, @@ -458,7 +393,7 @@ pub fn trans_monomorphized_callee(bcx: block, n_method: uint, vtbl: typeck::vtable_origin) -> Callee { - let _icx = bcx.insn_ctxt("impl::trans_monomorphized_callee"); + let _icx = push_ctxt("impl::trans_monomorphized_callee"); return match vtbl { typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => { let ccx = bcx.ccx(); @@ -467,15 +402,16 @@ pub fn trans_monomorphized_callee(bcx: block, bcx.ccx(), impl_did, mname); // obtain the `self` value: + let mut temp_cleanups = ~[]; let Result {bcx, val: llself_val} = - trans_self_arg(bcx, base, mentry); + trans_self_arg(bcx, base, &mut temp_cleanups, mentry); // create a concatenated set of substitutions which includes // those from the impl and those from the method: - let callee_substs = combine_impl_and_methods_tps( - bcx, mth_id, impl_did, callee_id, *rcvr_substs); - let callee_origins = combine_impl_and_methods_origins( - bcx, mth_id, impl_did, callee_id, rcvr_origins); + let (callee_substs, callee_origins) = + combine_impl_and_methods_tps( + bcx, mth_id, impl_did, callee_id, + *rcvr_substs, rcvr_origins); // translate the function let callee = trans_fn_ref_with_vtables(bcx, @@ -486,7 +422,7 @@ pub fn trans_monomorphized_callee(bcx: block, // create a llvalue that represents the fn ptr let fn_ty = node_id_type(bcx, callee_id); - let llfn_ty = T_ptr(type_of_fn_from_ty(ccx, fn_ty)); + let llfn_ty = type_of_fn_from_ty(ccx, fn_ty).ptr_to(); let llfn_val = PointerCast(bcx, callee.llfn, llfn_ty); // combine the self environment with the rest @@ -495,6 +431,7 @@ pub fn trans_monomorphized_callee(bcx: block, data: Method(MethodData { llfn: llfn_val, llself: llself_val, + temp_cleanup: temp_cleanups.head_opt().map(|&v| *v), self_ty: node_id_type(bcx, base.id), self_mode: mentry.self_mode, }) @@ -503,6 +440,9 @@ pub fn trans_monomorphized_callee(bcx: block, typeck::vtable_param(*) => { fail!("vtable_param left in monomorphized function's vtable substs"); } + typeck::vtable_self(*) => { + fail!("vtable_self left in monomorphized function's vtable substs"); + } }; } @@ -511,8 +451,9 @@ pub fn combine_impl_and_methods_tps(bcx: block, mth_did: ast::def_id, impl_did: ast::def_id, callee_id: ast::node_id, - rcvr_substs: &[ty::t]) - -> ~[ty::t] { + rcvr_substs: &[ty::t], + rcvr_origins: typeck::vtable_res) + -> (~[ty::t], typeck::vtable_res) { /*! * * Creates a concatenated set of substitutions which includes @@ -535,59 +476,24 @@ pub fn combine_impl_and_methods_tps(bcx: block, let node_substs = node_id_type_params(bcx, callee_id); debug!("rcvr_substs=%?", rcvr_substs.map(|t| bcx.ty_to_str(*t))); let ty_substs - = vec::append(rcvr_substs.to_vec(), - vec::tailn(node_substs, - node_substs.len() - n_m_tps)); + = vec::append(rcvr_substs.to_owned(), + node_substs.tailn(node_substs.len() - n_m_tps)); debug!("n_m_tps=%?", n_m_tps); debug!("node_substs=%?", node_substs.map(|t| bcx.ty_to_str(*t))); debug!("ty_substs=%?", ty_substs.map(|t| bcx.ty_to_str(*t))); - return ty_substs; -} - -pub fn combine_impl_and_methods_origins(bcx: block, - mth_did: ast::def_id, - impl_did: ast::def_id, - callee_id: ast::node_id, - rcvr_origins: typeck::vtable_res) - -> typeck::vtable_res { - /*! - * - * Similar to `combine_impl_and_methods_tps`, but for vtables. - * This is much messier because of the flattened layout we are - * currently using (for some reason that I fail to understand). - * The proper fix is described in #3446. - */ - - // Find the bounds for the method, which are the tail of the - // bounds found in the item type, as the item type combines the - // rcvr + method bounds. - let ccx = bcx.ccx(); - let tcx = bcx.tcx(); - let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did); - let ty::ty_param_bounds_and_ty { - generics: r_m_generics, - _ - } = ty::lookup_item_type(tcx, mth_did); - let n_r_m_tps = r_m_generics.type_param_defs.len(); // rcvr + method tps - let m_type_param_defs = - vec::slice(*r_m_generics.type_param_defs, n_r_m_tps - n_m_tps, n_r_m_tps); - - // Flatten out to find the number of vtables the method expects. - let m_vtables = ty::count_traits_and_supertraits(tcx, m_type_param_defs); - - // Find the vtables we computed at type check time and monomorphize them + // Now, do the same work for the vtables. The vtables might not + // exist, in which case we need to make them. let r_m_origins = match node_vtables(bcx, callee_id) { Some(vt) => vt, - None => @~[] + None => @vec::from_elem(node_substs.len(), @~[]) }; + let vtables + = @vec::append(rcvr_origins.to_owned(), + r_m_origins.tailn(r_m_origins.len() - n_m_tps)); - // Extract those that belong to method: - let m_origins = vec::tailn(*r_m_origins, r_m_origins.len() - m_vtables); - - // Combine rcvr + method to find the final result: - @vec::append(/*bad*/copy *rcvr_origins, m_origins) + return (ty_substs, vtables); } @@ -607,7 +513,7 @@ pub fn trans_trait_callee(bcx: block, // first evaluate the self expression (expected a by-ref result) and then // extract the self data and vtable out of the pair. - let _icx = bcx.insn_ctxt("impl::trans_trait_callee"); + let _icx = push_ctxt("impl::trans_trait_callee"); let mut bcx = bcx; let self_datum = unpack_datum!(bcx, expr::trans_to_datum(bcx, self_expr)); @@ -616,7 +522,7 @@ pub fn trans_trait_callee(bcx: block, let llpair = match explicit_self { ast::sty_region(*) => Load(bcx, llpair), ast::sty_static | ast::sty_value | - ast::sty_box(_) | ast::sty_uniq(_) => llpair + ast::sty_box(_) | ast::sty_uniq => llpair }; let callee_ty = node_id_type(bcx, callee_id); @@ -640,27 +546,27 @@ pub fn trans_trait_callee_from_llval(bcx: block, // Same as `trans_trait_callee()` above, except that it is given // a by-ref pointer to the @Trait pair. - let _icx = bcx.insn_ctxt("impl::trans_trait_callee"); + let _icx = push_ctxt("impl::trans_trait_callee"); let ccx = bcx.ccx(); let mut bcx = bcx; // Load the vtable from the @Trait pair debug!("(translating trait callee) loading vtable from pair %s", - val_str(bcx.ccx().tn, llpair)); + bcx.val_to_str(llpair)); let llvtable = Load(bcx, PointerCast(bcx, GEPi(bcx, llpair, [0u, abi::trt_field_vtable]), - T_ptr(T_ptr(T_vtable())))); + Type::vtable().ptr_to().ptr_to())); // Load the box from the @Trait pair and GEP over the box header if // necessary: let mut llself; debug!("(translating trait callee) loading second index from pair"); - let llbox = Load(bcx, GEPi(bcx, llpair, [0u, abi::trt_field_box])); + let llboxptr = GEPi(bcx, llpair, [0u, abi::trt_field_box]); + let llbox = Load(bcx, llboxptr); // Munge `llself` appropriately for the type of `self` in the method. - let self_mode; match explicit_self { ast::sty_static => { bcx.tcx().sess.bug("shouldn't see static method here"); @@ -670,8 +576,6 @@ pub fn trans_trait_callee_from_llval(bcx: block, called on objects"); } ast::sty_region(*) => { - // As before, we need to pass a pointer to a pointer to the - // payload. match store { ty::BoxTraitStore | ty::UniqTraitStore => { @@ -681,46 +585,35 @@ pub fn trans_trait_callee_from_llval(bcx: block, llself = llbox; } } - - let llscratch = alloca(bcx, val_ty(llself)); - Store(bcx, llself, llscratch); - llself = llscratch; - - self_mode = ty::ByRef; } ast::sty_box(_) => { // Bump the reference count on the box. debug!("(translating trait callee) callee type is `%s`", bcx.ty_to_str(callee_ty)); - bcx = glue::take_ty(bcx, llbox, callee_ty); + glue::incr_refcnt_of_boxed(bcx, llbox); // Pass a pointer to the box. match store { ty::BoxTraitStore => llself = llbox, _ => bcx.tcx().sess.bug("@self receiver with non-@Trait") } - - let llscratch = alloca(bcx, val_ty(llself)); - Store(bcx, llself, llscratch); - llself = llscratch; - - self_mode = ty::ByRef; } - ast::sty_uniq(_) => { + ast::sty_uniq => { // Pass the unique pointer. match store { ty::UniqTraitStore => llself = llbox, _ => bcx.tcx().sess.bug("~self receiver with non-~Trait") } - let llscratch = alloca(bcx, val_ty(llself)); - Store(bcx, llself, llscratch); - llself = llscratch; - - self_mode = ty::ByRef; + zero_mem(bcx, llboxptr, ty::mk_opaque_box(bcx.tcx())); } } + llself = PointerCast(bcx, llself, Type::opaque_box(ccx).ptr_to()); + let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()), false); + Store(bcx, llself, scratch.val); + scratch.add_clean(bcx); + // Load the function from the vtable and cast it to the expected type. debug!("(translating trait callee) loading method"); let llcallee_ty = type_of_fn_from_ty(ccx, callee_ty); @@ -728,15 +621,16 @@ pub fn trans_trait_callee_from_llval(bcx: block, // Plus one in order to skip past the type descriptor. let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + 1])); - let mptr = PointerCast(bcx, mptr, T_ptr(llcallee_ty)); + let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to()); return Callee { bcx: bcx, data: Method(MethodData { llfn: mptr, - llself: llself, - self_ty: ty::mk_opaque_box(bcx.tcx()), - self_mode: self_mode, + llself: scratch.to_value_llval(bcx), + temp_cleanup: Some(scratch.val), + self_ty: scratch.ty, + self_mode: ty::ByCopy, /* XXX: Some(llbox) */ }) }; @@ -786,22 +680,22 @@ pub fn get_vtable(bcx: block, } /// Helper function to declare and initialize the vtable. -pub fn make_vtable(ccx: @mut CrateContext, - tydesc: @mut tydesc_info, +pub fn make_vtable(ccx: &mut CrateContext, + tydesc: &tydesc_info, ptrs: &[ValueRef]) -> ValueRef { unsafe { - let _icx = ccx.insn_ctxt("impl::make_vtable"); + let _icx = push_ctxt("impl::make_vtable"); let mut components = ~[ tydesc.tydesc ]; - for ptrs.each |&ptr| { + for ptrs.iter().advance |&ptr| { components.push(ptr) } let tbl = C_struct(components); - let vtable = ccx.sess.str_of((ccx.names)("vtable")); - let vt_gvar = do str::as_c_str(vtable) |buf| { - llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf) + let vtable = ccx.sess.str_of(gensym_name("vtable")); + let vt_gvar = do vtable.as_c_str |buf| { + llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl).to_ref(), buf) }; llvm::LLVMSetInitializer(vt_gvar, tbl); llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True); @@ -814,11 +708,11 @@ pub fn make_vtable(ccx: @mut CrateContext, pub fn make_impl_vtable(bcx: block, impl_id: ast::def_id, self_ty: ty::t, - substs: ~[ty::t], + substs: &[ty::t], vtables: typeck::vtable_res) -> ValueRef { let ccx = bcx.ccx(); - let _icx = ccx.insn_ctxt("impl::make_impl_vtable"); + let _icx = push_ctxt("impl::make_impl_vtable"); let tcx = ccx.tcx; let trt_id = match ty::impl_trait_ref(tcx, impl_id) { @@ -837,7 +731,7 @@ pub fn make_impl_vtable(bcx: block, if im.generics.has_type_params() || ty::type_has_self(fty) { debug!("(making impl vtable) method has self or type params: %s", tcx.sess.str_of(im.ident)); - C_null(T_ptr(T_nil())) + C_null(Type::nil().ptr_to()) } else { debug!("(making impl vtable) adding method to vtable: %s", tcx.sess.str_of(im.ident)); @@ -862,7 +756,7 @@ pub fn trans_trait_cast(bcx: block, _store: ty::TraitStore) -> block { let mut bcx = bcx; - let _icx = bcx.insn_ctxt("impl::trans_cast"); + let _icx = push_ctxt("impl::trans_cast"); let lldest = match dest { Ignore => { @@ -880,16 +774,16 @@ pub fn trans_trait_cast(bcx: block, // have no type descriptor field.) llboxdest = PointerCast(bcx, llboxdest, - T_ptr(type_of(bcx.ccx(), v_ty))); + type_of(bcx.ccx(), v_ty).ptr_to()); bcx = expr::trans_into(bcx, val, SaveIn(llboxdest)); // Store the vtable into the pair or triple. - let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0]; + let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0][0]; let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig); let vtable = get_vtable(bcx, v_ty, orig); Store(bcx, vtable, PointerCast(bcx, GEPi(bcx, lldest, [0u, abi::trt_field_vtable]), - T_ptr(val_ty(vtable)))); + val_ty(vtable).ptr_to())); bcx } diff --git a/src/librustc/middle/trans/mod.rs b/src/librustc/middle/trans/mod.rs index 49cadfbcc81..64d6bbec87c 100644 --- a/src/librustc/middle/trans/mod.rs +++ b/src/librustc/middle/trans/mod.rs @@ -35,10 +35,9 @@ pub mod cabi_arm; pub mod cabi_mips; pub mod foreign; pub mod reflect; -pub mod shape; pub mod debuginfo; pub mod type_use; -pub mod reachable; pub mod machine; pub mod adt; pub mod asm; +pub mod type_; diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index df283194713..ad48c30747e 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use back::link::mangle_exported_name; use driver::session; use lib::llvm::ValueRef; -use middle::trans::base::{get_insn_ctxt}; use middle::trans::base::{set_inline_hint_if_appr, set_inline_hint}; -use middle::trans::base::{trans_enum_variant}; +use middle::trans::base::{trans_enum_variant,push_ctxt}; use middle::trans::base::{trans_fn, decl_internal_cdecl_fn}; use middle::trans::base::{get_item_val, no_self}; use middle::trans::base; @@ -32,7 +30,6 @@ use middle::ty::{FnSig}; use middle::typeck; use util::ppaux::{Repr,ty_to_str}; -use core::vec; use syntax::ast; use syntax::ast_map; use syntax::ast_map::path_name; @@ -44,6 +41,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, fn_id: ast::def_id, real_substs: &ty::substs, vtables: Option<typeck::vtable_res>, + self_vtable: Option<typeck::vtable_origin>, impl_did_opt: Option<ast::def_id>, ref_id: Option<ast::node_id>) -> (ValueRef, bool) @@ -60,18 +58,18 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, impl_did_opt.repr(ccx.tcx), ref_id); - assert!(real_substs.tps.all(|t| !ty::type_needs_infer(*t))); - let _icx = ccx.insn_ctxt("monomorphic_fn"); + assert!(real_substs.tps.iter().all(|t| !ty::type_needs_infer(*t))); + let _icx = push_ctxt("monomorphic_fn"); let mut must_cast = false; - let substs = vec::map(real_substs.tps, |t| { + let substs = real_substs.tps.iter().transform(|t| { match normalize_for_monomorphization(ccx.tcx, *t) { Some(t) => { must_cast = true; t } None => *t } - }); + }).collect::<~[ty::t]>(); - for real_substs.tps.each() |s| { assert!(!ty::type_has_params(*s)); } - for substs.each() |s| { assert!(!ty::type_has_params(*s)); } + for real_substs.tps.iter().advance |s| { assert!(!ty::type_has_params(*s)); } + for substs.iter().advance |s| { assert!(!ty::type_has_params(*s)); } let param_uses = type_use::type_uses_for(ccx, fn_id, substs.len()); let hash_id = make_mono_id(ccx, fn_id, substs, vtables, impl_did_opt, Some(param_uses)); @@ -162,9 +160,11 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, } ccx.monomorphizing.insert(fn_id, depth + 1); - let pt = vec::append(/*bad*/copy *pt, - [path_name((ccx.names)(ccx.sess.str_of(name)))]); + let elt = path_name(gensym_name(ccx.sess.str_of(name))); + let mut pt = /* bad */copy (*pt); + pt.push(elt); let s = mangle_exported_name(ccx, /*bad*/copy pt, mono_ty); + debug!("monomorphize_fn mangled to %s", s); let mk_lldecl = || { let lldecl = decl_internal_cdecl_fn(ccx.llmod, /*bad*/copy s, llfty); @@ -175,8 +175,8 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, let psubsts = Some(@param_substs { tys: substs, vtables: vtables, - type_param_defs: tpt.generics.type_param_defs, - self_ty: real_substs.self_ty + self_ty: real_substs.self_ty, + self_vtable: self_vtable }); let lldecl = match map_node { @@ -194,7 +194,6 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, no_self, psubsts, fn_id.node, - None, []); d } @@ -209,7 +208,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, } ast_map::node_variant(ref v, enum_item, _) => { let tvs = ty::enum_variants(ccx.tcx, local_def(enum_item.id)); - let this_tv = vec::find(*tvs, |tv| { tv.id.node == fn_id.node}).get(); + let this_tv = *tvs.iter().find_(|tv| { tv.id.node == fn_id.node}).get(); let d = mk_lldecl(); set_inline_hint(d); match v.node.kind { @@ -222,27 +221,17 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, } d } - ast_map::node_method(mth, supplied_impl_did, _) => { + ast_map::node_method(mth, _, _) => { // XXX: What should the self type be here? let d = mk_lldecl(); set_inline_hint_if_appr(/*bad*/copy mth.attrs, d); - - // Override the impl def ID if necessary. - let impl_did; - match impl_did_opt { - None => impl_did = supplied_impl_did, - Some(override_impl_did) => impl_did = override_impl_did - } - - meth::trans_method(ccx, pt, mth, psubsts, None, d, impl_did); + meth::trans_method(ccx, pt, mth, psubsts, d); d } ast_map::node_trait_method(@ast::provided(mth), _, pt) => { let d = mk_lldecl(); set_inline_hint_if_appr(/*bad*/copy mth.attrs, d); - debug!("monomorphic_fn impl_did_opt is %?", impl_did_opt); - meth::trans_method(ccx, /*bad*/copy *pt, mth, psubsts, None, d, - impl_did_opt.get()); + meth::trans_method(ccx, /*bad*/copy *pt, mth, psubsts, d); d } ast_map::node_struct_ctor(struct_def, _, _) => { @@ -294,7 +283,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt, ty::ty_closure(ref fty) => { Some(normalized_closure_ty(tcx, fty.sigil)) } - ty::ty_trait(_, _, ref store, _) => { + ty::ty_trait(_, _, ref store, _, _) => { let sigil = match *store { ty::UniqTraitStore => ast::OwnedSigil, ty::BoxTraitStore => ast::ManagedSigil, @@ -335,26 +324,22 @@ pub fn make_mono_id(ccx: @mut CrateContext, vtables: Option<typeck::vtable_res>, impl_did_opt: Option<ast::def_id>, param_uses: Option<@~[type_use::type_uses]>) -> mono_id { - let precise_param_ids = match vtables { + // FIXME (possibly #5801): Need a lot of type hints to get + // .collect() to work. + let precise_param_ids: ~[(ty::t, Option<@~[mono_id]>)] = match vtables { Some(vts) => { - let item_ty = ty::lookup_item_type(ccx.tcx, item); - let mut i = 0; - vec::map_zip(*item_ty.generics.type_param_defs, substs, |type_param_def, subst| { - let mut v = ~[]; - for type_param_def.bounds.trait_bounds.each |_bound| { - v.push(meth::vtable_id(ccx, &vts[i])); - i += 1; - } + debug!("make_mono_id vtables=%s substs=%s", + vts.repr(ccx.tcx), substs.repr(ccx.tcx)); + vts.iter().zip(substs.iter()).transform(|(vtable, subst)| { + let v = vtable.map(|vt| meth::vtable_id(ccx, vt)); (*subst, if !v.is_empty() { Some(@v) } else { None }) - }) - } - None => { - vec::map(substs, |subst| (*subst, None)) + }).collect() } + None => substs.iter().transform(|subst| (*subst, None::<@~[mono_id]>)).collect() }; let param_ids = match param_uses { Some(ref uses) => { - vec::map_zip(precise_param_ids, **uses, |id, uses| { + precise_param_ids.iter().zip(uses.iter()).transform(|(id, uses)| { if ccx.sess.no_monomorphic_collapse() { match copy *id { (a, b) => mono_precise(a, b) @@ -391,13 +376,13 @@ pub fn make_mono_id(ccx: @mut CrateContext, } } } - }) + }).collect() } None => { - precise_param_ids.map(|x| { + precise_param_ids.iter().transform(|x| { let (a, b) = copy *x; mono_precise(a, b) - }) + }).collect() } }; @mono_id_ {def: item, params: param_ids, impl_did_opt: impl_did_opt} diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs deleted file mode 100644 index 4641a13604b..00000000000 --- a/src/librustc/middle/trans/reachable.rs +++ /dev/null @@ -1,246 +0,0 @@ -// 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. - -// Finds items that are externally reachable, to determine which items -// need to have their metadata (and possibly their AST) serialized. -// All items that can be referred to through an exported name are -// reachable, and when a reachable thing is inline or generic, it -// makes all other generics or inline functions that it references -// reachable as well. - -use core::prelude::*; - -use middle::resolve; -use middle::ty; -use middle::typeck; - -use core::hashmap::HashSet; -use syntax::ast; -use syntax::ast::*; -use syntax::ast_util::def_id_of_def; -use syntax::attr; -use syntax::codemap; -use syntax::print::pprust::expr_to_str; -use syntax::{visit, ast_map}; - -pub type map = @HashSet<node_id>; - -struct ctx<'self> { - exp_map2: resolve::ExportMap2, - tcx: ty::ctxt, - method_map: typeck::method_map, - rmap: &'self mut HashSet<node_id>, -} - -pub fn find_reachable(crate_mod: &_mod, exp_map2: resolve::ExportMap2, - tcx: ty::ctxt, method_map: typeck::method_map) -> map { - let mut rmap = HashSet::new(); - { - let cx = @mut ctx { - exp_map2: exp_map2, - tcx: tcx, - method_map: method_map, - rmap: &mut rmap - }; - traverse_public_mod(cx, ast::crate_node_id, crate_mod); - traverse_all_resources_and_impls(cx, crate_mod); - } - return @rmap; -} - -fn traverse_exports(cx: @mut ctx, mod_id: node_id) -> bool { - let mut found_export = false; - match cx.exp_map2.find(&mod_id) { - Some(ref exp2s) => { - for (*exp2s).each |e2| { - found_export = true; - traverse_def_id(cx, e2.def_id) - }; - } - None => () - } - return found_export; -} - -fn traverse_def_id(cx: @mut ctx, did: def_id) { - if did.crate != local_crate { return; } - match cx.tcx.items.find(&did.node) { - None => (), // This can happen for self, for example - Some(&ast_map::node_item(item, _)) => traverse_public_item(cx, item), - Some(&ast_map::node_method(_, impl_id, _)) => traverse_def_id(cx, impl_id), - Some(&ast_map::node_foreign_item(item, _, _, _)) => { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - cx.rmap.insert(item.id); - } - Some(&ast_map::node_variant(ref v, _, _)) => { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - cx.rmap.insert(v.node.id); - } - _ => () - } -} - -fn traverse_public_mod(cx: @mut ctx, mod_id: node_id, m: &_mod) { - if !traverse_exports(cx, mod_id) { - // No exports, so every local item is exported - for m.items.each |item| { - traverse_public_item(cx, *item); - } - } -} - -fn traverse_public_item(cx: @mut ctx, item: @item) { - { - // FIXME #6021: naming rmap shouldn't be necessary - let cx = &mut *cx; - let rmap: &mut HashSet<node_id> = cx.rmap; - if rmap.contains(&item.id) { return; } - rmap.insert(item.id); - } - - match item.node { - item_mod(ref m) => traverse_public_mod(cx, item.id, m), - item_foreign_mod(ref nm) => { - if !traverse_exports(cx, item.id) { - for nm.items.each |item| { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - cx.rmap.insert(item.id); - } - } - } - item_fn(_, _, _, ref generics, ref blk) => { - if generics.ty_params.len() > 0u || - attr::find_inline_attr(item.attrs) != attr::ia_none { - traverse_inline_body(cx, blk); - } - } - item_impl(ref generics, _, _, ref ms) => { - for ms.each |m| { - if generics.ty_params.len() > 0u || - m.generics.ty_params.len() > 0u || - attr::find_inline_attr(m.attrs) != attr::ia_none - { - { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - cx.rmap.insert(m.id); - } - traverse_inline_body(cx, &m.body); - } - } - } - item_struct(ref struct_def, _) => { - for struct_def.ctor_id.iter().advance |&ctor_id| { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - cx.rmap.insert(ctor_id); - } - } - item_ty(t, _) => { - traverse_ty(t, (cx, - visit::mk_vt(@visit::Visitor {visit_ty: traverse_ty, - ..*visit::default_visitor()}))) - } - item_const(*) | - item_enum(*) | item_trait(*) => (), - item_mac(*) => fail!("item macros unimplemented") - } -} - -fn traverse_ty<'a>(ty: @Ty, (cx, v): (@mut ctx<'a>, visit::vt<@mut ctx<'a>>)) { - { - let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut - if cx.rmap.contains(&ty.id) { return; } - cx.rmap.insert(ty.id); - } - - match ty.node { - ty_path(p, p_id) => { - match cx.tcx.def_map.find(&p_id) { - // Kind of a hack to check this here, but I'm not sure what else - // to do - Some(&def_prim_ty(_)) => { /* do nothing */ } - Some(&d) => traverse_def_id(cx, def_id_of_def(d)), - None => { /* do nothing -- but should we fail here? */ } - } - for p.types.each |t| { - (v.visit_ty)(*t, (cx, v)); - } - } - _ => visit::visit_ty(ty, (cx, v)) - } -} - -fn traverse_inline_body(cx: @mut ctx, body: &blk) { - fn traverse_expr<'a>(e: @expr, (cx, v): (@mut ctx<'a>, - visit::vt<@mut ctx<'a>>)) { - match e.node { - expr_path(_) => { - match cx.tcx.def_map.find(&e.id) { - Some(&d) => { - traverse_def_id(cx, def_id_of_def(d)); - } - None => cx.tcx.sess.span_bug( - e.span, - fmt!("Unbound node id %? while traversing %s", - e.id, - expr_to_str(e, cx.tcx.sess.intr()))) - } - } - expr_method_call(*) => { - match cx.method_map.find(&e.id) { - Some(&typeck::method_map_entry { - origin: typeck::method_static(did), - _ - }) => { - traverse_def_id(cx, did); - } - Some(_) => {} - None => { - cx.tcx.sess.span_bug(e.span, "expr_method_call not in \ - method map"); - } - } - } - _ => () - } - visit::visit_expr(e, (cx, v)); - } - // Don't ignore nested items: for example if a generic fn contains a - // generic impl (as in deque::create), we need to monomorphize the - // impl as well - fn traverse_item(i: @item, (cx, _v): (@mut ctx, visit::vt<@mut ctx>)) { - traverse_public_item(cx, i); - } - visit::visit_block(body, (cx, visit::mk_vt(@visit::Visitor { - visit_expr: traverse_expr, - visit_item: traverse_item, - ..*visit::default_visitor() - }))); -} - -fn traverse_all_resources_and_impls(cx: @mut ctx, crate_mod: &_mod) { - visit::visit_mod( - crate_mod, - codemap::dummy_sp(), - 0, - (cx, - visit::mk_vt(@visit::Visitor { - visit_expr: |_e, (_cx, _v)| { }, - visit_item: |i, (cx, v)| { - visit::visit_item(i, (cx, v)); - match i.node { - item_impl(*) => { - traverse_public_item(cx, i); - } - _ => () - } - }, - ..*visit::default_visitor() - }))); -} diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index e4924e3a8db..9e227da49f8 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -9,7 +9,7 @@ // except according to those terms. use back::link::mangle_internal_name_by_path_and_seq; -use lib::llvm::{TypeRef, ValueRef, llvm}; +use lib::llvm::{ValueRef, llvm}; use middle::trans::adt; use middle::trans::base::*; use middle::trans::build::*; @@ -25,19 +25,21 @@ use middle::trans::type_of::*; use middle::ty; use util::ppaux::ty_to_str; -use core::libc::c_uint; -use core::option::None; -use core::vec; +use std::libc::c_uint; +use std::option::None; +use std::vec; use syntax::ast::def_id; use syntax::ast; use syntax::ast_map::path_name; use syntax::parse::token::special_idents; +use middle::trans::type_::Type; + pub struct Reflector { visitor_val: ValueRef, visitor_methods: @~[@ty::Method], final_bcx: block, - tydesc_ty: TypeRef, + tydesc_ty: Type, bcx: block } @@ -58,7 +60,7 @@ impl Reflector { let str_ty = ty::mk_estr(bcx.tcx(), str_vstore); let scratch = scratch_datum(bcx, str_ty, false); let len = C_uint(bcx.ccx(), s.len() + 1); - let c_str = PointerCast(bcx, C_cstr(bcx.ccx(), s), T_ptr(T_i8())); + let c_str = PointerCast(bcx, C_cstr(bcx.ccx(), s), Type::i8p()); Store(bcx, c_str, GEPi(bcx, scratch.val, [ 0, 0 ])); Store(bcx, len, GEPi(bcx, scratch.val, [ 0, 1 ])); scratch.val @@ -76,7 +78,7 @@ impl Reflector { let bcx = self.bcx; let static_ti = get_tydesc(bcx.ccx(), t); glue::lazily_emit_all_tydesc_glue(bcx.ccx(), static_ti); - PointerCast(bcx, static_ti.tydesc, T_ptr(self.tydesc_ty)) + PointerCast(bcx, static_ti.tydesc, self.tydesc_ty.ptr_to()) } pub fn c_mt(&mut self, mt: &ty::mt) -> ~[ValueRef] { @@ -84,7 +86,7 @@ impl Reflector { self.c_tydesc(mt.ty)] } - pub fn visit(&mut self, ty_name: ~str, args: &[ValueRef]) { + pub fn visit(&mut self, ty_name: &str, args: &[ValueRef]) { let tcx = self.bcx.tcx(); let mth_idx = ty::method_idx( tcx.sess.ident_of(~"visit_" + ty_name), @@ -95,8 +97,8 @@ impl Reflector { let v = self.visitor_val; debug!("passing %u args:", args.len()); let bcx = self.bcx; - for args.eachi |i, a| { - debug!("arg %u: %s", i, val_str(bcx.ccx().tn, *a)); + for args.iter().enumerate().advance |(i, a)| { + debug!("arg %u: %s", i, bcx.val_to_str(*a)); } let bool_ty = ty::mk_bool(); let scratch = scratch_datum(bcx, bool_ty, false); @@ -120,7 +122,7 @@ impl Reflector { } pub fn bracketed(&mut self, - bracket_name: ~str, + bracket_name: &str, extra: &[ValueRef], inner: &fn(&mut Reflector)) { self.visit(~"enter_" + bracket_name, extra); @@ -144,7 +146,7 @@ impl Reflector { } } - pub fn leaf(&mut self, name: ~str) { + pub fn leaf(&mut self, name: &str) { self.visit(name, []); } @@ -154,27 +156,27 @@ impl Reflector { debug!("reflect::visit_ty %s", ty_to_str(bcx.ccx().tcx, t)); match ty::get(t).sty { - ty::ty_bot => self.leaf(~"bot"), - ty::ty_nil => self.leaf(~"nil"), - ty::ty_bool => self.leaf(~"bool"), - ty::ty_int(ast::ty_i) => self.leaf(~"int"), - ty::ty_int(ast::ty_char) => self.leaf(~"char"), - ty::ty_int(ast::ty_i8) => self.leaf(~"i8"), - ty::ty_int(ast::ty_i16) => self.leaf(~"i16"), - ty::ty_int(ast::ty_i32) => self.leaf(~"i32"), - ty::ty_int(ast::ty_i64) => self.leaf(~"i64"), - ty::ty_uint(ast::ty_u) => self.leaf(~"uint"), - ty::ty_uint(ast::ty_u8) => self.leaf(~"u8"), - ty::ty_uint(ast::ty_u16) => self.leaf(~"u16"), - ty::ty_uint(ast::ty_u32) => self.leaf(~"u32"), - ty::ty_uint(ast::ty_u64) => self.leaf(~"u64"), - ty::ty_float(ast::ty_f) => self.leaf(~"float"), - ty::ty_float(ast::ty_f32) => self.leaf(~"f32"), - ty::ty_float(ast::ty_f64) => self.leaf(~"f64"), + ty::ty_bot => self.leaf("bot"), + ty::ty_nil => self.leaf("nil"), + ty::ty_bool => self.leaf("bool"), + ty::ty_int(ast::ty_i) => self.leaf("int"), + ty::ty_int(ast::ty_char) => self.leaf("char"), + ty::ty_int(ast::ty_i8) => self.leaf("i8"), + ty::ty_int(ast::ty_i16) => self.leaf("i16"), + ty::ty_int(ast::ty_i32) => self.leaf("i32"), + ty::ty_int(ast::ty_i64) => self.leaf("i64"), + ty::ty_uint(ast::ty_u) => self.leaf("uint"), + ty::ty_uint(ast::ty_u8) => self.leaf("u8"), + ty::ty_uint(ast::ty_u16) => self.leaf("u16"), + ty::ty_uint(ast::ty_u32) => self.leaf("u32"), + ty::ty_uint(ast::ty_u64) => self.leaf("u64"), + ty::ty_float(ast::ty_f) => self.leaf("float"), + ty::ty_float(ast::ty_f32) => self.leaf("f32"), + ty::ty_float(ast::ty_f64) => self.leaf("f64"), ty::ty_unboxed_vec(ref mt) => { let values = self.c_mt(mt); - self.visit(~"vec", values) + self.visit("vec", values) } ty::ty_estr(vst) => { @@ -188,28 +190,28 @@ impl Reflector { } ty::ty_box(ref mt) => { let extra = self.c_mt(mt); - self.visit(~"box", extra) + self.visit("box", extra) } ty::ty_uniq(ref mt) => { let extra = self.c_mt(mt); - self.visit(~"uniq", extra) + self.visit("uniq", extra) } ty::ty_ptr(ref mt) => { let extra = self.c_mt(mt); - self.visit(~"ptr", extra) + self.visit("ptr", extra) } ty::ty_rptr(_, ref mt) => { let extra = self.c_mt(mt); - self.visit(~"rptr", extra) + self.visit("rptr", extra) } ty::ty_tup(ref tys) => { let extra = ~[self.c_uint(tys.len())] + self.c_size_and_align(t); - do self.bracketed(~"tup", extra) |this| { - for tys.eachi |i, t| { + do self.bracketed("tup", extra) |this| { + for tys.iter().enumerate().advance |(i, t)| { let extra = ~[this.c_uint(i), this.c_tydesc(*t)]; - this.visit(~"tup_field", extra); + this.visit("tup_field", extra); } } } @@ -224,9 +226,9 @@ impl Reflector { self.c_uint(sigilval), self.c_uint(fty.sig.inputs.len()), self.c_uint(retval)]; - self.visit(~"enter_fn", extra); + self.visit("enter_fn", extra); self.visit_sig(retval, &fty.sig); - self.visit(~"leave_fn", extra); + self.visit("leave_fn", extra); } // FIXME (#2594): fetch constants out of intrinsic:: for the @@ -239,9 +241,9 @@ impl Reflector { self.c_uint(sigilval), self.c_uint(fty.sig.inputs.len()), self.c_uint(retval)]; - self.visit(~"enter_fn", extra); + self.visit("enter_fn", extra); self.visit_sig(retval, &fty.sig); - self.visit(~"leave_fn", extra); + self.visit("leave_fn", extra); } ty::ty_struct(did, ref substs) => { @@ -251,13 +253,13 @@ impl Reflector { let extra = ~[self.c_uint(fields.len())] + self.c_size_and_align(t); - do self.bracketed(~"class", extra) |this| { - for fields.eachi |i, field| { + do self.bracketed("class", extra) |this| { + for fields.iter().enumerate().advance |(i, field)| { let extra = ~[this.c_uint(i), this.c_slice( bcx.ccx().sess.str_of(field.ident))] + this.c_mt(&field.mt); - this.visit(~"class_field", extra); + this.visit("class_field", extra); } } } @@ -271,10 +273,8 @@ impl Reflector { let ccx = bcx.ccx(); let repr = adt::represent_type(bcx.ccx(), t); let variants = ty::substd_enum_variants(ccx.tcx, did, substs); - let llptrty = T_ptr(type_of(ccx, t)); - let (_, opaquety) = - ccx.tcx.intrinsic_defs.find_copy(&ccx.sess.ident_of("Opaque")) - .expect("Failed to resolve intrinsic::Opaque"); + let llptrty = type_of(ccx, t).ptr_to(); + let opaquety = ty::get_opaque_ty(ccx.tcx); let opaqueptrty = ty::mk_ptr(ccx.tcx, ty::mt { ty: opaquety, mutbl: ast::m_imm }); let make_get_disr = || { @@ -309,15 +309,15 @@ impl Reflector { let enum_args = ~[self.c_uint(variants.len()), make_get_disr()] + self.c_size_and_align(t); - do self.bracketed(~"enum", enum_args) |this| { - for variants.eachi |i, v| { + do self.bracketed("enum", enum_args) |this| { + for variants.iter().enumerate().advance |(i, v)| { let name = ccx.sess.str_of(v.name); let variant_args = ~[this.c_uint(i), this.c_int(v.disr_val), this.c_uint(v.args.len()), this.c_slice(name)]; - do this.bracketed(~"enum_variant", variant_args) |this| { - for v.args.eachi |j, a| { + do this.bracketed("enum_variant", variant_args) |this| { + for v.args.iter().enumerate().advance |(j, a)| { let bcx = this.bcx; let null = C_null(llptrty); let ptr = adt::trans_field_ptr(bcx, repr, null, v.disr_val, j); @@ -325,7 +325,7 @@ impl Reflector { let field_args = ~[this.c_uint(j), offset, this.c_tydesc(*a)]; - this.visit(~"enum_variant_field", field_args); + this.visit("enum_variant_field", field_args); } } } @@ -333,35 +333,35 @@ impl Reflector { } // Miscallaneous extra types - ty::ty_trait(_, _, _, _) => self.leaf(~"trait"), - ty::ty_infer(_) => self.leaf(~"infer"), - ty::ty_err => self.leaf(~"err"), + ty::ty_trait(_, _, _, _, _) => self.leaf("trait"), + ty::ty_infer(_) => self.leaf("infer"), + ty::ty_err => self.leaf("err"), ty::ty_param(ref p) => { let extra = ~[self.c_uint(p.idx)]; - self.visit(~"param", extra) + self.visit("param", extra) } - ty::ty_self(*) => self.leaf(~"self"), - ty::ty_type => self.leaf(~"type"), - ty::ty_opaque_box => self.leaf(~"opaque_box"), + ty::ty_self(*) => self.leaf("self"), + ty::ty_type => self.leaf("type"), + ty::ty_opaque_box => self.leaf("opaque_box"), ty::ty_opaque_closure_ptr(ck) => { let ckval = ast_sigil_constant(ck); let extra = ~[self.c_uint(ckval)]; - self.visit(~"closure_ptr", extra) + self.visit("closure_ptr", extra) } } } pub fn visit_sig(&mut self, retval: uint, sig: &ty::FnSig) { - for sig.inputs.eachi |i, arg| { + for sig.inputs.iter().enumerate().advance |(i, arg)| { let modeval = 5u; // "by copy" let extra = ~[self.c_uint(i), self.c_uint(modeval), self.c_tydesc(*arg)]; - self.visit(~"fn_input", extra); + self.visit("fn_input", extra); } let extra = ~[self.c_uint(retval), self.c_tydesc(sig.output)]; - self.visit(~"fn_output", extra); + self.visit("fn_output", extra); } } @@ -371,10 +371,8 @@ pub fn emit_calls_to_trait_visit_ty(bcx: block, visitor_val: ValueRef, visitor_trait_id: def_id) -> block { - use syntax::parse::token::special_idents::tydesc; let final = sub_block(bcx, "final"); - assert!(bcx.ccx().tcx.intrinsic_defs.contains_key(&tydesc)); - let (_, tydesc_ty) = bcx.ccx().tcx.intrinsic_defs.get_copy(&tydesc); + let tydesc_ty = ty::get_tydesc_ty(bcx.ccx().tcx); let tydesc_ty = type_of(bcx.ccx(), tydesc_ty); let mut r = Reflector { visitor_val: visitor_val, @@ -398,7 +396,6 @@ pub fn ast_sigil_constant(sigil: ast::Sigil) -> uint { pub fn ast_purity_constant(purity: ast::purity) -> uint { match purity { - ast::pure_fn => 0u, ast::unsafe_fn => 1u, ast::impure_fn => 2u, ast::extern_fn => 3u diff --git a/src/librustc/middle/trans/shape.rs b/src/librustc/middle/trans/shape.rs deleted file mode 100644 index 89ffb4b5bba..00000000000 --- a/src/librustc/middle/trans/shape.rs +++ /dev/null @@ -1,75 +0,0 @@ -// 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. - -// A "shape" is a compact encoding of a type that is used by interpreted glue. -// This substitutes for the runtime tags used by e.g. MLs. - - -use lib::llvm::llvm; -use lib::llvm::{True, ModuleRef, ValueRef}; -use middle::trans::common::*; -use middle::trans; - -use core::str; - -pub struct Ctxt { - next_tag_id: u16, - pad: u16, - pad2: u32 -} - -pub fn mk_global(ccx: &CrateContext, - name: &str, - llval: ValueRef, - internal: bool) - -> ValueRef { - unsafe { - let llglobal = do str::as_c_str(name) |buf| { - llvm::LLVMAddGlobal(ccx.llmod, val_ty(llval), buf) - }; - llvm::LLVMSetInitializer(llglobal, llval); - llvm::LLVMSetGlobalConstant(llglobal, True); - - if internal { - ::lib::llvm::SetLinkage(llglobal, - ::lib::llvm::InternalLinkage); - } - - return llglobal; - } -} - -pub fn mk_ctxt(llmod: ModuleRef) -> Ctxt { - unsafe { - let llshapetablesty = trans::common::T_named_struct("shapes"); - let _llshapetables = str::as_c_str("shapes", |buf| { - llvm::LLVMAddGlobal(llmod, llshapetablesty, buf) - }); - - return Ctxt { - next_tag_id: 0u16, - pad: 0u16, - pad2: 0u32 - }; - } -} - -/* -Although these two functions are never called, they are here -for a VERY GOOD REASON. See #3670 -*/ -pub fn add_u16(dest: &mut ~[u8], val: u16) { - *dest += [(val & 0xffu16) as u8, (val >> 8u16) as u8]; -} - -pub fn add_substr(dest: &mut ~[u8], src: ~[u8]) { - add_u16(&mut *dest, src.len() as u16); - *dest += src; -} diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 11a4e82050d..233508c5f66 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -11,7 +11,7 @@ use back::abi; use lib; -use lib::llvm::{llvm, ValueRef, TypeRef}; +use lib::llvm::{llvm, ValueRef}; use middle::trans::base; use middle::trans::base::*; use middle::trans::build::*; @@ -27,7 +27,9 @@ use middle::ty; use util::common::indenter; use util::ppaux::ty_to_str; -use core::option::None; +use middle::trans::type_::Type; + +use std::option::None; use syntax::ast; use syntax::codemap; @@ -51,7 +53,7 @@ pub fn expand_boxed_vec_ty(tcx: ty::ctxt, t: ty::t) -> ty::t { } pub fn get_fill(bcx: block, vptr: ValueRef) -> ValueRef { - let _icx = bcx.insn_ctxt("tvec::get_fill"); + let _icx = push_ctxt("tvec::get_fill"); Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill])) } pub fn set_fill(bcx: block, vptr: ValueRef, fill: ValueRef) { @@ -62,24 +64,24 @@ pub fn get_alloc(bcx: block, vptr: ValueRef) -> ValueRef { } pub fn get_bodyptr(bcx: block, vptr: ValueRef) -> ValueRef { - base::non_gc_box_cast(bcx, GEPi(bcx, vptr, [0u, abi::box_field_body])) + GEPi(bcx, vptr, [0u, abi::box_field_body]) } pub fn get_dataptr(bcx: block, vptr: ValueRef) -> ValueRef { - let _icx = bcx.insn_ctxt("tvec::get_dataptr"); + let _icx = push_ctxt("tvec::get_dataptr"); GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u]) } pub fn pointer_add(bcx: block, ptr: ValueRef, bytes: ValueRef) -> ValueRef { - let _icx = bcx.insn_ctxt("tvec::pointer_add"); + let _icx = push_ctxt("tvec::pointer_add"); let old_ty = val_ty(ptr); - let bptr = PointerCast(bcx, ptr, T_ptr(T_i8())); + let bptr = PointerCast(bcx, ptr, Type::i8p()); return PointerCast(bcx, InBoundsGEP(bcx, bptr, [bytes]), old_ty); } pub fn alloc_raw(bcx: block, unit_ty: ty::t, fill: ValueRef, alloc: ValueRef, heap: heap) -> Result { - let _icx = bcx.insn_ctxt("tvec::alloc_uniq"); + let _icx = push_ctxt("tvec::alloc_uniq"); let ccx = bcx.ccx(); let vecbodyty = ty::mk_mut_unboxed_vec(bcx.tcx(), unit_ty); @@ -103,7 +105,7 @@ pub fn alloc_vec(bcx: block, elts: uint, heap: heap) -> Result { - let _icx = bcx.insn_ctxt("tvec::alloc_uniq"); + let _icx = push_ctxt("tvec::alloc_uniq"); let ccx = bcx.ccx(); let llunitty = type_of::type_of(ccx, unit_ty); let unit_sz = nonzero_llsize_of(ccx, llunitty); @@ -117,7 +119,7 @@ pub fn alloc_vec(bcx: block, } pub fn duplicate_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> Result { - let _icx = bcx.insn_ctxt("tvec::duplicate_uniq"); + let _icx = push_ctxt("tvec::duplicate_uniq"); let fill = get_fill(bcx, get_bodyptr(bcx, vptr)); let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); @@ -135,7 +137,7 @@ pub fn duplicate_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> Result { pub fn make_drop_glue_unboxed(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> block { - let _icx = bcx.insn_ctxt("tvec::make_drop_glue_unboxed"); + let _icx = push_ctxt("tvec::make_drop_glue_unboxed"); let tcx = bcx.tcx(); let unit_ty = ty::sequence_element_type(tcx, vec_ty); if ty::type_needs_drop(tcx, unit_ty) { @@ -146,7 +148,7 @@ pub fn make_drop_glue_unboxed(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> pub struct VecTypes { vec_ty: ty::t, unit_ty: ty::t, - llunit_ty: TypeRef, + llunit_ty: Type, llunit_size: ValueRef } @@ -155,14 +157,14 @@ impl VecTypes { fmt!("VecTypes {vec_ty=%s, unit_ty=%s, llunit_ty=%s, llunit_size=%s}", ty_to_str(ccx.tcx, self.vec_ty), ty_to_str(ccx.tcx, self.unit_ty), - ty_str(ccx.tn, self.llunit_ty), - val_str(ccx.tn, self.llunit_size)) + ccx.tn.type_to_str(self.llunit_ty), + ccx.tn.val_to_str(self.llunit_size)) } } pub fn trans_fixed_vstore(bcx: block, vstore_expr: @ast::expr, - content_expr: @ast::expr, + content_expr: &ast::expr, dest: expr::Dest) -> block { //! @@ -227,7 +229,7 @@ pub fn trans_slice_vstore(bcx: block, let fixed_ty = ty::mk_evec(bcx.tcx(), ty::mt {ty: vt.unit_ty, mutbl: ast::m_mutbl}, ty::vstore_fixed(count)); - let llfixed_ty = T_ptr(type_of::type_of(bcx.ccx(), fixed_ty)); + let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty).ptr_to(); let llfixed_casted = BitCast(bcx, llfixed, llfixed_ty); add_clean(bcx, llfixed_casted, fixed_ty); @@ -271,13 +273,10 @@ pub fn trans_lit_str(bcx: block, let bytes = str_lit.len() + 1; // count null-terminator too let llbytes = C_uint(bcx.ccx(), bytes); let llcstr = C_cstr(bcx.ccx(), str_lit); - let llcstr = llvm::LLVMConstPointerCast(llcstr, - T_ptr(T_i8())); - Store(bcx, - llcstr, + let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p().to_ref()); + Store(bcx, llcstr, GEPi(bcx, lldest, [0u, abi::slice_elt_base])); - Store(bcx, - llbytes, + Store(bcx, llbytes, GEPi(bcx, lldest, [0u, abi::slice_elt_len])); bcx } @@ -286,10 +285,8 @@ pub fn trans_lit_str(bcx: block, } -pub fn trans_uniq_or_managed_vstore(bcx: block, - heap: heap, - vstore_expr: @ast::expr, - content_expr: @ast::expr) -> DatumBlock { +pub fn trans_uniq_or_managed_vstore(bcx: block, heap: heap, vstore_expr: @ast::expr, + content_expr: &ast::expr) -> DatumBlock { //! // // @[...] or ~[...] (also @"..." or ~"...") allocate boxes in the @@ -307,7 +304,7 @@ pub fn trans_uniq_or_managed_vstore(bcx: block, node: ast::lit_str(s), _ }) => { let llptrval = C_cstr(bcx.ccx(), s); - let llptrval = PointerCast(bcx, llptrval, T_ptr(T_i8())); + let llptrval = PointerCast(bcx, llptrval, Type::i8p()); let llsizeval = C_uint(bcx.ccx(), s.len()); let typ = ty::mk_estr(bcx.tcx(), ty::vstore_uniq); let lldestval = scratch_datum(bcx, typ, false); @@ -324,6 +321,7 @@ pub fn trans_uniq_or_managed_vstore(bcx: block, _ => {} } } + heap_exchange_closure => fail!("vectors are not allocated with closure_exchange_alloc"), heap_managed | heap_managed_unique => {} } @@ -336,7 +334,7 @@ pub fn trans_uniq_or_managed_vstore(bcx: block, let dataptr = get_dataptr(bcx, get_bodyptr(bcx, val)); debug!("alloc_vec() returned val=%s, dataptr=%s", - bcx.val_str(val), bcx.val_str(dataptr)); + bcx.val_to_str(val), bcx.val_to_str(dataptr)); let bcx = write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(dataptr)); @@ -349,10 +347,10 @@ pub fn trans_uniq_or_managed_vstore(bcx: block, pub fn write_content(bcx: block, vt: &VecTypes, vstore_expr: @ast::expr, - content_expr: @ast::expr, + content_expr: &ast::expr, dest: Dest) -> block { - let _icx = bcx.insn_ctxt("tvec::write_content"); + let _icx = push_ctxt("tvec::write_content"); let mut bcx = bcx; debug!("write_content(vt=%s, dest=%s, vstore_expr=%?)", @@ -379,23 +377,23 @@ pub fn write_content(bcx: block, ast::expr_vec(ref elements, _) => { match dest { Ignore => { - for elements.each |element| { + for elements.iter().advance |element| { bcx = expr::trans_into(bcx, *element, Ignore); } } SaveIn(lldest) => { let mut temp_cleanups = ~[]; - for elements.eachi |i, element| { + for elements.iter().enumerate().advance |(i, element)| { let lleltptr = GEPi(bcx, lldest, [i]); debug!("writing index %? with lleltptr=%?", - i, bcx.val_str(lleltptr)); + i, bcx.val_to_str(lleltptr)); bcx = expr::trans_into(bcx, *element, SaveIn(lleltptr)); add_clean_temp_mem(bcx, lleltptr, vt.unit_ty); temp_cleanups.push(lleltptr); } - for temp_cleanups.each |cleanup| { + for temp_cleanups.iter().advance |cleanup| { revoke_clean(bcx, *cleanup); } } @@ -474,7 +472,7 @@ pub fn write_content(bcx: block, } } -pub fn vec_types_from_expr(bcx: block, vec_expr: @ast::expr) -> VecTypes { +pub fn vec_types_from_expr(bcx: block, vec_expr: &ast::expr) -> VecTypes { let vec_ty = node_id_type(bcx, vec_expr.id); vec_types(bcx, vec_ty) } @@ -491,7 +489,7 @@ pub fn vec_types(bcx: block, vec_ty: ty::t) -> VecTypes { llunit_size: llunit_size} } -pub fn elements_required(bcx: block, content_expr: @ast::expr) -> uint { +pub fn elements_required(bcx: block, content_expr: &ast::expr) -> uint { //! Figure out the number of elements we need to store this content match content_expr.node { @@ -545,13 +543,11 @@ pub fn get_base_and_len(bcx: block, } } -pub type val_and_ty_fn = @fn(block, ValueRef, ty::t) -> Result; - pub type iter_vec_block<'self> = &'self fn(block, ValueRef, ty::t) -> block; pub fn iter_vec_raw(bcx: block, data_ptr: ValueRef, vec_ty: ty::t, fill: ValueRef, f: iter_vec_block) -> block { - let _icx = bcx.insn_ctxt("tvec::iter_vec_raw"); + let _icx = push_ctxt("tvec::iter_vec_raw"); let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); @@ -582,14 +578,14 @@ pub fn iter_vec_raw(bcx: block, data_ptr: ValueRef, vec_ty: ty::t, pub fn iter_vec_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t, fill: ValueRef, f: iter_vec_block) -> block { - let _icx = bcx.insn_ctxt("tvec::iter_vec_uniq"); + let _icx = push_ctxt("tvec::iter_vec_uniq"); let data_ptr = get_dataptr(bcx, get_bodyptr(bcx, vptr)); iter_vec_raw(bcx, data_ptr, vec_ty, fill, f) } pub fn iter_vec_unboxed(bcx: block, body_ptr: ValueRef, vec_ty: ty::t, f: iter_vec_block) -> block { - let _icx = bcx.insn_ctxt("tvec::iter_vec_unboxed"); + let _icx = push_ctxt("tvec::iter_vec_unboxed"); let fill = get_fill(bcx, body_ptr); let dataptr = get_dataptr(bcx, body_ptr); return iter_vec_raw(bcx, dataptr, vec_ty, fill, f); diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs new file mode 100644 index 00000000000..e52d33fc6e9 --- /dev/null +++ b/src/librustc/middle/trans/type_.rs @@ -0,0 +1,369 @@ +// 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. + + +use lib::llvm::{llvm, TypeRef, Bool, False, True, TypeKind}; +use lib::llvm::{Float, Double, X86_FP80, PPC_FP128, FP128}; + +use middle::ty; + +use middle::trans::context::CrateContext; +use middle::trans::base; + +use syntax::ast; +use syntax::abi::{Architecture, X86, X86_64, Arm, Mips}; + +use std::vec; +use std::cast; + +use std::libc::{c_uint}; + +#[deriving(Eq)] +pub struct Type { + priv rf: TypeRef +} + +macro_rules! ty ( + ($e:expr) => ( Type::from_ref(unsafe { $e })) +) + +/** + * Wrapper for LLVM TypeRef + */ +impl Type { + #[inline(always)] + pub fn from_ref(r: TypeRef) -> Type { + Type { + rf: r + } + } + + #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler + pub fn to_ref(&self) -> TypeRef { + self.rf + } + + pub fn void() -> Type { + ty!(llvm::LLVMVoidTypeInContext(base::task_llcx())) + } + + pub fn nil() -> Type { + Type::empty_struct() + } + + pub fn metadata() -> Type { + ty!(llvm::LLVMMetadataTypeInContext(base::task_llcx())) + } + + pub fn i1() -> Type { + ty!(llvm::LLVMInt1TypeInContext(base::task_llcx())) + } + + pub fn i8() -> Type { + ty!(llvm::LLVMInt8TypeInContext(base::task_llcx())) + } + + pub fn i16() -> Type { + ty!(llvm::LLVMInt16TypeInContext(base::task_llcx())) + } + + pub fn i32() -> Type { + ty!(llvm::LLVMInt32TypeInContext(base::task_llcx())) + } + + pub fn i64() -> Type { + ty!(llvm::LLVMInt64TypeInContext(base::task_llcx())) + } + + pub fn f32() -> Type { + ty!(llvm::LLVMFloatTypeInContext(base::task_llcx())) + } + + pub fn f64() -> Type { + ty!(llvm::LLVMDoubleTypeInContext(base::task_llcx())) + } + + pub fn bool() -> Type { + Type::i8() + } + + pub fn char() -> Type { + Type::i32() + } + + pub fn i8p() -> Type { + Type::i8().ptr_to() + } + + pub fn int(arch: Architecture) -> Type { + match arch { + X86 | Arm | Mips => Type::i32(), + X86_64 => Type::i64() + } + } + + pub fn float(_: Architecture) -> Type { + // All architectures currently just use doubles as the default + // float size + Type::f64() + } + + pub fn int_from_ty(ctx: &CrateContext, t: ast::int_ty) -> Type { + match t { + ast::ty_i => ctx.int_type, + ast::ty_char => Type::char(), + ast::ty_i8 => Type::i8(), + ast::ty_i16 => Type::i16(), + ast::ty_i32 => Type::i32(), + ast::ty_i64 => Type::i64() + } + } + + pub fn uint_from_ty(ctx: &CrateContext, t: ast::uint_ty) -> Type { + match t { + ast::ty_u => ctx.int_type, + ast::ty_u8 => Type::i8(), + ast::ty_u16 => Type::i16(), + ast::ty_u32 => Type::i32(), + ast::ty_u64 => Type::i64() + } + } + + pub fn float_from_ty(ctx: &CrateContext, t: ast::float_ty) -> Type { + match t { + ast::ty_f => ctx.float_type, + ast::ty_f32 => Type::f32(), + ast::ty_f64 => Type::f64() + } + } + + pub fn size_t(arch: Architecture) -> Type { + Type::int(arch) + } + + pub fn func(args: &[Type], ret: &Type) -> Type { + let vec : &[TypeRef] = unsafe { cast::transmute(args) }; + ty!(llvm::LLVMFunctionType(ret.to_ref(), vec::raw::to_ptr(vec), + args.len() as c_uint, False)) + } + + pub fn func_pair(cx: &CrateContext, fn_ty: &Type) -> Type { + Type::struct_([fn_ty.ptr_to(), Type::opaque_cbox_ptr(cx)], false) + } + + pub fn ptr(ty: Type) -> Type { + ty!(llvm::LLVMPointerType(ty.to_ref(), 0 as c_uint)) + } + + pub fn struct_(els: &[Type], packed: bool) -> Type { + let els : &[TypeRef] = unsafe { cast::transmute(els) }; + ty!(llvm::LLVMStructTypeInContext(base::task_llcx(), vec::raw::to_ptr(els), + els.len() as c_uint, packed as Bool)) + } + + pub fn named_struct(name: &str) -> Type { + let ctx = base::task_llcx(); + ty!(name.as_c_str(|s| llvm::LLVMStructCreateNamed(ctx, s))) + } + + pub fn empty_struct() -> Type { + Type::struct_([], false) + } + + pub fn vtable() -> Type { + Type::array(&Type::i8().ptr_to(), 1) + } + + pub fn generic_glue_fn(cx: &mut CrateContext) -> Type { + match cx.tn.find_type("glue_fn") { + Some(ty) => return ty, + None => () + } + + let ty = Type::glue_fn(); + cx.tn.associate_type("glue_fn", &ty); + + return ty; + } + + pub fn glue_fn() -> Type { + Type::func([ Type::nil().ptr_to(), Type::i8p() ], + &Type::void()) + } + + pub fn tydesc(arch: Architecture) -> Type { + let mut tydesc = Type::named_struct("tydesc"); + let glue_fn_ty = Type::glue_fn().ptr_to(); + + let int_ty = Type::int(arch); + + let elems = [ + int_ty, int_ty, + glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty + ]; + + tydesc.set_struct_body(elems, false); + + return tydesc; + } + + pub fn array(ty: &Type, len: u64) -> Type { + ty!(llvm::LLVMArrayType(ty.to_ref(), len as c_uint)) + } + + pub fn vector(ty: &Type, len: u64) -> Type { + ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint)) + } + + pub fn vec(arch: Architecture, ty: &Type) -> Type { + Type::struct_( + [ Type::int(arch), Type::int(arch), Type::array(ty, 0) ], + false) + } + + pub fn opaque_vec(arch: Architecture) -> Type { + Type::vec(arch, &Type::i8()) + } + + #[inline] + pub fn box_header_fields(ctx: &CrateContext) -> ~[Type] { + ~[ + ctx.int_type, ctx.tydesc_type.ptr_to(), + Type::i8().ptr_to(), Type::i8().ptr_to() + ] + } + + pub fn box_header(ctx: &CrateContext) -> Type { + Type::struct_(Type::box_header_fields(ctx), false) + } + + pub fn box(ctx: &CrateContext, ty: &Type) -> Type { + Type::struct_(Type::box_header_fields(ctx) + [*ty], false) + } + + pub fn opaque_box(ctx: &CrateContext) -> Type { + Type::box(ctx, &Type::i8()) + } + + pub fn unique(ctx: &CrateContext, ty: &Type) -> Type { + Type::box(ctx, ty) + } + + pub fn opaque_cbox_ptr(cx: &CrateContext) -> Type { + Type::opaque_box(cx).ptr_to() + } + + pub fn enum_discrim(cx: &CrateContext) -> Type { + cx.int_type + } + + pub fn opaque_trait(ctx: &CrateContext, store: ty::TraitStore) -> Type { + let tydesc_ptr = ctx.tydesc_type.ptr_to(); + match store { + ty::BoxTraitStore => { + Type::struct_( + [ tydesc_ptr, Type::opaque_box(ctx).ptr_to() ], + false) + } + ty::UniqTraitStore => { + Type::struct_( + [ tydesc_ptr, Type::unique(ctx, &Type::i8()).ptr_to()], + false) + } + ty::RegionTraitStore(*) => { + Type::struct_( + [ tydesc_ptr, Type::i8().ptr_to() ], + false) + } + } + } + + pub fn kind(&self) -> TypeKind { + unsafe { + llvm::LLVMGetTypeKind(self.to_ref()) + } + } + + pub fn set_struct_body(&mut self, els: &[Type], packed: bool) { + unsafe { + let vec : &[TypeRef] = cast::transmute(els); + llvm::LLVMStructSetBody(self.to_ref(), vec::raw::to_ptr(vec), + els.len() as c_uint, packed as Bool) + } + } + + pub fn ptr_to(&self) -> Type { + ty!(llvm::LLVMPointerType(self.to_ref(), 0)) + } + + pub fn get_field(&self, idx: uint) -> Type { + unsafe { + let num_fields = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint; + let mut elems = vec::from_elem(num_fields, 0 as TypeRef); + + llvm::LLVMGetStructElementTypes(self.to_ref(), vec::raw::to_mut_ptr(elems)); + + Type::from_ref(elems[idx]) + } + } + + pub fn is_packed(&self) -> bool { + unsafe { + llvm::LLVMIsPackedStruct(self.to_ref()) == True + } + } + + pub fn element_type(&self) -> Type { + unsafe { + Type::from_ref(llvm::LLVMGetElementType(self.to_ref())) + } + } + + pub fn array_length(&self) -> uint { + unsafe { + llvm::LLVMGetArrayLength(self.to_ref()) as uint + } + } + + pub fn field_types(&self) -> ~[Type] { + unsafe { + let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint; + if n_elts == 0 { + return ~[]; + } + let mut elts = vec::from_elem(n_elts, 0 as TypeRef); + llvm::LLVMGetStructElementTypes(self.to_ref(), &mut elts[0]); + cast::transmute(elts) + } + } + + pub fn return_type(&self) -> Type { + ty!(llvm::LLVMGetReturnType(self.to_ref())) + } + + pub fn func_params(&self) -> ~[Type] { + unsafe { + let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint; + let args = vec::from_elem(n_args, 0 as TypeRef); + llvm::LLVMGetParamTypes(self.to_ref(), vec::raw::to_ptr(args)); + cast::transmute(args) + } + } + + pub fn float_width(&self) -> uint { + match self.kind() { + Float => 32, + Double => 64, + X86_FP80 => 80, + FP128 | PPC_FP128 => 128, + _ => fail!("llvm_float_width called on a non-float type") + } + } +} diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 268d60d4417..481f08ee192 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -8,63 +8,61 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; -use lib::llvm::llvm; -use lib::llvm::{TypeRef}; use middle::trans::adt; -use middle::trans::base; use middle::trans::common::*; -use middle::trans::common; use middle::ty; use util::ppaux; +use middle::trans::type_::Type; + use syntax::ast; pub fn arg_is_indirect(_: &CrateContext, arg_ty: &ty::t) -> bool { !ty::type_is_immediate(*arg_ty) } -pub fn type_of_explicit_arg(ccx: &mut CrateContext, arg_ty: &ty::t) -> TypeRef { +pub fn type_of_explicit_arg(ccx: &mut CrateContext, arg_ty: &ty::t) -> Type { let llty = type_of(ccx, *arg_ty); - if arg_is_indirect(ccx, arg_ty) {T_ptr(llty)} else {llty} + if arg_is_indirect(ccx, arg_ty) { + llty.ptr_to() + } else { + llty + } } pub fn type_of_explicit_args(ccx: &mut CrateContext, - inputs: &[ty::t]) -> ~[TypeRef] { + inputs: &[ty::t]) -> ~[Type] { inputs.map(|arg_ty| type_of_explicit_arg(ccx, arg_ty)) } -pub fn type_of_fn(cx: &mut CrateContext, inputs: &[ty::t], output: ty::t) - -> TypeRef { - unsafe { - let mut atys: ~[TypeRef] = ~[]; - - // Arg 0: Output pointer. - // (if the output type is non-immediate) - let output_is_immediate = ty::type_is_immediate(output); - let lloutputtype = type_of(cx, output); - if !output_is_immediate { - atys.push(T_ptr(lloutputtype)); - } +pub fn type_of_fn(cx: &mut CrateContext, inputs: &[ty::t], output: ty::t) -> Type { + let mut atys: ~[Type] = ~[]; - // Arg 1: Environment - atys.push(T_opaque_box_ptr(cx)); + // Arg 0: Output pointer. + // (if the output type is non-immediate) + let output_is_immediate = ty::type_is_immediate(output); + let lloutputtype = type_of(cx, output); + if !output_is_immediate { + atys.push(lloutputtype.ptr_to()); + } - // ... then explicit args. - atys.push_all(type_of_explicit_args(cx, inputs)); + // Arg 1: Environment + atys.push(Type::opaque_box(cx).ptr_to()); - // Use the output as the actual return value if it's immediate. - if output_is_immediate { - T_fn(atys, lloutputtype) - } else { - T_fn(atys, llvm::LLVMVoidTypeInContext(cx.llcx)) - } + // ... then explicit args. + atys.push_all(type_of_explicit_args(cx, inputs)); + + // Use the output as the actual return value if it's immediate. + if output_is_immediate && !ty::type_is_nil(output) { + Type::func(atys, &lloutputtype) + } else { + Type::func(atys, &Type::void()) } } // Given a function type and a count of ty params, construct an llvm type -pub fn type_of_fn_from_ty(cx: &mut CrateContext, fty: ty::t) -> TypeRef { +pub fn type_of_fn_from_ty(cx: &mut CrateContext, fty: ty::t) -> Type { match ty::get(fty).sty { ty::ty_closure(ref f) => type_of_fn(cx, f.sig.inputs, f.sig.output), ty::ty_bare_fn(ref f) => type_of_fn(cx, f.sig.inputs, f.sig.output), @@ -74,7 +72,7 @@ pub fn type_of_fn_from_ty(cx: &mut CrateContext, fty: ty::t) -> TypeRef { } } -pub fn type_of_non_gc_box(cx: &mut CrateContext, t: ty::t) -> TypeRef { +pub fn type_of_non_gc_box(cx: &mut CrateContext, t: ty::t) -> Type { assert!(!ty::type_needs_infer(t)); let t_norm = ty::normalize_ty(cx.tcx, t); @@ -84,11 +82,11 @@ pub fn type_of_non_gc_box(cx: &mut CrateContext, t: ty::t) -> TypeRef { match ty::get(t).sty { ty::ty_box(mt) => { let ty = type_of(cx, mt.ty); - T_ptr(T_box(cx, ty)) + Type::box(cx, &ty).ptr_to() } ty::ty_uniq(mt) => { let ty = type_of(cx, mt.ty); - T_ptr(T_unique(cx, ty)) + Type::unique(cx, &ty).ptr_to() } _ => { cx.sess.bug("non-box in type_of_non_gc_box"); @@ -109,18 +107,18 @@ pub fn type_of_non_gc_box(cx: &mut CrateContext, t: ty::t) -> TypeRef { // recursive types. For example, `static_size_of_enum()` relies on this // behavior. -pub fn sizing_type_of(cx: &mut CrateContext, t: ty::t) -> TypeRef { - match cx.llsizingtypes.find(&t) { - Some(t) => return *t, +pub fn sizing_type_of(cx: &mut CrateContext, t: ty::t) -> Type { + match cx.llsizingtypes.find_copy(&t) { + Some(t) => return t, None => () } let llsizingty = match ty::get(t).sty { - ty::ty_nil | ty::ty_bot => T_nil(), - ty::ty_bool => T_bool(), - ty::ty_int(t) => T_int_ty(cx, t), - ty::ty_uint(t) => T_uint_ty(cx, t), - ty::ty_float(t) => T_float_ty(cx, t), + ty::ty_nil | ty::ty_bot => Type::nil(), + ty::ty_bool => Type::bool(), + ty::ty_int(t) => Type::int_from_ty(cx, t), + ty::ty_uint(t) => Type::uint_from_ty(cx, t), + ty::ty_float(t) => Type::float_from_ty(cx, t), ty::ty_estr(ty::vstore_uniq) | ty::ty_estr(ty::vstore_box) | @@ -132,48 +130,46 @@ pub fn sizing_type_of(cx: &mut CrateContext, t: ty::t) -> TypeRef { ty::ty_ptr(*) | ty::ty_rptr(*) | ty::ty_type | - ty::ty_opaque_closure_ptr(*) => T_ptr(T_i8()), + ty::ty_opaque_closure_ptr(*) => Type::i8p(), ty::ty_estr(ty::vstore_slice(*)) | ty::ty_evec(_, ty::vstore_slice(*)) => { - T_struct([T_ptr(T_i8()), T_ptr(T_i8())], false) + Type::struct_([Type::i8p(), Type::i8p()], false) } - ty::ty_bare_fn(*) => T_ptr(T_i8()), - ty::ty_closure(*) => T_struct([T_ptr(T_i8()), T_ptr(T_i8())], false), - ty::ty_trait(_, _, store, _) => T_opaque_trait(cx, store), + ty::ty_bare_fn(*) => Type::i8p(), + ty::ty_closure(*) => Type::struct_([Type::i8p(), Type::i8p()], false), + ty::ty_trait(_, _, store, _, _) => Type::opaque_trait(cx, store), - ty::ty_estr(ty::vstore_fixed(size)) => T_array(T_i8(), size), + ty::ty_estr(ty::vstore_fixed(size)) => Type::array(&Type::i8(), size as u64), ty::ty_evec(mt, ty::vstore_fixed(size)) => { - T_array(sizing_type_of(cx, mt.ty), size) + Type::array(&sizing_type_of(cx, mt.ty), size as u64) } ty::ty_unboxed_vec(mt) => { let sz_ty = sizing_type_of(cx, mt.ty); - T_vec(cx, sz_ty) + Type::vec(cx.sess.targ_cfg.arch, &sz_ty) } ty::ty_tup(*) | ty::ty_enum(*) => { let repr = adt::represent_type(cx, t); - T_struct(adt::sizing_fields_of(cx, repr), false) + Type::struct_(adt::sizing_fields_of(cx, repr), false) } ty::ty_struct(did, _) => { if ty::type_is_simd(cx.tcx, t) { let et = ty::simd_type(cx.tcx, t); let n = ty::simd_size(cx.tcx, t); - T_vector(type_of(cx, et), n) + Type::vector(&type_of(cx, et), n as u64) } else { let repr = adt::represent_type(cx, t); let packed = ty::lookup_packed(cx.tcx, did); - T_struct(adt::sizing_fields_of(cx, repr), packed) + Type::struct_(adt::sizing_fields_of(cx, repr), packed) } } ty::ty_self(_) | ty::ty_infer(*) | ty::ty_param(*) | ty::ty_err(*) => { - cx.tcx.sess.bug( - fmt!("fictitious type %? in sizing_type_of()", - ty::get(t).sty)) + cx.tcx.sess.bug(fmt!("fictitious type %? in sizing_type_of()", ty::get(t).sty)) } }; @@ -182,7 +178,7 @@ pub fn sizing_type_of(cx: &mut CrateContext, t: ty::t) -> TypeRef { } // NB: If you update this, be sure to update `sizing_type_of()` as well. -pub fn type_of(cx: &mut CrateContext, t: ty::t) -> TypeRef { +pub fn type_of(cx: &mut CrateContext, t: ty::t) -> Type { debug!("type_of %?: %?", t, ty::get(t)); // Check the cache. @@ -204,14 +200,14 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> TypeRef { return llty; } - let llty = match ty::get(t).sty { - ty::ty_nil | ty::ty_bot => T_nil(), - ty::ty_bool => T_bool(), - ty::ty_int(t) => T_int_ty(cx, t), - ty::ty_uint(t) => T_uint_ty(cx, t), - ty::ty_float(t) => T_float_ty(cx, t), + let mut llty = match ty::get(t).sty { + ty::ty_nil | ty::ty_bot => Type::nil(), + ty::ty_bool => Type::bool(), + ty::ty_int(t) => Type::int_from_ty(cx, t), + ty::ty_uint(t) => Type::uint_from_ty(cx, t), + ty::ty_float(t) => Type::float_from_ty(cx, t), ty::ty_estr(ty::vstore_uniq) => { - T_unique_ptr(T_unique(cx, T_vec(cx, T_i8()))) + Type::unique(cx, &Type::vec(cx.sess.targ_cfg.arch, &Type::i8())).ptr_to() } ty::ty_enum(did, ref substs) => { // Only create the named struct, but don't fill it in. We @@ -219,84 +215,79 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> TypeRef { // avoids creating more than one copy of the enum when one // of the enum's variants refers to the enum itself. - common::T_named_struct(llvm_type_name(cx, - an_enum, - did, - substs.tps)) + Type::named_struct(llvm_type_name(cx, an_enum, did, substs.tps)) } ty::ty_estr(ty::vstore_box) => { - T_box_ptr(T_box(cx, T_vec(cx, T_i8()))) + Type::box(cx, &Type::vec(cx.sess.targ_cfg.arch, &Type::i8())).ptr_to() } ty::ty_evec(ref mt, ty::vstore_box) => { let e_ty = type_of(cx, mt.ty); - let v_ty = T_vec(cx, e_ty); - T_box_ptr(T_box(cx, v_ty)) + let v_ty = Type::vec(cx.sess.targ_cfg.arch, &e_ty); + Type::box(cx, &v_ty).ptr_to() } ty::ty_box(ref mt) => { let ty = type_of(cx, mt.ty); - T_box_ptr(T_box(cx, ty)) + Type::box(cx, &ty).ptr_to() } - ty::ty_opaque_box => T_box_ptr(T_box(cx, T_i8())), + ty::ty_opaque_box => Type::opaque_box(cx).ptr_to(), ty::ty_uniq(ref mt) => { let ty = type_of(cx, mt.ty); - T_unique_ptr(T_unique(cx, ty)) + Type::unique(cx, &ty).ptr_to() } ty::ty_evec(ref mt, ty::vstore_uniq) => { let ty = type_of(cx, mt.ty); - let ty = T_vec(cx, ty); - T_unique_ptr(T_unique(cx, ty)) + let ty = Type::vec(cx.sess.targ_cfg.arch, &ty); + Type::unique(cx, &ty).ptr_to() } ty::ty_unboxed_vec(ref mt) => { let ty = type_of(cx, mt.ty); - T_vec(cx, ty) + Type::vec(cx.sess.targ_cfg.arch, &ty) } - ty::ty_ptr(ref mt) => T_ptr(type_of(cx, mt.ty)), - ty::ty_rptr(_, ref mt) => T_ptr(type_of(cx, mt.ty)), + ty::ty_ptr(ref mt) => type_of(cx, mt.ty).ptr_to(), + ty::ty_rptr(_, ref mt) => type_of(cx, mt.ty).ptr_to(), ty::ty_evec(ref mt, ty::vstore_slice(_)) => { - let p_ty = T_ptr(type_of(cx, mt.ty)); - let u_ty = T_uint_ty(cx, ast::ty_u); - T_struct([p_ty, u_ty], false) + let p_ty = type_of(cx, mt.ty).ptr_to(); + let u_ty = Type::uint_from_ty(cx, ast::ty_u); + Type::struct_([p_ty, u_ty], false) } ty::ty_estr(ty::vstore_slice(_)) => { - T_struct([T_ptr(T_i8()), T_uint_ty(cx, ast::ty_u)], false) + // This means we get a nicer name in the output + cx.tn.find_type("str_slice").get() } ty::ty_estr(ty::vstore_fixed(n)) => { - T_array(T_i8(), n + 1u /* +1 for trailing null */) + Type::array(&Type::i8(), (n + 1u) as u64) } ty::ty_evec(ref mt, ty::vstore_fixed(n)) => { - T_array(type_of(cx, mt.ty), n) + Type::array(&type_of(cx, mt.ty), n as u64) } - ty::ty_bare_fn(_) => T_ptr(type_of_fn_from_ty(cx, t)), + ty::ty_bare_fn(_) => type_of_fn_from_ty(cx, t).ptr_to(), ty::ty_closure(_) => { let ty = type_of_fn_from_ty(cx, t); - T_fn_pair(cx, ty) + Type::func_pair(cx, &ty) } - ty::ty_trait(_, _, store, _) => T_opaque_trait(cx, store), - ty::ty_type => T_ptr(cx.tydesc_type), + ty::ty_trait(_, _, store, _, _) => Type::opaque_trait(cx, store), + ty::ty_type => cx.tydesc_type.ptr_to(), ty::ty_tup(*) => { let repr = adt::represent_type(cx, t); - T_struct(adt::fields_of(cx, repr), false) + Type::struct_(adt::fields_of(cx, repr), false) } - ty::ty_opaque_closure_ptr(_) => T_opaque_box_ptr(cx), + ty::ty_opaque_closure_ptr(_) => Type::opaque_box(cx).ptr_to(), ty::ty_struct(did, ref substs) => { - if ty::type_is_simd(cx.tcx, t) { - let et = ty::simd_type(cx.tcx, t); - let n = ty::simd_size(cx.tcx, t); - T_vector(type_of(cx, et), n) - } else { - // Only create the named struct, but don't fill it in. We fill it - // in *after* placing it into the type cache. This prevents - // infinite recursion with recursive struct types. - T_named_struct(llvm_type_name(cx, - a_struct, - did, - substs.tps)) - } + if ty::type_is_simd(cx.tcx, t) { + let et = ty::simd_type(cx.tcx, t); + let n = ty::simd_size(cx.tcx, t); + Type::vector(&type_of(cx, et), n as u64) + } else { + // Only create the named struct, but don't fill it in. We fill it + // in *after* placing it into the type cache. This prevents + // infinite recursion with recursive struct types. + Type::named_struct(llvm_type_name(cx, a_struct, did, substs.tps)) + } } ty::ty_self(*) => cx.tcx.sess.unimpl("type_of: ty_self"), ty::ty_infer(*) => cx.tcx.sess.bug("type_of with ty_infer"), @@ -310,16 +301,14 @@ pub fn type_of(cx: &mut CrateContext, t: ty::t) -> TypeRef { match ty::get(t).sty { ty::ty_enum(*) => { let repr = adt::represent_type(cx, t); - common::set_struct_body(llty, adt::fields_of(cx, repr), - false); + llty.set_struct_body(adt::fields_of(cx, repr), false); } ty::ty_struct(did, _) => { if !ty::type_is_simd(cx.tcx, t) { let repr = adt::represent_type(cx, t); let packed = ty::lookup_packed(cx.tcx, did); - common::set_struct_body(llty, adt::fields_of(cx, repr), - packed); + llty.set_struct_body(adt::fields_of(cx, repr), packed); } } _ => () @@ -336,33 +325,18 @@ pub fn llvm_type_name(cx: &CrateContext, did: ast::def_id, tps: &[ty::t]) -> ~str { let name = match what { - a_struct => { "~struct" } - an_enum => { "~enum" } + a_struct => { "struct" } + an_enum => { "enum" } }; - return fmt!( - "%s %s[#%d]", - name, - ppaux::parameterized( - cx.tcx, - ty::item_path_str(cx.tcx, did), - None, - tps), - did.crate - ); -} - -pub fn type_of_dtor(ccx: &mut CrateContext, self_ty: ty::t) -> TypeRef { - T_fn([T_ptr(type_of(ccx, self_ty))] /* self */, T_nil()) -} - -pub fn type_of_rooted(ccx: &mut CrateContext, t: ty::t) -> TypeRef { - let addrspace = base::get_tydesc(ccx, t).addrspace; - debug!("type_of_rooted %s in addrspace %u", - ppaux::ty_to_str(ccx.tcx, t), addrspace as uint); - return T_root(type_of(ccx, t), addrspace); + let tstr = ppaux::parameterized(cx.tcx, ty::item_path_str(cx.tcx, did), None, tps); + if did.crate == 0 { + fmt!("%s.%s", name, tstr) + } else { + fmt!("%s.%s[#%d]", name, tstr, did.crate) + } } -pub fn type_of_glue_fn(ccx: &CrateContext) -> TypeRef { - let tydescpp = T_ptr(T_ptr(ccx.tydesc_type)); - return T_fn([T_ptr(T_nil()), tydescpp, T_ptr(T_i8())], T_nil()); +pub fn type_of_dtor(ccx: &mut CrateContext, self_ty: ty::t) -> Type { + let self_ty = type_of(ccx, self_ty).ptr_to(); + Type::func([self_ty], &Type::void()) } diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 8c4ff441564..b3848f5e86c 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -33,9 +33,9 @@ use middle::trans::inline; use middle::ty; use middle::typeck; -use core::option::{Some, None}; -use core::uint; -use core::vec; +use std::option::{Some, None}; +use std::uint; +use std::vec; use extra::list::{List, Cons, Nil}; use extra::list; use syntax::ast; @@ -78,8 +78,8 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint) match ty::get(ty::lookup_item_type(cx.ccx.tcx, fn_id).ty).sty { ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) | ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => { - for sig.inputs.each |arg| { - type_needs(cx, use_repr, *arg); + for sig.inputs.iter().advance |arg| { + type_needs(&cx, use_repr, *arg); } } _ => () @@ -100,7 +100,7 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint) ast_map::node_item(@ast::item { node: item_fn(_, _, _, _, ref body), _ }, _) | ast_map::node_method(@ast::method {body: ref body, _}, _, _) => { - handle_body(cx, body); + handle_body(&cx, body); } ast_map::node_trait_method(*) => { // This will be a static trait method. For now, we just assume @@ -117,46 +117,43 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint) _, _) => { if abi.is_intrinsic() { - let flags = match cx.ccx.sess.str_of(i.ident).as_slice() { - "size_of" | "pref_align_of" | "min_align_of" | - "uninit" | "init" | "transmute" | "move_val" | - "move_val_init" => use_repr, - - "get_tydesc" | "needs_drop" => use_tydesc, - - "atomic_cxchg" | "atomic_cxchg_acq"| - "atomic_cxchg_rel"| "atomic_load" | - "atomic_load_acq" | "atomic_store" | - "atomic_store_rel"| "atomic_xchg" | - "atomic_xadd" | "atomic_xsub" | - "atomic_xchg_acq" | "atomic_xadd_acq" | - "atomic_xsub_acq" | "atomic_xchg_rel" | - "atomic_xadd_rel" | "atomic_xsub_rel" => 0, - - "visit_tydesc" | "forget" | "frame_address" | - "morestack_addr" => 0, - - "memcpy32" | "memcpy64" | "memmove32" | "memmove64" | - "memset32" | "memset64" => use_repr, - - "sqrtf32" | "sqrtf64" | "powif32" | "powif64" | - "sinf32" | "sinf64" | "cosf32" | "cosf64" | - "powf32" | "powf64" | "expf32" | "expf64" | - "exp2f32" | "exp2f64" | "logf32" | "logf64" | - "log10f32"| "log10f64"| "log2f32" | "log2f64" | - "fmaf32" | "fmaf64" | "fabsf32" | "fabsf64" | - "floorf32"| "floorf64"| "ceilf32" | "ceilf64" | - "truncf32"| "truncf64" => 0, - - "ctpop8" | "ctpop16" | "ctpop32" | "ctpop64" => 0, - - "ctlz8" | "ctlz16" | "ctlz32" | "ctlz64" => 0, - "cttz8" | "cttz16" | "cttz32" | "cttz64" => 0, - - "bswap16" | "bswap32" | "bswap64" => 0, - - // would be cool to make these an enum instead of strings! - _ => fail!("unknown intrinsic in type_use") + let nm = cx.ccx.sess.str_of(i.ident); + let name = nm.as_slice(); + let flags = if name.starts_with("atomic_") { + 0 + } else { + match name { + "size_of" | "pref_align_of" | "min_align_of" | + "uninit" | "init" | "transmute" | "move_val" | + "move_val_init" => use_repr, + + "get_tydesc" | "needs_drop" | "contains_managed" => use_tydesc, + + "visit_tydesc" | "forget" | "frame_address" | + "morestack_addr" => 0, + + "memcpy32" | "memcpy64" | "memmove32" | "memmove64" | + "memset32" | "memset64" => use_repr, + + "sqrtf32" | "sqrtf64" | "powif32" | "powif64" | + "sinf32" | "sinf64" | "cosf32" | "cosf64" | + "powf32" | "powf64" | "expf32" | "expf64" | + "exp2f32" | "exp2f64" | "logf32" | "logf64" | + "log10f32"| "log10f64"| "log2f32" | "log2f64" | + "fmaf32" | "fmaf64" | "fabsf32" | "fabsf64" | + "floorf32"| "floorf64"| "ceilf32" | "ceilf64" | + "truncf32"| "truncf64" => 0, + + "ctpop8" | "ctpop16" | "ctpop32" | "ctpop64" => 0, + + "ctlz8" | "ctlz16" | "ctlz32" | "ctlz64" => 0, + "cttz8" | "cttz16" | "cttz32" | "cttz64" => 0, + + "bswap16" | "bswap32" | "bswap64" => 0, + + // would be cool to make these an enum instead of strings! + _ => fail!("unknown intrinsic in type_use") + } }; for uint::range(0u, n_tps) |n| { cx.uses[n] |= flags;} } @@ -180,7 +177,7 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint) uses } -pub fn type_needs(cx: Context, use_: uint, ty: ty::t) { +pub fn type_needs(cx: &Context, use_: uint, ty: ty::t) { // Optimization -- don't descend type if all params already have this use let len = { let uses = &*cx.uses; @@ -194,7 +191,7 @@ pub fn type_needs(cx: Context, use_: uint, ty: ty::t) { } } -pub fn type_needs_inner(cx: Context, +pub fn type_needs_inner(cx: &Context, use_: uint, ty: ty::t, enums_seen: @List<def_id>) { @@ -211,13 +208,14 @@ pub fn type_needs_inner(cx: Context, ty::ty_bare_fn(*) | ty::ty_ptr(_) | ty::ty_rptr(_, _) | - ty::ty_trait(_, _, _, _) => false, + ty::ty_trait(*) => false, ty::ty_enum(did, ref substs) => { if list::find(enums_seen, |id| *id == did).is_none() { let seen = @Cons(did, enums_seen); - for vec::each(*ty::enum_variants(cx.ccx.tcx, did)) |v| { - for v.args.each |aty| { + let r = ty::enum_variants(cx.ccx.tcx, did); + for r.iter().advance |v| { + for v.args.iter().advance |aty| { let t = ty::subst(cx.ccx.tcx, &(*substs), *aty); type_needs_inner(cx, use_, t, seen); } @@ -235,11 +233,11 @@ pub fn type_needs_inner(cx: Context, } } -pub fn node_type_needs(cx: Context, use_: uint, id: node_id) { +pub fn node_type_needs(cx: &Context, use_: uint, id: node_id) { type_needs(cx, use_, ty::node_id_to_type(cx.ccx.tcx, id)); } -pub fn mark_for_method_call(cx: Context, e_id: node_id, callee_id: node_id) { +pub fn mark_for_method_call(cx: &Context, e_id: node_id, callee_id: node_id) { let mut opt_static_did = None; { let r = cx.ccx.maps.method_map.find(&e_id); @@ -277,10 +275,10 @@ pub fn mark_for_method_call(cx: Context, e_id: node_id, callee_id: node_id) { } } -pub fn mark_for_expr(cx: Context, e: @expr) { +pub fn mark_for_expr(cx: &Context, e: &expr) { match e.node { expr_vstore(_, _) | expr_vec(_, _) | expr_struct(*) | expr_tup(_) | - expr_unary(_, box(_), _) | expr_unary(_, uniq(_), _) | + expr_unary(_, box(_), _) | expr_unary(_, uniq, _) | expr_binary(_, add, _, _) | expr_copy(_) | expr_repeat(*) => { node_type_needs(cx, use_repr, e.id); } @@ -317,7 +315,7 @@ pub fn mark_for_expr(cx: Context, e: @expr) { match ty::ty_closure_sigil(ty::expr_ty(cx.ccx.tcx, e)) { ast::OwnedSigil => {} ast::BorrowedSigil | ast::ManagedSigil => { - for freevars::get_freevars(cx.ccx.tcx, e.id).each |fv| { + for freevars::get_freevars(cx.ccx.tcx, e.id).iter().advance |fv| { let node_id = ast_util::def_id_of_def(fv.def).node; node_type_needs(cx, use_repr, node_id); } @@ -347,7 +345,8 @@ pub fn mark_for_expr(cx: Context, e: @expr) { node_type_needs(cx, use_tydesc, val.id); } expr_call(f, _, _) => { - for ty::ty_fn_args(ty::node_id_to_type(cx.ccx.tcx, f.id)).each |a| { + let r = ty::ty_fn_args(ty::node_id_to_type(cx.ccx.tcx, f.id)); + for r.iter().advance |a| { type_needs(cx, use_repr, *a); } } @@ -355,17 +354,18 @@ pub fn mark_for_expr(cx: Context, e: @expr) { let base_ty = ty::node_id_to_type(cx.ccx.tcx, rcvr.id); type_needs(cx, use_repr, ty::type_autoderef(cx.ccx.tcx, base_ty)); - for ty::ty_fn_args(ty::node_id_to_type(cx.ccx.tcx, callee_id)).each |a| { + let r = ty::ty_fn_args(ty::node_id_to_type(cx.ccx.tcx, callee_id)); + for r.iter().advance |a| { type_needs(cx, use_repr, *a); } mark_for_method_call(cx, e.id, callee_id); } expr_inline_asm(ref ia) => { - for ia.inputs.each |&(_, in)| { + for ia.inputs.iter().advance |&(_, in)| { node_type_needs(cx, use_repr, in.id); } - for ia.outputs.each |&(_, out)| { + for ia.outputs.iter().advance |&(_, out)| { node_type_needs(cx, use_repr, out.id); } } @@ -379,7 +379,7 @@ pub fn mark_for_expr(cx: Context, e: @expr) { } } -pub fn handle_body(cx: Context, body: &blk) { +pub fn handle_body(cx: &Context, body: &blk) { let v = visit::mk_vt(@visit::Visitor { visit_expr: |e, (cx, v)| { visit::visit_expr(e, (cx, v)); diff --git a/src/librustc/middle/trans/uniq.rs b/src/librustc/middle/trans/uniq.rs index 4ce2b780011..ada85c82b30 100644 --- a/src/librustc/middle/trans/uniq.rs +++ b/src/librustc/middle/trans/uniq.rs @@ -21,7 +21,7 @@ use middle::ty; pub fn make_free_glue(bcx: block, vptrptr: ValueRef, box_ty: ty::t) -> block { - let _icx = bcx.insn_ctxt("uniq::make_free_glue"); + let _icx = push_ctxt("uniq::make_free_glue"); let box_datum = immediate_rvalue(Load(bcx, vptrptr), box_ty); let not_null = IsNotNull(bcx, box_datum.val); @@ -38,7 +38,7 @@ pub fn make_free_glue(bcx: block, vptrptr: ValueRef, box_ty: ty::t) } pub fn duplicate(bcx: block, src_box: ValueRef, src_ty: ty::t) -> Result { - let _icx = bcx.insn_ctxt("uniq::duplicate"); + let _icx = push_ctxt("uniq::duplicate"); // Load the body of the source (*src) let src_datum = immediate_rvalue(src_box, src_ty); @@ -52,13 +52,5 @@ pub fn duplicate(bcx: block, src_box: ValueRef, src_ty: ty::t) -> Result { } = malloc_unique(bcx, body_datum.ty); body_datum.copy_to(bcx, datum::INIT, dst_body); - // Copy the type descriptor - let src_tydesc_ptr = GEPi(bcx, src_box, - [0u, back::abi::box_field_tydesc]); - let dst_tydesc_ptr = GEPi(bcx, dst_box, - [0u, back::abi::box_field_tydesc]); - let td = Load(bcx, src_tydesc_ptr); - Store(bcx, td, dst_tydesc_ptr); - - return rslt(bcx, dst_box); + rslt(bcx, dst_box) } diff --git a/src/librustc/middle/trans/write_guard.rs b/src/librustc/middle/trans/write_guard.rs index d76d4642801..068ce4e2b33 100644 --- a/src/librustc/middle/trans/write_guard.rs +++ b/src/librustc/middle/trans/write_guard.rs @@ -14,7 +14,6 @@ //! and for each in debugging (e.g., so you can use //! `RUST_LOG=rustc::middle::trans::write_guard`). -use core::prelude::*; use lib::llvm::ValueRef; use middle::borrowck::{RootInfo, root_map_key, DynaImm, DynaMut}; @@ -28,6 +27,8 @@ use middle::ty; use syntax::codemap::span; use syntax::ast; +use middle::trans::type_::Type; + pub fn root_and_write_guard(datum: &Datum, mut bcx: block, span: span, @@ -64,20 +65,15 @@ pub fn return_to_mut(mut bcx: block, debug!("write_guard::return_to_mut(root_key=%?, %s, %s, %s)", root_key, bcx.to_str(), - val_str(bcx.ccx().tn, frozen_val_ref), - val_str(bcx.ccx().tn, bits_val_ref)); + bcx.val_to_str(frozen_val_ref), + bcx.val_to_str(bits_val_ref)); - let box_ptr = - Load(bcx, PointerCast(bcx, - frozen_val_ref, - T_ptr(T_ptr(T_i8())))); + let box_ptr = Load(bcx, PointerCast(bcx, frozen_val_ref, Type::i8p().ptr_to())); - let bits_val = - Load(bcx, bits_val_ref); + let bits_val = Load(bcx, bits_val_ref); if bcx.tcx().sess.debug_borrows() { - bcx = callee::trans_lang_call( - bcx, + bcx = callee::trans_lang_call( bcx, bcx.tcx().lang_items.unrecord_borrow_fn(), [ box_ptr, @@ -146,10 +142,7 @@ fn root(datum: &Datum, DynaMut => bcx.tcx().lang_items.borrow_as_mut_fn(), }; - let box_ptr = Load(bcx, - PointerCast(bcx, - scratch.val, - T_ptr(T_ptr(T_i8())))); + let box_ptr = Load(bcx, PointerCast(bcx, scratch.val, Type::i8p().ptr_to())); bcx = callee::trans_lang_call( bcx, @@ -194,6 +187,6 @@ fn perform_write_guard(datum: &Datum, callee::trans_lang_call( bcx, bcx.tcx().lang_items.check_not_borrowed_fn(), - [PointerCast(bcx, llval, T_ptr(T_i8())), filename, line], + [PointerCast(bcx, llval, Type::i8p()), filename, line], expr::Ignore) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 4fc431e0a54..bbf548d2659 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use driver::session; use metadata::csearch; @@ -21,22 +20,22 @@ use middle::ty; use middle::subst::Subst; use middle::typeck; use middle; -use util::ppaux::{note_and_explain_region, bound_region_to_str}; +use util::ppaux::{note_and_explain_region, bound_region_ptr_to_str}; use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str}; use util::ppaux::{Repr, UserString}; use util::common::{indenter}; use util::enum_set::{EnumSet, CLike}; -use core::cast; -use core::cmp; -use core::hashmap::{HashMap, HashSet}; -use core::iter; -use core::ops; -use core::ptr::to_unsafe_ptr; -use core::to_bytes; -use core::u32; -use core::uint; -use core::vec; +use std::cast; +use std::cmp; +use std::hashmap::{HashMap, HashSet}; +use std::iter; +use std::ops; +use std::ptr::to_unsafe_ptr; +use std::to_bytes; +use std::u32; +use std::uint; +use std::vec; use syntax::ast::*; use syntax::ast_util::is_local; use syntax::ast_util; @@ -44,7 +43,6 @@ use syntax::attr; use syntax::codemap::span; use syntax::codemap; use syntax::parse::token; -use syntax::parse::token::special_idents; use syntax::{ast, ast_map}; use syntax::opt_vec::OptVec; use syntax::opt_vec; @@ -53,7 +51,7 @@ use syntax; // Data types -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct field { ident: ast::ident, mt: mt @@ -97,13 +95,13 @@ impl Method { } } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct mt { ty: t, mutbl: ast::mutability, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable, IterBytes)] pub enum vstore { vstore_fixed(uint), vstore_uniq, @@ -134,7 +132,7 @@ pub struct field_ty { // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct creader_cache_key { cnum: int, pos: uint, @@ -143,14 +141,6 @@ pub struct creader_cache_key { type creader_cache = @mut HashMap<creader_cache_key, t>; -impl to_bytes::IterBytes for creader_cache_key { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.cnum.iter_bytes(lsb0, f) && - self.pos.iter_bytes(lsb0, f) && - self.len.iter_bytes(lsb0, f) - } -} - struct intern_key { sty: *sty, } @@ -169,6 +159,8 @@ impl cmp::Eq for intern_key { } } +// NB: Do not replace this with #[deriving(IterBytes)], as above. (Figured +// this out the hard way.) impl to_bytes::IterBytes for intern_key { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { unsafe { @@ -276,8 +268,7 @@ struct ctxt_ { trait_defs: @mut HashMap<def_id, @TraitDef>, items: ast_map::map, - intrinsic_defs: @mut HashMap<ast::ident, (ast::def_id, t)>, - intrinsic_traits: @mut HashMap<ast::ident, @TraitRef>, + intrinsic_defs: @mut HashMap<ast::def_id, t>, freevars: freevars::freevar_map, tcache: type_cache, rcache: creader_cache, @@ -374,14 +365,14 @@ pub fn type_has_regions(t: t) -> bool { } pub fn type_id(t: t) -> uint { get(t).id } -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct BareFnTy { purity: ast::purity, abis: AbiSet, sig: FnSig } -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct ClosureTy { purity: ast::purity, sigil: ast::Sigil, @@ -398,31 +389,13 @@ pub struct ClosureTy { * - `lifetimes` is the list of region names bound in this fn. * - `inputs` is the list of arguments and their modes. * - `output` is the return type. */ -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct FnSig { bound_lifetime_names: OptVec<ast::ident>, inputs: ~[t], output: t } -impl to_bytes::IterBytes for BareFnTy { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.purity.iter_bytes(lsb0, f) && - self.abis.iter_bytes(lsb0, f) && - self.sig.iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for ClosureTy { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.purity.iter_bytes(lsb0, f) && - self.sigil.iter_bytes(lsb0, f) && - self.onceness.iter_bytes(lsb0, f) && - self.region.iter_bytes(lsb0, f) && - self.sig.iter_bytes(lsb0, f) - } -} - #[deriving(Eq, IterBytes)] pub struct param_ty { idx: uint, @@ -527,7 +500,7 @@ type opt_region = Option<Region>; * - `self_ty` is the type to which `self` should be remapped, if any. The * `self` type is rather funny in that it can only appear on traits and is * always substituted away to the implementing type for a trait. */ -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct substs { self_r: opt_region, self_ty: Option<ty::t>, @@ -583,7 +556,7 @@ mod primitives { // NB: If you change this, you'll probably want to change the corresponding // AST structure in libsyntax/ast.rs as well. -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub enum sty { ty_nil, ty_bot, @@ -600,7 +573,7 @@ pub enum sty { ty_rptr(Region, mt), ty_bare_fn(BareFnTy), ty_closure(ClosureTy), - ty_trait(def_id, substs, TraitStore, ast::mutability), + ty_trait(def_id, substs, TraitStore, ast::mutability, BuiltinBounds), ty_struct(def_id, substs), ty_tup(~[t]), @@ -687,8 +660,8 @@ pub type BuiltinBounds = EnumSet<BuiltinBound>; pub enum BuiltinBound { BoundCopy, BoundStatic, - BoundOwned, - BoundConst, + BoundSend, + BoundFreeze, BoundSized, } @@ -700,8 +673,8 @@ pub fn AllBuiltinBounds() -> BuiltinBounds { let mut set = EnumSet::empty(); set.add(BoundCopy); set.add(BoundStatic); - set.add(BoundOwned); - set.add(BoundConst); + set.add(BoundSend); + set.add(BoundFreeze); set.add(BoundSized); set } @@ -715,62 +688,33 @@ impl CLike for BuiltinBound { } } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct TyVid(uint); -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct IntVid(uint); -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct FloatVid(uint); -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable, IterBytes)] pub struct RegionVid { id: uint } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub enum InferTy { TyVar(TyVid), IntVar(IntVid), FloatVar(FloatVid) } -impl to_bytes::IterBytes for InferTy { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - TyVar(ref tv) => { - 0u8.iter_bytes(lsb0, f) && tv.iter_bytes(lsb0, f) - } - IntVar(ref iv) => { - 1u8.iter_bytes(lsb0, f) && iv.iter_bytes(lsb0, f) - } - FloatVar(ref fv) => { - 2u8.iter_bytes(lsb0, f) && fv.iter_bytes(lsb0, f) - } - } - } -} - -#[deriving(Encodable, Decodable)] +#[deriving(Encodable, Decodable, IterBytes)] pub enum InferRegion { ReVar(RegionVid), ReSkolemized(uint, bound_region) } -impl to_bytes::IterBytes for InferRegion { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - ReVar(ref rv) => { - 0u8.iter_bytes(lsb0, f) && rv.iter_bytes(lsb0, f) - } - ReSkolemized(ref v, _) => { - 1u8.iter_bytes(lsb0, f) && v.iter_bytes(lsb0, f) - } - } - } -} - impl cmp::Eq for InferRegion { fn eq(&self, other: &InferRegion) -> bool { match ((*self), *other) { @@ -850,30 +794,6 @@ impl ToStr for IntVarValue { } } -impl to_bytes::IterBytes for TyVid { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.to_uint().iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for IntVid { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.to_uint().iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for FloatVid { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.to_uint().iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for RegionVid { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.to_uint().iter_bytes(lsb0, f) - } -} - pub struct TypeParameterDef { def_id: ast::def_id, bounds: @ParamBounds @@ -953,7 +873,6 @@ pub fn mk_ctxt(s: session::Session, node_type_substs: @mut HashMap::new(), trait_refs: @mut HashMap::new(), trait_defs: @mut HashMap::new(), - intrinsic_traits: @mut HashMap::new(), items: amap, intrinsic_defs: @mut HashMap::new(), freevars: freevars, @@ -1018,7 +937,7 @@ fn mk_t(cx: ctxt, st: sty) -> t { } fn sflags(substs: &substs) -> uint { let mut f = 0u; - for substs.tps.each |tt| { f |= get(*tt).flags; } + for substs.tps.iter().advance |tt| { f |= get(*tt).flags; } for substs.self_r.iter().advance |r| { f |= rflags(*r) } return f; } @@ -1046,7 +965,7 @@ fn mk_t(cx: ctxt, st: sty) -> t { &ty_infer(_) => flags |= needs_infer as uint, &ty_self(_) => flags |= has_self as uint, &ty_enum(_, ref substs) | &ty_struct(_, ref substs) | - &ty_trait(_, ref substs, _, _) => { + &ty_trait(_, ref substs, _, _, _) => { flags |= sflags(substs); } &ty_box(ref m) | &ty_uniq(ref m) | &ty_evec(ref m, _) | @@ -1057,16 +976,16 @@ fn mk_t(cx: ctxt, st: sty) -> t { flags |= rflags(r); flags |= get(m.ty).flags; } - &ty_tup(ref ts) => for ts.each |tt| { flags |= get(*tt).flags; }, + &ty_tup(ref ts) => for ts.iter().advance |tt| { flags |= get(*tt).flags; }, &ty_bare_fn(ref f) => { - for f.sig.inputs.each |a| { flags |= get(*a).flags; } + for f.sig.inputs.iter().advance |a| { flags |= get(*a).flags; } flags |= get(f.sig.output).flags; // T -> _|_ is *not* _|_ ! flags &= !(has_ty_bot as uint); } &ty_closure(ref f) => { flags |= rflags(f.region); - for f.sig.inputs.each |a| { flags |= get(*a).flags; } + for f.sig.inputs.iter().advance |a| { flags |= get(*a).flags; } flags |= get(f.sig.output).flags; // T -> _|_ is *not* _|_ ! flags &= !(has_ty_bot as uint); @@ -1253,7 +1172,7 @@ pub fn mk_ctor_fn(cx: ctxt, input_tys: &[ty::t], output: ty::t) -> t { let input_args = input_tys.map(|t| *t); mk_bare_fn(cx, BareFnTy { - purity: ast::pure_fn, + purity: ast::impure_fn, abis: AbiSet::Rust(), sig: FnSig { bound_lifetime_names: opt_vec::Empty, @@ -1268,10 +1187,11 @@ pub fn mk_trait(cx: ctxt, did: ast::def_id, substs: substs, store: TraitStore, - mutability: ast::mutability) + mutability: ast::mutability, + bounds: BuiltinBounds) -> t { // take a copy of substs so that we own the vectors inside - mk_t(cx, ty_trait(did, substs, store, mutability)) + mk_t(cx, ty_trait(did, substs, store, mutability, bounds)) } pub fn mk_struct(cx: ctxt, struct_id: ast::def_id, substs: substs) -> t { @@ -1319,16 +1239,16 @@ pub fn maybe_walk_ty(ty: t, f: &fn(t) -> bool) { maybe_walk_ty(tm.ty, f); } ty_enum(_, ref substs) | ty_struct(_, ref substs) | - ty_trait(_, ref substs, _, _) => { - for (*substs).tps.each |subty| { maybe_walk_ty(*subty, f); } + ty_trait(_, ref substs, _, _, _) => { + for (*substs).tps.iter().advance |subty| { maybe_walk_ty(*subty, |x| f(x)); } } - ty_tup(ref ts) => { for ts.each |tt| { maybe_walk_ty(*tt, f); } } + ty_tup(ref ts) => { for ts.iter().advance |tt| { maybe_walk_ty(*tt, |x| f(x)); } } ty_bare_fn(ref ft) => { - for ft.sig.inputs.each |a| { maybe_walk_ty(*a, f); } + for ft.sig.inputs.iter().advance |a| { maybe_walk_ty(*a, |x| f(x)); } maybe_walk_ty(ft.sig.output, f); } ty_closure(ref ft) => { - for ft.sig.inputs.each |a| { maybe_walk_ty(*a, f); } + for ft.sig.inputs.iter().advance |a| { maybe_walk_ty(*a, |x| f(x)); } maybe_walk_ty(ft.sig.output, f); } } @@ -1380,8 +1300,8 @@ fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty { ty_enum(tid, ref substs) => { ty_enum(tid, fold_substs(substs, fldop)) } - ty_trait(did, ref substs, st, mutbl) => { - ty_trait(did, fold_substs(substs, fldop), st, mutbl) + ty_trait(did, ref substs, st, mutbl, bounds) => { + ty_trait(did, fold_substs(substs, fldop), st, mutbl, bounds) } ty_tup(ref ts) => { let new_ts = ts.map(|tt| fldop(*tt)); @@ -1410,7 +1330,7 @@ fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty { // Folds types from the bottom up. pub fn fold_ty(cx: ctxt, t0: t, fldop: &fn(t) -> t) -> t { - let sty = fold_sty(&get(t0).sty, |t| fold_ty(cx, fldop(t), fldop)); + let sty = fold_sty(&get(t0).sty, |t| fold_ty(cx, fldop(t), |t| fldop(t))); fldop(mk_t(cx, sty)) } @@ -1424,8 +1344,8 @@ pub fn walk_regions_and_ty( fold_regions_and_ty( cx, ty, |r| { walkr(r); r }, - |t| { walk_regions_and_ty(cx, t, walkr, walkt); t }, - |t| { walk_regions_and_ty(cx, t, walkr, walkt); t }); + |t| { walk_regions_and_ty(cx, t, |r| walkr(r), |t| walkt(t)); t }, + |t| { walk_regions_and_ty(cx, t, |r| walkr(r), |t| walkt(t)); t }); } } @@ -1470,8 +1390,12 @@ pub fn fold_regions_and_ty( ty_struct(def_id, ref substs) => { ty::mk_struct(cx, def_id, fold_substs(substs, fldr, fldt)) } - ty_trait(def_id, ref substs, st, mutbl) => { - ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl) + ty_trait(def_id, ref substs, st, mutbl, bounds) => { + let st = match st { + RegionTraitStore(region) => RegionTraitStore(fldr(region)), + st => st, + }; + ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), st, mutbl, bounds) } ty_bare_fn(ref f) => { ty::mk_bare_fn(cx, BareFnTy {sig: fold_sig(&f.sig, fldfnt), @@ -1501,8 +1425,8 @@ pub fn fold_regions( fold_regions_and_ty( cx, ty, |r| fldr(r, in_fn), - |t| do_fold(cx, t, true, fldr), - |t| do_fold(cx, t, in_fn, fldr)) + |t| do_fold(cx, t, true, |r,b| fldr(r,b)), + |t| do_fold(cx, t, in_fn, |r,b| fldr(r,b))) } do_fold(cx, ty, false, fldr) } @@ -1772,8 +1696,8 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t, true } ty_enum(did, ref substs) => { - for (*enum_variants(cx, did)).each |v| { - for v.args.each |aty| { + for (*enum_variants(cx, did)).iter().advance |v| { + for v.args.iter().advance |aty| { let t = subst(cx, substs, *aty); needs_unwind_cleanup |= type_needs_unwind_cleanup_(cx, t, tycache, @@ -1835,8 +1759,8 @@ impl TypeContents { match bb { BoundCopy => self.is_copy(cx), BoundStatic => self.is_static(cx), - BoundConst => self.is_const(cx), - BoundOwned => self.is_owned(cx), + BoundFreeze => self.is_freezable(cx), + BoundSend => self.is_sendable(cx), BoundSized => self.is_sized(cx), } } @@ -1850,7 +1774,7 @@ impl TypeContents { } pub fn noncopyable(_cx: ctxt) -> TypeContents { - TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_OWNED_CLOSURE + + TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_NONCOPY_TRAIT + TC_EMPTY_ENUM } @@ -1862,23 +1786,23 @@ impl TypeContents { TC_BORROWED_POINTER } - pub fn is_owned(&self, cx: ctxt) -> bool { - !self.intersects(TypeContents::nonowned(cx)) + pub fn is_sendable(&self, cx: ctxt) -> bool { + !self.intersects(TypeContents::nonsendable(cx)) } - pub fn nonowned(_cx: ctxt) -> TypeContents { - TC_MANAGED + TC_BORROWED_POINTER + TC_NON_OWNED + pub fn nonsendable(_cx: ctxt) -> TypeContents { + TC_MANAGED + TC_BORROWED_POINTER + TC_NON_SENDABLE } pub fn contains_managed(&self) -> bool { self.intersects(TC_MANAGED) } - pub fn is_const(&self, cx: ctxt) -> bool { - !self.intersects(TypeContents::nonconst(cx)) + pub fn is_freezable(&self, cx: ctxt) -> bool { + !self.intersects(TypeContents::nonfreezable(cx)) } - pub fn nonconst(_cx: ctxt) -> TypeContents { + pub fn nonfreezable(_cx: ctxt) -> TypeContents { TC_MUTABLE } @@ -1899,13 +1823,21 @@ impl TypeContents { } pub fn needs_drop(&self, cx: ctxt) -> bool { - let tc = TC_MANAGED + TC_DTOR + TypeContents::owned(cx); + if self.intersects(TC_NONCOPY_TRAIT) { + // Currently all noncopyable existentials are 2nd-class types + // behind owned pointers. With dynamically-sized types, remove + // this assertion. + assert!(self.intersects(TC_OWNED_POINTER) || + // (...or stack closures without a copy bound.) + self.intersects(TC_BORROWED_POINTER)); + } + let tc = TC_MANAGED + TC_DTOR + TypeContents::sendable(cx); self.intersects(tc) } - pub fn owned(_cx: ctxt) -> TypeContents { - //! Any kind of owned contents. - TC_OWNED_CLOSURE + TC_OWNED_POINTER + TC_OWNED_VEC + pub fn sendable(_cx: ctxt) -> TypeContents { + //! Any kind of sendable contents. + TC_OWNED_POINTER + TC_OWNED_VEC } } @@ -1939,8 +1871,8 @@ static TC_OWNED_POINTER: TypeContents = TypeContents{bits: 0b0000_0000_0010}; /// Contains an owned vector ~[] or owned string ~str static TC_OWNED_VEC: TypeContents = TypeContents{bits: 0b0000_0000_0100}; -/// Contains a ~fn() or a ~Trait, which is non-copyable. -static TC_OWNED_CLOSURE: TypeContents = TypeContents{bits: 0b0000_0000_1000}; +/// Contains a non-copyable ~fn() or a ~Trait (NOT a ~fn:Copy() or ~Trait:Copy). +static TC_NONCOPY_TRAIT: TypeContents = TypeContents{bits: 0b0000_0000_1000}; /// Type with a destructor static TC_DTOR: TypeContents = TypeContents{bits: 0b0000_0001_0000}; @@ -1960,8 +1892,8 @@ static TC_ONCE_CLOSURE: TypeContents = TypeContents{bits: 0b0001_0000_0000}; /// An enum with no variants. static TC_EMPTY_ENUM: TypeContents = TypeContents{bits: 0b0010_0000_0000}; -/// Contains a type marked with `#[non_owned]` -static TC_NON_OWNED: TypeContents = TypeContents{bits: 0b0100_0000_0000}; +/// Contains a type marked with `#[no_send]` +static TC_NON_SENDABLE: TypeContents = TypeContents{bits: 0b0100_0000_0000}; /// Is a bare vector, str, function, trait, etc (only relevant at top level). static TC_DYNAMIC_SIZE: TypeContents = TypeContents{bits: 0b1000_0000_0000}; @@ -1977,12 +1909,12 @@ pub fn type_is_static(cx: ctxt, t: ty::t) -> bool { type_contents(cx, t).is_static(cx) } -pub fn type_is_owned(cx: ctxt, t: ty::t) -> bool { - type_contents(cx, t).is_owned(cx) +pub fn type_is_sendable(cx: ctxt, t: ty::t) -> bool { + type_contents(cx, t).is_sendable(cx) } -pub fn type_is_const(cx: ctxt, t: ty::t) -> bool { - type_contents(cx, t).is_const(cx) +pub fn type_is_freezable(cx: ctxt, t: ty::t) -> bool { + type_contents(cx, t).is_freezable(cx) } pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { @@ -2036,7 +1968,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { let _i = indenter(); let result = match get(ty).sty { - // Scalar and unique types are sendable, constant, and owned + // Scalar and unique types are sendable, freezable, and durable ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(_) | ty_ptr(_) => { TC_NONE @@ -2051,27 +1983,17 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } ty_box(mt) => { - TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache))) + TC_MANAGED + + statically_sized(nonsendable(tc_mt(cx, mt, cache))) } - ty_trait(_, _, UniqTraitStore, _) => { - TC_OWNED_CLOSURE - } - - ty_trait(_, _, BoxTraitStore, mutbl) => { - match mutbl { - ast::m_mutbl => TC_MANAGED + TC_MUTABLE, - _ => TC_MANAGED - } - } - - ty_trait(_, _, RegionTraitStore(r), mutbl) => { - borrowed_contents(r, mutbl) + ty_trait(_, _, store, mutbl, bounds) => { + trait_contents(store, mutbl, bounds) } ty_rptr(r, mt) => { borrowed_contents(r, mt.mutbl) + - statically_sized(nonowned(tc_mt(cx, mt, cache))) + statically_sized(nonsendable(tc_mt(cx, mt, cache))) } ty_uniq(mt) => { @@ -2083,12 +2005,13 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } ty_evec(mt, vstore_box) => { - TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache))) + TC_MANAGED + + statically_sized(nonsendable(tc_mt(cx, mt, cache))) } ty_evec(mt, vstore_slice(r)) => { borrowed_contents(r, mt.mutbl) + - statically_sized(nonowned(tc_mt(cx, mt, cache))) + statically_sized(nonsendable(tc_mt(cx, mt, cache))) } ty_evec(mt, vstore_fixed(_)) => { @@ -2116,17 +2039,17 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { ty_struct(did, ref substs) => { let flds = struct_fields(cx, did, substs); - let mut res = flds.foldl( + let mut res = flds.iter().fold( TC_NONE, |tc, f| tc + tc_mt(cx, f.mt, cache)); if ty::has_dtor(cx, did) { - res += TC_DTOR; + res = res + TC_DTOR; } apply_tc_attr(cx, did, res) } ty_tup(ref tys) => { - tys.foldl(TC_NONE, |tc, ty| *tc + tc_ty(cx, *ty, cache)) + tys.iter().fold(TC_NONE, |tc, ty| tc + tc_ty(cx, *ty, cache)) } ty_enum(did, ref substs) => { @@ -2136,10 +2059,9 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { // are non-copyable TC_EMPTY_ENUM } else { - variants.foldl(TC_NONE, |tc, variant| { - variant.args.foldl( - *tc, - |tc, arg_ty| *tc + tc_ty(cx, *arg_ty, cache)) + variants.iter().fold(TC_NONE, |tc, variant| { + variant.args.iter().fold(tc, + |tc, arg_ty| tc + tc_ty(cx, *arg_ty, cache)) }) }; apply_tc_attr(cx, did, res) @@ -2179,7 +2101,9 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { match sigil { ast::BorrowedSigil => TC_BORROWED_POINTER, ast::ManagedSigil => TC_MANAGED, - ast::OwnedSigil => TC_OWNED_CLOSURE + // FIXME(#3569): Looks like noncopyability should depend + // on the bounds, but I don't think this case ever comes up. + ast::OwnedSigil => TC_NONCOPY_TRAIT + TC_OWNED_POINTER, } } @@ -2203,11 +2127,11 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } fn apply_tc_attr(cx: ctxt, did: def_id, mut tc: TypeContents) -> TypeContents { - if has_attr(cx, did, "mutable") { - tc += TC_MUTABLE; + if has_attr(cx, did, "no_freeze") { + tc = tc + TC_MUTABLE; } - if has_attr(cx, did, "non_owned") { - tc += TC_NON_OWNED; + if has_attr(cx, did, "no_send") { + tc = tc + TC_NON_SENDABLE; } tc } @@ -2228,7 +2152,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { mc + rc } - fn nonowned(pointee: TypeContents) -> TypeContents { + fn nonsendable(pointee: TypeContents) -> TypeContents { /*! * * Given a non-owning pointer to some type `T` with @@ -2250,17 +2174,64 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } fn closure_contents(cty: &ClosureTy) -> TypeContents { + // Closure contents are just like trait contents, but with potentially + // even more stuff. let st = match cty.sigil { - ast::BorrowedSigil => TC_BORROWED_POINTER, - ast::ManagedSigil => TC_MANAGED, - ast::OwnedSigil => TC_OWNED_CLOSURE + ast::BorrowedSigil => + trait_contents(RegionTraitStore(cty.region), m_imm, cty.bounds) + + TC_BORROWED_POINTER, // might be an env packet even if static + ast::ManagedSigil => + trait_contents(BoxTraitStore, m_imm, cty.bounds), + ast::OwnedSigil => + trait_contents(UniqTraitStore, m_imm, cty.bounds), }; + // FIXME(#3569): This borrowed_contents call should be taken care of in + // trait_contents, after ~Traits and @Traits can have region bounds too. + // This one here is redundant for &fns but important for ~fns and @fns. let rt = borrowed_contents(cty.region, m_imm); + // This also prohibits "@once fn" from being copied, which allows it to + // be called. Neither way really makes much sense. let ot = match cty.onceness { ast::Once => TC_ONCE_CLOSURE, ast::Many => TC_NONE }; - st + rt + ot + // Prevent noncopyable types captured in the environment from being copied. + let ct = if cty.bounds.contains_elem(BoundCopy) || + cty.sigil == ast::ManagedSigil { + TC_NONE + } else { + TC_NONCOPY_TRAIT + }; + st + rt + ot + ct + } + + fn trait_contents(store: TraitStore, mutbl: ast::mutability, + bounds: BuiltinBounds) -> TypeContents { + let st = match store { + UniqTraitStore => TC_OWNED_POINTER, + BoxTraitStore => TC_MANAGED, + RegionTraitStore(r) => borrowed_contents(r, mutbl), + }; + let mt = match mutbl { ast::m_mutbl => TC_MUTABLE, _ => TC_NONE }; + // We get additional "special type contents" for each bound that *isn't* + // on the trait. So iterate over the inverse of the bounds that are set. + // This is like with typarams below, but less "pessimistic" and also + // dependent on the trait store. + let mut bt = TC_NONE; + for (AllBuiltinBounds() - bounds).each |bound| { + bt = bt + match bound { + BoundCopy if store == UniqTraitStore + => TC_NONCOPY_TRAIT, + BoundCopy => TC_NONE, // @Trait/&Trait are copyable either way + BoundStatic if bounds.contains_elem(BoundSend) + => TC_NONE, // Send bound implies static bound. + BoundStatic => TC_BORROWED_POINTER, // Useful for "@Trait:'static" + BoundSend => TC_NON_SENDABLE, + BoundFreeze => TC_MUTABLE, + BoundSized => TC_NONE, // don't care if interior is sized + }; + } + st + mt + bt } fn type_param_def_to_contents(cx: ctxt, @@ -2275,8 +2246,8 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { tc = tc - match bound { BoundCopy => TypeContents::noncopyable(cx), BoundStatic => TypeContents::nonstatic(cx), - BoundOwned => TypeContents::nonowned(cx), - BoundConst => TypeContents::nonconst(cx), + BoundSend => TypeContents::nonsendable(cx), + BoundFreeze => TypeContents::nonfreezable(cx), // The dynamic-size bit can be removed at pointer-level, etc. BoundSized => TypeContents::dynamically_sized(cx), }; @@ -2348,11 +2319,11 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool { false // unsafe ptrs can always be NULL } - ty_trait(_, _, _, _) => { + ty_trait(_, _, _, _, _) => { false } - ty_struct(ref did, _) if vec::contains(*seen, did) => { + ty_struct(ref did, _) if seen.contains(did) => { false } @@ -2365,10 +2336,10 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool { } ty_tup(ref ts) => { - ts.any(|t| type_requires(cx, seen, r_ty, *t)) + ts.iter().any_(|t| type_requires(cx, seen, r_ty, *t)) } - ty_enum(ref did, _) if vec::contains(*seen, did) => { + ty_enum(ref did, _) if seen.contains(did) => { false } @@ -2408,25 +2379,26 @@ pub fn type_structurally_contains(cx: ctxt, if test(sty) { return true; } match *sty { ty_enum(did, ref substs) => { - for (*enum_variants(cx, did)).each |variant| { - for variant.args.each |aty| { + for (*enum_variants(cx, did)).iter().advance |variant| { + for variant.args.iter().advance |aty| { let sty = subst(cx, substs, *aty); - if type_structurally_contains(cx, sty, test) { return true; } + if type_structurally_contains(cx, sty, |x| test(x)) { return true; } } } return false; } ty_struct(did, ref substs) => { - for lookup_struct_fields(cx, did).each |field| { + let r = lookup_struct_fields(cx, did); + for r.iter().advance |field| { let ft = lookup_field_type(cx, did, field.id, substs); - if type_structurally_contains(cx, ft, test) { return true; } + if type_structurally_contains(cx, ft, |x| test(x)) { return true; } } return false; } ty_tup(ref ts) => { - for ts.each |tt| { - if type_structurally_contains(cx, *tt, test) { return true; } + for ts.iter().advance |tt| { + if type_structurally_contains(cx, *tt, |x| test(x)) { return true; } } return false; } @@ -2500,11 +2472,11 @@ pub fn type_is_pod(cx: ctxt, ty: t) -> bool { ty_box(_) | ty_uniq(_) | ty_closure(_) | ty_estr(vstore_uniq) | ty_estr(vstore_box) | ty_evec(_, vstore_uniq) | ty_evec(_, vstore_box) | - ty_trait(_, _, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false, + ty_trait(_, _, _, _, _) | ty_rptr(_,_) | ty_opaque_box => result = false, // Structural types ty_enum(did, ref substs) => { let variants = enum_variants(cx, did); - for (*variants).each |variant| { + for (*variants).iter().advance |variant| { let tup_ty = mk_tup(cx, /*bad*/copy variant.args); // Perform any type parameter substitutions. @@ -2513,7 +2485,7 @@ pub fn type_is_pod(cx: ctxt, ty: t) -> bool { } } ty_tup(ref elts) => { - for elts.each |elt| { if !type_is_pod(cx, *elt) { result = false; } } + for elts.iter().advance |elt| { if !type_is_pod(cx, *elt) { result = false; } } } ty_estr(vstore_fixed(_)) => result = true, ty_evec(ref mt, vstore_fixed(_)) | ty_unboxed_vec(ref mt) => { @@ -2702,122 +2674,6 @@ impl cmp::TotalEq for bound_region { } } -impl to_bytes::IterBytes for vstore { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - vstore_fixed(ref u) => { - 0u8.iter_bytes(lsb0, f) && u.iter_bytes(lsb0, f) - } - vstore_uniq => 1u8.iter_bytes(lsb0, f), - vstore_box => 2u8.iter_bytes(lsb0, f), - - vstore_slice(ref r) => { - 3u8.iter_bytes(lsb0, f) && r.iter_bytes(lsb0, f) - } - } - } -} - -impl to_bytes::IterBytes for substs { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.self_r.iter_bytes(lsb0, f) && - self.self_ty.iter_bytes(lsb0, f) && - self.tps.iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for mt { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.ty.iter_bytes(lsb0, f) && self.mutbl.iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for field { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.ident.iter_bytes(lsb0, f) && self.mt.iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for FnSig { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.inputs.iter_bytes(lsb0, f) && self.output.iter_bytes(lsb0, f) - } -} - -impl to_bytes::IterBytes for sty { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - ty_nil => 0u8.iter_bytes(lsb0, f), - ty_bool => 1u8.iter_bytes(lsb0, f), - - ty_int(ref t) => 2u8.iter_bytes(lsb0, f) && t.iter_bytes(lsb0, f), - - ty_uint(ref t) => 3u8.iter_bytes(lsb0, f) && t.iter_bytes(lsb0, f), - - ty_float(ref t) => 4u8.iter_bytes(lsb0, f) && t.iter_bytes(lsb0, f), - - ty_estr(ref v) => 5u8.iter_bytes(lsb0, f) && v.iter_bytes(lsb0, f), - - ty_enum(ref did, ref substs) => { - 6u8.iter_bytes(lsb0, f) && - did.iter_bytes(lsb0, f) && - substs.iter_bytes(lsb0, f) - } - - ty_box(ref mt) => 7u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f), - - ty_evec(ref mt, ref v) => { - 8u8.iter_bytes(lsb0, f) && - mt.iter_bytes(lsb0, f) && - v.iter_bytes(lsb0, f) - } - - ty_unboxed_vec(ref mt) => 9u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f), - - ty_tup(ref ts) => 10u8.iter_bytes(lsb0, f) && ts.iter_bytes(lsb0, f), - - ty_bare_fn(ref ft) => 12u8.iter_bytes(lsb0, f) && ft.iter_bytes(lsb0, f), - - ty_self(ref did) => 13u8.iter_bytes(lsb0, f) && did.iter_bytes(lsb0, f), - - ty_infer(ref v) => 14u8.iter_bytes(lsb0, f) && v.iter_bytes(lsb0, f), - - ty_param(ref p) => 15u8.iter_bytes(lsb0, f) && p.iter_bytes(lsb0, f), - - ty_type => 16u8.iter_bytes(lsb0, f), - ty_bot => 17u8.iter_bytes(lsb0, f), - - ty_ptr(ref mt) => 18u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f), - - ty_uniq(ref mt) => 19u8.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f), - - ty_trait(ref did, ref substs, ref v, ref mutbl) => { - 20u8.iter_bytes(lsb0, f) && - did.iter_bytes(lsb0, f) && - substs.iter_bytes(lsb0, f) && - v.iter_bytes(lsb0, f) && - mutbl.iter_bytes(lsb0, f) - } - - ty_opaque_closure_ptr(ref ck) => 21u8.iter_bytes(lsb0, f) && ck.iter_bytes(lsb0, f), - - ty_opaque_box => 22u8.iter_bytes(lsb0, f), - - ty_struct(ref did, ref substs) => { - 23u8.iter_bytes(lsb0, f) && did.iter_bytes(lsb0, f) && substs.iter_bytes(lsb0, f) - } - - ty_rptr(ref r, ref mt) => { - 24u8.iter_bytes(lsb0, f) && r.iter_bytes(lsb0, f) && mt.iter_bytes(lsb0, f) - } - - ty_err => 25u8.iter_bytes(lsb0, f), - - ty_closure(ref ct) => 26u8.iter_bytes(lsb0, f) && ct.iter_bytes(lsb0, f), - } - } -} - pub fn node_id_to_trait_ref(cx: ctxt, id: ast::node_id) -> @ty::TraitRef { match cx.trait_refs.find(&id) { Some(&t) => t, @@ -2976,7 +2832,7 @@ pub fn block_ty(cx: ctxt, b: &ast::blk) -> t { // Returns the type of a pattern as a monotype. Like @expr_ty, this function // doesn't provide type parameter substitutions. -pub fn pat_ty(cx: ctxt, pat: @ast::pat) -> t { +pub fn pat_ty(cx: ctxt, pat: &ast::pat) -> t { return node_id_to_type(cx, pat.id); } @@ -2992,11 +2848,11 @@ pub fn pat_ty(cx: ctxt, pat: @ast::pat) -> t { // ask for the type of "id" in "id(3)", it will return "fn(&int) -> int" // instead of "fn(t) -> T with T = int". If this isn't what you want, see // expr_ty_params_and_ty() below. -pub fn expr_ty(cx: ctxt, expr: @ast::expr) -> t { +pub fn expr_ty(cx: ctxt, expr: &ast::expr) -> t { return node_id_to_type(cx, expr.id); } -pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t { +pub fn expr_ty_adjusted(cx: ctxt, expr: &ast::expr) -> t { /*! * * Returns the type of `expr`, considering any `AutoAdjustment` @@ -3150,7 +3006,7 @@ pub struct ParamsTy { } pub fn expr_ty_params_and_ty(cx: ctxt, - expr: @ast::expr) + expr: &ast::expr) -> ParamsTy { ParamsTy { params: node_id_to_type_params(cx, expr.id), @@ -3158,7 +3014,7 @@ pub fn expr_ty_params_and_ty(cx: ctxt, } } -pub fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool { +pub fn expr_has_ty_params(cx: ctxt, expr: &ast::expr) -> bool { return node_id_has_type_params(cx, expr.id); } @@ -3194,7 +3050,7 @@ pub fn method_call_type_param_defs( } } -pub fn resolve_expr(tcx: ctxt, expr: @ast::expr) -> ast::def { +pub fn resolve_expr(tcx: ctxt, expr: &ast::expr) -> ast::def { match tcx.def_map.find(&expr.id) { Some(&def) => def, None => { @@ -3206,7 +3062,7 @@ pub fn resolve_expr(tcx: ctxt, expr: @ast::expr) -> ast::def { pub fn expr_is_lval(tcx: ctxt, method_map: typeck::method_map, - e: @ast::expr) -> bool { + e: &ast::expr) -> bool { match expr_kind(tcx, method_map, e) { LvalueExpr => true, RvalueDpsExpr | RvalueDatumExpr | RvalueStmtExpr => false @@ -3227,7 +3083,7 @@ pub enum ExprKind { pub fn expr_kind(tcx: ctxt, method_map: typeck::method_map, - expr: @ast::expr) -> ExprKind { + expr: &ast::expr) -> ExprKind { if method_map.contains_key(&expr.id) { // Overloaded operations are generally calls, and hence they are // generated via DPS. However, assign_op (e.g., `x += y`) is an @@ -3249,7 +3105,7 @@ pub fn expr_kind(tcx: ctxt, // Note: there is actually a good case to be made that // def_args, particularly those of immediate type, ought to // considered rvalues. - ast::def_const(*) | + ast::def_static(*) | ast::def_binding(*) | ast::def_upvar(*) | ast::def_arg(*) | @@ -3347,7 +3203,7 @@ pub fn expr_kind(tcx: ctxt, } } -pub fn stmt_node_id(s: @ast::stmt) -> ast::node_id { +pub fn stmt_node_id(s: &ast::stmt) -> ast::node_id { match s.node { ast::stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) => { return id; @@ -3358,14 +3214,14 @@ pub fn stmt_node_id(s: @ast::stmt) -> ast::node_id { pub fn field_idx(id: ast::ident, fields: &[field]) -> Option<uint> { let mut i = 0u; - for fields.each |f| { if f.ident == id { return Some(i); } i += 1u; } + for fields.iter().advance |f| { if f.ident == id { return Some(i); } i += 1u; } return None; } pub fn field_idx_strict(tcx: ty::ctxt, id: ast::ident, fields: &[field]) -> uint { let mut i = 0u; - for fields.each |f| { if f.ident == id { return i; } i += 1u; } + for fields.iter().advance |f| { if f.ident == id { return i; } i += 1u; } tcx.sess.bug(fmt!( "No field named `%s` found in the list of fields `%?`", tcx.sess.str_of(id), @@ -3373,7 +3229,7 @@ pub fn field_idx_strict(tcx: ty::ctxt, id: ast::ident, fields: &[field]) } pub fn method_idx(id: ast::ident, meths: &[@Method]) -> Option<uint> { - vec::position(meths, |m| m.ident == id) + meths.iter().position_(|m| m.ident == id) } /// Returns a vector containing the indices of all type parameters that appear @@ -3410,7 +3266,7 @@ pub fn occurs_check(tcx: ctxt, sp: span, vid: TyVid, rt: t) { if !type_needs_infer(rt) { return; } // Occurs check! - if vec::contains(vars_in_type(rt), &vid) { + if vars_in_type(rt).contains(&vid) { // Maybe this should be span_err -- however, there's an // assertion later on that the type doesn't contain // variables, so in this case we have to be sure to die. @@ -3440,7 +3296,7 @@ pub fn ty_sort_str(cx: ctxt, t: t) -> ~str { ty_rptr(_, _) => ~"&-ptr", ty_bare_fn(_) => ~"extern fn", ty_closure(_) => ~"fn", - ty_trait(id, _, _, _) => fmt!("trait %s", item_path_str(cx, id)), + ty_trait(id, _, _, _, _) => fmt!("trait %s", item_path_str(cx, id)), ty_struct(id, _) => fmt!("struct %s", item_path_str(cx, id)), ty_tup(_) => ~"tuple", ty_infer(TyVar(_)) => ~"inferred type", @@ -3532,12 +3388,12 @@ pub fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str { terr_regions_insufficiently_polymorphic(br, _) => { fmt!("expected bound lifetime parameter %s, \ but found concrete lifetime", - bound_region_to_str(cx, br)) + bound_region_ptr_to_str(cx, br)) } terr_regions_overly_polymorphic(br, _) => { fmt!("expected concrete lifetime, \ but found bound lifetime parameter %s", - bound_region_to_str(cx, br)) + bound_region_ptr_to_str(cx, br)) } terr_vstores_differ(k, ref values) => { fmt!("%s storage differs: expected %s but found %s", @@ -3632,7 +3488,7 @@ pub fn def_has_ty_params(def: ast::def) -> bool { } } -pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] { +pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[@Method] { if is_local(id) { match cx.items.find(&id.node) { Some(&ast_map::node_item(@ast::item { @@ -3640,13 +3496,13 @@ pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] { _ }, _)) => match ast_util::split_trait_methods(*ms) { - (_, p) => p.map(|method| method.ident) + (_, p) => p.map(|m| method(cx, ast_util::local_def(m.id))) }, _ => cx.sess.bug(fmt!("provided_trait_methods: %? is not a trait", id)) } } else { - csearch::get_provided_trait_methods(cx, id).map(|ifo| ifo.ty.ident) + csearch::get_provided_trait_methods(cx, id) } } @@ -3774,7 +3630,7 @@ pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> { pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> { match get(ty).sty { - ty_trait(id, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id), + ty_trait(id, _, _, _, _) | ty_struct(id, _) | ty_enum(id, _) => Some(id), _ => None } } @@ -3818,15 +3674,15 @@ pub fn substd_enum_variants(cx: ctxt, id: ast::def_id, substs: &substs) -> ~[VariantInfo] { - do vec::map(*enum_variants(cx, id)) |variant_info| { - let substd_args = vec::map(variant_info.args, - |aty| subst(cx, substs, *aty)); + do enum_variants(cx, id).iter().transform |variant_info| { + let substd_args = variant_info.args.iter() + .transform(|aty| subst(cx, substs, *aty)).collect(); let substd_ctor_ty = subst(cx, substs, variant_info.ctor_ty); @VariantInfo_{args: substd_args, ctor_ty: substd_ctor_ty, ../*bad*/copy **variant_info} - } + }.collect() } pub fn item_path_str(cx: ctxt, id: ast::def_id) -> ~str { @@ -3835,27 +3691,38 @@ pub fn item_path_str(cx: ctxt, id: ast::def_id) -> ~str { pub enum DtorKind { NoDtor, - TraitDtor(def_id) + TraitDtor(def_id, bool) } impl DtorKind { - pub fn is_not_present(&const self) -> bool { + pub fn is_not_present(&self) -> bool { match *self { NoDtor => true, _ => false } } - pub fn is_present(&const self) -> bool { + pub fn is_present(&self) -> bool { !self.is_not_present() } + + pub fn has_drop_flag(&self) -> bool { + match self { + &NoDtor => false, + &TraitDtor(_, flag) => flag + } + } } /* If struct_id names a struct with a dtor, return Some(the dtor's id). Otherwise return none. */ pub fn ty_dtor(cx: ctxt, struct_id: def_id) -> DtorKind { match cx.destructor_for_type.find(&struct_id) { - Some(&method_def_id) => TraitDtor(method_def_id), + Some(&method_def_id) => { + let flag = !has_attr(cx, struct_id, "unsafe_no_drop_flag"); + + TraitDtor(method_def_id, flag) + } None => NoDtor, } } @@ -3902,7 +3769,7 @@ pub fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path { } ast_map::node_variant(ref variant, _, path) => { - vec::append_one(vec::to_owned(vec::init(*path)), + vec::append_one(vec::to_owned(path.init()), ast_map::path_name((*variant).node.name)) } @@ -3948,7 +3815,7 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] { _ }, _) => { let mut disr_val = -1; - @vec::map(enum_definition.variants, |variant| { + @enum_definition.variants.iter().transform(|variant| { match variant.node.kind { ast::tuple_variant_kind(ref args) => { let ctor_ty = node_id_to_type(cx, variant.node.id); @@ -3981,7 +3848,7 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] { fail!("struct variant kinds unimpl in enum_variants") } } - }) + }).collect() } _ => cx.sess.bug("tag_variants: id not bound to an enum") } @@ -4129,9 +3996,10 @@ pub fn lookup_struct_field(cx: ctxt, parent: ast::def_id, field_id: ast::def_id) -> field_ty { - match vec::find(lookup_struct_fields(cx, parent), + let r = lookup_struct_fields(cx, parent); + match r.iter().find_( |f| f.id.node == field_id.node) { - Some(t) => t, + Some(t) => *t, None => cx.sess.bug("struct ID not found in parent's fields") } } @@ -4321,7 +4189,7 @@ pub fn normalize_ty(cx: ctxt, t: t) -> t { } // Returns the repeat count for a repeating vector expression. -pub fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr) -> uint { +pub fn eval_repeat_count(tcx: ctxt, count_expr: &ast::expr) -> uint { match const_eval::eval_const_expr_partial(tcx, count_expr) { Ok(ref const_val) => match *const_val { const_eval::const_int(count) => if count < 0 { @@ -4383,7 +4251,7 @@ pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id), pub fn each_bound_trait_and_supertraits(tcx: ctxt, bounds: &ParamBounds, f: &fn(@TraitRef) -> bool) -> bool { - for bounds.trait_bounds.each |&bound_trait_ref| { + for bounds.trait_bounds.iter().advance |&bound_trait_ref| { let mut supertrait_set = HashMap::new(); let mut trait_refs = ~[]; let mut i = 0; @@ -4403,7 +4271,7 @@ pub fn each_bound_trait_and_supertraits(tcx: ctxt, // Add supertraits to supertrait_set let supertrait_refs = trait_ref_supertraits(tcx, trait_refs[i]); - for supertrait_refs.each |&supertrait_ref| { + for supertrait_refs.iter().advance |&supertrait_ref| { debug!("each_bound_trait_and_supertraits(supertrait_ref=%s)", supertrait_ref.repr(tcx)); @@ -4424,7 +4292,7 @@ pub fn each_bound_trait_and_supertraits(tcx: ctxt, pub fn count_traits_and_supertraits(tcx: ctxt, type_param_defs: &[TypeParameterDef]) -> uint { let mut total = 0; - for type_param_defs.each |type_param_def| { + for type_param_defs.iter().advance |type_param_def| { for each_bound_trait_and_supertraits(tcx, type_param_def.bounds) |_| { total += 1; } @@ -4448,10 +4316,29 @@ pub fn get_impl_id(tcx: ctxt, trait_id: def_id, self_ty: t) -> def_id { } } +pub fn get_tydesc_ty(tcx: ctxt) -> t { + let tydesc_lang_item = tcx.lang_items.ty_desc(); + tcx.intrinsic_defs.find_copy(&tydesc_lang_item) + .expect("Failed to resolve TyDesc") +} + +pub fn get_opaque_ty(tcx: ctxt) -> t { + let opaque_lang_item = tcx.lang_items.opaque(); + tcx.intrinsic_defs.find_copy(&opaque_lang_item) + .expect("Failed to resolve Opaque") +} + pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) { - let ty_visitor_name = special_idents::ty_visitor; - assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name)); - let trait_ref = tcx.intrinsic_traits.get_copy(&ty_visitor_name); + let substs = substs { + self_r: None, + self_ty: None, + tps: ~[] + }; + let trait_lang_item = tcx.lang_items.ty_visitor(); + let trait_ref = @TraitRef { def_id: trait_lang_item, substs: substs }; + let mut static_trait_bound = EmptyBuiltinBounds(); + static_trait_bound.add(BoundStatic); (trait_ref, - mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore, ast::m_imm)) + mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, + BoxTraitStore, ast::m_imm, static_trait_bound)) } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 4b5f416cdd1..4d2849c5210 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -52,7 +52,6 @@ * an rptr (`&r.T`) use the region `r` that appears in the rptr. */ -use core::prelude::*; use middle::const_eval; use middle::ty::{substs}; @@ -63,8 +62,8 @@ use middle::typeck::rscope::{region_scope, RegionError}; use middle::typeck::rscope::RegionParamNames; use middle::typeck::lookup_def_tcx; -use core::result; -use core::vec; +use std::result; +use std::vec; use syntax::abi::AbiSet; use syntax::{ast, ast_util}; use syntax::codemap::span; @@ -248,7 +247,7 @@ pub static NO_TPS: uint = 2; // internal notion of a type. `getter` is a function that returns the type // corresponding to a definition ID: pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>( - this: &AC, rscope: &RS, ast_ty: @ast::Ty) -> ty::t { + this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t { fn ast_mt_to_mt<AC:AstConv, RS:region_scope + Copy + 'static>( this: &AC, rscope: &RS, mt: &ast::mt) -> ty::mt { @@ -277,7 +276,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>( } return ty::mk_evec(tcx, mt, vst); } - ast::ty_path(path, id) => { + ast::ty_path(path, bounds, id) => { + // Note that the "bounds must be empty if path is not a trait" + // restriction is enforced in the below case for ty_path, which + // will run after this as long as the path isn't a trait. match tcx.def_map.find(&id) { Some(&ast::def_prim_ty(ast::ty_str)) if a_seq_ty.mutbl == ast::m_imm => { check_path_args(tcx, path, NO_TPS | NO_REGIONS); @@ -300,11 +302,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>( ty::BoxTraitStore } }; + let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store); return ty::mk_trait(tcx, result.def_id, copy result.substs, trait_store, - a_seq_ty.mutbl); + a_seq_ty.mutbl, + bounds); } _ => {} } @@ -381,7 +385,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>( bf.abis, &bf.lifetimes, &bf.decl)) } ast::ty_closure(ref f) => { - let bounds = conv_builtin_bounds(this.tcx(), &f.bounds); + let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil { + // Use corresponding trait store to figure out default bounds + // if none were specified. + ast::BorrowedSigil => ty::RegionTraitStore(ty::re_empty), // dummy region + ast::OwnedSigil => ty::UniqTraitStore, + ast::ManagedSigil => ty::BoxTraitStore, + }); let fn_decl = ty_of_closure(this, rscope, f.sigil, @@ -395,13 +405,22 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>( ast_ty.span); ty::mk_closure(tcx, fn_decl) } - ast::ty_path(path, id) => { + ast::ty_path(path, bounds, id) => { let a_def = match tcx.def_map.find(&id) { None => tcx.sess.span_fatal( ast_ty.span, fmt!("unbound path %s", path_to_str(path, tcx.sess.intr()))), Some(&d) => d }; + // Kind bounds on path types are only supported for traits. + match a_def { + // But don't emit the error if the user meant to do a trait anyway. + ast::def_trait(*) => { }, + _ if bounds.is_some() => + tcx.sess.span_err(ast_ty.span, + "kind bounds can only be used on trait types"), + _ => { }, + } match a_def { ast::def_trait(_) => { let path_str = path_to_str(path, tcx.sess.intr()); @@ -534,7 +553,7 @@ pub fn bound_lifetimes<AC:AstConv>( let special_idents = [special_idents::statik, special_idents::self_]; let mut bound_lifetime_names = opt_vec::Empty; ast_lifetimes.map_to_vec(|ast_lifetime| { - if special_idents.any(|&i| i == ast_lifetime.ident) { + if special_idents.iter().any_(|&i| i == ast_lifetime.ident) { this.tcx().sess.span_err( ast_lifetime.span, fmt!("illegal lifetime parameter name: `%s`", @@ -642,10 +661,10 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:region_scope + Copy + 'static>( ty::mt {ty: self_info.untransformed_self_ty, mutbl: mutability})) } - ast::sty_uniq(mutability) => { + ast::sty_uniq => { Some(ty::mk_uniq(this.tcx(), ty::mt {ty: self_info.untransformed_self_ty, - mutbl: mutability})) + mutbl: ast::m_imm})) } } } @@ -699,14 +718,14 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>( let bound_lifetime_names = bound_lifetimes(this, lifetimes); let rb = in_binding_rscope(rscope, RegionParamNames(copy bound_lifetime_names)); - let input_tys = do decl.inputs.mapi |i, a| { + let input_tys = do decl.inputs.iter().enumerate().transform |(i, a)| { let expected_arg_ty = do expected_sig.chain_ref |e| { // no guarantee that the correct number of expected args // were supplied if i < e.inputs.len() {Some(e.inputs[i])} else {None} }; ty_of_arg(this, &rb, *a, expected_arg_ty) - }; + }.collect(); let expected_ret_ty = expected_sig.map(|e| e.output); let output_ty = match decl.output.node { @@ -727,60 +746,79 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>( } } -fn conv_builtin_bounds(tcx: ty::ctxt, - ast_bounds: &OptVec<ast::TyParamBound>) +fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBound>>, + store: ty::TraitStore) -> ty::BuiltinBounds { //! Converts a list of bounds from the AST into a `BuiltinBounds` //! struct. Reports an error if any of the bounds that appear //! in the AST refer to general traits and not the built-in traits - //! like `Copy` or `Owned`. Used to translate the bounds that + //! like `Copy` or `Send`. Used to translate the bounds that //! appear in closure and trait types, where only builtin bounds are //! legal. - - let mut builtin_bounds = ty::EmptyBuiltinBounds(); - for ast_bounds.each |ast_bound| { - match *ast_bound { - ast::TraitTyParamBound(b) => { - match lookup_def_tcx(tcx, b.path.span, b.ref_id) { - ast::def_trait(trait_did) => { - if try_add_builtin_trait(tcx, - trait_did, - &mut builtin_bounds) { - loop; // success + //! If no bounds were specified, we choose a "default" bound based on + //! the allocation type of the fn/trait, as per issue #7264. The user can + //! override this with an empty bounds list, e.g. "~fn:()" or "~Trait:". + + match (ast_bounds, store) { + (&Some(ref bound_vec), _) => { + let mut builtin_bounds = ty::EmptyBuiltinBounds(); + for bound_vec.iter().advance |ast_bound| { + match *ast_bound { + ast::TraitTyParamBound(b) => { + match lookup_def_tcx(tcx, b.path.span, b.ref_id) { + ast::def_trait(trait_did) => { + if try_add_builtin_trait(tcx, + trait_did, + &mut builtin_bounds) { + loop; // success + } + } + _ => { } } + tcx.sess.span_fatal( + b.path.span, + fmt!("only the builtin traits can be used \ + as closure or object bounds")); + } + ast::RegionTyParamBound => { + builtin_bounds.add(ty::BoundStatic); } - _ => { } } - tcx.sess.span_fatal( - b.path.span, - fmt!("only the builtin traits can be used \ - as closure or object bounds")); - } - ast::RegionTyParamBound => { - builtin_bounds.add(ty::BoundStatic); } + builtin_bounds + }, + // ~Trait is sugar for ~Trait:Send. + (&None, ty::UniqTraitStore) => { + let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundSend); set + } + // @Trait is sugar for @Trait:'static. + // &'static Trait is sugar for &'static Trait:'static. + (&None, ty::BoxTraitStore) | + (&None, ty::RegionTraitStore(ty::re_static)) => { + let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundStatic); set } + // &'r Trait is sugar for &'r Trait:<no-bounds>. + (&None, ty::RegionTraitStore(*)) => ty::EmptyBuiltinBounds(), } - builtin_bounds } pub fn try_add_builtin_trait(tcx: ty::ctxt, trait_def_id: ast::def_id, builtin_bounds: &mut ty::BuiltinBounds) -> bool { //! Checks whether `trait_ref` refers to one of the builtin - //! traits, like `Copy` or `Owned`, and adds the corresponding + //! traits, like `Copy` or `Send`, and adds the corresponding //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref` //! is a builtin trait. let li = &tcx.lang_items; - if trait_def_id == li.owned_trait() { - builtin_bounds.add(ty::BoundOwned); + if trait_def_id == li.send_trait() { + builtin_bounds.add(ty::BoundSend); true } else if trait_def_id == li.copy_trait() { builtin_bounds.add(ty::BoundCopy); true - } else if trait_def_id == li.const_trait() { - builtin_bounds.add(ty::BoundConst); + } else if trait_def_id == li.freeze_trait() { + builtin_bounds.add(ty::BoundFreeze); true } else if trait_def_id == li.sized_trait() { builtin_bounds.add(ty::BoundSized); diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 97e933496c8..45867ae77e0 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const}; use middle::ty; @@ -16,9 +15,10 @@ use middle::typeck::check::demand; use middle::typeck::check::{check_block, check_expr_has_type, FnCtxt}; use middle::typeck::check::{instantiate_path, lookup_def}; use middle::typeck::check::{structure_of, valid_range_bounds}; +use middle::typeck::infer; use middle::typeck::require_same_types; -use core::hashmap::{HashMap, HashSet}; +use std::hashmap::{HashMap, HashSet}; use syntax::ast; use syntax::ast_util; use syntax::codemap::span; @@ -30,27 +30,32 @@ pub fn check_match(fcx: @mut FnCtxt, arms: &[ast::arm]) { let tcx = fcx.ccx.tcx; - let pattern_ty = fcx.infcx().next_ty_var(); - check_expr_has_type(fcx, discrim, pattern_ty); + let discrim_ty = fcx.infcx().next_ty_var(); + check_expr_has_type(fcx, discrim, discrim_ty); // Typecheck the patterns first, so that we get types for all the // bindings. - for arms.each |arm| { + for arms.iter().advance |arm| { let pcx = pat_ctxt { fcx: fcx, map: pat_id_map(tcx.def_map, arm.pats[0]), - match_region: ty::re_scope(expr.id), - block_region: ty::re_scope(arm.body.node.id) }; - for arm.pats.each |p| { check_pat(&pcx, *p, pattern_ty);} + for arm.pats.iter().advance |p| { check_pat(&pcx, *p, discrim_ty);} } + // The result of the match is the common supertype of all the + // arms. Start out the value as bottom, since it's the, well, + // bottom the type lattice, and we'll be moving up the lattice as + // we process each arm. (Note that any match with 0 arms is matching + // on any empty type and is therefore unreachable; should the flow + // of execution reach it, we will fail, so bottom is an appropriate + // type in that case) + let mut result_ty = ty::mk_bot(); + // Now typecheck the blocks. - let mut result_ty = fcx.infcx().next_ty_var(); - let mut arm_non_bot = false; - let mut saw_err = false; - for arms.each |arm| { + let mut saw_err = ty::type_is_error(discrim_ty); + for arms.iter().advance |arm| { let mut guard_err = false; let mut guard_bot = false; match arm.guard { @@ -76,26 +81,28 @@ pub fn check_match(fcx: @mut FnCtxt, else if guard_bot { fcx.write_bot(arm.body.node.id); } - else if !ty::type_is_bot(bty) { - arm_non_bot = true; // If the match *may* evaluate to a non-_|_ - // expr, the whole thing is non-_|_ - } - demand::suptype(fcx, arm.body.span, result_ty, bty); + + result_ty = + infer::common_supertype( + fcx.infcx(), + infer::MatchExpression(expr.span), + true, // result_ty is "expected" here + result_ty, + bty); } + if saw_err { result_ty = ty::mk_err(); - } - else if !arm_non_bot { + } else if ty::type_is_bot(discrim_ty) { result_ty = ty::mk_bot(); } + fcx.write_ty(expr.id, result_ty); } pub struct pat_ctxt { fcx: @mut FnCtxt, map: PatIdMap, - match_region: ty::Region, // Region for the match as a whole - block_region: ty::Region, // Region for the block of the arm } pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, @@ -248,7 +255,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, if error_happened { for subpats.iter().advance |pats| { - for pats.each |pat| { + for pats.iter().advance |pat| { check_pat(pcx, *pat, ty::mk_err()); } } @@ -274,13 +281,13 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt, // Index the class fields. let mut field_map = HashMap::new(); - for class_fields.eachi |i, class_field| { + for class_fields.iter().enumerate().advance |(i, class_field)| { field_map.insert(class_field.ident, i); } // Typecheck each field. let mut found_fields = HashSet::new(); - for fields.each |field| { + for fields.iter().advance |field| { match field_map.find(&field.ident) { Some(&index) => { let class_field = class_fields[index]; @@ -303,7 +310,7 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt, // Report an error if not all the fields were specified. if !etc { - for class_fields.eachi |i, field| { + for class_fields.iter().enumerate().advance |(i, field)| { if found_fields.contains(&i) { loop; } @@ -443,8 +450,8 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { // then the type of x is &M T where M is the mutability // and T is the expected type let region_var = - fcx.infcx().next_region_var_with_lb( - pat.span, pcx.block_region); + fcx.infcx().next_region_var( + infer::PatternRegion(pat.span)); let mt = ty::mt {ty: expected, mutbl: mutbl}; let region_ty = ty::mk_rptr(tcx, region_var, mt); demand::eqtype(fcx, pat.span, region_ty, typ); @@ -510,13 +517,13 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { let e_count = elts.len(); match s { ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => { - for elts.eachi |i, elt| { + for elts.iter().enumerate().advance |(i, elt)| { check_pat(pcx, *elt, ex_elts[i]); } fcx.write_ty(pat.id, expected); } _ => { - for elts.each |elt| { + for elts.iter().advance |elt| { check_pat(pcx, *elt, ty::mk_err()); } // use terr_tuple_size if both types are tuples @@ -538,16 +545,15 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { check_pointer_pat(pcx, Managed, inner, pat.id, pat.span, expected); } ast::pat_uniq(inner) => { - check_pointer_pat(pcx, Owned, inner, pat.id, pat.span, expected); + check_pointer_pat(pcx, Send, inner, pat.id, pat.span, expected); } ast::pat_region(inner) => { check_pointer_pat(pcx, Borrowed, inner, pat.id, pat.span, expected); } ast::pat_vec(ref before, slice, ref after) => { let default_region_var = - fcx.infcx().next_region_var_with_lb( - pat.span, pcx.block_region - ); + fcx.infcx().next_region_var( + infer::PatternRegion(pat.span)); let (elt_type, region_var) = match structure_of( fcx, pat.span, expected @@ -565,13 +571,13 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { (mt, default_region_var) }, _ => { - for before.each |&elt| { + for before.iter().advance |&elt| { check_pat(pcx, elt, ty::mk_err()); } for slice.iter().advance |&elt| { check_pat(pcx, elt, ty::mk_err()); } - for after.each |&elt| { + for after.iter().advance |&elt| { check_pat(pcx, elt, ty::mk_err()); } fcx.infcx().type_error_message_str_with_expected( @@ -587,7 +593,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { return; } }; - for before.each |elt| { + for before.iter().advance |elt| { check_pat(pcx, *elt, elt_type.ty); } match slice { @@ -600,7 +606,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } None => () } - for after.each |elt| { + for after.iter().advance |elt| { check_pat(pcx, *elt, elt_type.ty); } fcx.write_ty(pat.id, expected); @@ -624,7 +630,7 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, ty::ty_box(e_inner) if pointer_kind == Managed => { check_inner(e_inner); } - ty::ty_uniq(e_inner) if pointer_kind == Owned => { + ty::ty_uniq(e_inner) if pointer_kind == Send => { check_inner(e_inner); } ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => { @@ -641,7 +647,7 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, Some(expected), fmt!("%s pattern", match pointer_kind { Managed => "an @-box", - Owned => "a ~-box", + Send => "a ~-box", Borrowed => "an &-pointer" }), None); @@ -651,4 +657,5 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, } #[deriving(Eq)] -enum PointerKind { Managed, Owned, Borrowed } +enum PointerKind { Managed, Send, Borrowed } + diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc/middle/typeck/check/demand.rs index 3fa551e4b05..cf29d3f7f1f 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc/middle/typeck/check/demand.rs @@ -13,8 +13,8 @@ use middle::ty; use middle::typeck::check::FnCtxt; use middle::typeck::infer; -use core::result::{Err, Ok}; -use core::result; +use std::result::{Err, Ok}; +use std::result; use syntax::ast; use syntax::codemap::span; @@ -35,7 +35,7 @@ pub fn suptype_with_fn(fcx: @mut FnCtxt, ty_a: ty::t, ty_b: ty::t, handle_err: &fn(span, ty::t, ty::t, &ty::type_err)) { // n.b.: order of actual, expected is reversed - match infer::mk_subty(fcx.infcx(), b_is_expected, sp, + match infer::mk_subty(fcx.infcx(), b_is_expected, infer::Misc(sp), ty_b, ty_a) { result::Ok(()) => { /* ok */ } result::Err(ref err) => { @@ -45,7 +45,7 @@ pub fn suptype_with_fn(fcx: @mut FnCtxt, } pub fn eqtype(fcx: @mut FnCtxt, sp: span, expected: ty::t, actual: ty::t) { - match infer::mk_eqty(fcx.infcx(), false, sp, actual, expected) { + match infer::mk_eqty(fcx.infcx(), false, infer::Misc(sp), actual, expected) { Ok(()) => { /* ok */ } Err(ref err) => { fcx.report_mismatched_types(sp, expected, actual, err); diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index b2c9d27241d..ee61399113a 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -79,7 +79,6 @@ obtained the type `Foo`, we would never match this method. */ -use core::prelude::*; use middle::resolve; use middle::ty::*; @@ -95,10 +94,10 @@ use middle::typeck::{method_self, method_static, method_trait, method_super}; use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; use util::common::indenter; -use core::hashmap::HashSet; -use core::result; -use core::uint; -use core::vec; +use std::hashmap::HashSet; +use std::result; +use std::uint; +use std::vec; use extra::list::Nil; use syntax::ast::{def_id, sty_value, sty_region, sty_box}; use syntax::ast::{sty_uniq, sty_static, node_id}; @@ -254,7 +253,7 @@ impl<'self> LookupContext<'self> { ty_enum(did, _) => { // Watch out for newtype'd enums like "enum t = @T". // See discussion in typeck::check::do_autoderef(). - if enum_dids.contains(&did) { + if enum_dids.iter().any_(|x| x == &did) { return None; } enum_dids.push(did); @@ -292,7 +291,7 @@ impl<'self> LookupContext<'self> { ty_param(p) => { self.push_inherent_candidates_from_param(self_ty, p); } - ty_trait(did, ref substs, store, _) => { + ty_trait(did, ref substs, store, _, _) => { self.push_inherent_candidates_from_trait( self_ty, did, substs, store); self.push_inherent_impl_candidates_for_type(did); @@ -300,13 +299,8 @@ impl<'self> LookupContext<'self> { ty_self(self_did) => { // Call is of the form "self.foo()" and appears in one // of a trait's default method implementations. - let substs = substs { - self_r: None, - self_ty: None, - tps: ~[] - }; self.push_inherent_candidates_from_self( - self_ty, self_did, &substs); + self_ty, self_did); } ty_enum(did, _) | ty_struct(did, _) => { if self.check_traits == CheckTraitsAndInherentMethods { @@ -333,14 +327,12 @@ impl<'self> LookupContext<'self> { let trait_map: &mut resolve::TraitMap = &mut self.fcx.ccx.trait_map; let opt_applicable_traits = trait_map.find(&self.expr.id); for opt_applicable_traits.iter().advance |applicable_traits| { - for applicable_traits.each |trait_did| { - let coherence_info = self.fcx.ccx.coherence_info; - + for applicable_traits.iter().advance |trait_did| { // Look for explicit implementations. let opt_impl_infos = - coherence_info.extension_methods.find(trait_did); + self.fcx.ccx.coherence_info.extension_methods.find(trait_did); for opt_impl_infos.iter().advance |impl_infos| { - for impl_infos.each |impl_info| { + for impl_infos.iter().advance |impl_info| { self.push_candidates_from_impl( self.extension_candidates, *impl_info); @@ -376,7 +368,7 @@ impl<'self> LookupContext<'self> { let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); let pos = { - match trait_methods.position(|m| { + match trait_methods.iter().position_(|m| { m.explicit_self != ast::sty_static && m.ident == self.m_name }) { @@ -420,7 +412,7 @@ impl<'self> LookupContext<'self> { let tcx = self.tcx(); let ms = ty::trait_methods(tcx, did); - let index = match vec::position(*ms, |m| m.ident == self.m_name) { + let index = match ms.iter().position_(|m| m.ident == self.m_name) { Some(i) => i, None => { return; } // no method with the right name }; @@ -462,40 +454,41 @@ impl<'self> LookupContext<'self> { pub fn push_inherent_candidates_from_self(&self, self_ty: ty::t, - did: def_id, - substs: &ty::substs) { + did: def_id) { struct MethodInfo { method_ty: @ty::Method, trait_def_id: ast::def_id, - index: uint + index: uint, + trait_ref: @ty::TraitRef } let tcx = self.tcx(); // First, try self methods let mut method_info: Option<MethodInfo> = None; let methods = ty::trait_methods(tcx, did); - match vec::position(*methods, |m| m.ident == self.m_name) { + match methods.iter().position_(|m| m.ident == self.m_name) { Some(i) => { method_info = Some(MethodInfo { method_ty: methods[i], index: i, - trait_def_id: did + trait_def_id: did, + trait_ref: ty::lookup_trait_def(tcx, did).trait_ref }); } None => () } // No method found yet? Check each supertrait if method_info.is_none() { - for ty::trait_supertraits(tcx, did).each() |trait_ref| { + for ty::trait_supertraits(tcx, did).iter().advance |trait_ref| { let supertrait_methods = ty::trait_methods(tcx, trait_ref.def_id); - match vec::position(*supertrait_methods, - |m| m.ident == self.m_name) { + match supertrait_methods.iter().position_(|m| m.ident == self.m_name) { Some(i) => { method_info = Some(MethodInfo { method_ty: supertrait_methods[i], index: i, - trait_def_id: trait_ref.def_id + trait_def_id: trait_ref.def_id, + trait_ref: *trait_ref }); break; } @@ -506,8 +499,6 @@ impl<'self> LookupContext<'self> { match method_info { Some(ref info) => { // We've found a method -- return it - let rcvr_substs = substs {self_ty: Some(self_ty), - ..copy *substs }; let origin = if did == info.trait_def_id { method_self(info.trait_def_id, info.index) } else { @@ -515,7 +506,7 @@ impl<'self> LookupContext<'self> { }; self.inherent_candidates.push(Candidate { rcvr_ty: self_ty, - rcvr_substs: rcvr_substs, + rcvr_substs: copy info.trait_ref.substs, method_ty: info.method_ty, origin: origin }); @@ -528,7 +519,7 @@ impl<'self> LookupContext<'self> { let opt_impl_infos = self.fcx.ccx.coherence_info.inherent_methods.find(&did); for opt_impl_infos.iter().advance |impl_infos| { - for impl_infos.each |impl_info| { + for impl_infos.iter().advance |impl_info| { self.push_candidates_from_impl( self.inherent_candidates, *impl_info); } @@ -541,9 +532,13 @@ impl<'self> LookupContext<'self> { if !self.impl_dups.insert(impl_info.did) { return; // already visited } + debug!("push_candidates_from_impl: %s %s %s", + self.m_name.repr(self.tcx()), + impl_info.ident.repr(self.tcx()), + impl_info.methods.map(|m| m.ident).repr(self.tcx())); let idx = { - match impl_info.methods.position(|m| m.ident == self.m_name) { + match impl_info.methods.iter().position_(|m| m.ident == self.m_name) { Some(idx) => idx, None => { return; } // No method with the right name. } @@ -624,14 +619,18 @@ impl<'self> LookupContext<'self> { autoref: None})) } ty::ty_rptr(_, self_mt) => { - let region = self.infcx().next_region_var_nb(self.expr.span); + let region = + self.infcx().next_region_var( + infer::Autoref(self.expr.span)); (ty::mk_rptr(tcx, region, self_mt), ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs+1, autoref: Some(ty::AutoPtr(region, self_mt.mutbl))})) } ty::ty_evec(self_mt, vstore_slice(_)) => { - let region = self.infcx().next_region_var_nb(self.expr.span); + let region = + self.infcx().next_region_var( + infer::Autoref(self.expr.span)); (ty::mk_evec(tcx, self_mt, vstore_slice(region)), ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, @@ -763,8 +762,10 @@ impl<'self> LookupContext<'self> { -> Option<method_map_entry> { // This is hokey. We should have mutability inference as a // variable. But for now, try &const, then &, then &mut: - let region = self.infcx().next_region_var_nb(self.expr.span); - for mutbls.each |mutbl| { + let region = + self.infcx().next_region_var( + infer::Autoref(self.expr.span)); + for mutbls.iter().advance |mutbl| { let autoref_ty = mk_autoref_ty(*mutbl, region); match self.search_for_method(autoref_ty) { None => {} @@ -813,8 +814,9 @@ impl<'self> LookupContext<'self> { rcvr_ty: ty::t, candidates: &mut ~[Candidate]) -> Option<method_map_entry> { - let relevant_candidates = - candidates.filter_to_vec(|c| self.is_relevant(rcvr_ty, c)); + let relevant_candidates: ~[Candidate] = + candidates.iter().transform(|c| copy *c). + filter(|c| self.is_relevant(rcvr_ty, c)).collect(); let relevant_candidates = self.merge_candidates(relevant_candidates); @@ -942,7 +944,7 @@ impl<'self> LookupContext<'self> { parameters given for this method"); self.fcx.infcx().next_ty_vars(num_method_tps) } else { - self.supplied_tps.to_vec() + self.supplied_tps.to_owned() } }; @@ -974,7 +976,8 @@ impl<'self> LookupContext<'self> { let (_, opt_transformed_self_ty, fn_sig) = replace_bound_regions_in_fn_sig( tcx, @Nil, Some(transformed_self_ty), &bare_fn_ty.sig, - |_br| self.fcx.infcx().next_region_var_nb(self.expr.span)); + |br| self.fcx.infcx().next_region_var( + infer::BoundRegionInFnCall(self.expr.span, br))); let transformed_self_ty = opt_transformed_self_ty.get(); let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {sig: fn_sig, ..bare_fn_ty}); debug!("after replacing bound regions, fty=%s", self.ty_to_str(fty)); @@ -986,7 +989,7 @@ impl<'self> LookupContext<'self> { // variables to unify etc). Since we checked beforehand, and // nothing has changed in the meantime, this unification // should never fail. - match self.fcx.mk_subty(false, self.self_expr.span, + match self.fcx.mk_subty(false, infer::Misc(self.self_expr.span), rcvr_ty, transformed_self_ty) { result::Ok(_) => (), result::Err(_) => { @@ -999,7 +1002,7 @@ impl<'self> LookupContext<'self> { self.fcx.write_ty(self.callee_id, fty); self.fcx.write_substs(self.callee_id, all_substs); method_map_entry { - self_ty: candidate.rcvr_ty, + self_ty: rcvr_ty, self_mode: self_mode, explicit_self: candidate.method_ty.explicit_self, origin: candidate.origin, @@ -1089,16 +1092,19 @@ impl<'self> LookupContext<'self> { _ => {} } - return match candidate.method_ty.explicit_self { + let result = match candidate.method_ty.explicit_self { sty_static => { + debug!("(is relevant?) explicit self is static"); false } sty_value => { + debug!("(is relevant?) explicit self is by-value"); self.fcx.can_mk_subty(rcvr_ty, candidate.rcvr_ty).is_ok() } sty_region(_, m) => { + debug!("(is relevant?) explicit self is a region"); match ty::get(rcvr_ty).sty { ty::ty_rptr(_, mt) => { mutability_matches(mt.mutbl, m) && @@ -1110,6 +1116,7 @@ impl<'self> LookupContext<'self> { } sty_box(m) => { + debug!("(is relevant?) explicit self is a box"); match ty::get(rcvr_ty).sty { ty::ty_box(mt) => { mutability_matches(mt.mutbl, m) && @@ -1120,10 +1127,11 @@ impl<'self> LookupContext<'self> { } } - sty_uniq(m) => { + sty_uniq => { + debug!("(is relevant?) explicit self is a unique pointer"); match ty::get(rcvr_ty).sty { ty::ty_uniq(mt) => { - mutability_matches(mt.mutbl, m) && + mutability_matches(mt.mutbl, ast::m_imm) && self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok() } @@ -1132,6 +1140,10 @@ impl<'self> LookupContext<'self> { } }; + debug!("(is relevant?) %s", if result { "yes" } else { "no" }); + + return result; + fn mutability_matches(self_mutbl: ast::mutability, candidate_mutbl: ast::mutability) -> bool { //! True if `self_mutbl <: candidate_mutbl` @@ -1248,7 +1260,7 @@ impl<'self> LookupContext<'self> { pub fn get_mode_from_explicit_self(explicit_self: ast::explicit_self_) -> SelfMode { match explicit_self { - sty_value => ty::ByCopy, - _ => ty::ByRef, + sty_value => ty::ByRef, + _ => ty::ByCopy, } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 12b413bc5af..00ebca5abc1 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -76,7 +76,6 @@ type parameter). */ -use core::prelude::*; use middle::const_eval; use middle::pat_util::pat_id_map; @@ -107,15 +106,15 @@ use middle::typeck::{isr_alist, lookup_def_ccx}; use middle::typeck::no_params; use middle::typeck::{require_same_types, method_map, vtable_map}; use util::common::{block_query, indenter, loop_query}; -use util::ppaux::{bound_region_to_str}; +use util::ppaux::{bound_region_ptr_to_str}; use util::ppaux; -use core::cast::transmute; -use core::hashmap::HashMap; -use core::result; -use core::util::replace; -use core::vec; +use std::cast::transmute; +use std::hashmap::HashMap; +use std::result; +use std::util::replace; +use std::vec; use extra::list::Nil; use syntax::abi::AbiSet; use syntax::ast::{provided, required}; @@ -213,6 +212,13 @@ impl PurityState { } } +/// Whether `check_binop` allows overloaded operators to be invoked. +#[deriving(Eq)] +enum AllowOverloadedOperatorsFlag { + AllowOverloadedOperators, + DontAllowOverloadedOperators, +} + pub struct FnCtxt { // Number of errors that had been reported when we started // checking this function. On exit, if we find that *more* errors @@ -275,7 +281,7 @@ pub fn blank_fn_ctxt(ccx: @mut CrateCtxt, err_count_on_creation: ccx.tcx.sess.err_count(), ret_ty: rty, indirect_ret_ty: None, - ps: PurityState::function(ast::pure_fn, 0), + ps: PurityState::function(ast::impure_fn, 0), region_lb: region_bnd, in_scope_regions: @Nil, fn_kind: Vanilla, @@ -284,7 +290,7 @@ pub fn blank_fn_ctxt(ccx: @mut CrateCtxt, } } -pub fn check_item_types(ccx: @mut CrateCtxt, crate: @ast::crate) { +pub fn check_item_types(ccx: @mut CrateCtxt, crate: &ast::crate) { let visit = visit::mk_simple_visitor(@visit::SimpleVisitor { visit_item: |a| check_item(ccx, a), .. *visit::default_simple_visitor() @@ -461,8 +467,6 @@ pub fn check_fn(ccx: @mut CrateCtxt, let pcx = pat_ctxt { fcx: fcx, map: pat_id_map(tcx.def_map, input.pat), - match_region: region, - block_region: region, }; _match::check_pat(&pcx, input.pat, *arg_ty); } @@ -550,7 +554,7 @@ pub fn check_no_duplicate_fields(tcx: ty::ctxt, fields: ~[(ast::ident, span)]) { let mut field_names = HashMap::new(); - for fields.each |p| { + for fields.iter().advance |p| { let (id, sp) = *p; let orig_sp = field_names.find(&id).map_consume(|x| *x); match orig_sp { @@ -585,7 +589,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { let _indenter = indenter(); match it.node { - ast::item_const(_, e) => check_const(ccx, it.span, e, it.id), + ast::item_static(_, _, e) => check_const(ccx, it.span, e, it.id), ast::item_enum(ref enum_definition, _) => { check_enum_variants(ccx, it.span, @@ -599,12 +603,13 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { let rp = ccx.tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); debug!("item_impl %s with id %d rp %?", ccx.tcx.sess.str_of(it.ident), it.id, rp); - for ms.each |m| { + for ms.iter().advance |m| { check_method(ccx, *m); } + vtable::resolve_impl(ccx, it); } ast::item_trait(_, _, ref trait_methods) => { - for (*trait_methods).each |trait_method| { + for (*trait_methods).iter().advance |trait_method| { match *trait_method { required(*) => { // Nothing to do, since required methods don't have @@ -625,11 +630,11 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { } ast::item_foreign_mod(ref m) => { if m.abis.is_intrinsic() { - for m.items.each |item| { + for m.items.iter().advance |item| { check_intrinsic_type(ccx, *item); } } else { - for m.items.each |item| { + for m.items.iter().advance |item| { let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id)); if tpt.generics.has_type_params() { ccx.tcx.sess.span_err( @@ -679,9 +684,14 @@ impl FnCtxt { result::Ok(self.block_region()) } else { result::Err(RegionError { - msg: fmt!("named region `%s` not in scope here", - bound_region_to_str(self.tcx(), br)), - replacement: self.infcx().next_region_var_nb(span) + msg: { + fmt!("named region `%s` not in scope here", + bound_region_ptr_to_str(self.tcx(), br)) + }, + replacement: { + self.infcx().next_region_var( + infer::BoundRegionError(span)) + } }) } } @@ -691,7 +701,7 @@ impl FnCtxt { impl region_scope for FnCtxt { fn anon_region(&self, span: span) -> Result<ty::Region, RegionError> { - result::Ok(self.infcx().next_region_var_nb(span)) + result::Ok(self.infcx().next_region_var(infer::MiscVariable(span))) } fn self_region(&self, span: span) -> Result<ty::Region, RegionError> { self.search_in_scope_regions(span, ty::br_self) @@ -784,10 +794,6 @@ impl FnCtxt { ast_ty_to_ty(self, self, ast_t) } - pub fn expr_to_str(&self, expr: @ast::expr) -> ~str { - expr.repr(self.tcx()) - } - pub fn pat_to_str(&self, pat: @ast::pat) -> ~str { pat.repr(self.tcx()) } @@ -796,9 +802,8 @@ impl FnCtxt { match self.inh.node_types.find(&ex.id) { Some(&t) => t, None => { - self.tcx().sess.bug( - fmt!("no type for %s in fcx %s", - self.expr_to_str(ex), self.tag())); + self.tcx().sess.bug(fmt!("no type for expr in fcx %s", + self.tag())); } } } @@ -843,11 +848,11 @@ impl FnCtxt { pub fn mk_subty(&self, a_is_expected: bool, - span: span, + origin: infer::TypeOrigin, sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - infer::mk_subty(self.infcx(), a_is_expected, span, sub, sup) + infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup) } pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t) @@ -855,9 +860,16 @@ impl FnCtxt { infer::can_mk_subty(self.infcx(), sub, sup) } - pub fn mk_assignty(&self, expr: @ast::expr, sub: ty::t, sup: ty::t) + pub fn mk_assignty(&self, + expr: @ast::expr, + sub: ty::t, + sup: ty::t) -> Result<(), ty::type_err> { - match infer::mk_coercety(self.infcx(), false, expr.span, sub, sup) { + match infer::mk_coercety(self.infcx(), + false, + infer::ExprAssignable(expr), + sub, + sup) { Ok(None) => result::Ok(()), Err(ref e) => result::Err((*e)), Ok(Some(adjustment)) => { @@ -874,20 +886,19 @@ impl FnCtxt { pub fn mk_eqty(&self, a_is_expected: bool, - span: span, + origin: infer::TypeOrigin, sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - infer::mk_eqty(self.infcx(), a_is_expected, span, sub, sup) + infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup) } pub fn mk_subr(&self, a_is_expected: bool, - span: span, + origin: infer::SubregionOrigin, sub: ty::Region, - sup: ty::Region) - -> Result<(), ty::type_err> { - infer::mk_subr(self.infcx(), a_is_expected, span, sub, sup) + sup: ty::Region) { + infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup) } pub fn with_region_lb<R>(@mut self, lb: ast::node_id, f: &fn() -> R) @@ -903,7 +914,9 @@ impl FnCtxt { rp: Option<ty::region_variance>, span: span) -> Option<ty::Region> { - rp.map(|_rp| self.infcx().next_region_var_nb(span)) + rp.map( + |_| self.infcx().next_region_var( + infer::BoundRegionInTypeOrImpl(span))) } pub fn type_error_message(&self, @@ -983,7 +996,7 @@ pub fn do_autoderef(fcx: @mut FnCtxt, sp: span, t: ty::t) -> (ty::t, uint) { // concerned with this, as an error will be reported // on the enum definition as well because the enum is // not instantiable. - if vec::contains(enum_dids, did) { + if enum_dids.contains(did) { return (t1, autoderefs); } enum_dids.push(*did); @@ -1087,7 +1100,8 @@ pub fn impl_self_ty(vcx: &VtableContext, }; let self_r = if region_param.is_some() { - Some(vcx.infcx.next_region_var_nb(location_info.span)) + Some(vcx.infcx.next_region_var( + infer::BoundRegionInTypeOrImpl(location_info.span))) } else { None }; @@ -1107,7 +1121,7 @@ pub fn lookup_field_ty(tcx: ty::ctxt, fieldname: ast::ident, substs: &ty::substs) -> Option<ty::t> { - let o_field = vec::find(items, |f| f.ident == fieldname); + let o_field = items.iter().find_(|f| f.ident == fieldname); do o_field.map() |f| { ty::lookup_field_type(tcx, class_id, f.id, substs) } @@ -1138,7 +1152,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, expr: @ast::expr, expected: Option<ty::t>, unifier: &fn()) { - debug!(">> typechecking %s", fcx.expr_to_str(expr)); + debug!(">> typechecking"); fn check_method_argument_types( fcx: @mut FnCtxt, @@ -1225,7 +1239,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // functions. This is so that we have more information about the types // of arguments when we typecheck the functions. This isn't really the // right way to do this. - for [false, true].each |check_blocks| { + let xs = [false, true]; + for xs.iter().advance |check_blocks| { let check_blocks = *check_blocks; debug!("check_blocks=%b", check_blocks); @@ -1236,7 +1251,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, vtable::early_resolve_expr(callee_expr, fcx, true); } - for args.eachi |i, arg| { + for args.iter().enumerate().advance |(i, arg)| { let is_block = match arg.node { ast::expr_fn_block(*) | ast::expr_loop_body(*) | ast::expr_do_body(*) => true, @@ -1349,7 +1364,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let (_, _, fn_sig) = replace_bound_regions_in_fn_sig( fcx.tcx(), @Nil, None, &fn_sig, - |_br| fcx.infcx().next_region_var_nb(call_expr.span)); + |br| fcx.infcx().next_region_var( + infer::BoundRegionInFnCall(call_expr.span, br))); // Call the generic checker. check_argument_types(fcx, call_expr.span, fn_sig.inputs, f, @@ -1390,6 +1406,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, method_map.insert(expr.id, (*entry)); } None => { + debug!("(checking method call) failing expr is %d", expr.id); + fcx.type_error_message(expr.span, |actual| { fmt!("type `%s` does not implement any method in scope \ @@ -1418,27 +1436,42 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // A generic function for checking the then and else in an if // or if-check fn check_then_else(fcx: @mut FnCtxt, - thn: &ast::blk, - elsopt: Option<@ast::expr>, + cond_expr: @ast::expr, + then_blk: &ast::blk, + opt_else_expr: Option<@ast::expr>, id: ast::node_id, - _sp: span) { - let if_t = - match elsopt { - Some(els) => { - let if_t = fcx.infcx().next_ty_var(); - check_block(fcx, thn); - let thn_t = fcx.node_ty(thn.node.id); - demand::suptype(fcx, thn.span, if_t, thn_t); - check_expr_has_type(fcx, els, if_t); - if_t - } - None => { - check_block_no_value(fcx, thn); - ty::mk_nil() - } - }; + sp: span, + expected: Option<ty::t>) { + check_expr_has_type(fcx, cond_expr, ty::mk_bool()); + + let branches_ty = match opt_else_expr { + Some(else_expr) => { + check_block_with_expected(fcx, then_blk, expected); + let then_ty = fcx.node_ty(then_blk.node.id); + check_expr_with_opt_hint(fcx, else_expr, expected); + let else_ty = fcx.expr_ty(else_expr); + infer::common_supertype(fcx.infcx(), + infer::IfExpression(sp), + true, + then_ty, + else_ty) + } + None => { + check_block_no_value(fcx, then_blk); + ty::mk_nil() + } + }; - fcx.write_ty(id, if_t); + let cond_ty = fcx.expr_ty(cond_expr); + let if_ty = if ty::type_is_error(cond_ty) { + ty::mk_err() + } else if ty::type_is_bot(cond_ty) { + ty::mk_bot() + } else { + branches_ty + }; + + fcx.write_ty(id, if_ty); } fn lookup_op_method(fcx: @mut FnCtxt, @@ -1486,7 +1519,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, lhs: @ast::expr, rhs: @ast::expr, // Used only in the error case - expected_result: Option<ty::t> + expected_result: Option<ty::t>, + allow_overloaded_operators: AllowOverloadedOperatorsFlag ) { let tcx = fcx.ccx.tcx; @@ -1536,8 +1570,30 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } - let result_t = check_user_binop(fcx, callee_id, expr, lhs, lhs_t, op, rhs, - expected_result); + // Check for overloaded operators if allowed. + let result_t; + if allow_overloaded_operators == AllowOverloadedOperators { + result_t = check_user_binop(fcx, + callee_id, + expr, + lhs, + lhs_t, + op, + rhs, + expected_result); + } else { + fcx.type_error_message(expr.span, + |actual| { + fmt!("binary operation %s cannot be \ + applied to type `%s`", + ast_util::binop_to_str(op), + actual) + }, + lhs_t, + None); + result_t = ty::mk_err(); + } + fcx.write_ty(expr.id, result_t); if ty::type_is_error(result_t) { fcx.write_ty(rhs.id, result_t); @@ -1703,8 +1759,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, ty::mk_closure(tcx, fn_ty_copy) }; - debug!("check_expr_fn_with_unifier %s fty=%s", - fcx.expr_to_str(expr), + debug!("check_expr_fn_with_unifier fty=%s", fcx.infcx().ty_to_str(fty)); fcx.write_ty(expr.id, fty); @@ -1754,7 +1809,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, _ => () } - let tps = vec::map(tys, |ty| fcx.to_ty(*ty)); + let tps = tys.iter().transform(|ty| fcx.to_ty(*ty)).collect::<~[ty::t]>(); match method::lookup(fcx, expr, base, @@ -1803,14 +1858,14 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let mut class_field_map = HashMap::new(); let mut fields_found = 0; - for field_types.each |field| { + for field_types.iter().advance |field| { class_field_map.insert(field.ident, (field.id, false)); } let mut error_happened = false; // Typecheck each field. - for ast_fields.each |field| { + for ast_fields.iter().advance |field| { let mut expected_field_type = ty::mk_err(); let pair = class_field_map.find(&field.node.ident). @@ -1856,7 +1911,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, assert!(fields_found <= field_types.len()); if fields_found < field_types.len() { let mut missing_fields = ~[]; - for field_types.each |class_field| { + for field_types.iter().advance |class_field| { let name = class_field.ident; let (_, seen) = *class_field_map.get(&name); if !seen { @@ -2058,7 +2113,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x)); let inner_ty = match expected_sty { Some(ty::ty_closure(ref fty)) => { - match fcx.mk_subty(false, expr.span, + match fcx.mk_subty(false, infer::Misc(expr.span), fty.sig.output, ty::mk_bool()) { result::Ok(_) => { ty::mk_closure(tcx, ty::ClosureTy { @@ -2175,7 +2230,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, _ => mutability = mutbl } let t: ty::t = fcx.infcx().next_ty_var(); - for args.each |e| { + for args.iter().advance |e| { check_expr_has_type(fcx, *e, t); let arg_t = fcx.expr_ty(*e); if ty::type_is_error(arg_t) { @@ -2228,7 +2283,15 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fcx.write_ty(id, typ); } ast::expr_binary(callee_id, op, lhs, rhs) => { - check_binop(fcx, callee_id, expr, op, lhs, rhs, expected); + check_binop(fcx, + callee_id, + expr, + op, + lhs, + rhs, + expected, + AllowOverloadedOperators); + let lhs_ty = fcx.expr_ty(lhs); let rhs_ty = fcx.expr_ty(rhs); if ty::type_is_error(lhs_ty) || @@ -2241,7 +2304,15 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } ast::expr_assign_op(callee_id, op, lhs, rhs) => { - check_binop(fcx, callee_id, expr, op, lhs, rhs, expected); + check_binop(fcx, + callee_id, + expr, + op, + lhs, + rhs, + expected, + DontAllowOverloadedOperators); + let lhs_t = fcx.expr_ty(lhs); let result_t = fcx.expr_ty(expr); demand::suptype(fcx, expr.span, result_t, lhs_t); @@ -2257,7 +2328,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, ast::expr_unary(callee_id, unop, oprnd) => { let exp_inner = do unpack_expected(fcx, expected) |sty| { match unop { - ast::box(_) | ast::uniq(_) => match *sty { + ast::box(_) | ast::uniq => match *sty { ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => Some(mt.ty), _ => None }, @@ -2274,9 +2345,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, oprnd_t = ty::mk_box(tcx, ty::mt {ty: oprnd_t, mutbl: mutbl}); } - ast::uniq(mutbl) => { + ast::uniq => { oprnd_t = ty::mk_uniq(tcx, - ty::mt {ty: oprnd_t, mutbl: mutbl}); + ty::mt {ty: oprnd_t, + mutbl: ast::m_imm}); } ast::deref => { let sty = structure_of(fcx, expr.span, oprnd_t); @@ -2351,7 +2423,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Finally, borrowck is charged with guaranteeing that the // value whose address was taken can actually be made to live // as long as it needs to live. - let region = fcx.infcx().next_region_var_nb(expr.span); + let region = fcx.infcx().next_region_var( + infer::AddrOfRegion(expr.span)); let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl }; let oprnd_t = if ty::type_is_error(tm.ty) { @@ -2377,10 +2450,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fcx.write_ty(id, ty_param_bounds_and_ty.ty); } ast::expr_inline_asm(ref ia) => { - for ia.inputs.each |&(_, in)| { + for ia.inputs.iter().advance |&(_, in)| { check_expr(fcx, in); } - for ia.outputs.each |&(_, out)| { + for ia.outputs.iter().advance |&(_, out)| { check_expr(fcx, out); } fcx.write_nil(id); @@ -2393,7 +2466,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, Some(t) => t, None => fcx.ret_ty }; match expr_opt { - None => match fcx.mk_eqty(false, expr.span, + None => match fcx.mk_eqty(false, infer::Misc(expr.span), ret_ty, ty::mk_nil()) { result::Ok(_) => { /* fall through */ } result::Err(_) => { @@ -2443,25 +2516,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fcx.write_nil(id); } } - ast::expr_if(cond, ref thn, elsopt) => { - check_expr_has_type(fcx, cond, ty::mk_bool()); - check_then_else(fcx, thn, elsopt, id, expr.span); - let cond_ty = fcx.expr_ty(cond); - let then_ty = fcx.node_ty(thn.node.id); - let else_is_bot = elsopt.map_default(false, |els| { - ty::type_is_bot(fcx.expr_ty(*els))}); - if ty::type_is_error(cond_ty) || ty::type_is_error(then_ty) { - fcx.write_error(id); - } - else if elsopt.map_default(false, |els| { - ty::type_is_error(fcx.expr_ty(*els)) }) { - fcx.write_error(id); - } - else if ty::type_is_bot(cond_ty) || - (ty::type_is_bot(then_ty) && else_is_bot) { - fcx.write_bot(id); - } - // Other cases were handled by check_then_else + ast::expr_if(cond, ref then_blk, opt_else_expr) => { + check_then_else(fcx, cond, then_blk, opt_else_expr, + id, expr.span, expected); } ast::expr_while(cond, ref body) => { check_expr_has_type(fcx, cond, ty::mk_bool()); @@ -2489,30 +2546,6 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } ast::expr_match(discrim, ref arms) => { _match::check_match(fcx, expr, discrim, *arms); - let discrim_ty = fcx.expr_ty(discrim); - let arm_tys = arms.map(|a| fcx.node_ty(a.body.node.id)); - if ty::type_is_error(discrim_ty) || - arm_tys.any(|t| ty::type_is_error(*t)) { - fcx.write_error(id); - } - // keep in mind that `all` returns true in the empty vec case, - // which is what we want - else if ty::type_is_bot(discrim_ty) || - arm_tys.all(|t| ty::type_is_bot(*t)) { - fcx.write_bot(id); - } - else { - // Find the first non-_|_ arm. - // We know there's at least one because we already checked - // for n=0 as well as all arms being _|_ in the previous - // `if`. - for arm_tys.each() |arm_ty| { - if !ty::type_is_bot(*arm_ty) { - fcx.write_ty(id, *arm_ty); - break; - } - } - } } ast::expr_fn_block(ref decl, ref body) => { check_expr_fn(fcx, expr, None, @@ -2561,8 +2594,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, ast::expr_call(f, ref args, sugar) => { check_call(fcx, expr.id, expr, f, *args, sugar); let f_ty = fcx.expr_ty(f); - let (args_bot, args_err) = args.foldl((false, false), - |&(rest_bot, rest_err), a| { + let (args_bot, args_err) = args.iter().fold((false, false), + |(rest_bot, rest_err), a| { // is this not working? let a_ty = fcx.expr_ty(*a); (rest_bot || ty::type_is_bot(a_ty), @@ -2578,8 +2611,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, check_method_call(fcx, callee_id, expr, rcvr, ident, *args, *tps, sugar); let f_ty = fcx.expr_ty(rcvr); let arg_tys = args.map(|a| fcx.expr_ty(*a)); - let (args_bot, args_err) = arg_tys.foldl((false, false), - |&(rest_bot, rest_err), a| { + let (args_bot, args_err) = arg_tys.iter().fold((false, false), + |(rest_bot, rest_err), a| { (rest_bot || ty::type_is_bot(*a), rest_err || ty::type_is_error(*a))}); if ty::type_is_error(f_ty) || args_err { @@ -2642,7 +2675,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let el = ty::sequence_element_type(fcx.tcx(), t1); infer::mk_eqty(fcx.infcx(), false, - sp, el, t2).is_ok() + infer::Misc(sp), el, t2).is_ok() } } @@ -2687,7 +2720,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let t: ty::t = fcx.infcx().next_ty_var(); let mut arg_is_bot = false; let mut arg_is_err = false; - for args.each |e| { + for args.iter().advance |e| { check_expr_has_type(fcx, *e, t); let arg_t = fcx.expr_ty(*e); arg_is_bot |= ty::type_is_bot(arg_t); @@ -2722,7 +2755,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let mut bot_field = false; let mut err_field = false; - let elt_ts = do elts.mapi |i, e| { + let elt_ts = do elts.iter().enumerate().transform |(i, e)| { let opt_hint = match flds { Some(ref fs) if i < fs.len() => Some(fs[i]), _ => None @@ -2732,7 +2765,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, err_field = err_field || ty::type_is_error(t); bot_field = bot_field || ty::type_is_bot(t); t - }; + }.collect(); if bot_field { fcx.write_bot(id); } else if err_field { @@ -2863,8 +2896,6 @@ pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::local) { let pcx = pat_ctxt { fcx: fcx, map: pat_id_map(tcx.def_map, local.node.pat), - match_region: region, - block_region: region, }; _match::check_pat(&pcx, local.node.pat, t); let pat_ty = fcx.node_ty(local.node.pat.id); @@ -2948,7 +2979,7 @@ pub fn check_block_with_expected(fcx: @mut FnCtxt, let mut last_was_bot = false; let mut any_bot = false; let mut any_err = false; - for blk.node.stmts.each |s| { + for blk.node.stmts.iter().advance |s| { check_stmt(fcx, *s); let s_id = ast_util::stmt_id(*s); let s_ty = fcx.node_ty(s_id); @@ -3085,7 +3116,7 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, disr_val: &mut int, variants: &mut ~[ty::VariantInfo]) { let rty = ty::node_id_to_type(ccx.tcx, id); - for vs.each |v| { + for vs.iter().advance |v| { for v.node.disr_expr.iter().advance |e_ref| { let e = *e_ref; debug!("disr expr, checking %s", @@ -3112,7 +3143,7 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, } } } - if vec::contains(*disr_vals, &*disr_val) { + if disr_vals.contains(&*disr_val) { ccx.tcx.sess.span_err(v.span, "discriminator value already exists"); } @@ -3215,7 +3246,7 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, } ast::def_fn(id, _) | ast::def_static_method(id, _, _) | - ast::def_const(id) | ast::def_variant(_, id) | + ast::def_static(id, _) | ast::def_variant(_, id) | ast::def_struct(id) => { return ty::lookup_item_type(fcx.ccx.tcx, id); } @@ -3246,6 +3277,9 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, ast::def_self_ty(*) => { fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty"); } + ast::def_method(*) => { + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method"); + } } } @@ -3365,7 +3399,7 @@ pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt, ast::expr_vstore_uniq => ty::vstore_uniq, ast::expr_vstore_box | ast::expr_vstore_mut_box => ty::vstore_box, ast::expr_vstore_slice | ast::expr_vstore_mut_slice => { - let r = fcx.infcx().next_region_var_nb(e.span); + let r = fcx.infcx().next_region_var(infer::AddrOfSlice(e.span)); ty::vstore_slice(r) } } @@ -3419,7 +3453,7 @@ pub fn check_bounds_are_used(ccx: @mut CrateCtxt, true }); - for tps_used.eachi |i, b| { + for tps_used.iter().enumerate().advance |(i, b)| { if !*b { ccx.tcx.sess.span_err( span, fmt!("type parameter `%s` is unused", @@ -3434,252 +3468,270 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { } let tcx = ccx.tcx; - let str = ccx.tcx.sess.str_of(it.ident); - let (n_tps, inputs, output) = match str.as_slice() { - "size_of" | - "pref_align_of" | "min_align_of" => (1u, ~[], ty::mk_uint()), - "init" => (1u, ~[], param(ccx, 0u)), - "uninit" => (1u, ~[], param(ccx, 0u)), - "forget" => (1u, ~[ param(ccx, 0) ], ty::mk_nil()), - "transmute" => (2, ~[ param(ccx, 0) ], param(ccx, 1)), - "move_val" | "move_val_init" => { - (1u, - ~[ - ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), param(ccx, 0)), - param(ccx, 0u) - ], - ty::mk_nil()) - } - "needs_drop" => (1u, ~[], ty::mk_bool()), - - "atomic_cxchg" | "atomic_cxchg_acq"| "atomic_cxchg_rel" => { - (0, - ~[ - ty::mk_mut_rptr(tcx, - ty::re_bound(ty::br_anon(0)), - ty::mk_int()), - ty::mk_int(), - ty::mk_int() - ], - ty::mk_int()) - } - "atomic_load" | "atomic_load_acq" => { - (0, - ~[ - ty::mk_imm_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()) - ], - ty::mk_int()) - } - "atomic_store" | "atomic_store_rel" => { - (0, - ~[ - ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()), - ty::mk_int() - ], - ty::mk_nil()) - } - "atomic_xchg" | "atomic_xadd" | "atomic_xsub" | - "atomic_xchg_acq" | "atomic_xadd_acq" | "atomic_xsub_acq" | - "atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => { - (0, - ~[ - ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()), - ty::mk_int() - ], - ty::mk_int()) - } - - "get_tydesc" => { - // FIXME (#3730): return *intrinsic::tydesc, not *() - (1u, ~[], ty::mk_nil_ptr(ccx.tcx)) - } - "visit_tydesc" => { - let tydesc_name = special_idents::tydesc; - assert!(tcx.intrinsic_defs.contains_key(&tydesc_name)); - let (_, tydesc_ty) = tcx.intrinsic_defs.get_copy(&tydesc_name); - let (_, visitor_object_ty) = ty::visitor_object_ty(tcx); - let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt { - ty: tydesc_ty, - mutbl: ast::m_imm - }); - (0, ~[ td_ptr, visitor_object_ty ], ty::mk_nil()) - } - "frame_address" => { - let fty = ty::mk_closure(ccx.tcx, ty::ClosureTy { - purity: ast::impure_fn, - sigil: ast::BorrowedSigil, - onceness: ast::Once, - region: ty::re_bound(ty::br_anon(0)), - bounds: ty::EmptyBuiltinBounds(), - sig: ty::FnSig { - bound_lifetime_names: opt_vec::Empty, - inputs: ~[ty::mk_imm_ptr(ccx.tcx, ty::mk_mach_uint(ast::ty_u8))], - output: ty::mk_nil() - } - }); - (0u, ~[fty], ty::mk_nil()) - } - "morestack_addr" => { - (0u, ~[], ty::mk_nil_ptr(ccx.tcx)) - } - "memcpy32" => { - (1, - ~[ - ty::mk_ptr(tcx, ty::mt { - ty: param(ccx, 0), - mutbl: ast::m_mutbl - }), - ty::mk_ptr(tcx, ty::mt { - ty: param(ccx, 0), - mutbl: ast::m_imm - }), - ty::mk_u32() - ], - ty::mk_nil()) - } - "memcpy64" => { - (1, - ~[ - ty::mk_ptr(tcx, ty::mt { - ty: param(ccx, 0), - mutbl: ast::m_mutbl - }), - ty::mk_ptr(tcx, ty::mt { - ty: param(ccx, 0), - mutbl: ast::m_imm - }), - ty::mk_u64() - ], - ty::mk_nil()) - } - "memmove32" => { - (1, - ~[ - ty::mk_ptr(tcx, ty::mt { - ty: param(ccx, 0), - mutbl: ast::m_mutbl - }), - ty::mk_ptr(tcx, ty::mt { - ty: param(ccx, 0), + let nm = ccx.tcx.sess.str_of(it.ident); + let name = nm.as_slice(); + let (n_tps, inputs, output) = if name.starts_with("atomic_") { + let split : ~[&str] = name.split_iter('_').collect(); + assert!(split.len() >= 2, "Atomic intrinsic not correct format"); + + //We only care about the operation here + match split[1] { + "cxchg" => (0, ~[ty::mk_mut_rptr(tcx, + ty::re_bound(ty::br_anon(0)), + ty::mk_int()), + ty::mk_int(), + ty::mk_int() + ], ty::mk_int()), + "load" => (0, + ~[ + ty::mk_imm_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()) + ], + ty::mk_int()), + "store" => (0, + ~[ + ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()), + ty::mk_int() + ], + ty::mk_nil()), + + "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | + "min" | "umax" | "umin" => { + (0, ~[ty::mk_mut_rptr(tcx, + ty::re_bound(ty::br_anon(0)), + ty::mk_int()), ty::mk_int() ], ty::mk_int()) + } + + op => { + tcx.sess.span_err(it.span, + fmt!("unrecognized atomic operation function: `%s`", + op)); + return; + } + } + + } else { + match name { + "size_of" | + "pref_align_of" | "min_align_of" => (1u, ~[], ty::mk_uint()), + "init" => (1u, ~[], param(ccx, 0u)), + "uninit" => (1u, ~[], param(ccx, 0u)), + "forget" => (1u, ~[ param(ccx, 0) ], ty::mk_nil()), + "transmute" => (2, ~[ param(ccx, 0) ], param(ccx, 1)), + "move_val" | "move_val_init" => { + (1u, + ~[ + ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), param(ccx, 0)), + param(ccx, 0u) + ], + ty::mk_nil()) + } + "needs_drop" => (1u, ~[], ty::mk_bool()), + "contains_managed" => (1u, ~[], ty::mk_bool()), + "atomic_xchg" | "atomic_xadd" | "atomic_xsub" | + "atomic_xchg_acq" | "atomic_xadd_acq" | "atomic_xsub_acq" | + "atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => { + (0, + ~[ + ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()), + ty::mk_int() + ], + ty::mk_int()) + } + + "get_tydesc" => { + let tydesc_ty = ty::get_tydesc_ty(ccx.tcx); + let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt { + ty: tydesc_ty, mutbl: ast::m_imm - }), - ty::mk_u32() - ], - ty::mk_nil()) - } - "memmove64" => { - (1, - ~[ - ty::mk_ptr(tcx, ty::mt { - ty: param(ccx, 0), - mutbl: ast::m_mutbl - }), - ty::mk_ptr(tcx, ty::mt { - ty: param(ccx, 0), + }); + (1u, ~[], td_ptr) + } + "visit_tydesc" => { + let tydesc_ty = ty::get_tydesc_ty(ccx.tcx); + let (_, visitor_object_ty) = ty::visitor_object_ty(tcx); + let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt { + ty: tydesc_ty, mutbl: ast::m_imm - }), - ty::mk_u64() - ], - ty::mk_nil()) - } - "memset32" => { - (1, - ~[ - ty::mk_ptr(tcx, ty::mt { - ty: param(ccx, 0), - mutbl: ast::m_mutbl - }), - ty::mk_u8(), - ty::mk_u32() - ], - ty::mk_nil()) - } - "memset64" => { - (1, - ~[ - ty::mk_ptr(tcx, ty::mt { - ty: param(ccx, 0), - mutbl: ast::m_mutbl - }), - ty::mk_u8(), - ty::mk_u64() - ], - ty::mk_nil()) - } - "sqrtf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "sqrtf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "powif32" => { - (0, - ~[ ty::mk_f32(), ty::mk_i32() ], - ty::mk_f32()) - } - "powif64" => { - (0, - ~[ ty::mk_f64(), ty::mk_i32() ], - ty::mk_f64()) - } - "sinf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "sinf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "cosf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "cosf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "powf32" => { - (0, - ~[ ty::mk_f32(), ty::mk_f32() ], - ty::mk_f32()) - } - "powf64" => { - (0, - ~[ ty::mk_f64(), ty::mk_f64() ], - ty::mk_f64()) - } - "expf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "expf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "exp2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "exp2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "logf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "logf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "log10f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "log10f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "log2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "log2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "fmaf32" => { - (0, - ~[ ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ], - ty::mk_f32()) - } - "fmaf64" => { - (0, - ~[ ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ], - ty::mk_f64()) - } - "fabsf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "fabsf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "floorf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "floorf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "ceilf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "ceilf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "truncf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), - "truncf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), - "ctpop8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()), - "ctpop16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()), - "ctpop32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()), - "ctpop64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()), - "ctlz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()), - "ctlz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()), - "ctlz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()), - "ctlz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()), - "cttz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()), - "cttz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()), - "cttz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()), - "cttz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()), - "bswap16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()), - "bswap32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()), - "bswap64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()), - ref other => { - tcx.sess.span_err(it.span, - fmt!("unrecognized intrinsic function: `%s`", - *other)); - return; + }); + (0, ~[ td_ptr, visitor_object_ty ], ty::mk_nil()) + } + "frame_address" => { + let fty = ty::mk_closure(ccx.tcx, ty::ClosureTy { + purity: ast::impure_fn, + sigil: ast::BorrowedSigil, + onceness: ast::Once, + region: ty::re_bound(ty::br_anon(0)), + bounds: ty::EmptyBuiltinBounds(), + sig: ty::FnSig { + bound_lifetime_names: opt_vec::Empty, + inputs: ~[ty::mk_imm_ptr(ccx.tcx, ty::mk_mach_uint(ast::ty_u8))], + output: ty::mk_nil() + } + }); + (0u, ~[fty], ty::mk_nil()) + } + "morestack_addr" => { + (0u, ~[], ty::mk_nil_ptr(ccx.tcx)) + } + "memcpy32" => { + (1, + ~[ + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_mutbl + }), + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_imm + }), + ty::mk_u32() + ], + ty::mk_nil()) + } + "memcpy64" => { + (1, + ~[ + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_mutbl + }), + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_imm + }), + ty::mk_u64() + ], + ty::mk_nil()) + } + "memmove32" => { + (1, + ~[ + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_mutbl + }), + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_imm + }), + ty::mk_u32() + ], + ty::mk_nil()) + } + "memmove64" => { + (1, + ~[ + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_mutbl + }), + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_imm + }), + ty::mk_u64() + ], + ty::mk_nil()) + } + "memset32" => { + (1, + ~[ + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_mutbl + }), + ty::mk_u8(), + ty::mk_u32() + ], + ty::mk_nil()) + } + "memset64" => { + (1, + ~[ + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_mutbl + }), + ty::mk_u8(), + ty::mk_u64() + ], + ty::mk_nil()) + } + "sqrtf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "sqrtf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "powif32" => { + (0, + ~[ ty::mk_f32(), ty::mk_i32() ], + ty::mk_f32()) + } + "powif64" => { + (0, + ~[ ty::mk_f64(), ty::mk_i32() ], + ty::mk_f64()) + } + "sinf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "sinf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "cosf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "cosf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "powf32" => { + (0, + ~[ ty::mk_f32(), ty::mk_f32() ], + ty::mk_f32()) + } + "powf64" => { + (0, + ~[ ty::mk_f64(), ty::mk_f64() ], + ty::mk_f64()) + } + "expf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "expf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "exp2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "exp2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "logf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "logf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "log10f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "log10f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "log2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "log2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "fmaf32" => { + (0, + ~[ ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ], + ty::mk_f32()) + } + "fmaf64" => { + (0, + ~[ ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ], + ty::mk_f64()) + } + "fabsf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "fabsf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "floorf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "floorf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "ceilf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "ceilf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "truncf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()), + "truncf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()), + "ctpop8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()), + "ctpop16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()), + "ctpop32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()), + "ctpop64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()), + "ctlz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()), + "ctlz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()), + "ctlz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()), + "ctlz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()), + "cttz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()), + "cttz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()), + "cttz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()), + "cttz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()), + "bswap16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()), + "bswap32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()), + "bswap64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()), + ref other => { + tcx.sess.span_err(it.span, + fmt!("unrecognized intrinsic function: `%s`", + *other)); + return; + } } }; let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 4cedb71245a..2e41649e4db 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/* +/*! The region check is a final pass that runs over the AST after we have inferred the type constraints but before we have actually finalized @@ -27,7 +27,6 @@ this point a bit better. */ -use core::prelude::*; use middle::freevars::get_freevars; use middle::ty::{re_scope}; @@ -36,11 +35,13 @@ use middle::typeck::check::FnCtxt; use middle::typeck::check::regionmanip::relate_nested_regions; use middle::typeck::infer::resolve_and_force_all_but_regions; use middle::typeck::infer::resolve_type; -use util::ppaux::{note_and_explain_region, ty_to_str, region_to_str}; +use middle::typeck::infer; +use util::ppaux::{note_and_explain_region, ty_to_str, + region_to_str}; use middle::pat_util; -use core::result; -use core::uint; +use std::result; +use std::uint; use syntax::ast::{ManagedSigil, OwnedSigil, BorrowedSigil}; use syntax::ast::{def_arg, def_binding, def_local, def_self, def_upvar}; use syntax::ast; @@ -184,7 +185,7 @@ fn visit_block(b: &ast::blk, (rcx, v): (@mut Rcx, rvt)) { fn visit_arm(arm: &ast::arm, (rcx, v): (@mut Rcx, rvt)) { // see above - for arm.pats.each |&p| { + for arm.pats.iter().advance |&p| { constrain_bindings_in_pat(p, rcx); } @@ -225,12 +226,14 @@ fn constrain_bindings_in_pat(pat: @ast::pat, rcx: @mut Rcx) { // variable's type enclose at least the variable's scope. let encl_region = tcx.region_maps.encl_region(id); - constrain_regions_in_type_of_node(rcx, id, encl_region, span); + constrain_regions_in_type_of_node( + rcx, id, encl_region, + infer::BindingTypeIsNotValidAtDecl(span)); } } fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) { - debug!("regionck::visit_expr(e=%s)", rcx.fcx.expr_to_str(expr)); + debug!("regionck::visit_expr(e=?)"); let has_method_map = rcx.fcx.inh.method_map.contains_key(&expr.id); @@ -267,7 +270,7 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) { } ast::expr_match(_, ref arms) => { tcx.region_maps.record_cleanup_scope(expr.id); - for arms.each |arm| { + for arms.iter().advance |arm| { for arm.guard.iter().advance |guard| { tcx.region_maps.record_cleanup_scope(guard.id); } @@ -299,7 +302,8 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) { // // FIXME(#6268) remove to support nested method calls constrain_regions_in_type_of_node( - rcx, expr.id, ty::re_scope(expr.id), expr.span); + rcx, expr.id, ty::re_scope(expr.id), + infer::AutoBorrow(expr.span)); } } _ => {} @@ -360,10 +364,13 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) { // explaining how it goes about doing that. let target_ty = rcx.resolve_node_type(expr.id); match ty::get(target_ty).sty { - ty::ty_trait(_, _, ty::RegionTraitStore(trait_region), _) => { + ty::ty_trait(_, _, ty::RegionTraitStore(trait_region), _, _) => { let source_ty = rcx.fcx.expr_ty(source); - constrain_regions_in_type(rcx, trait_region, - expr.span, source_ty); + constrain_regions_in_type( + rcx, + trait_region, + infer::RelateObjectBound(expr.span), + source_ty); } _ => () } @@ -380,7 +387,8 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) { // // FIXME(#6268) nested method calls requires that this rule change let ty0 = rcx.resolve_node_type(expr.id); - constrain_regions_in_type(rcx, ty::re_scope(expr.id), expr.span, ty0); + constrain_regions_in_type(rcx, ty::re_scope(expr.id), + infer::AddrOf(expr.span), ty0); } ast::expr_match(discr, ref arms) => { @@ -419,20 +427,8 @@ fn constrain_callee(rcx: @mut Rcx, match ty::get(callee_ty).sty { ty::ty_bare_fn(*) => { } ty::ty_closure(ref closure_ty) => { - match rcx.fcx.mk_subr(true, callee_expr.span, - call_region, closure_ty.region) { - result::Err(_) => { - tcx.sess.span_err( - callee_expr.span, - fmt!("cannot invoke closure outside of its lifetime")); - note_and_explain_region( - tcx, - "the closure is only valid for ", - closure_ty.region, - ""); - } - result::Ok(_) => {} - } + rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span), + call_region, closure_ty.region); } _ => { // this should not happen, but it does if the program is @@ -476,11 +472,12 @@ fn constrain_call(rcx: @mut Rcx, let callee_scope = call_expr.id; let callee_region = ty::re_scope(callee_scope); - for arg_exprs.each |&arg_expr| { + for arg_exprs.iter().advance |&arg_expr| { // ensure that any regions appearing in the argument type are // valid for at least the lifetime of the function: constrain_regions_in_type_of_node( - rcx, arg_expr.id, callee_region, arg_expr.span); + rcx, arg_expr.id, callee_region, + infer::CallArg(arg_expr.span)); // unfortunately, there are two means of taking implicit // references, and we need to propagate constraints as a @@ -494,7 +491,7 @@ fn constrain_call(rcx: @mut Rcx, // as loop above, but for receiver for receiver.iter().advance |&r| { constrain_regions_in_type_of_node( - rcx, r.id, callee_region, r.span); + rcx, r.id, callee_region, infer::CallRcvr(r.span)); if implicitly_ref_args { guarantor::for_by_ref(rcx, r, callee_scope); } @@ -503,7 +500,8 @@ fn constrain_call(rcx: @mut Rcx, // constrain regions that may appear in the return type to be // valid for the function call: constrain_regions_in_type( - rcx, callee_region, call_expr.span, fn_sig.output); + rcx, callee_region, infer::CallReturn(call_expr.span), + fn_sig.output); } fn constrain_derefs(rcx: @mut Rcx, @@ -520,8 +518,7 @@ fn constrain_derefs(rcx: @mut Rcx, let tcx = rcx.fcx.tcx(); let r_deref_expr = ty::re_scope(deref_expr.id); for uint::range(0, derefs) |i| { - debug!("constrain_derefs(deref_expr=%s, derefd_ty=%s, derefs=%?/%?", - rcx.fcx.expr_to_str(deref_expr), + debug!("constrain_derefs(deref_expr=?, derefd_ty=%s, derefs=%?/%?", rcx.fcx.infcx().ty_to_str(derefd_ty), i, derefs); @@ -547,20 +544,8 @@ pub fn mk_subregion_due_to_derefence(rcx: @mut Rcx, deref_span: span, minimum_lifetime: ty::Region, maximum_lifetime: ty::Region) { - match rcx.fcx.mk_subr(true, deref_span, - minimum_lifetime, maximum_lifetime) { - result::Ok(*) => {} - result::Err(*) => { - rcx.tcx().sess.span_err( - deref_span, - fmt!("dereference of reference outside its lifetime")); - note_and_explain_region( - rcx.tcx(), - "the reference is only valid for ", - maximum_lifetime, - ""); - } - } + rcx.fcx.mk_subr(true, infer::DerefPointer(deref_span), + minimum_lifetime, maximum_lifetime) } @@ -576,27 +561,15 @@ fn constrain_index(rcx: @mut Rcx, let tcx = rcx.fcx.tcx(); - debug!("constrain_index(index_expr=%s, indexed_ty=%s", - rcx.fcx.expr_to_str(index_expr), + debug!("constrain_index(index_expr=?, indexed_ty=%s", rcx.fcx.infcx().ty_to_str(indexed_ty)); let r_index_expr = ty::re_scope(index_expr.id); match ty::get(indexed_ty).sty { ty::ty_estr(ty::vstore_slice(r_ptr)) | ty::ty_evec(_, ty::vstore_slice(r_ptr)) => { - match rcx.fcx.mk_subr(true, index_expr.span, r_index_expr, r_ptr) { - result::Ok(*) => {} - result::Err(*) => { - tcx.sess.span_err( - index_expr.span, - fmt!("index of slice outside its lifetime")); - note_and_explain_region( - tcx, - "the slice is only valid for ", - r_ptr, - ""); - } - } + rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span), + r_index_expr, r_ptr); } _ => {} @@ -614,30 +587,13 @@ fn constrain_free_variables(rcx: @mut Rcx, let tcx = rcx.fcx.ccx.tcx; debug!("constrain_free_variables(%s, %s)", region.repr(tcx), expr.repr(tcx)); - for get_freevars(tcx, expr.id).each |freevar| { + for get_freevars(tcx, expr.id).iter().advance |freevar| { debug!("freevar def is %?", freevar.def); let def = freevar.def; let en_region = encl_region_of_def(rcx.fcx, def); debug!("en_region = %s", en_region.repr(tcx)); - match rcx.fcx.mk_subr(true, freevar.span, - region, en_region) { - result::Ok(()) => {} - result::Err(_) => { - tcx.sess.span_err( - freevar.span, - "captured variable does not outlive the enclosing closure"); - note_and_explain_region( - tcx, - "captured variable is valid for ", - en_region, - ""); - note_and_explain_region( - tcx, - "closure is valid for ", - region, - ""); - } - } + rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span), + region, en_region); } } @@ -645,7 +601,7 @@ fn constrain_regions_in_type_of_node( rcx: @mut Rcx, id: ast::node_id, minimum_lifetime: ty::Region, - span: span) -> bool + origin: infer::SubregionOrigin) -> bool { //! Guarantees that any lifetimes which appear in the type of //! the node `id` (after applying adjustments) are valid for at @@ -658,18 +614,18 @@ fn constrain_regions_in_type_of_node( // report errors later on in the writeback phase. let ty0 = rcx.resolve_node_type(id); let adjustment = rcx.fcx.inh.adjustments.find_copy(&id); - let ty = ty::adjust_ty(tcx, span, ty0, adjustment); + let ty = ty::adjust_ty(tcx, origin.span(), ty0, adjustment); debug!("constrain_regions_in_type_of_node(\ ty=%s, ty0=%s, id=%d, minimum_lifetime=%?, adjustment=%?)", ty_to_str(tcx, ty), ty_to_str(tcx, ty0), id, minimum_lifetime, adjustment); - constrain_regions_in_type(rcx, minimum_lifetime, span, ty) + constrain_regions_in_type(rcx, minimum_lifetime, origin, ty) } fn constrain_regions_in_type( rcx: @mut Rcx, minimum_lifetime: ty::Region, - span: span, + origin: infer::SubregionOrigin, ty: ty::t) -> bool { /*! @@ -690,53 +646,27 @@ fn constrain_regions_in_type( let tcx = rcx.fcx.ccx.tcx; debug!("constrain_regions_in_type(minimum_lifetime=%s, ty=%s)", - region_to_str(tcx, minimum_lifetime), + region_to_str(tcx, "", false, minimum_lifetime), ty_to_str(tcx, ty)); do relate_nested_regions(tcx, Some(minimum_lifetime), ty) |r_sub, r_sup| { debug!("relate(r_sub=%s, r_sup=%s)", - region_to_str(tcx, r_sub), - region_to_str(tcx, r_sup)); + region_to_str(tcx, "", false, r_sub), + region_to_str(tcx, "", false, r_sup)); if r_sup.is_bound() || r_sub.is_bound() { // a bound region is one which appears inside an fn type. // (e.g., the `&` in `fn(&T)`). Such regions need not be // constrained by `minimum_lifetime` as they are placeholders // for regions that are as-yet-unknown. + } else if r_sub == minimum_lifetime { + rcx.fcx.mk_subr( + true, origin, + r_sub, r_sup); } else { - match rcx.fcx.mk_subr(true, span, r_sub, r_sup) { - result::Err(_) => { - if r_sub == minimum_lifetime { - tcx.sess.span_err( - span, - fmt!("reference is not valid outside of its lifetime")); - note_and_explain_region( - tcx, - "the reference is only valid for ", - r_sup, - ""); - } else { - tcx.sess.span_err( - span, - fmt!("in type `%s`, pointer has a longer lifetime than \ - the data it references", - rcx.fcx.infcx().ty_to_str(ty))); - note_and_explain_region( - tcx, - "the pointer is valid for ", - r_sub, - ""); - note_and_explain_region( - tcx, - "but the referenced data is only valid for ", - r_sup, - ""); - } - rcx.errors_reported += 1u; - } - result::Ok(()) => { - } - } + rcx.fcx.mk_subr( + true, infer::ReferenceOutlivesReferent(ty, origin.span()), + r_sub, r_sup); } } @@ -790,16 +720,16 @@ pub mod guarantor { * but more special purpose. */ - use core::prelude::*; - use middle::typeck::check::regionck::{Rcx, infallibly_mk_subr}; + use middle::typeck::check::regionck::Rcx; use middle::typeck::check::regionck::mk_subregion_due_to_derefence; + use middle::typeck::infer; use middle::ty; use syntax::ast; use syntax::codemap::span; use util::ppaux::{ty_to_str}; - use core::uint; + use std::uint; pub fn for_addr_of(rcx: @mut Rcx, expr: @ast::expr, base: @ast::expr) { /*! @@ -808,7 +738,7 @@ pub mod guarantor { * to the lifetime of its guarantor (if any). */ - debug!("guarantor::for_addr_of(base=%s)", rcx.fcx.expr_to_str(base)); + debug!("guarantor::for_addr_of(base=?)"); let guarantor = guarantor(rcx, base); link(rcx, expr.span, expr.id, guarantor); @@ -824,8 +754,8 @@ pub mod guarantor { debug!("regionck::for_match()"); let discr_guarantor = guarantor(rcx, discr); debug!("discr_guarantor=%s", discr_guarantor.repr(rcx.tcx())); - for arms.each |arm| { - for arm.pats.each |pat| { + for arms.iter().advance |arm| { + for arm.pats.iter().advance |pat| { link_ref_bindings_in_pat(rcx, *pat, discr_guarantor); } } @@ -842,8 +772,7 @@ pub mod guarantor { * region pointers. */ - debug!("guarantor::for_autoref(expr=%s, autoref=%?)", - rcx.fcx.expr_to_str(expr), autoref); + debug!("guarantor::for_autoref(autoref=%?)", autoref); let mut expr_ct = categorize_unadjusted(rcx, expr); debug!(" unadjusted cat=%?", expr_ct.cat); @@ -874,9 +803,11 @@ pub mod guarantor { rcx: @mut Rcx, expr: @ast::expr, sub_region: ty::Region, - sup_region: Option<ty::Region>) { + sup_region: Option<ty::Region>) + { for sup_region.iter().advance |r| { - infallibly_mk_subr(rcx, true, expr.span, sub_region, *r); + rcx.fcx.mk_subr(true, infer::Reborrow(expr.span), + sub_region, *r); } } } @@ -934,7 +865,7 @@ pub mod guarantor { let tcx = rcx.fcx.ccx.tcx; debug!("rptr_ty=%s", ty_to_str(tcx, rptr_ty)); let r = ty::ty_region(tcx, span, rptr_ty); - infallibly_mk_subr(rcx, true, span, r, bound); + rcx.fcx.mk_subr(true, infer::Reborrow(span), r, bound); } } @@ -970,7 +901,7 @@ pub mod guarantor { * `&expr`). */ - debug!("guarantor(expr=%s)", rcx.fcx.expr_to_str(expr)); + debug!("guarantor()"); match expr.node { ast::expr_unary(_, ast::deref, b) => { let cat = categorize(rcx, b); @@ -1034,7 +965,7 @@ pub mod guarantor { } fn categorize(rcx: @mut Rcx, expr: @ast::expr) -> ExprCategorization { - debug!("categorize(expr=%s)", rcx.fcx.expr_to_str(expr)); + debug!("categorize()"); let mut expr_ct = categorize_unadjusted(rcx, expr); debug!("before adjustments, cat=%?", expr_ct.cat); @@ -1086,7 +1017,7 @@ pub mod guarantor { fn categorize_unadjusted(rcx: @mut Rcx, expr: @ast::expr) -> ExprCategorizationType { - debug!("categorize_unadjusted(expr=%s)", rcx.fcx.expr_to_str(expr)); + debug!("categorize_unadjusted()"); let guarantor = { if rcx.fcx.inh.method_map.contains_key(&expr.id) { @@ -1217,7 +1148,7 @@ pub mod guarantor { link_ref_bindings_in_pats(rcx, pats, guarantor); } ast::pat_struct(_, ref fpats, _) => { - for fpats.each |fpat| { + for fpats.iter().advance |fpat| { link_ref_bindings_in_pat(rcx, fpat.pat, guarantor); } } @@ -1258,33 +1189,9 @@ pub mod guarantor { fn link_ref_bindings_in_pats(rcx: @mut Rcx, pats: &~[@ast::pat], guarantor: Option<ty::Region>) { - for pats.each |pat| { + for pats.iter().advance |pat| { link_ref_bindings_in_pat(rcx, *pat, guarantor); } } } - -pub fn infallibly_mk_subr(rcx: @mut Rcx, - a_is_expected: bool, - span: span, - a: ty::Region, - b: ty::Region) { - /*! - * Constrains `a` to be a subregion of `b`. In many cases, we - * know that this can never yield an error due to the way that - * region inferencing works. Therefore just report a bug if we - * ever see `Err(_)`. - */ - - match rcx.fcx.mk_subr(a_is_expected, span, a, b) { - result::Ok(()) => {} - result::Err(e) => { - rcx.fcx.ccx.tcx.sess.span_bug( - span, - fmt!("Supposedly infallible attempt to \ - make %? < %? failed: %?", - a, b, e)); - } - } -} diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index a5cfa629cf0..02c003b7525 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -10,7 +10,6 @@ // #[warn(deprecated_mode)]; -use core::prelude::*; use middle::ty; @@ -103,8 +102,8 @@ pub fn replace_bound_regions_in_fn_sig( } // For each type `ty` in `tys`... - do tys.foldl(isr) |isr, ty| { - let mut isr = *isr; + do tys.iter().fold(isr) |isr, ty| { + let mut isr = isr; // Using fold_regions is inefficient, because it // constructs new types, but it avoids code duplication in @@ -112,7 +111,7 @@ pub fn replace_bound_regions_in_fn_sig( // kinds of types. This had already caused me several // bugs so I decided to switch over. do ty::fold_regions(tcx, *ty) |r, in_fn| { - if !in_fn { isr = append_isr(isr, to_r, r); } + if !in_fn { isr = append_isr(isr, |br| to_r(br), r); } r }; @@ -149,7 +148,7 @@ pub fn replace_bound_regions_in_fn_sig( tcx.sess.bug( fmt!("Bound region not found in \ in_scope_regions list: %s", - region_to_str(tcx, r))); + region_to_str(tcx, "", false, r))); } } } @@ -211,18 +210,18 @@ pub fn relate_nested_regions( match ty::get(ty).sty { ty::ty_rptr(r, ref mt) | ty::ty_evec(ref mt, ty::vstore_slice(r)) => { - relate(*the_stack, r, relate_op); + relate(*the_stack, r, |x,y| relate_op(x,y)); the_stack.push(r); - walk_ty(tcx, the_stack, mt.ty, relate_op); + walk_ty(tcx, the_stack, mt.ty, |x,y| relate_op(x,y)); the_stack.pop(); } _ => { ty::fold_regions_and_ty( tcx, ty, - |r| { relate(*the_stack, r, relate_op); r }, - |t| { walk_ty(tcx, the_stack, t, relate_op); t }, - |t| { walk_ty(tcx, the_stack, t, relate_op); t }); + |r| { relate( *the_stack, r, |x,y| relate_op(x,y)); r }, + |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t }, + |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t }); } } } @@ -231,7 +230,7 @@ pub fn relate_nested_regions( r_sub: ty::Region, relate_op: &fn(ty::Region, ty::Region)) { - for the_stack.each |&r| { + for the_stack.iter().advance |&r| { if !r.is_bound() && !r_sub.is_bound() { relate_op(r, r_sub); } @@ -259,14 +258,14 @@ pub fn relate_free_regions( debug!("relate_free_regions >>"); let mut all_tys = ~[]; - for fn_sig.inputs.each |arg| { + for fn_sig.inputs.iter().advance |arg| { all_tys.push(*arg); } for self_ty.iter().advance |&t| { all_tys.push(t); } - for all_tys.each |&t| { + for all_tys.iter().advance |&t| { debug!("relate_free_regions(t=%s)", ppaux::ty_to_str(tcx, t)); relate_nested_regions(tcx, None, t, |a, b| { match (&a, &b) { diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 197bf5d82cc..d9086334439 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use middle::ty::param_ty; use middle::ty; @@ -17,15 +16,15 @@ use middle::typeck::check::{structurally_resolved_type}; use middle::typeck::infer::fixup_err_to_str; use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; use middle::typeck::infer; -use middle::typeck::{CrateCtxt, vtable_origin, vtable_param, vtable_res}; -use middle::typeck::vtable_static; +use middle::typeck::{CrateCtxt, vtable_origin, vtable_res}; +use middle::typeck::{vtable_static, vtable_param, vtable_self}; use middle::subst::Subst; use util::common::indenter; use util::ppaux::tys_to_str; use util::ppaux; -use core::hashmap::HashSet; -use core::result; +use std::hashmap::HashSet; +use std::result; use syntax::ast; use syntax::ast_util; use syntax::codemap::span; @@ -64,11 +63,11 @@ pub struct VtableContext { } impl VtableContext { - pub fn tcx(&const self) -> ty::ctxt { self.ccx.tcx } + pub fn tcx(&self) -> ty::ctxt { self.ccx.tcx } } fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool { - type_param_defs.any( + type_param_defs.iter().any_( |type_param_def| !type_param_def.bounds.trait_bounds.is_empty()) } @@ -88,8 +87,9 @@ fn lookup_vtables(vcx: &VtableContext, let tcx = vcx.tcx(); let mut result = ~[]; let mut i = 0u; - for substs.tps.each |ty| { + for substs.tps.iter().advance |ty| { // ty is the value supplied for the type parameter A... + let mut param_result = ~[]; for ty::each_bound_trait_and_supertraits( tcx, type_param_defs[i].bounds) |trait_ref| @@ -101,22 +101,23 @@ fn lookup_vtables(vcx: &VtableContext, // Substitute the values of the type parameters that may // appear in the bound. - let trait_ref = (*trait_ref).subst(tcx, substs); + let trait_ref = trait_ref.subst(tcx, substs); debug!("after subst: %s", trait_ref.repr(tcx)); - match lookup_vtable(vcx, location_info, *ty, &trait_ref, is_early) { - Some(vtable) => result.push(vtable), + match lookup_vtable(vcx, location_info, *ty, trait_ref, is_early) { + Some(vtable) => param_result.push(vtable), None => { vcx.tcx().sess.span_fatal( location_info.span, fmt!("failed to find an implementation of \ trait %s for %s", - vcx.infcx.trait_ref_to_str(&trait_ref), + vcx.infcx.trait_ref_to_str(trait_ref), vcx.infcx.ty_to_str(*ty))); } } } + result.push(@param_result); i += 1u; } debug!("lookup_vtables result(\ @@ -139,10 +140,11 @@ fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo, let t = ty::mk_trait(tcx, id, substs, ty::RegionTraitStore(ty::re_static), - ast::m_imm); + ast::m_imm, + ty::EmptyBuiltinBounds()); do fixup_ty(vcx, location_info, t, is_early).map |t_f| { match ty::get(*t_f).sty { - ty::ty_trait(_, ref substs_f, _, _) => (/*bad*/copy *substs_f), + ty::ty_trait(_, ref substs_f, _, _, _) => (/*bad*/copy *substs_f), _ => fail!("t_f should be a trait") } } @@ -150,8 +152,8 @@ fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo, fn relate_trait_refs(vcx: &VtableContext, location_info: &LocationInfo, - act_trait_ref: &ty::TraitRef, - exp_trait_ref: &ty::TraitRef) + act_trait_ref: @ty::TraitRef, + exp_trait_ref: @ty::TraitRef) { /*! * @@ -160,8 +162,11 @@ fn relate_trait_refs(vcx: &VtableContext, * error otherwise. */ - match infer::mk_sub_trait_refs(vcx.infcx, false, location_info.span, - act_trait_ref, exp_trait_ref) + match infer::mk_sub_trait_refs(vcx.infcx, + false, + infer::RelateTraitRefs(location_info.span), + act_trait_ref, + exp_trait_ref) { result::Ok(()) => {} // Ok. result::Err(ref err) => { @@ -189,7 +194,7 @@ fn relate_trait_refs(vcx: &VtableContext, fn lookup_vtable(vcx: &VtableContext, location_info: &LocationInfo, ty: ty::t, - trait_ref: &ty::TraitRef, + trait_ref: @ty::TraitRef, is_early: bool) -> Option<vtable_origin> { @@ -236,6 +241,17 @@ fn lookup_vtable(vcx: &VtableContext, } } + ty::ty_self(trait_id) => { + debug!("trying to find %? vtable for type %?", + trait_ref.def_id, trait_id); + + if trait_id == trait_ref.def_id { + let vtable = vtable_self(trait_id); + debug!("found self vtable: %?", vtable); + return Some(vtable); + } + } + _ => { let mut found = ~[]; @@ -291,7 +307,8 @@ fn lookup_vtable(vcx: &VtableContext, } = impl_self_ty(vcx, location_info, im.did); match infer::mk_subty(vcx.infcx, false, - location_info.span, + infer::RelateSelfType( + location_info.span), ty, for_ty) { result::Err(_) => loop, @@ -324,11 +341,10 @@ fn lookup_vtable(vcx: &VtableContext, vcx.infcx.trait_ref_to_str(trait_ref), vcx.infcx.trait_ref_to_str(of_trait_ref)); - let of_trait_ref = - (*of_trait_ref).subst(tcx, &substs); + let of_trait_ref = of_trait_ref.subst(tcx, &substs); relate_trait_refs( vcx, location_info, - &of_trait_ref, trait_ref); + of_trait_ref, trait_ref); // Recall that trait_ref -- the trait type // we're casting to -- is the trait with @@ -437,7 +453,7 @@ fn fixup_ty(vcx: &VtableContext, fn connect_trait_tps(vcx: &VtableContext, location_info: &LocationInfo, impl_substs: &ty::substs, - trait_ref: &ty::TraitRef, + trait_ref: @ty::TraitRef, impl_did: ast::def_id) { let tcx = vcx.tcx(); @@ -448,8 +464,8 @@ fn connect_trait_tps(vcx: &VtableContext, "connect_trait_tps invoked on a type impl") }; - let impl_trait_ref = (*impl_trait_ref).subst(tcx, impl_substs); - relate_trait_refs(vcx, location_info, &impl_trait_ref, trait_ref); + let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); + relate_trait_refs(vcx, location_info, impl_trait_ref, trait_ref); } fn insert_vtables(fcx: @mut FnCtxt, @@ -466,6 +482,12 @@ pub fn location_info_for_expr(expr: @ast::expr) -> LocationInfo { id: expr.id } } +pub fn location_info_for_item(item: @ast::item) -> LocationInfo { + LocationInfo { + span: item.span, + id: item.id + } +} pub fn early_resolve_expr(ex: @ast::expr, fcx: @mut FnCtxt, @@ -530,7 +552,9 @@ pub fn early_resolve_expr(ex: @ast::expr, debug!("vtable resolution on expr %s", ex.repr(fcx.tcx())); let target_ty = fcx.expr_ty(ex); match ty::get(target_ty).sty { - ty::ty_trait(target_def_id, ref target_substs, store, target_mutbl) => { + // Bounds of type's contents are not checked here, but in kind.rs. + ty::ty_trait(target_def_id, ref target_substs, store, + target_mutbl, _bounds) => { fn mutability_allowed(a_mutbl: ast::mutability, b_mutbl: ast::mutability) -> bool { a_mutbl == b_mutbl || @@ -560,7 +584,7 @@ pub fn early_resolve_expr(ex: @ast::expr, ccx: fcx.ccx, infcx: fcx.infcx() }; - let target_trait_ref = ty::TraitRef { + let target_trait_ref = @ty::TraitRef { def_id: target_def_id, substs: ty::substs { tps: copy target_substs.tps, @@ -572,7 +596,7 @@ pub fn early_resolve_expr(ex: @ast::expr, lookup_vtable(&vcx, location_info, mt.ty, - &target_trait_ref, + target_trait_ref, is_early); match vtable_opt { Some(vtable) => { @@ -580,7 +604,8 @@ pub fn early_resolve_expr(ex: @ast::expr, // vtable (that is: "ex has vtable // <vtable>") if !is_early { - insert_vtables(fcx, ex.id, @~[vtable]); + insert_vtables(fcx, ex.id, + @~[@~[vtable]]); } } None => { @@ -600,7 +625,8 @@ pub fn early_resolve_expr(ex: @ast::expr, ty::RegionTraitStore(rb)) => { infer::mk_subr(fcx.infcx(), false, - ex.span, + infer::RelateObjectBound( + ex.span), rb, ra); } @@ -647,6 +673,27 @@ fn resolve_expr(ex: @ast::expr, visit::visit_expr(ex, (fcx, v)); } +pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { + let def_id = ast_util::local_def(impl_item.id); + match ty::impl_trait_ref(ccx.tcx, def_id) { + None => {}, + Some(trait_ref) => { + let infcx = infer::new_infer_ctxt(ccx.tcx); + let vcx = VtableContext { ccx: ccx, infcx: infcx }; + let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id); + + let vtbls = lookup_vtables(&vcx, + &location_info_for_item(impl_item), + *trait_def.generics.type_param_defs, + &trait_ref.substs, + false); + + // FIXME(#7450): Doesn't work cross crate + ccx.vtable_map.insert(impl_item.id, vtbls); + } + } +} + // Detect points where a trait-bounded type parameter is // instantiated, resolve the impls for the parameters. pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::blk) { diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index a60fa9ee0be..e5248e01ed7 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -12,7 +12,6 @@ // unresolved type variables and replaces "ty_var" types with their // substitutions. -use core::prelude::*; use middle::pat_util; use middle::ty; @@ -20,7 +19,8 @@ use middle::typeck::check::{FnCtxt, SelfInfo}; use middle::typeck::infer::{force_all, resolve_all, resolve_region}; use middle::typeck::infer::resolve_type; use middle::typeck::infer; -use middle::typeck::{vtable_origin, vtable_static, vtable_param}; +use middle::typeck::{vtable_res, vtable_origin}; +use middle::typeck::{vtable_static, vtable_param, vtable_self}; use middle::typeck::method_map_entry; use middle::typeck::write_substs_to_tcx; use middle::typeck::write_ty_to_tcx; @@ -84,7 +84,7 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { match fcx.inh.vtable_map.find(&id) { None => {} Some(origins) => { - let r_origins = @origins.map(|o| resolve_origin(fcx, sp, o)); + let r_origins = resolve_origins(fcx, sp, *origins); let vtable_map = fcx.ccx.vtable_map; vtable_map.insert(id, r_origins); debug!("writeback::resolve_vtable_map_entry(id=%d, vtables=%?)", @@ -92,18 +92,26 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { } } + fn resolve_origins(fcx: @mut FnCtxt, sp: span, + vtbls: vtable_res) -> vtable_res { + @vtbls.map(|os| @os.map(|o| resolve_origin(fcx, sp, o))) + } + fn resolve_origin(fcx: @mut FnCtxt, sp: span, origin: &vtable_origin) -> vtable_origin { match origin { &vtable_static(def_id, ref tys, origins) => { let r_tys = resolve_type_vars_in_types(fcx, sp, *tys); - let r_origins = @origins.map(|o| resolve_origin(fcx, sp, o)); + let r_origins = resolve_origins(fcx, sp, origins); vtable_static(def_id, r_tys, r_origins) } &vtable_param(n, b) => { vtable_param(n, b) } + &vtable_self(def_id) => { + vtable_self(def_id) + } } } } @@ -175,7 +183,7 @@ fn resolve_type_vars_for_node(wbcx: @mut WbCtxt, sp: span, id: ast::node_id) write_ty_to_tcx(tcx, id, t); for fcx.opt_node_ty_substs(id) |substs| { let mut new_tps = ~[]; - for substs.tps.each |subst| { + for substs.tps.iter().advance |subst| { match resolve_type_vars_in_type(fcx, sp, *subst) { Some(t) => new_tps.push(t), None => { wbcx.success = false; return None; } @@ -240,7 +248,7 @@ fn visit_expr(e: @ast::expr, (wbcx, v): (@mut WbCtxt, wb_vt)) { match e.node { ast::expr_fn_block(ref decl, _) => { - for decl.inputs.each |input| { + for decl.inputs.iter().advance |input| { let _ = resolve_type_vars_for_node(wbcx, e.span, input.id); } } @@ -341,7 +349,7 @@ pub fn resolve_type_vars_in_fn(fcx: @mut FnCtxt, self_info.span, self_info.self_id); } - for decl.inputs.each |arg| { + for decl.inputs.iter().advance |arg| { do pat_util::pat_bindings(fcx.tcx().def_map, arg.pat) |_bm, pat_id, span, _path| { resolve_type_vars_for_node(wbcx, span, pat_id); diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index d71820a67b3..24ac63ac7b0 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -14,11 +14,8 @@ // has at most one implementation for each type. Then we build a mapping from // each trait in the system to its implementations. -use core::prelude::*; -use driver; use metadata::csearch::{each_path, get_impl_trait}; -use metadata::csearch::{get_impls_for_mod}; use metadata::csearch; use metadata::cstore::{CStore, iter_crate_data}; use metadata::decoder::{dl_def, dl_field, dl_impl}; @@ -39,7 +36,8 @@ use middle::typeck::infer::combine::Combine; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::{new_infer_ctxt, resolve_ivar}; use middle::typeck::infer::{resolve_nested_tvar, resolve_type}; -use syntax::ast::{crate, def_id, def_mod, def_struct, def_trait, def_ty}; +use middle::typeck::infer; +use syntax::ast::{crate, def_id, def_struct, def_ty}; use syntax::ast::{item, item_enum, item_impl, item_mod, item_struct}; use syntax::ast::{local_crate, method, trait_ref, ty_path}; use syntax::ast; @@ -54,10 +52,10 @@ use syntax::visit::{Visitor, SimpleVisitor}; use syntax::visit::{visit_mod}; use util::ppaux::ty_to_str; -use core::hashmap::{HashMap, HashSet}; -use core::result::Ok; -use core::uint; -use core::vec; +use std::hashmap::{HashMap, HashSet}; +use std::result::Ok; +use std::uint; +use std::vec; pub struct UniversalQuantificationResult { monotype: t, @@ -114,7 +112,7 @@ pub fn type_is_defined_in_local_crate(original_type: t) -> bool { do ty::walk_ty(original_type) |t| { match get(t).sty { ty_enum(def_id, _) | - ty_trait(def_id, _, _, _) | + ty_trait(def_id, _, _, _, _) | ty_struct(def_id, _) => { if def_id.crate == ast::local_crate { found_nominal = true; @@ -140,7 +138,7 @@ pub fn get_base_type_def_id(inference_context: @mut InferCtxt, match get(base_type).sty { ty_enum(def_id, _) | ty_struct(def_id, _) | - ty_trait(def_id, _, _, _) => { + ty_trait(def_id, _, _, _, _) => { return Some(def_id); } _ => { @@ -199,7 +197,7 @@ pub struct CoherenceChecker { } impl CoherenceChecker { - pub fn check_coherence(self, crate: @crate) { + pub fn check_coherence(self, crate: &crate) { // Check implementations and traits. This populates the tables // containing the inherent methods and extension methods. It also // builds up the trait inheritance table. @@ -270,7 +268,7 @@ impl CoherenceChecker { // We only want to generate one Impl structure. When we generate one, // we store it here so that we don't recreate it. let mut implementation_opt = None; - for associated_traits.each |&associated_trait| { + for associated_traits.iter().advance |&associated_trait| { let trait_ref = ty::node_id_to_trait_ref( self.crate_context.tcx, @@ -279,7 +277,7 @@ impl CoherenceChecker { trait_ref.repr(self.crate_context.tcx), self.crate_context.tcx.sess.str_of(item.ident)); - self.instantiate_default_methods(item.id, trait_ref); + self.instantiate_default_methods(local_def(item.id), trait_ref); let implementation; if implementation_opt.is_none() { @@ -327,15 +325,16 @@ impl CoherenceChecker { // and trait pair. Then, for each provided method in the trait, inserts a // `ProvidedMethodInfo` instance into the `provided_method_sources` map. pub fn instantiate_default_methods(&self, - impl_id: ast::node_id, + impl_id: ast::def_id, trait_ref: &ty::TraitRef) { let tcx = self.crate_context.tcx; debug!("instantiate_default_methods(impl_id=%?, trait_ref=%s)", impl_id, trait_ref.repr(tcx)); - let impl_poly_type = ty::lookup_item_type(tcx, local_def(impl_id)); + let impl_poly_type = ty::lookup_item_type(tcx, impl_id); - for self.each_provided_trait_method(trait_ref.def_id) |trait_method| { + let provided = ty::provided_trait_methods(tcx, trait_ref.def_id); + for provided.iter().advance |trait_method| { // Synthesize an ID. let new_id = parse::next_node_id(tcx.sess.parse_sess); let new_did = local_def(new_id); @@ -349,7 +348,7 @@ impl CoherenceChecker { impl_id, trait_ref, new_did, - trait_method); + *trait_method); debug!("new_method_ty=%s", new_method_ty.repr(tcx)); @@ -375,7 +374,7 @@ impl CoherenceChecker { // ID of the method. let source = ProvidedMethodSource { method_id: trait_method.def_id, - impl_id: local_def(impl_id) + impl_id: impl_id }; self.crate_context.tcx.provided_method_sources.insert(new_did, @@ -393,7 +392,7 @@ impl CoherenceChecker { }; let pmm = self.crate_context.tcx.provided_methods; - match pmm.find(&local_def(impl_id)) { + match pmm.find(&impl_id) { Some(&mis) => { // If the trait already has an entry in the // provided_methods_map, we just need to add this @@ -410,7 +409,7 @@ impl CoherenceChecker { for method `%s`", self.crate_context.tcx.sess.str_of( provided_method_info.method_info.ident)); - pmm.insert(local_def(impl_id), + pmm.insert(impl_id, @mut ~[provided_method_info]); } } @@ -456,7 +455,7 @@ impl CoherenceChecker { } pub fn check_implementation_coherence(&self) { - let coherence_info = self.crate_context.coherence_info; + let coherence_info = &self.crate_context.coherence_info; for coherence_info.extension_methods.each_key |&trait_id| { self.check_implementation_coherence_of(trait_id); } @@ -515,7 +514,7 @@ impl CoherenceChecker { } pub fn iter_impls_of_trait(&self, trait_def_id: def_id, f: &fn(@Impl)) { - let coherence_info = self.crate_context.coherence_info; + let coherence_info = &self.crate_context.coherence_info; let extension_methods = &*coherence_info.extension_methods; match extension_methods.find(&trait_def_id) { @@ -528,28 +527,6 @@ impl CoherenceChecker { } } - pub fn each_provided_trait_method(&self, - trait_did: ast::def_id, - f: &fn(x: @ty::Method) -> bool) - -> bool { - // Make a list of all the names of the provided methods. - // XXX: This is horrible. - let mut provided_method_idents = HashSet::new(); - let tcx = self.crate_context.tcx; - for ty::provided_trait_methods(tcx, trait_did).each |ident| { - provided_method_idents.insert(*ident); - } - - for ty::trait_methods(tcx, trait_did).each |&method| { - if provided_method_idents.contains(&method.ident) { - if !f(method) { - return false; - } - } - } - return true; - } - pub fn polytypes_unify(&self, polytype_a: ty_param_bounds_and_ty, polytype_b: ty_param_bounds_and_ty) @@ -570,10 +547,10 @@ impl CoherenceChecker { pub fn universally_quantify_polytype(&self, polytype: ty_param_bounds_and_ty) -> UniversalQuantificationResult { - // NDM--this span is bogus. let self_region = polytype.generics.region_param.map( - |_r| self.inference_context.next_region_var_nb(dummy_sp())); + |_| self.inference_context.next_region_var( + infer::BoundRegionInCoherence)); let bounds_count = polytype.generics.type_param_defs.len(); let type_parameters = self.inference_context.next_ty_vars(bounds_count); @@ -604,14 +581,13 @@ impl CoherenceChecker { b: &'a UniversalQuantificationResult) -> bool { - let mut might_unify = true; - let _ = do self.inference_context.probe { - let result = self.inference_context.sub(true, dummy_sp()) - .tys(a.monotype, b.monotype); - if result.is_ok() { + match infer::can_mk_subty(self.inference_context, + a.monotype, b.monotype) { + Ok(_) => { // Check to ensure that each parameter binding respected its // kind bounds. - for [ a, b ].each |result| { + let xs = [a, b]; + for xs.iter().advance |result| { for result.type_variables.iter() .zip(result.type_param_defs.iter()) .advance |(ty_var, type_param_def)| @@ -627,8 +603,7 @@ impl CoherenceChecker { self.inference_context.tcx, resolved_ty) { - might_unify = false; - break; + return false; } } Err(*) => { @@ -638,13 +613,13 @@ impl CoherenceChecker { } } } - } else { - might_unify = false; + true } - result - }; - might_unify + Err(_) => { + false + } + } } pub fn get_self_type_for_implementation(&self, implementation: @Impl) @@ -653,7 +628,7 @@ impl CoherenceChecker { } // Privileged scope checking - pub fn check_privileged_scopes(self, crate: @crate) { + pub fn check_privileged_scopes(self, crate: &crate) { visit_crate(crate, ((), mk_vt(@Visitor { visit_item: |item, (_context, visitor)| { match item.node { @@ -728,11 +703,15 @@ impl CoherenceChecker { provided_names.insert(all_methods[i].ident); } // Default methods - for ty::provided_trait_methods(tcx, trait_did).each |ident| { - provided_names.insert(*ident); + let r = ty::provided_trait_methods(tcx, trait_did); + for r.iter().advance |method| { + debug!("inserting provided method %s", method.ident.repr(tcx)); + provided_names.insert(method.ident); } - for (*ty::trait_methods(tcx, trait_did)).each |method| { + let r = ty::trait_methods(tcx, trait_did); + for r.iter().advance |method| { + debug!("checking for %s", method.ident.repr(tcx)); if provided_names.contains(&method.ident) { loop; } tcx.sess.span_err(trait_ref_span, @@ -747,7 +726,7 @@ impl CoherenceChecker { pub fn ast_type_is_defined_in_local_crate(&self, original_type: @ast::Ty) -> bool { match original_type.node { - ty_path(_, path_id) => { + ty_path(_, _, path_id) => { match self.crate_context.tcx.def_map.get_copy(&path_id) { def_ty(def_id) | def_struct(def_id) => { if def_id.crate != local_crate { @@ -781,23 +760,45 @@ impl CoherenceChecker { } } - // Converts an implementation in the AST to an Impl structure. - pub fn create_impl_from_item(&self, item: @item) -> @Impl { - fn add_provided_methods(all_methods: &mut ~[@MethodInfo], - all_provided_methods: &mut ~[@ProvidedMethodInfo], - sess: driver::session::Session) { - for all_provided_methods.each |provided_method| { - debug!( - "(creating impl) adding provided method `%s` to impl", - sess.str_of(provided_method.method_info.ident)); - vec::push(all_methods, provided_method.method_info); + fn add_provided_methods_to_impl( + &self, + all_methods: &mut ~[@MethodInfo], + trait_did: &ast::def_id, + impl_id: &ast::def_id) { + + + match self.crate_context.tcx + .provided_methods + .find(impl_id) { + None => { + debug!("(creating impl) trait with node_id `%d` \ + has no provided methods", trait_did.node); + /* fall through */ + } + Some(&all_provided_methods) => { + debug!("(creating impl) trait with node_id `%d` \ + has provided methods", trait_did.node); + // Add all provided methods. + for all_provided_methods.iter().advance |provided_method| { + debug!( + "(creating impl) adding provided method \ + `%s` to impl", + provided_method.method_info + .ident.repr(self.crate_context.tcx)); + all_methods.push(provided_method.method_info); + } + } } - } + + } + + // Converts an implementation in the AST to an Impl structure. + pub fn create_impl_from_item(&self, item: @item) -> @Impl { match item.node { item_impl(_, ref trait_refs, _, ref ast_methods) => { let mut methods = ~[]; - for ast_methods.each |ast_method| { + for ast_methods.iter().advance |ast_method| { methods.push(method_to_MethodInfo(*ast_method)); } @@ -816,27 +817,11 @@ impl CoherenceChecker { // if a method of that name is not inherent to the // impl, use the provided definition in the trait. for trait_refs.iter().advance |trait_ref| { - let trait_did = - self.trait_ref_to_trait_def_id(*trait_ref); - - match self.crate_context.tcx - .provided_methods - .find(&local_def(item.id)) { - None => { - debug!("(creating impl) trait with node_id `%d` \ - has no provided methods", trait_did.node); - /* fall through */ - } - Some(&all_provided) => { - debug!("(creating impl) trait with node_id `%d` \ - has provided methods", trait_did.node); - // Add all provided methods. - add_provided_methods( - &mut methods, - all_provided, - self.crate_context.tcx.sess); - } - } + let trait_did = self.trait_ref_to_trait_def_id(*trait_ref); + self.add_provided_methods_to_impl( + &mut methods, + &trait_did, + &local_def(item.id)); } return @Impl { @@ -867,111 +852,82 @@ impl CoherenceChecker { // External crate handling - pub fn add_impls_for_module(&self, - impls_seen: &mut HashSet<def_id>, - crate_store: @mut CStore, - module_def_id: def_id) { - let implementations = get_impls_for_mod(crate_store, - module_def_id, - None); - for implementations.each |implementation| { - debug!("coherence: adding impl from external crate: %s", - ty::item_path_str(self.crate_context.tcx, - implementation.did)); - - // Make sure we don't visit the same implementation - // multiple times. - if !impls_seen.insert(implementation.did) { - // Skip this one. - loop; - } - // Good. Continue. - - let self_type = lookup_item_type(self.crate_context.tcx, - implementation.did); - let associated_traits = get_impl_trait(self.crate_context.tcx, - implementation.did); + pub fn add_external_impl(&self, + impls_seen: &mut HashSet<def_id>, + crate_store: @mut CStore, + impl_def_id: def_id) { + let implementation = csearch::get_impl(crate_store, impl_def_id); - // Do a sanity check to make sure that inherent methods have base - // types. + debug!("coherence: adding impl from external crate: %s", + ty::item_path_str(self.crate_context.tcx, implementation.did)); - if associated_traits.is_none() { - match get_base_type_def_id(self.inference_context, - dummy_sp(), - self_type.ty) { - None => { - let session = self.crate_context.tcx.sess; - session.bug(fmt!( - "no base type for external impl \ - with no trait: %s (type %s)!", - session.str_of(implementation.ident), - ty_to_str(self.crate_context.tcx,self_type.ty))); - } - Some(_) => { - // Nothing to do. - } - } - } - - // Record all the trait methods. - for associated_traits.iter().advance |trait_ref| { - self.add_trait_method(trait_ref.def_id, *implementation); - } + // Make sure we don't visit the same implementation multiple times. + if !impls_seen.insert(implementation.did) { + // Skip this one. + return + } + // Good. Continue. - // Add the implementation to the mapping from - // implementation to base type def ID, if there is a base - // type for this implementation. + let self_type = lookup_item_type(self.crate_context.tcx, + implementation.did); + let associated_traits = get_impl_trait(self.crate_context.tcx, + implementation.did); + // Do a sanity check to make sure that inherent methods have base + // types. + if associated_traits.is_none() { match get_base_type_def_id(self.inference_context, - dummy_sp(), - self_type.ty) { + dummy_sp(), + self_type.ty) { None => { - // Nothing to do. - } - Some(base_type_def_id) => { - // inherent methods apply to `impl Type` but not - // `impl Trait for Type`: - if associated_traits.is_none() { - self.add_inherent_method(base_type_def_id, - *implementation); - } - - self.base_type_def_ids.insert(implementation.did, - base_type_def_id); + let session = self.crate_context.tcx.sess; + session.bug(fmt!("no base type for external impl with no \ + trait: %s (type %s)!", + session.str_of(implementation.ident), + ty_to_str(self.crate_context.tcx, + self_type.ty))); } + Some(_) => {} // Nothing to do. } } - } - - pub fn add_default_methods_for_external_trait(&self, - trait_def_id: ast::def_id) { - let tcx = self.crate_context.tcx; - let pmm = tcx.provided_methods; - - if pmm.contains_key(&trait_def_id) { return; } - - debug!("(adding default methods for trait) processing trait"); - for csearch::get_provided_trait_methods(tcx, trait_def_id).each - |trait_method_info| { - debug!("(adding default methods for trait) found default method"); + // Record all the trait methods. + let mut implementation = @implementation; + for associated_traits.iter().advance |trait_ref| { + self.instantiate_default_methods(implementation.did, + *trait_ref); + + // XXX(sully): We could probably avoid this copy if there are no + // default methods. + let mut methods = copy implementation.methods; + self.add_provided_methods_to_impl(&mut methods, + &trait_ref.def_id, + &implementation.did); + implementation = @Impl { + methods: methods, + ..*implementation + }; - // Create a new def ID for this provided method. - let parse_sess = &self.crate_context.tcx.sess.parse_sess; - let new_did = local_def(parse::next_node_id(*parse_sess)); + self.add_trait_method(trait_ref.def_id, implementation); + } - let provided_method_info = - @ProvidedMethodInfo { - method_info: @MethodInfo { - did: new_did, - n_tps: trait_method_info.ty.generics.type_param_defs.len(), - ident: trait_method_info.ty.ident, - explicit_self: trait_method_info.ty.explicit_self - }, - trait_method_def_id: trait_method_info.def_id - }; + // Add the implementation to the mapping from implementation to base + // type def ID, if there is a base type for this implementation. + match get_base_type_def_id(self.inference_context, + dummy_sp(), + self_type.ty) { + None => {} // Nothing to do. + Some(base_type_def_id) => { + // inherent methods apply to `impl Type` but not + // `impl Trait for Type`: + if associated_traits.is_none() { + self.add_inherent_method(base_type_def_id, + implementation); + } - pmm.insert(trait_def_id, @mut ~[provided_method_info]); + self.base_type_def_ids.insert(implementation.did, + base_type_def_id); + } } } @@ -982,25 +938,14 @@ impl CoherenceChecker { let crate_store = self.crate_context.tcx.sess.cstore; do iter_crate_data(crate_store) |crate_number, _crate_metadata| { - self.add_impls_for_module(&mut impls_seen, - crate_store, - def_id { crate: crate_number, - node: 0 }); - for each_path(crate_store, crate_number) |_, def_like, _| { match def_like { - dl_def(def_mod(def_id)) => { - self.add_impls_for_module(&mut impls_seen, - crate_store, - def_id); - } - dl_def(def_trait(def_id)) => { - self.add_default_methods_for_external_trait(def_id); - } - dl_def(_) | dl_impl(_) | dl_field => { - // Skip this. - loop; + dl_impl(def_id) => { + self.add_external_impl(&mut impls_seen, + crate_store, + def_id) } + dl_def(_) | dl_field => loop, // Skip this. } } } @@ -1011,7 +956,7 @@ impl CoherenceChecker { // pub fn populate_destructor_table(&self) { - let coherence_info = self.crate_context.coherence_info; + let coherence_info = &self.crate_context.coherence_info; let tcx = self.crate_context.tcx; let drop_trait = tcx.lang_items.drop_trait(); let impls_opt = coherence_info.extension_methods.find(&drop_trait); @@ -1022,7 +967,7 @@ impl CoherenceChecker { Some(found_impls) => impls = found_impls } - for impls.each |impl_info| { + for impls.iter().advance |impl_info| { if impl_info.methods.len() < 1 { // We'll error out later. For now, just don't ICE. loop; @@ -1059,12 +1004,11 @@ impl CoherenceChecker { } } -fn subst_receiver_types_in_method_ty(tcx: ty::ctxt, - impl_id: ast::node_id, - trait_ref: &ty::TraitRef, - new_def_id: ast::def_id, - method: &ty::Method) - -> ty::Method { +pub fn make_substs_for_receiver_types(tcx: ty::ctxt, + impl_id: ast::def_id, + trait_ref: &ty::TraitRef, + method: &ty::Method) + -> ty::substs { /*! * Substitutes the values for the receiver's type parameters * that are found in method, leaving the method's type parameters @@ -1075,7 +1019,7 @@ fn subst_receiver_types_in_method_ty(tcx: ty::ctxt, // determine how many type parameters were declared on the impl let num_impl_type_parameters = { - let impl_polytype = ty::lookup_item_type(tcx, local_def(impl_id)); + let impl_polytype = ty::lookup_item_type(tcx, impl_id); impl_polytype.generics.type_param_defs.len() }; @@ -1101,11 +1045,22 @@ fn subst_receiver_types_in_method_ty(tcx: ty::ctxt, } }); - let combined_substs = ty::substs { + return ty::substs { self_r: trait_ref.substs.self_r, self_ty: trait_ref.substs.self_ty, tps: combined_tps }; +} + +fn subst_receiver_types_in_method_ty(tcx: ty::ctxt, + impl_id: ast::def_id, + trait_ref: &ty::TraitRef, + new_def_id: ast::def_id, + method: &ty::Method) + -> ty::Method { + + let combined_substs = make_substs_for_receiver_types( + tcx, impl_id, trait_ref, method); ty::Method::new( method.ident, @@ -1125,7 +1080,7 @@ fn subst_receiver_types_in_method_ty(tcx: ty::ctxt, ) } -pub fn check_coherence(crate_context: @mut CrateCtxt, crate: @crate) { - let coherence_checker = @CoherenceChecker(crate_context); +pub fn check_coherence(crate_context: @mut CrateCtxt, crate: &crate) { + let coherence_checker = CoherenceChecker(crate_context); coherence_checker.check_coherence(crate); } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 56e9875d2ba..de05aca61ca 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -30,7 +30,6 @@ are represented as `ty_param()` instances. */ -use core::prelude::*; use metadata::csearch; use middle::ty::{substs, ty_param_bounds_and_ty}; @@ -47,8 +46,8 @@ use util::common::pluralize; use util::ppaux; use util::ppaux::UserString; -use core::result; -use core::vec; +use std::result; +use std::vec; use syntax::abi::AbiSet; use syntax::ast::{RegionTyParamBound, TraitTyParamBound}; use syntax::ast; @@ -61,56 +60,17 @@ use syntax::visit; use syntax::opt_vec::OptVec; use syntax::opt_vec; -pub fn collect_item_types(ccx: @mut CrateCtxt, crate: @ast::crate) { - - // FIXME (#2592): hooking into the "intrinsic" root module is crude. - // There ought to be a better approach. Attributes? - - for crate.node.module.items.each |crate_item| { - if crate_item.ident - == ::syntax::parse::token::special_idents::intrinsic { - - match crate_item.node { - ast::item_mod(ref m) => { - for m.items.each |intrinsic_item| { - let def_id = ast::def_id { crate: ast::local_crate, - node: intrinsic_item.id }; - let substs = substs { - self_r: None, - self_ty: None, - tps: ~[] - }; - - match intrinsic_item.node { - ast::item_trait(*) => { - let tref = @ty::TraitRef {def_id: def_id, - substs: substs}; - ccx.tcx.intrinsic_traits.insert - (intrinsic_item.ident, tref); - } - - ast::item_enum(*) => { - let ty = ty::mk_enum(ccx.tcx, def_id, substs); - ccx.tcx.intrinsic_defs.insert - (intrinsic_item.ident, (def_id, ty)); - } - - ast::item_struct(*) => { - let ty = ty::mk_struct(ccx.tcx, def_id, substs); - ccx.tcx.intrinsic_defs.insert - (intrinsic_item.ident, (def_id, ty)); - } - - _ => {} - } - } - } - _ => { } - } - break; - } +pub fn collect_item_types(ccx: @mut CrateCtxt, crate: &ast::crate) { + fn collect_intrinsic_type(ccx: &CrateCtxt, + lang_item: ast::def_id) { + let ty::ty_param_bounds_and_ty { ty: ty, _ } = + ccx.get_item_ty(lang_item); + ccx.tcx.intrinsic_defs.insert(lang_item, ty); } + collect_intrinsic_type(ccx, ccx.tcx.lang_items.ty_desc()); + collect_intrinsic_type(ccx, ccx.tcx.lang_items.opaque()); + visit::visit_crate( crate, ((), visit::mk_simple_visitor(@visit::SimpleVisitor { @@ -120,10 +80,20 @@ pub fn collect_item_types(ccx: @mut CrateCtxt, crate: @ast::crate) { }))); } -impl CrateCtxt { +pub trait ToTy { fn to_ty<RS:region_scope + Copy + 'static>( - &self, rs: &RS, ast_ty: @ast::Ty) -> ty::t - { + &self, + rs: &RS, + ast_ty: &ast::Ty) + -> ty::t; +} + +impl ToTy for CrateCtxt { + fn to_ty<RS:region_scope + Copy + 'static>( + &self, + rs: &RS, + ast_ty: &ast::Ty) + -> ty::t { ast_ty_to_ty(self, rs, ast_ty) } } @@ -168,7 +138,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, let tcx = ccx.tcx; // Create a set of parameter types shared among all the variants. - for variants.each |variant| { + for variants.iter().advance |variant| { let region_parameterization = RegionParameterization::from_variance_and_generics(rp, generics); @@ -233,7 +203,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, // For each method, construct a suitable ty::Method and // store it into the `tcx.methods` table: - for ms.each |m| { + for ms.iter().advance |m| { let ty_method = @match m { &ast::required(ref m) => { ty_method_of_trait_method( @@ -416,12 +386,12 @@ pub fn ensure_supertraits(ccx: &CrateCtxt, let self_ty = ty::mk_self(ccx.tcx, local_def(id)); let mut ty_trait_refs: ~[@ty::TraitRef] = ~[]; - for ast_trait_refs.each |&ast_trait_ref| { + for ast_trait_refs.iter().advance |&ast_trait_ref| { let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, rp, generics, self_ty); // FIXME(#5527) Could have same trait multiple times - if ty_trait_refs.any(|other_trait| other_trait.def_id == trait_ref.def_id) { + if ty_trait_refs.iter().any_(|other_trait| other_trait.def_id == trait_ref.def_id) { // This means a trait inherited from the same supertrait more // than once. tcx.sess.span_err(sp, "Duplicate supertrait in trait declaration"); @@ -515,7 +485,7 @@ pub fn compare_impl_method(tcx: ty::ctxt, return; } - for trait_m.generics.type_param_defs.eachi |i, trait_param_def| { + for trait_m.generics.type_param_defs.iter().enumerate().advance |(i, trait_param_def)| { // For each of the corresponding impl ty param's bounds... let impl_param_def = &impl_m.generics.type_param_defs[i]; @@ -645,7 +615,8 @@ pub fn compare_impl_method(tcx: ty::ctxt, }; debug!("trait_fty (post-subst): %s", trait_fty.repr(tcx)); - match infer::mk_subty(infcx, false, cm.span, impl_fty, trait_fty) { + match infer::mk_subty(infcx, false, infer::MethodCompatCheck(cm.span), + impl_fty, trait_fty) { result::Ok(()) => {} result::Err(ref terr) => { tcx.sess.span_err( @@ -671,7 +642,7 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, generics: &ast::Generics, rp: Option<ty::region_variance>, selfty: ty::t, - a_trait_ty: @ast::trait_ref, + a_trait_ty: &ast::trait_ref, impl_ms: &[ConvertedMethod]) { let tcx = ccx.tcx; @@ -686,12 +657,12 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, // Trait methods we don't implement must be default methods, but if not // we'll catch it in coherence let trait_ms = ty::trait_methods(tcx, trait_ref.def_id); - for impl_ms.each |impl_m| { - match trait_ms.find(|trait_m| trait_m.ident == impl_m.mty.ident) { + for impl_ms.iter().advance |impl_m| { + match trait_ms.iter().find_(|trait_m| trait_m.ident == impl_m.mty.ident) { Some(trait_m) => { let num_impl_tps = generics.ty_params.len(); compare_impl_method( - ccx.tcx, num_impl_tps, impl_m, trait_m, + ccx.tcx, num_impl_tps, impl_m, *trait_m, &trait_ref.substs, selfty); } None => { @@ -709,7 +680,7 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, pub fn convert_field(ccx: &CrateCtxt, rp: Option<ty::region_variance>, type_param_defs: @~[ty::TypeParameterDef], - v: @ast::struct_field, + v: &ast::struct_field, generics: &ast::Generics) { let region_parameterization = RegionParameterization::from_variance_and_generics(rp, generics); @@ -742,7 +713,7 @@ pub fn convert_methods(ccx: &CrateCtxt, -> ~[ConvertedMethod] { let tcx = ccx.tcx; - return vec::map(ms, |m| { + return ms.iter().transform(|m| { let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs.len(); let m_ty_generics = ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics, @@ -772,10 +743,10 @@ pub fn convert_methods(ccx: &CrateCtxt, tcx.methods.insert(mty.def_id, mty); ConvertedMethod {mty: mty, id: m.id, span: m.span, body_id: m.body.node.id} - }); + }).collect(); fn ty_of_method(ccx: &CrateCtxt, - m: @ast::method, + m: &ast::method, rp: Option<ty::region_variance>, untransformed_rcvr_ty: ty::t, rcvr_generics: &ast::Generics, @@ -814,7 +785,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, span: span, generics: &ast::Generics, thing: &'static str) { - for generics.ty_params.each |ty_param| { + for generics.ty_params.iter().advance |ty_param| { if ty_param.bounds.len() > 0 { ccx.tcx.sess.span_err( span, @@ -824,7 +795,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, } } -pub fn convert(ccx: &CrateCtxt, it: @ast::item) { +pub fn convert(ccx: &CrateCtxt, it: &ast::item) { let tcx = ccx.tcx; let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); debug!("convert: item %s with id %d rp %?", @@ -914,14 +885,14 @@ pub fn convert(ccx: &CrateCtxt, it: @ast::item) { pub fn convert_struct(ccx: &CrateCtxt, rp: Option<ty::region_variance>, - struct_def: @ast::struct_def, + struct_def: &ast::struct_def, generics: &ast::Generics, tpt: ty::ty_param_bounds_and_ty, id: ast::node_id) { let tcx = ccx.tcx; // Write the type of each of the members - for struct_def.fields.each |f| { + for struct_def.fields.iter().advance |f| { convert_field(ccx, rp, tpt.generics.type_param_defs, *f, generics); } let (_, substs) = mk_item_substs(ccx, generics, rp, None); @@ -953,7 +924,7 @@ pub fn convert_struct(ccx: &CrateCtxt, } } -pub fn convert_foreign(ccx: &CrateCtxt, i: @ast::foreign_item) { +pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::foreign_item) { // As above, this call populates the type table with the converted // type of the foreign item. We simply write it into the node type // table. @@ -976,7 +947,7 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: @ast::foreign_item) { } pub fn instantiate_trait_ref(ccx: &CrateCtxt, - ast_trait_ref: @ast::trait_ref, + ast_trait_ref: &ast::trait_ref, rp: Option<ty::region_variance>, generics: &ast::Generics, self_ty: ty::t) -> @ty::TraitRef @@ -1022,7 +993,7 @@ fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::def_id) -> @ty::TraitDef { } } -pub fn trait_def_of_item(ccx: &CrateCtxt, it: @ast::item) -> @ty::TraitDef { +pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::item) -> @ty::TraitDef { let def_id = local_def(it.id); let tcx = ccx.tcx; match tcx.trait_defs.find(&def_id) { @@ -1050,7 +1021,7 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: @ast::item) -> @ty::TraitDef { } } -pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) +pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::item) -> ty::ty_param_bounds_and_ty { let def_id = local_def(it.id); let tcx = ccx.tcx; @@ -1060,7 +1031,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) } let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); match it.node { - ast::item_const(t, _) => { + ast::item_static(t, _, _) => { let typ = ccx.to_ty(&empty_rscope, t); let tpt = no_params(typ); tcx.tcache.insert(local_def(it.id), tpt); @@ -1142,7 +1113,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) } pub fn ty_of_foreign_item(ccx: &CrateCtxt, - it: @ast::foreign_item, + it: &ast::foreign_item, abis: AbiSet) -> ty::ty_param_bounds_and_ty { match it.node { @@ -1153,7 +1124,7 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, generics, abis) } - ast::foreign_item_const(t) => { + ast::foreign_item_static(t, _) => { ty::ty_param_bounds_and_ty { generics: ty::Generics { type_param_defs: @~[], @@ -1204,14 +1175,14 @@ pub fn ty_generics(ccx: &CrateCtxt, * enum consisting of a newtyped Ty or a region) to ty's * notion of ty param bounds, which can either be user-defined * traits, or one of the four built-in traits (formerly known - * as kinds): Const, Copy, and Send. + * as kinds): Freeze, Copy, and Send. */ let mut param_bounds = ty::ParamBounds { builtin_bounds: ty::EmptyBuiltinBounds(), trait_bounds: ~[] }; - for ast_bounds.each |ast_bound| { + for ast_bounds.iter().advance |ast_bound| { match *ast_bound { TraitTyParamBound(b) => { let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id); diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 18940bb89e1..03d243797b3 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -64,14 +64,13 @@ we may want to adjust precisely when coercions occur. */ -use core::prelude::*; use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn}; use middle::ty::{AutoDerefRef}; use middle::ty::{vstore_slice, vstore_box, vstore_uniq}; use middle::ty::{mt}; use middle::ty; -use middle::typeck::infer::{CoerceResult, resolve_type}; +use middle::typeck::infer::{CoerceResult, resolve_type, Coercion}; use middle::typeck::infer::combine::CombineFields; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; @@ -166,7 +165,7 @@ impl Coerce { } Err(e) => { self.infcx.tcx.sess.span_bug( - self.span, + self.trace.origin.span(), fmt!("Failed to resolve even without \ any force options: %?", e)); } @@ -190,7 +189,7 @@ impl Coerce { // yield. let sub = Sub(**self); - let r_borrow = self.infcx.next_region_var_nb(self.span); + let r_borrow = self.infcx.next_region_var(Coercion(self.trace)); let inner_ty = match *sty_a { ty::ty_box(mt_a) => mt_a.ty, @@ -228,7 +227,7 @@ impl Coerce { } }; - let r_a = self.infcx.next_region_var_nb(self.span); + let r_a = self.infcx.next_region_var(Coercion(self.trace)); let a_borrowed = ty::mk_estr(self.infcx.tcx, vstore_slice(r_a)); if_ok!(self.subtype(a_borrowed, b)); Ok(Some(@AutoDerefRef(AutoDerefRef { @@ -248,7 +247,7 @@ impl Coerce { b.inf_str(self.infcx)); let sub = Sub(**self); - let r_borrow = self.infcx.next_region_var_nb(self.span); + let r_borrow = self.infcx.next_region_var(Coercion(self.trace)); let ty_inner = match *sty_a { ty::ty_evec(mt, _) => mt.ty, _ => { @@ -286,7 +285,7 @@ impl Coerce { } }; - let r_borrow = self.infcx.next_region_var_nb(self.span); + let r_borrow = self.infcx.next_region_var(Coercion(self.trace)); let a_borrowed = ty::mk_closure( self.infcx.tcx, ty::ClosureTy { diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 76681674892..f03f0173229 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -54,7 +54,6 @@ // terms of error reporting, although we do not do that properly right // now. -use core::prelude::*; use middle::ty::{FloatVar, FnSig, IntVar, TyVar}; use middle::ty::{IntType, UintType, substs}; @@ -64,11 +63,13 @@ use middle::typeck::infer::glb::Glb; use middle::typeck::infer::lub::Lub; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; -use middle::typeck::infer::{cres, InferCtxt, ures}; +use middle::typeck::infer::unify::{InferCtxtMethods}; +use middle::typeck::infer::{InferCtxt, cres, ures}; +use middle::typeck::infer::{TypeOrigin, TypeTrace}; use util::common::indent; -use core::result::{iter_vec2, map_vec2}; -use core::vec; +use std::result::{iter_vec2, map_vec2}; +use std::vec; use syntax::ast::{Onceness, purity}; use syntax::ast; use syntax::opt_vec; @@ -79,7 +80,7 @@ pub trait Combine { fn infcx(&self) -> @mut InferCtxt; fn tag(&self) -> ~str; fn a_is_expected(&self) -> bool; - fn span(&self) -> span; + fn trace(&self) -> TypeTrace; fn sub(&self) -> Sub; fn lub(&self) -> Lub; @@ -121,7 +122,7 @@ pub trait Combine { pub struct CombineFields { infcx: @mut InferCtxt, a_is_expected: bool, - span: span, + trace: TypeTrace, } pub fn expected_found<C:Combine,T>( @@ -265,7 +266,7 @@ pub fn super_tps<C:Combine>( if vec::same_length(as_, bs) { iter_vec2(as_, bs, |a, b| { eq_tys(this, *a, *b) - }).then(|| Ok(as_.to_vec()) ) + }).then(|| Ok(as_.to_owned()) ) } else { Err(ty::terr_ty_param_size( expected_found(this, as_.len(), bs.len()))) @@ -508,13 +509,15 @@ pub fn super_tys<C:Combine>( } } - (&ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl), - &ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl)) + (&ty::ty_trait(a_id, ref a_substs, a_store, a_mutbl, a_bounds), + &ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl, b_bounds)) if a_id == b_id && a_mutbl == b_mutbl => { let trait_def = ty::lookup_trait_def(tcx, a_id); do this.substs(&trait_def.generics, a_substs, b_substs).chain |substs| { do this.trait_stores(ty::terr_trait, a_store, b_store).chain |s| { - Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s, a_mutbl)) + do this.bounds(a_bounds, b_bounds).chain |bounds| { + Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s, a_mutbl, bounds)) + } } } } diff --git a/src/librustc/middle/typeck/infer/doc.rs b/src/librustc/middle/typeck/infer/doc.rs new file mode 100644 index 00000000000..11bfbc63716 --- /dev/null +++ b/src/librustc/middle/typeck/infer/doc.rs @@ -0,0 +1,243 @@ +// 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. + +/*! + +# Type inference engine + +This is loosely based on standard HM-type inference, but with an +extension to try and accommodate subtyping. There is nothing +principled about this extension; it's sound---I hope!---but it's a +heuristic, ultimately, and does not guarantee that it finds a valid +typing even if one exists (in fact, there are known scenarios where it +fails, some of which may eventually become problematic). + +## Key idea + +The main change is that each type variable T is associated with a +lower-bound L and an upper-bound U. L and U begin as bottom and top, +respectively, but gradually narrow in response to new constraints +being introduced. When a variable is finally resolved to a concrete +type, it can (theoretically) select any type that is a supertype of L +and a subtype of U. + +There are several critical invariants which we maintain: + +- the upper-bound of a variable only becomes lower and the lower-bound + only becomes higher over time; +- the lower-bound L is always a subtype of the upper bound U; +- the lower-bound L and upper-bound U never refer to other type variables, + but only to types (though those types may contain type variables). + +> An aside: if the terms upper- and lower-bound confuse you, think of +> "supertype" and "subtype". The upper-bound is a "supertype" +> (super=upper in Latin, or something like that anyway) and the lower-bound +> is a "subtype" (sub=lower in Latin). I find it helps to visualize +> a simple class hierarchy, like Java minus interfaces and +> primitive types. The class Object is at the root (top) and other +> types lie in between. The bottom type is then the Null type. +> So the tree looks like: +> +> Object +> / \ +> String Other +> \ / +> (null) +> +> So the upper bound type is the "supertype" and the lower bound is the +> "subtype" (also, super and sub mean upper and lower in Latin, or something +> like that anyway). + +## Satisfying constraints + +At a primitive level, there is only one form of constraint that the +inference understands: a subtype relation. So the outside world can +say "make type A a subtype of type B". If there are variables +involved, the inferencer will adjust their upper- and lower-bounds as +needed to ensure that this relation is satisfied. (We also allow "make +type A equal to type B", but this is translated into "A <: B" and "B +<: A") + +As stated above, we always maintain the invariant that type bounds +never refer to other variables. This keeps the inference relatively +simple, avoiding the scenario of having a kind of graph where we have +to pump constraints along and reach a fixed point, but it does impose +some heuristics in the case where the user is relating two type +variables A <: B. + +Combining two variables such that variable A will forever be a subtype +of variable B is the trickiest part of the algorithm because there is +often no right choice---that is, the right choice will depend on +future constraints which we do not yet know. The problem comes about +because both A and B have bounds that can be adjusted in the future. +Let's look at some of the cases that can come up. + +Imagine, to start, the best case, where both A and B have an upper and +lower bound (that is, the bounds are not top nor bot respectively). In +that case, if we're lucky, A.ub <: B.lb, and so we know that whatever +A and B should become, they will forever have the desired subtyping +relation. We can just leave things as they are. + +### Option 1: Unify + +However, suppose that A.ub is *not* a subtype of B.lb. In +that case, we must make a decision. One option is to unify A +and B so that they are one variable whose bounds are: + + UB = GLB(A.ub, B.ub) + LB = LUB(A.lb, B.lb) + +(Note that we will have to verify that LB <: UB; if it does not, the +types are not intersecting and there is an error) In that case, A <: B +holds trivially because A==B. However, we have now lost some +flexibility, because perhaps the user intended for A and B to end up +as different types and not the same type. + +Pictorally, what this does is to take two distinct variables with +(hopefully not completely) distinct type ranges and produce one with +the intersection. + + B.ub B.ub + /\ / + A.ub / \ A.ub / + / \ / \ \ / + / X \ UB + / / \ \ / \ + / / / \ / / + \ \ / / \ / + \ X / LB + \ / \ / / \ + \ / \ / / \ + A.lb B.lb A.lb B.lb + + +### Option 2: Relate UB/LB + +Another option is to keep A and B as distinct variables but set their +bounds in such a way that, whatever happens, we know that A <: B will hold. +This can be achieved by ensuring that A.ub <: B.lb. In practice there +are two ways to do that, depicted pictorally here: + + Before Option #1 Option #2 + + B.ub B.ub B.ub + /\ / \ / \ + A.ub / \ A.ub /(B')\ A.ub /(B')\ + / \ / \ \ / / \ / / + / X \ __UB____/ UB / + / / \ \ / | | / + / / / \ / | | / + \ \ / / /(A')| | / + \ X / / LB ______LB/ + \ / \ / / / \ / (A')/ \ + \ / \ / \ / \ \ / \ + A.lb B.lb A.lb B.lb A.lb B.lb + +In these diagrams, UB and LB are defined as before. As you can see, +the new ranges `A'` and `B'` are quite different from the range that +would be produced by unifying the variables. + +### What we do now + +Our current technique is to *try* (transactionally) to relate the +existing bounds of A and B, if there are any (i.e., if `UB(A) != top +&& LB(B) != bot`). If that succeeds, we're done. If it fails, then +we merge A and B into same variable. + +This is not clearly the correct course. For example, if `UB(A) != +top` but `LB(B) == bot`, we could conceivably set `LB(B)` to `UB(A)` +and leave the variables unmerged. This is sometimes the better +course, it depends on the program. + +The main case which fails today that I would like to support is: + + fn foo<T>(x: T, y: T) { ... } + + fn bar() { + let x: @mut int = @mut 3; + let y: @int = @3; + foo(x, y); + } + +In principle, the inferencer ought to find that the parameter `T` to +`foo(x, y)` is `@const int`. Today, however, it does not; this is +because the type variable `T` is merged with the type variable for +`X`, and thus inherits its UB/LB of `@mut int`. This leaves no +flexibility for `T` to later adjust to accommodate `@int`. + +### What to do when not all bounds are present + +In the prior discussion we assumed that A.ub was not top and B.lb was +not bot. Unfortunately this is rarely the case. Often type variables +have "lopsided" bounds. For example, if a variable in the program has +been initialized but has not been used, then its corresponding type +variable will have a lower bound but no upper bound. When that +variable is then used, we would like to know its upper bound---but we +don't have one! In this case we'll do different things depending on +how the variable is being used. + +## Transactional support + +Whenever we adjust merge variables or adjust their bounds, we always +keep a record of the old value. This allows the changes to be undone. + +## Regions + +I've only talked about type variables here, but region variables +follow the same principle. They have upper- and lower-bounds. A +region A is a subregion of a region B if A being valid implies that B +is valid. This basically corresponds to the block nesting structure: +the regions for outer block scopes are superregions of those for inner +block scopes. + +## Integral and floating-point type variables + +There is a third variety of type variable that we use only for +inferring the types of unsuffixed integer literals. Integral type +variables differ from general-purpose type variables in that there's +no subtyping relationship among the various integral types, so instead +of associating each variable with an upper and lower bound, we just +use simple unification. Each integer variable is associated with at +most one integer type. Floating point types are handled similarly to +integral types. + +## GLB/LUB + +Computing the greatest-lower-bound and least-upper-bound of two +types/regions is generally straightforward except when type variables +are involved. In that case, we follow a similar "try to use the bounds +when possible but otherwise merge the variables" strategy. In other +words, `GLB(A, B)` where `A` and `B` are variables will often result +in `A` and `B` being merged and the result being `A`. + +## Type coercion + +We have a notion of assignability which differs somewhat from +subtyping; in particular it may cause region borrowing to occur. See +the big comment later in this file on Type Coercion for specifics. + +### In conclusion + +I showed you three ways to relate `A` and `B`. There are also more, +of course, though I'm not sure if there are any more sensible options. +The main point is that there are various options, each of which +produce a distinct range of types for `A` and `B`. Depending on what +the correct values for A and B are, one of these options will be the +right choice: but of course we don't know the right values for A and B +yet, that's what we're trying to find! In our code, we opt to unify +(Option #1). + +# Implementation details + +We make use of a trait-like impementation strategy to consolidate +duplicated code between subtypes, GLB, and LUB computations. See the +section on "Type Combining" below for details. + +*/ \ No newline at end of file diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs new file mode 100644 index 00000000000..e533f019b46 --- /dev/null +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -0,0 +1,472 @@ +// Copyright 2012-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. + +/*! + +Error Reporting Code for the inference engine + +Because of the way inference, and in particular region inference, +works, it often happens that errors are not detected until far after +the relevant line of code has been type-checked. Therefore, there is +an elaborate system to track why a particular constraint in the +inference graph arose so that we can explain to the user what gave +rise to a patricular error. + +The basis of the system are the "origin" types. An "origin" is the +reason that a constraint or inference variable arose. There are +different "origin" enums for different kinds of constraints/variables +(e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has +a span, but also more information so that we can generate a meaningful +error message. + +Having a catalogue of all the different reasons an error can arise is +also useful for other reasons, like cross-referencing FAQs etc, though +we are not really taking advantage of this yet. + +# Region Inference + +Region inference is particularly tricky because it always succeeds "in +the moment" and simply registers a constraint. Then, at the end, we +can compute the full graph and report errors, so we need to be able to +store and later report what gave rise to the conflicting constraints. + +# Subtype Trace + +Determing whether `T1 <: T2` often involves a number of subtypes and +subconstraints along the way. A "TypeTrace" is an extended version +of an origin that traces the types and other values that were being +compared. It is not necessarily comprehensive (in fact, at the time of +this writing it only tracks the root values being compared) but I'd +like to extend it to include significant "waypoints". For example, if +you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2 +<: T4` fails, I'd like the trace to include enough information to say +"in the 2nd element of the tuple". Similarly, failures when comparing +arguments or return types in fn types should be able to cite the +specific position, etc. + +# Reality vs plan + +Of course, there is still a LOT of code in typeck that has yet to be +ported to this system, and which relies on string concatenation at the +time of error detection. + +*/ + +use std::prelude::*; +use middle::ty; +use middle::ty::Region; +use middle::typeck::infer; +use middle::typeck::infer::InferCtxt; +use middle::typeck::infer::TypeTrace; +use middle::typeck::infer::TypeOrigin; +use middle::typeck::infer::SubregionOrigin; +use middle::typeck::infer::RegionVariableOrigin; +use middle::typeck::infer::Types; +use middle::typeck::infer::TraitRefs; +use middle::typeck::infer::ValuePairs; +use middle::typeck::infer::region_inference::RegionResolutionError; +use middle::typeck::infer::region_inference::ConcreteFailure; +use middle::typeck::infer::region_inference::SubSupConflict; +use middle::typeck::infer::region_inference::SupSupConflict; +use syntax::opt_vec; +use syntax::opt_vec::OptVec; +use util::ppaux::UserString; +use util::ppaux::note_and_explain_region; + +pub trait ErrorReporting { + pub fn report_region_errors(@mut self, + errors: &OptVec<RegionResolutionError>); + + pub fn report_and_explain_type_error(@mut self, + trace: TypeTrace, + terr: &ty::type_err); + + fn values_str(@mut self, values: &ValuePairs) -> Option<~str>; + + fn expected_found_str<T:UserString+Resolvable>( + @mut self, + exp_found: &ty::expected_found<T>) + -> Option<~str>; + + fn report_concrete_failure(@mut self, + origin: SubregionOrigin, + sub: Region, + sup: Region); + + fn report_sub_sup_conflict(@mut self, + var_origin: RegionVariableOrigin, + sub_origin: SubregionOrigin, + sub_region: Region, + sup_origin: SubregionOrigin, + sup_region: Region); + + fn report_sup_sup_conflict(@mut self, + var_origin: RegionVariableOrigin, + origin1: SubregionOrigin, + region1: Region, + origin2: SubregionOrigin, + region2: Region); +} + + +impl ErrorReporting for InferCtxt { + pub fn report_region_errors(@mut self, + errors: &OptVec<RegionResolutionError>) { + for errors.iter().advance |error| { + match *error { + ConcreteFailure(origin, sub, sup) => { + self.report_concrete_failure(origin, sub, sup); + } + + SubSupConflict(var_origin, + sub_origin, sub_r, + sup_origin, sup_r) => { + self.report_sub_sup_conflict(var_origin, + sub_origin, sub_r, + sup_origin, sup_r); + } + + SupSupConflict(var_origin, + origin1, r1, + origin2, r2) => { + self.report_sup_sup_conflict(var_origin, + origin1, r1, + origin2, r2); + } + } + } + } + + pub fn report_and_explain_type_error(@mut self, + trace: TypeTrace, + terr: &ty::type_err) { + let tcx = self.tcx; + + let expected_found_str = match self.values_str(&trace.values) { + Some(v) => v, + None => { + return; /* derived error */ + } + }; + + let message_root_str = match trace.origin { + infer::Misc(_) => "mismatched types", + infer::MethodCompatCheck(_) => "method not compatible with trait", + infer::ExprAssignable(_) => "mismatched types", + infer::RelateTraitRefs(_) => "mismatched traits", + infer::RelateSelfType(_) => "mismatched types", + infer::MatchExpression(_) => "match arms have incompatible types", + infer::IfExpression(_) => "if and else have incompatible types", + }; + + self.tcx.sess.span_err( + trace.origin.span(), + fmt!("%s: %s (%s)", + message_root_str, + expected_found_str, + ty::type_err_to_str(tcx, terr))); + + ty::note_and_explain_type_err(self.tcx, terr); + } + + fn values_str(@mut self, values: &ValuePairs) -> Option<~str> { + /*! + * Returns a string of the form "expected `%s` but found `%s`", + * or None if this is a derived error. + */ + match *values { + infer::Types(ref exp_found) => { + self.expected_found_str(exp_found) + } + infer::TraitRefs(ref exp_found) => { + self.expected_found_str(exp_found) + } + } + } + + fn expected_found_str<T:UserString+Resolvable>( + @mut self, + exp_found: &ty::expected_found<T>) + -> Option<~str> + { + let expected = exp_found.expected.resolve(self); + if expected.contains_error() { + return None; + } + + let found = exp_found.found.resolve(self); + if found.contains_error() { + return None; + } + + Some(fmt!("expected `%s` but found `%s`", + expected.user_string(self.tcx), + found.user_string(self.tcx))) + } + + fn report_concrete_failure(@mut self, + origin: SubregionOrigin, + sub: Region, + sup: Region) { + match origin { + infer::Subtype(trace) => { + let terr = ty::terr_regions_does_not_outlive(sup, sub); + self.report_and_explain_type_error(trace, &terr); + } + infer::Reborrow(span) => { + self.tcx.sess.span_err( + span, + "lifetime of borrowed pointer outlines \ + lifetime of borrowed content..."); + note_and_explain_region( + self.tcx, + "...the borrowed pointer is valid for ", + sub, + "..."); + note_and_explain_region( + self.tcx, + "...but the borrowed content is only valid for ", + sup, + ""); + } + infer::InvokeClosure(span) => { + self.tcx.sess.span_err( + span, + "cannot invoke closure outside of its lifetime"); + note_and_explain_region( + self.tcx, + "the closure is only valid for ", + sup, + ""); + } + infer::DerefPointer(span) => { + self.tcx.sess.span_err( + span, + "dereference of reference outside its lifetime"); + note_and_explain_region( + self.tcx, + "the reference is only valid for ", + sup, + ""); + } + infer::FreeVariable(span) => { + self.tcx.sess.span_err( + span, + "captured variable does not outlive the enclosing closure"); + note_and_explain_region( + self.tcx, + "captured variable is valid for ", + sup, + ""); + note_and_explain_region( + self.tcx, + "closure is valid for ", + sub, + ""); + } + infer::IndexSlice(span) => { + self.tcx.sess.span_err( + span, + fmt!("index of slice outside its lifetime")); + note_and_explain_region( + self.tcx, + "the slice is only valid for ", + sup, + ""); + } + infer::RelateObjectBound(span) => { + self.tcx.sess.span_err( + span, + "lifetime of the source pointer does not outlive \ + lifetime bound of the object type"); + note_and_explain_region( + self.tcx, + "object type is valid for ", + sub, + ""); + note_and_explain_region( + self.tcx, + "source pointer is only valid for ", + sup, + ""); + } + infer::CallRcvr(span) => { + self.tcx.sess.span_err( + span, + "lifetime of method receiver does not outlive \ + the method call"); + note_and_explain_region( + self.tcx, + "the receiver is only valid for ", + sup, + ""); + } + infer::CallArg(span) => { + self.tcx.sess.span_err( + span, + "lifetime of function argument does not outlive \ + the function call"); + note_and_explain_region( + self.tcx, + "the function argument is only valid for ", + sup, + ""); + } + infer::CallReturn(span) => { + self.tcx.sess.span_err( + span, + "lifetime of return value does not outlive \ + the function call"); + note_and_explain_region( + self.tcx, + "the return value is only valid for ", + sup, + ""); + } + infer::AddrOf(span) => { + self.tcx.sess.span_err( + span, + "borrowed pointer is not valid \ + at the time of borrow"); + note_and_explain_region( + self.tcx, + "the borrow is only valid for ", + sup, + ""); + } + infer::AutoBorrow(span) => { + self.tcx.sess.span_err( + span, + "automatically borrowed pointer is not valid \ + at the time of borrow"); + note_and_explain_region( + self.tcx, + "the automatic borrow is only valid for ", + sup, + ""); + } + infer::BindingTypeIsNotValidAtDecl(span) => { + self.tcx.sess.span_err( + span, + "lifetime of variable does not enclose its declaration"); + note_and_explain_region( + self.tcx, + "the variable is only valid for ", + sup, + ""); + } + infer::ReferenceOutlivesReferent(ty, span) => { + self.tcx.sess.span_err( + origin.span(), + fmt!("in type `%s`, pointer has a longer lifetime than \ + the data it references", + ty.user_string(self.tcx))); + note_and_explain_region( + self.tcx, + "the pointer is valid for ", + sub, + ""); + note_and_explain_region( + self.tcx, + "but the referenced data is only valid for ", + sup, + ""); + } + } + } + + fn report_sub_sup_conflict(@mut self, + var_origin: RegionVariableOrigin, + sub_origin: SubregionOrigin, + sub_region: Region, + sup_origin: SubregionOrigin, + sup_region: Region) { + self.tcx.sess.span_err( + var_origin.span(), + fmt!("cannot infer an appropriate lifetime \ + due to conflicting requirements")); + + note_and_explain_region( + self.tcx, + "first, the lifetime cannot outlive ", + sup_region, + "..."); + + self.tcx.sess.span_note( + sup_origin.span(), + fmt!("...due to the following expression")); + + note_and_explain_region( + self.tcx, + "but, the lifetime must be valid for ", + sub_region, + "..."); + + self.tcx.sess.span_note( + sub_origin.span(), + fmt!("...due to the following expression")); + } + + fn report_sup_sup_conflict(@mut self, + var_origin: RegionVariableOrigin, + origin1: SubregionOrigin, + region1: Region, + origin2: SubregionOrigin, + region2: Region) { + self.tcx.sess.span_err( + var_origin.span(), + fmt!("cannot infer an appropriate lifetime \ + due to conflicting requirements")); + + note_and_explain_region( + self.tcx, + "first, the lifetime must be contained by ", + region1, + "..."); + + self.tcx.sess.span_note( + origin1.span(), + fmt!("...due to the following expression")); + + note_and_explain_region( + self.tcx, + "but, the lifetime must also be contained by ", + region2, + "..."); + + self.tcx.sess.span_note( + origin2.span(), + fmt!("...due to the following expression")); + } +} + +trait Resolvable { + fn resolve(&self, infcx: @mut InferCtxt) -> Self; + fn contains_error(&self) -> bool; +} + +impl Resolvable for ty::t { + fn resolve(&self, infcx: @mut InferCtxt) -> ty::t { + infcx.resolve_type_vars_if_possible(*self) + } + fn contains_error(&self) -> bool { + ty::type_is_error(*self) + } +} + +impl Resolvable for @ty::TraitRef { + fn resolve(&self, infcx: @mut InferCtxt) -> @ty::TraitRef { + @infcx.resolve_type_vars_in_trait_ref_if_possible(*self) + } + fn contains_error(&self) -> bool { + ty::trait_ref_contains_error(*self) + } +} + diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 700a78699b1..fefbf2336c2 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use middle::ty::{BuiltinBounds}; use middle::ty::RegionVid; @@ -19,11 +18,12 @@ use middle::typeck::infer::lub::Lub; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::{cres, InferCtxt}; +use middle::typeck::infer::{TypeTrace, Subtype}; use middle::typeck::infer::fold_regions_in_sig; use middle::typeck::isr_alist; use syntax::ast; use syntax::ast::{Many, Once, extern_fn, impure_fn, m_const, m_imm, m_mutbl}; -use syntax::ast::{pure_fn, unsafe_fn}; +use syntax::ast::{unsafe_fn}; use syntax::ast::{Onceness, purity}; use syntax::abi::AbiSet; use syntax::codemap::span; @@ -38,7 +38,7 @@ impl Combine for Glb { fn infcx(&self) -> @mut InferCtxt { self.infcx } fn tag(&self) -> ~str { ~"glb" } fn a_is_expected(&self) -> bool { self.a_is_expected } - fn span(&self) -> span { self.span } + fn trace(&self) -> TypeTrace { self.trace } fn sub(&self) -> Sub { Sub(**self) } fn lub(&self) -> Lub { Lub(**self) } @@ -103,7 +103,6 @@ impl Combine for Glb { fn purities(&self, a: purity, b: purity) -> cres<purity> { match (a, b) { - (pure_fn, _) | (_, pure_fn) => Ok(pure_fn), (extern_fn, _) | (_, extern_fn) => Ok(extern_fn), (impure_fn, _) | (_, impure_fn) => Ok(impure_fn), (unsafe_fn, unsafe_fn) => Ok(unsafe_fn) @@ -129,9 +128,7 @@ impl Combine for Glb { a.inf_str(self.infcx), b.inf_str(self.infcx)); - do indent { - self.infcx.region_vars.glb_regions(self.span, a, b) - } + Ok(self.infcx.region_vars.glb_regions(Subtype(self.trace), a, b)) } fn contraregions(&self, a: ty::Region, b: ty::Region) @@ -183,11 +180,11 @@ impl Combine for Glb { // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_isr) = self.infcx.replace_bound_regions_with_fresh_regions( - self.span, a); + self.trace, a); let a_vars = var_ids(self, a_isr); let (b_with_fresh, b_isr) = self.infcx.replace_bound_regions_with_fresh_regions( - self.span, b); + self.trace, b); let b_vars = var_ids(self, b_isr); // Collect constraints. @@ -223,7 +220,7 @@ impl Combine for Glb { let mut a_r = None; let mut b_r = None; let mut only_new_vars = true; - for tainted.each |r| { + for tainted.iter().advance |r| { if is_var_in_set(a_vars, *r) { if a_r.is_some() { return fresh_bound_variable(this); @@ -279,7 +276,7 @@ impl Combine for Glb { } this.infcx.tcx.sess.span_bug( - this.span, + this.trace.origin.span(), fmt!("could not find original bound region for %?", r)); } diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs index 7a3230079ee..b1a6aefd179 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/typeck/infer/lattice.rs @@ -32,7 +32,6 @@ * a lattice. */ -use core::prelude::*; use middle::ty::{RegionVid, TyVar, Vid}; use middle::ty; @@ -71,15 +70,53 @@ impl LatticeValue for ty::t { } } -impl CombineFields { - pub fn var_sub_var<T:Copy + InferStr + LatticeValue, - V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>(&self, - a_id: - V, - b_id: - V) - -> - ures { +pub trait CombineFieldsLatticeMethods { + fn var_sub_var<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>(&self, + a_id: V, + b_id: V) + -> ures; + /// make variable a subtype of T + fn var_sub_t<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>( + &self, + a_id: V, + b: T) + -> ures; + fn t_sub_var<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>( + &self, + a: T, + b_id: V) + -> ures; + fn merge_bnd<T:Copy + InferStr + LatticeValue>( + &self, + a: &Bound<T>, + b: &Bound<T>, + lattice_op: LatticeOp<T>) + -> cres<Bound<T>>; + fn set_var_to_merged_bounds<T:Copy + InferStr + LatticeValue, + V:Copy+Eq+ToStr+Vid+UnifyVid<Bounds<T>>>( + &self, + v_id: V, + a: &Bounds<T>, + b: &Bounds<T>, + rank: uint) + -> ures; + fn bnds<T:Copy + InferStr + LatticeValue>( + &self, + a: &Bound<T>, + b: &Bound<T>) + -> ures; +} + +impl CombineFieldsLatticeMethods for CombineFields { + fn var_sub_var<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>( + &self, + a_id: V, + b_id: V) + -> ures { /*! * * Make one variable a subtype of another variable. This is a @@ -127,12 +164,12 @@ impl CombineFields { } /// make variable a subtype of T - pub fn var_sub_t<T:Copy + InferStr + LatticeValue, - V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>(&self, - a_id: V, - b: T) - -> ures - { + fn var_sub_t<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>( + &self, + a_id: V, + b: T) + -> ures { /*! * * Make a variable (`a_id`) a subtype of the concrete type `b` */ @@ -151,12 +188,12 @@ impl CombineFields { a_id, a_bounds, b_bounds, node_a.rank) } - pub fn t_sub_var<T:Copy + InferStr + LatticeValue, - V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>(&self, - a: T, - b_id: V) - -> ures - { + fn t_sub_var<T:Copy + InferStr + LatticeValue, + V:Copy + Eq + ToStr + Vid + UnifyVid<Bounds<T>>>( + &self, + a: T, + b_id: V) + -> ures { /*! * * Make a concrete type (`a`) a subtype of the variable `b_id` */ @@ -175,12 +212,12 @@ impl CombineFields { b_id, a_bounds, b_bounds, node_b.rank) } - pub fn merge_bnd<T:Copy + InferStr + LatticeValue>(&self, - a: &Bound<T>, - b: &Bound<T>, - lattice_op: - LatticeOp<T>) - -> cres<Bound<T>> { + fn merge_bnd<T:Copy + InferStr + LatticeValue>( + &self, + a: &Bound<T>, + b: &Bound<T>, + lattice_op: LatticeOp<T>) + -> cres<Bound<T>> { /*! * * Combines two bounds into a more general bound. */ @@ -202,14 +239,14 @@ impl CombineFields { } } - pub fn set_var_to_merged_bounds<T:Copy + InferStr + LatticeValue, - V:Copy+Eq+ToStr+Vid+UnifyVid<Bounds<T>>>( - &self, - v_id: V, - a: &Bounds<T>, - b: &Bounds<T>, - rank: uint) - -> ures { + fn set_var_to_merged_bounds<T:Copy + InferStr + LatticeValue, + V:Copy+Eq+ToStr+Vid+UnifyVid<Bounds<T>>>( + &self, + v_id: V, + a: &Bounds<T>, + b: &Bounds<T>, + rank: uint) + -> ures { /*! * * Updates the bounds for the variable `v_id` to be the intersection @@ -264,10 +301,10 @@ impl CombineFields { uok() } - pub fn bnds<T:Copy + InferStr + LatticeValue>(&self, - a: &Bound<T>, - b: &Bound<T>) - -> ures { + fn bnds<T:Copy + InferStr + LatticeValue>(&self, + a: &Bound<T>, + b: &Bound<T>) + -> ures { debug!("bnds(%s <: %s)", a.inf_str(self.infcx), b.inf_str(self.infcx)); let _r = indenter(); @@ -493,7 +530,7 @@ pub fn var_ids<T:Combine>(this: &T, isr: isr_alist) -> ~[RegionVid] { ty::re_infer(ty::ReVar(r)) => { result.push(r); } r => { this.infcx().tcx.sess.span_bug( - this.span(), + this.trace().origin.span(), fmt!("Found non-region-vid: %?", r)); } } @@ -503,7 +540,7 @@ pub fn var_ids<T:Combine>(this: &T, isr: isr_alist) -> ~[RegionVid] { pub fn is_var_in_set(new_vars: &[RegionVid], r: ty::Region) -> bool { match r { - ty::re_infer(ty::ReVar(ref v)) => new_vars.contains(v), + ty::re_infer(ty::ReVar(ref v)) => new_vars.iter().any_(|x| x == v), _ => false } } diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 1a73d5bd36b..efb1dc200b5 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use middle::ty::{BuiltinBounds}; use middle::ty::RegionVid; @@ -20,6 +19,7 @@ use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::{cres, InferCtxt}; use middle::typeck::infer::fold_regions_in_sig; +use middle::typeck::infer::{TypeTrace, Subtype}; use middle::typeck::isr_alist; use util::common::indent; use util::ppaux::mt_to_str; @@ -28,7 +28,7 @@ use extra::list; use syntax::abi::AbiSet; use syntax::ast; use syntax::ast::{Many, Once, extern_fn, m_const, impure_fn}; -use syntax::ast::{pure_fn, unsafe_fn}; +use syntax::ast::{unsafe_fn}; use syntax::ast::{Onceness, purity}; use syntax::codemap::span; @@ -45,7 +45,7 @@ impl Combine for Lub { fn infcx(&self) -> @mut InferCtxt { self.infcx } fn tag(&self) -> ~str { ~"lub" } fn a_is_expected(&self) -> bool { self.a_is_expected } - fn span(&self) -> span { self.span } + fn trace(&self) -> TypeTrace { self.trace } fn sub(&self) -> Sub { Sub(**self) } fn lub(&self) -> Lub { Lub(**self) } @@ -92,8 +92,7 @@ impl Combine for Lub { match (a, b) { (unsafe_fn, _) | (_, unsafe_fn) => Ok(unsafe_fn), (impure_fn, _) | (_, impure_fn) => Ok(impure_fn), - (extern_fn, _) | (_, extern_fn) => Ok(extern_fn), - (pure_fn, pure_fn) => Ok(pure_fn) + (extern_fn, extern_fn) => Ok(extern_fn), } } @@ -121,9 +120,7 @@ impl Combine for Lub { a.inf_str(self.infcx), b.inf_str(self.infcx)); - do indent { - self.infcx.region_vars.lub_regions(self.span, a, b) - } + Ok(self.infcx.region_vars.lub_regions(Subtype(self.trace), a, b)) } fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> { @@ -139,10 +136,10 @@ impl Combine for Lub { // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_isr) = self.infcx.replace_bound_regions_with_fresh_regions( - self.span, a); + self.trace, a); let (b_with_fresh, _) = self.infcx.replace_bound_regions_with_fresh_regions( - self.span, b); + self.trace, b); // Collect constraints. let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh)); @@ -175,7 +172,7 @@ impl Combine for Lub { // Variables created during LUB computation which are // *related* to regions that pre-date the LUB computation // stay as they are. - if !tainted.all(|r| is_var_in_set(new_vars, *r)) { + if !tainted.iter().all(|r| is_var_in_set(new_vars, *r)) { debug!("generalize_region(r0=%?): \ non-new-variables found in %?", r0, tainted); @@ -189,7 +186,7 @@ impl Combine for Lub { // with. for list::each(a_isr) |pair| { let (a_br, a_r) = *pair; - if tainted.contains(&a_r) { + if tainted.iter().any_(|x| x == &a_r) { debug!("generalize_region(r0=%?): \ replacing with %?, tainted=%?", r0, a_br, tainted); @@ -198,7 +195,7 @@ impl Combine for Lub { } this.infcx.tcx.sess.span_bug( - this.span, + this.trace.origin.span(), fmt!("Region %? is not associated with \ any bound region from A!", r0)); } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 410e2fe23c1..3360edc6a46 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -8,241 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! - -# Type inference engine - -This is loosely based on standard HM-type inference, but with an -extension to try and accommodate subtyping. There is nothing -principled about this extension; it's sound---I hope!---but it's a -heuristic, ultimately, and does not guarantee that it finds a valid -typing even if one exists (in fact, there are known scenarios where it -fails, some of which may eventually become problematic). - -## Key idea - -The main change is that each type variable T is associated with a -lower-bound L and an upper-bound U. L and U begin as bottom and top, -respectively, but gradually narrow in response to new constraints -being introduced. When a variable is finally resolved to a concrete -type, it can (theoretically) select any type that is a supertype of L -and a subtype of U. - -There are several critical invariants which we maintain: - -- the upper-bound of a variable only becomes lower and the lower-bound - only becomes higher over time; -- the lower-bound L is always a subtype of the upper bound U; -- the lower-bound L and upper-bound U never refer to other type variables, - but only to types (though those types may contain type variables). - -> An aside: if the terms upper- and lower-bound confuse you, think of -> "supertype" and "subtype". The upper-bound is a "supertype" -> (super=upper in Latin, or something like that anyway) and the lower-bound -> is a "subtype" (sub=lower in Latin). I find it helps to visualize -> a simple class hierarchy, like Java minus interfaces and -> primitive types. The class Object is at the root (top) and other -> types lie in between. The bottom type is then the Null type. -> So the tree looks like: -> -> Object -> / \ -> String Other -> \ / -> (null) -> -> So the upper bound type is the "supertype" and the lower bound is the -> "subtype" (also, super and sub mean upper and lower in Latin, or something -> like that anyway). - -## Satisfying constraints - -At a primitive level, there is only one form of constraint that the -inference understands: a subtype relation. So the outside world can -say "make type A a subtype of type B". If there are variables -involved, the inferencer will adjust their upper- and lower-bounds as -needed to ensure that this relation is satisfied. (We also allow "make -type A equal to type B", but this is translated into "A <: B" and "B -<: A") - -As stated above, we always maintain the invariant that type bounds -never refer to other variables. This keeps the inference relatively -simple, avoiding the scenario of having a kind of graph where we have -to pump constraints along and reach a fixed point, but it does impose -some heuristics in the case where the user is relating two type -variables A <: B. - -Combining two variables such that variable A will forever be a subtype -of variable B is the trickiest part of the algorithm because there is -often no right choice---that is, the right choice will depend on -future constraints which we do not yet know. The problem comes about -because both A and B have bounds that can be adjusted in the future. -Let's look at some of the cases that can come up. - -Imagine, to start, the best case, where both A and B have an upper and -lower bound (that is, the bounds are not top nor bot respectively). In -that case, if we're lucky, A.ub <: B.lb, and so we know that whatever -A and B should become, they will forever have the desired subtyping -relation. We can just leave things as they are. - -### Option 1: Unify - -However, suppose that A.ub is *not* a subtype of B.lb. In -that case, we must make a decision. One option is to unify A -and B so that they are one variable whose bounds are: - - UB = GLB(A.ub, B.ub) - LB = LUB(A.lb, B.lb) - -(Note that we will have to verify that LB <: UB; if it does not, the -types are not intersecting and there is an error) In that case, A <: B -holds trivially because A==B. However, we have now lost some -flexibility, because perhaps the user intended for A and B to end up -as different types and not the same type. - -Pictorally, what this does is to take two distinct variables with -(hopefully not completely) distinct type ranges and produce one with -the intersection. - - B.ub B.ub - /\ / - A.ub / \ A.ub / - / \ / \ \ / - / X \ UB - / / \ \ / \ - / / / \ / / - \ \ / / \ / - \ X / LB - \ / \ / / \ - \ / \ / / \ - A.lb B.lb A.lb B.lb - - -### Option 2: Relate UB/LB - -Another option is to keep A and B as distinct variables but set their -bounds in such a way that, whatever happens, we know that A <: B will hold. -This can be achieved by ensuring that A.ub <: B.lb. In practice there -are two ways to do that, depicted pictorally here: - - Before Option #1 Option #2 - - B.ub B.ub B.ub - /\ / \ / \ - A.ub / \ A.ub /(B')\ A.ub /(B')\ - / \ / \ \ / / \ / / - / X \ __UB____/ UB / - / / \ \ / | | / - / / / \ / | | / - \ \ / / /(A')| | / - \ X / / LB ______LB/ - \ / \ / / / \ / (A')/ \ - \ / \ / \ / \ \ / \ - A.lb B.lb A.lb B.lb A.lb B.lb - -In these diagrams, UB and LB are defined as before. As you can see, -the new ranges `A'` and `B'` are quite different from the range that -would be produced by unifying the variables. - -### What we do now - -Our current technique is to *try* (transactionally) to relate the -existing bounds of A and B, if there are any (i.e., if `UB(A) != top -&& LB(B) != bot`). If that succeeds, we're done. If it fails, then -we merge A and B into same variable. - -This is not clearly the correct course. For example, if `UB(A) != -top` but `LB(B) == bot`, we could conceivably set `LB(B)` to `UB(A)` -and leave the variables unmerged. This is sometimes the better -course, it depends on the program. - -The main case which fails today that I would like to support is: - - fn foo<T>(x: T, y: T) { ... } - - fn bar() { - let x: @mut int = @mut 3; - let y: @int = @3; - foo(x, y); - } - -In principle, the inferencer ought to find that the parameter `T` to -`foo(x, y)` is `@const int`. Today, however, it does not; this is -because the type variable `T` is merged with the type variable for -`X`, and thus inherits its UB/LB of `@mut int`. This leaves no -flexibility for `T` to later adjust to accommodate `@int`. - -### What to do when not all bounds are present - -In the prior discussion we assumed that A.ub was not top and B.lb was -not bot. Unfortunately this is rarely the case. Often type variables -have "lopsided" bounds. For example, if a variable in the program has -been initialized but has not been used, then its corresponding type -variable will have a lower bound but no upper bound. When that -variable is then used, we would like to know its upper bound---but we -don't have one! In this case we'll do different things depending on -how the variable is being used. - -## Transactional support - -Whenever we adjust merge variables or adjust their bounds, we always -keep a record of the old value. This allows the changes to be undone. - -## Regions - -I've only talked about type variables here, but region variables -follow the same principle. They have upper- and lower-bounds. A -region A is a subregion of a region B if A being valid implies that B -is valid. This basically corresponds to the block nesting structure: -the regions for outer block scopes are superregions of those for inner -block scopes. - -## Integral and floating-point type variables - -There is a third variety of type variable that we use only for -inferring the types of unsuffixed integer literals. Integral type -variables differ from general-purpose type variables in that there's -no subtyping relationship among the various integral types, so instead -of associating each variable with an upper and lower bound, we just -use simple unification. Each integer variable is associated with at -most one integer type. Floating point types are handled similarly to -integral types. - -## GLB/LUB +/*! See doc.rs for documentation */ -Computing the greatest-lower-bound and least-upper-bound of two -types/regions is generally straightforward except when type variables -are involved. In that case, we follow a similar "try to use the bounds -when possible but otherwise merge the variables" strategy. In other -words, `GLB(A, B)` where `A` and `B` are variables will often result -in `A` and `B` being merged and the result being `A`. - -## Type coercion - -We have a notion of assignability which differs somewhat from -subtyping; in particular it may cause region borrowing to occur. See -the big comment later in this file on Type Coercion for specifics. - -### In conclusion - -I showed you three ways to relate `A` and `B`. There are also more, -of course, though I'm not sure if there are any more sensible options. -The main point is that there are various options, each of which -produce a distinct range of types for `A` and `B`. Depending on what -the correct values for A and B are, one of these options will be the -right choice: but of course we don't know the right values for A and B -yet, that's what we're trying to find! In our code, we opt to unify -(Option #1). - -# Implementation details - -We make use of a trait-like impementation strategy to consolidate -duplicated code between subtypes, GLB, and LUB computations. See the -section on "Type Combining" below for details. - -*/ - -use core::prelude::*; pub use middle::ty::IntVarValue; pub use middle::typeck::infer::resolve::resolve_and_force_all_but_regions; @@ -261,14 +28,17 @@ use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys}; use middle::typeck::infer::region_inference::{RegionVarBindings}; use middle::typeck::infer::resolve::{resolver}; use middle::typeck::infer::sub::Sub; +use middle::typeck::infer::lub::Lub; use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::unify::{ValsAndBindings, Root}; +use middle::typeck::infer::error_reporting::ErrorReporting; use middle::typeck::isr_alist; use util::common::indent; -use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str}; +use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str, Repr, + UserString}; -use core::result; -use core::vec; +use std::result; +use std::vec; use extra::list::Nil; use extra::smallintmap::SmallIntMap; use syntax::ast::{m_imm, m_mutbl}; @@ -276,17 +46,20 @@ use syntax::ast; use syntax::codemap; use syntax::codemap::span; +pub mod doc; pub mod macros; pub mod combine; pub mod glb; pub mod lattice; pub mod lub; +#[path = "region_inference/mod.rs"] pub mod region_inference; pub mod resolve; pub mod sub; pub mod to_str; pub mod unify; pub mod coercion; +pub mod error_reporting; pub type Bound<T> = Option<T>; pub struct Bounds<T> { @@ -320,6 +93,133 @@ pub struct InferCtxt { region_vars: RegionVarBindings, } +/// Why did we require that the two types be related? +/// +/// See `error_reporting.rs` for more details +pub enum TypeOrigin { + // Not yet categorized in a better way + Misc(span), + + // Checking that method of impl is compatible with trait + MethodCompatCheck(span), + + // Checking that this expression can be assigned where it needs to be + ExprAssignable(@ast::expr), + + // Relating trait refs when resolving vtables + RelateTraitRefs(span), + + // Relating trait refs when resolving vtables + RelateSelfType(span), + + // Computing common supertype in a match expression + MatchExpression(span), + + // Computing common supertype in an if expression + IfExpression(span), +} + +/// See `error_reporting.rs` for more details +pub enum ValuePairs { + Types(ty::expected_found<ty::t>), + TraitRefs(ty::expected_found<@ty::TraitRef>), +} + +/// The trace designates the path through inference that we took to +/// encounter an error or subtyping constraint. +/// +/// See `error_reporting.rs` for more details. +pub struct TypeTrace { + origin: TypeOrigin, + values: ValuePairs, +} + +/// The origin of a `r1 <= r2` constraint. +/// +/// See `error_reporting.rs` for more details +pub enum SubregionOrigin { + // Arose from a subtyping relation + Subtype(TypeTrace), + + // Invocation of closure must be within its lifetime + InvokeClosure(span), + + // Dereference of borrowed pointer must be within its lifetime + DerefPointer(span), + + // Closure bound must not outlive captured free variables + FreeVariable(span), + + // Index into slice must be within its lifetime + IndexSlice(span), + + // When casting `&'a T` to an `&'b Trait` object, + // relating `'a` to `'b` + RelateObjectBound(span), + + // Creating a pointer `b` to contents of another borrowed pointer + Reborrow(span), + + // (&'a &'b T) where a >= b + ReferenceOutlivesReferent(ty::t, span), + + // A `ref b` whose region does not enclose the decl site + BindingTypeIsNotValidAtDecl(span), + + // Regions appearing in a method receiver must outlive method call + CallRcvr(span), + + // Regions appearing in a function argument must outlive func call + CallArg(span), + + // Region in return type of invoked fn must enclose call + CallReturn(span), + + // Region resulting from a `&` expr must enclose the `&` expr + AddrOf(span), + + // An auto-borrow that does not enclose the expr where it occurs + AutoBorrow(span), +} + +/// Reasons to create a region inference variable +/// +/// See `error_reporting.rs` for more details +pub enum RegionVariableOrigin { + // Region variables created for ill-categorized reasons, + // mostly indicates places in need of refactoring + MiscVariable(span), + + // Regions created by a `&P` or `[...]` pattern + PatternRegion(span), + + // Regions created by `&` operator + AddrOfRegion(span), + + // Regions created by `&[...]` literal + AddrOfSlice(span), + + // Regions created as part of an autoref of a method receiver + Autoref(span), + + // Regions created as part of an automatic coercion + Coercion(TypeTrace), + + // Region variables created for bound regions + // in a function or method that is called + BoundRegionInFnCall(span, ty::bound_region), + + // Region variables created for bound regions + // when doing subtyping/lub/glb computations + BoundRegionInFnType(span, ty::bound_region), + + BoundRegionInTypeOrImpl(span), + + BoundRegionInCoherence, + + BoundRegionError(span), +} + pub enum fixup_err { unresolved_int_ty(IntVid), unresolved_ty(TyVid), @@ -365,16 +265,51 @@ pub fn new_infer_ctxt(tcx: ty::ctxt) -> @mut InferCtxt { } } +pub fn common_supertype(cx: @mut InferCtxt, + origin: TypeOrigin, + a_is_expected: bool, + a: ty::t, + b: ty::t) + -> ty::t { + /*! + * Computes the least upper-bound of `a` and `b`. If this is + * not possible, reports an error and returns ty::err. + */ + + debug!("common_supertype(%s, %s)", a.inf_str(cx), b.inf_str(cx)); + + let trace = TypeTrace { + origin: origin, + values: Types(expected_found(a_is_expected, a, b)) + }; + + let result = do cx.commit { + cx.lub(a_is_expected, trace).tys(a, b) + }; + + match result { + Ok(t) => t, + Err(ref err) => { + cx.report_and_explain_type_error(trace, err); + ty::mk_err() + } + } +} + pub fn mk_subty(cx: @mut InferCtxt, a_is_expected: bool, - span: span, + origin: TypeOrigin, a: ty::t, b: ty::t) -> ures { debug!("mk_subty(%s <: %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.commit { - cx.sub(a_is_expected, span).tys(a, b) + let trace = TypeTrace { + origin: origin, + values: Types(expected_found(a_is_expected, a, b)) + }; + cx.sub(a_is_expected, trace).tys(a, b) } }.to_ures() } @@ -383,35 +318,40 @@ pub fn can_mk_subty(cx: @mut InferCtxt, a: ty::t, b: ty::t) -> ures { debug!("can_mk_subty(%s <: %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.probe { - cx.sub(true, codemap::dummy_sp()).tys(a, b) + let trace = TypeTrace { + origin: Misc(codemap::dummy_sp()), + values: Types(expected_found(true, a, b)) + }; + cx.sub(true, trace).tys(a, b) } }.to_ures() } pub fn mk_subr(cx: @mut InferCtxt, a_is_expected: bool, - span: span, + origin: SubregionOrigin, a: ty::Region, - b: ty::Region) - -> ures { + b: ty::Region) { debug!("mk_subr(%s <: %s)", a.inf_str(cx), b.inf_str(cx)); - do indent { - do cx.commit { - cx.sub(a_is_expected, span).regions(a, b) - } - }.to_ures() + cx.region_vars.start_snapshot(); + cx.region_vars.make_subregion(origin, a, b); + cx.region_vars.commit(); } pub fn mk_eqty(cx: @mut InferCtxt, a_is_expected: bool, - span: span, + origin: TypeOrigin, a: ty::t, b: ty::t) -> ures { debug!("mk_eqty(%s <: %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.commit { - let suber = cx.sub(a_is_expected, span); + let trace = TypeTrace { + origin: origin, + values: Types(expected_found(a_is_expected, a, b)) + }; + let suber = cx.sub(a_is_expected, trace); eq_tys(&suber, a, b) } }.to_ures() @@ -419,31 +359,49 @@ pub fn mk_eqty(cx: @mut InferCtxt, pub fn mk_sub_trait_refs(cx: @mut InferCtxt, a_is_expected: bool, - span: span, - a: &ty::TraitRef, - b: &ty::TraitRef) + origin: TypeOrigin, + a: @ty::TraitRef, + b: @ty::TraitRef) -> ures { debug!("mk_sub_trait_refs(%s <: %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.commit { - let suber = cx.sub(a_is_expected, span); + let trace = TypeTrace { + origin: origin, + values: TraitRefs(expected_found(a_is_expected, a, b)) + }; + let suber = cx.sub(a_is_expected, trace); suber.trait_refs(a, b) } }.to_ures() } +fn expected_found<T>(a_is_expected: bool, + a: T, + b: T) -> ty::expected_found<T> { + if a_is_expected { + ty::expected_found {expected: a, found: b} + } else { + ty::expected_found {expected: b, found: a} + } +} + pub fn mk_coercety(cx: @mut InferCtxt, a_is_expected: bool, - span: span, + origin: TypeOrigin, a: ty::t, b: ty::t) -> CoerceResult { debug!("mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.commit { - Coerce(cx.combine_fields(a_is_expected, span)).tys(a, b) + let trace = TypeTrace { + origin: origin, + values: Types(expected_found(a_is_expected, a, b)) + }; + Coerce(cx.combine_fields(a_is_expected, trace)).tys(a, b) } } } @@ -452,8 +410,11 @@ pub fn can_mk_coercety(cx: @mut InferCtxt, a: ty::t, b: ty::t) -> ures { debug!("can_mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.probe { - let span = codemap::dummy_sp(); - Coerce(cx.combine_fields(true, span)).tys(a, b) + let trace = TypeTrace { + origin: Misc(codemap::dummy_sp()), + values: Types(expected_found(true, a, b)) + }; + Coerce(cx.combine_fields(true, trace)).tys(a, b) } }.to_ures() } @@ -536,15 +497,21 @@ struct Snapshot { } impl InferCtxt { - pub fn combine_fields(@mut self, a_is_expected: bool, span: span) + pub fn combine_fields(@mut self, + a_is_expected: bool, + trace: TypeTrace) -> CombineFields { CombineFields {infcx: self, a_is_expected: a_is_expected, - span: span} + trace: trace} } - pub fn sub(@mut self, a_is_expected: bool, span: span) -> Sub { - Sub(self.combine_fields(a_is_expected, span)) + pub fn sub(@mut self, a_is_expected: bool, trace: TypeTrace) -> Sub { + Sub(self.combine_fields(a_is_expected, trace)) + } + + pub fn lub(@mut self, a_is_expected: bool, trace: TypeTrace) -> Lub { + Lub(self.combine_fields(a_is_expected, trace)) } pub fn in_snapshot(&self) -> bool { @@ -582,7 +549,7 @@ impl InferCtxt { debug!("commit()"); do indent { - let r = self.try(f); + let r = self.try(|| f()); self.ty_var_bindings.bindings.truncate(0); self.int_var_bindings.bindings.truncate(0); @@ -664,31 +631,13 @@ impl InferCtxt { ty::mk_float_var(self.tcx, self.next_float_var_id()) } - pub fn next_region_var_nb(&mut self, span: span) -> ty::Region { - ty::re_infer(ty::ReVar(self.region_vars.new_region_var(span))) - } - - pub fn next_region_var_with_lb(&mut self, - span: span, - lb_region: ty::Region) - -> ty::Region { - let region_var = self.next_region_var_nb(span); - - // add lb_region as a lower bound on the newly built variable - assert!(self.region_vars.make_subregion(span, - lb_region, - region_var).is_ok()); - - return region_var; - } - - pub fn next_region_var(&mut self, span: span, scope_id: ast::node_id) - -> ty::Region { - self.next_region_var_with_lb(span, ty::re_scope(scope_id)) + pub fn next_region_var(&mut self, origin: RegionVariableOrigin) -> ty::Region { + ty::re_infer(ty::ReVar(self.region_vars.new_region_var(origin))) } - pub fn resolve_regions(&mut self) { - self.region_vars.resolve_regions(); + pub fn resolve_regions(@mut self) { + let errors = self.region_vars.resolve_regions(); + self.report_region_errors(&errors); // see error_reporting.rs } pub fn ty_to_str(@mut self, t: ty::t) -> ~str { @@ -717,10 +666,11 @@ impl InferCtxt { trait_ref.def_id, copy trait_ref.substs, ty::UniqTraitStore, - ast::m_imm); + ast::m_imm, + ty::EmptyBuiltinBounds()); let dummy1 = self.resolve_type_vars_if_possible(dummy0); match ty::get(dummy1).sty { - ty::ty_trait(ref def_id, ref substs, _, _) => { + ty::ty_trait(ref def_id, ref substs, _, _, _) => { ty::TraitRef {def_id: *def_id, substs: copy *substs} } @@ -809,19 +759,15 @@ impl InferCtxt { } pub fn replace_bound_regions_with_fresh_regions(&mut self, - span: span, + trace: TypeTrace, fsig: &ty::FnSig) - -> (ty::FnSig, - isr_alist) { + -> (ty::FnSig, isr_alist) { let(isr, _, fn_sig) = replace_bound_regions_in_fn_sig(self.tcx, @Nil, None, fsig, |br| { - // N.B.: The name of the bound region doesn't have anything to - // do with the region variable that's created for it. The - // only thing we're doing with `br` here is using it in the - // debug message. - let rvar = self.next_region_var_nb(span); + let rvar = self.next_region_var( + BoundRegionInFnType(trace.origin.span(), br)); debug!("Bound region %s maps to %?", - bound_region_to_str(self.tcx, br), + bound_region_to_str(self.tcx, "", false, br), rvar); rvar }); @@ -835,6 +781,128 @@ pub fn fold_regions_in_sig( fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnSig { do ty::fold_sig(fn_sig) |t| { - ty::fold_regions(tcx, t, fldr) + ty::fold_regions(tcx, t, |r, in_fn| fldr(r, in_fn)) + } +} + +impl TypeTrace { + pub fn span(&self) -> span { + self.origin.span() + } +} + +impl Repr for TypeTrace { + fn repr(&self, tcx: ty::ctxt) -> ~str { + fmt!("TypeTrace(%s)", self.origin.repr(tcx)) + } +} + +impl TypeOrigin { + pub fn span(&self) -> span { + match *self { + MethodCompatCheck(span) => span, + ExprAssignable(expr) => expr.span, + Misc(span) => span, + RelateTraitRefs(span) => span, + RelateSelfType(span) => span, + MatchExpression(span) => span, + IfExpression(span) => span, + } } } + +impl Repr for TypeOrigin { + fn repr(&self, tcx: ty::ctxt) -> ~str { + match *self { + MethodCompatCheck(a) => fmt!("MethodCompatCheck(%s)", a.repr(tcx)), + ExprAssignable(a) => fmt!("ExprAssignable(%s)", a.repr(tcx)), + Misc(a) => fmt!("Misc(%s)", a.repr(tcx)), + RelateTraitRefs(a) => fmt!("RelateTraitRefs(%s)", a.repr(tcx)), + RelateSelfType(a) => fmt!("RelateSelfType(%s)", a.repr(tcx)), + MatchExpression(a) => fmt!("MatchExpression(%s)", a.repr(tcx)), + IfExpression(a) => fmt!("IfExpression(%s)", a.repr(tcx)), + } + } +} + +impl SubregionOrigin { + pub fn span(&self) -> span { + match *self { + Subtype(a) => a.span(), + InvokeClosure(a) => a, + DerefPointer(a) => a, + FreeVariable(a) => a, + IndexSlice(a) => a, + RelateObjectBound(a) => a, + Reborrow(a) => a, + ReferenceOutlivesReferent(_, a) => a, + BindingTypeIsNotValidAtDecl(a) => a, + CallRcvr(a) => a, + CallArg(a) => a, + CallReturn(a) => a, + AddrOf(a) => a, + AutoBorrow(a) => a, + } + } +} + +impl Repr for SubregionOrigin { + fn repr(&self, tcx: ty::ctxt) -> ~str { + match *self { + Subtype(a) => fmt!("Subtype(%s)", a.repr(tcx)), + InvokeClosure(a) => fmt!("InvokeClosure(%s)", a.repr(tcx)), + DerefPointer(a) => fmt!("DerefPointer(%s)", a.repr(tcx)), + FreeVariable(a) => fmt!("FreeVariable(%s)", a.repr(tcx)), + IndexSlice(a) => fmt!("IndexSlice(%s)", a.repr(tcx)), + RelateObjectBound(a) => fmt!("RelateObjectBound(%s)", a.repr(tcx)), + Reborrow(a) => fmt!("Reborrow(%s)", a.repr(tcx)), + ReferenceOutlivesReferent(_, a) => fmt!("ReferenceOutlivesReferent(%s)", a.repr(tcx)), + BindingTypeIsNotValidAtDecl(a) => fmt!("BindingTypeIsNotValidAtDecl(%s)", a.repr(tcx)), + CallRcvr(a) => fmt!("CallRcvr(%s)", a.repr(tcx)), + CallArg(a) => fmt!("CallArg(%s)", a.repr(tcx)), + CallReturn(a) => fmt!("CallReturn(%s)", a.repr(tcx)), + AddrOf(a) => fmt!("AddrOf(%s)", a.repr(tcx)), + AutoBorrow(a) => fmt!("AutoBorrow(%s)", a.repr(tcx)), + } + } +} + +impl RegionVariableOrigin { + pub fn span(&self) -> span { + match *self { + MiscVariable(a) => a, + PatternRegion(a) => a, + AddrOfRegion(a) => a, + AddrOfSlice(a) => a, + Autoref(a) => a, + Coercion(a) => a.span(), + BoundRegionInFnCall(a, _) => a, + BoundRegionInFnType(a, _) => a, + BoundRegionInTypeOrImpl(a) => a, + BoundRegionInCoherence => codemap::dummy_sp(), + BoundRegionError(a) => a, + } + } +} + +impl Repr for RegionVariableOrigin { + fn repr(&self, tcx: ty::ctxt) -> ~str { + match *self { + MiscVariable(a) => fmt!("MiscVariable(%s)", a.repr(tcx)), + PatternRegion(a) => fmt!("PatternRegion(%s)", a.repr(tcx)), + AddrOfRegion(a) => fmt!("AddrOfRegion(%s)", a.repr(tcx)), + AddrOfSlice(a) => fmt!("AddrOfSlice(%s)", a.repr(tcx)), + Autoref(a) => fmt!("Autoref(%s)", a.repr(tcx)), + Coercion(a) => fmt!("Coercion(%s)", a.repr(tcx)), + BoundRegionInFnCall(a, b) => fmt!("BoundRegionInFnCall(%s,%s)", + a.repr(tcx), b.repr(tcx)), + BoundRegionInFnType(a, b) => fmt!("BoundRegionInFnType(%s,%s)", + a.repr(tcx), b.repr(tcx)), + BoundRegionInTypeOrImpl(a) => fmt!("BoundRegionInTypeOrImpl(%s)", + a.repr(tcx)), + BoundRegionInCoherence => fmt!("BoundRegionInCoherence"), + BoundRegionError(a) => fmt!("BoundRegionError(%s)", a.repr(tcx)), + } + } +} + diff --git a/src/librustc/middle/typeck/infer/region_inference/doc.rs b/src/librustc/middle/typeck/infer/region_inference/doc.rs new file mode 100644 index 00000000000..df6d5dc1b20 --- /dev/null +++ b/src/librustc/middle/typeck/infer/region_inference/doc.rs @@ -0,0 +1,773 @@ +// 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. + +/*! + +Region inference module. + +# Terminology + +Note that we use the terms region and lifetime interchangeably, +though the term `lifetime` is preferred. + +# Introduction + +Region inference uses a somewhat more involved algorithm than type +inference. It is not the most efficient thing ever written though it +seems to work well enough in practice (famous last words). The reason +that we use a different algorithm is because, unlike with types, it is +impractical to hand-annotate with regions (in some cases, there aren't +even the requisite syntactic forms). So we have to get it right, and +it's worth spending more time on a more involved analysis. Moreover, +regions are a simpler case than types: they don't have aggregate +structure, for example. + +Unlike normal type inference, which is similar in spirit to H-M and thus +works progressively, the region type inference works by accumulating +constraints over the course of a function. Finally, at the end of +processing a function, we process and solve the constraints all at +once. + +The constraints are always of one of three possible forms: + +- ConstrainVarSubVar(R_i, R_j) states that region variable R_i + must be a subregion of R_j +- ConstrainRegSubVar(R, R_i) states that the concrete region R + (which must not be a variable) must be a subregion of the varibale R_i +- ConstrainVarSubReg(R_i, R) is the inverse + +# Building up the constraints + +Variables and constraints are created using the following methods: + +- `new_region_var()` creates a new, unconstrained region variable; +- `make_subregion(R_i, R_j)` states that R_i is a subregion of R_j +- `lub_regions(R_i, R_j) -> R_k` returns a region R_k which is + the smallest region that is greater than both R_i and R_j +- `glb_regions(R_i, R_j) -> R_k` returns a region R_k which is + the greatest region that is smaller than both R_i and R_j + +The actual region resolution algorithm is not entirely +obvious, though it is also not overly complex. + +## Snapshotting + +It is also permitted to try (and rollback) changes to the graph. This +is done by invoking `start_snapshot()`, which returns a value. Then +later you can call `rollback_to()` which undoes the work. +Alternatively, you can call `commit()` which ends all snapshots. +Snapshots can be recursive---so you can start a snapshot when another +is in progress, but only the root snapshot can "commit". + +# Resolving constraints + +The constraint resolution algorithm is not super complex but also not +entirely obvious. Here I describe the problem somewhat abstractly, +then describe how the current code works. There may be other, smarter +ways of doing this with which I am unfamiliar and can't be bothered to +research at the moment. - NDM + +## The problem + +Basically our input is a directed graph where nodes can be divided +into two categories: region variables and concrete regions. Each edge +`R -> S` in the graph represents a constraint that the region `R` is a +subregion of the region `S`. + +Region variable nodes can have arbitrary degree. There is one region +variable node per region variable. + +Each concrete region node is associated with some, well, concrete +region: e.g., a free lifetime, or the region for a particular scope. +Note that there may be more than one concrete region node for a +particular region value. Moreover, because of how the graph is built, +we know that all concrete region nodes have either in-degree 1 or +out-degree 1. + +Before resolution begins, we build up the constraints in a hashmap +that maps `Constraint` keys to spans. During resolution, we construct +the actual `Graph` structure that we describe here. + +## Our current algorithm + +We divide region variables into two groups: Expanding and Contracting. +Expanding region variables are those that have a concrete region +predecessor (direct or indirect). Contracting region variables are +all others. + +We first resolve the values of Expanding region variables and then +process Contracting ones. We currently use an iterative, fixed-point +procedure (but read on, I believe this could be replaced with a linear +walk). Basically we iterate over the edges in the graph, ensuring +that, if the source of the edge has a value, then this value is a +subregion of the target value. If the target does not yet have a +value, it takes the value from the source. If the target already had +a value, then the resulting value is Least Upper Bound of the old and +new values. When we are done, each Expanding node will have the +smallest region that it could possibly have and still satisfy the +constraints. + +We next process the Contracting nodes. Here we again iterate over the +edges, only this time we move values from target to source (if the +source is a Contracting node). For each contracting node, we compute +its value as the GLB of all its successors. Basically contracting +nodes ensure that there is overlap between their successors; we will +ultimately infer the largest overlap possible. + +# The Region Hierarchy + +## Without closures + +Let's first consider the region hierarchy without thinking about +closures, because they add a lot of complications. The region +hierarchy *basically* mirrors the lexical structure of the code. +There is a region for every piece of 'evaluation' that occurs, meaning +every expression, block, and pattern (patterns are considered to +"execute" by testing the value they are applied to and creating any +relevant bindings). So, for example: + + fn foo(x: int, y: int) { // -+ + // +------------+ // | + // | +-----+ // | + // | +-+ +-+ +-+ // | + // | | | | | | | // | + // v v v v v v v // | + let z = x + y; // | + ... // | + } // -+ + + fn bar() { ... } + +In this example, there is a region for the fn body block as a whole, +and then a subregion for the declaration of the local variable. +Within that, there are sublifetimes for the assignment pattern and +also the expression `x + y`. The expression itself has sublifetimes +for evaluating `x` and and `y`. + +## Function calls + +Function calls are a bit tricky. I will describe how we handle them +*now* and then a bit about how we can improve them (Issue #6268). + +Consider a function call like `func(expr1, expr2)`, where `func`, +`arg1`, and `arg2` are all arbitrary expressions. Currently, +we construct a region hierarchy like: + + +----------------+ + | | + +--+ +---+ +---+| + v v v v v vv + func(expr1, expr2) + +Here you can see that the call as a whole has a region and the +function plus arguments are subregions of that. As a side-effect of +this, we get a lot of spurious errors around nested calls, in +particular when combined with `&mut` functions. For example, a call +like this one + + self.foo(self.bar()) + +where both `foo` and `bar` are `&mut self` functions will always yield +an error. + +Here is a more involved example (which is safe) so we can see what's +going on: + + struct Foo { f: uint, g: uint } + ... + fn add(p: &mut uint, v: uint) { + *p += v; + } + ... + fn inc(p: &mut uint) -> uint { + *p += 1; *p + } + fn weird() { + let mut x: ~Foo = ~Foo { ... }; + 'a: add(&mut (*x).f, + 'b: inc(&mut (*x).f)) // (*) + } + +The important part is the line marked `(*)` which contains a call to +`add()`. The first argument is a mutable borrow of the field `f`. The +second argument also borrows the field `f`. Now, in the current borrow +checker, the first borrow is given the lifetime of the call to +`add()`, `'a`. The second borrow is given the lifetime of `'b` of the +call to `inc()`. Because `'b` is considered to be a sublifetime of +`'a`, an error is reported since there are two co-existing mutable +borrows of the same data. + +However, if we were to examine the lifetimes a bit more carefully, we +can see that this error is unnecessary. Let's examine the lifetimes +involved with `'a` in detail. We'll break apart all the steps involved +in a call expression: + + 'a: { + 'a_arg1: let a_temp1: ... = add; + 'a_arg2: let a_temp2: &'a mut uint = &'a mut (*x).f; + 'a_arg3: let a_temp3: uint = { + let b_temp1: ... = inc; + let b_temp2: &'b = &'b mut (*x).f; + 'b_call: b_temp1(b_temp2) + }; + 'a_call: a_temp1(a_temp2, a_temp3) // (**) + } + +Here we see that the lifetime `'a` includes a number of substatements. +In particular, there is this lifetime I've called `'a_call` that +corresponds to the *actual execution of the function `add()`*, after +all arguments have been evaluated. There is a corresponding lifetime +`'b_call` for the execution of `inc()`. If we wanted to be precise +about it, the lifetime of the two borrows should be `'a_call` and +`'b_call` respectively, since the borrowed pointers that were created +will not be dereferenced except during the execution itself. + +However, this model by itself is not sound. The reason is that +while the two borrowed pointers that are created will never be used +simultaneously, it is still true that the first borrowed pointer is +*created* before the second argument is evaluated, and so even though +it will not be *dereferenced* during the evaluation of the second +argument, it can still be *invalidated* by that evaluation. Consider +this similar but unsound example: + + struct Foo { f: uint, g: uint } + ... + fn add(p: &mut uint, v: uint) { + *p += v; + } + ... + fn consume(x: ~Foo) -> uint { + x.f + x.g + } + fn weird() { + let mut x: ~Foo = ~Foo { ... }; + 'a: add(&mut (*x).f, consume(x)) // (*) + } + +In this case, the second argument to `add` actually consumes `x`, thus +invalidating the first argument. + +So, for now, we exclude the `call` lifetimes from our model. +Eventually I would like to include them, but we will have to make the +borrow checker handle this situation correctly. In particular, if +there is a borrowed pointer created whose lifetime does not enclose +the borrow expression, we must issue sufficient restrictions to ensure +that the pointee remains valid. + +## Adding closures + +The other significant complication to the region hierarchy is +closures. I will describe here how closures should work, though some +of the work to implement this model is ongoing at the time of this +writing. + +The body of closures are type-checked along with the function that +creates them. However, unlike other expressions that appear within the +function body, it is not entirely obvious when a closure body executes +with respect to the other expressions. This is because the closure +body will execute whenever the closure is called; however, we can +never know precisely when the closure will be called, especially +without some sort of alias analysis. + +However, we can place some sort of limits on when the closure +executes. In particular, the type of every closure `fn:'r K` includes +a region bound `'r`. This bound indicates the maximum lifetime of that +closure; once we exit that region, the closure cannot be called +anymore. Therefore, we say that the lifetime of the closure body is a +sublifetime of the closure bound, but the closure body itself is unordered +with respect to other parts of the code. + +For example, consider the following fragment of code: + + 'a: { + let closure: fn:'a() = || 'b: { + 'c: ... + }; + 'd: ... + } + +Here we have four lifetimes, `'a`, `'b`, `'c`, and `'d`. The closure +`closure` is bounded by the lifetime `'a`. The lifetime `'b` is the +lifetime of the closure body, and `'c` is some statement within the +closure body. Finally, `'d` is a statement within the outer block that +created the closure. + +We can say that the closure body `'b` is a sublifetime of `'a` due to +the closure bound. By the usual lexical scoping conventions, the +statement `'c` is clearly a sublifetime of `'b`, and `'d` is a +sublifetime of `'d`. However, there is no ordering between `'c` and +`'d` per se (this kind of ordering between statements is actually only +an issue for dataflow; passes like the borrow checker must assume that +closures could execute at any time from the moment they are created +until they go out of scope). + +### Complications due to closure bound inference + +There is only one problem with the above model: in general, we do not +actually *know* the closure bounds during region inference! In fact, +closure bounds are almost always region variables! This is very tricky +because the inference system implicitly assumes that we can do things +like compute the LUB of two scoped lifetimes without needing to know +the values of any variables. + +Here is an example to illustrate the problem: + + fn identify<T>(x: T) -> T { x } + + fn foo() { // 'foo is the function body + 'a: { + let closure = identity(|| 'b: { + 'c: ... + }); + 'd: closure(); + } + 'e: ...; + } + +In this example, the closure bound is not explicit. At compile time, +we will create a region variable (let's call it `V0`) to represent the +closure bound. + +The primary difficulty arises during the constraint propagation phase. +Imagine there is some variable with incoming edges from `'c` and `'d`. +This means that the value of the variable must be `LUB('c, +'d)`. However, without knowing what the closure bound `V0` is, we +can't compute the LUB of `'c` and `'d`! Any we don't know the closure +bound until inference is done. + +The solution is to rely on the fixed point nature of inference. +Basically, when we must compute `LUB('c, 'd)`, we just use the current +value for `V0` as the closure's bound. If `V0`'s binding should +change, then we will do another round of inference, and the result of +`LUB('c, 'd)` will change. + +One minor implication of this is that the graph does not in fact track +the full set of dependencies between edges. We cannot easily know +whether the result of a LUB computation will change, since there may +be indirect dependencies on other variables that are not reflected on +the graph. Therefore, we must *always* iterate over all edges when +doing the fixed point calculation, not just those adjacent to nodes +whose values have changed. + +Were it not for this requirement, we could in fact avoid fixed-point +iteration altogether. In that universe, we could instead first +identify and remove strongly connected components (SCC) in the graph. +Note that such components must consist solely of region variables; all +of these variables can effectively be unified into a single variable. +Once SCCs are removed, we are left with a DAG. At this point, we +could walk the DAG in toplogical order once to compute the expanding +nodes, and again in reverse topological order to compute the +contracting nodes. However, as I said, this does not work given the +current treatment of closure bounds, but perhaps in the future we can +address this problem somehow and make region inference somewhat more +efficient. Note that this is solely a matter of performance, not +expressiveness. + +# Skolemization and functions + +One of the trickiest and most subtle aspects of regions is dealing +with the fact that region variables are bound in function types. I +strongly suggest that if you want to understand the situation, you +read this paper (which is, admittedly, very long, but you don't have +to read the whole thing): + +http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/ + +Although my explanation will never compete with SPJ's (for one thing, +his is approximately 100 pages), I will attempt to explain the basic +problem and also how we solve it. Note that the paper only discusses +subtyping, not the computation of LUB/GLB. + +The problem we are addressing is that there is a kind of subtyping +between functions with bound region parameters. Consider, for +example, whether the following relation holds: + + fn(&'a int) <: &fn(&'b int)? (Yes, a => b) + +The answer is that of course it does. These two types are basically +the same, except that in one we used the name `a` and one we used +the name `b`. + +In the examples that follow, it becomes very important to know whether +a lifetime is bound in a function type (that is, is a lifetime +parameter) or appears free (is defined in some outer scope). +Therefore, from now on I will write the bindings explicitly, using a +notation like `fn<a>(&'a int)` to indicate that `a` is a lifetime +parameter. + +Now let's consider two more function types. Here, we assume that the +`self` lifetime is defined somewhere outside and hence is not a +lifetime parameter bound by the function type (it "appears free"): + + fn<a>(&'a int) <: &fn(&'self int)? (Yes, a => self) + +This subtyping relation does in fact hold. To see why, you have to +consider what subtyping means. One way to look at `T1 <: T2` is to +say that it means that it is always ok to treat an instance of `T1` as +if it had the type `T2`. So, with our functions, it is always ok to +treat a function that can take pointers with any lifetime as if it +were a function that can only take a pointer with the specific +lifetime `&self`. After all, `&self` is a lifetime, after all, and +the function can take values of any lifetime. + +You can also look at subtyping as the *is a* relationship. This amounts +to the same thing: a function that accepts pointers with any lifetime +*is a* function that accepts pointers with some specific lifetime. + +So, what if we reverse the order of the two function types, like this: + + fn(&'self int) <: &fn<a>(&'a int)? (No) + +Does the subtyping relationship still hold? The answer of course is +no. In this case, the function accepts *only the lifetime `&self`*, +so it is not reasonable to treat it as if it were a function that +accepted any lifetime. + +What about these two examples: + + fn<a,b>(&'a int, &'b int) <: &fn<a>(&'a int, &'a int)? (Yes) + fn<a>(&'a int, &'a int) <: &fn<a,b>(&'a int, &'b int)? (No) + +Here, it is true that functions which take two pointers with any two +lifetimes can be treated as if they only accepted two pointers with +the same lifetime, but not the reverse. + +## The algorithm + +Here is the algorithm we use to perform the subtyping check: + +1. Replace all bound regions in the subtype with new variables +2. Replace all bound regions in the supertype with skolemized + equivalents. A "skolemized" region is just a new fresh region + name. +3. Check that the parameter and return types match as normal +4. Ensure that no skolemized regions 'leak' into region variables + visible from "the outside" + +Let's walk through some examples and see how this algorithm plays out. + +#### First example + +We'll start with the first example, which was: + + 1. fn<a>(&'a T) <: &fn<b>(&'b T)? Yes: a -> b + +After steps 1 and 2 of the algorithm we will have replaced the types +like so: + + 1. fn(&'A T) <: &fn(&'x T)? + +Here the upper case `&A` indicates a *region variable*, that is, a +region whose value is being inferred by the system. I also replaced +`&b` with `&x`---I'll use letters late in the alphabet (`x`, `y`, `z`) +to indicate skolemized region names. We can assume they don't appear +elsewhere. Note that neither the sub- nor the supertype bind any +region names anymore (as indicated by the absence of `<` and `>`). + +The next step is to check that the parameter types match. Because +parameters are contravariant, this means that we check whether: + + &'x T <: &'A T + +Region pointers are contravariant so this implies that + + &A <= &x + +must hold, where `<=` is the subregion relationship. Processing +*this* constrain simply adds a constraint into our graph that `&A <= +&x` and is considered successful (it can, for example, be satisfied by +choosing the value `&x` for `&A`). + +So far we have encountered no error, so the subtype check succeeds. + +#### The third example + +Now let's look first at the third example, which was: + + 3. fn(&'self T) <: &fn<b>(&'b T)? No! + +After steps 1 and 2 of the algorithm we will have replaced the types +like so: + + 3. fn(&'self T) <: &fn(&'x T)? + +This looks pretty much the same as before, except that on the LHS +`&self` was not bound, and hence was left as-is and not replaced with +a variable. The next step is again to check that the parameter types +match. This will ultimately require (as before) that `&self` <= `&x` +must hold: but this does not hold. `self` and `x` are both distinct +free regions. So the subtype check fails. + +#### Checking for skolemization leaks + +You may be wondering about that mysterious last step in the algorithm. +So far it has not been relevant. The purpose of that last step is to +catch something like *this*: + + fn<a>() -> fn(&'a T) <: &fn() -> fn<b>(&'b T)? No. + +Here the function types are the same but for where the binding occurs. +The subtype returns a function that expects a value in precisely one +region. The supertype returns a function that expects a value in any +region. If we allow an instance of the subtype to be used where the +supertype is expected, then, someone could call the fn and think that +the return value has type `fn<b>(&'b T)` when it really has type +`fn(&'a T)` (this is case #3, above). Bad. + +So let's step through what happens when we perform this subtype check. +We first replace the bound regions in the subtype (the supertype has +no bound regions). This gives us: + + fn() -> fn(&'A T) <: &fn() -> fn<b>(&'b T)? + +Now we compare the return types, which are covariant, and hence we have: + + fn(&'A T) <: &fn<b>(&'b T)? + +Here we skolemize the bound region in the supertype to yield: + + fn(&'A T) <: &fn(&'x T)? + +And then proceed to compare the argument types: + + &'x T <: &'A T + &A <= &x + +Finally, this is where it gets interesting! This is where an error +*should* be reported. But in fact this will not happen. The reason why +is that `A` is a variable: we will infer that its value is the fresh +region `x` and think that everything is happy. In fact, this behavior +is *necessary*, it was key to the first example we walked through. + +The difference between this example and the first one is that the variable +`A` already existed at the point where the skolemization occurred. In +the first example, you had two functions: + + fn<a>(&'a T) <: &fn<b>(&'b T) + +and hence `&A` and `&x` were created "together". In general, the +intention of the skolemized names is that they are supposed to be +fresh names that could never be equal to anything from the outside. +But when inference comes into play, we might not be respecting this +rule. + +So the way we solve this is to add a fourth step that examines the +constraints that refer to skolemized names. Basically, consider a +non-directed verison of the constraint graph. Let `Tainted(x)` be the +set of all things reachable from a skolemized variable `x`. +`Tainted(x)` should not contain any regions that existed before the +step at which the skolemization was performed. So this case here +would fail because `&x` was created alone, but is relatable to `&A`. + +## Computing the LUB and GLB + +The paper I pointed you at is written for Haskell. It does not +therefore considering subtyping and in particular does not consider +LUB or GLB computation. We have to consider this. Here is the +algorithm I implemented. + +First though, let's discuss what we are trying to compute in more +detail. The LUB is basically the "common supertype" and the GLB is +"common subtype"; one catch is that the LUB should be the +*most-specific* common supertype and the GLB should be *most general* +common subtype (as opposed to any common supertype or any common +subtype). + +Anyway, to help clarify, here is a table containing some +function pairs and their LUB/GLB: + +``` +Type 1 Type 2 LUB GLB +fn<a>(&a) fn(&X) fn(&X) fn<a>(&a) +fn(&A) fn(&X) -- fn<a>(&a) +fn<a,b>(&a, &b) fn<x>(&x, &x) fn<a>(&a, &a) fn<a,b>(&a, &b) +fn<a,b>(&a, &b, &a) fn<x,y>(&x, &y, &y) fn<a>(&a, &a, &a) fn<a,b,c>(&a,&b,&c) +``` + +### Conventions + +I use lower-case letters (e.g., `&a`) for bound regions and upper-case +letters for free regions (`&A`). Region variables written with a +dollar-sign (e.g., `$a`). I will try to remember to enumerate the +bound-regions on the fn type as well (e.g., `fn<a>(&a)`). + +### High-level summary + +Both the LUB and the GLB algorithms work in a similar fashion. They +begin by replacing all bound regions (on both sides) with fresh region +inference variables. Therefore, both functions are converted to types +that contain only free regions. We can then compute the LUB/GLB in a +straightforward way, as described in `combine.rs`. This results in an +interim type T. The algorithms then examine the regions that appear +in T and try to, in some cases, replace them with bound regions to +yield the final result. + +To decide whether to replace a region `R` that appears in `T` with a +bound region, the algorithms make use of two bits of information. +First is a set `V` that contains all region variables created as part +of the LUB/GLB computation. `V` will contain the region variables +created to replace the bound regions in the input types, but it also +contains 'intermediate' variables created to represent the LUB/GLB of +individual regions. Basically, when asked to compute the LUB/GLB of a +region variable with another region, the inferencer cannot oblige +immediately since the valuese of that variables are not known. +Therefore, it creates a new variable that is related to the two +regions. For example, the LUB of two variables `$x` and `$y` is a +fresh variable `$z` that is constrained such that `$x <= $z` and `$y +<= $z`. So `V` will contain these intermediate variables as well. + +The other important factor in deciding how to replace a region in T is +the function `Tainted($r)` which, for a region variable, identifies +all regions that the region variable is related to in some way +(`Tainted()` made an appearance in the subtype computation as well). + +### LUB + +The LUB algorithm proceeds in three steps: + +1. Replace all bound regions (on both sides) with fresh region + inference variables. +2. Compute the LUB "as normal", meaning compute the GLB of each + pair of argument types and the LUB of the return types and + so forth. Combine those to a new function type `F`. +3. Replace each region `R` that appears in `F` as follows: + - Let `V` be the set of variables created during the LUB + computational steps 1 and 2, as described in the previous section. + - If `R` is not in `V`, replace `R` with itself. + - If `Tainted(R)` contains a region that is not in `V`, + replace `R` with itself. + - Otherwise, select the earliest variable in `Tainted(R)` that originates + from the left-hand side and replace `R` with the bound region that + this variable was a replacement for. + +So, let's work through the simplest example: `fn(&A)` and `fn<a>(&a)`. +In this case, `&a` will be replaced with `$a` and the interim LUB type +`fn($b)` will be computed, where `$b=GLB(&A,$a)`. Therefore, `V = +{$a, $b}` and `Tainted($b) = { $b, $a, &A }`. When we go to replace +`$b`, we find that since `&A \in Tainted($b)` is not a member of `V`, +we leave `$b` as is. When region inference happens, `$b` will be +resolved to `&A`, as we wanted. + +Let's look at a more complex one: `fn(&a, &b)` and `fn(&x, &x)`. In +this case, we'll end up with a (pre-replacement) LUB type of `fn(&g, +&h)` and a graph that looks like: + +``` + $a $b *--$x + \ \ / / + \ $h-* / + $g-----------* +``` + +Here `$g` and `$h` are fresh variables that are created to represent +the LUB/GLB of things requiring inference. This means that `V` and +`Tainted` will look like: + +``` +V = {$a, $b, $g, $h, $x} +Tainted($g) = Tainted($h) = { $a, $b, $h, $g, $x } +``` + +Therefore we replace both `$g` and `$h` with `$a`, and end up +with the type `fn(&a, &a)`. + +### GLB + +The procedure for computing the GLB is similar. The difference lies +in computing the replacements for the various variables. For each +region `R` that appears in the type `F`, we again compute `Tainted(R)` +and examine the results: + +1. If `R` is not in `V`, it is not replaced. +2. Else, if `Tainted(R)` contains only variables in `V`, and it + contains exactly one variable from the LHS and one variable from + the RHS, then `R` can be mapped to the bound version of the + variable from the LHS. +3. Else, if `Tainted(R)` contains no variable from the LHS and no + variable from the RHS, then `R` can be mapped to itself. +4. Else, `R` is mapped to a fresh bound variable. + +These rules are pretty complex. Let's look at some examples to see +how they play out. + +Out first example was `fn(&a)` and `fn(&X)`. In this case, `&a` will +be replaced with `$a` and we will ultimately compute a +(pre-replacement) GLB type of `fn($g)` where `$g=LUB($a,&X)`. +Therefore, `V={$a,$g}` and `Tainted($g)={$g,$a,&X}. To find the +replacement for `$g` we consult the rules above: +- Rule (1) does not apply because `$g \in V` +- Rule (2) does not apply because `&X \in Tainted($g)` +- Rule (3) does not apply because `$a \in Tainted($g)` +- Hence, by rule (4), we replace `$g` with a fresh bound variable `&z`. +So our final result is `fn(&z)`, which is correct. + +The next example is `fn(&A)` and `fn(&Z)`. In this case, we will again +have a (pre-replacement) GLB of `fn(&g)`, where `$g = LUB(&A,&Z)`. +Therefore, `V={$g}` and `Tainted($g) = {$g, &A, &Z}`. In this case, +by rule (3), `$g` is mapped to itself, and hence the result is +`fn($g)`. This result is correct (in this case, at least), but it is +indicative of a case that *can* lead us into concluding that there is +no GLB when in fact a GLB does exist. See the section "Questionable +Results" below for more details. + +The next example is `fn(&a, &b)` and `fn(&c, &c)`. In this case, as +before, we'll end up with `F=fn($g, $h)` where `Tainted($g) = +Tainted($h) = {$g, $h, $a, $b, $c}`. Only rule (4) applies and hence +we'll select fresh bound variables `y` and `z` and wind up with +`fn(&y, &z)`. + +For the last example, let's consider what may seem trivial, but is +not: `fn(&a, &a)` and `fn(&b, &b)`. In this case, we'll get `F=fn($g, +$h)` where `Tainted($g) = {$g, $a, $x}` and `Tainted($h) = {$h, $a, +$x}`. Both of these sets contain exactly one bound variable from each +side, so we'll map them both to `&a`, resulting in `fn(&a, &a)`, which +is the desired result. + +### Shortcomings and correctness + +You may be wondering whether this algorithm is correct. The answer is +"sort of". There are definitely cases where they fail to compute a +result even though a correct result exists. I believe, though, that +if they succeed, then the result is valid, and I will attempt to +convince you. The basic argument is that the "pre-replacement" step +computes a set of constraints. The replacements, then, attempt to +satisfy those constraints, using bound identifiers where needed. + +For now I will briefly go over the cases for LUB/GLB and identify +their intent: + +- LUB: + - The region variables that are substituted in place of bound regions + are intended to collect constraints on those bound regions. + - If Tainted(R) contains only values in V, then this region is unconstrained + and can therefore be generalized, otherwise it cannot. +- GLB: + - The region variables that are substituted in place of bound regions + are intended to collect constraints on those bound regions. + - If Tainted(R) contains exactly one variable from each side, and + only variables in V, that indicates that those two bound regions + must be equated. + - Otherwise, if Tainted(R) references any variables from left or right + side, then it is trying to combine a bound region with a free one or + multiple bound regions, so we need to select fresh bound regions. + +Sorry this is more of a shorthand to myself. I will try to write up something +more convincing in the future. + +#### Where are the algorithms wrong? + +- The pre-replacement computation can fail even though using a + bound-region would have succeeded. +- We will compute GLB(fn(fn($a)), fn(fn($b))) as fn($c) where $c is the + GLB of $a and $b. But if inference finds that $a and $b must be mapped + to regions without a GLB, then this is effectively a failure to compute + the GLB. However, the result `fn<$c>(fn($c))` is a valid GLB. + +*/ diff --git a/src/librustc/middle/typeck/infer/region_inference.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 9d6176af0ba..96cb5d3c747 100644 --- a/src/librustc/middle/typeck/infer/region_inference.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -8,581 +8,36 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! - -Region inference module. - -# Introduction - -Region inference uses a somewhat more involved algorithm than type -inference. It is not the most efficient thing ever written though it -seems to work well enough in practice (famous last words). The reason -that we use a different algorithm is because, unlike with types, it is -impractical to hand-annotate with regions (in some cases, there aren't -even the requisite syntactic forms). So we have to get it right, and -it's worth spending more time on a more involved analysis. Moreover, -regions are a simpler case than types: they don't have aggregate -structure, for example. - -Unlike normal type inference, which is similar in spirit to H-M and thus -works progressively, the region type inference works by accumulating -constraints over the course of a function. Finally, at the end of -processing a function, we process and solve the constraints all at -once. - -The constraints are always of one of three possible forms: - -- ConstrainVarSubVar(R_i, R_j) states that region variable R_i - must be a subregion of R_j -- ConstrainRegSubVar(R, R_i) states that the concrete region R - (which must not be a variable) must be a subregion of the varibale R_i -- ConstrainVarSubReg(R_i, R) is the inverse - -# Building up the constraints - -Variables and constraints are created using the following methods: - -- `new_region_var()` creates a new, unconstrained region variable; -- `make_subregion(R_i, R_j)` states that R_i is a subregion of R_j -- `lub_regions(R_i, R_j) -> R_k` returns a region R_k which is - the smallest region that is greater than both R_i and R_j -- `glb_regions(R_i, R_j) -> R_k` returns a region R_k which is - the greatest region that is smaller than both R_i and R_j - -The actual region resolution algorithm is not entirely -obvious, though it is also not overly complex. I'll explain -the algorithm as it currently works, then explain a somewhat -more complex variant that would probably scale better for -large graphs (and possibly all graphs). - -## Snapshotting - -It is also permitted to try (and rollback) changes to the graph. This -is done by invoking `start_snapshot()`, which returns a value. Then -later you can call `rollback_to()` which undoes the work. -Alternatively, you can call `commit()` which ends all snapshots. -Snapshots can be recursive---so you can start a snapshot when another -is in progress, but only the root snapshot can "commit". - -# Resolving constraints - -The constraint resolution algorithm is not super complex but also not -entirely obvious. Here I describe the problem somewhat abstractly, -then describe how the current code works, and finally describe a -better solution that is as of yet unimplemented. There may be other, -smarter ways of doing this with which I am unfamiliar and can't be -bothered to research at the moment. - NDM - -## The problem - -Basically our input is a directed graph where nodes can be divided -into two categories: region variables and concrete regions. Each edge -`R -> S` in the graph represents a constraint that the region `R` is a -subregion of the region `S`. - -Region variable nodes can have arbitrary degree. There is one region -variable node per region variable. - -Each concrete region node is associated with some, well, concrete -region: e.g., a free lifetime, or the region for a particular scope. -Note that there may be more than one concrete region node for a -particular region value. Moreover, because of how the graph is built, -we know that all concrete region nodes have either in-degree 1 or -out-degree 1. - -Before resolution begins, we build up the constraints in a hashmap -that maps `Constraint` keys to spans. During resolution, we construct -the actual `Graph` structure that we describe here. - -## Our current algorithm - -We divide region variables into two groups: Expanding and Contracting. -Expanding region variables are those that have a concrete region -predecessor (direct or indirect). Contracting region variables are -all others. - -We first resolve the values of Expanding region variables and then -process Contracting ones. We currently use an iterative, fixed-point -procedure (but read on, I believe this could be replaced with a linear -walk). Basically we iterate over the edges in the graph, ensuring -that, if the source of the edge has a value, then this value is a -subregion of the target value. If the target does not yet have a -value, it takes the value from the source. If the target already had -a value, then the resulting value is Least Upper Bound of the old and -new values. When we are done, each Expanding node will have the -smallest region that it could possibly have and still satisfy the -constraints. - -We next process the Contracting nodes. Here we again iterate over the -edges, only this time we move values from target to source (if the -source is a Contracting node). For each contracting node, we compute -its value as the GLB of all its successors. Basically contracting -nodes ensure that there is overlap between their successors; we will -ultimately infer the largest overlap possible. - -### A better algorithm - -Fixed-point iteration is not necessary. What we ought to do is first -identify and remove strongly connected components (SCC) in the graph. -Note that such components must consist solely of region variables; all -of these variables can effectively be unified into a single variable. - -Once SCCs are removed, we are left with a DAG. At this point, we can -walk the DAG in toplogical order once to compute the expanding nodes, -and again in reverse topological order to compute the contracting -nodes. The main reason I did not write it this way is that I did not -feel like implementing the SCC and toplogical sort algorithms at the -moment. - -# Skolemization and functions - -One of the trickiest and most subtle aspects of regions is dealing -with the fact that region variables are bound in function types. I -strongly suggest that if you want to understand the situation, you -read this paper (which is, admittedly, very long, but you don't have -to read the whole thing): +/*! See doc.rs */ -http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/ - -Although my explanation will never compete with SPJ's (for one thing, -his is approximately 100 pages), I will attempt to explain the basic -problem and also how we solve it. Note that the paper only discusses -subtyping, not the computation of LUB/GLB. - -The problem we are addressing is that there is a kind of subtyping -between functions with bound region parameters. Consider, for -example, whether the following relation holds: - - fn(&'a int) <: &fn(&'b int)? (Yes, a => b) - -The answer is that of course it does. These two types are basically -the same, except that in one we used the name `a` and one we used -the name `b`. - -In the examples that follow, it becomes very important to know whether -a lifetime is bound in a function type (that is, is a lifetime -parameter) or appears free (is defined in some outer scope). -Therefore, from now on I will write the bindings explicitly, using a -notation like `fn<a>(&'a int)` to indicate that `a` is a lifetime -parameter. - -Now let's consider two more function types. Here, we assume that the -`self` lifetime is defined somewhere outside and hence is not a -lifetime parameter bound by the function type (it "appears free"): - - fn<a>(&'a int) <: &fn(&'self int)? (Yes, a => self) - -This subtyping relation does in fact hold. To see why, you have to -consider what subtyping means. One way to look at `T1 <: T2` is to -say that it means that it is always ok to treat an instance of `T1` as -if it had the type `T2`. So, with our functions, it is always ok to -treat a function that can take pointers with any lifetime as if it -were a function that can only take a pointer with the specific -lifetime `&self`. After all, `&self` is a lifetime, after all, and -the function can take values of any lifetime. - -You can also look at subtyping as the *is a* relationship. This amounts -to the same thing: a function that accepts pointers with any lifetime -*is a* function that accepts pointers with some specific lifetime. - -So, what if we reverse the order of the two function types, like this: - - fn(&'self int) <: &fn<a>(&'a int)? (No) - -Does the subtyping relationship still hold? The answer of course is -no. In this case, the function accepts *only the lifetime `&self`*, -so it is not reasonable to treat it as if it were a function that -accepted any lifetime. - -What about these two examples: - - fn<a,b>(&'a int, &'b int) <: &fn<a>(&'a int, &'a int)? (Yes) - fn<a>(&'a int, &'a int) <: &fn<a,b>(&'a int, &'b int)? (No) - -Here, it is true that functions which take two pointers with any two -lifetimes can be treated as if they only accepted two pointers with -the same lifetime, but not the reverse. - -## The algorithm - -Here is the algorithm we use to perform the subtyping check: - -1. Replace all bound regions in the subtype with new variables -2. Replace all bound regions in the supertype with skolemized - equivalents. A "skolemized" region is just a new fresh region - name. -3. Check that the parameter and return types match as normal -4. Ensure that no skolemized regions 'leak' into region variables - visible from "the outside" - -Let's walk through some examples and see how this algorithm plays out. - -#### First example - -We'll start with the first example, which was: - - 1. fn<a>(&'a T) <: &fn<b>(&'b T)? Yes: a -> b - -After steps 1 and 2 of the algorithm we will have replaced the types -like so: - - 1. fn(&'A T) <: &fn(&'x T)? - -Here the upper case `&A` indicates a *region variable*, that is, a -region whose value is being inferred by the system. I also replaced -`&b` with `&x`---I'll use letters late in the alphabet (`x`, `y`, `z`) -to indicate skolemized region names. We can assume they don't appear -elsewhere. Note that neither the sub- nor the supertype bind any -region names anymore (as indicated by the absence of `<` and `>`). - -The next step is to check that the parameter types match. Because -parameters are contravariant, this means that we check whether: - - &'x T <: &'A T - -Region pointers are contravariant so this implies that - - &A <= &x - -must hold, where `<=` is the subregion relationship. Processing -*this* constrain simply adds a constraint into our graph that `&A <= -&x` and is considered successful (it can, for example, be satisfied by -choosing the value `&x` for `&A`). - -So far we have encountered no error, so the subtype check succeeds. - -#### The third example - -Now let's look first at the third example, which was: - - 3. fn(&'self T) <: &fn<b>(&'b T)? No! - -After steps 1 and 2 of the algorithm we will have replaced the types -like so: - - 3. fn(&'self T) <: &fn(&'x T)? - -This looks pretty much the same as before, except that on the LHS -`&self` was not bound, and hence was left as-is and not replaced with -a variable. The next step is again to check that the parameter types -match. This will ultimately require (as before) that `&self` <= `&x` -must hold: but this does not hold. `self` and `x` are both distinct -free regions. So the subtype check fails. - -#### Checking for skolemization leaks - -You may be wondering about that mysterious last step in the algorithm. -So far it has not been relevant. The purpose of that last step is to -catch something like *this*: - - fn<a>() -> fn(&'a T) <: &fn() -> fn<b>(&'b T)? No. - -Here the function types are the same but for where the binding occurs. -The subtype returns a function that expects a value in precisely one -region. The supertype returns a function that expects a value in any -region. If we allow an instance of the subtype to be used where the -supertype is expected, then, someone could call the fn and think that -the return value has type `fn<b>(&'b T)` when it really has type -`fn(&'a T)` (this is case #3, above). Bad. - -So let's step through what happens when we perform this subtype check. -We first replace the bound regions in the subtype (the supertype has -no bound regions). This gives us: - - fn() -> fn(&'A T) <: &fn() -> fn<b>(&'b T)? - -Now we compare the return types, which are covariant, and hence we have: - - fn(&'A T) <: &fn<b>(&'b T)? - -Here we skolemize the bound region in the supertype to yield: - - fn(&'A T) <: &fn(&'x T)? - -And then proceed to compare the argument types: - - &'x T <: &'A T - &A <= &x - -Finally, this is where it gets interesting! This is where an error -*should* be reported. But in fact this will not happen. The reason why -is that `A` is a variable: we will infer that its value is the fresh -region `x` and think that everything is happy. In fact, this behavior -is *necessary*, it was key to the first example we walked through. - -The difference between this example and the first one is that the variable -`A` already existed at the point where the skolemization occurred. In -the first example, you had two functions: - - fn<a>(&'a T) <: &fn<b>(&'b T) - -and hence `&A` and `&x` were created "together". In general, the -intention of the skolemized names is that they are supposed to be -fresh names that could never be equal to anything from the outside. -But when inference comes into play, we might not be respecting this -rule. - -So the way we solve this is to add a fourth step that examines the -constraints that refer to skolemized names. Basically, consider a -non-directed verison of the constraint graph. Let `Tainted(x)` be the -set of all things reachable from a skolemized variable `x`. -`Tainted(x)` should not contain any regions that existed before the -step at which the skolemization was performed. So this case here -would fail because `&x` was created alone, but is relatable to `&A`. - -## Computing the LUB and GLB - -The paper I pointed you at is written for Haskell. It does not -therefore considering subtyping and in particular does not consider -LUB or GLB computation. We have to consider this. Here is the -algorithm I implemented. - -First though, let's discuss what we are trying to compute in more -detail. The LUB is basically the "common supertype" and the GLB is -"common subtype"; one catch is that the LUB should be the -*most-specific* common supertype and the GLB should be *most general* -common subtype (as opposed to any common supertype or any common -subtype). - -Anyway, to help clarify, here is a table containing some -function pairs and their LUB/GLB: - -``` -Type 1 Type 2 LUB GLB -fn<a>(&a) fn(&X) fn(&X) fn<a>(&a) -fn(&A) fn(&X) -- fn<a>(&a) -fn<a,b>(&a, &b) fn<x>(&x, &x) fn<a>(&a, &a) fn<a,b>(&a, &b) -fn<a,b>(&a, &b, &a) fn<x,y>(&x, &y, &y) fn<a>(&a, &a, &a) fn<a,b,c>(&a,&b,&c) -``` - -### Conventions - -I use lower-case letters (e.g., `&a`) for bound regions and upper-case -letters for free regions (`&A`). Region variables written with a -dollar-sign (e.g., `$a`). I will try to remember to enumerate the -bound-regions on the fn type as well (e.g., `fn<a>(&a)`). - -### High-level summary - -Both the LUB and the GLB algorithms work in a similar fashion. They -begin by replacing all bound regions (on both sides) with fresh region -inference variables. Therefore, both functions are converted to types -that contain only free regions. We can then compute the LUB/GLB in a -straightforward way, as described in `combine.rs`. This results in an -interim type T. The algorithms then examine the regions that appear -in T and try to, in some cases, replace them with bound regions to -yield the final result. - -To decide whether to replace a region `R` that appears in `T` with a -bound region, the algorithms make use of two bits of information. -First is a set `V` that contains all region variables created as part -of the LUB/GLB computation. `V` will contain the region variables -created to replace the bound regions in the input types, but it also -contains 'intermediate' variables created to represent the LUB/GLB of -individual regions. Basically, when asked to compute the LUB/GLB of a -region variable with another region, the inferencer cannot oblige -immediately since the valuese of that variables are not known. -Therefore, it creates a new variable that is related to the two -regions. For example, the LUB of two variables `$x` and `$y` is a -fresh variable `$z` that is constrained such that `$x <= $z` and `$y -<= $z`. So `V` will contain these intermediate variables as well. - -The other important factor in deciding how to replace a region in T is -the function `Tainted($r)` which, for a region variable, identifies -all regions that the region variable is related to in some way -(`Tainted()` made an appearance in the subtype computation as well). - -### LUB - -The LUB algorithm proceeds in three steps: - -1. Replace all bound regions (on both sides) with fresh region - inference variables. -2. Compute the LUB "as normal", meaning compute the GLB of each - pair of argument types and the LUB of the return types and - so forth. Combine those to a new function type `F`. -3. Replace each region `R` that appears in `F` as follows: - - Let `V` be the set of variables created during the LUB - computational steps 1 and 2, as described in the previous section. - - If `R` is not in `V`, replace `R` with itself. - - If `Tainted(R)` contains a region that is not in `V`, - replace `R` with itself. - - Otherwise, select the earliest variable in `Tainted(R)` that originates - from the left-hand side and replace `R` with the bound region that - this variable was a replacement for. - -So, let's work through the simplest example: `fn(&A)` and `fn<a>(&a)`. -In this case, `&a` will be replaced with `$a` and the interim LUB type -`fn($b)` will be computed, where `$b=GLB(&A,$a)`. Therefore, `V = -{$a, $b}` and `Tainted($b) = { $b, $a, &A }`. When we go to replace -`$b`, we find that since `&A \in Tainted($b)` is not a member of `V`, -we leave `$b` as is. When region inference happens, `$b` will be -resolved to `&A`, as we wanted. - -Let's look at a more complex one: `fn(&a, &b)` and `fn(&x, &x)`. In -this case, we'll end up with a (pre-replacement) LUB type of `fn(&g, -&h)` and a graph that looks like: - -``` - $a $b *--$x - \ \ / / - \ $h-* / - $g-----------* -``` - -Here `$g` and `$h` are fresh variables that are created to represent -the LUB/GLB of things requiring inference. This means that `V` and -`Tainted` will look like: - -``` -V = {$a, $b, $g, $h, $x} -Tainted($g) = Tainted($h) = { $a, $b, $h, $g, $x } -``` - -Therefore we replace both `$g` and `$h` with `$a`, and end up -with the type `fn(&a, &a)`. - -### GLB - -The procedure for computing the GLB is similar. The difference lies -in computing the replacements for the various variables. For each -region `R` that appears in the type `F`, we again compute `Tainted(R)` -and examine the results: - -1. If `R` is not in `V`, it is not replaced. -2. Else, if `Tainted(R)` contains only variables in `V`, and it - contains exactly one variable from the LHS and one variable from - the RHS, then `R` can be mapped to the bound version of the - variable from the LHS. -3. Else, if `Tainted(R)` contains no variable from the LHS and no - variable from the RHS, then `R` can be mapped to itself. -4. Else, `R` is mapped to a fresh bound variable. - -These rules are pretty complex. Let's look at some examples to see -how they play out. - -Out first example was `fn(&a)` and `fn(&X)`. In this case, `&a` will -be replaced with `$a` and we will ultimately compute a -(pre-replacement) GLB type of `fn($g)` where `$g=LUB($a,&X)`. -Therefore, `V={$a,$g}` and `Tainted($g)={$g,$a,&X}. To find the -replacement for `$g` we consult the rules above: -- Rule (1) does not apply because `$g \in V` -- Rule (2) does not apply because `&X \in Tainted($g)` -- Rule (3) does not apply because `$a \in Tainted($g)` -- Hence, by rule (4), we replace `$g` with a fresh bound variable `&z`. -So our final result is `fn(&z)`, which is correct. - -The next example is `fn(&A)` and `fn(&Z)`. In this case, we will again -have a (pre-replacement) GLB of `fn(&g)`, where `$g = LUB(&A,&Z)`. -Therefore, `V={$g}` and `Tainted($g) = {$g, &A, &Z}`. In this case, -by rule (3), `$g` is mapped to itself, and hence the result is -`fn($g)`. This result is correct (in this case, at least), but it is -indicative of a case that *can* lead us into concluding that there is -no GLB when in fact a GLB does exist. See the section "Questionable -Results" below for more details. - -The next example is `fn(&a, &b)` and `fn(&c, &c)`. In this case, as -before, we'll end up with `F=fn($g, $h)` where `Tainted($g) = -Tainted($h) = {$g, $h, $a, $b, $c}`. Only rule (4) applies and hence -we'll select fresh bound variables `y` and `z` and wind up with -`fn(&y, &z)`. - -For the last example, let's consider what may seem trivial, but is -not: `fn(&a, &a)` and `fn(&b, &b)`. In this case, we'll get `F=fn($g, -$h)` where `Tainted($g) = {$g, $a, $x}` and `Tainted($h) = {$h, $a, -$x}`. Both of these sets contain exactly one bound variable from each -side, so we'll map them both to `&a`, resulting in `fn(&a, &a)`, which -is the desired result. - -### Shortcomings and correctness - -You may be wondering whether this algorithm is correct. The answer is -"sort of". There are definitely cases where they fail to compute a -result even though a correct result exists. I believe, though, that -if they succeed, then the result is valid, and I will attempt to -convince you. The basic argument is that the "pre-replacement" step -computes a set of constraints. The replacements, then, attempt to -satisfy those constraints, using bound identifiers where needed. - -For now I will briefly go over the cases for LUB/GLB and identify -their intent: - -- LUB: - - The region variables that are substituted in place of bound regions - are intended to collect constraints on those bound regions. - - If Tainted(R) contains only values in V, then this region is unconstrained - and can therefore be generalized, otherwise it cannot. -- GLB: - - The region variables that are substituted in place of bound regions - are intended to collect constraints on those bound regions. - - If Tainted(R) contains exactly one variable from each side, and - only variables in V, that indicates that those two bound regions - must be equated. - - Otherwise, if Tainted(R) references any variables from left or right - side, then it is trying to combine a bound region with a free one or - multiple bound regions, so we need to select fresh bound regions. - -Sorry this is more of a shorthand to myself. I will try to write up something -more convincing in the future. - -#### Where are the algorithms wrong? - -- The pre-replacement computation can fail even though using a - bound-region would have succeeded. -- We will compute GLB(fn(fn($a)), fn(fn($b))) as fn($c) where $c is the - GLB of $a and $b. But if inference finds that $a and $b must be mapped - to regions without a GLB, then this is effectively a failure to compute - the GLB. However, the result `fn<$c>(fn($c))` is a valid GLB. - -*/ - -use core::prelude::*; use middle::ty; use middle::ty::{FreeRegion, Region, RegionVid}; use middle::ty::{re_empty, re_static, re_infer, re_free, re_bound}; use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh}; use middle::typeck::infer::cres; +use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin}; +use middle::typeck::infer; use util::common::indenter; -use util::ppaux::note_and_explain_region; +use util::ppaux::{note_and_explain_region, Repr, UserString}; -use core::cell::Cell; -use core::hashmap::{HashMap, HashSet}; -use core::to_bytes; -use core::uint; -use core::vec; +use std::cell::Cell; +use std::hashmap::{HashMap, HashSet}; +use std::uint; +use std::vec; use syntax::codemap::span; use syntax::ast; +use syntax::opt_vec; +use syntax::opt_vec::OptVec; -#[deriving(Eq)] +mod doc; + +#[deriving(Eq, IterBytes)] enum Constraint { ConstrainVarSubVar(RegionVid, RegionVid), ConstrainRegSubVar(Region, RegionVid), - ConstrainVarSubReg(RegionVid, Region) -} - -impl to_bytes::IterBytes for Constraint { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - ConstrainVarSubVar(ref v0, ref v1) => { - 0u8.iter_bytes(lsb0, f) && - v0.iter_bytes(lsb0, f) && - v1.iter_bytes(lsb0, f) - } - - ConstrainRegSubVar(ref ra, ref va) => { - 1u8.iter_bytes(lsb0, f) && - ra.iter_bytes(lsb0, f) && - va.iter_bytes(lsb0, f) - } - - ConstrainVarSubReg(ref va, ref ra) => { - 2u8.iter_bytes(lsb0, f) && - va.iter_bytes(lsb0, f) && - ra.iter_bytes(lsb0, f) - } - } - } + ConstrainVarSubReg(RegionVid, Region), + ConstrainRegSubReg(Region, Region), } #[deriving(Eq, IterBytes)] @@ -602,12 +57,37 @@ enum CombineMapType { Lub, Glb } +pub enum RegionResolutionError { + /// `ConcreteFailure(o, a, b)`: + /// + /// `o` requires that `a <= b`, but this does not hold + ConcreteFailure(SubregionOrigin, Region, Region), + + /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`: + /// + /// Could not infer a value for `v` because `sub_r <= v` (due to + /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and + /// `sub_r <= sup_r` does not hold. + SubSupConflict(RegionVariableOrigin, + SubregionOrigin, Region, + SubregionOrigin, Region), + + /// `SupSupConflict(v, origin1, r1, origin2, r2)`: + /// + /// Could not infer a value for `v` because `v <= r1` (due to + /// `origin1`) and `v <= r2` (due to `origin2`) and + /// `r1` and `r2` have no intersection. + SupSupConflict(RegionVariableOrigin, + SubregionOrigin, Region, + SubregionOrigin, Region), +} + type CombineMap = HashMap<TwoRegions, RegionVid>; pub struct RegionVarBindings { tcx: ty::ctxt, - var_spans: ~[span], - constraints: HashMap<Constraint, span>, + var_origins: ~[RegionVariableOrigin], + constraints: HashMap<Constraint, SubregionOrigin>, lubs: CombineMap, glbs: CombineMap, skolemization_count: uint, @@ -632,7 +112,7 @@ pub struct RegionVarBindings { pub fn RegionVarBindings(tcx: ty::ctxt) -> RegionVarBindings { RegionVarBindings { tcx: tcx, - var_spans: ~[], + var_origins: ~[], values: Cell::new_empty(), constraints: HashMap::new(), lubs: HashMap::new(), @@ -673,8 +153,8 @@ impl RegionVarBindings { match undo_item { Snapshot => {} AddVar(vid) => { - assert_eq!(self.var_spans.len(), vid.to_uint() + 1); - self.var_spans.pop(); + assert_eq!(self.var_origins.len(), vid.to_uint() + 1); + self.var_origins.pop(); } AddConstraint(ref constraint) => { self.constraints.remove(constraint); @@ -690,18 +170,18 @@ impl RegionVarBindings { } pub fn num_vars(&mut self) -> uint { - self.var_spans.len() + self.var_origins.len() } - pub fn new_region_var(&mut self, span: span) -> RegionVid { + pub fn new_region_var(&mut self, origin: RegionVariableOrigin) -> RegionVid { let id = self.num_vars(); - self.var_spans.push(span); + self.var_origins.push(origin); let vid = RegionVid { id: id }; if self.in_snapshot() { self.undo_log.push(AddVar(vid)); } - debug!("created new region variable %? with span %?", - vid, self.tcx.sess.codemap.span_to_str(span)); + debug!("created new region variable %? with origin %?", + vid, origin.repr(self.tcx)); return vid; } @@ -731,109 +211,106 @@ impl RegionVarBindings { re_bound(br_fresh(sc)) } - pub fn add_constraint(&mut self, constraint: Constraint, span: span) { + pub fn add_constraint(&mut self, + constraint: Constraint, + origin: SubregionOrigin) { // cannot add constraints once regions are resolved assert!(self.values.is_empty()); debug!("RegionVarBindings: add_constraint(%?)", constraint); - if self.constraints.insert(constraint, span) { + if self.constraints.insert(constraint, origin) { if self.in_snapshot() { self.undo_log.push(AddConstraint(constraint)); } } } - pub fn make_subregion(&mut self, span: span, sub: Region, sup: Region) - -> cres<()> { + pub fn make_subregion(&mut self, + origin: SubregionOrigin, + sub: Region, + sup: Region) { // cannot add constraints once regions are resolved assert!(self.values.is_empty()); debug!("RegionVarBindings: make_subregion(%?, %?)", sub, sup); match (sub, sup) { (re_infer(ReVar(sub_id)), re_infer(ReVar(sup_id))) => { - self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), span); - Ok(()) + self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); } (r, re_infer(ReVar(sup_id))) => { - self.add_constraint(ConstrainRegSubVar(r, sup_id), span); - Ok(()) + self.add_constraint(ConstrainRegSubVar(r, sup_id), origin); } (re_infer(ReVar(sub_id)), r) => { - self.add_constraint(ConstrainVarSubReg(sub_id, r), span); - Ok(()) + self.add_constraint(ConstrainVarSubReg(sub_id, r), origin); } (re_bound(br), _) => { self.tcx.sess.span_bug( - span, + origin.span(), fmt!("Cannot relate bound region as subregion: %?", br)); } (_, re_bound(br)) => { self.tcx.sess.span_bug( - span, + origin.span(), fmt!("Cannot relate bound region as superregion: %?", br)); } _ => { - if self.is_subregion_of(sub, sup) { - Ok(()) - } else { - Err(ty::terr_regions_does_not_outlive(sub, sup)) - } + self.add_constraint(ConstrainRegSubReg(sub, sup), origin); } } } - pub fn lub_regions(&mut self, span: span, a: Region, b: Region) - -> cres<Region> { + pub fn lub_regions(&mut self, + origin: SubregionOrigin, + a: Region, + b: Region) + -> Region { // cannot add constraints once regions are resolved assert!(self.values.is_empty()); debug!("RegionVarBindings: lub_regions(%?, %?)", a, b); match (a, b) { - (re_static, _) | (_, re_static) => { - Ok(re_static) // nothing lives longer than static - } - - (re_infer(ReVar(*)), _) | (_, re_infer(ReVar(*))) => { - self.combine_vars( - Lub, a, b, span, - |this, old_r, new_r| this.make_subregion(span, old_r, new_r)) - } + (re_static, _) | (_, re_static) => { + re_static // nothing lives longer than static + } - _ => { - Ok(self.lub_concrete_regions(a, b)) - } + _ => { + self.combine_vars( + Lub, a, b, origin, + |this, old_r, new_r| + this.make_subregion(origin, old_r, new_r)) + } } } - pub fn glb_regions(&mut self, span: span, a: Region, b: Region) - -> cres<Region> { + pub fn glb_regions(&mut self, + origin: SubregionOrigin, + a: Region, + b: Region) + -> Region { // cannot add constraints once regions are resolved assert!(self.values.is_empty()); debug!("RegionVarBindings: glb_regions(%?, %?)", a, b); match (a, b) { - (re_static, r) | (r, re_static) => { - // static lives longer than everything else - Ok(r) - } - - (re_infer(ReVar(*)), _) | (_, re_infer(ReVar(*))) => { - self.combine_vars( - Glb, a, b, span, - |this, old_r, new_r| this.make_subregion(span, new_r, old_r)) - } + (re_static, r) | (r, re_static) => { + // static lives longer than everything else + r + } - _ => { - self.glb_concrete_regions(a, b) - } + _ => { + self.combine_vars( + Glb, a, b, origin, + |this, old_r, new_r| + this.make_subregion(origin, new_r, old_r)) + } } } pub fn resolve_var(&mut self, rid: RegionVid) -> ty::Region { if self.values.is_empty() { self.tcx.sess.span_bug( - self.var_spans[rid.to_uint()], + self.var_origins[rid.to_uint()].span(), fmt!("Attempt to resolve region variable before values have \ been computed!")); } @@ -856,46 +333,41 @@ impl RegionVarBindings { } } + fn combine_map<'a>(&'a mut self, + t: CombineMapType) + -> &'a mut CombineMap + { + match t { + Glb => &mut self.glbs, + Lub => &mut self.lubs, + } + } + pub fn combine_vars(&mut self, t: CombineMapType, a: Region, b: Region, - span: span, + origin: SubregionOrigin, relate: &fn(this: &mut RegionVarBindings, old_r: Region, - new_r: Region) -> cres<()>) - -> cres<Region> { + new_r: Region)) + -> Region { let vars = TwoRegions { a: a, b: b }; - let c; - { - // FIXME (#3850): shouldn't need a scope, nor should this need to be - // done twice to get the maps out - { - let combines = match t { - Glb => &self.glbs, Lub => &self.lubs - }; - match combines.find(&vars) { - Some(&c) => return Ok(re_infer(ReVar(c))), - None => () - } - } - c = self.new_region_var(span); - { - let combines = match t { - Glb => &mut self.glbs, Lub => &mut self.lubs - }; - combines.insert(vars, c); + match self.combine_map(t).find(&vars) { + Some(&c) => { + return re_infer(ReVar(c)); } + None => {} } + let c = self.new_region_var(infer::MiscVariable(origin.span())); + self.combine_map(t).insert(vars, c); if self.in_snapshot() { self.undo_log.push(AddCombination(t, vars)); } - do relate(self, a, re_infer(ReVar(c))).then { - do relate(self, b, re_infer(ReVar(c))).then { - debug!("combine_vars() c=%?", c); - Ok(re_infer(ReVar(c))) - } - } + relate(self, a, re_infer(ReVar(c))); + relate(self, b, re_infer(ReVar(c))); + debug!("combine_vars() c=%?", c); + re_infer(ReVar(c)) } pub fn vars_created_since_snapshot(&mut self, snapshot: uint) @@ -950,6 +422,9 @@ impl RegionVarBindings { AddConstraint(ConstrainVarSubReg(ref a, ref b)) => { Some((re_infer(ReVar(*a)), *b)) } + AddConstraint(ConstrainRegSubReg(a, b)) => { + Some((a, b)) + } _ => { None } @@ -957,11 +432,11 @@ impl RegionVarBindings { match regs { None => {} - Some((ref r1, ref r2)) => { + Some((r1, r2)) => { result_set = - consider_adding_edge(result_set, &r, r1, r2); + consider_adding_edge(result_set, r, r1, r2); result_set = - consider_adding_edge(result_set, &r, r2, r1); + consider_adding_edge(result_set, r, r2, r1); } } @@ -974,14 +449,14 @@ impl RegionVarBindings { return result_set; fn consider_adding_edge(result_set: ~[Region], - r: &Region, - r1: &Region, - r2: &Region) -> ~[Region] + r: Region, + r1: Region, + r2: Region) -> ~[Region] { let mut result_set = result_set; - if *r == *r1 { // Clearly, this is potentially inefficient. - if !result_set.contains(r2) { - result_set.push(*r2); + if r == r1 { // Clearly, this is potentially inefficient. + if !result_set.iter().any_(|x| *x == r2) { + result_set.push(r2); } } return result_set; @@ -995,10 +470,12 @@ impl RegionVarBindings { constraints, assuming such values can be found; if they cannot, errors are reported. */ - pub fn resolve_regions(&mut self) { + pub fn resolve_regions(&mut self) -> OptVec<RegionResolutionError> { debug!("RegionVarBindings: resolve_regions()"); - let v = self.infer_variable_values(); + let mut errors = opt_vec::Empty; + let v = self.infer_variable_values(&mut errors); self.values.put_back(v); + errors } } @@ -1020,7 +497,7 @@ impl RegionVarBindings { (re_infer(ReVar(v_id)), _) | (_, re_infer(ReVar(v_id))) => { self.tcx.sess.span_bug( - self.var_spans[v_id.to_uint()], + self.var_origins[v_id.to_uint()].span(), fmt!("lub_concrete_regions invoked with \ non-concrete regions: %?, %?", a, b)); } @@ -1122,7 +599,7 @@ impl RegionVarBindings { (re_infer(ReVar(v_id)), _) | (_, re_infer(ReVar(v_id))) => { self.tcx.sess.span_bug( - self.var_spans[v_id.to_uint()], + self.var_origins[v_id.to_uint()].span(), fmt!("glb_concrete_regions invoked with \ non-concrete regions: %?, %?", a, b)); } @@ -1199,9 +676,11 @@ impl RegionVarBindings { } } - fn report_type_error(&mut self, span: span, terr: &ty::type_err) { + fn report_type_error(&mut self, + origin: SubregionOrigin, + terr: &ty::type_err) { let terr_str = ty::type_err_to_str(self.tcx, terr); - self.tcx.sess.span_err(span, terr_str); + self.tcx.sess.span_err(origin.span(), terr_str); } fn intersect_scopes(&self, @@ -1236,7 +715,7 @@ enum Classification { Expanding, Contracting } enum GraphNodeValue { NoValue, Value(Region), ErrorValue } struct GraphNode { - span: span, + origin: RegionVariableOrigin, classification: Classification, value: GraphNodeValue, head_edge: [uint, ..2], @@ -1245,7 +724,6 @@ struct GraphNode { struct GraphEdge { next_edge: [uint, ..2], constraint: Constraint, - span: span, } struct Graph { @@ -1253,20 +731,23 @@ struct Graph { edges: ~[GraphEdge], } -struct SpannedRegion { +struct RegionAndOrigin { region: Region, - span: span, + origin: SubregionOrigin, } impl RegionVarBindings { - pub fn infer_variable_values(&mut self) -> ~[GraphNodeValue] { + fn infer_variable_values(&mut self, + errors: &mut OptVec<RegionResolutionError>) + -> ~[GraphNodeValue] { let mut graph = self.construct_graph(); self.expansion(&mut graph); self.contraction(&mut graph); - self.extract_values_and_report_conflicts(&graph) + self.collect_concrete_region_errors(&graph, errors); + self.extract_values_and_collect_conflicts(&graph, errors) } - pub fn construct_graph(&mut self) -> Graph { + fn construct_graph(&mut self) -> Graph { let num_vars = self.num_vars(); let num_edges = self.constraints.len(); @@ -1277,7 +758,7 @@ impl RegionVarBindings { // those nodes that have a concrete region predecessor to // Expanding. classification: Contracting, - span: self.var_spans[var_idx], + origin: self.var_origins[var_idx], value: NoValue, head_edge: [uint::max_value, uint::max_value] } @@ -1285,11 +766,10 @@ impl RegionVarBindings { // It would be nice to write this using map(): let mut edges = vec::with_capacity(num_edges); - for self.constraints.each |constraint, span| { + for self.constraints.iter().advance |(constraint, _)| { edges.push(GraphEdge { next_edge: [uint::max_value, uint::max_value], constraint: *constraint, - span: *span }); } @@ -1310,6 +790,10 @@ impl RegionVarBindings { ConstrainVarSubReg(a_id, _) => { insert_edge(&mut graph, a_id, Outgoing, edge_idx); } + ConstrainRegSubReg(*) => { + // Relations between two concrete regions do not + // require an edge in the graph. + } } } @@ -1331,7 +815,7 @@ impl RegionVarBindings { } } - pub fn expansion(&mut self, graph: &mut Graph) { + fn expansion(&mut self, graph: &mut Graph) { do iterate_until_fixed_point(~"Expansion", graph) |nodes, edge| { match edge.constraint { ConstrainRegSubVar(a_region, b_vid) => { @@ -1351,15 +835,19 @@ impl RegionVarBindings { // This is a contraction constraint. Ignore it. false } + ConstrainRegSubReg(*) => { + // No region variables involved. Ignore. + false + } } } } - pub fn expand_node(&mut self, - a_region: Region, - b_vid: RegionVid, - b_node: &mut GraphNode) - -> bool { + fn expand_node(&mut self, + a_region: Region, + b_vid: RegionVid, + b_node: &mut GraphNode) + -> bool { debug!("expand_node(%?, %? == %?)", a_region, b_vid, b_node.value); @@ -1391,7 +879,8 @@ impl RegionVarBindings { } } - pub fn contraction(&mut self, graph: &mut Graph) { + fn contraction(&mut self, + graph: &mut Graph) { do iterate_until_fixed_point(~"Contraction", graph) |nodes, edge| { match edge.constraint { ConstrainRegSubVar(*) => { @@ -1411,15 +900,19 @@ impl RegionVarBindings { let a_node = &mut nodes[a_vid.to_uint()]; self.contract_node(a_vid, a_node, b_region) } + ConstrainRegSubReg(*) => { + // No region variables involved. Ignore. + false + } } } } - pub fn contract_node(&mut self, - a_vid: RegionVid, - a_node: &mut GraphNode, - b_region: Region) - -> bool { + fn contract_node(&mut self, + a_vid: RegionVid, + a_node: &mut GraphNode, + b_region: Region) + -> bool { debug!("contract_node(%? == %?/%?, %?)", a_vid, a_node.value, a_node.classification, b_region); @@ -1487,9 +980,44 @@ impl RegionVarBindings { } } - pub fn extract_values_and_report_conflicts(&mut self, graph: &Graph) - -> ~[GraphNodeValue] { - debug!("extract_values_and_report_conflicts()"); + fn collect_concrete_region_errors( + &mut self, + graph: &Graph, + errors: &mut OptVec<RegionResolutionError>) + { + let num_edges = graph.edges.len(); + for uint::range(0, num_edges) |edge_idx| { + let edge = &graph.edges[edge_idx]; + let origin = self.constraints.get_copy(&edge.constraint); + + let (sub, sup) = match edge.constraint { + ConstrainVarSubVar(*) | + ConstrainRegSubVar(*) | + ConstrainVarSubReg(*) => { + loop; + } + ConstrainRegSubReg(sub, sup) => { + (sub, sup) + } + }; + + if self.is_subregion_of(sub, sup) { + loop; + } + + debug!("ConcreteFailure: !(sub <= sup): sub=%?, sup=%?", + sub, sup); + errors.push(ConcreteFailure(origin, sub, sup)); + } + } + + fn extract_values_and_collect_conflicts( + &mut self, + graph: &Graph, + errors: &mut OptVec<RegionResolutionError>) + -> ~[GraphNodeValue] + { + debug!("extract_values_and_collect_conflicts()"); // This is the best way that I have found to suppress // duplicate and related errors. Basically we keep a set of @@ -1504,7 +1032,7 @@ impl RegionVarBindings { // overlapping locations. let mut dup_vec = graph.nodes.map(|_| uint::max_value); - graph.nodes.mapi(|idx, node| { + graph.nodes.iter().enumerate().transform(|(idx, node)| { match node.value { Value(_) => { /* Inference successful */ @@ -1542,25 +1070,28 @@ impl RegionVarBindings { let node_vid = RegionVid { id: idx }; match node.classification { Expanding => { - self.report_error_for_expanding_node( - graph, dup_vec, node_vid); + self.collect_error_for_expanding_node( + graph, dup_vec, node_vid, errors); } Contracting => { - self.report_error_for_contracting_node( - graph, dup_vec, node_vid); + self.collect_error_for_contracting_node( + graph, dup_vec, node_vid, errors); } } } } node.value - }) + }).collect() } - pub fn report_error_for_expanding_node(&mut self, - graph: &Graph, - dup_vec: &mut [uint], - node_idx: RegionVid) { + fn collect_error_for_expanding_node( + &mut self, + graph: &Graph, + dup_vec: &mut [uint], + node_idx: RegionVid, + errors: &mut OptVec<RegionResolutionError>) + { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. let (lower_bounds, lower_dup) = @@ -1572,54 +1103,37 @@ impl RegionVarBindings { return; } - for lower_bounds.each |lower_bound| { - for upper_bounds.each |upper_bound| { + for lower_bounds.iter().advance |lower_bound| { + for upper_bounds.iter().advance |upper_bound| { if !self.is_subregion_of(lower_bound.region, upper_bound.region) { - - self.tcx.sess.span_err( - self.var_spans[node_idx.to_uint()], - fmt!("cannot infer an appropriate lifetime \ - due to conflicting requirements")); - - note_and_explain_region( - self.tcx, - "first, the lifetime cannot outlive ", - upper_bound.region, - "..."); - - self.tcx.sess.span_note( - upper_bound.span, - fmt!("...due to the following expression")); - - note_and_explain_region( - self.tcx, - "but, the lifetime must be valid for ", + errors.push(SubSupConflict( + self.var_origins[node_idx.to_uint()], + lower_bound.origin, lower_bound.region, - "..."); - - self.tcx.sess.span_note( - lower_bound.span, - fmt!("...due to the following expression")); - + upper_bound.origin, + upper_bound.region)); return; } } } self.tcx.sess.span_bug( - self.var_spans[node_idx.to_uint()], - fmt!("report_error_for_expanding_node() could not find error \ + self.var_origins[node_idx.to_uint()].span(), + fmt!("collect_error_for_expanding_node() could not find error \ for var %?, lower_bounds=%s, upper_bounds=%s", node_idx, lower_bounds.map(|x| x.region).repr(self.tcx), upper_bounds.map(|x| x.region).repr(self.tcx))); } - pub fn report_error_for_contracting_node(&mut self, - graph: &Graph, - dup_vec: &mut [uint], - node_idx: RegionVid) { + fn collect_error_for_contracting_node( + &mut self, + graph: &Graph, + dup_vec: &mut [uint], + node_idx: RegionVid, + errors: &mut OptVec<RegionResolutionError>) + { // Errors in contracting nodes result from two upper-bounds // that have no intersection. let (upper_bounds, dup_found) = @@ -1629,38 +1143,18 @@ impl RegionVarBindings { return; } - for upper_bounds.each |upper_bound_1| { - for upper_bounds.each |upper_bound_2| { + for upper_bounds.iter().advance |upper_bound_1| { + for upper_bounds.iter().advance |upper_bound_2| { match self.glb_concrete_regions(upper_bound_1.region, upper_bound_2.region) { Ok(_) => {} Err(_) => { - - self.tcx.sess.span_err( - self.var_spans[node_idx.to_uint()], - fmt!("cannot infer an appropriate lifetime \ - due to conflicting requirements")); - - note_and_explain_region( - self.tcx, - "first, the lifetime must be contained by ", + errors.push(SupSupConflict( + self.var_origins[node_idx.to_uint()], + upper_bound_1.origin, upper_bound_1.region, - "..."); - - self.tcx.sess.span_note( - upper_bound_1.span, - fmt!("...due to the following expression")); - - note_and_explain_region( - self.tcx, - "but, the lifetime must also be contained by ", - upper_bound_2.region, - "..."); - - self.tcx.sess.span_note( - upper_bound_2.span, - fmt!("...due to the following expression")); - + upper_bound_2.origin, + upper_bound_2.region)); return; } } @@ -1668,23 +1162,23 @@ impl RegionVarBindings { } self.tcx.sess.span_bug( - self.var_spans[node_idx.to_uint()], - fmt!("report_error_for_contracting_node() could not find error \ + self.var_origins[node_idx.to_uint()].span(), + fmt!("collect_error_for_contracting_node() could not find error \ for var %?, upper_bounds=%s", node_idx, upper_bounds.map(|x| x.region).repr(self.tcx))); } - pub fn collect_concrete_regions(&mut self, - graph: &Graph, - orig_node_idx: RegionVid, - dir: Direction, - dup_vec: &mut [uint]) - -> (~[SpannedRegion], bool) { + fn collect_concrete_regions(&mut self, + graph: &Graph, + orig_node_idx: RegionVid, + dir: Direction, + dup_vec: &mut [uint]) + -> (~[RegionAndOrigin], bool) { struct WalkState { set: HashSet<RegionVid>, stack: ~[RegionVid], - result: ~[SpannedRegion], + result: ~[RegionAndOrigin], dup_found: bool } let mut state = WalkState { @@ -1746,17 +1240,19 @@ impl RegionVarBindings { ConstrainRegSubVar(region, _) | ConstrainVarSubReg(_, region) => { - state.result.push(SpannedRegion { + state.result.push(RegionAndOrigin { region: region, - span: edge.span + origin: this.constraints.get_copy(&edge.constraint) }); } + + ConstrainRegSubReg(*) => {} } } } } - pub fn each_edge(&mut self, + pub fn each_edge(&self, graph: &Graph, node_idx: RegionVid, dir: Direction, diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index ab52ef36978..941431ce0e3 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -46,7 +46,6 @@ // future). If you want to resolve everything but one type, you are // probably better off writing `resolve_all - resolve_ivar`. -use core::prelude::*; use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; use middle::ty::{type_is_bot, IntType, UintType}; @@ -54,11 +53,10 @@ use middle::ty; use middle::typeck::infer::{Bounds, cyclic_ty, fixup_err, fres, InferCtxt}; use middle::typeck::infer::{region_var_bound_by_region_var, unresolved_ty}; use middle::typeck::infer::to_str::InferStr; -use middle::typeck::infer::unify::Root; +use middle::typeck::infer::unify::{Root, UnifyInferCtxtMethods}; use util::common::{indent, indenter}; use util::ppaux::ty_to_str; -use core::vec; use syntax::ast; pub static resolve_nested_tvar: uint = 0b0000000001; @@ -205,7 +203,7 @@ impl ResolveState { } pub fn resolve_ty_var(&mut self, vid: TyVid) -> ty::t { - if vec::contains(self.v_seen, &vid) { + if self.v_seen.contains(&vid) { self.err = Some(cyclic_ty(vid)); return ty::mk_var(self.infcx.tcx, vid); } else { diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 2578f7c8553..72178500b54 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use middle::ty::{BuiltinBounds}; use middle::ty; @@ -18,8 +17,10 @@ use middle::typeck::infer::combine::*; use middle::typeck::infer::cres; use middle::typeck::infer::glb::Glb; use middle::typeck::infer::InferCtxt; +use middle::typeck::infer::lattice::CombineFieldsLatticeMethods; use middle::typeck::infer::lub::Lub; use middle::typeck::infer::to_str::InferStr; +use middle::typeck::infer::{TypeTrace, Subtype}; use util::common::{indent, indenter}; use util::ppaux::bound_region_to_str; @@ -36,7 +37,7 @@ impl Combine for Sub { fn infcx(&self) -> @mut InferCtxt { self.infcx } fn tag(&self) -> ~str { ~"sub" } fn a_is_expected(&self) -> bool { self.a_is_expected } - fn span(&self) -> span { self.span } + fn trace(&self) -> TypeTrace { self.trace } fn sub(&self) -> Sub { Sub(**self) } fn lub(&self) -> Lub { Lub(**self) } @@ -62,12 +63,8 @@ impl Combine for Sub { self.tag(), a.inf_str(self.infcx), b.inf_str(self.infcx)); - do indent { - match self.infcx.region_vars.make_subregion(self.span, a, b) { - Ok(()) => Ok(a), - Err(ref e) => Err((*e)) - } - } + self.infcx.region_vars.make_subregion(Subtype(self.trace), a, b); + Ok(a) } fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> { @@ -170,7 +167,7 @@ impl Combine for Sub { // region variable. let (a_sig, _) = self.infcx.replace_bound_regions_with_fresh_regions( - self.span, a); + self.trace, a); // Second, we instantiate each bound region in the supertype with a // fresh concrete region. @@ -179,7 +176,7 @@ impl Combine for Sub { None, b) |br| { let skol = self.infcx.region_vars.new_skolemized(br); debug!("Bound region %s skolemized to %?", - bound_region_to_str(self.infcx.tcx, br), + bound_region_to_str(self.infcx.tcx, "", false, br), skol); skol } @@ -198,12 +195,12 @@ impl Combine for Sub { for list::each(skol_isr) |pair| { let (skol_br, skol) = *pair; let tainted = self.infcx.region_vars.tainted(snapshot, skol); - for tainted.each |tainted_region| { + for tainted.iter().advance |tainted_region| { // Each skolemized should only be relatable to itself // or new variables: match *tainted_region { ty::re_infer(ty::ReVar(ref vid)) => { - if new_vars.contains(vid) { loop; } + if new_vars.iter().any_(|x| x == vid) { loop; } } _ => { if *tainted_region == skol { loop; } diff --git a/src/librustc/middle/typeck/infer/test.rs b/src/librustc/middle/typeck/infer/test.rs index 0db9d16adf3..a3d11bedbdc 100644 --- a/src/librustc/middle/typeck/infer/test.rs +++ b/src/librustc/middle/typeck/infer/test.rs @@ -79,7 +79,7 @@ fn setup_env(test_name: &str, source_string: &str) -> Env { impl Env { pub fn create_region_hierarchy(&self, rh: &RH) { - for rh.sub.each |child_rh| { + for rh.sub.iter().advance |child_rh| { self.create_region_hierarchy(child_rh); self.tcx.region_map.insert(child_rh.id, rh.id); } @@ -109,7 +109,7 @@ impl Env { idx: uint, names: &[~str]) -> Option<ast::node_id> { assert!(idx < names.len()); - for m.items.each |item| { + for m.items.iter().advance |item| { if self.tcx.sess.str_of(item.ident) == names[idx] { return search(self, *item, idx+1, names); } @@ -227,7 +227,7 @@ impl Env { self.infcx.resolve_regions(); if self.err_messages.len() != exp_count { - for self.err_messages.each |msg| { + for self.err_messages.iter().advance |msg| { debug!("Error encountered: %s", *msg); } fmt!("Resolving regions encountered %u errors but expected %u!", diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs index 364d8b2d052..18594f35295 100644 --- a/src/librustc/middle/typeck/infer/to_str.rs +++ b/src/librustc/middle/typeck/infer/to_str.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use middle::ty::{FnSig, Vid}; use middle::ty::IntVarValue; @@ -18,7 +17,7 @@ use middle::typeck::infer::InferCtxt; use middle::typeck::infer::unify::{Redirect, Root, VarValue}; use util::ppaux::{mt_to_str, ty_to_str, trait_ref_to_str}; -use core::uint; +use std::uint; use syntax::ast; pub trait InferStr { diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index 371d389f712..a7c3350d1d1 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use extra::smallintmap::SmallIntMap; @@ -40,9 +39,31 @@ pub trait UnifyVid<T> { -> &'v mut ValsAndBindings<Self, T>; } -impl InferCtxt { - pub fn get<T:Copy, V:Copy+Eq+Vid+UnifyVid<T>>(&mut self, vid: V) - -> Node<V, T> { +pub trait UnifyInferCtxtMethods { + fn get<T:Copy, + V:Copy + Eq + Vid + UnifyVid<T>>( + &mut self, + vid: V) + -> Node<V, T>; + fn set<T:Copy + InferStr, + V:Copy + Vid + ToStr + UnifyVid<T>>( + &mut self, + vid: V, + new_v: VarValue<V, T>); + fn unify<T:Copy + InferStr, + V:Copy + Vid + ToStr + UnifyVid<T>>( + &mut self, + node_a: &Node<V, T>, + node_b: &Node<V, T>) + -> (V, uint); +} + +impl UnifyInferCtxtMethods for InferCtxt { + fn get<T:Copy, + V:Copy + Eq + Vid + UnifyVid<T>>( + &mut self, + vid: V) + -> Node<V, T> { /*! * * Find the root node for `vid`. This uses the standard @@ -84,10 +105,11 @@ impl InferCtxt { } } - pub fn set<T:Copy + InferStr, - V:Copy + Vid + ToStr + UnifyVid<T>>(&mut self, - vid: V, - new_v: VarValue<V, T>) { + fn set<T:Copy + InferStr, + V:Copy + Vid + ToStr + UnifyVid<T>>( + &mut self, + vid: V, + new_v: VarValue<V, T>) { /*! * * Sets the value for `vid` to `new_v`. `vid` MUST be a root node! @@ -102,11 +124,12 @@ impl InferCtxt { vb.vals.insert(vid.to_uint(), new_v); } - pub fn unify<T:Copy + InferStr, - V:Copy + Vid + ToStr + UnifyVid<T>>(&mut self, - node_a: &Node<V, T>, - node_b: &Node<V, T>) - -> (V, uint) { + fn unify<T:Copy + InferStr, + V:Copy + Vid + ToStr + UnifyVid<T>>( + &mut self, + node_a: &Node<V, T>, + node_b: &Node<V, T>) + -> (V, uint) { // Rank optimization: if you don't know what it is, check // out <http://en.wikipedia.org/wiki/Disjoint-set_data_structure> @@ -155,14 +178,31 @@ pub fn mk_err<T:SimplyUnifiable>(a_is_expected: bool, } } -impl InferCtxt { - pub fn simple_vars<T:Copy+Eq+InferStr+SimplyUnifiable, - V:Copy+Eq+Vid+ToStr+UnifyVid<Option<T>>>(&mut self, - a_is_expected: - bool, - a_id: V, - b_id: V) - -> ures { +pub trait InferCtxtMethods { + fn simple_vars<T:Copy + Eq + InferStr + SimplyUnifiable, + V:Copy + Eq + Vid + ToStr + UnifyVid<Option<T>>>( + &mut self, + a_is_expected: bool, + a_id: V, + b_id: V) + -> ures; + fn simple_var_t<T:Copy + Eq + InferStr + SimplyUnifiable, + V:Copy + Eq + Vid + ToStr + UnifyVid<Option<T>>>( + &mut self, + a_is_expected: bool, + a_id: V, + b: T) + -> ures; +} + +impl InferCtxtMethods for InferCtxt { + fn simple_vars<T:Copy + Eq + InferStr + SimplyUnifiable, + V:Copy + Eq + Vid + ToStr + UnifyVid<Option<T>>>( + &mut self, + a_is_expected: bool, + a_id: V, + b_id: V) + -> ures { /*! * * Unifies two simple variables. Because simple variables do @@ -194,13 +234,13 @@ impl InferCtxt { return uok(); } - pub fn simple_var_t<T:Copy+Eq+InferStr+SimplyUnifiable, - V:Copy+Eq+Vid+ToStr+UnifyVid<Option<T>>>(&mut self, - a_is_expected - : bool, - a_id: V, - b: T) - -> ures { + fn simple_var_t<T:Copy + Eq + InferStr + SimplyUnifiable, + V:Copy + Eq + Vid + ToStr + UnifyVid<Option<T>>>( + &mut self, + a_is_expected: bool, + a_id: V, + b: T) + -> ures { /*! * * Sets the value of the variable `a_id` to `b`. Because diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index dc561f413c7..bbcfc73853a 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -48,7 +48,6 @@ independently: */ -use core::prelude::*; use driver::session; @@ -58,8 +57,8 @@ use util::common::time; use util::ppaux::Repr; use util::ppaux; -use core::hashmap::HashMap; -use core::result; +use std::hashmap::HashMap; +use std::result; use extra::list::List; use extra::list; use syntax::codemap::span; @@ -135,8 +134,9 @@ pub struct method_map_entry { // of the method to be invoked pub type method_map = @mut HashMap<ast::node_id, method_map_entry>; +pub type vtable_param_res = @~[vtable_origin]; // Resolutions for bounds of all parameters, left to right, for a given path. -pub type vtable_res = @~[vtable_origin]; +pub type vtable_res = @~[vtable_param_res]; pub enum vtable_origin { /* @@ -154,7 +154,12 @@ pub enum vtable_origin { The first uint is the param number (identifying T in the example), and the second is the bound number (identifying baz) */ - vtable_param(uint, uint) + vtable_param(uint, uint), + + /* + Dynamic vtable, comes from self. + */ + vtable_self(ast::def_id) } impl Repr for vtable_origin { @@ -171,6 +176,9 @@ impl Repr for vtable_origin { vtable_param(x, y) => { fmt!("vtable_param(%?, %?)", x, y) } + vtable_self(def_id) => { + fmt!("vtable_self(%?)", def_id) + } } } } @@ -182,7 +190,7 @@ pub struct CrateCtxt { trait_map: resolve::TraitMap, method_map: method_map, vtable_map: vtable_map, - coherence_info: @coherence::CoherenceInfo, + coherence_info: coherence::CoherenceInfo, tcx: ty::ctxt } @@ -198,7 +206,7 @@ pub fn write_substs_to_tcx(tcx: ty::ctxt, if substs.len() > 0u { debug!("write_substs_to_tcx(%d, %?)", node_id, substs.map(|t| ppaux::ty_to_str(tcx, *t))); - assert!(substs.all(|t| !ty::type_needs_infer(*t))); + assert!(substs.iter().all(|t| !ty::type_needs_infer(*t))); tcx.node_type_substs.insert(node_id, substs); } } @@ -220,7 +228,7 @@ pub fn lookup_def_tcx(tcx: ty::ctxt, sp: span, id: ast::node_id) -> ast::def { } } -pub fn lookup_def_ccx(ccx: @mut CrateCtxt, sp: span, id: ast::node_id) +pub fn lookup_def_ccx(ccx: &CrateCtxt, sp: span, id: ast::node_id) -> ast::def { lookup_def_tcx(ccx.tcx, sp, id) } @@ -255,7 +263,7 @@ pub fn require_same_types( } } - match infer::mk_eqty(l_infcx, t1_is_expected, span, t1, t2) { + match infer::mk_eqty(l_infcx, t1_is_expected, infer::Misc(span), t1, t2) { result::Ok(()) => true, result::Err(ref terr) => { l_tcx.sess.span_err(span, msg() + ": " + @@ -276,11 +284,11 @@ trait get_and_find_region { } impl get_and_find_region for isr_alist { - fn get(&self, br: ty::bound_region) -> ty::Region { + pub fn get(&self, br: ty::bound_region) -> ty::Region { self.find(br).get() } - fn find(&self, br: ty::bound_region) -> Option<ty::Region> { + pub fn find(&self, br: ty::bound_region) -> Option<ty::Region> { for list::each(*self) |isr| { let (isr_br, isr_r) = *isr; if isr_br == br { return Some(isr_r); } @@ -289,7 +297,7 @@ impl get_and_find_region for isr_alist { } } -fn check_main_fn_ty(ccx: @mut CrateCtxt, +fn check_main_fn_ty(ccx: &CrateCtxt, main_id: ast::node_id, main_span: span) { let tcx = ccx.tcx; @@ -330,7 +338,7 @@ fn check_main_fn_ty(ccx: @mut CrateCtxt, } } -fn check_start_fn_ty(ccx: @mut CrateCtxt, +fn check_start_fn_ty(ccx: &CrateCtxt, start_id: ast::node_id, start_span: span) { let tcx = ccx.tcx; @@ -379,7 +387,7 @@ fn check_start_fn_ty(ccx: @mut CrateCtxt, } } -fn check_for_entry_fn(ccx: @mut CrateCtxt) { +fn check_for_entry_fn(ccx: &CrateCtxt) { let tcx = ccx.tcx; if !*tcx.sess.building_library { match *tcx.sess.entry_fn { @@ -395,14 +403,14 @@ fn check_for_entry_fn(ccx: @mut CrateCtxt) { pub fn check_crate(tcx: ty::ctxt, trait_map: resolve::TraitMap, - crate: @ast::crate) + crate: &ast::crate) -> (method_map, vtable_map) { let time_passes = tcx.sess.time_passes(); let ccx = @mut CrateCtxt { trait_map: trait_map, method_map: @mut HashMap::new(), vtable_map: @mut HashMap::new(), - coherence_info: @coherence::CoherenceInfo(), + coherence_info: coherence::CoherenceInfo(), tcx: tcx }; diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index 709d631de11..91c875559fe 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use middle::ty; -use core::result; +use std::result; use syntax::ast; use syntax::codemap::span; use syntax::opt_vec::OptVec; @@ -57,7 +56,7 @@ impl RegionParamNames { } fn has_ident(&self, ident: ast::ident) -> bool { - for self.each |region_param_name| { + for self.iter().advance |region_param_name| { if *region_param_name == ident { return true; } @@ -75,7 +74,7 @@ impl RegionParamNames { opt_vec::Vec(new_lifetimes.map(|lt| lt.ident))); } opt_vec::Vec(ref mut existing_lifetimes) => { - for new_lifetimes.each |new_lifetime| { + for new_lifetimes.iter().advance |new_lifetime| { existing_lifetimes.push(new_lifetime.ident); } } diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rs index 021dd6648cb..a930570dd17 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rs @@ -9,7 +9,7 @@ // except according to those terms. #[link(name = "rustc", - vers = "0.7-pre", + vers = "0.7", uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf", url = "https://github.com/mozilla/rust/tree/master/src/rustc")]; @@ -21,17 +21,9 @@ #[allow(non_camel_case_types)]; #[deny(deprecated_pattern)]; -#[no_core]; -#[no_std]; - -extern mod core(name = "std"); -extern mod extra(name = "extra"); +extern mod extra; extern mod syntax; -extern mod std(name = "std", vers = "0.7-pre"); - -use core::prelude::*; - use driver::driver::{host_triple, optgroups, early_error}; use driver::driver::{str_input, file_input, build_session_options}; use driver::driver::{build_session, build_configuration, parse_pretty}; @@ -40,13 +32,13 @@ use driver::driver::{compile_input}; use driver::session; use middle::lint; -use core::io; -use core::os; -use core::result; -use core::str; -use core::task; -use core::uint; -use core::vec; +use std::io; +use std::os; +use std::result; +use std::str; +use std::task; +use std::uint; +use std::vec; use extra::getopts::{groups, opt_present}; use extra::getopts; use syntax::codemap; @@ -80,13 +72,13 @@ pub mod middle { pub mod moves; pub mod entry; pub mod effect; + pub mod reachable; } pub mod front { pub mod config; pub mod test; pub mod std_inject; - pub mod intrinsic_inject; } pub mod back { @@ -120,15 +112,17 @@ pub mod lib { // A curious inner module that allows ::std::foo to be available in here for // macros. +/* mod std { - pub use core::cmp; - pub use core::os; - pub use core::str; - pub use core::sys; - pub use core::to_bytes; - pub use core::unstable; + pub use std::cmp; + pub use std::os; + pub use std::str; + pub use std::sys; + pub use std::to_bytes; + pub use std::unstable; pub use extra::serialize; } +*/ pub fn version(argv0: &str) { let mut vers = ~"unknown version"; @@ -140,10 +134,10 @@ pub fn version(argv0: &str) { pub fn usage(argv0: &str) { let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0); - io::println(fmt!("%s \ - Additional help: \ - -W help Print 'lint' options and default settings \ - -Z help Print internal options for debugging rustc", + io::println(fmt!("%s\ +Additional help: + -W help Print 'lint' options and default settings + -Z help Print internal options for debugging rustc\n", groups::usage(message, optgroups()))); } @@ -167,7 +161,7 @@ Available lint options: padded(max_key, "name"), "default", "meaning")); io::println(fmt!(" %s %7.7s %s\n", padded(max_key, "----"), "-------", "-------")); - for lint_dict.each |k, v| { + for lint_dict.iter().advance |(k, v)| { let k = k.replace("_", "-"); io::println(fmt!(" %s %7.7s %s", padded(max_key, k), @@ -184,7 +178,8 @@ Available lint options: pub fn describe_debug_flags() { io::println(fmt!("\nAvailable debug options:\n")); - for session::debugging_opts_map().each |pair| { + let r = session::debugging_opts_map(); + for r.iter().advance |pair| { let (name, desc, _) = /*bad*/copy *pair; io::println(fmt!(" -Z %-20s -- %s", name, desc)); } @@ -192,7 +187,7 @@ pub fn describe_debug_flags() { pub fn run_compiler(args: &~[~str], demitter: diagnostic::Emitter) { // Don't display log spew by default. Can override with RUST_LOG. - ::core::logging::console_off(); + ::std::logging::console_off(); let mut args = /*bad*/copy *args; let binary = args.shift().to_managed(); @@ -216,7 +211,7 @@ pub fn run_compiler(args: &~[~str], demitter: diagnostic::Emitter) { let lint_flags = vec::append(getopts::opt_strs(matches, "W"), getopts::opt_strs(matches, "warn")); - let show_lint_options = lint_flags.contains(&~"help") || + let show_lint_options = lint_flags.iter().any_(|x| x == &~"help") || (opt_present(matches, "W") && lint_flags.is_empty()); if show_lint_options { @@ -224,7 +219,8 @@ pub fn run_compiler(args: &~[~str], demitter: diagnostic::Emitter) { return; } - if getopts::opt_strs(matches, "Z").contains(&~"help") { + let r = getopts::opt_strs(matches, "Z"); + if r.iter().any_(|x| x == &~"help") { describe_debug_flags(); return; } @@ -303,7 +299,7 @@ fails without recording a fatal error then we've encountered a compiler bug and need to present an error. */ pub fn monitor(f: ~fn(diagnostic::Emitter)) { - use core::comm::*; + use std::comm::*; let (p, ch) = stream(); let ch = SharedChan::new(ch); let ch_capture = ch.clone(); @@ -327,7 +323,7 @@ pub fn monitor(f: ~fn(diagnostic::Emitter)) { } impl Drop for finally { - fn finalize(&self) { self.ch.send(done); } + fn drop(&self) { self.ch.send(done); } } let _finally = finally { ch: ch }; @@ -343,13 +339,14 @@ pub fn monitor(f: ~fn(diagnostic::Emitter)) { diagnostic::ice_msg("unexpected failure"), diagnostic::error); - for [ + let xs = [ ~"the compiler hit an unexpected failure path. \ this is a bug", ~"try running with RUST_LOG=rustc=1,::rt::backtrace \ to get further details and report the results \ to github.com/mozilla/rust/issues" - ].each |note| { + ]; + for xs.iter().advance |note| { diagnostic::emit(None, *note, diagnostic::note) } } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 0839c2b963b..1e2e30548ee 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use syntax::ast; use syntax::codemap::{span}; use syntax::visit; -use core::hashmap::HashSet; -use core::io; +use std::hashmap::HashSet; +use std::io; use extra; pub fn time<T>(do_it: bool, what: ~str, thunk: &fn() -> T) -> T { @@ -41,7 +40,7 @@ pub struct _indenter { } impl Drop for _indenter { - fn finalize(&self) { debug!("<<"); } + fn drop(&self) { debug!("<<"); } } pub fn _indenter(_i: ()) -> _indenter { diff --git a/src/librustc/util/enum_set.rs b/src/librustc/util/enum_set.rs index 3528f20cfb3..2bdb6583b23 100644 --- a/src/librustc/util/enum_set.rs +++ b/src/librustc/util/enum_set.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; #[deriving(Eq, IterBytes)] pub struct EnumSet<E> { @@ -96,10 +95,9 @@ impl<E:CLike> BitAnd<EnumSet<E>, EnumSet<E>> for EnumSet<E> { #[cfg(test)] mod test { - use core::prelude::*; - use core::cast; - use core::iter; + use std::cast; + use std::iter; use util::enum_set::*; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 64af555bb37..62894071145 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use metadata::encoder; use middle::ty::{ReSkolemized, ReVar}; @@ -32,9 +31,6 @@ use syntax::parse::token; use syntax::print::pprust; use syntax::{ast, ast_util}; -use core::str; -use core::vec; - /// Produces a string suitable for debugging output. pub trait Repr { fn repr(&self, tcx: ctxt) -> ~str; @@ -112,7 +108,7 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) idx + 1), br_fresh(_) => fmt!("an anonymous lifetime defined on"), _ => fmt!("the lifetime %s as defined on", - bound_region_to_str(cx, fr.bound_region)) + bound_region_ptr_to_str(cx, fr.bound_region)) }; match cx.items.find(&fr.scope_id) { @@ -147,22 +143,23 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) } } -pub fn bound_region_to_str(cx: ctxt, br: bound_region) -> ~str { - bound_region_to_str_space(cx, "&", br) +pub fn bound_region_ptr_to_str(cx: ctxt, br: bound_region) -> ~str { + bound_region_to_str(cx, "&", true, br) } -pub fn bound_region_to_str_space(cx: ctxt, - prefix: &str, - br: bound_region) - -> ~str { - if cx.sess.verbose() { return fmt!("%s%? ", prefix, br); } +pub fn bound_region_to_str(cx: ctxt, + prefix: &str, space: bool, + br: bound_region) -> ~str { + let space_str = if space { " " } else { "" }; + + if cx.sess.verbose() { return fmt!("%s%?%s", prefix, br, space_str); } match br { - br_named(id) => fmt!("%s'%s ", prefix, cx.sess.str_of(id)), - br_self => fmt!("%s'self ", prefix), + br_named(id) => fmt!("%s'%s%s", prefix, cx.sess.str_of(id), space_str), + br_self => fmt!("%s'self%s", prefix, space_str), br_anon(_) => prefix.to_str(), br_fresh(_) => prefix.to_str(), - br_cap_avoid(_, br) => bound_region_to_str_space(cx, prefix, *br) + br_cap_avoid(_, br) => bound_region_to_str(cx, prefix, space, *br) } } @@ -208,13 +205,15 @@ pub fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str { // In general, if you are giving a region error message, // you should use `explain_region()` or, better yet, // `note_and_explain_region()` -pub fn region_to_str(cx: ctxt, region: Region) -> ~str { - region_to_str_space(cx, "&", region) +pub fn region_ptr_to_str(cx: ctxt, region: Region) -> ~str { + region_to_str(cx, "&", true, region) } -pub fn region_to_str_space(cx: ctxt, prefix: &str, region: Region) -> ~str { +pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~str { + let space_str = if space { " " } else { "" }; + if cx.sess.verbose() { - return fmt!("%s%? ", prefix, region); + return fmt!("%s%?%s", prefix, region, space_str); } // These printouts are concise. They do not contain all the information @@ -223,14 +222,14 @@ pub fn region_to_str_space(cx: ctxt, prefix: &str, region: Region) -> ~str { // `explain_region()` or `note_and_explain_region()`. match region { re_scope(_) => prefix.to_str(), - re_bound(br) => bound_region_to_str_space(cx, prefix, br), - re_free(ref fr) => bound_region_to_str_space(cx, prefix, fr.bound_region), + re_bound(br) => bound_region_to_str(cx, prefix, space, br), + re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region), re_infer(ReSkolemized(_, br)) => { - bound_region_to_str_space(cx, prefix, br) + bound_region_to_str(cx, prefix, space, br) } re_infer(ReVar(_)) => prefix.to_str(), - re_static => fmt!("%s'static ", prefix), - re_empty => fmt!("%s'<empty> ", prefix) + re_static => fmt!("%s'static%s", prefix, space_str), + re_empty => fmt!("%s'<empty>%s", prefix, space_str) } } @@ -256,7 +255,7 @@ pub fn vstore_to_str(cx: ctxt, vs: ty::vstore) -> ~str { ty::vstore_fixed(n) => fmt!("%u", n), ty::vstore_uniq => ~"~", ty::vstore_box => ~"@", - ty::vstore_slice(r) => region_to_str_space(cx, "&", r) + ty::vstore_slice(r) => region_ptr_to_str(cx, r) } } @@ -264,7 +263,7 @@ pub fn trait_store_to_str(cx: ctxt, s: ty::TraitStore) -> ~str { match s { ty::UniqTraitStore => ~"~", ty::BoxTraitStore => ~"@", - ty::RegionTraitStore(r) => region_to_str_space(cx, "&", r) + ty::RegionTraitStore(r) => region_ptr_to_str(cx, r) } } @@ -340,7 +339,7 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { (ast::OwnedSigil, ty::re_static) => {} (_, region) => { - s.push_str(region_to_str_space(cx, "", region)); + s.push_str(region_to_str(cx, "", true, region)); } } @@ -362,6 +361,11 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { s.push_str("fn"); + if !cty.bounds.is_empty() { + s.push_str(":"); + } + s.push_str(cty.bounds.repr(cx)); + push_sig_to_str(cx, &mut s, &cty.sig); return s; @@ -392,7 +396,7 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { } // if there is an id, print that instead of the structural type: - /*for ty::type_def_id(typ).each |def_id| { + /*for ty::type_def_id(typ).iter().advance |def_id| { // note that this typedef cannot have type parameters return ast_map::path_to_str(ty::item_path(cx, *def_id), cx.sess.intr()); @@ -414,7 +418,7 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { ty_uniq(ref tm) => ~"~" + mt_to_str(cx, tm), ty_ptr(ref tm) => ~"*" + mt_to_str(cx, tm), ty_rptr(r, ref tm) => { - region_to_str_space(cx, "&", r) + mt_to_str(cx, tm) + region_ptr_to_str(cx, r) + mt_to_str(cx, tm) } ty_unboxed_vec(ref tm) => { fmt!("unboxed_vec<%s>", mt_to_str(cx, tm)) } ty_type => ~"type", @@ -431,13 +435,15 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { ty_infer(infer_ty) => infer_ty.to_str(), ty_err => ~"[type error]", ty_param(param_ty {idx: id, def_id: did}) => { + let mut parm = (('T' as uint) + id) as char; + if (parm as uint) > ('Z' as uint) { + parm = (parm as uint - 26) as char; + } + if cx.sess.verbose() { - fmt!("'%s:%?", - str::from_bytes([('a' as u8) + (id as u8)]), - did) + fmt!("%c:%?", parm, did) } else { - fmt!("'%s", - str::from_bytes([('a' as u8) + (id as u8)])) + fmt!("%c", parm) } } ty_self(*) => ~"Self", @@ -446,20 +452,23 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { let base = ast_map::path_to_str(path, cx.sess.intr()); parameterized(cx, base, substs.self_r, substs.tps) } - ty_trait(did, ref substs, s, mutbl) => { + ty_trait(did, ref substs, s, mutbl, ref bounds) => { let path = ty::item_path(cx, did); let base = ast_map::path_to_str(path, cx.sess.intr()); let ty = parameterized(cx, base, substs.self_r, substs.tps); - fmt!("%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty) + let bound_sep = if bounds.is_empty() { "" } else { ":" }; + let bound_str = bounds.repr(cx); + fmt!("%s%s%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty, + bound_sep, bound_str) } ty_evec(ref mt, vs) => { vstore_ty_to_str(cx, mt, vs) } ty_estr(vs) => fmt!("%s%s", vstore_to_str(cx, vs), "str"), ty_opaque_box => ~"@?", - ty_opaque_closure_ptr(ast::BorrowedSigil) => ~"closure&", - ty_opaque_closure_ptr(ast::ManagedSigil) => ~"closure@", - ty_opaque_closure_ptr(ast::OwnedSigil) => ~"closure~", + ty_opaque_closure_ptr(ast::BorrowedSigil) => ~"&closure", + ty_opaque_closure_ptr(ast::ManagedSigil) => ~"@closure", + ty_opaque_closure_ptr(ast::OwnedSigil) => ~"~closure", } } @@ -468,18 +477,22 @@ pub fn parameterized(cx: ctxt, self_r: Option<ty::Region>, tps: &[ty::t]) -> ~str { - let r_str = match self_r { - None => ~"", - Some(r) => { - fmt!("/%s", region_to_str(cx, r)) - } + let mut strs = ~[]; + match self_r { + None => (), + Some(r) => { + strs.push(region_to_str(cx, "", false, r)) + } }; - if tps.len() > 0u { - let strs = vec::map(tps, |t| ty_to_str(cx, *t)); - fmt!("%s%s<%s>", base, r_str, strs.connect(",")) + for tps.iter().advance |t| { + strs.push(ty_to_str(cx, *t)) + } + + if strs.len() > 0u { + fmt!("%s<%s>", base, strs.connect(",")) } else { - fmt!("%s%s", base, r_str) + fmt!("%s", base) } } @@ -561,12 +574,12 @@ impl Repr for ty::ParamBounds { res.push(match b { ty::BoundCopy => ~"Copy", ty::BoundStatic => ~"'static", - ty::BoundOwned => ~"Owned", - ty::BoundConst => ~"Const", + ty::BoundSend => ~"Send", + ty::BoundFreeze => ~"Freeze", ty::BoundSized => ~"Sized", }); } - for self.trait_bounds.each |t| { + for self.trait_bounds.iter().advance |t| { res.push(t.repr(tcx)); } res.connect("+") @@ -595,9 +608,15 @@ impl Repr for @ast::pat { } } +impl Repr for ty::bound_region { + fn repr(&self, tcx: ctxt) -> ~str { + bound_region_ptr_to_str(tcx, *self) + } +} + impl Repr for ty::Region { fn repr(&self, tcx: ctxt) -> ~str { - region_to_str(tcx, *self) + region_to_str(tcx, "", false, *self) } } @@ -767,8 +786,8 @@ impl UserString for ty::BuiltinBound { match *self { ty::BoundCopy => ~"Copy", ty::BoundStatic => ~"'static", - ty::BoundOwned => ~"Owned", - ty::BoundConst => ~"Const", + ty::BoundSend => ~"Send", + ty::BoundFreeze => ~"Freeze", ty::BoundSized => ~"Sized", } } @@ -780,6 +799,19 @@ impl Repr for ty::BuiltinBounds { } } +impl Repr for span { + fn repr(&self, tcx: ctxt) -> ~str { + tcx.sess.codemap.span_to_str(*self) + } +} + +impl<A:UserString> UserString for @A { + fn user_string(&self, tcx: ctxt) -> ~str { + let this: &A = &**self; + this.user_string(tcx) + } +} + impl UserString for ty::BuiltinBounds { fn user_string(&self, tcx: ctxt) -> ~str { if self.is_empty() { ~"<no-bounds>" } else { diff --git a/src/librustdoc/astsrv.rs b/src/librustdoc/astsrv.rs index 3775aafb569..9c586ae95d1 100644 --- a/src/librustdoc/astsrv.rs +++ b/src/librustdoc/astsrv.rs @@ -17,13 +17,12 @@ query AST-related information, shielding the rest of Rustdoc from its non-sendableness. */ -use core::prelude::*; use parse; -use core::cell::Cell; -use core::comm::{stream, SharedChan, Port}; -use core::task; +use std::cell::Cell; +use std::comm::{stream, SharedChan, Port}; +use std::task; use rustc::driver::driver; use rustc::driver::session::Session; use rustc::driver::session::{basic_options, options}; @@ -99,7 +98,7 @@ fn act(po: &Port<Msg>, source: @str, parse: Parser) { } } -pub fn exec<T:Owned>( +pub fn exec<T:Send>( srv: Srv, f: ~fn(ctxt: Ctxt) -> T ) -> T { diff --git a/src/librustdoc/attr_parser.rs b/src/librustdoc/attr_parser.rs index 1abdae113c5..7655e173e4e 100644 --- a/src/librustdoc/attr_parser.rs +++ b/src/librustdoc/attr_parser.rs @@ -15,7 +15,6 @@ The attribute parser provides methods for pulling documentation out of an AST's attributes. */ -use core::prelude::*; use syntax::ast; use syntax::attr; @@ -57,7 +56,8 @@ pub fn parse_desc(attrs: ~[ast::attribute]) -> Option<~str> { } pub fn parse_hidden(attrs: ~[ast::attribute]) -> bool { - do doc_metas(attrs).find |meta| { + let r = doc_metas(attrs); + do r.iter().any_ |meta| { match attr::get_meta_item_list(*meta) { Some(metas) => { let hiddens = attr::find_meta_items_by_name(metas, "hidden"); @@ -65,12 +65,11 @@ pub fn parse_hidden(attrs: ~[ast::attribute]) -> bool { } None => false } - }.is_some() + } } #[cfg(test)] mod test { - use core::prelude::*; use syntax::ast; use syntax; use super::{parse_hidden, parse_crate, parse_desc}; diff --git a/src/librustdoc/attr_pass.rs b/src/librustdoc/attr_pass.rs index a1dad7d17f8..2a9442fbe52 100644 --- a/src/librustdoc/attr_pass.rs +++ b/src/librustdoc/attr_pass.rs @@ -16,7 +16,6 @@ corresponding AST nodes. The information gathered here is the basis of the natural-language documentation for a crate. */ -use core::prelude::*; use astsrv; use attr_parser; @@ -27,7 +26,6 @@ use fold::Fold; use fold; use pass::Pass; -use core::vec; use syntax::ast; use syntax::ast_map; @@ -101,7 +99,7 @@ fn fold_item( } } -fn parse_item_attrs<T:Owned>( +fn parse_item_attrs<T:Send>( srv: astsrv::Srv, id: doc::AstId, parse_attrs: ~fn(a: ~[ast::attribute]) -> T) -> T { @@ -125,7 +123,7 @@ fn fold_enum( let doc = fold::default_seq_fold_enum(fold, doc); doc::EnumDoc { - variants: do vec::map(doc.variants) |variant| { + variants: do doc.variants.iter().transform |variant| { let variant = copy *variant; let desc = { let variant = copy variant; @@ -135,7 +133,7 @@ fn fold_enum( node: ast::item_enum(ref enum_definition, _), _ }, _) => { let ast_variant = - vec::find(enum_definition.variants, |v| { + copy *enum_definition.variants.iter().find_(|v| { to_str(v.node.name) == variant.name }).get(); @@ -154,7 +152,7 @@ fn fold_enum( desc: desc, .. variant } - }, + }.collect(), .. doc } } @@ -184,7 +182,7 @@ fn merge_method_attrs( ast_map::node_item(@ast::item { node: ast::item_trait(_, _, ref methods), _ }, _) => { - vec::map(*methods, |method| { + methods.iter().transform(|method| { match copy *method { ast::required(ty_m) => { (to_str(ty_m.ident), @@ -194,21 +192,21 @@ fn merge_method_attrs( (to_str(m.ident), attr_parser::parse_desc(copy m.attrs)) } } - }) + }).collect() } ast_map::node_item(@ast::item { node: ast::item_impl(_, _, _, ref methods), _ }, _) => { - vec::map(*methods, |method| { + methods.iter().transform(|method| { (to_str(method.ident), attr_parser::parse_desc(copy method.attrs)) - }) + }).collect() } _ => fail!("unexpected item") } }; - do vec::map_zip(docs, attrs) |doc, attrs| { + do docs.iter().zip(attrs.iter()).transform |(doc, attrs)| { assert!(doc.name == attrs.first()); let desc = attrs.second(); @@ -216,7 +214,7 @@ fn merge_method_attrs( desc: desc, .. copy *doc } - } + }.collect() } @@ -235,7 +233,6 @@ fn fold_impl( #[cfg(test)] mod test { - use core::prelude::*; use astsrv; use attr_pass::run; diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index ef65cc8e5a1..dd929fb143b 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,15 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; -use core::cell::Cell; -use core::os; -use core::result::Result; -use core::result; -use core::run::ProcessOutput; -use core::run; -use core::vec; +use std::cell::Cell; +use std::os; +use std::result::Result; +use std::result; +use std::run::ProcessOutput; +use std::run; +use std::vec; use extra::getopts; /// The type of document to output @@ -59,24 +58,25 @@ fn opt_help() -> ~str { ~"h" } fn opts() -> ~[(getopts::Opt, ~str)] { ~[ (getopts::optopt(opt_output_dir()), - ~"--output-dir <val> put documents here"), + ~"--output-dir <val> Put documents here (default: .)"), (getopts::optopt(opt_output_format()), - ~"--output-format <val> either 'markdown' or 'html'"), + ~"--output-format <val> 'markdown' or 'html' (default)"), (getopts::optopt(opt_output_style()), - ~"--output-style <val> either 'doc-per-crate' or 'doc-per-mod'"), + ~"--output-style <val> 'doc-per-crate' or 'doc-per-mod' (default)"), (getopts::optopt(opt_pandoc_cmd()), - ~"--pandoc-cmd <val> the command for running pandoc"), + ~"--pandoc-cmd <val> Command for running pandoc"), (getopts::optflag(opt_help()), - ~"-h print help") + ~"-h, --help Print help") ] } pub fn usage() { - use core::io::println; + use std::io::println; println("Usage: rustdoc [options] <cratefile>\n"); println("Options:\n"); - for opts().each |opt| { + let r = opts(); + for r.iter().advance |opt| { println(fmt!(" %s", opt.second())); } println(""); @@ -230,26 +230,24 @@ pub fn maybe_find_pandoc( } }; - let pandoc = do vec::find(possible_pandocs) |pandoc| { + let pandoc = do possible_pandocs.iter().find_ |&pandoc| { let output = process_output(*pandoc, [~"--version"]); debug!("testing pandoc cmd %s: %?", *pandoc, output); output.status == 0 }; - if pandoc.is_some() { - result::Ok(pandoc) - } else { - result::Err(~"couldn't find pandoc") + match pandoc { + Some(x) => Ok(Some(copy *x)), // ugly, shouldn't be doubly wrapped + None => Err(~"couldn't find pandoc") } } #[cfg(test)] mod test { - use core::prelude::*; use config::*; - use core::result; - use core::run::ProcessOutput; + use std::result; + use std::run::ProcessOutput; fn parse_config(args: &[~str]) -> Result<Config, ~str> { parse_config_(args, mock_process_output) diff --git a/src/librustdoc/demo.rs b/src/librustdoc/demo.rs index c5fb8f289f6..b6728e00fe4 100644 --- a/src/librustdoc/demo.rs +++ b/src/librustdoc/demo.rs @@ -21,7 +21,6 @@ * tests on this file */ -use core::prelude::*; /// The base price of a muffin on a non-holiday static price_of_a_muffin: float = 70f; @@ -128,7 +127,7 @@ struct Bored { } impl Drop for Bored { - fn finalize(&self) { } + fn drop(&self) { } } /** diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs index dbaa5e8532c..74d5d467413 100644 --- a/src/librustdoc/desc_to_brief_pass.rs +++ b/src/librustdoc/desc_to_brief_pass.rs @@ -15,7 +15,6 @@ If the first paragraph of a long description is short enough then it is interpreted as the brief description. */ -use core::prelude::*; use astsrv; use doc::ItemUtils; @@ -24,7 +23,7 @@ use fold::Fold; use fold; use pass::Pass; -use core::util; +use std::util; pub fn mk_pass() -> Pass { Pass { @@ -176,7 +175,6 @@ pub fn paragraphs(s: &str) -> ~[~str] { #[cfg(test)] mod test { - use core::prelude::*; use astsrv; use attr_pass; diff --git a/src/librustdoc/doc.rs b/src/librustdoc/doc.rs index 2fa4d3b63cd..b45550c06e4 100644 --- a/src/librustdoc/doc.rs +++ b/src/librustdoc/doc.rs @@ -10,11 +10,10 @@ //! The document model -use core::prelude::*; use doc; -use core::vec; +use std::vec; pub type AstId = int; diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs index f8c49f544bc..d5d2b4ce628 100644 --- a/src/librustdoc/extract.rs +++ b/src/librustdoc/extract.rs @@ -10,13 +10,12 @@ //! Converts the Rust AST to the rustdoc document model -use core::prelude::*; use astsrv; use doc::ItemUtils; use doc; -use core::vec; +use std::vec; use syntax::ast; use syntax::parse::token::{ident_interner, ident_to_str}; use syntax::parse::token; @@ -102,7 +101,7 @@ fn moddoc_from_mod( fndoc_from_fn(ItemDoc) )) } - ast::item_const(_, _) => { + ast::item_static(*) => { Some(doc::ConstTag( constdoc_from_const(ItemDoc) )) @@ -144,13 +143,13 @@ fn nmoddoc_from_mod( module_: ast::foreign_mod ) -> doc::NmodDoc { let mut fns = ~[]; - for module_.items.each |item| { + for module_.items.iter().advance |item| { let ItemDoc = mk_itemdoc(item.id, to_str(item.ident)); match item.node { ast::foreign_item_fn(*) => { fns.push(fndoc_from_fn(ItemDoc)); } - ast::foreign_item_const(*) => {} // XXX: Not implemented. + ast::foreign_item_static(*) => {} // XXX: Not implemented. } } doc::NmodDoc { @@ -187,7 +186,7 @@ fn enumdoc_from_enum( fn variantdocs_from_variants( variants: ~[ast::variant] ) -> ~[doc::VariantDoc] { - vec::map(variants, variantdoc_from_variant) + variants.iter().transform(variantdoc_from_variant).collect() } fn variantdoc_from_variant(variant: &ast::variant) -> doc::VariantDoc { @@ -204,7 +203,7 @@ fn traitdoc_from_trait( ) -> doc::TraitDoc { doc::TraitDoc { item: itemdoc, - methods: do vec::map(methods) |method| { + methods: do methods.iter().transform |method| { match copy *method { ast::required(ty_m) => { doc::MethodDoc { @@ -227,7 +226,7 @@ fn traitdoc_from_trait( } } } - } + }.collect() } } @@ -240,7 +239,7 @@ fn impldoc_from_impl( bounds_str: None, trait_types: ~[], self_ty: None, - methods: do vec::map(methods) |method| { + methods: do methods.iter().transform |method| { doc::MethodDoc { name: to_str(method.ident), brief: None, @@ -249,7 +248,7 @@ fn impldoc_from_impl( sig: None, implementation: doc::Provided, } - } + }.collect() } } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 7cf616065d3..6510384ef01 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -8,14 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use doc; #[cfg(test)] use extract; #[cfg(test)] use parse; -use core::vec; - pub struct Fold<T> { ctxt: T, fold_doc: FoldDoc<T>, @@ -156,7 +153,7 @@ pub fn default_par_fold<T:Clone>(ctxt: T) -> Fold<T> { pub fn default_seq_fold_doc<T>(fold: &Fold<T>, doc: doc::Doc) -> doc::Doc { doc::Doc { - pages: do vec::map(doc.pages) |page| { + pages: do doc.pages.iter().transform |page| { match copy *page { doc::CratePage(doc) => { doc::CratePage((fold.fold_crate)(fold, doc)) @@ -165,7 +162,7 @@ pub fn default_seq_fold_doc<T>(fold: &Fold<T>, doc: doc::Doc) -> doc::Doc { doc::ItemPage(fold_ItemTag(fold, doc)) } } - }, + }.collect(), .. doc } } @@ -192,9 +189,9 @@ pub fn default_any_fold_mod<T:Clone>( ) -> doc::ModDoc { doc::ModDoc { item: (fold.fold_item)(fold, copy doc.item), - items: vec::map(doc.items, |ItemTag| { + items: doc.items.iter().transform(|ItemTag| { fold_ItemTag(fold, copy *ItemTag) - }), + }).collect(), .. doc } } @@ -205,9 +202,9 @@ pub fn default_seq_fold_mod<T>( ) -> doc::ModDoc { doc::ModDoc { item: (fold.fold_item)(fold, copy doc.item), - items: vec::map(doc.items, |ItemTag| { + items: doc.items.iter().transform(|ItemTag| { fold_ItemTag(fold, copy *ItemTag) - }), + }).collect(), .. doc } } @@ -218,9 +215,9 @@ pub fn default_par_fold_mod<T:Clone>( ) -> doc::ModDoc { doc::ModDoc { item: (fold.fold_item)(fold, copy doc.item), - items: vec::map(doc.items, |ItemTag| { + items: doc.items.iter().transform(|ItemTag| { fold_ItemTag(fold, copy *ItemTag) - }), + }).collect(), .. doc } } @@ -231,9 +228,9 @@ pub fn default_any_fold_nmod<T:Clone>( ) -> doc::NmodDoc { doc::NmodDoc { item: (fold.fold_item)(fold, copy doc.item), - fns: vec::map(doc.fns, |FnDoc| { + fns: doc.fns.iter().transform(|FnDoc| { (fold.fold_fn)(fold, copy *FnDoc) - }), + }).collect(), .. doc } } @@ -244,9 +241,9 @@ pub fn default_seq_fold_nmod<T>( ) -> doc::NmodDoc { doc::NmodDoc { item: (fold.fold_item)(fold, copy doc.item), - fns: vec::map(doc.fns, |FnDoc| { + fns: doc.fns.iter().transform(|FnDoc| { (fold.fold_fn)(fold, copy *FnDoc) - }), + }).collect(), .. doc } } @@ -257,9 +254,9 @@ pub fn default_par_fold_nmod<T:Clone>( ) -> doc::NmodDoc { doc::NmodDoc { item: (fold.fold_item)(fold, copy doc.item), - fns: vec::map(doc.fns, |FnDoc| { + fns: doc.fns.iter().transform(|FnDoc| { (fold.fold_fn)(fold, copy *FnDoc) - }), + }).collect(), .. doc } } diff --git a/src/librustdoc/markdown_index_pass.rs b/src/librustdoc/markdown_index_pass.rs index 3634155b8a3..1e67f900822 100644 --- a/src/librustdoc/markdown_index_pass.rs +++ b/src/librustdoc/markdown_index_pass.rs @@ -10,7 +10,6 @@ //! Build indexes as appropriate for the markdown pass -use core::prelude::*; use astsrv; use config; @@ -164,7 +163,6 @@ pub fn pandoc_header_id(header: &str) -> ~str { #[cfg(test)] mod test { - use core::prelude::*; use astsrv; use attr_pass; diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index 075b64a674c..0705a5c1723 100644 --- a/src/librustdoc/markdown_pass.rs +++ b/src/librustdoc/markdown_pass.rs @@ -10,7 +10,6 @@ //! Generate markdown from a document tree -use core::prelude::*; use astsrv; use doc::ItemUtils; @@ -22,9 +21,9 @@ use markdown_writer::WriterFactory; use pass::Pass; use sort_pass; -use core::cell::Cell; -use core::str; -use core::vec; +use std::cell::Cell; +use std::str; +use std::vec; use syntax; pub fn mk_pass(writer_factory: WriterFactory) -> Pass { @@ -152,7 +151,7 @@ pub fn header_kind(doc: doc::ItemTag) -> ~str { ~"Function" } doc::ConstTag(_) => { - ~"Const" + ~"Freeze" } doc::EnumTag(_) => { ~"Enum" @@ -190,13 +189,13 @@ pub fn header_name(doc: doc::ItemTag) -> ~str { }; let self_ty = doc.self_ty.get_ref(); let mut trait_part = ~""; - for doc.trait_types.eachi |i, trait_type| { + for doc.trait_types.iter().enumerate().advance |(i, trait_type)| { if i == 0 { - trait_part += " of "; + trait_part.push_str(" of "); } else { - trait_part += ", "; + trait_part.push_str(", "); } - trait_part += *trait_type; + trait_part.push_str(*trait_type); } fmt!("%s for %s%s", trait_part, *self_ty, bounds) } @@ -280,7 +279,7 @@ fn write_desc( } fn write_sections(ctxt: &Ctxt, sections: &[doc::Section]) { - for sections.each |section| { + for sections.iter().advance |section| { write_section(ctxt, copy *section); } } @@ -300,7 +299,7 @@ fn write_mod_contents( write_index(ctxt, doc.index.get_ref()); } - for doc.items.each |itemTag| { + for doc.items.iter().advance |itemTag| { write_item(ctxt, copy *itemTag); } } @@ -350,7 +349,7 @@ fn write_index(ctxt: &Ctxt, index: &doc::Index) { ctxt.w.put_line(~"<div class='index'>"); ctxt.w.put_line(~""); - for index.entries.each |entry| { + for index.entries.iter().advance |entry| { let header = header_text_(entry.kind, entry.name); let id = copy entry.link; if entry.brief.is_some() { @@ -371,7 +370,7 @@ fn write_nmod(ctxt: &Ctxt, doc: doc::NmodDoc) { write_index(ctxt, doc.index.get_ref()); } - for doc.fns.each |FnDoc| { + for doc.fns.iter().advance |FnDoc| { write_item_header(ctxt, doc::FnTag(copy *FnDoc)); write_fn(ctxt, copy *FnDoc); } @@ -441,7 +440,7 @@ fn write_variants( write_header_(ctxt, H4, ~"Variants"); - for docs.each |variant| { + for docs.iter().advance |variant| { write_variant(ctxt, copy *variant); } @@ -480,7 +479,7 @@ fn write_trait(ctxt: &Ctxt, doc: doc::TraitDoc) { } fn write_methods(ctxt: &Ctxt, docs: &[doc::MethodDoc]) { - for docs.each |doc| { + for docs.iter().advance |doc| { write_method(ctxt, copy *doc); } } @@ -518,7 +517,6 @@ fn put_struct( #[cfg(test)] mod test { - use core::prelude::*; use astsrv; use attr_pass; @@ -786,7 +784,7 @@ mod test { #[test] fn should_write_const_header() { let markdown = render(~"static a: bool = true;"); - assert!(markdown.contains("## Const `a`\n\n")); + assert!(markdown.contains("## Freeze `a`\n\n")); } #[test] diff --git a/src/librustdoc/markdown_writer.rs b/src/librustdoc/markdown_writer.rs index 35315276326..9621ea0892b 100644 --- a/src/librustdoc/markdown_writer.rs +++ b/src/librustdoc/markdown_writer.rs @@ -8,19 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use config; use doc::ItemUtils; use doc; -use core::comm::*; -use core::comm; -use core::io; -use core::result; -use core::run; -use core::str; -use core::task; +use std::comm::*; +use std::comm; +use std::io; +use std::result; +use std::run; +use std::str; +use std::task; use extra::future; pub enum WriteInstr { @@ -104,7 +103,7 @@ fn pandoc_writer( ]; do generic_writer |markdown| { - use core::io::WriterUtil; + use std::io::WriterUtil; debug!("pandoc cmd: %s", pandoc_cmd); debug!("pandoc args: %s", pandoc_args.connect(" ")); @@ -130,7 +129,7 @@ fn generic_writer(process: ~fn(markdown: ~str)) -> Writer { let mut keep_going = true; while keep_going { match po.recv() { - Write(s) => markdown += s, + Write(s) => markdown.push_str(s), Done => keep_going = false } } @@ -177,7 +176,7 @@ pub fn make_filename( } fn write_file(path: &Path, s: ~str) { - use core::io::WriterUtil; + use std::io::WriterUtil; match io::file_writer(path, [io::Create, io::Truncate]) { result::Ok(writer) => { @@ -214,7 +213,7 @@ fn future_writer() -> (Writer, future::Future<~str>) { let mut res = ~""; loop { match port.recv() { - Write(s) => res += s, + Write(s) => res.push_str(s), Done => break } } @@ -225,7 +224,6 @@ fn future_writer() -> (Writer, future::Future<~str>) { #[cfg(test)] mod test { - use core::prelude::*; use astsrv; use doc; diff --git a/src/librustdoc/page_pass.rs b/src/librustdoc/page_pass.rs index 584e6ccc887..508cf302ede 100644 --- a/src/librustdoc/page_pass.rs +++ b/src/librustdoc/page_pass.rs @@ -15,7 +15,6 @@ Each page corresponds is a logical section. There may be pages for individual modules, pages for the crate, indexes, etc. */ -use core::prelude::*; use astsrv; use config; @@ -26,8 +25,8 @@ use fold; use pass::Pass; use util::NominalOp; -use core::comm::*; -use core::task; +use std::comm::*; +use std::task; use syntax::ast; #[cfg(test)] use doc::PageUtils; @@ -70,7 +69,7 @@ fn make_doc_from_pages(page_port: &PagePort) -> doc::Doc { loop { let val = page_port.recv(); if val.is_some() { - pages += [val.unwrap()]; + pages.push(val.unwrap()); } else { break; } diff --git a/src/librustdoc/parse.rs b/src/librustdoc/parse.rs index 138e4d49156..bf782c9d5f3 100644 --- a/src/librustdoc/parse.rs +++ b/src/librustdoc/parse.rs @@ -10,7 +10,6 @@ //! AST-parsing helpers -use core::prelude::*; use rustc::driver::driver::{file_input, str_input}; use rustc::driver::driver; diff --git a/src/librustdoc/pass.rs b/src/librustdoc/pass.rs index 3654e2c7606..3497e9515c6 100644 --- a/src/librustdoc/pass.rs +++ b/src/librustdoc/pass.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; use astsrv; diff --git a/src/librustdoc/path_pass.rs b/src/librustdoc/path_pass.rs index a7a36152ace..55ce135f277 100644 --- a/src/librustdoc/path_pass.rs +++ b/src/librustdoc/path_pass.rs @@ -10,7 +10,6 @@ //! Records the full path to items -use core::prelude::*; use astsrv; use doc::ItemUtils; diff --git a/src/librustdoc/prune_private_pass.rs b/src/librustdoc/prune_private_pass.rs index 741da3e265e..cb7da801e96 100644 --- a/src/librustdoc/prune_private_pass.rs +++ b/src/librustdoc/prune_private_pass.rs @@ -10,7 +10,6 @@ //! Prune things that are private -use core::prelude::*; use extract; use syntax::ast; @@ -21,7 +20,7 @@ use fold::Fold; use fold; use pass::Pass; -use core::util; +use std::util; pub fn mk_pass() -> Pass { Pass { @@ -82,7 +81,7 @@ fn strip_priv_methods( item_vis: ast::visibility ) -> doc::ImplDoc { let methods = do (&doc.methods).filtered |method| { - let ast_method = do methods.find |m| { + let ast_method = do methods.iter().find_ |m| { extract::to_str(m.ident) == method.name }; assert!(ast_method.is_some()); diff --git a/src/librustdoc/rustdoc.rc b/src/librustdoc/rustdoc.rs index 7ed5d5f5516..3659d24a254 100644 --- a/src/librustdoc/rustdoc.rc +++ b/src/librustdoc/rustdoc.rs @@ -11,7 +11,7 @@ //! Rustdoc - The Rust documentation generator #[link(name = "rustdoc", - vers = "0.7-pre", + vers = "0.7", uuid = "f8abd014-b281-484d-a0c3-26e3de8e2412", url = "https://github.com/mozilla/rust/tree/master/src/rustdoc")]; @@ -21,22 +21,17 @@ #[allow(non_implicitly_copyable_typarams)]; -#[no_std]; - -extern mod core(name = "std"); -extern mod extra(name = "extra"); - +extern mod extra; extern mod rustc; extern mod syntax; -use core::prelude::*; +use std::io; +use std::os; use config::Config; use doc::Item; use doc::ItemUtils; -use core::*; - pub mod pass; pub mod config; pub mod parse; @@ -66,19 +61,10 @@ pub mod escape_pass; pub mod prune_private_pass; pub mod util; -mod std { - pub use core::clone; - pub use core::cmp; - pub use core::os; - pub use core::str; - pub use core::sys; - pub use core::unstable; -} - pub fn main() { let args = os::args(); - if args.contains(&~"-h") || args.contains(&~"--help") { + if args.iter().any_(|x| "-h" == *x) || args.iter().any_(|x| "--help" == *x) { config::usage(); return; } diff --git a/src/librustdoc/sectionalize_pass.rs b/src/librustdoc/sectionalize_pass.rs index ba433bf479d..4e297c36dd4 100644 --- a/src/librustdoc/sectionalize_pass.rs +++ b/src/librustdoc/sectionalize_pass.rs @@ -10,7 +10,6 @@ //! Breaks rustdocs into sections according to their headers -use core::prelude::*; use astsrv; use doc::ItemUtils; @@ -19,7 +18,7 @@ use fold::Fold; use fold; use pass::Pass; -use core::iterator::IteratorUtil; +use std::iterator::IteratorUtil; pub fn mk_pass() -> Pass { Pass { @@ -162,7 +161,6 @@ fn parse_header<'a>(line: &'a str) -> Option<&'a str> { #[cfg(test)] mod test { - use core::prelude::*; use astsrv; use attr_pass; diff --git a/src/librustdoc/text_pass.rs b/src/librustdoc/text_pass.rs index 6db582a60e9..58b7571305d 100644 --- a/src/librustdoc/text_pass.rs +++ b/src/librustdoc/text_pass.rs @@ -10,7 +10,6 @@ //! Generic pass for performing an operation on all descriptions -use core::prelude::*; use astsrv; use doc::ItemUtils; @@ -20,7 +19,7 @@ use fold; use pass::Pass; use util::NominalOp; -use core::cell::Cell; +use std::cell::Cell; pub fn mk_pass(name: ~str, op: @fn(&str) -> ~str) -> Pass { let op = Cell::new(op); @@ -139,7 +138,6 @@ fn fold_impl( #[cfg(test)] mod test { - use core::prelude::*; use astsrv; use attr_pass; diff --git a/src/librustdoc/trim_pass.rs b/src/librustdoc/trim_pass.rs index 8bfa12ca0b5..281a59c8cb7 100644 --- a/src/librustdoc/trim_pass.rs +++ b/src/librustdoc/trim_pass.rs @@ -40,7 +40,7 @@ mod test { #[test] fn should_trim_text() { - use core::option::Some; + use std::option::Some; let doc = mk_doc(~"#[doc = \" desc \"] \ mod m { diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index 82336addb62..e40bdb532da 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -10,7 +10,6 @@ //! Pulls type information out of the AST and attaches it to the document -use core::prelude::*; use astsrv; use doc::ItemUtils; @@ -21,7 +20,6 @@ use fold::Fold; use fold; use pass::Pass; -use core::vec; use syntax::ast; use syntax::print::pprust; use syntax::parse::token; @@ -96,7 +94,7 @@ fn fold_const( do astsrv::exec(srv) |ctxt| { match ctxt.ast_map.get_copy(&doc.id()) { ast_map::node_item(@ast::item { - node: ast::item_const(ty, _), _ + node: ast::item_static(ty, _, _), _ }, _) => { pprust::ty_to_str(ty, extract::interner()) } @@ -115,7 +113,7 @@ fn fold_enum( let srv = fold.ctxt.clone(); doc::EnumDoc { - variants: do vec::map(doc.variants) |variant| { + variants: do doc.variants.iter().transform |variant| { let sig = { let variant = copy *variant; do astsrv::exec(srv.clone()) |ctxt| { @@ -124,7 +122,7 @@ fn fold_enum( node: ast::item_enum(ref enum_definition, _), _ }, _) => { let ast_variant = - do vec::find(enum_definition.variants) |v| { + copy *do enum_definition.variants.iter().find_ |v| { to_str(v.node.name) == variant.name }.get(); @@ -140,7 +138,7 @@ fn fold_enum( sig: Some(sig), .. copy *variant } - }, + }.collect(), .. doc } } @@ -160,12 +158,12 @@ fn merge_methods( item_id: doc::AstId, docs: ~[doc::MethodDoc] ) -> ~[doc::MethodDoc] { - do vec::map(docs) |doc| { + do docs.iter().transform |doc| { doc::MethodDoc { sig: get_method_sig(srv.clone(), item_id, copy doc.name), .. copy *doc } - } + }.collect() } fn get_method_sig( @@ -178,14 +176,14 @@ fn get_method_sig( ast_map::node_item(@ast::item { node: ast::item_trait(_, _, ref methods), _ }, _) => { - match vec::find(*methods, |method| { + match methods.iter().find_(|&method| { match copy *method { ast::required(ty_m) => to_str(ty_m.ident) == method_name, ast::provided(m) => to_str(m.ident) == method_name, } }) { Some(method) => { - match method { + match copy *method { ast::required(ty_m) => { Some(pprust::fun_to_str( &ty_m.decl, @@ -214,7 +212,7 @@ fn get_method_sig( ast_map::node_item(@ast::item { node: ast::item_impl(_, _, _, ref methods), _ }, _) => { - match vec::find(*methods, |method| { + match methods.iter().find_(|method| { to_str(method.ident) == method_name }) { Some(method) => { @@ -349,7 +347,6 @@ fn strip_struct_extra_stuff(item: @ast::item) -> @ast::item { #[cfg(test)] mod test { - use core::prelude::*; use astsrv; use doc; diff --git a/src/librustdoc/unindent_pass.rs b/src/librustdoc/unindent_pass.rs index 2bcf04c0262..7df6b320780 100644 --- a/src/librustdoc/unindent_pass.rs +++ b/src/librustdoc/unindent_pass.rs @@ -19,9 +19,8 @@ instances where the string containing the doc comment is opened in the middle of a line, and each of the following lines is indented. */ -use core::prelude::*; -use core::uint; +use std::uint; use pass::Pass; use text_pass; diff --git a/src/librustdoc/util.rs b/src/librustdoc/util.rs index fe39ac6bc50..20e64087442 100644 --- a/src/librustdoc/util.rs +++ b/src/librustdoc/util.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; // Just a named container for our op, so it can have impls pub struct NominalOp<T> { diff --git a/src/librusti/program.rs b/src/librusti/program.rs index 513baa67ac1..869b3472422 100644 --- a/src/librusti/program.rs +++ b/src/librusti/program.rs @@ -96,7 +96,7 @@ impl Program { code.push_str("fn main() {\n"); // It's easy to initialize things if we don't run things... - for self.local_vars.each |name, var| { + for self.local_vars.iter().advance |(name, var)| { let mt = var.mt(); code.push_str(fmt!("let%s %s: %s = fail!();\n", mt, *name, var.ty)); var.alter(*name, &mut code); @@ -107,12 +107,12 @@ impl Program { match *to_print { Some(ref s) => { code.push_str(*s); - code.push_char('\n'); + code.push_str(";\n"); } None => {} } - for new_locals.each |p| { + for new_locals.iter().advance |p| { code.push_str(fmt!("assert_encodable(&%s);\n", *p.first_ref())); } code.push_str("};}"); @@ -149,7 +149,7 @@ impl Program { // Using this __tls_map handle, deserialize each variable binding that // we know about - for self.local_vars.each |name, var| { + for self.local_vars.iter().advance |(name, var)| { let mt = var.mt(); code.push_str(fmt!("let%s %s: %s = { let data = __tls_map.get_copy(&~\"%s\"); @@ -175,7 +175,7 @@ impl Program { // After the input code is run, we can re-serialize everything back out // into tls map (to be read later on by this task) - for self.local_vars.each |name, var| { + for self.local_vars.iter().advance |(name, var)| { code.push_str(fmt!("{ let local: %s = %s; let bytes = do ::std::io::with_bytes_writer |io| { @@ -237,7 +237,7 @@ impl Program { /// program starts pub fn set_cache(&self) { let map = @mut HashMap::new(); - for self.local_vars.each |name, value| { + for self.local_vars.iter().advance |(name, value)| { map.insert(copy *name, @copy value.data); } unsafe { @@ -370,7 +370,7 @@ impl Program { // helper functions to perform ast iteration fn each_user_local(blk: &ast::blk, f: &fn(@ast::local)) { do find_user_block(blk) |blk| { - for blk.node.stmts.each |stmt| { + for blk.node.stmts.iter().advance |stmt| { match stmt.node { ast::stmt_decl(d, _) => { match d.node { @@ -385,7 +385,7 @@ impl Program { } fn find_user_block(blk: &ast::blk, f: &fn(&ast::blk)) { - for blk.node.stmts.each |stmt| { + for blk.node.stmts.iter().advance |stmt| { match stmt.node { ast::stmt_semi(e, _) => { match e.node { diff --git a/src/librusti/rusti.rc b/src/librusti/rusti.rc index c618623a2cb..bbc4b9ff719 100644 --- a/src/librusti/rusti.rc +++ b/src/librusti/rusti.rc @@ -44,7 +44,7 @@ */ #[link(name = "rusti", - vers = "0.7-pre", + vers = "0.7", uuid = "7fb5bf52-7d45-4fee-8325-5ad3311149fc", url = "https://github.com/mozilla/rust/tree/master/src/rusti")]; @@ -130,7 +130,7 @@ fn run(mut repl: Repl, input: ~str) -> Repl { do find_main(crate, sess) |blk| { // Fish out all the view items, be sure to record 'extern mod' items // differently beause they must appear before all 'use' statements - for blk.node.view_items.each |vi| { + for blk.node.view_items.iter().advance |vi| { let s = do with_pp(intr) |pp, _| { pprust::print_view_item(pp, *vi); }; @@ -144,7 +144,7 @@ fn run(mut repl: Repl, input: ~str) -> Repl { // Iterate through all of the block's statements, inserting them into // the correct portions of the program - for blk.node.stmts.each |stmt| { + for blk.node.stmts.iter().advance |stmt| { let s = do with_pp(intr) |pp, _| { pprust::print_stmt(pp, *stmt); }; match stmt.node { ast::stmt_decl(d, _) => { @@ -248,7 +248,7 @@ fn run(mut repl: Repl, input: ~str) -> Repl { fn find_main(crate: @ast::crate, sess: session::Session, f: &fn(&ast::blk)) { - for crate.node.module.items.each |item| { + for crate.node.module.items.iter().advance |item| { match item.node { ast::item_fn(_, _, _, _, ref blk) => { if item.ident == sess.ident_of("main") { @@ -287,7 +287,7 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> { // file, skip compilation and return None. let mut should_compile = true; let dir = os::list_dir_path(&Path(outputs.out_filename.dirname())); - let maybe_lib_path = do dir.find |file| { + let maybe_lib_path = do dir.iter().find_ |file| { // The actual file's name has a hash value and version // number in it which is unknown at this time, so looking // for a file that matches out_filename won't work, @@ -365,7 +365,7 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer, } ~"load" => { let mut loaded_crates: ~[~str] = ~[]; - for args.each |arg| { + for args.iter().advance |arg| { let (crate, filename) = if arg.ends_with(".rs") || arg.ends_with(".rc") { (arg.slice_to(arg.len() - 3).to_owned(), copy *arg) @@ -377,11 +377,11 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer, None => { } } } - for loaded_crates.each |crate| { + for loaded_crates.iter().advance |crate| { let crate_path = Path(*crate); let crate_dir = crate_path.dirname(); repl.program.record_extern(fmt!("extern mod %s;", *crate)); - if !repl.lib_search_paths.contains(&crate_dir) { + if !repl.lib_search_paths.iter().any_(|x| x == &crate_dir) { repl.lib_search_paths.push(crate_dir); } } @@ -402,7 +402,8 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer, if line.trim() == ":}" { end_multiline = true; } else { - multiline_cmd += line + "\n"; + multiline_cmd.push_str(line); + multiline_cmd.push_char('\n'); } } } @@ -430,7 +431,7 @@ pub fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str, if !cmd.is_empty() { let args = if len > 1 { - vec::slice(split, 1, len).to_vec() + vec::slice(split, 1, len).to_owned() } else { ~[] }; match run_cmd(repl, in, out, cmd, args, use_rl) { @@ -510,7 +511,8 @@ pub fn main() { } } -#[cfg(test)] +//#[cfg(test)] +#[cfg(ignore)] // FIXME #7541 doesn't work under cross-compile mod tests { use std::io; use std::iterator::IteratorUtil; diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs new file mode 100644 index 00000000000..f91d9932239 --- /dev/null +++ b/src/librusti/rusti.rs @@ -0,0 +1,687 @@ +// Copyright 2012-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. + +/*! + * rusti - A REPL using the JIT backend + * + * Rusti works by serializing state between lines of input. This means that each + * line can be run in a separate task, and the only limiting factor is that all + * local bound variables are encodable. + * + * This is accomplished by feeding in generated input to rustc for execution in + * the JIT compiler. Currently input actually gets fed in three times to get + * information about the program. + * + * - Pass #1 + * In this pass, the input is simply thrown at the parser and the input comes + * back. This validates the structure of the program, and at this stage the + * global items (fns, structs, impls, traits, etc.) are filtered from the + * input into the "global namespace". These declarations shadow all previous + * declarations of an item by the same name. + * + * - Pass #2 + * After items have been stripped, the remaining input is passed to rustc + * along with all local variables declared (initialized to nothing). This pass + * runs up to typechecking. From this, we can learn about the types of each + * bound variable, what variables are bound, and also ensure that all the + * types are encodable (the input can actually be run). + * + * - Pass #3 + * Finally, a program is generated to deserialize the local variable state, + * run the code input, and then reserialize all bindings back into a local + * hash map. Once this code runs, the input has fully been run and the REPL + * waits for new input. + * + * Encoding/decoding is done with EBML, and there is simply a map of ~str -> + * ~[u8] maintaining the values of each local binding (by name). + */ + +#[link(name = "rusti", + vers = "0.7", + uuid = "7fb5bf52-7d45-4fee-8325-5ad3311149fc", + url = "https://github.com/mozilla/rust/tree/master/src/rusti")]; + +#[license = "MIT/ASL2"]; +#[crate_type = "lib"]; + +extern mod extra; +extern mod rustc; +extern mod syntax; + +use std::{libc, io, os, task}; +use std::cell::Cell; +use extra::rl; + +use rustc::driver::{driver, session}; +use syntax::{ast, diagnostic}; +use syntax::ast_util::*; +use syntax::parse::token; +use syntax::print::pprust; + +use program::Program; +use utils::*; + +mod program; +pub mod utils; + +/** + * A structure shared across REPL instances for storing history + * such as statements and view items. I wish the AST was sendable. + */ +pub struct Repl { + prompt: ~str, + binary: ~str, + running: bool, + lib_search_paths: ~[~str], + + program: Program, +} + +// Action to do after reading a :command +enum CmdAction { + action_none, + action_run_line(~str), +} + +/// Run an input string in a Repl, returning the new Repl. +fn run(mut repl: Repl, input: ~str) -> Repl { + // Build some necessary rustc boilerplate for compiling things + let binary = repl.binary.to_managed(); + let options = @session::options { + crate_type: session::unknown_crate, + binary: binary, + addl_lib_search_paths: @mut repl.lib_search_paths.map(|p| Path(*p)), + jit: true, + .. copy *session::basic_options() + }; + // Because we assume that everything is encodable (and assert so), add some + // extra helpful information if the error crops up. Otherwise people are + // bound to be very confused when they find out code is running that they + // never typed in... + let sess = driver::build_session(options, |cm, msg, lvl| { + diagnostic::emit(cm, msg, lvl); + if msg.contains("failed to find an implementation of trait") && + msg.contains("extra::serialize::Encodable") { + diagnostic::emit(cm, + "Currrently rusti serializes bound locals between \ + different lines of input. This means that all \ + values of local variables need to be encodable, \ + and this type isn't encodable", + diagnostic::note); + } + }); + let intr = token::get_ident_interner(); + + // + // Stage 1: parse the input and filter it into the program (as necessary) + // + debug!("parsing: %s", input); + let crate = parse_input(sess, binary, input); + let mut to_run = ~[]; // statements to run (emitted back into code) + let new_locals = @mut ~[]; // new locals being defined + let mut result = None; // resultant expression (to print via pp) + do find_main(crate, sess) |blk| { + // Fish out all the view items, be sure to record 'extern mod' items + // differently beause they must appear before all 'use' statements + for blk.node.view_items.iter().advance |vi| { + let s = do with_pp(intr) |pp, _| { + pprust::print_view_item(pp, *vi); + }; + match vi.node { + ast::view_item_extern_mod(*) => { + repl.program.record_extern(s); + } + ast::view_item_use(*) => { repl.program.record_view_item(s); } + } + } + + // Iterate through all of the block's statements, inserting them into + // the correct portions of the program + for blk.node.stmts.iter().advance |stmt| { + let s = do with_pp(intr) |pp, _| { pprust::print_stmt(pp, *stmt); }; + match stmt.node { + ast::stmt_decl(d, _) => { + match d.node { + ast::decl_item(it) => { + let name = sess.str_of(it.ident); + match it.node { + // Structs are treated specially because to make + // them at all usable they need to be decorated + // with #[deriving(Encoable, Decodable)] + ast::item_struct(*) => { + repl.program.record_struct(name, s); + } + // Item declarations are hoisted out of main() + _ => { repl.program.record_item(name, s); } + } + } + + // Local declarations must be specially dealt with, + // record all local declarations for use later on + ast::decl_local(l) => { + let mutbl = l.node.is_mutbl; + do each_binding(l) |path, _| { + let s = do with_pp(intr) |pp, _| { + pprust::print_path(pp, path, false); + }; + new_locals.push((s, mutbl)); + } + to_run.push(s); + } + } + } + + // run statements with expressions (they have effects) + ast::stmt_mac(*) | ast::stmt_semi(*) | ast::stmt_expr(*) => { + to_run.push(s); + } + } + } + result = do blk.node.expr.map_consume |e| { + do with_pp(intr) |pp, _| { pprust::print_expr(pp, e); } + }; + } + // return fast for empty inputs + if to_run.len() == 0 && result.is_none() { + return repl; + } + + // + // Stage 2: run everything up to typeck to learn the types of the new + // variables introduced into the program + // + info!("Learning about the new types in the program"); + repl.program.set_cache(); // before register_new_vars (which changes them) + let input = to_run.connect("\n"); + let test = repl.program.test_code(input, &result, *new_locals); + debug!("testing with ^^^^^^ %?", (||{ println(test) })()); + let dinput = driver::str_input(test.to_managed()); + let cfg = driver::build_configuration(sess, binary, &dinput); + let outputs = driver::build_output_filenames(&dinput, &None, &None, [], sess); + let (crate, tcx) = driver::compile_upto(sess, copy cfg, &dinput, + driver::cu_typeck, Some(outputs)); + // Once we're typechecked, record the types of all local variables defined + // in this input + do find_main(crate.expect("crate after cu_typeck"), sess) |blk| { + repl.program.register_new_vars(blk, tcx.expect("tcx after cu_typeck")); + } + + // + // Stage 3: Actually run the code in the JIT + // + info!("actually running code"); + let code = repl.program.code(input, &result); + debug!("actually running ^^^^^^ %?", (||{ println(code) })()); + let input = driver::str_input(code.to_managed()); + let cfg = driver::build_configuration(sess, binary, &input); + let outputs = driver::build_output_filenames(&input, &None, &None, [], sess); + let sess = driver::build_session(options, diagnostic::emit); + driver::compile_upto(sess, cfg, &input, driver::cu_everything, + Some(outputs)); + + // + // Stage 4: Inform the program that computation is done so it can update all + // local variable bindings. + // + info!("cleaning up after code"); + repl.program.consume_cache(); + + return repl; + + fn parse_input(sess: session::Session, binary: @str, + input: &str) -> @ast::crate { + let code = fmt!("fn main() {\n %s \n}", input); + let input = driver::str_input(code.to_managed()); + let cfg = driver::build_configuration(sess, binary, &input); + let outputs = driver::build_output_filenames(&input, &None, &None, [], sess); + let (crate, _) = driver::compile_upto(sess, cfg, &input, + driver::cu_parse, Some(outputs)); + crate.expect("parsing should return a crate") + } + + fn find_main(crate: @ast::crate, sess: session::Session, + f: &fn(&ast::blk)) { + for crate.node.module.items.iter().advance |item| { + match item.node { + ast::item_fn(_, _, _, _, ref blk) => { + if item.ident == sess.ident_of("main") { + return f(blk); + } + } + _ => {} + } + } + fail!("main function was expected somewhere..."); + } +} + +// Compiles a crate given by the filename as a library if the compiled +// version doesn't exist or is older than the source file. Binary is +// the name of the compiling executable. Returns Some(true) if it +// successfully compiled, Some(false) if the crate wasn't compiled +// because it already exists and is newer than the source file, or +// None if there were compile errors. +fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> { + match do task::try { + let src_path = Path(src_filename); + let binary = binary.to_managed(); + let options = @session::options { + binary: binary, + addl_lib_search_paths: @mut ~[os::getcwd()], + .. copy *session::basic_options() + }; + let input = driver::file_input(copy src_path); + let sess = driver::build_session(options, diagnostic::emit); + *sess.building_library = true; + let cfg = driver::build_configuration(sess, binary, &input); + let outputs = driver::build_output_filenames( + &input, &None, &None, [], sess); + // If the library already exists and is newer than the source + // file, skip compilation and return None. + let mut should_compile = true; + let dir = os::list_dir_path(&Path(outputs.out_filename.dirname())); + let maybe_lib_path = do dir.iter().find_ |file| { + // The actual file's name has a hash value and version + // number in it which is unknown at this time, so looking + // for a file that matches out_filename won't work, + // instead we guess which file is the library by matching + // the prefix and suffix of out_filename to files in the + // directory. + let file_str = file.filename().get(); + file_str.starts_with(outputs.out_filename.filestem().get()) + && file_str.ends_with(outputs.out_filename.filetype().get()) + }; + match maybe_lib_path { + Some(lib_path) => { + let (src_mtime, _) = src_path.get_mtime().get(); + let (lib_mtime, _) = lib_path.get_mtime().get(); + if lib_mtime >= src_mtime { + should_compile = false; + } + }, + None => { }, + } + if (should_compile) { + println(fmt!("compiling %s...", src_filename)); + driver::compile_upto(sess, cfg, &input, driver::cu_everything, + Some(outputs)); + true + } else { false } + } { + Ok(true) => Some(true), + Ok(false) => Some(false), + Err(_) => None, + } +} + +/// Tries to get a line from rl after outputting a prompt. Returns +/// None if no input was read (e.g. EOF was reached). +fn get_line(use_rl: bool, prompt: &str) -> Option<~str> { + if use_rl { + let result = unsafe { rl::read(prompt) }; + + match result { + None => None, + Some(line) => { + unsafe { rl::add_history(line) }; + Some(line) + } + } + } else { + if io::stdin().eof() { + None + } else { + Some(io::stdin().read_line()) + } + } +} + +/// Run a command, e.g. :clear, :exit, etc. +fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer, + cmd: ~str, args: ~[~str], use_rl: bool) -> CmdAction { + let mut action = action_none; + match cmd { + ~"exit" => repl.running = false, + ~"clear" => { + repl.program.clear(); + + // XXX: Win32 version of linenoise can't do this + //rl::clear(); + } + ~"help" => { + println( + ":{\\n ..lines.. \\n:}\\n - execute multiline command\n\ + :load <crate> ... - loads given crates as dynamic libraries\n\ + :clear - clear the bindings\n\ + :exit - exit from the repl\n\ + :help - show this message"); + } + ~"load" => { + let mut loaded_crates: ~[~str] = ~[]; + for args.iter().advance |arg| { + let (crate, filename) = + if arg.ends_with(".rs") || arg.ends_with(".rc") { + (arg.slice_to(arg.len() - 3).to_owned(), copy *arg) + } else { + (copy *arg, *arg + ".rs") + }; + match compile_crate(filename, copy repl.binary) { + Some(_) => loaded_crates.push(crate), + None => { } + } + } + for loaded_crates.iter().advance |crate| { + let crate_path = Path(*crate); + let crate_dir = crate_path.dirname(); + repl.program.record_extern(fmt!("extern mod %s;", *crate)); + if !repl.lib_search_paths.iter().any_(|x| x == &crate_dir) { + repl.lib_search_paths.push(crate_dir); + } + } + if loaded_crates.is_empty() { + println("no crates loaded"); + } else { + println(fmt!("crates loaded: %s", + loaded_crates.connect(", "))); + } + } + ~"{" => { + let mut multiline_cmd = ~""; + let mut end_multiline = false; + while (!end_multiline) { + match get_line(use_rl, "rusti| ") { + None => fail!("unterminated multiline command :{ .. :}"), + Some(line) => { + if line.trim() == ":}" { + end_multiline = true; + } else { + multiline_cmd.push_str(line); + multiline_cmd.push_char('\n'); + } + } + } + } + action = action_run_line(multiline_cmd); + } + _ => println(~"unknown cmd: " + cmd) + } + return action; +} + +/// Executes a line of input, which may either be rust code or a +/// :command. Returns a new Repl if it has changed. +pub fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str, + use_rl: bool) + -> Option<Repl> { + if line.starts_with(":") { + // drop the : and the \n (one byte each) + let full = line.slice(1, line.len()); + let split: ~[~str] = full.word_iter().transform(|s| s.to_owned()).collect(); + let len = split.len(); + + if len > 0 { + let cmd = copy split[0]; + + if !cmd.is_empty() { + let args = if len > 1 { + split.slice(1, len).to_owned() + } else { ~[] }; + + match run_cmd(repl, in, out, cmd, args, use_rl) { + action_none => { } + action_run_line(multiline_cmd) => { + if !multiline_cmd.is_empty() { + return run_line(repl, in, out, multiline_cmd, use_rl); + } + } + } + return None; + } + } + } + + let line = Cell::new(line); + let r = Cell::new(copy *repl); + let result = do task::try { + run(r.take(), line.take()) + }; + + if result.is_ok() { + return Some(result.get()); + } + return None; +} + +pub fn main() { + let args = os::args(); + let in = io::stdin(); + let out = io::stdout(); + let mut repl = Repl { + prompt: ~"rusti> ", + binary: copy args[0], + running: true, + lib_search_paths: ~[], + + program: Program::new(), + }; + + let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0; + + // only print this stuff if the user is actually typing into rusti + if istty { + println("WARNING: The Rust REPL is experimental and may be"); + println("unstable. If you encounter problems, please use the"); + println("compiler instead. Type :help for help."); + + unsafe { + do rl::complete |line, suggest| { + if line.starts_with(":") { + suggest(~":clear"); + suggest(~":exit"); + suggest(~":help"); + suggest(~":load"); + } + } + } + } + + while repl.running { + match get_line(istty, repl.prompt) { + None => break, + Some(line) => { + if line.is_empty() { + if istty { + println("()"); + } + loop; + } + match run_line(&mut repl, in, out, line, istty) { + Some(new_repl) => repl = new_repl, + None => { } + } + } + } + } +} + +//#[cfg(test)] +#[cfg(ignore)] // FIXME #7541 doesn't work under cross-compile +mod tests { + use std::io; + use std::iterator::IteratorUtil; + use program::Program; + use super::*; + + fn repl() -> Repl { + Repl { + prompt: ~"rusti> ", + binary: ~"rusti", + running: true, + lib_search_paths: ~[], + program: Program::new(), + } + } + + // FIXME: #7220 rusti on 32bit mac doesn't work. + #[cfg(not(target_word_size="32"))] + #[cfg(not(target_os="macos"))] + fn run_program(prog: &str) { + let mut r = repl(); + for prog.split_iter('\n').advance |cmd| { + let result = run_line(&mut r, io::stdin(), io::stdout(), + cmd.to_owned(), false); + r = result.expect(fmt!("the command '%s' failed", cmd)); + } + } + #[cfg(target_word_size="32", target_os="macos")] + fn run_program(_: &str) {} + + #[test] + fn super_basic() { + run_program(""); + } + + #[test] + fn regression_5937() { + run_program("use std::hashmap;"); + } + + #[test] + fn regression_5784() { + run_program("let a = 3;"); + } + + #[test] #[ignore] + fn new_tasks() { + // XXX: can't spawn new tasks because the JIT code is cleaned up + // after the main function is done. + run_program(" + spawn( || println(\"Please don't segfault\") ); + do spawn { println(\"Please?\"); } + "); + } + + #[test] + fn inferred_integers_usable() { + run_program("let a = 2;\n()\n"); + run_program(" + let a = 3; + let b = 4u; + assert!((a as uint) + b == 7) + "); + } + + #[test] + fn local_variables_allow_shadowing() { + run_program(" + let a = 3; + let a = 5; + assert!(a == 5) + "); + } + + #[test] + fn string_usable() { + run_program(" + let a = ~\"\"; + let b = \"\"; + let c = @\"\"; + let d = a + b + c; + assert!(d.len() == 0); + "); + } + + #[test] + fn vectors_usable() { + run_program(" + let a = ~[1, 2, 3]; + let b = &[1, 2, 3]; + let c = @[1, 2, 3]; + let d = a + b + c; + assert!(d.len() == 9); + let e: &[int] = []; + "); + } + + #[test] + fn structs_usable() { + run_program(" + struct A{ a: int } + let b = A{ a: 3 }; + assert!(b.a == 3) + "); + } + + #[test] + fn mutable_variables_work() { + run_program(" + let mut a = 3; + a = 5; + let mut b = std::hashmap::HashSet::new::<int>(); + b.insert(a); + assert!(b.contains(&5)) + assert!(b.len() == 1) + "); + } + + #[test] + fn functions_saved() { + run_program(" + fn fib(x: int) -> int { if x < 2 {x} else { fib(x - 1) + fib(x - 2) } } + let a = fib(3); + let a = a + fib(4); + assert!(a == 5) + "); + } + + #[test] + fn modules_saved() { + run_program(" + mod b { pub fn foo() -> uint { 3 } } + assert!(b::foo() == 3) + "); + } + + #[test] + fn multiple_functions() { + run_program(" + fn f() {} + fn f() {} + f() + "); + } + + #[test] + fn multiple_items_same_name() { + run_program(" + fn f() {} + mod f {} + struct f; + enum f {} + fn f() {} + f() + "); + + debug!("simultaneous definitions + expressions are allowed"); + run_program(" + let a = 3; a as u8 + "); + } + + #[test] + fn exit_quits() { + let mut r = repl(); + assert!(r.running); + let result = run_line(&mut r, io::stdin(), io::stdout(), + ~":exit", false); + assert!(result.is_none()); + assert!(!r.running); + } +} diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs new file mode 100644 index 00000000000..c36c6390a75 --- /dev/null +++ b/src/librustpkg/api.rs @@ -0,0 +1,92 @@ +// 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. + +use context::*; +use crate::*; +use package_id::*; +use package_source::*; +use version::Version; + +use std::option::*; +use std::os; +use std::hashmap::*; +use std::path::*; + +/// Convenience functions intended for calling from pkg.rs + +fn default_ctxt(p: @Path) -> Ctx { + Ctx { sysroot_opt: Some(p), json: false, dep_cache: @mut HashMap::new() } +} + +pub fn build_lib(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Version, + lib: Path) { + + let pkg_src = PkgSrc { + root: root, + dst_dir: dest, + id: PkgId{ version: version, ..PkgId::new(name)}, + libs: ~[mk_crate(lib)], + mains: ~[], + tests: ~[], + benchs: ~[] + }; + pkg_src.build(&default_ctxt(sysroot), pkg_src.dst_dir, ~[]); +} + +pub fn build_exe(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Version, + main: Path) { + let pkg_src = PkgSrc { + root: root, + dst_dir: dest, + id: PkgId{ version: version, ..PkgId::new(name)}, + libs: ~[], + mains: ~[mk_crate(main)], + tests: ~[], + benchs: ~[] + }; + pkg_src.build(&default_ctxt(sysroot), pkg_src.dst_dir, ~[]); + +} + +pub fn install_lib(sysroot: @Path, + workspace: Path, + name: ~str, + lib_path: Path, + version: Version) { + debug!("self_exe: %?", os::self_exe_path()); + debug!("sysroot = %s", sysroot.to_str()); + debug!("workspace = %s", workspace.to_str()); + // make a PkgSrc + let pkg_id = PkgId{ version: version, ..PkgId::new(name)}; + let build_dir = workspace.push("build"); + let dst_dir = build_dir.push_rel(&*pkg_id.local_path); + let pkg_src = PkgSrc { + root: copy workspace, + dst_dir: copy dst_dir, + id: copy pkg_id, + libs: ~[mk_crate(lib_path)], + mains: ~[], + tests: ~[], + benchs: ~[] + }; + let cx = default_ctxt(sysroot); + pkg_src.build(&cx, dst_dir, ~[]); + cx.install_no_build(&workspace, &pkg_id); +} + +pub fn install_exe(sysroot: @Path, workspace: Path, name: ~str, version: Version) { + default_ctxt(sysroot).install(&workspace, &PkgId{ version: version, + ..PkgId::new(name)}); + +} + +fn mk_crate(p: Path) -> Crate { + Crate { file: p, flags: ~[], cfgs: ~[] } +} diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs index caab16cd291..c44563d8703 100644 --- a/src/librustpkg/conditions.rs +++ b/src/librustpkg/conditions.rs @@ -10,7 +10,7 @@ // Useful conditions -pub use core::path::Path; +pub use std::path::Path; pub use package_id::PkgId; condition! { diff --git a/src/librustpkg/context.rs b/src/librustpkg/context.rs index 4f67118e520..230a0f915ac 100644 --- a/src/librustpkg/context.rs +++ b/src/librustpkg/context.rs @@ -10,9 +10,8 @@ // Context data structure used by rustpkg -use core::prelude::*; -use core::hashmap::HashMap; +use std::hashmap::HashMap; pub struct Ctx { // Sysroot -- if this is None, uses rustc filesearch's diff --git a/src/librustpkg/crate.rs b/src/librustpkg/crate.rs index 5e8139063de..5fe45126032 100644 --- a/src/librustpkg/crate.rs +++ b/src/librustpkg/crate.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::path::Path; -use core::vec; +use std::path::Path; +use std::vec; /// A crate is a unit of Rust code to be compiled into a binary or library pub struct Crate { diff --git a/src/librustpkg/messages.rs b/src/librustpkg/messages.rs index d3962470e7c..43d727c2989 100644 --- a/src/librustpkg/messages.rs +++ b/src/librustpkg/messages.rs @@ -9,22 +9,22 @@ // except according to those terms. use extra::term; -use core::io; -use core::result::*; +use std::io; +use std::result::*; pub fn note(msg: &str) { - pretty_message(msg, "note: ", term::color_green, io::stdout()) + pretty_message(msg, "note: ", term::color::green, io::stdout()) } pub fn warn(msg: &str) { - pretty_message(msg, "warning: ", term::color_yellow, io::stdout()) + pretty_message(msg, "warning: ", term::color::yellow, io::stdout()) } pub fn error(msg: &str) { - pretty_message(msg, "error: ", term::color_red, io::stdout()) + pretty_message(msg, "error: ", term::color::red, io::stdout()) } -fn pretty_message<'a>(msg: &'a str, prefix: &'a str, color: u8, out: @io::Writer) { +fn pretty_message<'a>(msg: &'a str, prefix: &'a str, color: term::color::Color, out: @io::Writer) { let term = term::Terminal::new(out); match term { Ok(ref t) => { diff --git a/src/librustpkg/package_id.rs b/src/librustpkg/package_id.rs index 3ff0a6073b6..ebe2aa6f92a 100644 --- a/src/librustpkg/package_id.rs +++ b/src/librustpkg/package_id.rs @@ -9,7 +9,6 @@ // except according to those terms. pub use package_path::{RemotePath, LocalPath, normalize, hash}; -use core::prelude::*; use version::{try_getting_version, Version, NoVersion, split_version}; /// Path-fragment identifier of a package such as diff --git a/src/librustpkg/package_path.rs b/src/librustpkg/package_path.rs index 161634be650..a508d2ce153 100644 --- a/src/librustpkg/package_path.rs +++ b/src/librustpkg/package_path.rs @@ -10,11 +10,11 @@ // rustpkg utilities having to do with local and remote paths -use core::path::Path; -use core::option::Some; -use core::hash; -use core::rt::io::Writer; -use core::hash::Streaming; +use std::path::Path; +use std::option::Some; +use std::hash; +use std::rt::io::Writer; +use std::hash::Streaming; /// Wrappers to prevent local and remote paths from getting confused /// (These will go away after #6407) diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index 01cc48fc037..24c1bb9b200 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -10,9 +10,9 @@ use target::*; use package_id::PkgId; -use core::path::Path; -use core::option::*; -use core::{os, run, str, vec}; +use std::path::Path; +use std::option::*; +use std::{os, run, str}; use context::*; use crate::Crate; use messages::*; @@ -60,9 +60,9 @@ impl PkgSrc { let dir; let dirs = pkgid_src_in_workspace(&self.id, &self.root); debug!("Checking dirs: %?", dirs); - let path = dirs.find(|d| os::path_exists(d)); + let path = dirs.iter().find_(|&d| os::path_exists(d)); match path { - Some(d) => dir = d, + Some(d) => dir = copy *d, None => dir = match self.fetch_git() { None => cond.raise((copy self.id, ~"supplied path for package dir does not \ exist, and couldn't interpret it as a URL fragment")), @@ -146,8 +146,7 @@ impl PkgSrc { fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) { assert!(p.components.len() > prefix); let mut sub = Path(""); - for vec::slice(p.components, prefix, - p.components.len()).each |c| { + for p.components.slice(prefix, p.components.len()).iter().advance |c| { sub = sub.push(*c); } debug!("found crate %s", sub.to_str()); @@ -204,7 +203,7 @@ impl PkgSrc { crates: &[Crate], cfgs: &[~str], what: OutputType) { - for crates.each |&crate| { + for crates.iter().advance |&crate| { let path = &src_dir.push_rel(&crate.file).normalize(); note(fmt!("build_crates: compiling %s", path.to_str())); note(fmt!("build_crates: destination dir is %s", dst_dir.to_str())); diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index e68f48c8162..6371d726346 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -10,23 +10,50 @@ // rustpkg utilities having to do with paths and directories -use core::prelude::*; pub use package_path::{RemotePath, LocalPath, normalize}; pub use package_id::PkgId; pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install}; pub use version::{Version, NoVersion, split_version_general}; -use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; -use core::os::mkdir_recursive; -use core::os; -use core::iterator::IteratorUtil; +use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; +use std::os::mkdir_recursive; +use std::os; +use std::iterator::IteratorUtil; use messages::*; use package_id::*; +fn push_if_exists(vec: &mut ~[Path], p: &Path) { + let maybe_dir = p.push(".rust"); + if os::path_exists(&maybe_dir) { + vec.push(maybe_dir); + } +} + +#[cfg(windows)] +static path_entry_separator: &'static str = ";"; +#[cfg(not(windows))] +static path_entry_separator: &'static str = ":"; + /// Returns the value of RUST_PATH, as a list -/// of Paths. In general this should be read from the -/// environment; for now, it's hard-wired to just be "." +/// of Paths. Includes default entries for, if they exist: +/// $HOME/.rust +/// DIR/.rust for any DIR that's the current working directory +/// or an ancestor of it pub fn rust_path() -> ~[Path] { - ~[Path(".")] + let mut env_rust_path: ~[Path] = match os::getenv("RUST_PATH") { + Some(env_path) => { + let env_path_components: ~[&str] = + env_path.split_str_iter(path_entry_separator).collect(); + env_path_components.map(|&s| Path(s)) + } + None => ~[] + }; + let cwd = os::getcwd(); + // now add in default entries + env_rust_path.push(copy cwd); + do cwd.each_parent() |p| { push_if_exists(&mut env_rust_path, p) }; + let h = os::homedir(); + for h.iter().advance |h| { push_if_exists(&mut env_rust_path, h); } + env_rust_path } pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; @@ -43,7 +70,8 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, u_rwx) } /// pkgid's short name pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { let src_dir = workspace.push("src"); - for os::list_dir(&src_dir).each |&p| { + let dirs = os::list_dir(&src_dir); + for dirs.iter().advance |&p| { let p = Path(p); debug!("=> p = %s", p.to_str()); if !os::path_is_dir(&src_dir.push_rel(&p)) { @@ -93,7 +121,7 @@ pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> ~[Path] { /// Returns a src for pkgid that does exist -- None if none of them do pub fn first_pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { let rs = pkgid_src_in_workspace(pkgid, workspace); - for rs.each |p| { + for rs.iter().advance |p| { if os::path_exists(p) { return Some(copy *p); } @@ -189,7 +217,7 @@ pub fn library_in_workspace(path: &LocalPath, short_name: &str, where: Target, debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype); let mut result_filename = None; - for dir_contents.each |&p| { + for dir_contents.iter().advance |&p| { let mut which = 0; let mut hash = None; let p_path = Path(p); diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rs index 9242e450e24..8ca8ae1b1ed 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rs @@ -11,26 +11,26 @@ // rustpkg - a package manager and build system for Rust #[link(name = "rustpkg", - vers = "0.7-pre", + vers = "0.7", uuid = "25de5e6e-279e-4a20-845c-4cabae92daaf", url = "https://github.com/mozilla/rust/tree/master/src/librustpkg")]; #[license = "MIT/ASL2"]; #[crate_type = "lib"]; -#[no_core]; -#[no_std]; - -extern mod core(name = "std"); -extern mod extra(name = "extra"); - +extern mod extra; extern mod rustc; extern mod syntax; -use core::prelude::*; -use core::*; -pub use core::path::Path; -use core::hashmap::HashMap; +use std::result; +use std::io; +use std::os; +use std::run; +use std::str; + +pub use std::path::Path; +use std::hashmap::HashMap; + use rustc::driver::{driver, session}; use rustc::metadata::filesearch; use extra::{getopts}; @@ -46,6 +46,7 @@ use context::Ctx; use package_id::PkgId; use package_source::PkgSrc; +pub mod api; mod conditions; mod context; mod crate; @@ -64,15 +65,6 @@ mod workspace; pub mod usage; -mod std { - pub use core::cmp; - pub use core::condition; - pub use core::os; - pub use core::str; - pub use core::sys; - pub use core::unstable; -} - /// A PkgScript represents user-supplied custom logic for /// special build hooks. This only exists for packages with /// an explicit package script. @@ -104,8 +96,10 @@ impl<'self> PkgScript<'self> { let binary = os::args()[0].to_managed(); // Build the rustc session data structures to pass // to the compiler + debug!("pkgscript parse: %?", os::self_exe_path()); let options = @session::options { binary: binary, + maybe_sysroot: Some(@os::self_exe_path().get().pop()), crate_type: session::bin_crate, .. copy *session::basic_options() }; @@ -132,8 +126,7 @@ impl<'self> PkgScript<'self> { /// Returns a pair of an exit code and list of configs (obtained by /// calling the package script's configs() function if it exists // FIXME (#4432): Use workcache to only compile the script when changed - fn run_custom(&self, what: ~str) -> (~[~str], ExitCode) { - debug!("run_custom: %s", what); + fn run_custom(&self, sysroot: @Path) -> (~[~str], ExitCode) { let sess = self.sess; debug!("Working directory = %s", self.build_dir.to_str()); @@ -152,9 +145,12 @@ impl<'self> PkgScript<'self> { sess, crate, driver::build_configuration(sess, - binary, &self.input)); - debug!("Running program: %s %s %s", exe.to_str(), root.to_str(), what); - let status = run::process_status(exe.to_str(), [root.to_str(), what]); + binary, &self.input), + driver::cu_parse); + debug!("Running program: %s %s %s %s", exe.to_str(), + sysroot.to_str(), root.to_str(), "install"); + // FIXME #7401 should support commands besides `install` + let status = run::process_status(exe.to_str(), [sysroot.to_str(), ~"install"]); if status != 0 { return (~[], status); } @@ -180,7 +176,21 @@ impl<'self> PkgScript<'self> { } -impl Ctx { +pub trait CtxMethods { + fn run(&self, cmd: &str, args: ~[~str]); + fn do_cmd(&self, _cmd: &str, _pkgname: &str); + fn build(&self, workspace: &Path, pkgid: &PkgId); + fn clean(&self, workspace: &Path, id: &PkgId); + fn info(&self); + fn install(&self, workspace: &Path, id: &PkgId); + fn install_no_build(&self, workspace: &Path, id: &PkgId); + fn prefer(&self, _id: &str, _vers: Option<~str>); + fn test(&self); + fn uninstall(&self, _id: &str, _vers: Option<~str>); + fn unprefer(&self, _id: &str, _vers: Option<~str>); +} + +impl CtxMethods for Ctx { fn run(&self, cmd: &str, args: ~[~str]) { match cmd { @@ -291,10 +301,8 @@ impl Ctx { let pscript = PkgScript::parse(package_script_path, workspace, pkgid); - // Limited right now -- we're only running the post_build - // hook and probably fail otherwise - // also post_build should be called pre_build - let (cfgs, hook_result) = pscript.run_custom(~"post_build"); + let sysroot = self.sysroot_opt.expect("custom build needs a sysroot"); + let (cfgs, hook_result) = pscript.run_custom(sysroot); debug!("Command return code = %?", hook_result); if hook_result != 0 { fail!("Error running custom build command") @@ -341,13 +349,17 @@ impl Ctx { } fn install(&self, workspace: &Path, id: &PkgId) { - use conditions::copy_failed::cond; - - // Should use RUST_PATH in the future. + // FIXME #7402: Use RUST_PATH to determine target dir // Also should use workcache to not build if not necessary. self.build(workspace, id); debug!("install: workspace = %s, id = %s", workspace.to_str(), id.to_str()); + self.install_no_build(workspace, id); + + } + + fn install_no_build(&self, workspace: &Path, id: &PkgId) { + use conditions::copy_failed::cond; // Now copy stuff into the install dirs let maybe_executable = built_executable_in_workspace(id, workspace); diff --git a/src/librustpkg/search.rs b/src/librustpkg/search.rs index e5ffc5c9d84..d04b2c8f370 100644 --- a/src/librustpkg/search.rs +++ b/src/librustpkg/search.rs @@ -9,7 +9,6 @@ // except according to those terms. use path_util::installed_library_in_workspace; -use core::prelude::*; /// If a library with path `p` matching pkg_id's name exists under sroot_opt, /// return Some(p). Return None if there's no such path or if sroot_opt is None. diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 8b915873269..4acc621e7be 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -11,11 +11,10 @@ // rustpkg unit tests use context::Ctx; -use core::hashmap::HashMap; -use core::{io, libc, os, result, run, str}; -use core::prelude::*; +use std::hashmap::HashMap; +use std::{io, libc, os, result, run, str, vec}; use extra::tempfile::mkdtemp; -use core::run::ProcessOutput; +use std::run::ProcessOutput; use package_path::*; use package_id::{PkgId}; use package_source::*; @@ -25,7 +24,7 @@ use path_util::{target_executable_in_workspace, target_library_in_workspace, make_dir_rwx, u_rwx, library_in_workspace, built_bench_in_workspace, built_test_in_workspace, built_library_in_workspace, built_executable_in_workspace, - installed_library_in_workspace}; + installed_library_in_workspace, rust_path}; use target::*; /// Returns the last-modified date as an Option @@ -110,7 +109,7 @@ fn mk_temp_workspace(short_name: &LocalPath, version: &Version) -> Path { } fn is_rwx(p: &Path) -> bool { - use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; + use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; match p.get_mode() { None => return false, @@ -144,10 +143,10 @@ fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput { err_fd: None }); let output = prog.finish_with_output(); - io::println(fmt!("Output from command %s with args %? was %s {%s}[%?]", + debug!("Output from command %s with args %? was %s {%s}[%?]", cmd, args, str::from_bytes(output.output), str::from_bytes(output.error), - output.status)); + output.status); /* By the way, rustpkg *won't* return a nonzero exit code if it fails -- see #4547 @@ -248,7 +247,7 @@ fn command_line_test_output(args: &[~str]) -> ~[~str] { let p_output = command_line_test(args, &os::getcwd()); let test_output = str::from_bytes(p_output.output); for test_output.split_iter('\n').advance |s| { - result += [s.to_owned()]; + result.push(s.to_owned()); } result } @@ -268,12 +267,12 @@ fn output_file_name(workspace: &Path, short_name: &str) -> Path { workspace.push(fmt!("%s%s", short_name, os::EXE_SUFFIX)) } -fn touch_source_file(workspace: &Path, short_name: &str) { +fn touch_source_file(workspace: &Path, pkgid: &PkgId) { use conditions::bad_path::cond; - let pkg_src_dir = workspace.push("src").push(short_name); - let contents = os::list_dir(&pkg_src_dir); - for contents.each() |p| { - if Path(copy *p).filetype() == Some(~".rs") { + let pkg_src_dir = workspace.push("src").push(pkgid.to_str()); + let contents = os::list_dir_path(&pkg_src_dir); + for contents.iter().advance |p| { + if p.filetype() == Some(~".rs") { // should be able to do this w/o a process if run::process_output("touch", [p.to_str()]).status != 0 { let _ = cond.raise((copy pkg_src_dir, ~"Bad path")); @@ -287,20 +286,19 @@ fn touch_source_file(workspace: &Path, short_name: &str) { fn frob_source_file(workspace: &Path, pkgid: &PkgId) { use conditions::bad_path::cond; let pkg_src_dir = workspace.push("src").push(pkgid.to_str()); - let contents = os::list_dir(&pkg_src_dir); + let contents = os::list_dir_path(&pkg_src_dir); let mut maybe_p = None; - for contents.each() |p| { - if Path(copy *p).filetype() == Some(~".rs") { + for contents.iter().advance |p| { + if p.filetype() == Some(~".rs") { maybe_p = Some(p); break; } } match maybe_p { Some(p) => { - let p = Path(copy *p); - let w = io::buffered_file_writer(&p); + let w = io::file_writer(*p, &[io::Append]); match w { - Err(s) => { let _ = cond.raise((p, fmt!("Bad path: %s", s))); } + Err(s) => { let _ = cond.raise((copy **p, fmt!("Bad path: %s", s))); } Ok(w) => w.write_line("") } } @@ -309,18 +307,10 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId) { } } -#[test] #[ignore] //FIXME(#7249) -fn test_all() { - // FIXME(#7071): these tests use rustc, so they can't be run in parallel - // until this issue is resolved - test_make_dir_rwx(); - test_install_valid(); - test_install_invalid(); - test_install_url(); - test_package_ids_must_be_relative_path_like(); - test_package_version(); -} +// FIXME(#7249): these tests fail on multi-platform builds, so for now they're +// only run one x86 +#[test] #[ignore(cfg(target_arch = "x86"))] fn test_make_dir_rwx() { let temp = &os::tmpdir(); let dir = temp.push("quux"); @@ -333,6 +323,7 @@ fn test_make_dir_rwx() { assert!(os::remove_dir_recursive(&dir)); } +#[test] #[ignore(cfg(target_arch = "x86"))] fn test_install_valid() { use path_util::installed_library_in_workspace; @@ -362,6 +353,7 @@ fn test_install_valid() { assert!(!os::path_exists(&bench)); } +#[test] #[ignore(cfg(target_arch = "x86"))] fn test_install_invalid() { use conditions::nonexistent_package::cond; use cond1 = conditions::missing_pkg_files::cond; @@ -384,6 +376,7 @@ fn test_install_invalid() { assert!(error_occurred && error1_occurred); } +#[test] #[ignore(cfg(target_arch = "x86"))] fn test_install_url() { let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); let sysroot = test_sysroot(); @@ -419,6 +412,7 @@ fn test_install_url() { assert!(!os::path_exists(&bench)); } +#[test] #[ignore(cfg(target_arch = "x86"))] fn test_package_ids_must_be_relative_path_like() { use conditions::bad_pkg_id::cond; @@ -459,6 +453,7 @@ fn test_package_ids_must_be_relative_path_like() { } +#[test] #[ignore(cfg(target_arch = "x86"))] fn test_package_version() { let temp_pkg_id = PkgId::new("github.com/catamorphism/test_pkg_version"); match temp_pkg_id.version { @@ -481,9 +476,8 @@ fn test_package_version() { push("test_pkg_version"))); } -// FIXME #7006: Fails on linux for some reason -#[test] -#[ignore] +// FIXME #7006: Fails on linux/mac for some reason +#[test] #[ignore] fn test_package_request_version() { let temp_pkg_id = PkgId::new("github.com/catamorphism/test_pkg_version#0.3"); let temp = mk_empty_workspace(&LocalPath(Path("test_pkg_version")), &ExactRevision(~"0.3")); @@ -547,13 +541,75 @@ fn rustpkg_local_pkg() { } #[test] -#[ignore (reason = "RUST_PATH not yet implemented -- #5682")] +#[ignore] // XXX Failing on dist-linux bot +fn package_script_with_default_build() { + let dir = create_local_package(&PkgId::new("fancy-lib")); + debug!("dir = %s", dir.to_str()); + let source = test_sysroot().pop().pop().pop().push("src").push("librustpkg"). + push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs"); + debug!("package_script_with_default_build: %s", source.to_str()); + if !os::copy_file(&source, + & dir.push("src").push("fancy_lib-0.1").push("pkg.rs")) { + fail!("Couldn't copy file"); + } + command_line_test([~"install", ~"fancy-lib"], &dir); + assert_lib_exists(&dir, "fancy-lib"); + assert!(os::path_exists(&dir.push("build").push("fancy_lib").push("generated.rs"))); +} + +#[test] +#[ignore (reason = "Un-ignore when #7071 is fixed")] fn rust_path_test() { - let dir = mk_workspace(&Path("/home/more_rust"), - &normalize(RemotePath(Path("foo"))), - &NoVersion); - // command_line_test("RUST_PATH=/home/rust:/home/more_rust rustpkg install foo"); - command_line_test([~"install", ~"foo"], &dir); + let dir_for_path = mkdtemp(&os::tmpdir(), "more_rust").expect("rust_path_test failed"); + let dir = mk_workspace(&dir_for_path, &normalize(RemotePath(Path("foo"))), &NoVersion); + debug!("dir = %s", dir.to_str()); + writeFile(&Path("/Users/tjc/more_rust/src/foo-0.1/main.rs"), + "fn main() { let _x = (); }"); + + let cwd = os::getcwd(); + debug!("cwd = %s", cwd.to_str()); + let mut prog = run::Process::new("rustpkg", + [~"install", ~"foo"], + run::ProcessOptions { env: Some(&[(~"RUST_PATH", + dir_for_path.to_str())]), + dir: Some(&cwd), + in_fd: None, + out_fd: None, + err_fd: None + }); + prog.finish_with_output(); + assert_executable_exists(&dir_for_path, "foo"); +} + +#[test] +fn rust_path_contents() { + let dir = mkdtemp(&os::tmpdir(), "rust_path").expect("rust_path_contents failed"); + let abc = &dir.push("A").push("B").push("C"); + assert!(os::mkdir_recursive(&abc.push(".rust"), u_rwx)); + assert!(os::mkdir_recursive(&abc.pop().push(".rust"), u_rwx)); + assert!(os::mkdir_recursive(&abc.pop().pop().push(".rust"), u_rwx)); + assert!(do os::change_dir_locked(&dir.push("A").push("B").push("C")) { + let p = rust_path(); + let cwd = os::getcwd().push(".rust"); + let parent = cwd.pop().pop().push(".rust"); + let grandparent = cwd.pop().pop().pop().push(".rust"); + assert!(p.contains(&cwd)); + assert!(p.contains(&parent)); + assert!(p.contains(&grandparent)); + for p.iter().advance() |a_path| { + assert!(!a_path.components.is_empty()); + } + }); +} + +#[test] +fn rust_path_parse() { + os::setenv("RUST_PATH", "/a/b/c:/d/e/f:/g/h/i"); + let paths = rust_path(); + assert!(paths.contains(&Path("/g/h/i"))); + assert!(paths.contains(&Path("/d/e/f"))); + assert!(paths.contains(&Path("/a/b/c"))); + os::unsetenv("RUST_PATH"); } #[test] @@ -570,14 +626,14 @@ fn install_remove() { command_line_test([~"install", ~"bar"], &dir); command_line_test([~"install", ~"quux"], &dir); let list_output = command_line_test_output([~"list"]); - assert!(list_output.contains(&~"foo")); - assert!(list_output.contains(&~"bar")); - assert!(list_output.contains(&~"quux")); + assert!(list_output.iter().any_(|x| x == &~"foo")); + assert!(list_output.iter().any_(|x| x == &~"bar")); + assert!(list_output.iter().any_(|x| x == &~"quux")); command_line_test([~"remove", ~"foo"], &dir); let list_output = command_line_test_output([~"list"]); - assert!(!list_output.contains(&~"foo")); - assert!(list_output.contains(&~"bar")); - assert!(list_output.contains(&~"quux")); + assert!(!list_output.iter().any_(|x| x == &~"foo")); + assert!(list_output.iter().any_(|x| x == &~"bar")); + assert!(list_output.iter().any_(|x| x == &~"quux")); } #[test] @@ -615,7 +671,7 @@ fn do_rebuild_dep_dates_change() { let workspace = create_local_package_with_dep(&p_id, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar")); - touch_source_file(&workspace, "bar"); + touch_source_file(&workspace, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let new_bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar")); assert!(new_bar_date > bar_date); @@ -643,7 +699,7 @@ fn test_versions() { command_line_test([~"install", ~"foo#0.1"], &workspace); let output = command_line_test_output([~"list"]); // make sure output includes versions - assert!(!output.contains(&~"foo#0.2")); + assert!(!output.iter().any_(|x| x == &~"foo#0.2")); } #[test] diff --git a/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs b/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs index c9c1f00fb08..0fd68ca3a20 100644 --- a/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs +++ b/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs @@ -15,7 +15,7 @@ The test runner should check that, after `rustpkg build hello-world`: * testsuite/hello-world/build/ does not contain a library */ -use core::io; +use std::io; fn main() { io::println(~"Hello world!"); diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/fancy-lib.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/lib.rs index dc068eed143..dc068eed143 100644 --- a/src/librustpkg/testsuite/pass/src/fancy-lib/fancy-lib.rs +++ b/src/librustpkg/testsuite/pass/src/fancy-lib/lib.rs diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs index 2d3a75d9197..009f37c8a49 100644 --- a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs @@ -8,12 +8,37 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::run; +extern mod rustpkg; +extern mod rustc; + +use std::{io, os}; +use rustpkg::api; +use rustpkg::version::NoVersion; + +use rustc::metadata::filesearch; pub fn main() { - use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; + use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; + let args = os::args(); + +// by convention, first arg is sysroot + if args.len() < 2 { + fail!("Package script requires a directory where rustc libraries live as the first \ + argument"); + } + + let sysroot_arg = copy args[1]; + let sysroot = Path(sysroot_arg); + if !os::path_exists(&sysroot) { + fail!("Package script requires a sysroot that exists; %s doesn't", sysroot.to_str()); + } + + if args[2] != ~"install" { + io::println(fmt!("Warning: I don't know how to %s", args[2])); + return; + } - let out_path = Path(~"build/fancy_lib"); + let out_path = Path("build/fancy_lib"); if !os::path_exists(&out_path) { assert!(os::make_dir(&out_path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); } @@ -22,7 +47,10 @@ pub fn main() { [io::Create]).get(); file.write_str("pub fn wheeeee() { for [1, 2, 3].each() |_| { assert!(true); } }"); - // now compile the crate itself - run::process_status("rustc", [~"src/fancy-lib/fancy-lib.rs", ~"--lib", ~"-o", - out_path.push(~"fancy_lib").to_str()]); + + debug!("api_____install_____lib, my sysroot:"); + debug!(sysroot.to_str()); + + api::install_lib(@sysroot, os::getcwd(), ~"fancy-lib", Path("lib.rs"), + NoVersion); } \ No newline at end of file diff --git a/src/librustpkg/testsuite/pass/src/hello-world/main.rs b/src/librustpkg/testsuite/pass/src/hello-world/main.rs index 2ef387d9620..c8b2ce97c0c 100644 --- a/src/librustpkg/testsuite/pass/src/hello-world/main.rs +++ b/src/librustpkg/testsuite/pass/src/hello-world/main.rs @@ -18,7 +18,7 @@ The test runner should check that, after `rustpkg build hello-world`: * testsuite/pass/hello-world/build is empty */ -use core::io; +use std::io; fn main() { io::println(~"Hello world!"); diff --git a/src/librustpkg/usage.rs b/src/librustpkg/usage.rs index 90c87210faa..fee52c3c11f 100644 --- a/src/librustpkg/usage.rs +++ b/src/librustpkg/usage.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::io; +use std::io; pub fn general() { io::println("Usage: rustpkg [options] <cmd> [args..] diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 60fe7d52321..26e26add3dc 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; -use core::{libc, os, result, str}; +use std::{libc, os, result, str}; use rustc::driver::{driver, session}; use rustc::metadata::filesearch; use extra::getopts::groups::getopts; @@ -56,7 +55,7 @@ pub fn root() -> Path { } pub fn is_cmd(cmd: &str) -> bool { - Commands.any(|&c| c == cmd) + Commands.iter().any_(|&c| c == cmd) } struct ListenerFn { @@ -103,10 +102,10 @@ fn fold_item(ctx: @mut ReadyCtx, if attrs.len() > 0 { let mut cmds = ~[]; - for attrs.each |attr| { + for attrs.iter().advance |attr| { match attr.node.value.node { ast::meta_list(_, ref mis) => { - for mis.each |mi| { + for mis.iter().advance |mi| { match mi.node { ast::meta_word(cmd) => cmds.push(cmd.to_owned()), _ => {} @@ -187,7 +186,7 @@ pub fn compile_input(ctxt: &Ctx, Lib => lib_crate, Test | Bench | Main => bin_crate }; - let matches = getopts(~[~"-Z", ~"time-passes"] + let matches = getopts(debug_flags() + match what { Lib => ~[~"--lib"], // --test compiles both #[test] and #[bench] fns @@ -211,7 +210,7 @@ pub fn compile_input(ctxt: &Ctx, let addl_lib_search_paths = @mut options.addl_lib_search_paths; // Make sure all the library directories actually exist, since the linker will complain // otherwise - for addl_lib_search_paths.each() |p| { + for addl_lib_search_paths.iter().advance |p| { assert!(os::path_is_dir(p)); } @@ -257,7 +256,7 @@ pub fn compile_input(ctxt: &Ctx, debug!("calling compile_crate_from_input, out_dir = %s, building_library = %?", out_dir.to_str(), sess.building_library); - compile_crate_from_input(&input, out_dir, sess, crate, copy cfg); + compile_crate_from_input(&input, out_dir, sess, crate, copy cfg, driver::cu_expand); true } @@ -270,7 +269,8 @@ pub fn compile_crate_from_input(input: &driver::input, build_dir: &Path, sess: session::Session, crate: @ast::crate, - cfg: ast::crate_cfg) { + cfg: ast::crate_cfg, + compile_from: driver::compile_phase) { debug!("Calling build_output_filenames with %s, building library? %?", build_dir.to_str(), sess.building_library); @@ -280,14 +280,14 @@ pub fn compile_crate_from_input(input: &driver::input, debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type); debug!("additional libraries:"); - for sess.opts.addl_lib_search_paths.each |lib| { + for sess.opts.addl_lib_search_paths.iter().advance |lib| { debug!("an additional library: %s", lib.to_str()); } driver::compile_rest(sess, cfg, compile_upto { - from: driver::cu_expand, + from: compile_from, to: driver::cu_everything }, Some(outputs), @@ -311,7 +311,7 @@ pub fn compile_crate(ctxt: &Ctx, pkg_id: &PkgId, what: OutputType) -> bool { debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str()); debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str()); - for flags.each |&fl| { + for flags.iter().advance |&fl| { debug!("+++ %s", fl); } compile_input(ctxt, pkg_id, crate, dir, flags, cfgs, opt, what) @@ -331,7 +331,7 @@ pub fn find_and_install_dependencies(ctxt: &Ctx, debug!("In find_and_install_dependencies..."); let my_workspace = copy *workspace; let my_ctxt = copy *ctxt; - for c.each_view_item() |vi: @ast::view_item| { + for c.each_view_item() |vi: &ast::view_item| { debug!("A view item!"); match vi.node { // ignore metadata, I guess @@ -414,3 +414,7 @@ mod test { } } + +// tjc: cheesy +fn debug_flags() -> ~[~str] { ~[] } +// static debug_flags: ~[~str] = ~[~"-Z", ~"time-passes"]; diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs index 7431b5e4c01..1ec15c107c7 100644 --- a/src/librustpkg/version.rs +++ b/src/librustpkg/version.rs @@ -14,8 +14,7 @@ extern mod std; use extra::semver; -use core::prelude::*; -use core::{char, os, result, run, str}; +use std::{char, os, result, run, str}; use package_path::RemotePath; use extra::tempfile::mkdtemp; @@ -155,7 +154,7 @@ fn try_parsing_version(s: &str) -> Option<Version> { /// Just an approximation fn is_url_like(p: &RemotePath) -> bool { let str = p.to_str(); - str.split_iter('/').count() > 2 + str.split_iter('/').len_() > 2 } /// If s is of the form foo#bar, where bar is a valid version @@ -170,7 +169,7 @@ pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Vers for s.split_iter(sep).advance |st| { debug!("whole = %s part = %s", s, st); } - if s.split_iter(sep).count() > 2 { + if s.split_iter(sep).len_() > 2 { return None; } match s.rfind(sep) { @@ -208,4 +207,4 @@ fn test_split_version() { let s = "a#1.2"; assert!(split_version(s) == Some((s.slice(0, 1), ExactRevision(~"1.2")))); assert!(split_version("a#a#3.4") == None); -} \ No newline at end of file +} diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index 54144f8e31f..dd2cf445302 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -12,7 +12,7 @@ use path_util::{rust_path, workspace_contains_package_id}; use package_id::PkgId; -use core::path::Path; +use std::path::Path; pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool { // Using the RUST_PATH, find workspaces that contain @@ -25,7 +25,7 @@ pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> b pkgid.remote_path.to_str(), rust_path().to_str()); } - for workspaces.each |ws| { + for workspaces.iter().advance |ws| { if action(ws) { break; } @@ -36,4 +36,4 @@ pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> b pub fn pkg_parent_workspaces(pkgid: &PkgId) -> ~[Path] { rust_path().filtered(|ws| workspace_contains_package_id(pkgid, ws)) -} \ No newline at end of file +} diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index 18dfbd82c5a..75d0fe7a0b2 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -12,13 +12,13 @@ use cast::transmute; use container::Container; +use iterator::IteratorUtil; use kinds::Copy; -use old_iter; -use old_iter::BaseIter; use option::Option; use sys; use uint; use vec; +use vec::ImmutableVector; /// Code for dealing with @-vectors. This is pretty incomplete, and /// contains a bunch of duplication from the code for ~-vectors. @@ -91,9 +91,9 @@ pub fn build_sized_opt<A>(size: Option<uint>, /// Iterates over the `rhs` vector, copying each element and appending it to the /// `lhs`. Afterwards, the `lhs` is then returned for use again. #[inline] -pub fn append<T:Copy>(lhs: @[T], rhs: &const [T]) -> @[T] { +pub fn append<T:Copy>(lhs: @[T], rhs: &[T]) -> @[T] { do build_sized(lhs.len() + rhs.len()) |push| { - for lhs.each |x| { push(copy *x); } + for lhs.iter().advance |x| { push(copy *x); } for uint::range(0, rhs.len()) |i| { push(copy rhs[i]); } } } @@ -102,7 +102,7 @@ pub fn append<T:Copy>(lhs: @[T], rhs: &const [T]) -> @[T] { /// Apply a function to each element of a vector and return the results pub fn map<T, U>(v: &[T], f: &fn(x: &T) -> U) -> @[U] { do build_sized(v.len()) |push| { - for v.each |elem| { + for v.iter().advance |elem| { push(f(elem)); } } @@ -114,7 +114,7 @@ pub fn map<T, U>(v: &[T], f: &fn(x: &T) -> U) -> @[U] { * Creates an immutable vector of size `n_elts` and initializes the elements * to the value returned by the function `op`. */ -pub fn from_fn<T>(n_elts: uint, op: old_iter::InitOp<T>) -> @[T] { +pub fn from_fn<T>(n_elts: uint, op: &fn(uint) -> T) -> @[T] { do build_sized(n_elts) |push| { let mut i: uint = 0u; while i < n_elts { push(op(i)); i += 1u; } @@ -163,9 +163,9 @@ pub mod traits { use kinds::Copy; use ops::Add; - impl<'self,T:Copy> Add<&'self const [T],@[T]> for @[T] { + impl<'self,T:Copy> Add<&'self [T],@[T]> for @[T] { #[inline] - fn add(&self, rhs: & &'self const [T]) -> @[T] { + fn add(&self, rhs: & &'self [T]) -> @[T] { append(*self, (*rhs)) } } @@ -176,15 +176,16 @@ pub mod traits {} pub mod raw { use at_vec::capacity; + use cast; use cast::{transmute, transmute_copy}; use libc; use ptr; use sys; use uint; - use unstable::intrinsics::{move_val_init}; + use unstable::intrinsics; + use unstable::intrinsics::{move_val_init, TyDesc}; use vec; use vec::UnboxedVecRepr; - use sys::TypeDesc; pub type VecRepr = vec::raw::VecRepr; pub type SliceRepr = vec::raw::SliceRepr; @@ -246,14 +247,16 @@ pub mod raw { // Only make the (slow) call into the runtime if we have to if capacity(*v) < n { let ptr: *mut *mut VecRepr = transmute(v); - let ty = sys::get_type_desc::<T>(); + let ty = intrinsics::get_tydesc::<T>(); + // XXX transmute shouldn't be necessary + let ty = cast::transmute(ty); return reserve_raw(ty, ptr, n); } } // Implementation detail. Shouldn't be public #[allow(missing_doc)] - pub fn reserve_raw(ty: *TypeDesc, ptr: *mut *mut VecRepr, n: uint) { + pub fn reserve_raw(ty: *TyDesc, ptr: *mut *mut VecRepr, n: uint) { unsafe { let size_in_bytes = n * (*ty).size; diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs index e1d2b246dd3..53ea11f2b05 100644 --- a/src/libstd/cell.rs +++ b/src/libstd/cell.rs @@ -22,7 +22,8 @@ A dynamic, mutable location. Similar to a mutable option type, but friendlier. */ -#[mutable] +#[mutable] // XXX remove after snap +#[no_freeze] #[deriving(Clone, DeepClone, Eq)] #[allow(missing_doc)] pub struct Cell<T> { diff --git a/src/libstd/char.rs b/src/libstd/char.rs index 797fd9e8c02..6a9555f4efc 100644 --- a/src/libstd/char.rs +++ b/src/libstd/char.rs @@ -11,12 +11,12 @@ //! Utilities for manipulating the char type use option::{None, Option, Some}; -use str; -use str::{StrSlice, OwnedStr}; -use u32; -use uint; +use int; +use str::StrSlice; use unicode::{derived_property, general_category}; +#[cfg(test)] use str::OwnedStr; + #[cfg(not(test))] use cmp::{Eq, Ord}; #[cfg(not(test))] use num::Zero; @@ -201,21 +201,21 @@ pub fn from_digit(num: uint, radix: uint) -> Option<char> { /// - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN` /// - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN` /// -pub fn escape_unicode(c: char) -> ~str { - let s = u32::to_str_radix(c as u32, 16u); - let (c, pad) = cond!( - (c <= '\xff') { ('x', 2u) } - (c <= '\uffff') { ('u', 4u) } - _ { ('U', 8u) } +pub fn escape_unicode(c: char, f: &fn(char)) { + // avoid calling str::to_str_radix because we don't really need to allocate + // here. + f('\\'); + let pad = cond!( + (c <= '\xff') { f('x'); 2 } + (c <= '\uffff') { f('u'); 4 } + _ { f('U'); 8 } ); - assert!(s.len() <= pad); - let mut out = ~"\\"; - out.push_str(str::from_char(c)); - for uint::range(s.len(), pad) |_| { - out.push_str("0"); + for int::range_step(4 * (pad - 1), -1, -4) |offset| { + match ((c as u32) >> offset) & 0xf { + i @ 0 .. 9 => { f('0' + i as char); } + i => { f('a' + (i - 10) as char); } + } } - out.push_str(s); - out } /// @@ -230,16 +230,16 @@ pub fn escape_unicode(c: char) -> ~str { /// - Any other chars in the range [0x20,0x7e] are not escaped. /// - Any other chars are given hex unicode escapes; see `escape_unicode`. /// -pub fn escape_default(c: char) -> ~str { +pub fn escape_default(c: char, f: &fn(char)) { match c { - '\t' => ~"\\t", - '\r' => ~"\\r", - '\n' => ~"\\n", - '\\' => ~"\\\\", - '\'' => ~"\\'", - '"' => ~"\\\"", - '\x20' .. '\x7e' => str::from_char(c), - _ => c.escape_unicode(), + '\t' => { f('\\'); f('t'); } + '\r' => { f('\\'); f('r'); } + '\n' => { f('\\'); f('n'); } + '\\' => { f('\\'); f('\\'); } + '\'' => { f('\\'); f('\''); } + '"' => { f('\\'); f('"'); } + '\x20' .. '\x7e' => { f(c); } + _ => c.escape_unicode(f), } } @@ -273,8 +273,8 @@ pub trait Char { fn is_digit_radix(&self, radix: uint) -> bool; fn to_digit(&self, radix: uint) -> Option<uint>; fn from_digit(num: uint, radix: uint) -> Option<char>; - fn escape_unicode(&self) -> ~str; - fn escape_default(&self) -> ~str; + fn escape_unicode(&self, f: &fn(char)); + fn escape_default(&self, f: &fn(char)); fn len_utf8_bytes(&self) -> uint; } @@ -301,9 +301,9 @@ impl Char for char { fn from_digit(num: uint, radix: uint) -> Option<char> { from_digit(num, radix) } - fn escape_unicode(&self) -> ~str { escape_unicode(*self) } + fn escape_unicode(&self, f: &fn(char)) { escape_unicode(*self, f) } - fn escape_default(&self) -> ~str { escape_default(*self) } + fn escape_default(&self, f: &fn(char)) { escape_default(*self, f) } fn len_utf8_bytes(&self) -> uint { len_utf8_bytes(*self) } } @@ -391,27 +391,37 @@ fn test_is_digit() { #[test] fn test_escape_default() { - assert_eq!('\n'.escape_default(), ~"\\n"); - assert_eq!('\r'.escape_default(), ~"\\r"); - assert_eq!('\''.escape_default(), ~"\\'"); - assert_eq!('"'.escape_default(), ~"\\\""); - assert_eq!(' '.escape_default(), ~" "); - assert_eq!('a'.escape_default(), ~"a"); - assert_eq!('~'.escape_default(), ~"~"); - assert_eq!('\x00'.escape_default(), ~"\\x00"); - assert_eq!('\x1f'.escape_default(), ~"\\x1f"); - assert_eq!('\x7f'.escape_default(), ~"\\x7f"); - assert_eq!('\xff'.escape_default(), ~"\\xff"); - assert_eq!('\u011b'.escape_default(), ~"\\u011b"); - assert_eq!('\U0001d4b6'.escape_default(), ~"\\U0001d4b6"); + fn string(c: char) -> ~str { + let mut result = ~""; + do escape_default(c) |c| { result.push_char(c); } + return result; + } + assert_eq!(string('\n'), ~"\\n"); + assert_eq!(string('\r'), ~"\\r"); + assert_eq!(string('\''), ~"\\'"); + assert_eq!(string('"'), ~"\\\""); + assert_eq!(string(' '), ~" "); + assert_eq!(string('a'), ~"a"); + assert_eq!(string('~'), ~"~"); + assert_eq!(string('\x00'), ~"\\x00"); + assert_eq!(string('\x1f'), ~"\\x1f"); + assert_eq!(string('\x7f'), ~"\\x7f"); + assert_eq!(string('\xff'), ~"\\xff"); + assert_eq!(string('\u011b'), ~"\\u011b"); + assert_eq!(string('\U0001d4b6'), ~"\\U0001d4b6"); } #[test] fn test_escape_unicode() { - assert_eq!('\x00'.escape_unicode(), ~"\\x00"); - assert_eq!('\n'.escape_unicode(), ~"\\x0a"); - assert_eq!(' '.escape_unicode(), ~"\\x20"); - assert_eq!('a'.escape_unicode(), ~"\\x61"); - assert_eq!('\u011b'.escape_unicode(), ~"\\u011b"); - assert_eq!('\U0001d4b6'.escape_unicode(), ~"\\U0001d4b6"); + fn string(c: char) -> ~str { + let mut result = ~""; + do escape_unicode(c) |c| { result.push_char(c); } + return result; + } + assert_eq!(string('\x00'), ~"\\x00"); + assert_eq!(string('\n'), ~"\\x0a"); + assert_eq!(string(' '), ~"\\x20"); + assert_eq!(string('a'), ~"\\x61"); + assert_eq!(string('\u011b'), ~"\\u011b"); + assert_eq!(string('\U0001d4b6'), ~"\\U0001d4b6"); } diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs index 36c1fdf781b..abda76c9ca6 100644 --- a/src/libstd/cleanup.rs +++ b/src/libstd/cleanup.rs @@ -10,17 +10,13 @@ #[doc(hidden)]; -use libc::{c_char, c_void, intptr_t, uintptr_t}; -use ptr::mut_null; +use libc::c_void; +use ptr::{mut_null}; use repr::BoxRepr; -use rt; -use rt::OldTaskContext; -use sys::TypeDesc; use cast::transmute; +use unstable::intrinsics::TyDesc; -#[cfg(not(test))] use ptr::to_unsafe_ptr; - -type DropGlue<'self> = &'self fn(**TypeDesc, *c_void); +type DropGlue<'self> = &'self fn(**TyDesc, *c_void); /* * Box annihilation @@ -63,6 +59,8 @@ unsafe fn each_live_alloc(read_next_before: bool, #[cfg(unix)] fn debug_mem() -> bool { + use rt; + use rt::OldTaskContext; // XXX: Need to port the environment struct to newsched match rt::context() { OldTaskContext => ::rt::env::get().debug_mem, @@ -75,6 +73,19 @@ fn debug_mem() -> bool { false } +#[inline] +#[cfg(not(stage0))] +unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) { + // This function should be inlined when stage0 is gone + ((*tydesc).drop_glue)(data); +} + +#[inline] +#[cfg(stage0)] +unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) { + ((*tydesc).drop_glue)(0 as **TyDesc, data); +} + /// Destroys all managed memory (i.e. @ boxes) held by the current task. pub unsafe fn annihilate() { use rt::local_heap::local_free; @@ -115,9 +126,9 @@ pub unsafe fn annihilate() { // callback, as the original value may have been freed. for each_live_alloc(false) |box, uniq| { if !uniq { - let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc); - let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0)); - drop_glue(&tydesc, transmute(&(*box).data)); + let tydesc: *TyDesc = transmute(copy (*box).header.type_desc); + let data = transmute(&(*box).data); + call_drop_glue(tydesc, data); } } diff --git a/src/libstd/clone.rs b/src/libstd/clone.rs index 5ec594cef7e..947aa5708c2 100644 --- a/src/libstd/clone.rs +++ b/src/libstd/clone.rs @@ -22,7 +22,7 @@ by convention implementing the `Clone` trait and calling the */ -use core::kinds::Const; +use core::kinds::Freeze; /// A common trait for cloning an object. pub trait Clone { @@ -56,6 +56,18 @@ impl<'self, T> Clone for &'self T { fn clone(&self) -> &'self T { *self } } +impl<'self, T> Clone for &'self [T] { + /// Return a shallow copy of the slice. + #[inline] + fn clone(&self) -> &'self [T] { *self } +} + +impl<'self> Clone for &'self str { + /// Return a shallow copy of the slice. + #[inline] + fn clone(&self) -> &'self str { *self } +} + macro_rules! clone_impl( ($t:ty) => { impl Clone for $t { @@ -100,17 +112,17 @@ impl<T: DeepClone> DeepClone for ~T { fn deep_clone(&self) -> ~T { ~(**self).deep_clone() } } -// FIXME: #6525: should also be implemented for `T: Owned + DeepClone` -impl<T: Const + DeepClone> DeepClone for @T { - /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing +// FIXME: #6525: should also be implemented for `T: Send + DeepClone` +impl<T: Freeze + DeepClone> DeepClone for @T { + /// Return a deep copy of the managed box. The `Freeze` trait is required to prevent performing /// a deep clone of a potentially cyclical type. #[inline] fn deep_clone(&self) -> @T { @(**self).deep_clone() } } -// FIXME: #6525: should also be implemented for `T: Owned + DeepClone` -impl<T: Const + DeepClone> DeepClone for @mut T { - /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing +// FIXME: #6525: should also be implemented for `T: Send + DeepClone` +impl<T: Freeze + DeepClone> DeepClone for @mut T { + /// Return a deep copy of the managed box. The `Freeze` trait is required to prevent performing /// a deep clone of a potentially cyclical type. #[inline] fn deep_clone(&self) -> @mut T { @mut (**self).deep_clone() } diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index 00c33c8ab32..1bb0ff044fe 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -17,7 +17,7 @@ Message passing use cast::{transmute, transmute_mut}; use container::Container; use either::{Either, Left, Right}; -use kinds::Owned; +use kinds::Send; use option::{Option, Some, None}; use uint; use vec::OwnedVector; @@ -77,7 +77,7 @@ pub struct Port<T> { These allow sending or receiving an unlimited number of messages. */ -pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) { +pub fn stream<T:Send>() -> (Port<T>, Chan<T>) { let (port, chan) = match rt::context() { rt::OldTaskContext => match pipesy::stream() { (p, c) => (Left(p), Left(c)) @@ -91,7 +91,7 @@ pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) { return (port, chan); } -impl<T: Owned> GenericChan<T> for Chan<T> { +impl<T: Send> GenericChan<T> for Chan<T> { fn send(&self, x: T) { match self.inner { Left(ref chan) => chan.send(x), @@ -100,7 +100,7 @@ impl<T: Owned> GenericChan<T> for Chan<T> { } } -impl<T: Owned> GenericSmartChan<T> for Chan<T> { +impl<T: Send> GenericSmartChan<T> for Chan<T> { fn try_send(&self, x: T) -> bool { match self.inner { Left(ref chan) => chan.try_send(x), @@ -109,7 +109,7 @@ impl<T: Owned> GenericSmartChan<T> for Chan<T> { } } -impl<T: Owned> GenericPort<T> for Port<T> { +impl<T: Send> GenericPort<T> for Port<T> { fn recv(&self) -> T { match self.inner { Left(ref port) => port.recv(), @@ -125,7 +125,7 @@ impl<T: Owned> GenericPort<T> for Port<T> { } } -impl<T: Owned> Peekable<T> for Port<T> { +impl<T: Send> Peekable<T> for Port<T> { fn peek(&self) -> bool { match self.inner { Left(ref port) => port.peek(), @@ -134,7 +134,7 @@ impl<T: Owned> Peekable<T> for Port<T> { } } -impl<T: Owned> Selectable for Port<T> { +impl<T: Send> Selectable for Port<T> { fn header(&mut self) -> *mut PacketHeader { match self.inner { Left(ref mut port) => port.header(), @@ -149,7 +149,7 @@ pub struct PortSet<T> { ports: ~[pipesy::Port<T>], } -impl<T: Owned> PortSet<T> { +impl<T: Send> PortSet<T> { pub fn new() -> PortSet<T> { PortSet { ports: ~[] @@ -175,7 +175,7 @@ impl<T: Owned> PortSet<T> { } } -impl<T:Owned> GenericPort<T> for PortSet<T> { +impl<T:Send> GenericPort<T> for PortSet<T> { fn try_recv(&self) -> Option<T> { unsafe { let self_ports = transmute_mut(&self.ports); @@ -204,7 +204,7 @@ impl<T:Owned> GenericPort<T> for PortSet<T> { } } -impl<T: Owned> Peekable<T> for PortSet<T> { +impl<T: Send> Peekable<T> for PortSet<T> { fn peek(&self) -> bool { // It'd be nice to use self.port.each, but that version isn't // pure. @@ -223,7 +223,7 @@ pub struct SharedChan<T> { inner: Either<Exclusive<pipesy::Chan<T>>, rtcomm::SharedChan<T>> } -impl<T: Owned> SharedChan<T> { +impl<T: Send> SharedChan<T> { /// Converts a `chan` into a `shared_chan`. pub fn new(c: Chan<T>) -> SharedChan<T> { let Chan { inner } = c; @@ -235,7 +235,7 @@ impl<T: Owned> SharedChan<T> { } } -impl<T: Owned> GenericChan<T> for SharedChan<T> { +impl<T: Send> GenericChan<T> for SharedChan<T> { fn send(&self, x: T) { match self.inner { Left(ref chan) => { @@ -252,7 +252,7 @@ impl<T: Owned> GenericChan<T> for SharedChan<T> { } } -impl<T: Owned> GenericSmartChan<T> for SharedChan<T> { +impl<T: Send> GenericSmartChan<T> for SharedChan<T> { fn try_send(&self, x: T) -> bool { match self.inner { Left(ref chan) => { @@ -269,7 +269,7 @@ impl<T: Owned> GenericSmartChan<T> for SharedChan<T> { } } -impl<T: Owned> ::clone::Clone for SharedChan<T> { +impl<T: Send> ::clone::Clone for SharedChan<T> { fn clone(&self) -> SharedChan<T> { SharedChan { inner: self.inner.clone() } } @@ -283,7 +283,7 @@ pub struct ChanOne<T> { inner: Either<pipesy::ChanOne<T>, rtcomm::ChanOne<T>> } -pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { +pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) { let (port, chan) = match rt::context() { rt::OldTaskContext => match pipesy::oneshot() { (p, c) => (Left(p), Left(c)), @@ -297,7 +297,7 @@ pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { return (port, chan); } -impl<T: Owned> PortOne<T> { +impl<T: Send> PortOne<T> { pub fn recv(self) -> T { let PortOne { inner } = self; match inner { @@ -315,7 +315,7 @@ impl<T: Owned> PortOne<T> { } } -impl<T: Owned> ChanOne<T> { +impl<T: Send> ChanOne<T> { pub fn send(self, data: T) { let ChanOne { inner } = self; match inner { @@ -333,7 +333,7 @@ impl<T: Owned> ChanOne<T> { } } -pub fn recv_one<T: Owned>(port: PortOne<T>) -> T { +pub fn recv_one<T: Send>(port: PortOne<T>) -> T { let PortOne { inner } = port; match inner { Left(p) => pipesy::recv_one(p), @@ -341,7 +341,7 @@ pub fn recv_one<T: Owned>(port: PortOne<T>) -> T { } } -pub fn try_recv_one<T: Owned>(port: PortOne<T>) -> Option<T> { +pub fn try_recv_one<T: Send>(port: PortOne<T>) -> Option<T> { let PortOne { inner } = port; match inner { Left(p) => pipesy::try_recv_one(p), @@ -349,7 +349,7 @@ pub fn try_recv_one<T: Owned>(port: PortOne<T>) -> Option<T> { } } -pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) { +pub fn send_one<T: Send>(chan: ChanOne<T>, data: T) { let ChanOne { inner } = chan; match inner { Left(c) => pipesy::send_one(c, data), @@ -357,7 +357,7 @@ pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) { } } -pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T) -> bool { +pub fn try_send_one<T: Send>(chan: ChanOne<T>, data: T) -> bool { let ChanOne { inner } = chan; match inner { Left(c) => pipesy::try_send_one(c, data), @@ -367,7 +367,7 @@ pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T) -> bool { mod pipesy { - use kinds::Owned; + use kinds::Send; use option::{Option, Some, None}; use pipes::{recv, try_recv, peek, PacketHeader}; use super::{GenericChan, GenericSmartChan, GenericPort, Peekable, Selectable}; @@ -375,17 +375,17 @@ mod pipesy { use util::replace; /*proto! oneshot ( - Oneshot:send<T:Owned> { + Oneshot:send<T:Send> { send(T) -> ! } )*/ #[allow(non_camel_case_types)] pub mod oneshot { - priv use core::kinds::Owned; + priv use core::kinds::Send; use ptr::to_mut_unsafe_ptr; - pub fn init<T: Owned>() -> (server::Oneshot<T>, client::Oneshot<T>) { + pub fn init<T: Send>() -> (server::Oneshot<T>, client::Oneshot<T>) { pub use core::pipes::HasBuffer; let buffer = ~::core::pipes::Buffer { @@ -409,10 +409,10 @@ mod pipesy { #[allow(non_camel_case_types)] pub mod client { - priv use core::kinds::Owned; + priv use core::kinds::Send; #[allow(non_camel_case_types)] - pub fn try_send<T: Owned>(pipe: Oneshot<T>, x_0: T) -> + pub fn try_send<T: Send>(pipe: Oneshot<T>, x_0: T) -> ::core::option::Option<()> { { use super::send; @@ -424,7 +424,7 @@ mod pipesy { } #[allow(non_camel_case_types)] - pub fn send<T: Owned>(pipe: Oneshot<T>, x_0: T) { + pub fn send<T: Send>(pipe: Oneshot<T>, x_0: T) { { use super::send; let message = send(x_0); @@ -474,12 +474,12 @@ mod pipesy { } /// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair. - pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { + pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) { let (port, chan) = oneshot::init(); (PortOne::new(port), ChanOne::new(chan)) } - impl<T: Owned> PortOne<T> { + impl<T: Send> PortOne<T> { pub fn recv(self) -> T { recv_one(self) } pub fn try_recv(self) -> Option<T> { try_recv_one(self) } pub fn unwrap(self) -> oneshot::server::Oneshot<T> { @@ -489,7 +489,7 @@ mod pipesy { } } - impl<T: Owned> ChanOne<T> { + impl<T: Send> ChanOne<T> { pub fn send(self, data: T) { send_one(self, data) } pub fn try_send(self, data: T) -> bool { try_send_one(self, data) } pub fn unwrap(self) -> oneshot::client::Oneshot<T> { @@ -503,7 +503,7 @@ mod pipesy { * Receive a message from a oneshot pipe, failing if the connection was * closed. */ - pub fn recv_one<T: Owned>(port: PortOne<T>) -> T { + pub fn recv_one<T: Send>(port: PortOne<T>) -> T { match port { PortOne { contents: port } => { let oneshot::send(message) = recv(port); @@ -513,7 +513,7 @@ mod pipesy { } /// Receive a message from a oneshot pipe unless the connection was closed. - pub fn try_recv_one<T: Owned> (port: PortOne<T>) -> Option<T> { + pub fn try_recv_one<T: Send> (port: PortOne<T>) -> Option<T> { match port { PortOne { contents: port } => { let message = try_recv(port); @@ -529,7 +529,7 @@ mod pipesy { } /// Send a message on a oneshot pipe, failing if the connection was closed. - pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) { + pub fn send_one<T: Send>(chan: ChanOne<T>, data: T) { match chan { ChanOne { contents: chan } => oneshot::client::send(chan, data), } @@ -539,7 +539,7 @@ mod pipesy { * Send a message on a oneshot pipe, or return false if the connection was * closed. */ - pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T) -> bool { + pub fn try_send_one<T: Send>(chan: ChanOne<T>, data: T) -> bool { match chan { ChanOne { contents: chan } => { oneshot::client::try_send(chan, data).is_some() @@ -550,16 +550,16 @@ mod pipesy { // Streams - Make pipes a little easier in general. /*proto! streamp ( - Open:send<T: Owned> { + Open:send<T: Send> { data(T) -> Open<T> } )*/ #[allow(non_camel_case_types)] pub mod streamp { - priv use core::kinds::Owned; + priv use core::kinds::Send; - pub fn init<T: Owned>() -> (server::Open<T>, client::Open<T>) { + pub fn init<T: Send>() -> (server::Open<T>, client::Open<T>) { pub use core::pipes::HasBuffer; ::core::pipes::entangle() } @@ -569,10 +569,10 @@ mod pipesy { #[allow(non_camel_case_types)] pub mod client { - priv use core::kinds::Owned; + priv use core::kinds::Send; #[allow(non_camel_case_types)] - pub fn try_data<T: Owned>(pipe: Open<T>, x_0: T) -> + pub fn try_data<T: Send>(pipe: Open<T>, x_0: T) -> ::core::option::Option<Open<T>> { { use super::data; @@ -585,7 +585,7 @@ mod pipesy { } #[allow(non_camel_case_types)] - pub fn data<T: Owned>(pipe: Open<T>, x_0: T) -> Open<T> { + pub fn data<T: Send>(pipe: Open<T>, x_0: T) -> Open<T> { { use super::data; let (s, c) = ::core::pipes::entangle(); @@ -623,7 +623,7 @@ mod pipesy { These allow sending or receiving an unlimited number of messages. */ - pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) { + pub fn stream<T:Send>() -> (Port<T>, Chan<T>) { let (s, c) = streamp::init(); (Port { @@ -633,7 +633,7 @@ mod pipesy { }) } - impl<T: Owned> GenericChan<T> for Chan<T> { + impl<T: Send> GenericChan<T> for Chan<T> { #[inline] fn send(&self, x: T) { unsafe { @@ -644,7 +644,7 @@ mod pipesy { } } - impl<T: Owned> GenericSmartChan<T> for Chan<T> { + impl<T: Send> GenericSmartChan<T> for Chan<T> { #[inline] fn try_send(&self, x: T) -> bool { unsafe { @@ -661,7 +661,7 @@ mod pipesy { } } - impl<T: Owned> GenericPort<T> for Port<T> { + impl<T: Send> GenericPort<T> for Port<T> { #[inline] fn recv(&self) -> T { unsafe { @@ -689,7 +689,7 @@ mod pipesy { } } - impl<T: Owned> Peekable<T> for Port<T> { + impl<T: Send> Peekable<T> for Port<T> { #[inline] fn peek(&self) -> bool { unsafe { @@ -705,7 +705,7 @@ mod pipesy { } } - impl<T: Owned> Selectable for Port<T> { + impl<T: Send> Selectable for Port<T> { fn header(&mut self) -> *mut PacketHeader { match self.endp { Some(ref mut endp) => endp.header(), @@ -733,15 +733,15 @@ pub fn select2i<A:Selectable, B:Selectable>(a: &mut A, b: &mut B) } /// Receive a message from one of two endpoints. -pub trait Select2<T: Owned, U: Owned> { +pub trait Select2<T: Send, U: Send> { /// Receive a message or return `None` if a connection closes. fn try_select(&mut self) -> Either<Option<T>, Option<U>>; /// Receive a message or fail if a connection closes. fn select(&mut self) -> Either<T, U>; } -impl<T:Owned, - U:Owned, +impl<T:Send, + U:Send, Left:Selectable + GenericPort<T>, Right:Selectable + GenericPort<U>> Select2<T, U> diff --git a/src/libstd/condition.rs b/src/libstd/condition.rs index 2f150a0d1b2..04f2d815d08 100644 --- a/src/libstd/condition.rs +++ b/src/libstd/condition.rs @@ -90,7 +90,7 @@ struct Guard<'self, T, U> { #[unsafe_destructor] impl<'self, T, U> Drop for Guard<'self, T, U> { - fn finalize(&self) { + fn drop(&self) { unsafe { debug!("Guard: popping handler from TLS"); let curr = local_data_pop(self.cond.key); diff --git a/src/libstd/container.rs b/src/libstd/container.rs index c1b656f1cd9..d6f4c26715a 100644 --- a/src/libstd/container.rs +++ b/src/libstd/container.rs @@ -34,18 +34,6 @@ pub trait Map<K, V>: Mutable { /// Return true if the map contains a value for the specified key fn contains_key(&self, key: &K) -> bool; - /// Visits all keys and values - fn each<'a>(&'a self, f: &fn(&K, &'a V) -> bool) -> bool; - - /// Visit all keys - fn each_key(&self, f: &fn(&K) -> bool) -> bool; - - /// Visit all values - fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) -> bool; - - /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) -> bool; - /// Return a reference to the value corresponding to the key fn find<'a>(&'a self, key: &K) -> Option<&'a V>; diff --git a/src/libstd/either.rs b/src/libstd/either.rs index 681a7fbc821..b6da93f9d40 100644 --- a/src/libstd/either.rs +++ b/src/libstd/either.rs @@ -15,11 +15,11 @@ use container::Container; use cmp::Eq; use kinds::Copy; -use old_iter::BaseIter; +use iterator::IteratorUtil; use result::Result; use result; use vec; -use vec::OwnedVector; +use vec::{OwnedVector, ImmutableVector}; /// The either type #[deriving(Clone, Eq)] @@ -45,7 +45,7 @@ pub fn either<T, U, V>(f_left: &fn(&T) -> V, /// Extracts from a vector of either all the left values pub fn lefts<T:Copy,U>(eithers: &[Either<T, U>]) -> ~[T] { do vec::build_sized(eithers.len()) |push| { - for eithers.each |elt| { + for eithers.iter().advance |elt| { match *elt { Left(ref l) => { push(copy *l); } _ => { /* fallthrough */ } @@ -57,7 +57,7 @@ pub fn lefts<T:Copy,U>(eithers: &[Either<T, U>]) -> ~[T] { /// Extracts from a vector of either all the right values pub fn rights<T, U: Copy>(eithers: &[Either<T, U>]) -> ~[U] { do vec::build_sized(eithers.len()) |push| { - for eithers.each |elt| { + for eithers.iter().advance |elt| { match *elt { Right(ref r) => { push(copy *r); } _ => { /* fallthrough */ } diff --git a/src/libstd/gc.rs b/src/libstd/gc.rs index 611b95a7745..c9e33219fa5 100644 --- a/src/libstd/gc.rs +++ b/src/libstd/gc.rs @@ -40,12 +40,13 @@ with destructors. use cast; use container::{Map, Set}; use io; -use libc::{size_t, uintptr_t}; +use libc::{uintptr_t}; use option::{None, Option, Some}; use ptr; use hashmap::HashSet; use stackwalk::walk_stack; use sys; +use unstable::intrinsics::{TyDesc}; pub use stackwalk::Word; @@ -58,18 +59,12 @@ pub struct StackSegment { } pub mod rustrt { - use libc::size_t; use stackwalk::Word; use super::StackSegment; #[link_name = "rustrt"] pub extern { #[rust_stack] - pub unsafe fn rust_call_tydesc_glue(root: *Word, - tydesc: *Word, - field: size_t); - - #[rust_stack] pub unsafe fn rust_gc_metadata() -> *Word; pub unsafe fn rust_get_stack_segment() -> *StackSegment; @@ -125,7 +120,7 @@ unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> { return None; } -type Visitor<'self> = &'self fn(root: **Word, tydesc: *Word) -> bool; +type Visitor<'self> = &'self fn(root: **Word, tydesc: *TyDesc) -> bool; // Walks the list of roots for the given safe point, and calls visitor // on each root. @@ -139,7 +134,7 @@ unsafe fn _walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) -> bool { let stack_roots: *u32 = bump(sp_meta, 2); let reg_roots: *u8 = bump(stack_roots, num_stack_roots); let addrspaces: *Word = align_to_pointer(bump(reg_roots, num_reg_roots)); - let tydescs: ***Word = bump(addrspaces, num_stack_roots); + let tydescs: ***TyDesc = bump(addrspaces, num_stack_roots); // Stack roots let mut sri = 0; @@ -321,6 +316,19 @@ fn expect_sentinel() -> bool { true } #[cfg(nogc)] fn expect_sentinel() -> bool { false } +#[inline] +#[cfg(not(stage0))] +unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) { + // This function should be inlined when stage0 is gone + ((*tydesc).drop_glue)(data); +} + +#[inline] +#[cfg(stage0)] +unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) { + ((*tydesc).drop_glue)(0 as **TyDesc, data); +} + // Entry point for GC-based cleanup. Walks stack looking for exchange // heap and stack allocations requiring drop, and runs all // destructors. @@ -364,7 +372,7 @@ pub fn cleanup_stack_for_failure() { // FIXME #4420: Destroy this box // FIXME #4330: Destroy this box } else { - rustrt::rust_call_tydesc_glue(*root, tydesc, 3 as size_t); + call_drop_glue(tydesc, *root as *i8); } } } diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs index 1967a57e867..6c3fcd41ed3 100644 --- a/src/libstd/hash.rs +++ b/src/libstd/hash.rs @@ -22,10 +22,12 @@ #[allow(missing_doc)]; use container::Container; -use old_iter::BaseIter; +use iterator::IteratorUtil; use rt::io::Writer; +use str::OwnedStr; use to_bytes::IterBytes; use uint; +use vec::ImmutableVector; // Alias `SipState` to `State`. pub use State = hash::SipState; @@ -367,8 +369,8 @@ impl Streaming for SipState { fn result_str(&mut self) -> ~str { let r = self.result_bytes(); let mut s = ~""; - for r.each |b| { - s += uint::to_str_radix(*b as uint, 16u); + for r.iter().advance |b| { + s.push_str(uint::to_str_radix(*b as uint, 16u)); } s } @@ -469,8 +471,8 @@ mod tests { fn to_hex_str(r: &[u8, ..8]) -> ~str { let mut s = ~""; - for (*r).each |b| { - s += uint::to_str_radix(*b as uint, 16u); + for r.iter().advance |b| { + s.push_str(uint::to_str_radix(*b as uint, 16u)); } s } @@ -491,7 +493,7 @@ mod tests { assert!(f == i && f == v); - buf += [t as u8]; + buf.push(t as u8); stream_inc.input([t as u8]); t += 1; diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index d05fa63a6f9..85dca1154bc 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -18,14 +18,13 @@ use container::{Container, Mutable, Map, Set}; use cmp::{Eq, Equiv}; use hash::Hash; -use old_iter::BaseIter; -use old_iter; -use iterator::{IteratorUtil}; +use iterator::{Iterator, IteratorUtil}; use option::{None, Option, Some}; use rand::RngUtil; use rand; use uint; use vec; +use vec::{ImmutableVector, MutableVector}; use kinds::Copy; use util::{replace, unreachable}; @@ -283,10 +282,10 @@ impl<K:Hash + Eq,V> HashMap<K, V> { impl<K:Hash + Eq,V> Container for HashMap<K, V> { /// Return the number of elements in the map - fn len(&const self) -> uint { self.size } + fn len(&self) -> uint { self.size } /// Return true if the map contains no elements - fn is_empty(&const self) -> bool { self.len() == 0 } + fn is_empty(&self) -> bool { self.len() == 0 } } impl<K:Hash + Eq,V> Mutable for HashMap<K, V> { @@ -308,41 +307,6 @@ impl<K:Hash + Eq,V> Map<K, V> for HashMap<K, V> { } } - /// Visit all key-value pairs - fn each<'a>(&'a self, blk: &fn(&K, &'a V) -> bool) -> bool { - for self.buckets.each |bucket| { - for bucket.iter().advance |pair| { - if !blk(&pair.key, &pair.value) { - return false; - } - } - } - return true; - } - - /// Visit all keys - fn each_key(&self, blk: &fn(k: &K) -> bool) -> bool { - self.each(|k, _| blk(k)) - } - - /// Visit all values - fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) -> bool { - self.each(|_, v| blk(v)) - } - - /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, blk: &fn(&K, &mut V) -> bool) -> bool { - for uint::range(0, self.buckets.len()) |i| { - match self.buckets[i] { - Some(Bucket{key: ref key, value: ref mut value, _}) => { - if !blk(key, value) { return false; } - } - None => () - } - } - return true; - } - /// Return a reference to the value corresponding to the key fn find<'a>(&'a self, k: &K) -> Option<&'a V> { match self.bucket_for_key(k) { @@ -523,6 +487,42 @@ impl<K: Hash + Eq, V> HashMap<K, V> { TableFull | FoundHole(_) => None, } } + + /// Visit all keys + pub fn each_key(&self, blk: &fn(k: &K) -> bool) -> bool { + self.iter().advance(|(k, _)| blk(k)) + } + + /// Visit all values + pub fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) -> bool { + self.iter().advance(|(_, v)| blk(v)) + } + + /// Iterate over the map and mutate the contained values + pub fn mutate_values(&mut self, blk: &fn(&K, &mut V) -> bool) -> bool { + for uint::range(0, self.buckets.len()) |i| { + match self.buckets[i] { + Some(Bucket{key: ref key, value: ref mut value, _}) => { + if !blk(key, value) { return false; } + } + None => () + } + } + return true; + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// Iterator element type is (&'a K, &'a V). + pub fn iter<'a>(&'a self) -> HashMapIterator<'a, K, V> { + HashMapIterator { iter: self.buckets.iter() } + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// Iterator element type is (&'a K, &'a mut V). + pub fn mut_iter<'a>(&'a mut self) -> HashMapMutIterator<'a, K, V> { + HashMapMutIterator { iter: self.buckets.mut_iter() } + } } impl<K: Hash + Eq, V: Copy> HashMap<K, V> { @@ -541,7 +541,7 @@ impl<K:Hash + Eq,V:Eq> Eq for HashMap<K, V> { fn eq(&self, other: &HashMap<K, V>) -> bool { if self.len() != other.len() { return false; } - for self.each |key, value| { + for self.iter().advance |(key, value)| { match other.find(key) { None => return false, Some(v) => if value != v { return false }, @@ -554,6 +554,61 @@ impl<K:Hash + Eq,V:Eq> Eq for HashMap<K, V> { fn ne(&self, other: &HashMap<K, V>) -> bool { !self.eq(other) } } +/// HashMap iterator +pub struct HashMapIterator<'self, K, V> { + priv iter: vec::VecIterator<'self, Option<Bucket<K, V>>>, +} + +/// HashMap mutable values iterator +pub struct HashMapMutIterator<'self, K, V> { + priv iter: vec::VecMutIterator<'self, Option<Bucket<K, V>>>, +} + +/// HashSet iterator +pub struct HashSetIterator<'self, K> { + priv iter: vec::VecIterator<'self, Option<Bucket<K, ()>>>, +} + +impl<'self, K, V> Iterator<(&'self K, &'self V)> for HashMapIterator<'self, K, V> { + #[inline] + fn next(&mut self) -> Option<(&'self K, &'self V)> { + for self.iter.advance |elt| { + match elt { + &Some(ref bucket) => return Some((&bucket.key, &bucket.value)), + &None => {}, + } + } + None + } +} + +impl<'self, K, V> Iterator<(&'self K, &'self mut V)> for HashMapMutIterator<'self, K, V> { + #[inline] + fn next(&mut self) -> Option<(&'self K, &'self mut V)> { + for self.iter.advance |elt| { + match elt { + &Some(ref mut bucket) => return Some((&bucket.key, &mut bucket.value)), + &None => {}, + } + } + None + } +} + +impl<'self, K> Iterator<&'self K> for HashSetIterator<'self, K> { + #[inline] + fn next(&mut self) -> Option<&'self K> { + for self.iter.advance |elt| { + match elt { + &Some(ref bucket) => return Some(&bucket.key), + &None => {}, + } + } + None + } +} + + /// An implementation of a hash set using the underlying representation of a /// HashMap where the value is (). As with the `HashMap` type, a `HashSet` /// requires that the elements implement the `Eq` and `Hash` traits. @@ -561,12 +616,6 @@ pub struct HashSet<T> { priv map: HashMap<T, ()> } -impl<T:Hash + Eq> BaseIter<T> for HashSet<T> { - /// Visit all values in order - fn each(&self, f: &fn(&T) -> bool) -> bool { self.map.each_key(f) } - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - impl<T:Hash + Eq> Eq for HashSet<T> { fn eq(&self, other: &HashSet<T>) -> bool { self.map == other.map } fn ne(&self, other: &HashSet<T>) -> bool { self.map != other.map } @@ -574,10 +623,10 @@ impl<T:Hash + Eq> Eq for HashSet<T> { impl<T:Hash + Eq> Container for HashSet<T> { /// Return the number of elements in the set - fn len(&const self) -> uint { self.map.len() } + fn len(&self) -> uint { self.map.len() } /// Return true if the set contains no elements - fn is_empty(&const self) -> bool { self.map.is_empty() } + fn is_empty(&self) -> bool { self.map.is_empty() } } impl<T:Hash + Eq> Mutable for HashSet<T> { @@ -600,12 +649,12 @@ impl<T:Hash + Eq> Set<T> for HashSet<T> { /// Return true if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. fn is_disjoint(&self, other: &HashSet<T>) -> bool { - old_iter::all(self, |v| !other.contains(v)) + self.iter().all(|v| !other.contains(v)) } /// Return true if the set is a subset of another fn is_subset(&self, other: &HashSet<T>) -> bool { - old_iter::all(self, |v| other.contains(v)) + self.iter().all(|v| other.contains(v)) } /// Return true if the set is a superset of another @@ -615,24 +664,25 @@ impl<T:Hash + Eq> Set<T> for HashSet<T> { /// Visit the values representing the difference fn difference(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool { - self.each(|v| other.contains(v) || f(v)) + self.iter().advance(|v| other.contains(v) || f(v)) } /// Visit the values representing the symmetric difference fn symmetric_difference(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool { - self.difference(other, f) && other.difference(self, f) + self.difference(other, |t| f(t)) && other.difference(self, |t| f(t)) } /// Visit the values representing the intersection fn intersection(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool { - self.each(|v| !other.contains(v) || f(v)) + self.iter().advance(|v| !other.contains(v) || f(v)) } /// Visit the values representing the union fn union(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool { - self.each(f) && other.each(|v| self.contains(v) || f(v)) + self.iter().advance(|t| f(t)) && + other.iter().advance(|v| self.contains(v) || f(v)) } } @@ -663,6 +713,12 @@ impl<T:Hash + Eq> HashSet<T> { pub fn contains_equiv<Q:Hash + Equiv<T>>(&self, value: &Q) -> bool { self.map.contains_key_equiv(value) } + + /// An iterator visiting all elements in arbitrary order. + /// Iterator element type is &'a T. + pub fn iter<'a>(&'a self) -> HashSetIterator<'a, T> { + HashSetIterator { iter: self.map.buckets.iter() } + } } #[cfg(test)] @@ -807,7 +863,7 @@ mod test_map { assert!(m.insert(i, i*2)); } let mut observed = 0; - for m.each |k, v| { + for m.iter().advance |(k, v)| { assert_eq!(*v, *k * 2); observed |= (1 << *k); } @@ -883,7 +939,8 @@ mod test_map { mod test_set { use super::*; use container::{Container, Map, Set}; - use vec; + use vec::ImmutableEqVector; + use uint; #[test] fn test_disjoint() { @@ -937,6 +994,19 @@ mod test_set { } #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for uint::range(0, 32) |i| { + assert!(a.insert(i)); + } + let mut observed = 0; + for a.iter().advance |k| { + observed |= (1 << *k); + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] fn test_intersection() { let mut a = HashSet::new(); let mut b = HashSet::new(); @@ -960,7 +1030,7 @@ mod test_set { let mut i = 0; let expected = [3, 5, 11, 77]; for a.intersection(&b) |x| { - assert!(vec::contains(expected, x)); + assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); @@ -983,7 +1053,7 @@ mod test_set { let mut i = 0; let expected = [1, 5, 11]; for a.difference(&b) |x| { - assert!(vec::contains(expected, x)); + assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); @@ -1009,7 +1079,7 @@ mod test_set { let mut i = 0; let expected = [-2, 1, 5, 11, 14, 22]; for a.symmetric_difference(&b) |x| { - assert!(vec::contains(expected, x)); + assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); @@ -1039,7 +1109,7 @@ mod test_set { let mut i = 0; let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; for a.union(&b) |x| { - assert!(vec::contains(expected, x)); + assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); diff --git a/src/libstd/io.rs b/src/libstd/io.rs index e5e8a4cb601..bdcad15f45c 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -57,7 +57,7 @@ use os; use cast; use path::Path; use ops::Drop; -use old_iter::{BaseIter, CopyableIter}; +use iterator::IteratorUtil; use ptr; use result; use str; @@ -65,7 +65,7 @@ use str::StrSlice; use to_str::ToStr; use uint; use vec; -use vec::{OwnedVector, OwnedCopyableVector}; +use vec::{MutableVector, ImmutableVector, OwnedVector, OwnedCopyableVector, CopyableVector}; #[allow(non_camel_case_types)] // not sure what to do about this pub type fd_t = c_int; @@ -698,7 +698,7 @@ impl<T:Reader> ReaderUtil for T { // over-read by reading 1-byte per char needed nbread = if ncreq > nbreq { ncreq } else { nbreq }; if nbread > 0 { - bytes = vec::slice(bytes, offset, bytes.len()).to_vec(); + bytes = bytes.slice(offset, bytes.len()).to_owned(); } } chars @@ -771,7 +771,9 @@ impl<T:Reader> ReaderUtil for T { fn read_le_uint_n(&self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut (val, pos, i) = (0u64, 0, nbytes); + let mut val = 0u64; + let mut pos = 0; + let mut i = nbytes; while i > 0 { val += (self.read_u8() as u64) << pos; pos += 8; @@ -787,7 +789,8 @@ impl<T:Reader> ReaderUtil for T { fn read_be_uint_n(&self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut (val, i) = (0u64, nbytes); + let mut val = 0u64; + let mut i = nbytes; while i > 0 { i -= 1; val += (self.read_u8() as u64) << i * 8; @@ -989,7 +992,7 @@ impl FILERes { } impl Drop for FILERes { - fn finalize(&self) { + fn drop(&self) { unsafe { libc::fclose(self.f); } @@ -1042,16 +1045,18 @@ pub fn file_reader(path: &Path) -> Result<@Reader, ~str> { // Byte readers -pub struct BytesReader<'self> { - bytes: &'self [u8], +pub struct BytesReader { + // FIXME(#5723) see other FIXME below + // FIXME(#7268) this should also be parameterized over <'self> + bytes: &'static [u8], pos: @mut uint } -impl<'self> Reader for BytesReader<'self> { +impl Reader for BytesReader { fn read(&self, bytes: &mut [u8], len: uint) -> uint { let count = uint::min(len, self.bytes.len() - *self.pos); - let view = vec::slice(self.bytes, *self.pos, self.bytes.len()); + let view = self.bytes.slice(*self.pos, self.bytes.len()); vec::bytes::copy_memory(bytes, view, count); *self.pos += count; @@ -1084,6 +1089,10 @@ impl<'self> Reader for BytesReader<'self> { } pub fn with_bytes_reader<T>(bytes: &[u8], f: &fn(@Reader) -> T) -> T { + // XXX XXX XXX this is glaringly unsound + // FIXME(#5723) Use a &Reader for the callback's argument. Should be: + // fn with_bytes_reader<'r, T>(bytes: &'r [u8], f: &fn(&'r Reader) -> T) -> T + let bytes: &'static [u8] = unsafe { cast::transmute(bytes) }; f(@BytesReader { bytes: bytes, pos: @mut 0 @@ -1091,6 +1100,7 @@ pub fn with_bytes_reader<T>(bytes: &[u8], f: &fn(@Reader) -> T) -> T { } pub fn with_str_reader<T>(s: &str, f: &fn(@Reader) -> T) -> T { + // FIXME(#5723): As above. with_bytes_reader(s.as_bytes(), f) } @@ -1142,7 +1152,7 @@ impl<W:Writer,C> Writer for Wrapper<W, C> { impl Writer for *libc::FILE { fn write(&self, v: &[u8]) { unsafe { - do vec::as_const_buf(v) |vbuf, len| { + do vec::as_imm_buf(v) |vbuf, len| { let nout = libc::fwrite(vbuf as *c_void, 1, len as size_t, @@ -1193,9 +1203,9 @@ impl Writer for fd_t { fn write(&self, v: &[u8]) { unsafe { let mut count = 0u; - do vec::as_const_buf(v) |vbuf, len| { + do vec::as_imm_buf(v) |vbuf, len| { while count < len { - let vb = ptr::const_offset(vbuf, count) as *c_void; + let vb = ptr::offset(vbuf, count) as *c_void; let nout = libc::write(*self, vb, len as size_t); if nout < 0 as ssize_t { error!("error writing buffer"); @@ -1234,7 +1244,7 @@ impl FdRes { } impl Drop for FdRes { - fn finalize(&self) { + fn drop(&self) { unsafe { libc::close(self.fd); } @@ -1261,7 +1271,7 @@ pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) fn wb() -> c_int { O_WRONLY as c_int } let mut fflags: c_int = wb(); - for flags.each |f| { + for flags.iter().advance |f| { match *f { Append => fflags |= O_APPEND as c_int, Create => fflags |= O_CREAT as c_int, @@ -1651,12 +1661,12 @@ impl Writer for BytesWriter { let bytes = &mut *self.bytes; let count = uint::max(bytes.len(), *self.pos + v_len); - vec::reserve(bytes, count); + bytes.reserve(count); unsafe { vec::raw::set_len(bytes, count); - let view = vec::mut_slice(*bytes, *self.pos, count); + let view = bytes.mut_slice(*self.pos, count); vec::bytes::copy_memory(view, v, v_len); } @@ -1772,7 +1782,7 @@ pub mod fsync { #[unsafe_destructor] impl<T:Copy> Drop for Res<T> { - fn finalize(&self) { + fn drop(&self) { match self.arg.opt_level { None => (), Some(level) => { @@ -1902,8 +1912,9 @@ mod tests { if len <= ivals.len() { assert_eq!(res.len(), len); } - assert!(vec::slice(ivals, 0u, res.len()) == - vec::map(res, |x| *x as int)); + for ivals.iter().zip(res.iter()).advance |(iv, c)| { + assert!(*iv == *c as int) + } } } let mut i = 0; @@ -2015,7 +2026,7 @@ mod tests { // write the ints to the file { let file = io::file_writer(&path, [io::Create]).get(); - for uints.each |i| { + for uints.iter().advance |i| { file.write_le_u64(*i); } } @@ -2023,7 +2034,7 @@ mod tests { // then read them back and check that they are the same { let file = io::file_reader(&path).get(); - for uints.each |i| { + for uints.iter().advance |i| { assert_eq!(file.read_le_u64(), *i); } } @@ -2037,7 +2048,7 @@ mod tests { // write the ints to the file { let file = io::file_writer(&path, [io::Create]).get(); - for uints.each |i| { + for uints.iter().advance |i| { file.write_be_u64(*i); } } @@ -2045,7 +2056,7 @@ mod tests { // then read them back and check that they are the same { let file = io::file_reader(&path).get(); - for uints.each |i| { + for uints.iter().advance |i| { assert_eq!(file.read_be_u64(), *i); } } @@ -2059,7 +2070,7 @@ mod tests { // write the ints to the file { let file = io::file_writer(&path, [io::Create]).get(); - for ints.each |i| { + for ints.iter().advance |i| { file.write_be_i32(*i); } } @@ -2067,7 +2078,7 @@ mod tests { // then read them back and check that they are the same { let file = io::file_reader(&path).get(); - for ints.each |i| { + for ints.iter().advance |i| { // this tests that the sign extension is working // (comparing the values as i32 would not test this) assert_eq!(file.read_be_int_n(4), *i as i64); diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs index 7053cbe0df5..4e598a4aa1c 100644 --- a/src/libstd/iter.rs +++ b/src/libstd/iter.rs @@ -56,7 +56,7 @@ pub trait FromIter<T> { /// /// ~~~ {.rust} /// let xs = ~[1, 2, 3]; - /// let ys: ~[int] = do FromIter::from_iter |f| { xs.each(|x| f(*x)) }; + /// let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) }; /// assert_eq!(xs, ys); /// ~~~ pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> Self; @@ -69,8 +69,8 @@ pub trait FromIter<T> { * * ~~~ {.rust} * let xs = ~[1u, 2, 3, 4, 5]; - * assert!(any(|&x: &uint| x > 2, |f| xs.each(f))); - * assert!(!any(|&x: &uint| x > 5, |f| xs.each(f))); + * assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f))); + * assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f))); * ~~~ */ #[inline] @@ -109,7 +109,7 @@ pub fn all<T>(predicate: &fn(T) -> bool, * * ~~~ {.rust} * let xs = ~[1u, 2, 3, 4, 5, 6]; - * assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); + * assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4); * ~~~ */ #[inline] @@ -130,7 +130,7 @@ pub fn find<T>(predicate: &fn(&T) -> bool, * * ~~~ {.rust} * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - * assert_eq!(max(|f| xs.each(f)).unwrap(), &15); + * assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15); * ~~~ */ #[inline] @@ -156,7 +156,7 @@ pub fn max<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> { * * ~~~ {.rust} * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - * assert_eq!(max(|f| xs.each(f)).unwrap(), &-5); + * assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &-5); * ~~~ */ #[inline] @@ -223,7 +223,7 @@ pub fn fold_ref<T, U>(start: T, iter: &fn(f: &fn(&U) -> bool) -> bool, f: &fn(&m * * ~~~ {.rust} * let xs: ~[int] = ~[1, 2, 3, 4]; - * assert_eq!(do sum |f| { xs.each(f) }, 10); + * assert_eq!(do sum |f| { xs.iter().advance(f) }, 10); * ~~~ */ #[inline] @@ -238,7 +238,7 @@ pub fn sum<T: Zero + Add<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { * * ~~~ {.rust} * let xs: ~[int] = ~[1, 2, 3, 4]; - * assert_eq!(do product |f| { xs.each(f) }, 24); + * assert_eq!(do product |f| { xs.iter().advance(f) }, 24); * ~~~ */ #[inline] @@ -257,15 +257,15 @@ mod tests { #[test] fn test_from_iter() { let xs = ~[1, 2, 3]; - let ys: ~[int] = do FromIter::from_iter |f| { xs.each(|x| f(*x)) }; + let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) }; assert_eq!(xs, ys); } #[test] fn test_any() { let xs = ~[1u, 2, 3, 4, 5]; - assert!(any(|&x: &uint| x > 2, |f| xs.each(f))); - assert!(!any(|&x: &uint| x > 5, |f| xs.each(f))); + assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f))); + assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f))); } #[test] @@ -277,19 +277,19 @@ mod tests { #[test] fn test_find() { let xs = ~[1u, 2, 3, 4, 5, 6]; - assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); + assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4); } #[test] fn test_max() { let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - assert_eq!(max(|f| xs.each(f)).unwrap(), &15); + assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15); } #[test] fn test_min() { let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - assert_eq!(min(|f| xs.each(f)).unwrap(), &-5); + assert_eq!(min(|f| xs.iter().advance(f)).unwrap(), &-5); } #[test] @@ -300,24 +300,24 @@ mod tests { #[test] fn test_sum() { let xs: ~[int] = ~[1, 2, 3, 4]; - assert_eq!(do sum |f| { xs.each(f) }, 10); + assert_eq!(do sum |f| { xs.iter().advance(f) }, 10); } #[test] fn test_empty_sum() { let xs: ~[int] = ~[]; - assert_eq!(do sum |f| { xs.each(f) }, 0); + assert_eq!(do sum |f| { xs.iter().advance(f) }, 0); } #[test] fn test_product() { let xs: ~[int] = ~[1, 2, 3, 4]; - assert_eq!(do product |f| { xs.each(f) }, 24); + assert_eq!(do product |f| { xs.iter().advance(f) }, 24); } #[test] fn test_empty_product() { let xs: ~[int] = ~[]; - assert_eq!(do product |f| { xs.each(f) }, 1); + assert_eq!(do product |f| { xs.iter().advance(f) }, 1); } } diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index eefad1a03dc..77befbf19aa 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -17,20 +17,33 @@ implementing the `Iterator` trait. */ +#[allow(default_methods)]; // solid enough for the use case here + use cmp; -use iter::{FromIter, Times}; +use iter::Times; use num::{Zero, One}; use option::{Option, Some, None}; use ops::{Add, Mul}; use cmp::Ord; use clone::Clone; +/// Conversion from an `Iterator` +pub trait FromIterator<A, T: Iterator<A>> { + /// Build a container with elements from an external iterator. + pub fn from_iterator(iterator: &mut T) -> Self; +} + /// An interface for dealing with "external iterators". These types of iterators /// can be resumed at any time as all state is stored internally as opposed to /// being located on the call stack. pub trait Iterator<A> { /// Advance the iterator and return the next value. Return `None` when the end is reached. fn next(&mut self) -> Option<A>; + + /// Return a lower bound and upper bound on the remaining length of the iterator. + /// + /// The common use case for the estimate is pre-allocating space to store the results. + fn size_hint(&self) -> (Option<uint>, Option<uint>) { (None, None) } } /// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also @@ -72,8 +85,7 @@ pub trait IteratorUtil<A> { // FIXME: #5898: should be called map /// Creates a new iterator which will apply the specified function to each - /// element returned by the first, yielding the mapped element instead. This - /// similar to the `vec::map` function. + /// element returned by the first, yielding the mapped element instead. /// /// # Example /// @@ -212,6 +224,26 @@ pub trait IteratorUtil<A> { fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option<B>) -> ScanIterator<'r, A, B, Self, St>; + /// Creates an iterator that maps each element to an iterator, + /// and yields the elements of the produced iterators + /// + /// # Example + /// + /// ~~~ {.rust} + /// let xs = [2u, 3]; + /// let ys = [0u, 1, 0, 1, 2]; + /// let mut it = xs.iter().flat_map_(|&x| Counter::new(0u, 1).take_(x)); + /// // Check that `it` has the same elements as `ys` + /// let mut i = 0; + /// for it.advance |x: uint| { + /// assert_eq!(x, ys[i]); + /// i += 1; + /// } + /// ~~~ + // FIXME: #5898: should be called `flat_map` + fn flat_map_<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U) + -> FlatMapIterator<'r, A, B, Self, U>; + /// An adaptation of an external iterator to the for-loop protocol of rust. /// /// # Example @@ -226,7 +258,7 @@ pub trait IteratorUtil<A> { fn advance(&mut self, f: &fn(A) -> bool) -> bool; /// Loops through the entire iterator, collecting all of the elements into - /// a container implementing `FromIter`. + /// a container implementing `FromIterator`. /// /// # Example /// @@ -235,7 +267,7 @@ pub trait IteratorUtil<A> { /// let b: ~[int] = a.iter().transform(|&x| x).collect(); /// assert!(a == b); /// ~~~ - fn collect<B: FromIter<A>>(&mut self) -> B; + fn collect<B: FromIterator<A, Self>>(&mut self) -> B; /// Loops through `n` iterations, returning the `n`th element of the /// iterator. @@ -273,6 +305,7 @@ pub trait IteratorUtil<A> { /// ~~~ fn fold<B>(&mut self, start: B, f: &fn(B, A) -> B) -> B; + // FIXME: #5898: should be called len /// Counts the number of elements in this iterator. /// /// # Example @@ -280,10 +313,10 @@ pub trait IteratorUtil<A> { /// ~~~ {.rust} /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); - /// assert!(it.count() == 5); - /// assert!(it.count() == 0); + /// assert!(it.len_() == 5); + /// assert!(it.len_() == 0); /// ~~~ - fn count(&mut self) -> uint; + fn len_(&mut self) -> uint; /// Tests whether the predicate holds true for all elements in the iterator. /// @@ -314,6 +347,29 @@ pub trait IteratorUtil<A> { /// Return the index of the first element satisfying the specified predicate fn position_(&mut self, predicate: &fn(A) -> bool) -> Option<uint>; + + /// Count the number of elements satisfying the specified predicate + fn count(&mut self, predicate: &fn(A) -> bool) -> uint; + + /// Return the element that gives the maximum value from the specfied function + /// + /// # Example + /// + /// ~~~ {.rust} + /// let xs = [-3, 0, 1, 5, -10]; + /// assert_eq!(*xs.iter().max_by(|x| x.abs()).unwrap(), -10); + /// ~~~ + fn max_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A>; + + /// Return the element that gives the minimum value from the specfied function + /// + /// # Example + /// + /// ~~~ {.rust} + /// let xs = [-3, 0, 1, 5, -10]; + /// assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0); + /// ~~~ + fn min_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A>; } /// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also @@ -379,6 +435,12 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { ScanIterator{iter: self, f: f, state: initial_state} } + #[inline] + fn flat_map_<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U) + -> FlatMapIterator<'r, A, B, T, U> { + FlatMapIterator{iter: self, f: f, subiter: None } + } + /// A shim implementing the `for` loop iteration protocol for iterator objects #[inline] fn advance(&mut self, f: &fn(A) -> bool) -> bool { @@ -393,8 +455,8 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { } #[inline] - fn collect<B: FromIter<A>>(&mut self) -> B { - FromIter::from_iter::<A, B>(|f| self.advance(f)) + fn collect<B: FromIterator<A, T>>(&mut self) -> B { + FromIterator::from_iterator(self) } /// Return the `n`th item yielded by an iterator. @@ -432,7 +494,7 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { /// Count the number of items yielded by an iterator #[inline] - fn count(&mut self) -> uint { self.fold(0, |cnt, _x| cnt + 1) } + fn len_(&mut self) -> uint { self.fold(0, |cnt, _x| cnt + 1) } #[inline] fn all(&mut self, f: &fn(A) -> bool) -> bool { @@ -467,6 +529,45 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { } None } + + #[inline] + fn count(&mut self, predicate: &fn(A) -> bool) -> uint { + let mut i = 0; + for self.advance |x| { + if predicate(x) { i += 1 } + } + i + } + + #[inline] + fn max_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A> { + self.fold(None, |max: Option<(A, B)>, x| { + let x_val = f(&x); + match max { + None => Some((x, x_val)), + Some((y, y_val)) => if x_val > y_val { + Some((x, x_val)) + } else { + Some((y, y_val)) + } + } + }).map_consume(|(x, _)| x) + } + + #[inline] + fn min_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A> { + self.fold(None, |min: Option<(A, B)>, x| { + let x_val = f(&x); + match min { + None => Some((x, x_val)), + Some((y, y_val)) => if x_val < y_val { + Some((x, x_val)) + } else { + Some((y, y_val)) + } + } + }).map_consume(|(x, _)| x) + } } /// A trait for iterators over elements which can be added together @@ -581,6 +682,26 @@ impl<A, T: Iterator<A>, U: Iterator<A>> Iterator<A> for ChainIterator<A, T, U> { self.b.next() } } + + #[inline] + fn size_hint(&self) -> (Option<uint>, Option<uint>) { + let (a_lower, a_upper) = self.a.size_hint(); + let (b_lower, b_upper) = self.b.size_hint(); + + let lower = match (a_lower, b_lower) { + (Some(x), Some(y)) => Some(x + y), + (Some(x), None) => Some(x), + (None, Some(y)) => Some(y), + (None, None) => None + }; + + let upper = match (a_upper, b_upper) { + (Some(x), Some(y)) => Some(x + y), + _ => None + }; + + (lower, upper) + } } /// An iterator which iterates two other iterators simultaneously @@ -614,6 +735,11 @@ impl<'self, A, B, T: Iterator<A>> Iterator<B> for MapIterator<'self, A, B, T> { _ => None } } + + #[inline] + fn size_hint(&self) -> (Option<uint>, Option<uint>) { + self.iter.size_hint() + } } /// An iterator which filters the elements of `iter` with `predicate` @@ -634,6 +760,12 @@ impl<'self, A, T: Iterator<A>> Iterator<A> for FilterIterator<'self, A, T> { } None } + + #[inline] + fn size_hint(&self) -> (Option<uint>, Option<uint>) { + let (_, upper) = self.iter.size_hint(); + (None, upper) // can't know a lower bound, due to the predicate + } } /// An iterator which uses `f` to both filter and map elements from `iter` @@ -653,6 +785,12 @@ impl<'self, A, B, T: Iterator<A>> Iterator<B> for FilterMapIterator<'self, A, B, } None } + + #[inline] + fn size_hint(&self) -> (Option<uint>, Option<uint>) { + let (_, upper) = self.iter.size_hint(); + (None, upper) // can't know a lower bound, due to the predicate + } } /// An iterator which yields the current count and the element during iteration @@ -805,6 +943,34 @@ impl<'self, A, B, T: Iterator<A>, St> Iterator<B> for ScanIterator<'self, A, B, } } +/// An iterator that maps each element to an iterator, +/// and yields the elements of the produced iterators +/// +// FIXME #6967: Dummy B parameter to get around type inference bug +pub struct FlatMapIterator<'self, A, B, T, U> { + priv iter: T, + priv f: &'self fn(A) -> U, + priv subiter: Option<U>, +} + +impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for + FlatMapIterator<'self, A, B, T, U> { + #[inline] + fn next(&mut self) -> Option<B> { + loop { + for self.subiter.mut_iter().advance |inner| { + for inner.advance |x| { + return Some(x) + } + } + match self.iter.next().map_consume(|x| (self.f)(x)) { + None => return None, + next => self.subiter = next, + } + } + } +} + /// An iterator which just modifies the contained state throughout iteration. pub struct UnfoldrIterator<'self, A, St> { priv f: &'self fn(&mut St) -> Option<A>, @@ -816,7 +982,7 @@ impl<'self, A, St> UnfoldrIterator<'self, A, St> { /// Creates a new iterator with the specified closure as the "iterator /// function" and an initial state to eventually pass to the iterator #[inline] - pub fn new<'a>(f: &'a fn(&mut St) -> Option<A>, initial_state: St) + pub fn new<'a>(initial_state: St, f: &'a fn(&mut St) -> Option<A>) -> UnfoldrIterator<'a, A, St> { UnfoldrIterator { f: f, @@ -863,13 +1029,12 @@ mod tests { use super::*; use prelude::*; - use iter; use uint; #[test] fn test_counter_from_iter() { let mut it = Counter::new(0, 5).take_(10); - let xs: ~[int] = iter::FromIter::from_iter::<int, ~[int]>(|f| it.advance(f)); + let xs: ~[int] = FromIterator::from_iterator(&mut it); assert_eq!(xs, ~[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); } @@ -984,6 +1149,19 @@ mod tests { } #[test] + fn test_iterator_flat_map() { + let xs = [0u, 3, 6]; + let ys = [0u, 1, 2, 3, 4, 5, 6, 7, 8]; + let mut it = xs.iter().flat_map_(|&x| Counter::new(x, 1).take_(3)); + let mut i = 0; + for it.advance |x: uint| { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); + } + + #[test] fn test_unfoldr() { fn count(st: &mut uint) -> Option<uint> { if *st < 10 { @@ -995,7 +1173,7 @@ mod tests { } } - let mut it = UnfoldrIterator::new(count, 0); + let mut it = UnfoldrIterator::new(0, count); let mut i = 0; for it.advance |counted| { assert_eq!(counted, i); @@ -1020,11 +1198,11 @@ mod tests { } #[test] - fn test_iterator_count() { + fn test_iterator_len() { let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().count(), 4); - assert_eq!(v.slice(0, 10).iter().count(), 10); - assert_eq!(v.slice(0, 0).iter().count(), 0); + assert_eq!(v.slice(0, 4).iter().len_(), 4); + assert_eq!(v.slice(0, 10).iter().len_(), 10); + assert_eq!(v.slice(0, 0).iter().len_(), 0); } #[test] @@ -1099,4 +1277,24 @@ mod tests { assert_eq!(v.iter().position_(|x| *x % 3 == 0).unwrap(), 1); assert!(v.iter().position_(|x| *x % 12 == 0).is_none()); } + + #[test] + fn test_count() { + let xs = &[1, 2, 2, 1, 5, 9, 0, 2]; + assert_eq!(xs.iter().count(|x| *x == 2), 3); + assert_eq!(xs.iter().count(|x| *x == 5), 1); + assert_eq!(xs.iter().count(|x| *x == 95), 0); + } + + #[test] + fn test_max_by() { + let xs = [-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().max_by(|x| x.abs()).unwrap(), -10); + } + + #[test] + fn test_min_by() { + let xs = [-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0); + } } diff --git a/src/libstd/kinds.rs b/src/libstd/kinds.rs index 05c963a32cc..f350e106168 100644 --- a/src/libstd/kinds.rs +++ b/src/libstd/kinds.rs @@ -24,11 +24,10 @@ The 4 kinds are scalar types and managed pointers, and exludes owned pointers. It also excludes types that implement `Drop`. -* Owned - owned types and types containing owned types. These types +* Send - owned types and types containing owned types. These types may be transferred across task boundaries. -* Const - types that are deeply immutable. Const types are used for - freezable data structures. +* Freeze - types that are deeply immutable. `Copy` types include both implicitly copyable types that the compiler will copy automatically and non-implicitly copyable types that require @@ -44,14 +43,28 @@ pub trait Copy { // Empty. } +#[cfg(stage0)] #[lang="owned"] -pub trait Owned { - // Empty. +pub trait Send { + // empty. +} + +#[cfg(not(stage0))] +#[lang="send"] +pub trait Send { + // empty. } +#[cfg(stage0)] #[lang="const"] -pub trait Const { - // Empty. +pub trait Freeze { + // empty. +} + +#[cfg(not(stage0))] +#[lang="freeze"] +pub trait Freeze { + // empty. } #[lang="sized"] diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 07b2ac6ed01..f4ea29b5c05 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -102,10 +102,12 @@ pub use libc::funcs::posix88::stdio::*; pub use libc::funcs::posix88::fcntl::*; pub use libc::funcs::posix88::dirent::*; pub use libc::funcs::posix88::unistd::*; +pub use libc::funcs::posix88::mman::*; pub use libc::funcs::posix01::stat_::*; pub use libc::funcs::posix01::unistd::*; pub use libc::funcs::posix01::glob::*; +pub use libc::funcs::posix01::mman::*; pub use libc::funcs::posix08::unistd::*; pub use libc::funcs::bsd44::*; @@ -257,6 +259,8 @@ pub mod types { pub type intptr_t = int; pub type uintptr_t = uint; } + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "mips")] pub mod posix88 { pub type off_t = i32; pub type dev_t = u64; @@ -268,8 +272,22 @@ pub mod types { pub type mode_t = u32; pub type ssize_t = i32; } + #[cfg(target_arch = "arm")] + pub mod posix88 { + pub type off_t = i32; + pub type dev_t = u32; + pub type ino_t = u32; + pub type pid_t = i32; + pub type uid_t = u32; + pub type gid_t = u32; + pub type useconds_t = u32; + pub type mode_t = u16; + pub type ssize_t = i32; + } + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "mips")] pub mod posix01 { - use libc::types::os::arch::c95::{c_short, c_long, c_ulong, time_t}; + use libc::types::os::arch::c95::{c_short, c_long, time_t}; use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; use libc::types::os::arch::posix88::{mode_t, off_t}; use libc::types::os::arch::posix88::{uid_t}; @@ -279,7 +297,6 @@ pub mod types { pub type blkcnt_t = i32; #[cfg(target_arch = "x86")] - #[cfg(target_arch = "arm")] pub struct stat { st_dev: dev_t, __pad1: c_short, @@ -327,6 +344,38 @@ pub mod types { st_pad5: [c_long, ..14], } } + #[cfg(target_arch = "arm")] + pub mod posix01 { + use libc::types::os::arch::c95::{c_uchar, c_uint, c_ulong, time_t}; + use libc::types::os::arch::c99::{c_longlong, c_ulonglong}; + use libc::types::os::arch::posix88::{uid_t, gid_t, ino_t}; + + pub type nlink_t = u16; + pub type blksize_t = u32; + pub type blkcnt_t = u32; + + pub struct stat { + st_dev: c_ulonglong, + __pad0: [c_uchar, ..4], + __st_ino: ino_t, + st_mode: c_uint, + st_nlink: c_uint, + st_uid: uid_t, + st_gid: gid_t, + st_rdev: c_ulonglong, + __pad3: [c_uchar, ..4], + st_size: c_longlong, + st_blksize: blksize_t, + st_blocks: c_ulonglong, + st_atime: time_t, + st_atime_nsec: c_ulong, + st_mtime: time_t, + st_mtime_nsec: c_ulong, + st_ctime: time_t, + st_ctime_nsec: c_ulong, + st_ino: c_ulonglong + } + } pub mod posix08 {} pub mod bsd44 {} pub mod extra {} @@ -518,7 +567,7 @@ pub mod types { pub mod os { pub mod common { pub mod posix01 { - use libc::types::os::arch::c95::{c_int, c_short}; + use libc::types::os::arch::c95::c_short; use libc::types::os::arch::extra::{int64, time64_t}; use libc::types::os::arch::posix88::{dev_t, ino_t}; use libc::types::os::arch::posix88::mode_t; @@ -855,52 +904,56 @@ pub mod consts { #[cfg(target_os = "win32")] pub mod os { pub mod c95 { - pub static EXIT_FAILURE : int = 1; - pub static EXIT_SUCCESS : int = 0; - pub static RAND_MAX : int = 32767; - pub static EOF : int = -1; - pub static SEEK_SET : int = 0; - pub static SEEK_CUR : int = 1; - pub static SEEK_END : int = 2; - pub static _IOFBF : int = 0; - pub static _IONBF : int = 4; - pub static _IOLBF : int = 64; - pub static BUFSIZ : uint = 512_u; - pub static FOPEN_MAX : uint = 20_u; - pub static FILENAME_MAX : uint = 260_u; - pub static L_tmpnam : uint = 16_u; - pub static TMP_MAX : uint = 32767_u; + use libc::types::os::arch::c95::{c_int, c_uint}; + + pub static EXIT_FAILURE : c_int = 1; + pub static EXIT_SUCCESS : c_int = 0; + pub static RAND_MAX : c_int = 32767; + pub static EOF : c_int = -1; + pub static SEEK_SET : c_int = 0; + pub static SEEK_CUR : c_int = 1; + pub static SEEK_END : c_int = 2; + pub static _IOFBF : c_int = 0; + pub static _IONBF : c_int = 4; + pub static _IOLBF : c_int = 64; + pub static BUFSIZ : c_uint = 512_u32; + pub static FOPEN_MAX : c_uint = 20_u32; + pub static FILENAME_MAX : c_uint = 260_u32; + pub static L_tmpnam : c_uint = 16_u32; + pub static TMP_MAX : c_uint = 32767_u32; } pub mod c99 { } pub mod posix88 { - pub static O_RDONLY : int = 0; - pub static O_WRONLY : int = 1; - pub static O_RDWR : int = 2; - pub static O_APPEND : int = 8; - pub static O_CREAT : int = 256; - pub static O_EXCL : int = 1024; - pub static O_TRUNC : int = 512; - pub static S_IFIFO : int = 4096; - pub static S_IFCHR : int = 8192; - pub static S_IFBLK : int = 12288; - pub static S_IFDIR : int = 16384; - pub static S_IFREG : int = 32768; - pub static S_IFMT : int = 61440; - pub static S_IEXEC : int = 64; - pub static S_IWRITE : int = 128; - pub static S_IREAD : int = 256; - pub static S_IRWXU : int = 448; - pub static S_IXUSR : int = 64; - pub static S_IWUSR : int = 128; - pub static S_IRUSR : int = 256; - pub static F_OK : int = 0; - pub static R_OK : int = 4; - pub static W_OK : int = 2; - pub static X_OK : int = 1; - pub static STDIN_FILENO : int = 0; - pub static STDOUT_FILENO : int = 1; - pub static STDERR_FILENO : int = 2; + use libc::types::os::arch::c95::c_int; + + pub static O_RDONLY : c_int = 0; + pub static O_WRONLY : c_int = 1; + pub static O_RDWR : c_int = 2; + pub static O_APPEND : c_int = 8; + pub static O_CREAT : c_int = 256; + pub static O_EXCL : c_int = 1024; + pub static O_TRUNC : c_int = 512; + pub static S_IFIFO : c_int = 4096; + pub static S_IFCHR : c_int = 8192; + pub static S_IFBLK : c_int = 12288; + pub static S_IFDIR : c_int = 16384; + pub static S_IFREG : c_int = 32768; + pub static S_IFMT : c_int = 61440; + pub static S_IEXEC : c_int = 64; + pub static S_IWRITE : c_int = 128; + pub static S_IREAD : c_int = 256; + pub static S_IRWXU : c_int = 448; + pub static S_IXUSR : c_int = 64; + pub static S_IWUSR : c_int = 128; + pub static S_IRUSR : c_int = 256; + pub static F_OK : c_int = 0; + pub static R_OK : c_int = 4; + pub static W_OK : c_int = 2; + pub static X_OK : c_int = 1; + pub static STDIN_FILENO : c_int = 0; + pub static STDOUT_FILENO : c_int = 1; + pub static STDERR_FILENO : c_int = 2; } pub mod posix01 { } @@ -909,18 +962,19 @@ pub mod consts { pub mod bsd44 { } pub mod extra { + use libc::types::os::arch::c95::c_int; use libc::types::os::arch::extra::{DWORD, BOOL}; pub static TRUE : BOOL = 1; pub static FALSE : BOOL = 0; - pub static O_TEXT : int = 16384; - pub static O_BINARY : int = 32768; - pub static O_NOINHERIT: int = 128; + pub static O_TEXT : c_int = 16384; + pub static O_BINARY : c_int = 32768; + pub static O_NOINHERIT: c_int = 128; - pub static ERROR_SUCCESS : int = 0; - pub static ERROR_INSUFFICIENT_BUFFER : int = 122; - pub static INVALID_HANDLE_VALUE: int = -1; + pub static ERROR_SUCCESS : c_int = 0; + pub static ERROR_INSUFFICIENT_BUFFER : c_int = 122; + pub static INVALID_HANDLE_VALUE: c_int = -1; pub static DELETE : DWORD = 0x00010000; pub static READ_CONTROL : DWORD = 0x00020000; @@ -973,21 +1027,23 @@ pub mod consts { #[cfg(target_os = "android")] pub mod os { pub mod c95 { - pub static EXIT_FAILURE : int = 1; - pub static EXIT_SUCCESS : int = 0; - pub static RAND_MAX : int = 2147483647; - pub static EOF : int = -1; - pub static SEEK_SET : int = 0; - pub static SEEK_CUR : int = 1; - pub static SEEK_END : int = 2; - pub static _IOFBF : int = 0; - pub static _IONBF : int = 2; - pub static _IOLBF : int = 1; - pub static BUFSIZ : uint = 8192_u; - pub static FOPEN_MAX : uint = 16_u; - pub static FILENAME_MAX : uint = 4096_u; - pub static L_tmpnam : uint = 20_u; - pub static TMP_MAX : uint = 238328_u; + use libc::types::os::arch::c95::{c_int, c_uint}; + + pub static EXIT_FAILURE : c_int = 1; + pub static EXIT_SUCCESS : c_int = 0; + pub static RAND_MAX : c_int = 2147483647; + pub static EOF : c_int = -1; + pub static SEEK_SET : c_int = 0; + pub static SEEK_CUR : c_int = 1; + pub static SEEK_END : c_int = 2; + pub static _IOFBF : c_int = 0; + pub static _IONBF : c_int = 2; + pub static _IOLBF : c_int = 1; + pub static BUFSIZ : c_uint = 8192_u32; + pub static FOPEN_MAX : c_uint = 16_u32; + pub static FILENAME_MAX : c_uint = 4096_u32; + pub static L_tmpnam : c_uint = 20_u32; + pub static TMP_MAX : c_uint = 238328_u32; } pub mod c99 { } @@ -995,309 +1051,791 @@ pub mod consts { #[cfg(target_arch = "x86_64")] #[cfg(target_arch = "arm")] pub mod posix88 { - pub static O_RDONLY : int = 0; - pub static O_WRONLY : int = 1; - pub static O_RDWR : int = 2; - pub static O_APPEND : int = 1024; - pub static O_CREAT : int = 64; - pub static O_EXCL : int = 128; - pub static O_TRUNC : int = 512; - pub static S_IFIFO : int = 4096; - pub static S_IFCHR : int = 8192; - pub static S_IFBLK : int = 24576; - pub static S_IFDIR : int = 16384; - pub static S_IFREG : int = 32768; - pub static S_IFMT : int = 61440; - pub static S_IEXEC : int = 64; - pub static S_IWRITE : int = 128; - pub static S_IREAD : int = 256; - pub static S_IRWXU : int = 448; - pub static S_IXUSR : int = 64; - pub static S_IWUSR : int = 128; - pub static S_IRUSR : int = 256; - pub static F_OK : int = 0; - pub static R_OK : int = 4; - pub static W_OK : int = 2; - pub static X_OK : int = 1; - pub static STDIN_FILENO : int = 0; - pub static STDOUT_FILENO : int = 1; - pub static STDERR_FILENO : int = 2; - pub static F_LOCK : int = 1; - pub static F_TEST : int = 3; - pub static F_TLOCK : int = 2; - pub static F_ULOCK : int = 0; - pub static SIGHUP : int = 1; - pub static SIGINT : int = 2; - pub static SIGQUIT : int = 3; - pub static SIGILL : int = 4; - pub static SIGABRT : int = 6; - pub static SIGFPE : int = 8; - pub static SIGKILL : int = 9; - pub static SIGSEGV : int = 11; - pub static SIGPIPE : int = 13; - pub static SIGALRM : int = 14; - pub static SIGTERM : int = 15; + use libc::types::os::arch::c95::c_int; + use libc::types::common::c95::c_void; + + pub static O_RDONLY : c_int = 0; + pub static O_WRONLY : c_int = 1; + pub static O_RDWR : c_int = 2; + pub static O_APPEND : c_int = 1024; + pub static O_CREAT : c_int = 64; + pub static O_EXCL : c_int = 128; + pub static O_TRUNC : c_int = 512; + pub static S_IFIFO : c_int = 4096; + pub static S_IFCHR : c_int = 8192; + pub static S_IFBLK : c_int = 24576; + pub static S_IFDIR : c_int = 16384; + pub static S_IFREG : c_int = 32768; + pub static S_IFMT : c_int = 61440; + pub static S_IEXEC : c_int = 64; + pub static S_IWRITE : c_int = 128; + pub static S_IREAD : c_int = 256; + pub static S_IRWXU : c_int = 448; + pub static S_IXUSR : c_int = 64; + pub static S_IWUSR : c_int = 128; + pub static S_IRUSR : c_int = 256; + pub static F_OK : c_int = 0; + pub static R_OK : c_int = 4; + pub static W_OK : c_int = 2; + pub static X_OK : c_int = 1; + pub static STDIN_FILENO : c_int = 0; + pub static STDOUT_FILENO : c_int = 1; + pub static STDERR_FILENO : c_int = 2; + pub static F_LOCK : c_int = 1; + pub static F_TEST : c_int = 3; + pub static F_TLOCK : c_int = 2; + pub static F_ULOCK : c_int = 0; + pub static SIGHUP : c_int = 1; + pub static SIGINT : c_int = 2; + pub static SIGQUIT : c_int = 3; + pub static SIGILL : c_int = 4; + pub static SIGABRT : c_int = 6; + pub static SIGFPE : c_int = 8; + pub static SIGKILL : c_int = 9; + pub static SIGSEGV : c_int = 11; + pub static SIGPIPE : c_int = 13; + pub static SIGALRM : c_int = 14; + pub static SIGTERM : c_int = 15; + + pub static PROT_NONE : c_int = 0; + pub static PROT_READ : c_int = 1; + pub static PROT_WRITE : c_int = 2; + pub static PROT_EXEC : c_int = 4; + + pub static MAP_FILE : c_int = 0x0000; + pub static MAP_SHARED : c_int = 0x0001; + pub static MAP_PRIVATE : c_int = 0x0002; + pub static MAP_FIXED : c_int = 0x0010; + pub static MAP_ANON : c_int = 0x1000; + + pub static MAP_FAILED : *c_void = -1 as *c_void; + + pub static MCL_CURRENT : c_int = 0x0001; + pub static MCL_FUTURE : c_int = 0x0002; + + pub static MS_ASYNC : c_int = 0x0001; + pub static MS_INVALIDATE : c_int = 0x0002; + pub static MS_SYNC : c_int = 0x0004; } #[cfg(target_arch = "mips")] pub mod posix88 { - pub static O_RDONLY : int = 0; - pub static O_WRONLY : int = 1; - pub static O_RDWR : int = 2; - pub static O_APPEND : int = 8; - pub static O_CREAT : int = 256; - pub static O_EXCL : int = 1024; - pub static O_TRUNC : int = 512; - pub static S_IFIFO : int = 4096; - pub static S_IFCHR : int = 8192; - pub static S_IFBLK : int = 24576; - pub static S_IFDIR : int = 16384; - pub static S_IFREG : int = 32768; - pub static S_IFMT : int = 61440; - pub static S_IEXEC : int = 64; - pub static S_IWRITE : int = 128; - pub static S_IREAD : int = 256; - pub static S_IRWXU : int = 448; - pub static S_IXUSR : int = 64; - pub static S_IWUSR : int = 128; - pub static S_IRUSR : int = 256; - pub static F_OK : int = 0; - pub static R_OK : int = 4; - pub static W_OK : int = 2; - pub static X_OK : int = 1; - pub static STDIN_FILENO : int = 0; - pub static STDOUT_FILENO : int = 1; - pub static STDERR_FILENO : int = 2; - pub static F_LOCK : int = 1; - pub static F_TEST : int = 3; - pub static F_TLOCK : int = 2; - pub static F_ULOCK : int = 0; - pub static SIGHUP : int = 1; - pub static SIGINT : int = 2; - pub static SIGQUIT : int = 3; - pub static SIGILL : int = 4; - pub static SIGABRT : int = 6; - pub static SIGFPE : int = 8; - pub static SIGKILL : int = 9; - pub static SIGSEGV : int = 11; - pub static SIGPIPE : int = 13; - pub static SIGALRM : int = 14; - pub static SIGTERM : int = 15; + use libc::types::os::arch::c95::c_int; + use libc::types::common::c95::c_void; + + pub static O_RDONLY : c_int = 0; + pub static O_WRONLY : c_int = 1; + pub static O_RDWR : c_int = 2; + pub static O_APPEND : c_int = 8; + pub static O_CREAT : c_int = 256; + pub static O_EXCL : c_int = 1024; + pub static O_TRUNC : c_int = 512; + pub static S_IFIFO : c_int = 4096; + pub static S_IFCHR : c_int = 8192; + pub static S_IFBLK : c_int = 24576; + pub static S_IFDIR : c_int = 16384; + pub static S_IFREG : c_int = 32768; + pub static S_IFMT : c_int = 61440; + pub static S_IEXEC : c_int = 64; + pub static S_IWRITE : c_int = 128; + pub static S_IREAD : c_int = 256; + pub static S_IRWXU : c_int = 448; + pub static S_IXUSR : c_int = 64; + pub static S_IWUSR : c_int = 128; + pub static S_IRUSR : c_int = 256; + pub static F_OK : c_int = 0; + pub static R_OK : c_int = 4; + pub static W_OK : c_int = 2; + pub static X_OK : c_int = 1; + pub static STDIN_FILENO : c_int = 0; + pub static STDOUT_FILENO : c_int = 1; + pub static STDERR_FILENO : c_int = 2; + pub static F_LOCK : c_int = 1; + pub static F_TEST : c_int = 3; + pub static F_TLOCK : c_int = 2; + pub static F_ULOCK : c_int = 0; + pub static SIGHUP : c_int = 1; + pub static SIGINT : c_int = 2; + pub static SIGQUIT : c_int = 3; + pub static SIGILL : c_int = 4; + pub static SIGABRT : c_int = 6; + pub static SIGFPE : c_int = 8; + pub static SIGKILL : c_int = 9; + pub static SIGSEGV : c_int = 11; + pub static SIGPIPE : c_int = 13; + pub static SIGALRM : c_int = 14; + pub static SIGTERM : c_int = 15; + + pub static PROT_NONE : c_int = 0; + pub static PROT_READ : c_int = 1; + pub static PROT_WRITE : c_int = 2; + pub static PROT_EXEC : c_int = 4; + + pub static MAP_FILE : c_int = 0x0000; + pub static MAP_SHARED : c_int = 0x0001; + pub static MAP_PRIVATE : c_int = 0x0002; + pub static MAP_FIXED : c_int = 0x0010; + pub static MAP_ANON : c_int = 0x1000; + + pub static MAP_FAILED : *c_void = -1 as *c_void; + + pub static MCL_CURRENT : c_int = 0x0001; + pub static MCL_FUTURE : c_int = 0x0002; + + pub static MS_ASYNC : c_int = 0x0001; + pub static MS_INVALIDATE : c_int = 0x0002; + pub static MS_SYNC : c_int = 0x0004; + + pub static _SC_ARG_MAX : c_int = 0; + pub static _SC_CHILD_MAX : c_int = 1; + pub static _SC_CLK_TCK : c_int = 2; + pub static _SC_NGROUPS_MAX : c_int = 3; + pub static _SC_OPEN_MAX : c_int = 4; + pub static _SC_STREAM_MAX : c_int = 5; + pub static _SC_TZNAME_MAX : c_int = 6; + pub static _SC_JOB_CONTROL : c_int = 7; + pub static _SC_SAVED_IDS : c_int = 8; + pub static _SC_REALTIME_SIGNALS : c_int = 9; + pub static _SC_PRIORITY_SCHEDULING : c_int = 10; + pub static _SC_TIMERS : c_int = 11; + pub static _SC_ASYNCHRONOUS_IO : c_int = 12; + pub static _SC_PRIORITIZED_IO : c_int = 13; + pub static _SC_SYNCHRONIZED_IO : c_int = 14; + pub static _SC_FSYNC : c_int = 15; + pub static _SC_MAPPED_FILES : c_int = 16; + pub static _SC_MEMLOCK : c_int = 17; + pub static _SC_MEMLOCK_RANGE : c_int = 18; + pub static _SC_MEMORY_PROTECTION : c_int = 19; + pub static _SC_MESSAGE_PASSING : c_int = 20; + pub static _SC_SEMAPHORES : c_int = 21; + pub static _SC_SHARED_MEMORY_OBJECTS : c_int = 22; + pub static _SC_AIO_LISTIO_MAX : c_int = 23; + pub static _SC_AIO_MAX : c_int = 24; + pub static _SC_AIO_PRIO_DELTA_MAX : c_int = 25; + pub static _SC_DELAYTIMER_MAX : c_int = 26; + pub static _SC_MQ_OPEN_MAX : c_int = 27; + pub static _SC_VERSION : c_int = 29; + pub static _SC_PAGESIZE : c_int = 30; + pub static _SC_RTSIG_MAX : c_int = 31; + pub static _SC_SEM_NSEMS_MAX : c_int = 32; + pub static _SC_SEM_VALUE_MAX : c_int = 33; + pub static _SC_SIGQUEUE_MAX : c_int = 34; + pub static _SC_TIMER_MAX : c_int = 35; + pub static _SC_BC_BASE_MAX : c_int = 36; + pub static _SC_BC_DIM_MAX : c_int = 37; + pub static _SC_BC_SCALE_MAX : c_int = 38; + pub static _SC_BC_STRING_MAX : c_int = 39; + pub static _SC_COLL_WEIGHTS_MAX : c_int = 40; + pub static _SC_EXPR_NEST_MAX : c_int = 42; + pub static _SC_LINE_MAX : c_int = 43; + pub static _SC_RE_DUP_MAX : c_int = 44; + pub static _SC_2_VERSION : c_int = 46; + pub static _SC_2_C_BIND : c_int = 47; + pub static _SC_2_C_DEV : c_int = 48; + pub static _SC_2_FORT_DEV : c_int = 49; + pub static _SC_2_FORT_RUN : c_int = 50; + pub static _SC_2_SW_DEV : c_int = 51; + pub static _SC_2_LOCALEDEF : c_int = 52; + pub static _SC_2_CHAR_TERM : c_int = 95; + pub static _SC_2_C_VERSION : c_int = 96; + pub static _SC_2_UPE : c_int = 97; + pub static _SC_XBS5_ILP32_OFF32 : c_int = 125; + pub static _SC_XBS5_ILP32_OFFBIG : c_int = 126; + pub static _SC_XBS5_LPBIG_OFFBIG : c_int = 128; } pub mod posix01 { - pub static SIGTRAP : int = 5; - - pub static GLOB_ERR : int = 1 << 0; - pub static GLOB_MARK : int = 1 << 1; - pub static GLOB_NOSORT : int = 1 << 2; - pub static GLOB_DOOFFS : int = 1 << 3; - pub static GLOB_NOCHECK : int = 1 << 4; - pub static GLOB_APPEND : int = 1 << 5; - pub static GLOB_NOESCAPE : int = 1 << 6; - - pub static GLOB_NOSPACE : int = 1; - pub static GLOB_ABORTED : int = 2; - pub static GLOB_NOMATCH : int = 3; + use libc::types::os::arch::c95::c_int; + + pub static SIGTRAP : c_int = 5; + + pub static GLOB_ERR : c_int = 1 << 0; + pub static GLOB_MARK : c_int = 1 << 1; + pub static GLOB_NOSORT : c_int = 1 << 2; + pub static GLOB_DOOFFS : c_int = 1 << 3; + pub static GLOB_NOCHECK : c_int = 1 << 4; + pub static GLOB_APPEND : c_int = 1 << 5; + pub static GLOB_NOESCAPE : c_int = 1 << 6; + + pub static GLOB_NOSPACE : c_int = 1; + pub static GLOB_ABORTED : c_int = 2; + pub static GLOB_NOMATCH : c_int = 3; + + pub static POSIX_MADV_NORMAL : c_int = 0; + pub static POSIX_MADV_RANDOM : c_int = 1; + pub static POSIX_MADV_SEQUENTIAL : c_int = 2; + pub static POSIX_MADV_WILLNEED : c_int = 3; + pub static POSIX_MADV_DONTNEED : c_int = 4; + + pub static _SC_MQ_PRIO_MAX : c_int = 28; + pub static _SC_IOV_MAX : c_int = 60; + pub static _SC_GETGR_R_SIZE_MAX : c_int = 69; + pub static _SC_GETPW_R_SIZE_MAX : c_int = 70; + pub static _SC_LOGIN_NAME_MAX : c_int = 71; + pub static _SC_TTY_NAME_MAX : c_int = 72; + pub static _SC_THREADS : c_int = 67; + pub static _SC_THREAD_SAFE_FUNCTIONS : c_int = 68; + pub static _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 73; + pub static _SC_THREAD_KEYS_MAX : c_int = 74; + pub static _SC_THREAD_STACK_MIN : c_int = 75; + pub static _SC_THREAD_THREADS_MAX : c_int = 76; + pub static _SC_THREAD_ATTR_STACKADDR : c_int = 77; + pub static _SC_THREAD_ATTR_STACKSIZE : c_int = 78; + pub static _SC_THREAD_PRIORITY_SCHEDULING : c_int = 79; + pub static _SC_THREAD_PRIO_INHERIT : c_int = 80; + pub static _SC_THREAD_PRIO_PROTECT : c_int = 81; + pub static _SC_THREAD_PROCESS_SHARED : c_int = 82; + pub static _SC_ATEXIT_MAX : c_int = 87; + pub static _SC_XOPEN_VERSION : c_int = 89; + pub static _SC_XOPEN_XCU_VERSION : c_int = 90; + pub static _SC_XOPEN_UNIX : c_int = 91; + pub static _SC_XOPEN_CRYPT : c_int = 92; + pub static _SC_XOPEN_ENH_I18N : c_int = 93; + pub static _SC_XOPEN_SHM : c_int = 94; + pub static _SC_XOPEN_LEGACY : c_int = 129; + pub static _SC_XOPEN_REALTIME : c_int = 130; + pub static _SC_XOPEN_REALTIME_THREADS : c_int = 131; } pub mod posix08 { } pub mod bsd44 { + use libc::types::os::arch::c95::c_int; + + pub static MADV_NORMAL : c_int = 0; + pub static MADV_RANDOM : c_int = 1; + pub static MADV_SEQUENTIAL : c_int = 2; + pub static MADV_WILLNEED : c_int = 3; + pub static MADV_DONTNEED : c_int = 4; + pub static MADV_REMOVE : c_int = 9; + pub static MADV_DONTFORK : c_int = 10; + pub static MADV_DOFORK : c_int = 11; + pub static MADV_MERGEABLE : c_int = 12; + pub static MADV_UNMERGEABLE : c_int = 13; + pub static MADV_HWPOISON : c_int = 100; } #[cfg(target_arch = "x86")] #[cfg(target_arch = "x86_64")] #[cfg(target_arch = "arm")] pub mod extra { - pub static O_RSYNC : int = 1052672; - pub static O_DSYNC : int = 4096; - pub static O_SYNC : int = 1052672; + use libc::types::os::arch::c95::c_int; + + pub static O_RSYNC : c_int = 1052672; + pub static O_DSYNC : c_int = 4096; + pub static O_SYNC : c_int = 1052672; + + pub static PROT_GROWSDOWN : c_int = 0x010000000; + pub static PROT_GROWSUP : c_int = 0x020000000; + + pub static MAP_TYPE : c_int = 0x000f; + pub static MAP_ANONONYMOUS : c_int = 0x1000; + pub static MAP_32BIT : c_int = 0x0040; + pub static MAP_GROWSDOWN : c_int = 0x0100; + pub static MAP_DENYWRITE : c_int = 0x0800; + pub static MAP_EXECUTABLE : c_int = 0x01000; + pub static MAP_LOCKED : c_int = 0x02000; + pub static MAP_NONRESERVE : c_int = 0x04000; + pub static MAP_POPULATE : c_int = 0x08000; + pub static MAP_NONBLOCK : c_int = 0x010000; + pub static MAP_STACK : c_int = 0x020000; } #[cfg(target_arch = "mips")] pub mod extra { - pub static O_RSYNC : int = 16400; - pub static O_DSYNC : int = 16; - pub static O_SYNC : int = 16400; + use libc::types::os::arch::c95::c_int; + + pub static O_RSYNC : c_int = 16400; + pub static O_DSYNC : c_int = 16; + pub static O_SYNC : c_int = 16400; + + pub static PROT_GROWSDOWN : c_int = 0x010000000; + pub static PROT_GROWSUP : c_int = 0x020000000; + + pub static MAP_TYPE : c_int = 0x000f; + pub static MAP_ANONONYMOUS : c_int = 0x1000; + pub static MAP_32BIT : c_int = 0x0040; + pub static MAP_GROWSDOWN : c_int = 0x0100; + pub static MAP_DENYWRITE : c_int = 0x0800; + pub static MAP_EXECUTABLE : c_int = 0x01000; + pub static MAP_LOCKED : c_int = 0x02000; + pub static MAP_NONRESERVE : c_int = 0x04000; + pub static MAP_POPULATE : c_int = 0x08000; + pub static MAP_NONBLOCK : c_int = 0x010000; + pub static MAP_STACK : c_int = 0x020000; } } #[cfg(target_os = "freebsd")] pub mod os { pub mod c95 { - pub static EXIT_FAILURE : int = 1; - pub static EXIT_SUCCESS : int = 0; - pub static RAND_MAX : int = 2147483647; - pub static EOF : int = -1; - pub static SEEK_SET : int = 0; - pub static SEEK_CUR : int = 1; - pub static SEEK_END : int = 2; - pub static _IOFBF : int = 0; - pub static _IONBF : int = 2; - pub static _IOLBF : int = 1; - pub static BUFSIZ : uint = 1024_u; - pub static FOPEN_MAX : uint = 20_u; - pub static FILENAME_MAX : uint = 1024_u; - pub static L_tmpnam : uint = 1024_u; - pub static TMP_MAX : uint = 308915776_u; + use libc::types::os::arch::c95::{c_int, c_uint}; + + pub static EXIT_FAILURE : c_int = 1; + pub static EXIT_SUCCESS : c_int = 0; + pub static RAND_MAX : c_int = 2147483647; + pub static EOF : c_int = -1; + pub static SEEK_SET : c_int = 0; + pub static SEEK_CUR : c_int = 1; + pub static SEEK_END : c_int = 2; + pub static _IOFBF : c_int = 0; + pub static _IONBF : c_int = 2; + pub static _IOLBF : c_int = 1; + pub static BUFSIZ : c_uint = 1024_u32; + pub static FOPEN_MAX : c_uint = 20_u32; + pub static FILENAME_MAX : c_uint = 1024_u32; + pub static L_tmpnam : c_uint = 1024_u32; + pub static TMP_MAX : c_uint = 308915776_u32; } pub mod c99 { } pub mod posix88 { - pub static O_RDONLY : int = 0; - pub static O_WRONLY : int = 1; - pub static O_RDWR : int = 2; - pub static O_APPEND : int = 8; - pub static O_CREAT : int = 512; - pub static O_EXCL : int = 2048; - pub static O_TRUNC : int = 1024; - pub static S_IFIFO : int = 4096; - pub static S_IFCHR : int = 8192; - pub static S_IFBLK : int = 24576; - pub static S_IFDIR : int = 16384; - pub static S_IFREG : int = 32768; - pub static S_IFMT : int = 61440; - pub static S_IEXEC : int = 64; - pub static S_IWRITE : int = 128; - pub static S_IREAD : int = 256; - pub static S_IRWXU : int = 448; - pub static S_IXUSR : int = 64; - pub static S_IWUSR : int = 128; - pub static S_IRUSR : int = 256; - pub static F_OK : int = 0; - pub static R_OK : int = 4; - pub static W_OK : int = 2; - pub static X_OK : int = 1; - pub static STDIN_FILENO : int = 0; - pub static STDOUT_FILENO : int = 1; - pub static STDERR_FILENO : int = 2; - pub static F_LOCK : int = 1; - pub static F_TEST : int = 3; - pub static F_TLOCK : int = 2; - pub static F_ULOCK : int = 0; - pub static SIGHUP : int = 1; - pub static SIGINT : int = 2; - pub static SIGQUIT : int = 3; - pub static SIGILL : int = 4; - pub static SIGABRT : int = 6; - pub static SIGFPE : int = 8; - pub static SIGKILL : int = 9; - pub static SIGSEGV : int = 11; - pub static SIGPIPE : int = 13; - pub static SIGALRM : int = 14; - pub static SIGTERM : int = 15; + use libc::types::common::c95::c_void; + use libc::types::os::arch::c95::c_int; + + pub static O_RDONLY : c_int = 0; + pub static O_WRONLY : c_int = 1; + pub static O_RDWR : c_int = 2; + pub static O_APPEND : c_int = 8; + pub static O_CREAT : c_int = 512; + pub static O_EXCL : c_int = 2048; + pub static O_TRUNC : c_int = 1024; + pub static S_IFIFO : c_int = 4096; + pub static S_IFCHR : c_int = 8192; + pub static S_IFBLK : c_int = 24576; + pub static S_IFDIR : c_int = 16384; + pub static S_IFREG : c_int = 32768; + pub static S_IFMT : c_int = 61440; + pub static S_IEXEC : c_int = 64; + pub static S_IWRITE : c_int = 128; + pub static S_IREAD : c_int = 256; + pub static S_IRWXU : c_int = 448; + pub static S_IXUSR : c_int = 64; + pub static S_IWUSR : c_int = 128; + pub static S_IRUSR : c_int = 256; + pub static F_OK : c_int = 0; + pub static R_OK : c_int = 4; + pub static W_OK : c_int = 2; + pub static X_OK : c_int = 1; + pub static STDIN_FILENO : c_int = 0; + pub static STDOUT_FILENO : c_int = 1; + pub static STDERR_FILENO : c_int = 2; + pub static F_LOCK : c_int = 1; + pub static F_TEST : c_int = 3; + pub static F_TLOCK : c_int = 2; + pub static F_ULOCK : c_int = 0; + pub static SIGHUP : c_int = 1; + pub static SIGINT : c_int = 2; + pub static SIGQUIT : c_int = 3; + pub static SIGILL : c_int = 4; + pub static SIGABRT : c_int = 6; + pub static SIGFPE : c_int = 8; + pub static SIGKILL : c_int = 9; + pub static SIGSEGV : c_int = 11; + pub static SIGPIPE : c_int = 13; + pub static SIGALRM : c_int = 14; + pub static SIGTERM : c_int = 15; + + pub static PROT_NONE : c_int = 0; + pub static PROT_READ : c_int = 1; + pub static PROT_WRITE : c_int = 2; + pub static PROT_EXEC : c_int = 4; + + pub static MAP_FILE : c_int = 0x0000; + pub static MAP_SHARED : c_int = 0x0001; + pub static MAP_PRIVATE : c_int = 0x0002; + pub static MAP_FIXED : c_int = 0x0010; + pub static MAP_ANON : c_int = 0x1000; + + pub static MAP_FAILED : *c_void = -1 as *c_void; + + pub static MCL_CURRENT : c_int = 0x0001; + pub static MCL_FUTURE : c_int = 0x0002; + + pub static MS_SYNC : c_int = 0x0000; + pub static MS_ASYNC : c_int = 0x0001; + pub static MS_INVALIDATE : c_int = 0x0002; + + pub static _SC_ARG_MAX : c_int = 1; + pub static _SC_CHILD_MAX : c_int = 2; + pub static _SC_CLK_TCK : c_int = 3; + pub static _SC_NGROUPS_MAX : c_int = 4; + pub static _SC_OPEN_MAX : c_int = 5; + pub static _SC_JOB_CONTROL : c_int = 6; + pub static _SC_SAVED_IDS : c_int = 7; + pub static _SC_VERSION : c_int = 8; + pub static _SC_BC_BASE_MAX : c_int = 9; + pub static _SC_BC_DIM_MAX : c_int = 10; + pub static _SC_BC_SCALE_MAX : c_int = 11; + pub static _SC_BC_STRING_MAX : c_int = 12; + pub static _SC_COLL_WEIGHTS_MAX : c_int = 13; + pub static _SC_EXPR_NEST_MAX : c_int = 14; + pub static _SC_LINE_MAX : c_int = 15; + pub static _SC_RE_DUP_MAX : c_int = 16; + pub static _SC_2_VERSION : c_int = 17; + pub static _SC_2_C_BIND : c_int = 18; + pub static _SC_2_C_DEV : c_int = 19; + pub static _SC_2_CHAR_TERM : c_int = 20; + pub static _SC_2_FORT_DEV : c_int = 21; + pub static _SC_2_FORT_RUN : c_int = 22; + pub static _SC_2_LOCALEDEF : c_int = 23; + pub static _SC_2_SW_DEV : c_int = 24; + pub static _SC_2_UPE : c_int = 25; + pub static _SC_STREAM_MAX : c_int = 26; + pub static _SC_TZNAME_MAX : c_int = 27; + pub static _SC_ASYNCHRONOUS_IO : c_int = 28; + pub static _SC_MAPPED_FILES : c_int = 29; + pub static _SC_MEMLOCK : c_int = 30; + pub static _SC_MEMLOCK_RANGE : c_int = 31; + pub static _SC_MEMORY_PROTECTION : c_int = 32; + pub static _SC_MESSAGE_PASSING : c_int = 33; + pub static _SC_PRIORITIZED_IO : c_int = 34; + pub static _SC_PRIORITY_SCHEDULING : c_int = 35; + pub static _SC_REALTIME_SIGNALS : c_int = 36; + pub static _SC_SEMAPHORES : c_int = 37; + pub static _SC_FSYNC : c_int = 38; + pub static _SC_SHARED_MEMORY_OBJECTS : c_int = 39; + pub static _SC_SYNCHRONIZED_IO : c_int = 40; + pub static _SC_TIMERS : c_int = 41; + pub static _SC_AIO_LISTIO_MAX : c_int = 42; + pub static _SC_AIO_MAX : c_int = 43; + pub static _SC_AIO_PRIO_DELTA_MAX : c_int = 44; + pub static _SC_DELAYTIMER_MAX : c_int = 45; + pub static _SC_MQ_OPEN_MAX : c_int = 46; + pub static _SC_PAGESIZE : c_int = 47; + pub static _SC_RTSIG_MAX : c_int = 48; + pub static _SC_SEM_NSEMS_MAX : c_int = 49; + pub static _SC_SEM_VALUE_MAX : c_int = 50; + pub static _SC_SIGQUEUE_MAX : c_int = 51; + pub static _SC_TIMER_MAX : c_int = 52; } pub mod posix01 { - pub static SIGTRAP : int = 5; - - pub static GLOB_APPEND : int = 0x0001; - pub static GLOB_DOOFFS : int = 0x0002; - pub static GLOB_ERR : int = 0x0004; - pub static GLOB_MARK : int = 0x0008; - pub static GLOB_NOCHECK : int = 0x0010; - pub static GLOB_NOSORT : int = 0x0020; - pub static GLOB_NOESCAPE : int = 0x2000; - - pub static GLOB_NOSPACE : int = -1; - pub static GLOB_ABORTED : int = -2; - pub static GLOB_NOMATCH : int = -3; + use libc::types::os::arch::c95::c_int; + + pub static SIGTRAP : c_int = 5; + + pub static GLOB_APPEND : c_int = 0x0001; + pub static GLOB_DOOFFS : c_int = 0x0002; + pub static GLOB_ERR : c_int = 0x0004; + pub static GLOB_MARK : c_int = 0x0008; + pub static GLOB_NOCHECK : c_int = 0x0010; + pub static GLOB_NOSORT : c_int = 0x0020; + pub static GLOB_NOESCAPE : c_int = 0x2000; + + pub static GLOB_NOSPACE : c_int = -1; + pub static GLOB_ABORTED : c_int = -2; + pub static GLOB_NOMATCH : c_int = -3; + + pub static POSIX_MADV_NORMAL : c_int = 0; + pub static POSIX_MADV_RANDOM : c_int = 1; + pub static POSIX_MADV_SEQUENTIAL : c_int = 2; + pub static POSIX_MADV_WILLNEED : c_int = 3; + pub static POSIX_MADV_DONTNEED : c_int = 4; + + pub static _SC_IOV_MAX : c_int = 56; + pub static _SC_GETGR_R_SIZE_MAX : c_int = 70; + pub static _SC_GETPW_R_SIZE_MAX : c_int = 71; + pub static _SC_LOGIN_NAME_MAX : c_int = 73; + pub static _SC_MQ_PRIO_MAX : c_int = 75; + pub static _SC_THREAD_ATTR_STACKADDR : c_int = 82; + pub static _SC_THREAD_ATTR_STACKSIZE : c_int = 83; + pub static _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 85; + pub static _SC_THREAD_KEYS_MAX : c_int = 86; + pub static _SC_THREAD_PRIO_INHERIT : c_int = 87; + pub static _SC_THREAD_PRIO_PROTECT : c_int = 88; + pub static _SC_THREAD_PRIORITY_SCHEDULING : c_int = 89; + pub static _SC_THREAD_PROCESS_SHARED : c_int = 90; + pub static _SC_THREAD_SAFE_FUNCTIONS : c_int = 91; + pub static _SC_THREAD_STACK_MIN : c_int = 93; + pub static _SC_THREAD_THREADS_MAX : c_int = 94; + pub static _SC_THREADS : c_int = 96; + pub static _SC_TTY_NAME_MAX : c_int = 101; + pub static _SC_ATEXIT_MAX : c_int = 107; + pub static _SC_XOPEN_CRYPT : c_int = 108; + pub static _SC_XOPEN_ENH_I18N : c_int = 109; + pub static _SC_XOPEN_LEGACY : c_int = 110; + pub static _SC_XOPEN_REALTIME : c_int = 111; + pub static _SC_XOPEN_REALTIME_THREADS : c_int = 112; + pub static _SC_XOPEN_SHM : c_int = 113; + pub static _SC_XOPEN_UNIX : c_int = 115; + pub static _SC_XOPEN_VERSION : c_int = 116; + pub static _SC_XOPEN_XCU_VERSION : c_int = 117; } pub mod posix08 { } pub mod bsd44 { + use libc::types::os::arch::c95::c_int; + + pub static MADV_NORMAL : c_int = 0; + pub static MADV_RANDOM : c_int = 1; + pub static MADV_SEQUENTIAL : c_int = 2; + pub static MADV_WILLNEED : c_int = 3; + pub static MADV_DONTNEED : c_int = 4; + pub static MADV_FREE : c_int = 5; + pub static MADV_NOSYNC : c_int = 6; + pub static MADV_AUTOSYNC : c_int = 7; + pub static MADV_NOCORE : c_int = 8; + pub static MADV_CORE : c_int = 9; + pub static MADV_PROTECT : c_int = 10; + + pub static MINCORE_INCORE : c_int = 0x1; + pub static MINCORE_REFERENCED : c_int = 0x2; + pub static MINCORE_MODIFIED : c_int = 0x4; + pub static MINCORE_REFERENCED_OTHER : c_int = 0x8; + pub static MINCORE_MODIFIED_OTHER : c_int = 0x10; + pub static MINCORE_SUPER : c_int = 0x20; } pub mod extra { - pub static O_SYNC : int = 128; - pub static CTL_KERN: int = 1; - pub static KERN_PROC: int = 14; - pub static KERN_PROC_PATHNAME: int = 12; + use libc::types::os::arch::c95::c_int; + + pub static O_SYNC : c_int = 128; + pub static CTL_KERN: c_int = 1; + pub static KERN_PROC: c_int = 14; + pub static KERN_PROC_PATHNAME: c_int = 12; + + pub static MAP_COPY : c_int = 0x0002; + pub static MAP_RENAME : c_int = 0x0020; + pub static MAP_NORESERVE : c_int = 0x0040; + pub static MAP_HASSEMAPHORE : c_int = 0x0200; + pub static MAP_STACK : c_int = 0x0400; + pub static MAP_NOSYNC : c_int = 0x0800; + pub static MAP_NOCORE : c_int = 0x020000; } } #[cfg(target_os = "macos")] pub mod os { pub mod c95 { - pub static EXIT_FAILURE : int = 1; - pub static EXIT_SUCCESS : int = 0; - pub static RAND_MAX : int = 2147483647; - pub static EOF : int = -1; - pub static SEEK_SET : int = 0; - pub static SEEK_CUR : int = 1; - pub static SEEK_END : int = 2; - pub static _IOFBF : int = 0; - pub static _IONBF : int = 2; - pub static _IOLBF : int = 1; - pub static BUFSIZ : uint = 1024_u; - pub static FOPEN_MAX : uint = 20_u; - pub static FILENAME_MAX : uint = 1024_u; - pub static L_tmpnam : uint = 1024_u; - pub static TMP_MAX : uint = 308915776_u; + use libc::types::os::arch::c95::{c_int, c_uint}; + + pub static EXIT_FAILURE : c_int = 1; + pub static EXIT_SUCCESS : c_int = 0; + pub static RAND_MAX : c_int = 2147483647; + pub static EOF : c_int = -1; + pub static SEEK_SET : c_int = 0; + pub static SEEK_CUR : c_int = 1; + pub static SEEK_END : c_int = 2; + pub static _IOFBF : c_int = 0; + pub static _IONBF : c_int = 2; + pub static _IOLBF : c_int = 1; + pub static BUFSIZ : c_uint = 1024_u32; + pub static FOPEN_MAX : c_uint = 20_u32; + pub static FILENAME_MAX : c_uint = 1024_u32; + pub static L_tmpnam : c_uint = 1024_u32; + pub static TMP_MAX : c_uint = 308915776_u32; } pub mod c99 { } pub mod posix88 { - pub static O_RDONLY : int = 0; - pub static O_WRONLY : int = 1; - pub static O_RDWR : int = 2; - pub static O_APPEND : int = 8; - pub static O_CREAT : int = 512; - pub static O_EXCL : int = 2048; - pub static O_TRUNC : int = 1024; - pub static S_IFIFO : int = 4096; - pub static S_IFCHR : int = 8192; - pub static S_IFBLK : int = 24576; - pub static S_IFDIR : int = 16384; - pub static S_IFREG : int = 32768; - pub static S_IFMT : int = 61440; - pub static S_IEXEC : int = 64; - pub static S_IWRITE : int = 128; - pub static S_IREAD : int = 256; - pub static S_IRWXU : int = 448; - pub static S_IXUSR : int = 64; - pub static S_IWUSR : int = 128; - pub static S_IRUSR : int = 256; - pub static F_OK : int = 0; - pub static R_OK : int = 4; - pub static W_OK : int = 2; - pub static X_OK : int = 1; - pub static STDIN_FILENO : int = 0; - pub static STDOUT_FILENO : int = 1; - pub static STDERR_FILENO : int = 2; - pub static F_LOCK : int = 1; - pub static F_TEST : int = 3; - pub static F_TLOCK : int = 2; - pub static F_ULOCK : int = 0; - pub static SIGHUP : int = 1; - pub static SIGINT : int = 2; - pub static SIGQUIT : int = 3; - pub static SIGILL : int = 4; - pub static SIGABRT : int = 6; - pub static SIGFPE : int = 8; - pub static SIGKILL : int = 9; - pub static SIGSEGV : int = 11; - pub static SIGPIPE : int = 13; - pub static SIGALRM : int = 14; - pub static SIGTERM : int = 15; + use libc::types::common::c95::c_void; + use libc::types::os::arch::c95::c_int; + + pub static O_RDONLY : c_int = 0; + pub static O_WRONLY : c_int = 1; + pub static O_RDWR : c_int = 2; + pub static O_APPEND : c_int = 8; + pub static O_CREAT : c_int = 512; + pub static O_EXCL : c_int = 2048; + pub static O_TRUNC : c_int = 1024; + pub static S_IFIFO : c_int = 4096; + pub static S_IFCHR : c_int = 8192; + pub static S_IFBLK : c_int = 24576; + pub static S_IFDIR : c_int = 16384; + pub static S_IFREG : c_int = 32768; + pub static S_IFMT : c_int = 61440; + pub static S_IEXEC : c_int = 64; + pub static S_IWRITE : c_int = 128; + pub static S_IREAD : c_int = 256; + pub static S_IRWXU : c_int = 448; + pub static S_IXUSR : c_int = 64; + pub static S_IWUSR : c_int = 128; + pub static S_IRUSR : c_int = 256; + pub static F_OK : c_int = 0; + pub static R_OK : c_int = 4; + pub static W_OK : c_int = 2; + pub static X_OK : c_int = 1; + pub static STDIN_FILENO : c_int = 0; + pub static STDOUT_FILENO : c_int = 1; + pub static STDERR_FILENO : c_int = 2; + pub static F_LOCK : c_int = 1; + pub static F_TEST : c_int = 3; + pub static F_TLOCK : c_int = 2; + pub static F_ULOCK : c_int = 0; + pub static SIGHUP : c_int = 1; + pub static SIGINT : c_int = 2; + pub static SIGQUIT : c_int = 3; + pub static SIGILL : c_int = 4; + pub static SIGABRT : c_int = 6; + pub static SIGFPE : c_int = 8; + pub static SIGKILL : c_int = 9; + pub static SIGSEGV : c_int = 11; + pub static SIGPIPE : c_int = 13; + pub static SIGALRM : c_int = 14; + pub static SIGTERM : c_int = 15; + + pub static PROT_NONE : c_int = 0; + pub static PROT_READ : c_int = 1; + pub static PROT_WRITE : c_int = 2; + pub static PROT_EXEC : c_int = 4; + + pub static MAP_FILE : c_int = 0x0000; + pub static MAP_SHARED : c_int = 0x0001; + pub static MAP_PRIVATE : c_int = 0x0002; + pub static MAP_FIXED : c_int = 0x0010; + pub static MAP_ANON : c_int = 0x1000; + + pub static MAP_FAILED : *c_void = -1 as *c_void; + + pub static MCL_CURRENT : c_int = 0x0001; + pub static MCL_FUTURE : c_int = 0x0002; + + pub static MS_ASYNC : c_int = 0x0001; + pub static MS_INVALIDATE : c_int = 0x0002; + pub static MS_SYNC : c_int = 0x0010; + + pub static MS_KILLPAGES : c_int = 0x0004; + pub static MS_DEACTIVATE : c_int = 0x0008; + + pub static _SC_ARG_MAX : c_int = 1; + pub static _SC_CHILD_MAX : c_int = 2; + pub static _SC_CLK_TCK : c_int = 3; + pub static _SC_NGROUPS_MAX : c_int = 4; + pub static _SC_OPEN_MAX : c_int = 5; + pub static _SC_JOB_CONTROL : c_int = 6; + pub static _SC_SAVED_IDS : c_int = 7; + pub static _SC_VERSION : c_int = 8; + pub static _SC_BC_BASE_MAX : c_int = 9; + pub static _SC_BC_DIM_MAX : c_int = 10; + pub static _SC_BC_SCALE_MAX : c_int = 11; + pub static _SC_BC_STRING_MAX : c_int = 12; + pub static _SC_COLL_WEIGHTS_MAX : c_int = 13; + pub static _SC_EXPR_NEST_MAX : c_int = 14; + pub static _SC_LINE_MAX : c_int = 15; + pub static _SC_RE_DUP_MAX : c_int = 16; + pub static _SC_2_VERSION : c_int = 17; + pub static _SC_2_C_BIND : c_int = 18; + pub static _SC_2_C_DEV : c_int = 19; + pub static _SC_2_CHAR_TERM : c_int = 20; + pub static _SC_2_FORT_DEV : c_int = 21; + pub static _SC_2_FORT_RUN : c_int = 22; + pub static _SC_2_LOCALEDEF : c_int = 23; + pub static _SC_2_SW_DEV : c_int = 24; + pub static _SC_2_UPE : c_int = 25; + pub static _SC_STREAM_MAX : c_int = 26; + pub static _SC_TZNAME_MAX : c_int = 27; + pub static _SC_ASYNCHRONOUS_IO : c_int = 28; + pub static _SC_PAGESIZE : c_int = 29; + pub static _SC_MEMLOCK : c_int = 30; + pub static _SC_MEMLOCK_RANGE : c_int = 31; + pub static _SC_MEMORY_PROTECTION : c_int = 32; + pub static _SC_MESSAGE_PASSING : c_int = 33; + pub static _SC_PRIORITIZED_IO : c_int = 34; + pub static _SC_PRIORITY_SCHEDULING : c_int = 35; + pub static _SC_REALTIME_SIGNALS : c_int = 36; + pub static _SC_SEMAPHORES : c_int = 37; + pub static _SC_FSYNC : c_int = 38; + pub static _SC_SHARED_MEMORY_OBJECTS : c_int = 39; + pub static _SC_SYNCHRONIZED_IO : c_int = 40; + pub static _SC_TIMERS : c_int = 41; + pub static _SC_AIO_LISTIO_MAX : c_int = 42; + pub static _SC_AIO_MAX : c_int = 43; + pub static _SC_AIO_PRIO_DELTA_MAX : c_int = 44; + pub static _SC_DELAYTIMER_MAX : c_int = 45; + pub static _SC_MQ_OPEN_MAX : c_int = 46; + pub static _SC_MAPPED_FILES : c_int = 47; + pub static _SC_RTSIG_MAX : c_int = 48; + pub static _SC_SEM_NSEMS_MAX : c_int = 49; + pub static _SC_SEM_VALUE_MAX : c_int = 50; + pub static _SC_SIGQUEUE_MAX : c_int = 51; + pub static _SC_TIMER_MAX : c_int = 52; + pub static _SC_XBS5_ILP32_OFF32 : c_int = 122; + pub static _SC_XBS5_ILP32_OFFBIG : c_int = 123; + pub static _SC_XBS5_LP64_OFF64 : c_int = 124; + pub static _SC_XBS5_LPBIG_OFFBIG : c_int = 125; } pub mod posix01 { - pub static SIGTRAP : int = 5; - - pub static GLOB_APPEND : int = 0x0001; - pub static GLOB_DOOFFS : int = 0x0002; - pub static GLOB_ERR : int = 0x0004; - pub static GLOB_MARK : int = 0x0008; - pub static GLOB_NOCHECK : int = 0x0010; - pub static GLOB_NOSORT : int = 0x0020; - pub static GLOB_NOESCAPE : int = 0x2000; - - pub static GLOB_NOSPACE : int = -1; - pub static GLOB_ABORTED : int = -2; - pub static GLOB_NOMATCH : int = -3; + use libc::types::os::arch::c95::c_int; + + pub static SIGTRAP : c_int = 5; + + pub static GLOB_APPEND : c_int = 0x0001; + pub static GLOB_DOOFFS : c_int = 0x0002; + pub static GLOB_ERR : c_int = 0x0004; + pub static GLOB_MARK : c_int = 0x0008; + pub static GLOB_NOCHECK : c_int = 0x0010; + pub static GLOB_NOSORT : c_int = 0x0020; + pub static GLOB_NOESCAPE : c_int = 0x2000; + + pub static GLOB_NOSPACE : c_int = -1; + pub static GLOB_ABORTED : c_int = -2; + pub static GLOB_NOMATCH : c_int = -3; + + pub static POSIX_MADV_NORMAL : c_int = 0; + pub static POSIX_MADV_RANDOM : c_int = 1; + pub static POSIX_MADV_SEQUENTIAL : c_int = 2; + pub static POSIX_MADV_WILLNEED : c_int = 3; + pub static POSIX_MADV_DONTNEED : c_int = 4; + + pub static _SC_IOV_MAX : c_int = 56; + pub static _SC_GETGR_R_SIZE_MAX : c_int = 70; + pub static _SC_GETPW_R_SIZE_MAX : c_int = 71; + pub static _SC_LOGIN_NAME_MAX : c_int = 73; + pub static _SC_MQ_PRIO_MAX : c_int = 75; + pub static _SC_THREAD_ATTR_STACKADDR : c_int = 82; + pub static _SC_THREAD_ATTR_STACKSIZE : c_int = 83; + pub static _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 85; + pub static _SC_THREAD_KEYS_MAX : c_int = 86; + pub static _SC_THREAD_PRIO_INHERIT : c_int = 87; + pub static _SC_THREAD_PRIO_PROTECT : c_int = 88; + pub static _SC_THREAD_PRIORITY_SCHEDULING : c_int = 89; + pub static _SC_THREAD_PROCESS_SHARED : c_int = 90; + pub static _SC_THREAD_SAFE_FUNCTIONS : c_int = 91; + pub static _SC_THREAD_STACK_MIN : c_int = 93; + pub static _SC_THREAD_THREADS_MAX : c_int = 94; + pub static _SC_THREADS : c_int = 96; + pub static _SC_TTY_NAME_MAX : c_int = 101; + pub static _SC_ATEXIT_MAX : c_int = 107; + pub static _SC_XOPEN_CRYPT : c_int = 108; + pub static _SC_XOPEN_ENH_I18N : c_int = 109; + pub static _SC_XOPEN_LEGACY : c_int = 110; + pub static _SC_XOPEN_REALTIME : c_int = 111; + pub static _SC_XOPEN_REALTIME_THREADS : c_int = 112; + pub static _SC_XOPEN_SHM : c_int = 113; + pub static _SC_XOPEN_UNIX : c_int = 115; + pub static _SC_XOPEN_VERSION : c_int = 116; + pub static _SC_XOPEN_XCU_VERSION : c_int = 121; } pub mod posix08 { } pub mod bsd44 { + use libc::types::os::arch::c95::c_int; + + pub static MADV_NORMAL : c_int = 0; + pub static MADV_RANDOM : c_int = 1; + pub static MADV_SEQUENTIAL : c_int = 2; + pub static MADV_WILLNEED : c_int = 3; + pub static MADV_DONTNEED : c_int = 4; + pub static MADV_FREE : c_int = 5; + pub static MADV_ZERO_WIRED_PAGES : c_int = 6; + pub static MADV_FREE_REUSABLE : c_int = 7; + pub static MADV_FREE_REUSE : c_int = 8; + pub static MADV_CAN_REUSE : c_int = 9; + + pub static MINCORE_INCORE : c_int = 0x1; + pub static MINCORE_REFERENCED : c_int = 0x2; + pub static MINCORE_MODIFIED : c_int = 0x4; + pub static MINCORE_REFERENCED_OTHER : c_int = 0x8; + pub static MINCORE_MODIFIED_OTHER : c_int = 0x10; } pub mod extra { - pub static O_DSYNC : int = 4194304; - pub static O_SYNC : int = 128; - pub static F_FULLFSYNC : int = 51; + use libc::types::os::arch::c95::c_int; + + pub static O_DSYNC : c_int = 4194304; + pub static O_SYNC : c_int = 128; + pub static F_FULLFSYNC : c_int = 51; + + pub static MAP_COPY : c_int = 0x0002; + pub static MAP_RENAME : c_int = 0x0020; + pub static MAP_NORESERVE : c_int = 0x0040; + pub static MAP_NOEXTEND : c_int = 0x0100; + pub static MAP_HASSEMAPHORE : c_int = 0x0200; + pub static MAP_NOCACHE : c_int = 0x0400; + pub static MAP_JIT : c_int = 0x0800; } } } @@ -1407,7 +1945,7 @@ pub mod funcs { #[fast_ffi] unsafe fn malloc(size: size_t) -> *c_void; #[fast_ffi] - unsafe fn realloc(p: *c_void, size: size_t) -> *c_void; + unsafe fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; #[fast_ffi] unsafe fn free(p: *c_void); unsafe fn abort() -> !; @@ -1610,6 +2148,9 @@ pub mod funcs { -> c_int; } } + + pub mod mman { + } } @@ -1787,6 +2328,38 @@ pub mod funcs { unsafe fn kill(pid: pid_t, sig: c_int) -> c_int; } } + + #[nolink] + #[abi = "cdecl"] + pub mod mman { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{size_t, c_int, c_char}; + use libc::types::os::arch::posix88::{mode_t, off_t}; + + pub extern { + unsafe fn mlock(addr: *c_void, len: size_t) -> c_int; + unsafe fn munlock(addr: *c_void, len: size_t) -> c_int; + unsafe fn mlockall(flags: c_int) -> c_int; + unsafe fn munlockall() -> c_int; + + unsafe fn mmap(addr: *c_void, + len: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off_t) -> *mut c_void; + unsafe fn munmap(addr: *c_void, len: size_t) -> c_int; + + unsafe fn mprotect(addr: *c_void, len: size_t, prot: c_int) + -> c_int; + + unsafe fn msync(addr: *c_void, len: size_t, flags: c_int) + -> c_int; + unsafe fn shm_open(name: *c_char, oflag: c_int, mode: mode_t) + -> c_int; + unsafe fn shm_unlink(name: *c_char) -> c_int; + } + } } #[cfg(target_os = "linux")] @@ -1865,6 +2438,19 @@ pub mod funcs { unsafe fn globfree(pglob: *mut glob_t); } } + + #[nolink] + #[abi = "cdecl"] + pub mod mman { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_int, size_t}; + + pub extern { + unsafe fn posix_madvise(addr: *c_void, + len: size_t, + advice: c_int) -> c_int; + } + } } #[cfg(target_os = "win32")] @@ -1877,6 +2463,9 @@ pub mod funcs { pub mod glob { } + + pub mod mman { + } } @@ -1895,7 +2484,8 @@ pub mod funcs { #[cfg(target_os = "freebsd")] pub mod bsd44 { use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, c_int, c_uint, size_t}; + use libc::types::os::arch::c95::{c_char, c_uchar, c_int, c_uint, + size_t}; #[abi = "cdecl"] pub extern { @@ -1911,6 +2501,12 @@ pub mod funcs { sizep: *mut size_t) -> c_int; unsafe fn getdtablesize() -> c_int; + + unsafe fn madvise(addr: *c_void, len: size_t, advice: c_int) + -> c_int; + + unsafe fn mincore(addr: *c_void, len: size_t, vec: *c_uchar) + -> c_int; } } @@ -1918,11 +2514,18 @@ pub mod funcs { #[cfg(target_os = "linux")] #[cfg(target_os = "android")] pub mod bsd44 { - use libc::types::os::arch::c95::{c_int}; + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_uchar, c_int, size_t}; #[abi = "cdecl"] pub extern { unsafe fn getdtablesize() -> c_int; + + unsafe fn madvise(addr: *c_void, len: size_t, advice: c_int) + -> c_int; + + unsafe fn mincore(addr: *c_void, len: size_t, vec: *c_uchar) + -> c_int; } } diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index 82c01c998cf..c5f2c8ae584 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -46,7 +46,7 @@ use task::local_data_priv::{local_get, local_pop, local_modify, local_set, Handl * * These two cases aside, the interface is safe. */ -pub type LocalDataKey<'self,T> = &'self fn(v: @T); +pub type LocalDataKey<'self,T> = &'self fn:Copy(v: @T); /** * Remove a task-local data value from the table, returning the @@ -92,14 +92,12 @@ fn test_tls_multitask() { fn my_key(_x: @~str) { } local_data_set(my_key, @~"parent data"); do task::spawn { - unsafe { - // TLS shouldn't carry over. - assert!(local_data_get(my_key).is_none()); - local_data_set(my_key, @~"child data"); - assert!(*(local_data_get(my_key).get()) == + // TLS shouldn't carry over. + assert!(local_data_get(my_key).is_none()); + local_data_set(my_key, @~"child data"); + assert!(*(local_data_get(my_key).get()) == ~"child data"); - // should be cleaned up for us - } + // should be cleaned up for us } // Must work multiple times assert!(*(local_data_get(my_key).get()) == ~"parent data"); @@ -206,12 +204,11 @@ fn test_tls_cleanup_on_failure() { local_data_set(str_key, @~"parent data"); local_data_set(box_key, @@()); do task::spawn { - unsafe { // spawn_linked - local_data_set(str_key, @~"string data"); - local_data_set(box_key, @@()); - local_data_set(int_key, @42); - fail!(); - } + // spawn_linked + local_data_set(str_key, @~"string data"); + local_data_set(box_key, @@()); + local_data_set(int_key, @42); + fail!(); } // Not quite nondeterministic. local_data_set(int_key, @31337); diff --git a/src/libstd/managed.rs b/src/libstd/managed.rs index d514612b5af..2c9fcb2999f 100644 --- a/src/libstd/managed.rs +++ b/src/libstd/managed.rs @@ -15,9 +15,8 @@ use ptr::to_unsafe_ptr; #[cfg(not(test))] use cmp::{Eq, Ord}; pub mod raw { - use intrinsic::TyDesc; + use std::unstable::intrinsics::TyDesc; - pub static RC_EXCHANGE_UNIQUE : uint = (-1) as uint; pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; pub static RC_IMMORTAL : uint = 0x77777777; diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 117a474ffd7..0b6eb766b29 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -754,8 +754,8 @@ impl Float for f32 { /// #[inline] pub fn to_str(num: f32) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigAll); + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigAll); r } @@ -768,8 +768,8 @@ pub fn to_str(num: f32) -> ~str { /// #[inline] pub fn to_str_hex(num: f32) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 16u, true, strconv::SignNeg, strconv::DigAll); + let (r, _) = strconv::float_to_str_common( + num, 16u, true, strconv::SignNeg, strconv::DigAll); r } @@ -789,8 +789,8 @@ pub fn to_str_hex(num: f32) -> ~str { /// #[inline] pub fn to_str_radix(num: f32, rdx: uint) -> ~str { - let (r, special) = strconv::to_str_common( - &num, rdx, true, strconv::SignNeg, strconv::DigAll); + let (r, special) = strconv::float_to_str_common( + num, rdx, true, strconv::SignNeg, strconv::DigAll); if special { fail!("number has a special value, \ try to_str_radix_special() if those are expected") } r @@ -807,7 +807,7 @@ pub fn to_str_radix(num: f32, rdx: uint) -> ~str { /// #[inline] pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) { - strconv::to_str_common(&num, rdx, true, + strconv::float_to_str_common(num, rdx, true, strconv::SignNeg, strconv::DigAll) } @@ -822,8 +822,8 @@ pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) { /// #[inline] pub fn to_str_exact(num: f32, dig: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigExact(dig)); + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigExact(dig)); r } @@ -838,8 +838,8 @@ pub fn to_str_exact(num: f32, dig: uint) -> ~str { /// #[inline] pub fn to_str_digits(num: f32, dig: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigMax(dig)); + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigMax(dig)); r } diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index e13dff1e623..c39c7a3a57d 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -796,8 +796,8 @@ impl Float for f64 { /// #[inline] pub fn to_str(num: f64) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigAll); + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigAll); r } @@ -810,8 +810,8 @@ pub fn to_str(num: f64) -> ~str { /// #[inline] pub fn to_str_hex(num: f64) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 16u, true, strconv::SignNeg, strconv::DigAll); + let (r, _) = strconv::float_to_str_common( + num, 16u, true, strconv::SignNeg, strconv::DigAll); r } @@ -831,8 +831,8 @@ pub fn to_str_hex(num: f64) -> ~str { /// #[inline] pub fn to_str_radix(num: f64, rdx: uint) -> ~str { - let (r, special) = strconv::to_str_common( - &num, rdx, true, strconv::SignNeg, strconv::DigAll); + let (r, special) = strconv::float_to_str_common( + num, rdx, true, strconv::SignNeg, strconv::DigAll); if special { fail!("number has a special value, \ try to_str_radix_special() if those are expected") } r @@ -849,7 +849,7 @@ pub fn to_str_radix(num: f64, rdx: uint) -> ~str { /// #[inline] pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) { - strconv::to_str_common(&num, rdx, true, + strconv::float_to_str_common(num, rdx, true, strconv::SignNeg, strconv::DigAll) } @@ -864,8 +864,8 @@ pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) { /// #[inline] pub fn to_str_exact(num: f64, dig: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigExact(dig)); + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigExact(dig)); r } @@ -880,8 +880,8 @@ pub fn to_str_exact(num: f64, dig: uint) -> ~str { /// #[inline] pub fn to_str_digits(num: f64, dig: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigMax(dig)); + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigMax(dig)); r } diff --git a/src/libstd/num/float.rs b/src/libstd/num/float.rs index c583aeacf16..7a6e3042e7b 100644 --- a/src/libstd/num/float.rs +++ b/src/libstd/num/float.rs @@ -101,8 +101,8 @@ pub mod consts { /// #[inline] pub fn to_str(num: float) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigAll); + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigAll); r } @@ -115,8 +115,8 @@ pub fn to_str(num: float) -> ~str { /// #[inline] pub fn to_str_hex(num: float) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 16u, true, strconv::SignNeg, strconv::DigAll); + let (r, _) = strconv::float_to_str_common( + num, 16u, true, strconv::SignNeg, strconv::DigAll); r } @@ -136,8 +136,8 @@ pub fn to_str_hex(num: float) -> ~str { /// #[inline] pub fn to_str_radix(num: float, radix: uint) -> ~str { - let (r, special) = strconv::to_str_common( - &num, radix, true, strconv::SignNeg, strconv::DigAll); + let (r, special) = strconv::float_to_str_common( + num, radix, true, strconv::SignNeg, strconv::DigAll); if special { fail!("number has a special value, \ try to_str_radix_special() if those are expected") } r @@ -154,7 +154,7 @@ pub fn to_str_radix(num: float, radix: uint) -> ~str { /// #[inline] pub fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) { - strconv::to_str_common(&num, radix, true, + strconv::float_to_str_common(num, radix, true, strconv::SignNeg, strconv::DigAll) } @@ -169,8 +169,8 @@ pub fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) { /// #[inline] pub fn to_str_exact(num: float, digits: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigExact(digits)); + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigExact(digits)); r } @@ -185,8 +185,8 @@ pub fn to_str_exact(num: float, digits: uint) -> ~str { /// #[inline] pub fn to_str_digits(num: float, digits: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigMax(digits)); + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigMax(digits)); r } diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 74ec46ccfcd..f152d60cb7a 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -17,6 +17,7 @@ macro_rules! int_module (($T:ty, $bits:expr) => (mod generated { use num::{ToStrRadix, FromStrRadix}; use num::{Zero, One, strconv}; use prelude::*; +use str; pub use cmp::{min, max}; @@ -400,7 +401,8 @@ impl Integer for $T { #[inline] fn gcd(&self, other: &$T) -> $T { // Use Euclid's algorithm - let mut (m, n) = (*self, *other); + let mut m = *self; + let mut n = *other; while m != 0 { let temp = m; m = n % temp; @@ -528,25 +530,33 @@ impl FromStrRadix for $T { /// Convert to a string as a byte slice in a given base. #[inline] pub fn to_str_bytes<U>(n: $T, radix: uint, f: &fn(v: &[u8]) -> U) -> U { - let (buf, _) = strconv::to_str_bytes_common(&n, radix, false, - strconv::SignNeg, strconv::DigAll); - f(buf) + // The radix can be as low as 2, so we need at least 64 characters for a + // base 2 number, and then we need another for a possible '-' character. + let mut buf = [0u8, ..65]; + let mut cur = 0; + do strconv::int_to_str_bytes_common(n, radix, strconv::SignNeg) |i| { + buf[cur] = i; + cur += 1; + } + f(buf.slice(0, cur)) } /// Convert to a string in base 10. #[inline] pub fn to_str(num: $T) -> ~str { - let (buf, _) = strconv::to_str_common(&num, 10u, false, - strconv::SignNeg, strconv::DigAll); - buf + to_str_radix(num, 10u) } /// Convert to a string in a given base. #[inline] pub fn to_str_radix(num: $T, radix: uint) -> ~str { - let (buf, _) = strconv::to_str_common(&num, radix, false, - strconv::SignNeg, strconv::DigAll); - buf + let mut buf: ~[u8] = ~[]; + do strconv::int_to_str_bytes_common(num, radix, strconv::SignNeg) |i| { + buf.push(i); + } + // We know we generated valid utf-8, so we don't need to go through that + // check. + unsafe { str::raw::from_bytes_owned(buf) } } impl ToStr for $T { diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index 30a18a0587b..b856c3c65ea 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -412,7 +412,7 @@ pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(radix: uint, pow if my_pow % 2u == 1u { total = total * multiplier; } - my_pow = my_pow / 2u; + my_pow = my_pow / 2u; multiplier = multiplier * multiplier; } total diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index a062838aacf..f6dff4267b7 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -16,13 +16,12 @@ use ops::{Add, Sub, Mul, Div, Rem, Neg}; use option::{None, Option, Some}; use char; use str; -use str::{StrSlice}; +use str::StrSlice; use kinds::Copy; -use vec; -use vec::{CopyableVector, ImmutableVector}; +use vec::{CopyableVector, ImmutableVector, MutableVector}; use vec::OwnedVector; -use num::{NumCast, Zero, One, cast, pow_with_uint}; -use f64; +use num::{NumCast, Zero, One, cast, pow_with_uint, Integer}; +use num::{Round, Float, FPNaN, FPInfinite}; pub enum ExponentFormat { ExpNone, @@ -42,35 +41,6 @@ pub enum SignFormat { SignAll } -#[inline] -fn is_NaN<T:Eq>(num: &T) -> bool { - *num != *num -} - -#[inline] -fn is_inf<T:Eq+NumStrConv>(num: &T) -> bool { - match NumStrConv::inf() { - None => false, - Some(n) => *num == n - } -} - -#[inline] -fn is_neg_inf<T:Eq+NumStrConv>(num: &T) -> bool { - match NumStrConv::neg_inf() { - None => false, - Some(n) => *num == n - } -} - -#[inline] -fn is_neg_zero<T:Eq+One+Zero+NumStrConv+Div<T,T>>(num: &T) -> bool { - let _0: T = Zero::zero(); - let _1: T = One::one(); - - *num == _0 && is_neg_inf(&(_1 / *num)) -} - pub trait NumStrConv { fn NaN() -> Option<Self>; fn inf() -> Option<Self>; @@ -93,16 +63,9 @@ macro_rules! impl_NumStrConv_Floating (($t:ty) => ( fn neg_zero() -> Option<$t> { Some(-0.0 ) } #[inline] - fn round_to_zero(&self) -> $t { - ( if *self < 0.0 { f64::ceil(*self as f64) } - else { f64::floor(*self as f64) } - ) as $t - } - + fn round_to_zero(&self) -> $t { self.trunc() } #[inline] - fn fractional_part(&self) -> $t { - *self - self.round_to_zero() - } + fn fractional_part(&self) -> $t { self.fract() } } )) @@ -146,6 +109,87 @@ static negative_inf_buf: [u8, ..4] = ['-' as u8, 'i' as u8, 'n' as u8, static nan_buf: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8]; /** + * Converts an integral number to its string representation as a byte vector. + * This is meant to be a common base implementation for all integral string + * conversion functions like `to_str()` or `to_str_radix()`. + * + * # Arguments + * - `num` - The number to convert. Accepts any number that + * implements the numeric traits. + * - `radix` - Base to use. Accepts only the values 2-36. + * - `sign` - How to emit the sign. Options are: + * - `SignNone`: No sign at all. Basically emits `abs(num)`. + * - `SignNeg`: Only `-` on negative values. + * - `SignAll`: Both `+` on positive, and `-` on negative numbers. + * - `f` - a callback which will be invoked for each ascii character + * which composes the string representation of this integer + * + * # Return value + * A tuple containing the byte vector, and a boolean flag indicating + * whether it represents a special value like `inf`, `-inf`, `NaN` or not. + * It returns a tuple because there can be ambiguity between a special value + * and a number representation at higher bases. + * + * # Failure + * - Fails if `radix` < 2 or `radix` > 36. + */ +pub fn int_to_str_bytes_common<T:NumCast+Zero+Eq+Ord+Integer+ + Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( + num: T, radix: uint, sign: SignFormat, f: &fn(u8)) { + assert!(2 <= radix && radix <= 36); + + let _0: T = Zero::zero(); + + let neg = num < _0; + let radix_gen: T = cast(radix); + + let mut deccum = num; + // This is just for integral types, the largest of which is a u64. The + // smallest base that we can have is 2, so the most number of digits we're + // ever going to have is 64 + let mut buf = [0u8, ..64]; + let mut cur = 0; + + // Loop at least once to make sure at least a `0` gets emitted. + loop { + // Calculate the absolute value of each digit instead of only + // doing it once for the whole number because a + // representable negative number doesn't necessary have an + // representable additive inverse of the same type + // (See twos complement). But we assume that for the + // numbers [-35 .. 0] we always have [0 .. 35]. + let current_digit_signed = deccum % radix_gen; + let current_digit = if current_digit_signed < _0 { + -current_digit_signed + } else { + current_digit_signed + }; + buf[cur] = match current_digit.to_u8() { + i @ 0..9 => '0' as u8 + i, + i => 'a' as u8 + (i - 10), + }; + cur += 1; + + deccum = deccum / radix_gen; + // No more digits to calculate for the non-fractional part -> break + if deccum == _0 { break; } + } + + // Decide what sign to put in front + match sign { + SignNeg | SignAll if neg => { f('-' as u8); } + SignAll => { f('+' as u8); } + _ => () + } + + // We built the number in reverse order, so un-reverse it here + while cur > 0 { + cur -= 1; + f(buf[cur]); + } +} + +/** * Converts a number to its string representation as a byte vector. * This is meant to be a common base implementation for all numeric string * conversion functions like `to_str()` or `to_str_radix()`. @@ -176,44 +220,39 @@ static nan_buf: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8]; * # Failure * - Fails if `radix` < 2 or `radix` > 36. */ -pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ +pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+ Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( - num: &T, radix: uint, negative_zero: bool, + num: T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) { - if (radix as int) < 2 { - fail!("to_str_bytes_common: radix %? to low, must lie in the range [2, 36]", radix); - } else if radix as int > 36 { - fail!("to_str_bytes_common: radix %? to high, must lie in the range [2, 36]", radix); - } + assert!(2 <= radix && radix <= 36); let _0: T = Zero::zero(); let _1: T = One::one(); - if is_NaN(num) { - return ("NaN".as_bytes().to_owned(), true); - } - else if is_inf(num){ - return match sign { - SignAll => ("+inf".as_bytes().to_owned(), true), - _ => ("inf".as_bytes().to_owned(), true) + match num.classify() { + FPNaN => { return ("NaN".as_bytes().to_owned(), true); } + FPInfinite if num > _0 => { + return match sign { + SignAll => ("+inf".as_bytes().to_owned(), true), + _ => ("inf".as_bytes().to_owned(), true) + }; } - } - else if is_neg_inf(num) { - return match sign { - SignNone => ("inf".as_bytes().to_owned(), true), - _ => ("-inf".as_bytes().to_owned(), true), + FPInfinite if num < _0 => { + return match sign { + SignNone => ("inf".as_bytes().to_owned(), true), + _ => ("-inf".as_bytes().to_owned(), true), + }; } + _ => {} } - let neg = *num < _0 || (negative_zero && is_neg_zero(num)); + let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity()); let mut buf: ~[u8] = ~[]; let radix_gen: T = cast(radix as int); - let mut deccum; - // First emit the non-fractional part, looping at least once to make // sure at least a `0` gets emitted. - deccum = num.round_to_zero(); + let mut deccum = num.trunc(); loop { // Calculate the absolute value of each digit instead of only // doing it once for the whole number because a @@ -221,16 +260,11 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ // representable additive inverse of the same type // (See twos complement). But we assume that for the // numbers [-35 .. 0] we always have [0 .. 35]. - let current_digit_signed = deccum % radix_gen; - let current_digit = if current_digit_signed < _0 { - -current_digit_signed - } else { - current_digit_signed - }; + let current_digit = (deccum % radix_gen).abs(); // Decrease the deccumulator one digit at a time deccum = deccum / radix_gen; - deccum = deccum.round_to_zero(); + deccum = deccum.trunc(); buf.push(char::from_digit(current_digit.to_int() as uint, radix) .unwrap() as u8); @@ -257,7 +291,7 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ _ => () } - vec::reverse(buf); + buf.reverse(); // Remember start of the fractional digits. // Points one beyond end of buf if none get generated, @@ -265,7 +299,7 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ let start_fractional_digits = buf.len(); // Now emit the fractional part, if any - deccum = num.fractional_part(); + deccum = num.fract(); if deccum != _0 || (limit_digits && exact && digit_count > 0) { buf.push('.' as u8); let mut dig = 0u; @@ -286,18 +320,13 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ // Calculate the absolute value of each digit. // See note in first loop. - let current_digit_signed = deccum.round_to_zero(); - let current_digit = if current_digit_signed < _0 { - -current_digit_signed - } else { - current_digit_signed - }; + let current_digit = deccum.trunc().abs(); buf.push(char::from_digit( current_digit.to_int() as uint, radix).unwrap() as u8); // Decrease the deccumulator one fractional digit at a time - deccum = deccum.fractional_part(); + deccum = deccum.fract(); dig += 1u; } @@ -382,11 +411,11 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ * `to_str_bytes_common()`, for details see there. */ #[inline] -pub fn to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ - Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( - num: &T, radix: uint, negative_zero: bool, +pub fn float_to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Float+Round+ + Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( + num: T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits) -> (~str, bool) { - let (bytes, special) = to_str_bytes_common(num, radix, + let (bytes, special) = float_to_str_bytes_common(num, radix, negative_zero, sign, digits); (str::from_bytes(bytes), special) } diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 52f620f97ce..25e338fcd0f 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -18,6 +18,7 @@ use num::BitCount; use num::{ToStrRadix, FromStrRadix}; use num::{Zero, One, strconv}; use prelude::*; +use str; pub use cmp::{min, max}; @@ -237,7 +238,8 @@ impl Integer for $T { #[inline] fn gcd(&self, other: &$T) -> $T { // Use Euclid's algorithm - let mut (m, n) = (*self, *other); + let mut m = *self; + let mut n = *other; while m != 0 { let temp = m; m = n % temp; @@ -355,25 +357,33 @@ impl FromStrRadix for $T { /// Convert to a string as a byte slice in a given base. #[inline] pub fn to_str_bytes<U>(n: $T, radix: uint, f: &fn(v: &[u8]) -> U) -> U { - let (buf, _) = strconv::to_str_bytes_common(&n, radix, false, - strconv::SignNeg, strconv::DigAll); - f(buf) + // The radix can be as low as 2, so we need at least 64 characters for a + // base 2 number. + let mut buf = [0u8, ..64]; + let mut cur = 0; + do strconv::int_to_str_bytes_common(n, radix, strconv::SignNone) |i| { + buf[cur] = i; + cur += 1; + } + f(buf.slice(0, cur)) } /// Convert to a string in base 10. #[inline] pub fn to_str(num: $T) -> ~str { - let (buf, _) = strconv::to_str_common(&num, 10u, false, - strconv::SignNeg, strconv::DigAll); - buf + to_str_radix(num, 10u) } /// Convert to a string in a given base. #[inline] pub fn to_str_radix(num: $T, radix: uint) -> ~str { - let (buf, _) = strconv::to_str_common(&num, radix, false, - strconv::SignNeg, strconv::DigAll); - buf + let mut buf = ~[]; + do strconv::int_to_str_bytes_common(num, radix, strconv::SignNone) |i| { + buf.push(i); + } + // We know we generated valid utf-8, so we don't need to go through that + // check. + unsafe { str::raw::from_bytes_owned(buf) } } impl ToStr for $T { diff --git a/src/libstd/old_iter.rs b/src/libstd/old_iter.rs deleted file mode 100644 index 83bb9eb0908..00000000000 --- a/src/libstd/old_iter.rs +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2012-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. - -/*! - -**Deprecated** iteration traits and common implementations. - -*/ - -#[allow(missing_doc)]; - -use cmp::{Eq}; -use kinds::Copy; -use option::{None, Option, Some}; -use vec; - -/// A function used to initialize the elements of a sequence -pub type InitOp<'self,T> = &'self fn(uint) -> T; - -pub trait BaseIter<A> { - fn each(&self, blk: &fn(v: &A) -> bool) -> bool; - fn size_hint(&self) -> Option<uint>; -} - -pub trait ReverseIter<A>: BaseIter<A> { - fn each_reverse(&self, blk: &fn(&A) -> bool) -> bool; -} - -pub trait ExtendedIter<A> { - fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool; - fn all(&self, blk: &fn(&A) -> bool) -> bool; - fn any(&self, blk: &fn(&A) -> bool) -> bool; - fn foldl<B>(&self, b0: B, blk: &fn(&B, &A) -> B) -> B; - fn position(&self, f: &fn(&A) -> bool) -> Option<uint>; - fn map_to_vec<B>(&self, op: &fn(&A) -> B) -> ~[B]; - fn flat_map_to_vec<B,IB: BaseIter<B>>(&self, op: &fn(&A) -> IB) -> ~[B]; -} - -pub trait EqIter<A:Eq> { - fn contains(&self, x: &A) -> bool; - fn count(&self, x: &A) -> uint; -} - -pub trait CopyableIter<A:Copy> { - fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A]; - fn to_vec(&self) -> ~[A]; - fn find(&self, p: &fn(&A) -> bool) -> Option<A>; -} - -// A trait for sequences that can be built by imperatively pushing elements -// onto them. -pub trait Buildable<A> { - /** - * Builds a buildable sequence by calling a provided function with - * an argument function that pushes an element onto the back of - * the sequence. - * This version takes an initial size for the sequence. - * - * # Arguments - * - * * size - A hint for an initial size of the sequence - * * builder - A function that will construct the sequence. It receives - * as an argument a function that will push an element - * onto the sequence being constructed. - */ - fn build_sized(size: uint, builder: &fn(push: &fn(A))) -> Self; -} - -#[inline] -pub fn _eachi<A,IA:BaseIter<A>>(this: &IA, blk: &fn(uint, &A) -> bool) -> bool { - let mut i = 0; - for this.each |a| { - if !blk(i, a) { - return false; - } - i += 1; - } - return true; -} - -pub fn eachi<A,IA:BaseIter<A>>(this: &IA, blk: &fn(uint, &A) -> bool) -> bool { - _eachi(this, blk) -} - -#[inline] -pub fn all<A,IA:BaseIter<A>>(this: &IA, blk: &fn(&A) -> bool) -> bool { - for this.each |a| { - if !blk(a) { - return false; - } - } - return true; -} - -#[inline] -pub fn any<A,IA:BaseIter<A>>(this: &IA, blk: &fn(&A) -> bool) -> bool { - for this.each |a| { - if blk(a) { - return true; - } - } - return false; -} - -#[inline] -pub fn filter_to_vec<A:Copy,IA:BaseIter<A>>(this: &IA, - prd: &fn(&A) -> bool) - -> ~[A] { - do vec::build_sized_opt(this.size_hint()) |push| { - for this.each |a| { - if prd(a) { push(copy *a); } - } - } -} - -#[inline] -pub fn map_to_vec<A,B,IA:BaseIter<A>>(this: &IA, op: &fn(&A) -> B) -> ~[B] { - do vec::build_sized_opt(this.size_hint()) |push| { - for this.each |a| { - push(op(a)); - } - } -} - -#[inline] -pub fn flat_map_to_vec<A,B,IA:BaseIter<A>,IB:BaseIter<B>>(this: &IA, - op: &fn(&A) -> IB) - -> ~[B] { - do vec::build |push| { - for this.each |a| { - for op(a).each |&b| { - push(b); - } - } - } -} - -#[inline] -pub fn foldl<A,B,IA:BaseIter<A>>(this: &IA, b0: B, blk: &fn(&B, &A) -> B) - -> B { - let mut b = b0; - for this.each |a| { - b = blk(&b, a); - } - b -} - -#[inline] -pub fn to_vec<A:Copy,IA:BaseIter<A>>(this: &IA) -> ~[A] { - map_to_vec(this, |&x| x) -} - -#[inline] -pub fn contains<A:Eq,IA:BaseIter<A>>(this: &IA, x: &A) -> bool { - for this.each |a| { - if *a == *x { return true; } - } - return false; -} - -#[inline] -pub fn count<A:Eq,IA:BaseIter<A>>(this: &IA, x: &A) -> uint { - do foldl(this, 0) |count, value| { - if *value == *x { - *count + 1 - } else { - *count - } - } -} - -#[inline] -pub fn position<A,IA:BaseIter<A>>(this: &IA, f: &fn(&A) -> bool) - -> Option<uint> { - let mut i = 0; - for this.each |a| { - if f(a) { return Some(i); } - i += 1; - } - return None; -} - -#[inline] -pub fn find<A:Copy,IA:BaseIter<A>>(this: &IA, f: &fn(&A) -> bool) - -> Option<A> { - for this.each |i| { - if f(i) { return Some(copy *i) } - } - return None; -} - -// Some functions for just building - -/** - * Builds a sequence by calling a provided function with an argument - * function that pushes an element to the back of a sequence. - * - * # Arguments - * - * * builder - A function that will construct the sequence. It receives - * as an argument a function that will push an element - * onto the sequence being constructed. - */ -#[inline] -pub fn build<A,B: Buildable<A>>(builder: &fn(push: &fn(A))) -> B { - Buildable::build_sized(4, builder) -} - -/** - * Builds a sequence by calling a provided function with an argument - * function that pushes an element to the back of the sequence. - * This version takes an initial size for the sequence. - * - * # Arguments - * - * * size - An option, maybe containing initial size of the sequence - * to reserve. - * * builder - A function that will construct the sequence. It receives - * as an argument a function that will push an element - * onto the sequence being constructed. - */ -#[inline] -pub fn build_sized_opt<A,B: Buildable<A>>(size: Option<uint>, - builder: &fn(push: &fn(A))) -> B { - Buildable::build_sized(size.get_or_default(4), builder) -} - -// Functions that combine iteration and building - -/// Applies a function to each element of an iterable and returns the results -/// in a sequence built via `BU`. See also `map_to_vec`. -#[inline] -pub fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: &IT, f: &fn(&T) -> U) - -> BU { - do build_sized_opt(v.size_hint()) |push| { - for v.each() |elem| { - push(f(elem)); - } - } -} - -/** - * Creates and initializes a generic sequence from a function. - * - * Creates a generic sequence of size `n_elts` and initializes the elements - * to the value returned by the function `op`. - */ -#[inline] -pub fn from_fn<T,BT: Buildable<T>>(n_elts: uint, op: InitOp<T>) -> BT { - do Buildable::build_sized(n_elts) |push| { - let mut i: uint = 0u; - while i < n_elts { push(op(i)); i += 1u; } - } -} - -/** - * Creates and initializes a generic sequence with some elements. - * - * Creates an immutable vector of size `n_elts` and initializes the elements - * to the value `t`. - */ -#[inline] -pub fn from_elem<T:Copy,BT:Buildable<T>>(n_elts: uint, t: T) -> BT { - do Buildable::build_sized(n_elts) |push| { - let mut i: uint = 0; - while i < n_elts { push(copy t); i += 1; } - } -} - -/// Appends two generic sequences. -#[inline] -pub fn append<T:Copy,IT:BaseIter<T>,BT:Buildable<T>>(lhs: &IT, rhs: &IT) - -> BT { - let size_opt = lhs.size_hint().chain_ref( - |sz1| rhs.size_hint().map(|sz2| *sz1+*sz2)); - do build_sized_opt(size_opt) |push| { - for lhs.each |x| { push(copy *x); } - for rhs.each |x| { push(copy *x); } - } -} - -/// Copies a generic sequence, possibly converting it to a different -/// type of sequence. -#[inline] -pub fn copy_seq<T:Copy,IT:BaseIter<T>,BT:Buildable<T>>(v: &IT) -> BT { - do build_sized_opt(v.size_hint()) |push| { - for v.each |x| { push(copy *x); } - } -} diff --git a/src/libstd/ops.rs b/src/libstd/ops.rs index 77cfe62e495..020131ab119 100644 --- a/src/libstd/ops.rs +++ b/src/libstd/ops.rs @@ -14,7 +14,7 @@ #[lang="drop"] pub trait Drop { - fn finalize(&self); // FIXME(#4332): Rename to "drop"? --pcwalton + fn drop(&self); } #[lang="add"] diff --git a/src/libstd/option.rs b/src/libstd/option.rs index 7dc6b7fe4b1..64381231258 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -121,13 +121,13 @@ impl<T> Option<T> { /// Returns true if the option equals `none` #[inline] - pub fn is_none(&const self) -> bool { + pub fn is_none(&self) -> bool { match *self { None => true, Some(_) => false } } /// Returns true if the option contains some value #[inline] - pub fn is_some(&const self) -> bool { !self.is_none() } + pub fn is_some(&self) -> bool { !self.is_none() } /// Update an optional value by optionally running its content through a /// function that returns an option. @@ -159,6 +159,15 @@ impl<T> Option<T> { } } + /// Filters an optional value using given function. + #[inline(always)] + pub fn filtered<'a>(self, f: &fn(t: &'a T) -> bool) -> Option<T> { + match self { + Some(x) => if(f(&x)) {Some(x)} else {None}, + None => None + } + } + /// Maps a `some` value from one type to another by reference #[inline] pub fn map<'a, U>(&self, f: &fn(&'a T) -> U) -> Option<U> { @@ -407,7 +416,7 @@ fn test_unwrap_resource() { #[unsafe_destructor] impl ::ops::Drop for R { - fn finalize(&self) { *(self.i) += 1; } + fn drop(&self) { *(self.i) += 1; } } fn R(i: @mut int) -> R { @@ -438,7 +447,7 @@ fn test_option_dance() { } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_option_too_much_dance() { - let mut y = Some(util::NonCopyable::new()); + let mut y = Some(util::NonCopyable); let _y2 = y.swap_unwrap(); let _y3 = y.swap_unwrap(); } @@ -464,3 +473,11 @@ fn test_get_or_zero() { let no_stuff: Option<int> = None; assert_eq!(no_stuff.get_or_zero(), 0); } + +#[test] +fn test_filtered() { + let some_stuff = Some(42); + let modified_stuff = some_stuff.filtered(|&x| {x < 10}); + assert_eq!(some_stuff.get(), 42); + assert!(modified_stuff.is_none()); +} diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 765dd30febc..20c4346d618 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -29,19 +29,17 @@ #[allow(missing_doc)]; use cast; +use container::Container; use io; use iterator::IteratorUtil; use libc; use libc::{c_char, c_void, c_int, size_t}; -use libc::{mode_t, FILE}; +use libc::FILE; use local_data; -use option; use option::{Some, None}; use os; use prelude::*; use ptr; -use rt; -use rt::TaskContext; use str; use uint; use unstable::finally::Finally; @@ -137,7 +135,7 @@ pub mod win32 { } } if k != 0 && done { - let sub = vec::slice(buf, 0u, k as uint); + let sub = buf.slice(0, k as uint); res = option::Some(str::from_utf16(sub)); } } @@ -148,7 +146,7 @@ pub mod win32 { pub fn as_utf16_p<T>(s: &str, f: &fn(*u16) -> T) -> T { let mut t = s.to_utf16(); // Null terminate before passing on. - t += [0u16]; + t.push(0u16); vec::as_imm_buf(t, |buf, _len| f(buf)) } } @@ -183,7 +181,6 @@ pub fn env() -> ~[(~str,~str)] { unsafe { #[cfg(windows)] unsafe fn get_env_pairs() -> ~[~str] { - use libc::types::os::arch::extra::LPTCH; use libc::funcs::extra::kernel32::{ GetEnvironmentStringsA, FreeEnvironmentStringsA @@ -226,7 +223,7 @@ pub fn env() -> ~[(~str,~str)] { fn env_convert(input: ~[~str]) -> ~[(~str, ~str)] { let mut pairs = ~[]; - for input.each |p| { + for input.iter().advance |p| { let vs: ~[&str] = p.splitn_iter('=', 1).collect(); debug!("splitting: len: %u", vs.len()); @@ -250,10 +247,10 @@ pub fn getenv(n: &str) -> Option<~str> { do with_env_lock { let s = str::as_c_str(n, |s| libc::getenv(s)); if ptr::null::<u8>() == cast::transmute(s) { - option::None::<~str> + None::<~str> } else { let s = cast::transmute(s); - option::Some::<~str>(str::raw::from_buf(s)) + Some::<~str>(str::raw::from_buf(s)) } } } @@ -542,7 +539,7 @@ pub fn homedir() -> Option<Path> { #[cfg(windows)] fn secondary() -> Option<Path> { - do getenv(~"USERPROFILE").chain |p| { + do getenv("USERPROFILE").chain |p| { if !p.is_empty() { Some(Path(p)) } else { @@ -595,9 +592,10 @@ pub fn tmpdir() -> Path { /// Recursively walk a directory structure pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool { - list_dir(p).each(|q| { + let r = list_dir(p); + r.iter().advance(|q| { let path = &p.push(*q); - f(path) && (!path_is_dir(path) || walk_dir(path, f)) + f(path) && (!path_is_dir(path) || walk_dir(path, |p| f(p))) }) } @@ -648,9 +646,7 @@ pub fn make_dir(p: &Path, mode: c_int) -> bool { use os::win32::as_utf16_p; // FIXME: turn mode into something useful? #2623 do as_utf16_p(p.to_str()) |buf| { - libc::CreateDirectoryW(buf, unsafe { - cast::transmute(0) - }) + libc::CreateDirectoryW(buf, cast::transmute(0)) != (0 as libc::BOOL) } } @@ -660,7 +656,7 @@ pub fn make_dir(p: &Path, mode: c_int) -> bool { fn mkdir(p: &Path, mode: c_int) -> bool { unsafe { do as_c_charp(p.to_str()) |c| { - libc::mkdir(c, mode as mode_t) == (0 as c_int) + libc::mkdir(c, mode as libc::mode_t) == (0 as c_int) } } } @@ -733,9 +729,8 @@ pub fn list_dir(p: &Path) -> ~[~str] { } #[cfg(windows)] unsafe fn get_list(p: &Path) -> ~[~str] { - use libc::types::os::arch::extra::{LPCTSTR, HANDLE, BOOL}; use libc::consts::os::extra::INVALID_HANDLE_VALUE; - use libc::wcslen; + use libc::{wcslen, free}; use libc::funcs::extra::kernel32::{ FindFirstFileW, FindNextFileW, @@ -744,7 +739,8 @@ pub fn list_dir(p: &Path) -> ~[~str] { use os::win32::{ as_utf16_p }; - use rt::global_heap::{malloc_raw, free_raw}; + use rt::global_heap::malloc_raw; + #[nolink] extern { unsafe fn rust_list_dir_wfd_size() -> libc::size_t; @@ -759,7 +755,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { FindFirstFileW( path_ptr, ::cast::transmute(wfd_ptr)); - if find_handle as int != INVALID_HANDLE_VALUE { + if find_handle as libc::c_int != INVALID_HANDLE_VALUE { let mut more_files = 1 as libc::c_int; while more_files != 0 { let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr); @@ -777,7 +773,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { ::cast::transmute(wfd_ptr)); } FindClose(find_handle); - free_raw(wfd_ptr); + free(wfd_ptr) } strings } @@ -962,7 +958,7 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { // Give the new file the old file's permissions if do str::as_c_str(to.to_str()) |to_buf| { - libc::chmod(to_buf, from_mode as mode_t) + libc::chmod(to_buf, from_mode as libc::mode_t) } != 0 { return false; // should be a condition... } @@ -1146,7 +1142,7 @@ pub fn set_exit_status(code: int) { unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] { let mut args = ~[]; for uint::range(0, argc as uint) |i| { - vec::push(&mut args, str::raw::from_c_str(*argv.offset(i))); + args.push(str::raw::from_c_str(*argv.offset(i))); } args } @@ -1169,6 +1165,9 @@ pub fn real_args() -> ~[~str] { #[cfg(target_os = "android")] #[cfg(target_os = "freebsd")] pub fn real_args() -> ~[~str] { + use rt; + use rt::TaskContext; + if rt::context() == TaskContext { match rt::args::clone() { Some(args) => args, @@ -1199,8 +1198,7 @@ pub fn real_args() -> ~[~str] { while *ptr.offset(len) != 0 { len += 1; } // Push it onto the list. - vec::push(&mut args, - vec::raw::buf_as_slice(ptr, len, + args.push(vec::raw::buf_as_slice(ptr, len, str::from_utf16)); } } @@ -1337,7 +1335,7 @@ pub fn glob(pattern: &str) -> ~[Path] { /// Returns a vector of Path objects that match the given glob pattern #[cfg(target_os = "win32")] -pub fn glob(pattern: &str) -> ~[Path] { +pub fn glob(_pattern: &str) -> ~[Path] { fail!("glob() is unimplemented on Windows") } @@ -1514,7 +1512,10 @@ mod tests { fn test_getenv_big() { let mut s = ~""; let mut i = 0; - while i < 100 { s += "aaaaaaaaaa"; i += 1; } + while i < 100 { + s = s + "aaaaaaaaaa"; + i += 1; + } let n = make_rand_name(); setenv(n, s); debug!(copy s); @@ -1537,7 +1538,7 @@ mod tests { fn test_env_getenv() { let e = env(); assert!(e.len() > 0u); - for e.each |p| { + for e.iter().advance |p| { let (n, v) = copy *p; debug!(copy n); let v2 = getenv(n); @@ -1554,10 +1555,10 @@ mod tests { let mut e = env(); setenv(n, "VALUE"); - assert!(!vec::contains(e, &(copy n, ~"VALUE"))); + assert!(!e.contains(&(copy n, ~"VALUE"))); e = env(); - assert!(vec::contains(e, &(n, ~"VALUE"))); + assert!(e.contains(&(n, ~"VALUE"))); } #[test] @@ -1608,8 +1609,8 @@ mod tests { setenv("USERPROFILE", "/home/PaloAlto"); assert_eq!(os::homedir(), Some(Path("/home/MountainView"))); - oldhome.each(|s| { setenv("HOME", *s); true }); - olduserprofile.each(|s| { setenv("USERPROFILE", *s); true }); + oldhome.iter().advance(|s| { setenv("HOME", *s); true }); + olduserprofile.iter().advance(|s| { setenv("USERPROFILE", *s); true }); } #[test] @@ -1629,7 +1630,7 @@ mod tests { // Just assuming that we've got some contents in the current directory assert!(dirs.len() > 0u); - for dirs.each |dir| { + for dirs.iter().advance |dir| { debug!(copy *dir); } } @@ -1725,5 +1726,5 @@ mod tests { assert!(!os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); } - // More recursive_mkdir tests are in std::tempfile + // More recursive_mkdir tests are in extra::tempfile } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 9c51526aa7f..a5e82c31d79 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -21,12 +21,11 @@ use cmp::Eq; use iterator::IteratorUtil; use libc; use option::{None, Option, Some}; +use str::{OwnedStr, Str, StrSlice, StrVector}; use str; -use str::{Str, StrSlice, StrVector}; use to_str::ToStr; use ascii::{AsciiCast, AsciiStr}; -use old_iter::BaseIter; -use vec::OwnedVector; +use vec::{OwnedVector, ImmutableVector}; #[cfg(windows)] pub use Path = self::WindowsPath; @@ -128,7 +127,6 @@ pub trait GenericPath { #[cfg(target_os = "android")] mod stat { #[cfg(target_arch = "x86")] - #[cfg(target_arch = "arm")] pub mod arch { use libc; @@ -158,6 +156,35 @@ mod stat { } } + #[cfg(target_arch = "arm")] + pub mod arch { + use libc; + + pub fn default_stat() -> libc::stat { + libc::stat { + st_dev: 0, + __pad0: [0, ..4], + __st_ino: 0, + st_mode: 0, + st_nlink: 0, + st_uid: 0, + st_gid: 0, + st_rdev: 0, + __pad3: [0, ..4], + st_size: 0, + st_blksize: 0, + st_blocks: 0, + st_atime: 0, + st_atime_nsec: 0, + st_mtime: 0, + st_mtime_nsec: 0, + st_ctime: 0, + st_ctime_nsec: 0, + st_ino: 0 + } + } + } + #[cfg(target_arch = "mips")] pub mod arch { use libc; @@ -308,8 +335,8 @@ mod stat { } } - -impl Path { +#[cfg(target_os = "win32")] +impl WindowsPath { pub fn stat(&self) -> Option<libc::stat> { unsafe { do str::as_c_str(self.to_str()) |buf| { @@ -322,12 +349,35 @@ impl Path { } } - #[cfg(unix)] - pub fn lstat(&self) -> Option<libc::stat> { + pub fn exists(&self) -> bool { + match self.stat() { + None => false, + Some(_) => true, + } + } + + pub fn get_size(&self) -> Option<i64> { + match self.stat() { + None => None, + Some(ref st) => Some(st.st_size as i64), + } + } + + pub fn get_mode(&self) -> Option<uint> { + match self.stat() { + None => None, + Some(ref st) => Some(st.st_mode as uint), + } + } +} + +#[cfg(not(target_os = "win32"))] +impl PosixPath { + pub fn stat(&self) -> Option<libc::stat> { unsafe { - do str::as_c_str(self.to_str()) |buf| { + do str::as_c_str(self.to_str()) |buf| { let mut st = stat::arch::default_stat(); - match libc::lstat(buf, &mut st) { + match libc::stat(buf, &mut st) { 0 => Some(st), _ => None, } @@ -355,12 +405,21 @@ impl Path { Some(ref st) => Some(st.st_mode as uint), } } + + /// Execute a function on p as well as all of its ancestors + pub fn each_parent(&self, f: &fn(&Path)) { + if !self.components.is_empty() { + f(self); + self.pop().each_parent(f); + } + } + } #[cfg(target_os = "freebsd")] #[cfg(target_os = "linux")] #[cfg(target_os = "macos")] -impl Path { +impl PosixPath { pub fn get_atime(&self) -> Option<(i64, int)> { match self.stat() { None => None, @@ -392,9 +451,24 @@ impl Path { } } +#[cfg(unix)] +impl PosixPath { + pub fn lstat(&self) -> Option<libc::stat> { + unsafe { + do str::as_c_str(self.to_str()) |buf| { + let mut st = stat::arch::default_stat(); + match libc::lstat(buf, &mut st) { + 0 => Some(st), + _ => None, + } + } + } + } +} + #[cfg(target_os = "freebsd")] #[cfg(target_os = "macos")] -impl Path { +impl PosixPath { pub fn get_birthtime(&self) -> Option<(i64, int)> { match self.stat() { None => None, @@ -407,7 +481,7 @@ impl Path { } #[cfg(target_os = "win32")] -impl Path { +impl WindowsPath { pub fn get_atime(&self) -> Option<(i64, int)> { match self.stat() { None => None, @@ -434,13 +508,21 @@ impl Path { } } } + + /// Execute a function on p as well as all of its ancestors + pub fn each_parent(&self, f: &fn(&Path)) { + if !self.components.is_empty() { + f(self); + self.pop().each_parent(f); + } + } } impl ToStr for PosixPath { fn to_str(&self) -> ~str { let mut s = ~""; if self.is_absolute { - s += "/"; + s.push_str("/"); } s + self.components.connect("/") } @@ -568,7 +650,7 @@ impl GenericPath for PosixPath { fn push_many<S: Str>(&self, cs: &[S]) -> PosixPath { let mut v = copy self.components; - for cs.each |e| { + for cs.iter().advance |e| { for e.as_slice().split_iter(windows::is_sep).advance |s| { if !s.is_empty() { v.push(s.to_owned()) @@ -619,15 +701,21 @@ impl ToStr for WindowsPath { fn to_str(&self) -> ~str { let mut s = ~""; match self.host { - Some(ref h) => { s += "\\\\"; s += *h; } + Some(ref h) => { + s.push_str("\\\\"); + s.push_str(*h); + } None => { } } match self.device { - Some(ref d) => { s += *d; s += ":"; } + Some(ref d) => { + s.push_str(*d); + s.push_str(":"); + } None => { } } if self.is_absolute { - s += "\\"; + s.push_str("\\"); } s + self.components.connect("\\") } @@ -825,7 +913,7 @@ impl GenericPath for WindowsPath { fn push_many<S: Str>(&self, cs: &[S]) -> WindowsPath { let mut v = copy self.components; - for cs.each |e| { + for cs.iter().advance |e| { for e.as_slice().split_iter(windows::is_sep).advance |s| { if !s.is_empty() { v.push(s.to_owned()) @@ -887,7 +975,7 @@ impl GenericPath for WindowsPath { pub fn normalize(components: &[~str]) -> ~[~str] { let mut cs = ~[]; - for components.each |c| { + for components.iter().advance |c| { if *c == ~"." && components.len() > 1 { loop; } if *c == ~"" { loop; } if *c == ~".." && cs.len() != 0 { diff --git a/src/libstd/pipes.rs b/src/libstd/pipes.rs index 26dd4af45d6..49713a3a23b 100644 --- a/src/libstd/pipes.rs +++ b/src/libstd/pipes.rs @@ -88,7 +88,7 @@ use container::Container; use cast::{forget, transmute, transmute_copy, transmute_mut}; use either::{Either, Left, Right}; use iterator::IteratorUtil; -use kinds::Owned; +use kinds::Send; use libc; use ops::Drop; use option::{None, Option, Some}; @@ -177,7 +177,7 @@ impl PacketHeader { transmute_copy(&self.buffer) } - pub fn set_buffer<T:Owned>(&mut self, b: ~Buffer<T>) { + pub fn set_buffer<T:Send>(&mut self, b: ~Buffer<T>) { unsafe { self.buffer = transmute_copy(&b); } @@ -193,13 +193,13 @@ pub trait HasBuffer { fn set_buffer(&mut self, b: *libc::c_void); } -impl<T:Owned> HasBuffer for Packet<T> { +impl<T:Send> HasBuffer for Packet<T> { fn set_buffer(&mut self, b: *libc::c_void) { self.header.buffer = b; } } -pub fn mk_packet<T:Owned>() -> Packet<T> { +pub fn mk_packet<T:Send>() -> Packet<T> { Packet { header: PacketHeader(), payload: None, @@ -230,7 +230,7 @@ pub fn packet<T>() -> *mut Packet<T> { p } -pub fn entangle_buffer<T:Owned,Tstart:Owned>( +pub fn entangle_buffer<T:Send,Tstart:Send>( mut buffer: ~Buffer<T>, init: &fn(*libc::c_void, x: &mut T) -> *mut Packet<Tstart>) -> (RecvPacketBuffered<Tstart, T>, SendPacketBuffered<Tstart, T>) { @@ -309,7 +309,7 @@ struct BufferResource<T> { #[unsafe_destructor] impl<T> Drop for BufferResource<T> { - fn finalize(&self) { + fn drop(&self) { unsafe { // FIXME(#4330) Need self by value to get mutability. let this: &mut BufferResource<T> = transmute_mut(self); @@ -396,7 +396,7 @@ pub fn send<T,Tbuffer>(mut p: SendPacketBuffered<T,Tbuffer>, Fails if the sender closes the connection. */ -pub fn recv<T:Owned,Tbuffer:Owned>( +pub fn recv<T:Send,Tbuffer:Send>( p: RecvPacketBuffered<T, Tbuffer>) -> T { try_recv(p).expect("connection closed") } @@ -407,7 +407,7 @@ Returns `None` if the sender has closed the connection without sending a message, or `Some(T)` if a message was received. */ -pub fn try_recv<T:Owned,Tbuffer:Owned>(mut p: RecvPacketBuffered<T, Tbuffer>) +pub fn try_recv<T:Send,Tbuffer:Send>(mut p: RecvPacketBuffered<T, Tbuffer>) -> Option<T> { let p_ = p.unwrap(); let p = unsafe { &mut *p_ }; @@ -427,7 +427,7 @@ pub fn try_recv<T:Owned,Tbuffer:Owned>(mut p: RecvPacketBuffered<T, Tbuffer>) } } -fn try_recv_<T:Owned>(p: &mut Packet<T>) -> Option<T> { +fn try_recv_<T:Send>(p: &mut Packet<T>) -> Option<T> { // optimistic path match p.header.state { Full => { @@ -511,7 +511,7 @@ fn try_recv_<T:Owned>(p: &mut Packet<T>) -> Option<T> { } /// Returns true if messages are available. -pub fn peek<T:Owned,Tb:Owned>(p: &mut RecvPacketBuffered<T, Tb>) -> bool { +pub fn peek<T:Send,Tb:Send>(p: &mut RecvPacketBuffered<T, Tb>) -> bool { unsafe { match (*p.header()).state { Empty | Terminated => false, @@ -521,7 +521,7 @@ pub fn peek<T:Owned,Tb:Owned>(p: &mut RecvPacketBuffered<T, Tb>) -> bool { } } -fn sender_terminate<T:Owned>(p: *mut Packet<T>) { +fn sender_terminate<T:Send>(p: *mut Packet<T>) { let p = unsafe { &mut *p }; @@ -553,7 +553,7 @@ fn sender_terminate<T:Owned>(p: *mut Packet<T>) { } } -fn receiver_terminate<T:Owned>(p: *mut Packet<T>) { +fn receiver_terminate<T:Send>(p: *mut Packet<T>) { let p = unsafe { &mut *p }; @@ -671,8 +671,8 @@ pub struct SendPacketBuffered<T, Tbuffer> { } #[unsafe_destructor] -impl<T:Owned,Tbuffer:Owned> Drop for SendPacketBuffered<T,Tbuffer> { - fn finalize(&self) { +impl<T:Send,Tbuffer:Send> Drop for SendPacketBuffered<T,Tbuffer> { + fn drop(&self) { unsafe { let this: &mut SendPacketBuffered<T,Tbuffer> = transmute(self); if this.p != None { @@ -729,8 +729,8 @@ pub struct RecvPacketBuffered<T, Tbuffer> { } #[unsafe_destructor] -impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> { - fn finalize(&self) { +impl<T:Send,Tbuffer:Send> Drop for RecvPacketBuffered<T,Tbuffer> { + fn drop(&self) { unsafe { let this: &mut RecvPacketBuffered<T,Tbuffer> = transmute(self); if this.p != None { @@ -741,7 +741,7 @@ impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> { } } -impl<T:Owned,Tbuffer:Owned> RecvPacketBuffered<T, Tbuffer> { +impl<T:Send,Tbuffer:Send> RecvPacketBuffered<T, Tbuffer> { pub fn unwrap(&mut self) -> *mut Packet<T> { replace(&mut self.p, None).unwrap() } @@ -751,7 +751,7 @@ impl<T:Owned,Tbuffer:Owned> RecvPacketBuffered<T, Tbuffer> { } } -impl<T:Owned,Tbuffer:Owned> Selectable for RecvPacketBuffered<T, Tbuffer> { +impl<T:Send,Tbuffer:Send> Selectable for RecvPacketBuffered<T, Tbuffer> { fn header(&mut self) -> *mut PacketHeader { match self.p { Some(packet) => unsafe { @@ -807,7 +807,7 @@ Sometimes messages will be available on both endpoints at once. In this case, `select2` may return either `left` or `right`. */ -pub fn select2<A:Owned,Ab:Owned,B:Owned,Bb:Owned>( +pub fn select2<A:Send,Ab:Send,B:Send,Bb:Send>( mut a: RecvPacketBuffered<A, Ab>, mut b: RecvPacketBuffered<B, Bb>) -> Either<(Option<A>, RecvPacketBuffered<B, Bb>), @@ -847,7 +847,7 @@ pub fn select2i<A:Selectable,B:Selectable>(a: &mut A, b: &mut B) /// Waits on a set of endpoints. Returns a message, its index, and a /// list of the remaining endpoints. -pub fn select<T:Owned,Tb:Owned>(mut endpoints: ~[RecvPacketBuffered<T, Tb>]) +pub fn select<T:Send,Tb:Send>(mut endpoints: ~[RecvPacketBuffered<T, Tb>]) -> (uint, Option<T>, ~[RecvPacketBuffered<T, Tb>]) { diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 309df27e151..d560ce621ea 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -29,7 +29,8 @@ Rust's prelude has three main parts: // Reexported core operators pub use either::{Either, Left, Right}; -pub use kinds::{Const, Copy, Owned, Sized}; +pub use kinds::{Copy, Sized}; +pub use kinds::{Freeze, Send}; pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Drop}; @@ -46,8 +47,6 @@ pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Great pub use char::Char; pub use container::{Container, Mutable, Map, Set}; pub use hash::Hash; -pub use old_iter::{BaseIter, ReverseIter, ExtendedIter, EqIter}; -pub use old_iter::CopyableIter; pub use iter::{Times, FromIter}; pub use iterator::{Iterator, IteratorUtil, OrdIterator}; pub use num::{Num, NumCast}; @@ -74,8 +73,8 @@ pub use tuple::{ImmutableTuple2, ImmutableTuple3, ImmutableTuple4, ImmutableTupl pub use tuple::{ImmutableTuple6, ImmutableTuple7, ImmutableTuple8, ImmutableTuple9}; pub use tuple::{ImmutableTuple10, ImmutableTuple11, ImmutableTuple12}; pub use vec::{VectorVector, CopyableVector, ImmutableVector}; -pub use vec::{ImmutableEqVector, ImmutableCopyableVector}; -pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector}; +pub use vec::{ImmutableEqVector, ImmutableTotalOrdVector, ImmutableCopyableVector}; +pub use vec::{OwnedVector, OwnedCopyableVector,OwnedEqVector, MutableVector}; pub use io::{Reader, ReaderUtil, Writer, WriterUtil}; // Reexported runtime types diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index 7f89d454be1..473f56ddd79 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -232,9 +232,9 @@ pub unsafe fn array_each<T>(arr: **T, cb: &fn(*T)) { #[allow(missing_doc)] pub trait RawPtr<T> { - fn is_null(&const self) -> bool; - fn is_not_null(&const self) -> bool; - unsafe fn to_option(&const self) -> Option<&T>; + fn is_null(&self) -> bool; + fn is_not_null(&self) -> bool; + unsafe fn to_option(&self) -> Option<&T>; fn offset(&self, count: uint) -> Self; } @@ -242,11 +242,11 @@ pub trait RawPtr<T> { impl<T> RawPtr<T> for *T { /// Returns true if the pointer is equal to the null pointer. #[inline] - fn is_null(&const self) -> bool { is_null(*self) } + fn is_null(&self) -> bool { is_null(*self) } /// Returns true if the pointer is not equal to the null pointer. #[inline] - fn is_not_null(&const self) -> bool { is_not_null(*self) } + fn is_not_null(&self) -> bool { is_not_null(*self) } /// /// Returns `None` if the pointer is null, or else returns the value wrapped @@ -259,7 +259,7 @@ impl<T> RawPtr<T> for *T { /// be pointing to invalid memory. /// #[inline] - unsafe fn to_option(&const self) -> Option<&T> { + unsafe fn to_option(&self) -> Option<&T> { if self.is_null() { None } else { Some(cast::transmute(*self)) } @@ -274,11 +274,11 @@ impl<T> RawPtr<T> for *T { impl<T> RawPtr<T> for *mut T { /// Returns true if the pointer is equal to the null pointer. #[inline] - fn is_null(&const self) -> bool { is_null(*self) } + fn is_null(&self) -> bool { is_null(*self) } /// Returns true if the pointer is not equal to the null pointer. #[inline] - fn is_not_null(&const self) -> bool { is_not_null(*self) } + fn is_not_null(&self) -> bool { is_not_null(*self) } /// /// Returns `None` if the pointer is null, or else returns the value wrapped @@ -291,7 +291,7 @@ impl<T> RawPtr<T> for *mut T { /// be pointing to invalid memory. /// #[inline] - unsafe fn to_option(&const self) -> Option<&T> { + unsafe fn to_option(&self) -> Option<&T> { if self.is_null() { None } else { Some(cast::transmute(*self)) } diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index 739e3dfedc7..5f96e38a55a 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -42,6 +42,7 @@ fn main () { use cast; use cmp; +use container::Container; use int; use iterator::IteratorUtil; use local_data; @@ -544,7 +545,7 @@ impl<R: Rng> RngUtil for R { fn choose_weighted_option<T:Copy>(&mut self, v: &[Weighted<T>]) -> Option<T> { let mut total = 0u; - for v.each |item| { + for v.iter().advance |item| { total += item.weight; } if total == 0u { @@ -552,7 +553,7 @@ impl<R: Rng> RngUtil for R { } let chosen = self.gen_uint_range(0u, total); let mut so_far = 0u; - for v.each |item| { + for v.iter().advance |item| { so_far += item.weight; if so_far > chosen { return Some(copy item.item); @@ -567,7 +568,7 @@ impl<R: Rng> RngUtil for R { */ fn weighted_vec<T:Copy>(&mut self, v: &[Weighted<T>]) -> ~[T] { let mut r = ~[]; - for v.each |item| { + for v.iter().advance |item| { for uint::range(0u, item.weight) |_i| { r.push(copy item.item); } @@ -589,7 +590,7 @@ impl<R: Rng> RngUtil for R { // invariant: elements with index >= i have been locked in place. i -= 1u; // lock element i in place. - vec::swap(values, i, self.gen_uint_range(0u, i + 1u)); + values.swap(i, self.gen_uint_range(0u, i + 1u)); } } } @@ -720,7 +721,8 @@ impl IsaacRng { fn isaac(&mut self) { self.c += 1; // abbreviations - let mut (a, b) = (self.a, self.b + self.c); + let mut a = self.a; + let mut b = self.b + self.c; static midpoint: uint = RAND_SIZE as uint / 2; @@ -746,7 +748,8 @@ impl IsaacRng { }} ); - for [(0, midpoint), (midpoint, 0)].each |&(mr_offset, m2_offset)| { + let r = [(0, midpoint), (midpoint, 0)]; + for r.iter().advance |&(mr_offset, m2_offset)| { for uint::range_step(0, midpoint, 4) |base| { rngstep!(0, 13); rngstep!(1, -6); @@ -843,7 +846,7 @@ fn tls_rng_state(_v: @@mut IsaacRng) {} * `task_rng().gen::<int>()`. */ #[inline] -pub fn task_rng() -> @@mut IsaacRng { +pub fn task_rng() -> @mut IsaacRng { let r : Option<@@mut IsaacRng>; unsafe { r = local_data::local_data_get(tls_rng_state); @@ -853,20 +856,18 @@ pub fn task_rng() -> @@mut IsaacRng { unsafe { let rng = @@mut IsaacRng::new_seeded(seed()); local_data::local_data_set(tls_rng_state, rng); - rng + *rng } } - Some(rng) => rng + Some(rng) => *rng } } // Allow direct chaining with `task_rng` -impl<R: Rng> Rng for @@mut R { +impl<R: Rng> Rng for @mut R { #[inline] fn next(&mut self) -> u32 { - match *self { - @@ref mut r => r.next() - } + (**self).next() } } @@ -876,9 +877,7 @@ impl<R: Rng> Rng for @@mut R { */ #[inline] pub fn random<T: Rand>() -> T { - match *task_rng() { - @ref mut r => r.gen() - } + task_rng().gen() } #[cfg(test)] diff --git a/src/libstd/rand/distributions.rs b/src/libstd/rand/distributions.rs index 6f4f1a34977..e8dad2fc5e8 100644 --- a/src/libstd/rand/distributions.rs +++ b/src/libstd/rand/distributions.rs @@ -89,7 +89,8 @@ impl Rand for StandardNormal { // do-while, so the condition should be true on the first // run, they get overwritten anyway (0 < 1, so these are // good). - let mut (x, y) = (1.0, 0.0); + let mut x = 1.0; + let mut y = 0.0; // XXX infinities? while -2.0*y < x * x { diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index d276abf0c8b..16ab4771d0d 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -16,8 +16,10 @@ Runtime type reflection #[allow(missing_doc)]; -use intrinsic::{TyDesc, TyVisitor}; -use intrinsic::Opaque; +#[cfg(stage0)] +use intrinsic::{Opaque, TyDesc, TyVisitor}; +#[cfg(not(stage0))] +use unstable::intrinsics::{Opaque, TyDesc, TyVisitor}; use libc::c_void; use sys; use vec; diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index ab3f83d34d5..fdda65d3e95 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -19,9 +19,6 @@ More runtime type reflection use cast::transmute; use char; use container::Container; -use intrinsic; -use intrinsic::{TyDesc, TyVisitor, visit_tydesc}; -use intrinsic::Opaque; use io::{Writer, WriterUtil}; use iterator::IteratorUtil; use libc::c_void; @@ -34,6 +31,10 @@ use to_str::ToStr; use vec::raw::{VecRepr, SliceRepr}; use vec; use vec::{OwnedVector, UnboxedVecRepr}; +#[cfg(stage0)] +use intrinsic::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc}; +#[cfg(not(stage0))] +use unstable::intrinsics::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc}; #[cfg(test)] use io; @@ -56,9 +57,9 @@ impl EscapedCharWriter for @Writer { '"' => self.write_str("\\\""), '\x20'..'\x7e' => self.write_char(ch), _ => { - // FIXME #4423: This is inefficient because it requires a - // malloc. - self.write_str(char::escape_unicode(ch)) + do char::escape_unicode(ch) |c| { + self.write_char(c); + } } } } @@ -80,65 +81,35 @@ impl Repr for bool { } } -impl Repr for int { - fn write_repr(&self, writer: @Writer) { writer.write_int(*self); } -} -impl Repr for i8 { - fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); } -} -impl Repr for i16 { - fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); } -} -impl Repr for i32 { - fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); } -} -impl Repr for i64 { - // FIXME #4424: This can lose precision. - fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); } -} - -impl Repr for uint { - fn write_repr(&self, writer: @Writer) { writer.write_uint(*self); } -} -impl Repr for u8 { - fn write_repr(&self, writer: @Writer) { - writer.write_uint(*self as uint); - } -} -impl Repr for u16 { - fn write_repr(&self, writer: @Writer) { - writer.write_uint(*self as uint); - } -} -impl Repr for u32 { - fn write_repr(&self, writer: @Writer) { - writer.write_uint(*self as uint); - } -} -impl Repr for u64 { - // FIXME #4424: This can lose precision. +macro_rules! int_repr(($ty:ident) => (impl Repr for $ty { fn write_repr(&self, writer: @Writer) { - writer.write_uint(*self as uint); + do ::$ty::to_str_bytes(*self, 10u) |bits| { + writer.write(bits); + } } -} +})) -impl Repr for float { - // FIXME #4423: This mallocs. - fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); } -} -impl Repr for f32 { - // FIXME #4423 This mallocs. - fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); } -} -impl Repr for f64 { - // FIXME #4423: This mallocs. - fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); } -} +int_repr!(int) +int_repr!(i8) +int_repr!(i16) +int_repr!(i32) +int_repr!(i64) +int_repr!(uint) +int_repr!(u8) +int_repr!(u16) +int_repr!(u32) +int_repr!(u64) -impl Repr for char { - fn write_repr(&self, writer: @Writer) { writer.write_char(*self); } -} +macro_rules! num_repr(($ty:ident) => (impl Repr for $ty { + fn write_repr(&self, writer: @Writer) { + let s = self.to_str(); + writer.write(s.as_bytes()); + } +})) +num_repr!(float) +num_repr!(f32) +num_repr!(f64) // New implementation using reflect::MovePtr @@ -564,6 +535,7 @@ impl TyVisitor for ReprVisitor { fn visit_self(&self) -> bool { true } fn visit_type(&self) -> bool { true } + #[cfg(not(stage0))] fn visit_opaque_box(&self) -> bool { self.writer.write_char('@'); do self.get::<&managed::raw::BoxRepr> |b| { @@ -571,6 +543,16 @@ impl TyVisitor for ReprVisitor { self.visit_ptr_inner(p, b.header.type_desc); } } + #[cfg(stage0)] + fn visit_opaque_box(&self) -> bool { + self.writer.write_char('@'); + do self.get::<&managed::raw::BoxRepr> |b| { + let p = ptr::to_unsafe_ptr(&b.data) as *c_void; + unsafe { + self.visit_ptr_inner(p, transmute(b.header.type_desc)); + } + } + } // Type no longer exists, vestigial function. fn visit_constr(&self, _inner: *TyDesc) -> bool { fail!(); } @@ -581,7 +563,7 @@ impl TyVisitor for ReprVisitor { pub fn write_repr<T>(writer: @Writer, object: &T) { unsafe { let ptr = ptr::to_unsafe_ptr(object) as *c_void; - let tydesc = intrinsic::get_tydesc::<T>(); + let tydesc = get_tydesc::<T>(); let u = ReprVisitor(ptr, writer); let v = reflect::MovePtrAdaptor(u); visit_tydesc(tydesc, @v as @TyVisitor) diff --git a/src/libstd/result.rs b/src/libstd/result.rs index 6cef5c33de0..0b099b66ecf 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -16,10 +16,10 @@ use cmp::Eq; use either; use either::Either; use kinds::Copy; +use iterator::IteratorUtil; use option::{None, Option, Some}; -use old_iter::BaseIter; use vec; -use vec::OwnedVector; +use vec::{OwnedVector, ImmutableVector}; use container::Container; /// The result type @@ -303,7 +303,7 @@ pub fn map_vec<T,U:Copy,V:Copy>( ts: &[T], op: &fn(&T) -> Result<V,U>) -> Result<~[V],U> { let mut vs: ~[V] = vec::with_capacity(ts.len()); - for ts.each |t| { + for ts.iter().advance |t| { match op(t) { Ok(v) => vs.push(v), Err(u) => return Err(u) diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index 7608bc89e02..fba61711297 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -19,9 +19,9 @@ use option::*; use cast; use util; use ops::Drop; -use kinds::Owned; -use rt::sched::{Scheduler}; use rt::task::Task; +use kinds::Send; +use rt::sched::Scheduler; use rt::local::Local; use unstable::atomics::{AtomicUint, AtomicOption, SeqCst}; use unstable::sync::UnsafeAtomicRcBox; @@ -71,7 +71,7 @@ pub struct PortOneHack<T> { suppress_finalize: bool } -pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { +pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) { let packet: ~Packet<T> = ~Packet { state: AtomicUint::new(STATE_BOTH), payload: None @@ -242,7 +242,7 @@ impl<T> Peekable<T> for PortOne<T> { #[unsafe_destructor] impl<T> Drop for ChanOneHack<T> { - fn finalize(&self) { + fn drop(&self) { if self.suppress_finalize { return } unsafe { @@ -269,7 +269,7 @@ impl<T> Drop for ChanOneHack<T> { #[unsafe_destructor] impl<T> Drop for PortOneHack<T> { - fn finalize(&self) { + fn drop(&self) { if self.suppress_finalize { return } unsafe { @@ -330,20 +330,20 @@ pub struct Port<T> { next: Cell<StreamPortOne<T>> } -pub fn stream<T: Owned>() -> (Port<T>, Chan<T>) { +pub fn stream<T: Send>() -> (Port<T>, Chan<T>) { let (pone, cone) = oneshot(); let port = Port { next: Cell::new(pone) }; let chan = Chan { next: Cell::new(cone) }; return (port, chan); } -impl<T: Owned> GenericChan<T> for Chan<T> { +impl<T: Send> GenericChan<T> for Chan<T> { fn send(&self, val: T) { self.try_send(val); } } -impl<T: Owned> GenericSmartChan<T> for Chan<T> { +impl<T: Send> GenericSmartChan<T> for Chan<T> { fn try_send(&self, val: T) -> bool { let (next_pone, next_cone) = oneshot(); let cone = self.next.take(); @@ -393,13 +393,13 @@ impl<T> SharedChan<T> { } } -impl<T: Owned> GenericChan<T> for SharedChan<T> { +impl<T: Send> GenericChan<T> for SharedChan<T> { fn send(&self, val: T) { self.try_send(val); } } -impl<T: Owned> GenericSmartChan<T> for SharedChan<T> { +impl<T: Send> GenericSmartChan<T> for SharedChan<T> { fn try_send(&self, val: T) -> bool { unsafe { let (next_pone, next_cone) = oneshot(); @@ -433,7 +433,7 @@ impl<T> SharedPort<T> { } } -impl<T: Owned> GenericPort<T> for SharedPort<T> { +impl<T: Send> GenericPort<T> for SharedPort<T> { fn recv(&self) -> T { match self.try_recv() { Some(val) => val, @@ -475,12 +475,12 @@ impl<T> Clone for SharedPort<T> { // XXX: Need better name type MegaPipe<T> = (SharedPort<T>, SharedChan<T>); -pub fn megapipe<T: Owned>() -> MegaPipe<T> { +pub fn megapipe<T: Send>() -> MegaPipe<T> { let (port, chan) = stream(); (SharedPort::new(port), SharedChan::new(chan)) } -impl<T: Owned> GenericChan<T> for MegaPipe<T> { +impl<T: Send> GenericChan<T> for MegaPipe<T> { fn send(&self, val: T) { match *self { (_, ref c) => c.send(val) @@ -488,7 +488,7 @@ impl<T: Owned> GenericChan<T> for MegaPipe<T> { } } -impl<T: Owned> GenericSmartChan<T> for MegaPipe<T> { +impl<T: Send> GenericSmartChan<T> for MegaPipe<T> { fn try_send(&self, val: T) -> bool { match *self { (_, ref c) => c.try_send(val) @@ -496,7 +496,7 @@ impl<T: Owned> GenericSmartChan<T> for MegaPipe<T> { } } -impl<T: Owned> GenericPort<T> for MegaPipe<T> { +impl<T: Send> GenericPort<T> for MegaPipe<T> { fn recv(&self) -> T { match *self { (ref p, _) => p.recv() diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index e89df2b1c93..4b475d74397 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -8,104 +8,129 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use sys::{TypeDesc, size_of}; -use libc::{c_void, size_t, uintptr_t}; -use c_malloc = libc::malloc; -use c_free = libc::free; +use libc::{c_void, c_char, size_t, uintptr_t, free, malloc, realloc}; use managed::raw::{BoxHeaderRepr, BoxRepr}; -use cast::transmute; -use unstable::intrinsics::{atomic_xadd,atomic_xsub, atomic_load}; -use ptr::null; -use intrinsic::TyDesc; +use unstable::intrinsics::TyDesc; +use sys::size_of; -pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void { - assert!(td.is_not_null()); - - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert!(p.is_not_null()); - - // FIXME #3475: Converting between our two different tydesc types - let td: *TyDesc = transmute(td); - - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); +extern { + #[rust_stack] + fn abort(); +} - inc_count(); +#[inline] +fn get_box_size(body_size: uint, body_align: uint) -> uint { + let header_size = size_of::<BoxHeaderRepr>(); + // FIXME (#2699): This alignment calculation is suspicious. Is it right? + let total_size = align_to(header_size, body_align) + body_size; + total_size +} - return transmute(box); +// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power +// of two. +#[inline] +fn align_to(size: uint, align: uint) -> uint { + assert!(align != 0); + (size + align - 1) & !(align - 1) } -/** -Thin wrapper around libc::malloc, none of the box header -stuff in exchange_alloc::malloc -*/ + +/// A wrapper around libc::malloc, aborting on out-of-memory +#[inline] pub unsafe fn malloc_raw(size: uint) -> *c_void { - let p = c_malloc(size as size_t); + let p = malloc(size as size_t); if p.is_null() { - fail!("Failure in malloc_raw: result ptr is null"); + // we need a non-allocating way to print an error here + abort(); } - inc_count(); p } -pub unsafe fn free(ptr: *c_void) { - assert!(ptr.is_not_null()); - dec_count(); - c_free(ptr); +/// A wrapper around libc::realloc, aborting on out-of-memory +#[inline] +pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void { + let p = realloc(ptr, size as size_t); + if p.is_null() { + // we need a non-allocating way to print an error here + abort(); + } + p } -///Thin wrapper around libc::free, as with exchange_alloc::malloc_raw -pub unsafe fn free_raw(ptr: *c_void) { - assert!(ptr.is_not_null()); - dec_count(); - c_free(ptr); + +// FIXME #4942: Make these signatures agree with exchange_alloc's signatures +#[cfg(stage0, not(test))] +#[lang="exchange_malloc"] +#[inline] +pub unsafe fn exchange_malloc_(td: *c_char, size: uintptr_t) -> *c_char { + exchange_malloc(td, size) } -fn inc_count() { - unsafe { - let exchange_count = &mut *exchange_count_ptr(); - atomic_xadd(exchange_count, 1); - } +#[cfg(stage0)] +#[inline] +pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + let p = malloc_raw(total_size as uint); + + let box: *mut BoxRepr = p as *mut BoxRepr; + (*box).header.ref_count = -1; + (*box).header.type_desc = td; + + box as *c_char } -fn dec_count() { - unsafe { - let exchange_count = &mut *exchange_count_ptr(); - atomic_xsub(exchange_count, 1); - } +// FIXME #4942: Make these signatures agree with exchange_alloc's signatures +#[cfg(not(stage0), not(test))] +#[lang="exchange_malloc"] +#[inline] +pub unsafe fn exchange_malloc_(align: u32, size: uintptr_t) -> *c_char { + exchange_malloc(align, size) } -pub fn cleanup() { - unsafe { - let count_ptr = exchange_count_ptr(); - let allocations = atomic_load(&*count_ptr); - if allocations != 0 { - rtabort!("exchange heap not empty on exit - %i dangling allocations", allocations); - } - } +#[cfg(not(stage0))] +#[inline] +pub unsafe fn exchange_malloc(align: u32, size: uintptr_t) -> *c_char { + let total_size = get_box_size(size as uint, align as uint); + malloc_raw(total_size as uint) as *c_char } -fn get_box_size(body_size: uint, body_align: uint) -> uint { - let header_size = size_of::<BoxHeaderRepr>(); - // FIXME (#2699): This alignment calculation is suspicious. Is it right? - let total_size = align_to(header_size, body_align) + body_size; - return total_size; +// FIXME: #7496 +#[cfg(not(test))] +#[lang="closure_exchange_malloc"] +#[inline] +pub unsafe fn closure_exchange_malloc_(td: *c_char, size: uintptr_t) -> *c_char { + closure_exchange_malloc(td, size) } -// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power -// of two. -fn align_to(size: uint, align: uint) -> uint { - assert!(align != 0); - (size + align - 1) & !(align - 1) +#[inline] +pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + let p = malloc_raw(total_size as uint); + + let box: *mut BoxRepr = p as *mut BoxRepr; + (*box).header.type_desc = td; + + box as *c_char } -fn exchange_count_ptr() -> *mut int { - // XXX: Need mutable globals - unsafe { transmute(&rust_exchange_count) } +// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from +// inside a landing pad may corrupt the state of the exception handler. +#[cfg(not(test))] +#[lang="exchange_free"] +#[inline] +pub unsafe fn exchange_free_(ptr: *c_char) { + exchange_free(ptr) } -extern { - static rust_exchange_count: uintptr_t; +#[inline] +pub unsafe fn exchange_free(ptr: *c_char) { + free(ptr as *c_void); } diff --git a/src/libstd/rt/io/extensions.rs b/src/libstd/rt/io/extensions.rs index 55861f127bb..c6654e9dabe 100644 --- a/src/libstd/rt/io/extensions.rs +++ b/src/libstd/rt/io/extensions.rs @@ -292,13 +292,13 @@ impl<T: Reader> ReaderUtil for T { let start_len = buf.len(); let mut total_read = 0; - vec::reserve_at_least(buf, start_len + len); + buf.reserve_at_least(start_len + len); vec::raw::set_len(buf, start_len + len); do (|| { while total_read < len { let len = buf.len(); - let slice = vec::mut_slice(*buf, start_len + total_read, len); + let slice = buf.mut_slice(start_len + total_read, len); match self.read(slice) { Some(nread) => { total_read += nread; @@ -343,7 +343,9 @@ impl<T: Reader> ReaderByteConversions for T { fn read_le_uint_n(&mut self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut (val, pos, i) = (0u64, 0, nbytes); + let mut val = 0u64; + let mut pos = 0; + let mut i = nbytes; while i > 0 { val += (self.read_u8() as u64) << pos; pos += 8; @@ -359,7 +361,8 @@ impl<T: Reader> ReaderByteConversions for T { fn read_be_uint_n(&mut self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut (val, i) = (0u64, nbytes); + let mut val = 0u64; + let mut i = nbytes; while i > 0 { i -= 1; val += (self.read_u8() as u64) << i * 8; diff --git a/src/libstd/rt/io/mem.rs b/src/libstd/rt/io/mem.rs index bd9cff76e57..c93945a6a9a 100644 --- a/src/libstd/rt/io/mem.rs +++ b/src/libstd/rt/io/mem.rs @@ -86,7 +86,7 @@ impl Reader for MemReader { let write_len = min(buf.len(), self.buf.len() - self.pos); { let input = self.buf.slice(self.pos, self.pos + write_len); - let output = vec::mut_slice(buf, 0, write_len); + let output = buf.mut_slice(0, write_len); assert_eq!(input.len(), output.len()); vec::bytes::copy_memory(output, input, write_len); } diff --git a/src/libstd/rt/join_latch.rs b/src/libstd/rt/join_latch.rs index 79c0d5da9a4..8073c4a75b8 100644 --- a/src/libstd/rt/join_latch.rs +++ b/src/libstd/rt/join_latch.rs @@ -321,7 +321,7 @@ impl JoinLatch { } impl Drop for JoinLatch { - fn finalize(&self) { + fn drop(&self) { rtdebug!("DESTROYING %x", self.id()); rtassert!(self.closed); } @@ -333,7 +333,6 @@ mod test { use cell::Cell; use container::Container; use iter::Times; - use old_iter::BaseIter; use rt::test::*; use rand; use rand::RngUtil; @@ -552,7 +551,7 @@ mod test { rtdebug!("depth: %u", depth); let mut remaining_orders = remaining_orders; let mut num = 0; - for my_orders.each |&order| { + for my_orders.iter().advance |&order| { let child_latch = latch.new_child(); let child_latch = Cell::new(child_latch); let (child_orders, remaining) = split_orders(remaining_orders); @@ -592,7 +591,7 @@ mod test { orders: ~[Order] } fn next(latch: &mut JoinLatch, orders: ~[Order]) { - for orders.each |order| { + for orders.iter().advance |order| { let suborders = copy order.orders; let child_latch = Cell::new(latch.new_child()); let succeed = order.succeed; diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index f62c9fb2c66..c909bdb6285 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -76,7 +76,7 @@ impl LocalHeap { } impl Drop for LocalHeap { - fn finalize(&self) { + fn drop(&self) { unsafe { rust_delete_boxed_region(self.boxed_region); rust_delete_memory_region(self.memory_region); diff --git a/src/libstd/rt/message_queue.rs b/src/libstd/rt/message_queue.rs index 734be808797..6ef07577415 100644 --- a/src/libstd/rt/message_queue.rs +++ b/src/libstd/rt/message_queue.rs @@ -12,7 +12,7 @@ //! single consumer. use container::Container; -use kinds::Owned; +use kinds::Send; use vec::OwnedVector; use cell::Cell; use option::*; @@ -24,7 +24,7 @@ pub struct MessageQueue<T> { priv queue: ~Exclusive<~[T]> } -impl<T: Owned> MessageQueue<T> { +impl<T: Send> MessageQueue<T> { pub fn new() -> MessageQueue<T> { MessageQueue { queue: ~exclusive(~[]) diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index aae194ae548..b70549c266a 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -209,7 +209,6 @@ pub fn init(argc: int, argv: **u8, crate_map: *u8) { /// One-time runtime cleanup. pub fn cleanup() { args::cleanup(); - global_heap::cleanup(); } /// Execute the main function in a scheduler. diff --git a/src/libstd/rt/rc.rs b/src/libstd/rt/rc.rs index 2977d081508..18a5dd4a114 100644 --- a/src/libstd/rt/rc.rs +++ b/src/libstd/rt/rc.rs @@ -74,7 +74,7 @@ impl<T> RC<T> { #[unsafe_destructor] impl<T> Drop for RC<T> { - fn finalize(&self) { + fn drop(&self) { assert!(self.refcount() > 0); unsafe { diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 7d8c673636e..6e9aef77730 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -1074,7 +1074,8 @@ mod test { let n_tasks = 10; let token = 2000; - let mut (p, ch1) = stream(); + let (p, ch1) = stream(); + let mut p = p; ch1.send((token, end_chan)); let mut i = 2; while i <= n_tasks { @@ -1127,7 +1128,7 @@ mod test { struct S { field: () } impl Drop for S { - fn finalize(&self) { + fn drop(&self) { let _foo = @0; } } diff --git a/src/libstd/rt/stack.rs b/src/libstd/rt/stack.rs index b0e87a62c8b..fbb516b2df4 100644 --- a/src/libstd/rt/stack.rs +++ b/src/libstd/rt/stack.rs @@ -49,7 +49,7 @@ impl StackSegment { } impl Drop for StackSegment { - fn finalize(&self) { + fn drop(&self) { unsafe { // XXX: Using the FFI to call a C macro. Slow rust_valgrind_stack_deregister(self.valgrind_id); diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index b2e4f0d4716..b4f4c1b3e35 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -219,7 +219,7 @@ impl Task { } impl Drop for Task { - fn finalize(&self) { assert!(self.destroyed) } + fn drop(&self) { assert!(self.destroyed) } } // Coroutines represent nothing more than a context and a stack diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs index bc290191310..98d08c060e0 100644 --- a/src/libstd/rt/thread.rs +++ b/src/libstd/rt/thread.rs @@ -33,7 +33,7 @@ impl Thread { } impl Drop for Thread { - fn finalize(&self) { + fn drop(&self) { unsafe { rust_raw_thread_join_delete(self.raw_thread) } } } diff --git a/src/libstd/rt/thread_local_storage.rs b/src/libstd/rt/thread_local_storage.rs index 7187d2db41c..5041b559ecb 100644 --- a/src/libstd/rt/thread_local_storage.rs +++ b/src/libstd/rt/thread_local_storage.rs @@ -60,13 +60,13 @@ pub type Key = DWORD; #[cfg(windows)] pub unsafe fn create(key: &mut Key) { static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; - *key = unsafe { TlsAlloc() }; + *key = TlsAlloc(); assert!(*key != TLS_OUT_OF_INDEXES); } #[cfg(windows)] pub unsafe fn set(key: Key, value: *mut c_void) { - unsafe { assert!(0 != TlsSetValue(key, value)) } + assert!(0 != TlsSetValue(key, value)) } #[cfg(windows)] diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 4571747cebf..ada9aee35a7 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -389,7 +389,8 @@ mod test { if status.is_none() { rtdebug!("got %d bytes", nread); let buf = buf.unwrap(); - for buf.slice(0, nread as uint).each |byte| { + let r = buf.slice(0, nread as uint); + for r.iter().advance |byte| { assert!(*byte == count as u8); rtdebug!("%u", *byte as uint); count += 1; diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index b1708e70733..69d14dbf9a1 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -47,7 +47,7 @@ impl UvEventLoop { } impl Drop for UvEventLoop { - fn finalize(&self) { + fn drop(&self) { // XXX: Need mutable finalizer let this = unsafe { transmute::<&UvEventLoop, &mut UvEventLoop>(self) @@ -139,7 +139,7 @@ impl RemoteCallback for UvRemoteCallback { } impl Drop for UvRemoteCallback { - fn finalize(&self) { + fn drop(&self) { unsafe { let this: &mut UvRemoteCallback = cast::transmute_mut(self); do this.exit_flag.with |should_exit| { @@ -285,7 +285,7 @@ impl UvTcpListener { } impl Drop for UvTcpListener { - fn finalize(&self) { + fn drop(&self) { let watcher = self.watcher(); let scheduler = Local::take::<Scheduler>(); do scheduler.deschedule_running_task_and_then |_, task| { @@ -346,7 +346,7 @@ impl UvTcpStream { } impl Drop for UvTcpStream { - fn finalize(&self) { + fn drop(&self) { rtdebug!("closing tcp stream"); let watcher = self.watcher(); let scheduler = Local::take::<Scheduler>(); diff --git a/src/libstd/rt/uvio.rs b/src/libstd/rt/uvio.rs index 070ccf7fb44..0187ad3abf5 100644 --- a/src/libstd/rt/uvio.rs +++ b/src/libstd/rt/uvio.rs @@ -15,7 +15,6 @@ use super::io::net::ip::IpAddr; use super::uv::*; use super::rtio::*; use ops::Drop; -use old_iter::CopyableIter; use cell::Cell; use cast::transmute; use super::sched::{Scheduler, local_sched}; @@ -43,7 +42,7 @@ impl UvEventLoop { } impl Drop for UvEventLoop { - fn finalize(&self) { + fn drop(&self) { // XXX: Need mutable finalizer let this = unsafe { transmute::<&UvEventLoop, &mut UvEventLoop>(self) @@ -165,7 +164,7 @@ impl UvTcpListener { } impl Drop for UvTcpListener { - fn finalize(&self) { + fn drop(&self) { // XXX: Again, this never gets called. Use .close() instead //self.watcher().as_stream().close(||()); } @@ -231,7 +230,7 @@ impl UvStream { } impl Drop for UvStream { - fn finalize(&self) { + fn drop(&self) { rtdebug!("closing stream"); //self.watcher().close(||()); } diff --git a/src/libstd/rt/work_queue.rs b/src/libstd/rt/work_queue.rs index cfffc55a58c..00d27744268 100644 --- a/src/libstd/rt/work_queue.rs +++ b/src/libstd/rt/work_queue.rs @@ -13,7 +13,7 @@ use option::*; use vec::OwnedVector; use unstable::sync::{Exclusive, exclusive}; use cell::Cell; -use kinds::Owned; +use kinds::Send; use clone::Clone; pub struct WorkQueue<T> { @@ -21,7 +21,7 @@ pub struct WorkQueue<T> { priv queue: ~Exclusive<~[T]> } -impl<T: Owned> WorkQueue<T> { +impl<T: Send> WorkQueue<T> { pub fn new() -> WorkQueue<T> { WorkQueue { queue: ~exclusive(~[]) diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 060de3f4d5d..9e5def253c7 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -12,11 +12,10 @@ #[allow(missing_doc)]; -use iterator::IteratorUtil; use cast; use comm::{stream, SharedChan, GenericChan, GenericPort}; -use int; use io; +use iterator::IteratorUtil; use libc::{pid_t, c_void, c_int}; use libc; use option::{Some, None}; @@ -428,7 +427,7 @@ impl Process { } impl Drop for Process { - fn finalize(&self) { + fn drop(&self) { // FIXME(#4330) Need self by value to get mutability. let mut_self: &mut Process = unsafe { cast::transmute(self) }; @@ -465,7 +464,6 @@ fn spawn_process_os(prog: &str, args: &[~str], use libc::funcs::extra::msvcrt::get_osfhandle; use sys; - use uint; unsafe { @@ -582,7 +580,7 @@ pub fn make_command_line(prog: &str, args: &[~str]) -> ~str { let mut cmd = ~""; append_arg(&mut cmd, prog); - for args.each |arg| { + for args.iter().advance |arg| { cmd.push_char(' '); append_arg(&mut cmd, *arg); } @@ -638,6 +636,7 @@ fn spawn_process_os(prog: &str, args: &[~str], use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; use libc::funcs::bsd44::getdtablesize; + use int; mod rustrt { use libc::c_void; @@ -698,7 +697,7 @@ fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T { let mut argptrs = ~[str::as_c_str(prog, |b| b)]; let mut tmps = ~[]; - for args.each |arg| { + for args.iter().advance |arg| { let t = @copy *arg; tmps.push(t); argptrs.push(str::as_c_str(*t, |b| b)); @@ -716,7 +715,7 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T { let mut tmps = ~[]; let mut ptrs = ~[]; - for es.each |&(k, v)| { + for es.iter().advance |&(k, v)| { let kv = @fmt!("%s=%s", k, v); tmps.push(kv); ptrs.push(str::as_c_str(*kv, |b| b)); @@ -739,7 +738,7 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T { match env { Some(es) => { let mut blk = ~[]; - for es.each |&(k, v)| { + for es.iter().advance |&(k, v)| { let kv = fmt!("%s=%s", k, v); blk.push_all(kv.as_bytes_with_null_consume()); } @@ -944,12 +943,20 @@ mod tests { } #[test] + #[cfg(not(target_os="android"))] fn test_process_status() { assert_eq!(run::process_status("false", []), 1); assert_eq!(run::process_status("true", []), 0); } + #[test] + #[cfg(target_os="android")] + fn test_process_status() { + assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"false"]), 1); + assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"true"]), 0); + } #[test] + #[cfg(not(target_os="android"))] fn test_process_output_output() { let run::ProcessOutput {status, output, error} @@ -963,8 +970,24 @@ mod tests { assert_eq!(error, ~[]); } } + #[test] + #[cfg(target_os="android")] + fn test_process_output_output() { + + let run::ProcessOutput {status, output, error} + = run::process_output("/system/bin/sh", [~"-c",~"echo hello"]); + let output_str = str::from_bytes(output); + + assert_eq!(status, 0); + assert_eq!(output_str.trim().to_owned(), ~"hello"); + // FIXME #7224 + if !running_on_valgrind() { + assert_eq!(error, ~[]); + } + } #[test] + #[cfg(not(target_os="android"))] fn test_process_output_error() { let run::ProcessOutput {status, output, error} @@ -974,6 +997,17 @@ mod tests { assert_eq!(output, ~[]); assert!(!error.is_empty()); } + #[test] + #[cfg(target_os="android")] + fn test_process_output_error() { + + let run::ProcessOutput {status, output, error} + = run::process_output("/system/bin/mkdir", [~"."]); + + assert_eq!(status, 255); + assert_eq!(output, ~[]); + assert!(!error.is_empty()); + } #[test] fn test_pipes() { @@ -1024,19 +1058,37 @@ mod tests { } #[test] + #[cfg(not(target_os="android"))] fn test_finish_once() { let mut prog = run::Process::new("false", [], run::ProcessOptions::new()); assert_eq!(prog.finish(), 1); } + #[test] + #[cfg(target_os="android")] + fn test_finish_once() { + let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"], + run::ProcessOptions::new()); + assert_eq!(prog.finish(), 1); + } #[test] + #[cfg(not(target_os="android"))] fn test_finish_twice() { let mut prog = run::Process::new("false", [], run::ProcessOptions::new()); assert_eq!(prog.finish(), 1); assert_eq!(prog.finish(), 1); } + #[test] + #[cfg(target_os="android")] + fn test_finish_twice() { + let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"], + run::ProcessOptions::new()); + assert_eq!(prog.finish(), 1); + assert_eq!(prog.finish(), 1); + } #[test] + #[cfg(not(target_os="android"))] fn test_finish_with_output_once() { let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new()); @@ -1051,8 +1103,26 @@ mod tests { assert_eq!(error, ~[]); } } + #[test] + #[cfg(target_os="android")] + fn test_finish_with_output_once() { + + let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"], + run::ProcessOptions::new()); + let run::ProcessOutput {status, output, error} + = prog.finish_with_output(); + let output_str = str::from_bytes(output); + + assert_eq!(status, 0); + assert_eq!(output_str.trim().to_owned(), ~"hello"); + // FIXME #7224 + if !running_on_valgrind() { + assert_eq!(error, ~[]); + } + } #[test] + #[cfg(not(target_os="android"))] fn test_finish_with_output_twice() { let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new()); @@ -1078,10 +1148,38 @@ mod tests { assert_eq!(error, ~[]); } } + #[test] + #[cfg(target_os="android")] + fn test_finish_with_output_twice() { + + let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"], + run::ProcessOptions::new()); + let run::ProcessOutput {status, output, error} + = prog.finish_with_output(); + + let output_str = str::from_bytes(output); + + assert_eq!(status, 0); + assert_eq!(output_str.trim().to_owned(), ~"hello"); + // FIXME #7224 + if !running_on_valgrind() { + assert_eq!(error, ~[]); + } + + let run::ProcessOutput {status, output, error} + = prog.finish_with_output(); + + assert_eq!(status, 0); + assert_eq!(output, ~[]); + // FIXME #7224 + if !running_on_valgrind() { + assert_eq!(error, ~[]); + } + } #[test] #[should_fail] - #[cfg(not(windows))] + #[cfg(not(windows),not(target_os="android"))] fn test_finish_with_output_redirected() { let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions { env: None, @@ -1093,14 +1191,36 @@ mod tests { // this should fail because it is not valid to read the output when it was redirected prog.finish_with_output(); } + #[test] + #[should_fail] + #[cfg(not(windows),target_os="android")] + fn test_finish_with_output_redirected() { + let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"], + run::ProcessOptions { + env: None, + dir: None, + in_fd: Some(0), + out_fd: Some(1), + err_fd: Some(2) + }); + // this should fail because it is not valid to read the output when it was redirected + prog.finish_with_output(); + } - #[cfg(unix)] + #[cfg(unix,not(target_os="android"))] fn run_pwd(dir: Option<&Path>) -> run::Process { run::Process::new("pwd", [], run::ProcessOptions { dir: dir, .. run::ProcessOptions::new() }) } + #[cfg(unix,target_os="android")] + fn run_pwd(dir: Option<&Path>) -> run::Process { + run::Process::new("/system/bin/sh", [~"-c",~"pwd"], run::ProcessOptions { + dir: dir, + .. run::ProcessOptions::new() + }) + } #[cfg(windows)] fn run_pwd(dir: Option<&Path>) -> run::Process { @@ -1142,13 +1262,20 @@ mod tests { assert_eq!(parent_stat.st_ino, child_stat.st_ino); } - #[cfg(unix)] + #[cfg(unix,not(target_os="android"))] fn run_env(env: Option<&[(~str, ~str)]>) -> run::Process { run::Process::new("env", [], run::ProcessOptions { env: env, .. run::ProcessOptions::new() }) } + #[cfg(unix,target_os="android")] + fn run_env(env: Option<&[(~str, ~str)]>) -> run::Process { + run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions { + env: env, + .. run::ProcessOptions::new() + }) + } #[cfg(windows)] fn run_env(env: Option<&[(~str, ~str)]>) -> run::Process { @@ -1159,17 +1286,36 @@ mod tests { } #[test] + #[cfg(not(target_os="android"))] fn test_inherit_env() { if running_on_valgrind() { return; } let mut prog = run_env(None); let output = str::from_bytes(prog.finish_with_output().output); - for os::env().each |&(k, v)| { + let r = os::env(); + for r.iter().advance |&(k, v)| { // don't check windows magical empty-named variables assert!(k.is_empty() || output.contains(fmt!("%s=%s", k, v))); } } + #[test] + #[cfg(target_os="android")] + fn test_inherit_env() { + if running_on_valgrind() { return; } + + let mut prog = run_env(None); + let output = str::from_bytes(prog.finish_with_output().output); + + let r = os::env(); + for r.iter().advance |&(k, v)| { + // don't check android RANDOM variables + if k != ~"RANDOM" { + assert!(output.contains(fmt!("%s=%s", k, v)) || + output.contains(fmt!("%s=\'%s\'", k, v))); + } + } + } #[test] fn test_add_to_env() { diff --git a/src/libstd/core.rc b/src/libstd/std.rs index 6911c00e55b..f0f3bcdd4e9 100644 --- a/src/libstd/core.rc +++ b/src/libstd/std.rs @@ -49,7 +49,7 @@ they contained the following prologue: #[link(name = "std", - vers = "0.7-pre", + vers = "0.7", uuid = "c70c24a7-5551-4f73-8e37-380b11d80be8", url = "https://github.com/mozilla/rust/tree/master/src/libstd")]; @@ -138,7 +138,6 @@ pub mod from_str; #[path = "num/num.rs"] pub mod num; pub mod iter; -pub mod old_iter; pub mod iterator; pub mod to_str; pub mod to_bytes; diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 04f5247782b..4115cad6559 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -14,7 +14,7 @@ * Strings are a packed UTF-8 representation of text, stored as null * terminated buffers of u8 bytes. Strings should be indexed in bytes, * for efficiency, but UTF-8 unsafe operations should be avoided. For - * some heavy-duty uses, try std::rope. + * some heavy-duty uses, try extra::rope. */ use at_vec; @@ -29,7 +29,6 @@ use iterator::{Iterator, IteratorUtil, FilterIterator, AdditiveIterator, MapIter use libc; use num::Zero; use option::{None, Option, Some}; -use old_iter::{BaseIter, EqIter}; use ptr; use ptr::RawPtr; use to_str::ToStr; @@ -55,12 +54,11 @@ Section: Creating a string * * Raises the `not_utf8` condition if invalid UTF-8 */ - pub fn from_bytes(vv: &[u8]) -> ~str { use str::not_utf8::cond; if !is_utf8(vv) { - let first_bad_byte = vec::find(vv, |b| !is_utf8([*b])).get(); + let first_bad_byte = *vv.iter().find_(|&b| !is_utf8([*b])).get(); cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u", first_bad_byte as uint)) } @@ -70,6 +68,25 @@ pub fn from_bytes(vv: &[u8]) -> ~str { } /** + * Consumes a vector of bytes to create a new utf-8 string + * + * # Failure + * + * Raises the `not_utf8` condition if invalid UTF-8 + */ +pub fn from_bytes_owned(vv: ~[u8]) -> ~str { + use str::not_utf8::cond; + + if !is_utf8(vv) { + let first_bad_byte = *vv.iter().find_(|&b| !is_utf8([*b])).get(); + cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u", + first_bad_byte as uint)) + } else { + return unsafe { raw::from_bytes_owned(vv) } + } +} + +/** * Convert a vector of bytes to a UTF-8 string. * The vector needs to be one byte longer than the string, and end with a 0 byte. * @@ -147,7 +164,7 @@ pub fn from_char(ch: char) -> ~str { pub fn from_chars(chs: &[char]) -> ~str { let mut buf = ~""; buf.reserve(chs.len()); - for chs.each |ch| { + for chs.iter().advance |ch| { buf.push_char(*ch) } buf @@ -358,7 +375,8 @@ impl<'self> Iterator<(uint, uint)> for StrMatchesIndexIterator<'self> { fn next(&mut self) -> Option<(uint, uint)> { // See Issue #1932 for why this is a naive search let (h_len, n_len) = (self.haystack.len(), self.needle.len()); - let mut (match_start, match_i) = (0, 0); + let mut match_start = 0; + let mut match_i = 0; while self.position < h_len { if self.haystack[self.position] == self.needle[match_i] { @@ -434,10 +452,17 @@ pub fn each_split_within<'a>(ss: &'a str, let mut last_start = 0; let mut last_end = 0; let mut state = A; + let mut fake_i = ss.len(); + let mut lim = lim; let mut cont = true; let slice: &fn() = || { cont = it(ss.slice(slice_start, last_end)) }; + // if the limit is larger than the string, lower it to save cycles + if (lim >= fake_i) { + lim = fake_i; + } + let machine: &fn((uint, char)) -> bool = |(i, c)| { let whitespace = if char::is_whitespace(c) { Ws } else { Cr }; let limit = if (i - slice_start + 1) <= lim { UnderLim } else { OverLim }; @@ -463,10 +488,9 @@ pub fn each_split_within<'a>(ss: &'a str, cont }; - ss.iter().enumerate().advance(machine); + ss.iter().enumerate().advance(|x| machine(x)); // Let the automaton 'run out' by supplying trailing whitespace - let mut fake_i = ss.len(); while cont && match state { B | C => true, A => false } { machine((fake_i, ' ')); fake_i += 1; @@ -474,6 +498,31 @@ pub fn each_split_within<'a>(ss: &'a str, return cont; } +/** + * Replace all occurrences of one string with another + * + * # Arguments + * + * * s - The string containing substrings to replace + * * from - The string to replace + * * to - The replacement string + * + * # Return value + * + * The original string with all occurances of `from` replaced with `to` + */ +pub fn replace(s: &str, from: &str, to: &str) -> ~str { + let mut result = ~""; + let mut last_end = 0; + for s.matches_index_iter(from).advance |(start, end)| { + result.push_str(unsafe{raw::slice_bytes(s, last_end, start)}); + result.push_str(to); + last_end = end; + } + result.push_str(unsafe{raw::slice_bytes(s, last_end, s.len())}); + result +} + /* Section: Comparing strings */ @@ -544,7 +593,7 @@ Section: Misc */ /// Determines if a vector of bytes contains valid UTF-8 -pub fn is_utf8(v: &const [u8]) -> bool { +pub fn is_utf8(v: &[u8]) -> bool { let mut i = 0u; let total = v.len(); while i < total { @@ -632,6 +681,48 @@ pub fn with_capacity(capacity: uint) -> ~str { buf } +/** + * As char_len but for a slice of a string + * + * # Arguments + * + * * s - A valid string + * * start - The position inside `s` where to start counting in bytes + * * end - The position where to stop counting + * + * # Return value + * + * The number of Unicode characters in `s` between the given indices. + */ +pub fn count_chars(s: &str, start: uint, end: uint) -> uint { + assert!(s.is_char_boundary(start)); + assert!(s.is_char_boundary(end)); + let mut i = start; + let mut len = 0u; + while i < end { + let next = s.char_range_at(i).next; + len += 1u; + i = next; + } + return len; +} + +/// Counts the number of bytes taken by the first `n` chars in `s` +/// starting from `start`. +pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint { + assert!(s.is_char_boundary(start)); + let mut end = start; + let mut cnt = n; + let l = s.len(); + while cnt > 0u { + assert!(end < l); + let next = s.char_range_at(end).next; + cnt -= 1u; + end = next; + } + end - start +} + /// Given a first byte, determine how many bytes are in this UTF-8 character pub fn utf8_char_width(b: u8) -> uint { let byte: uint = b as uint; @@ -694,7 +785,7 @@ impl<'self> StrUtil for &'self str { // NB: len includes the trailing null. assert!(len > 0); if unsafe { *(ptr::offset(buf,len-1)) != 0 } { - to_owned(self).as_c_str(f) + to_owned(self).as_c_str(|s| f(s)) } else { f(buf as *libc::c_char) } @@ -738,7 +829,8 @@ pub mod raw { /// Create a Rust string from a null-terminated *u8 buffer pub unsafe fn from_buf(buf: *u8) -> ~str { - let mut (curr, i) = (buf, 0u); + let mut curr = buf; + let mut i = 0u; while *curr != 0u8 { i += 1u; curr = ptr::offset(buf, i); @@ -747,7 +839,7 @@ pub mod raw { } /// Create a Rust string from a *u8 buffer of the given length - pub unsafe fn from_buf_len(buf: *const u8, len: uint) -> ~str { + pub unsafe fn from_buf_len(buf: *u8, len: uint) -> ~str { let mut v: ~[u8] = vec::with_capacity(len + 1); vec::as_mut_buf(v, |vbuf, _len| { ptr::copy_memory(vbuf, buf as *u8, len) @@ -770,12 +862,19 @@ pub mod raw { } /// Converts a vector of bytes to a new owned string. - pub unsafe fn from_bytes(v: &const [u8]) -> ~str { - do vec::as_const_buf(v) |buf, len| { + pub unsafe fn from_bytes(v: &[u8]) -> ~str { + do vec::as_imm_buf(v) |buf, len| { from_buf_len(buf, len) } } + /// Converts an owned vector of bytes to a new owned string. This assumes + /// that the utf-8-ness of the vector has already been validated + pub unsafe fn from_bytes_owned(mut v: ~[u8]) -> ~str { + v.push(0u8); + cast::transmute(v) + } + /// Converts a vector of bytes to a string. /// The byte slice needs to contain valid utf8 and needs to be one byte longer than /// the string, if possible ending in a 0 byte. @@ -791,7 +890,8 @@ pub mod raw { /// invalidated later. pub unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str { let s = s as *u8; - let mut (curr, len) = (s, 0u); + let mut curr = s; + let mut len = 0u; while *curr != 0u8 { len += 1u; curr = ptr::offset(s, len); @@ -864,7 +964,7 @@ pub mod raw { unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) { let new_len = s.len() + bytes.len(); s.reserve_at_least(new_len); - for bytes.each |byte| { push_byte(&mut *s, *byte); } + for bytes.iter().advance |byte| { push_byte(&mut *s, *byte); } } /// Removes the last byte from a string and returns it. (Not UTF-8 safe). @@ -1071,6 +1171,17 @@ impl<'self> Str for @str { } } +impl<'self> Container for &'self str { + #[inline] + fn len(&self) -> uint { + do as_buf(*self) |_p, n| { n - 1u } + } + #[inline] + fn is_empty(&self) -> bool { + self.len() == 0 + } +} + #[allow(missing_doc)] pub trait StrSlice<'self> { fn contains<'a>(&self, needle: &'a str) -> bool; @@ -1089,10 +1200,8 @@ pub trait StrSlice<'self> { fn any_line_iter(&self) -> AnyLineIterator<'self>; fn word_iter(&self) -> WordIterator<'self>; fn ends_with(&self, needle: &str) -> bool; - fn is_empty(&self) -> bool; fn is_whitespace(&self) -> bool; fn is_alphanumeric(&self) -> bool; - fn len(&self) -> uint; fn char_len(&self) -> uint; fn slice(&self, begin: uint, end: uint) -> &'self str; @@ -1293,9 +1402,6 @@ impl<'self> StrSlice<'self> for &'self str { self.split_iter(char::is_whitespace).filter(|s| !s.is_empty()) } - /// Returns true if the string has length 0 - #[inline] - fn is_empty(&self) -> bool { self.len() == 0 } /** * Returns true if the string contains only whitespace * @@ -1310,14 +1416,9 @@ impl<'self> StrSlice<'self> for &'self str { */ #[inline] fn is_alphanumeric(&self) -> bool { self.iter().all(char::is_alphanumeric) } - /// Returns the size in bytes not counting the null terminator - #[inline] - fn len(&self) -> uint { - do as_buf(*self) |_p, n| { n - 1u } - } /// Returns the number of characters that a string holds #[inline] - fn char_len(&self) -> uint { self.iter().count() } + fn char_len(&self) -> uint { self.iter().len_() } /** * Returns a slice of the given string from the byte range @@ -1358,7 +1459,8 @@ impl<'self> StrSlice<'self> for &'self str { fn slice_chars(&self, begin: uint, end: uint) -> &'self str { assert!(begin <= end); // not sure how to use the iterators for this nicely. - let mut (position, count) = (0, 0); + let mut position = 0; + let mut count = 0; let l = self.len(); while count < begin && position < l { position = self.char_range_at(position).next; @@ -1395,7 +1497,9 @@ impl<'self> StrSlice<'self> for &'self str { let mut out: ~str = ~""; out.reserve_at_least(self.len()); for self.iter().advance |c| { - out.push_str(char::escape_default(c)); + do c.escape_default |c| { + out.push_char(c); + } } out } @@ -1405,7 +1509,9 @@ impl<'self> StrSlice<'self> for &'self str { let mut out: ~str = ~""; out.reserve_at_least(self.len()); for self.iter().advance |c| { - out.push_str(char::escape_unicode(c)); + do c.escape_unicode |c| { + out.push_char(c); + } } out } @@ -1506,7 +1612,8 @@ impl<'self> StrSlice<'self> for &'self str { * The original string with all occurances of `from` replaced with `to` */ pub fn replace(&self, from: &str, to: &str) -> ~str { - let mut (result, last_end) = (~"", 0); + let mut result = ~""; + let mut last_end = 0; for self.matches_index_iter(from).advance |(start, end)| { result.push_str(unsafe{raw::slice_bytes(*self, last_end, start)}); result.push_str(to); @@ -2082,7 +2189,7 @@ impl OwnedStr for ~str { pub fn reserve(&mut self, n: uint) { unsafe { let v: *mut ~[u8] = cast::transmute(self); - vec::reserve(&mut *v, n + 1); + (*v).reserve(n + 1); } } @@ -2116,8 +2223,8 @@ impl OwnedStr for ~str { * reallocating */ fn capacity(&self) -> uint { - let buf: &const ~[u8] = unsafe { cast::transmute(self) }; - let vcap = vec::capacity(buf); + let buf: &~[u8] = unsafe { cast::transmute(self) }; + let vcap = buf.capacity(); assert!(vcap > 0u); vcap - 1u } @@ -2225,9 +2332,9 @@ mod tests { use option::Some; use libc::c_char; use libc; - use old_iter::BaseIter; use ptr; use str::*; + use uint; use vec; use vec::{ImmutableVector, CopyableVector}; use cmp::{TotalOrd, Less, Equal, Greater}; @@ -2251,7 +2358,7 @@ mod tests { assert!("" <= ""); assert!("" <= "foo"); assert!("foo" <= "foo"); - assert!("foo" != ~"bar"); + assert!("foo" != "bar"); } #[test] @@ -2373,6 +2480,8 @@ mod tests { t("hello", 15, [~"hello"]); t("\nMary had a little lamb\nLittle lamb\n", 15, [~"Mary had a", ~"little lamb", ~"Little lamb"]); + t("\nMary had a little lamb\nLittle lamb\n", uint::max_value, + [~"Mary had a little lamb\nLittle lamb"]); } #[test] @@ -3080,7 +3189,7 @@ mod tests { 0xd801_u16, 0xdc95_u16, 0xd801_u16, 0xdc86_u16, 0x000a_u16 ]) ]; - for pairs.each |p| { + for pairs.iter().advance |p| { let (s, u) = copy *p; assert!(s.to_utf16() == u); assert!(from_utf16(u) == s); @@ -3094,7 +3203,7 @@ mod tests { let s = ~"ศไทย中华Việt Nam"; let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; let mut pos = 0; - for v.each |ch| { + for v.iter().advance |ch| { assert!(s.char_at(pos) == *ch); pos += from_char(*ch).len(); } @@ -3158,6 +3267,7 @@ mod tests { #[test] fn test_add() { + #[allow(unnecessary_allocation)]; macro_rules! t ( ($s1:expr, $s2:expr, $e:expr) => { assert_eq!($s1 + $s2, $e); diff --git a/src/libstd/str/ascii.rs b/src/libstd/str/ascii.rs index c71765f911a..d8b50c96fd8 100644 --- a/src/libstd/str/ascii.rs +++ b/src/libstd/str/ascii.rs @@ -14,7 +14,6 @@ use to_str::{ToStr,ToStrConsume}; use str; use str::StrSlice; use cast; -use old_iter::BaseIter; use iterator::IteratorUtil; use vec::{CopyableVector, ImmutableVector, OwnedVector}; use to_bytes::IterBytes; @@ -94,7 +93,7 @@ impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] { #[inline] fn is_ascii(&self) -> bool { - for self.each |b| { + for self.iter().advance |b| { if !b.is_ascii() { return false; } } true diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs index ad6f1d23c10..9f72f941bde 100644 --- a/src/libstd/sys.rs +++ b/src/libstd/sys.rs @@ -12,28 +12,15 @@ #[allow(missing_doc)]; -use option::{Some, None}; use cast; use gc; use io; use libc; -use libc::{c_void, c_char, size_t}; +use libc::{c_char, size_t}; use repr; use str; use unstable::intrinsics; -pub type FreeGlue<'self> = &'self fn(*TypeDesc, *c_void); - -// Corresponds to runtime type_desc type -pub struct TypeDesc { - size: uint, - align: uint, - take_glue: uint, - drop_glue: uint, - free_glue: uint - // Remaining fields not listed -} - /// The representation of a Rust closure pub struct Closure { code: *(), @@ -51,23 +38,6 @@ pub mod rustrt { } } -/** - * Returns a pointer to a type descriptor. - * - * Useful for calling certain function in the Rust runtime or otherwise - * performing dark magick. - */ -#[inline] -pub fn get_type_desc<T>() -> *TypeDesc { - unsafe { intrinsics::get_tydesc::<T>() as *TypeDesc } -} - -/// Returns a pointer to a type descriptor. -#[inline] -pub fn get_type_desc_val<T>(_val: &T) -> *TypeDesc { - get_type_desc::<T>() -} - /// Returns the size of a type #[inline] pub fn size_of<T>() -> uint { @@ -181,10 +151,9 @@ impl FailWithCause for &'static str { // FIXME #4427: Temporary until rt::rt_fail_ goes away pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { use cell::Cell; - use option::Option; use either::Left; use rt::{context, OldTaskContext, TaskContext}; - use rt::task::{Task, Unwinder}; + use rt::task::Task; use rt::local::Local; use rt::logging::Logger; diff --git a/src/libstd/task/local_data_priv.rs b/src/libstd/task/local_data_priv.rs index f6b14a51539..0956b76c970 100644 --- a/src/libstd/task/local_data_priv.rs +++ b/src/libstd/task/local_data_priv.rs @@ -142,7 +142,7 @@ unsafe fn local_data_lookup<T: 'static>( -> Option<(uint, *libc::c_void)> { let key_value = key_to_key_value(key); - let map_pos = (*map).position(|entry| + let map_pos = (*map).iter().position_(|entry| match *entry { Some((k,_,_)) => k == key_value, None => false @@ -215,7 +215,7 @@ pub unsafe fn local_set<T: 'static>( } None => { // Find an empty slot. If not, grow the vector. - match (*map).position(|x| x.is_none()) { + match (*map).iter().position_(|x| x.is_none()) { Some(empty_index) => { map[empty_index] = new_entry; } None => { map.push(new_entry); } } diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index b0fc6b2884f..ae8f1c2101d 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -353,7 +353,7 @@ impl TaskBuilder { } /// Runs a task, while transfering ownership of one argument to the child. - pub fn spawn_with<A:Owned>(&mut self, arg: A, f: ~fn(v: A)) { + pub fn spawn_with<A:Send>(&mut self, arg: A, f: ~fn(v: A)) { let arg = Cell::new(arg); do self.spawn { f(arg.take()); @@ -373,7 +373,7 @@ impl TaskBuilder { * # Failure * Fails if a future_result was already set for this task. */ - pub fn try<T:Owned>(&mut self, f: ~fn() -> T) -> Result<T,()> { + pub fn try<T:Send>(&mut self, f: ~fn() -> T) -> Result<T,()> { let (po, ch) = stream::<T>(); let mut result = None; @@ -445,7 +445,7 @@ pub fn spawn_supervised(f: ~fn()) { task.spawn(f) } -pub fn spawn_with<A:Owned>(arg: A, f: ~fn(v: A)) { +pub fn spawn_with<A:Send>(arg: A, f: ~fn(v: A)) { /*! * Runs a task, while transfering ownership of one argument to the * child. @@ -478,7 +478,7 @@ pub fn spawn_sched(mode: SchedMode, f: ~fn()) { task.spawn(f) } -pub fn try<T:Owned>(f: ~fn() -> T) -> Result<T,()> { +pub fn try<T:Send>(f: ~fn() -> T) -> Result<T,()> { /*! * Execute a function in another task and return either the return value * of the function or result::err. @@ -923,17 +923,15 @@ fn test_spawn_sched_blocking() { let lock = testrt::rust_dbg_lock_create(); do spawn_sched(SingleThreaded) { - unsafe { - testrt::rust_dbg_lock_lock(lock); + testrt::rust_dbg_lock_lock(lock); - start_ch.send(()); + start_ch.send(()); - // Block the scheduler thread - testrt::rust_dbg_lock_wait(lock); - testrt::rust_dbg_lock_unlock(lock); + // Block the scheduler thread + testrt::rust_dbg_lock_wait(lock); + testrt::rust_dbg_lock_unlock(lock); - fin_ch.send(()); - } + fin_ch.send(()); }; // Wait until the other task has its lock diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index aea8cda6a21..bcb7e06bf1f 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -91,8 +91,8 @@ use uint; use util; use unstable::sync::{Exclusive, exclusive}; use rt::local::Local; -use iterator::{IteratorUtil}; use rt::task::Task; +use iterator::IteratorUtil; #[cfg(test)] use task::default_task_opts; #[cfg(test)] use comm; @@ -112,7 +112,7 @@ fn taskset_remove(tasks: &mut TaskSet, task: *rust_task) { assert!(was_present); } pub fn taskset_each(tasks: &TaskSet, blk: &fn(v: *rust_task) -> bool) -> bool { - tasks.each(|k| blk(*k)) + tasks.iter().advance(|k| blk(*k)) } // One of these per group of linked-failure tasks. @@ -130,7 +130,7 @@ type TaskGroupInner<'self> = &'self mut Option<TaskGroupData>; // A taskgroup is 'dead' when nothing can cause it to fail; only members can. fn taskgroup_is_dead(tg: &TaskGroupData) -> bool { - (&const tg.members).is_empty() + tg.members.is_empty() } // A list-like structure by which taskgroups keep track of all ancestor groups @@ -231,11 +231,15 @@ fn each_ancestor(list: &mut AncestorList, // 'do_continue' - Did the forward_blk succeed at this point? (i.e., // should we recurse? or should our callers unwind?) + let forward_blk = Cell::new(forward_blk); + // The map defaults to None, because if ancestors is None, we're at // the end of the list, which doesn't make sense to coalesce. return do (**ancestors).map_default((None,false)) |ancestor_arc| { // NB: Takes a lock! (this ancestor node) do access_ancestors(ancestor_arc) |nobe| { + // Argh, but we couldn't give it to coalesce() otherwise. + let forward_blk = forward_blk.take(); // Check monotonicity assert!(last_generation > nobe.generation); /*##########################################################* @@ -318,7 +322,7 @@ struct TCB { impl Drop for TCB { // Runs on task exit. - fn finalize(&self) { + fn drop(&self) { unsafe { // FIXME(#4330) Need self by value to get mutability. let this: &mut TCB = transmute(self); @@ -373,7 +377,7 @@ struct AutoNotify { } impl Drop for AutoNotify { - fn finalize(&self) { + fn drop(&self) { let result = if self.failed { Failure } else { Success }; self.notify_chan.send(result); } @@ -610,11 +614,8 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { rtdebug!("spawn about to take scheduler"); - let mut sched = Local::take::<Scheduler>(); + let sched = Local::take::<Scheduler>(); rtdebug!("took sched in spawn"); -// let task = ~Coroutine::with_task(&mut sched.stack_pool, -// task, f); -// let task = ~Task::new_root(&mut sched.stack_pool, f); sched.schedule_task(task); } @@ -669,7 +670,8 @@ fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { let child_data = Cell::new((notify_chan, child_arc, ancestors)); let result: ~fn() = || { // Agh. Get move-mode items into the closure. FIXME (#2829) - let mut (notify_chan, child_arc, ancestors) = child_data.take(); + let (notify_chan, child_arc, ancestors) = child_data.take(); + let mut ancestors = ancestors; // Child task runs this code. // Even if the below code fails to kick the child off, we must diff --git a/src/libstd/to_bytes.rs b/src/libstd/to_bytes.rs index 822aab0a027..d6e92dd679e 100644 --- a/src/libstd/to_bytes.rs +++ b/src/libstd/to_bytes.rs @@ -17,9 +17,10 @@ The `ToBytes` and `IterBytes` traits use cast; use io; use io::Writer; +use iterator::IteratorUtil; use option::{None, Option, Some}; -use old_iter::BaseIter; use str::StrSlice; +use vec::ImmutableVector; pub type Cb<'self> = &'self fn(buf: &[u8]) -> bool; @@ -223,7 +224,7 @@ impl IterBytes for f64 { impl<'self,A:IterBytes> IterBytes for &'self [A] { #[inline] fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - self.each(|elt| elt.iter_bytes(lsb0, |b| f(b))) + self.iter().advance(|elt| elt.iter_bytes(lsb0, |b| f(b))) } } @@ -231,7 +232,8 @@ impl<A:IterBytes,B:IterBytes> IterBytes for (A,B) { #[inline] fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { match *self { - (ref a, ref b) => { a.iter_bytes(lsb0, f) && b.iter_bytes(lsb0, f) } + (ref a, ref b) => { a.iter_bytes(lsb0, |b| f(b)) && + b.iter_bytes(lsb0, |b| f(b)) } } } } @@ -241,7 +243,9 @@ impl<A:IterBytes,B:IterBytes,C:IterBytes> IterBytes for (A,B,C) { fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { match *self { (ref a, ref b, ref c) => { - a.iter_bytes(lsb0, f) && b.iter_bytes(lsb0, f) && c.iter_bytes(lsb0, f) + a.iter_bytes(lsb0, |b| f(b)) && + b.iter_bytes(lsb0, |b| f(b)) && + c.iter_bytes(lsb0, |b| f(b)) } } } @@ -295,7 +299,7 @@ impl<A:IterBytes> IterBytes for Option<A> { #[inline] fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { match *self { - Some(ref a) => 0u8.iter_bytes(lsb0, f) && a.iter_bytes(lsb0, f), + Some(ref a) => 0u8.iter_bytes(lsb0, |b| f(b)) && a.iter_bytes(lsb0, |b| f(b)), None => 1u8.iter_bytes(lsb0, f) } } diff --git a/src/libstd/to_str.rs b/src/libstd/to_str.rs index 3e782e728fe..77701acd33e 100644 --- a/src/libstd/to_str.rs +++ b/src/libstd/to_str.rs @@ -17,10 +17,10 @@ The `ToStr` trait for converting to strings use str::OwnedStr; use hashmap::HashMap; use hashmap::HashSet; -use container::Map; use hash::Hash; +use iterator::IteratorUtil; use cmp::Eq; -use old_iter::BaseIter; +use vec::ImmutableVector; /// A generic trait for converting a value to a string pub trait ToStr { @@ -53,8 +53,9 @@ impl<A:ToStr> ToStr for (A,) { impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> { #[inline] fn to_str(&self) -> ~str { - let mut (acc, first) = (~"{", true); - for self.each |key, value| { + let mut acc = ~"{"; + let mut first = true; + for self.iter().advance |(key, value)| { if first { first = false; } @@ -73,8 +74,9 @@ impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> { impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> { #[inline] fn to_str(&self) -> ~str { - let mut (acc, first) = (~"{", true); - for self.each |element| { + let mut acc = ~"{"; + let mut first = true; + for self.iter().advance |element| { if first { first = false; } @@ -121,8 +123,9 @@ impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) { impl<'self,A:ToStr> ToStr for &'self [A] { #[inline] fn to_str(&self) -> ~str { - let mut (acc, first) = (~"[", true); - for self.each |elt| { + let mut acc = ~"["; + let mut first = true; + for self.iter().advance |elt| { if first { first = false; } @@ -139,8 +142,9 @@ impl<'self,A:ToStr> ToStr for &'self [A] { impl<A:ToStr> ToStr for ~[A] { #[inline] fn to_str(&self) -> ~str { - let mut (acc, first) = (~"[", true); - for self.each |elt| { + let mut acc = ~"["; + let mut first = true; + for self.iter().advance |elt| { if first { first = false; } @@ -157,8 +161,9 @@ impl<A:ToStr> ToStr for ~[A] { impl<A:ToStr> ToStr for @[A] { #[inline] fn to_str(&self) -> ~str { - let mut (acc, first) = (~"[", true); - for self.each |elt| { + let mut acc = ~"["; + let mut first = true; + for self.iter().advance |elt| { if first { first = false; } @@ -177,7 +182,7 @@ impl<A:ToStr> ToStr for @[A] { mod tests { use hashmap::HashMap; use hashmap::HashSet; - use container::Set; + use container::{Set, Map}; #[test] fn test_simple_types() { assert_eq!(1i.to_str(), ~"1"); diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index aaeaa489834..8ce02d59ab1 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -35,11 +35,11 @@ pub struct TrieMap<T> { impl<T> Container for TrieMap<T> { /// Return the number of elements in the map #[inline] - fn len(&const self) -> uint { self.length } + fn len(&self) -> uint { self.length } /// Return true if the map contains no elements #[inline] - fn is_empty(&const self) -> bool { self.len() == 0 } + fn is_empty(&self) -> bool { self.len() == 0 } } impl<T> Mutable for TrieMap<T> { @@ -58,30 +58,6 @@ impl<T> Map<uint, T> for TrieMap<T> { self.find(key).is_some() } - /// Visit all key-value pairs in order - #[inline] - fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { - self.root.each(f) - } - - /// Visit all keys in order - #[inline] - fn each_key(&self, f: &fn(&uint) -> bool) -> bool { - self.each(|k, _| f(k)) - } - - /// Visit all values in order - #[inline] - fn each_value<'a>(&'a self, f: &fn(&'a T) -> bool) -> bool { - self.each(|_, v| f(v)) - } - - /// Iterate over the map and mutate the contained values - #[inline] - fn mutate_values(&mut self, f: &fn(&uint, &mut T) -> bool) -> bool { - self.root.mutate_values(f) - } - /// Return a reference to the value corresponding to the key #[inline] fn find<'a>(&'a self, key: &uint) -> Option<&'a T> { @@ -158,6 +134,30 @@ impl<T> TrieMap<T> { self.root.each_reverse(f) } + /// Visit all key-value pairs in order + #[inline] + pub fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { + self.root.each(f) + } + + /// Visit all keys in order + #[inline] + pub fn each_key(&self, f: &fn(&uint) -> bool) -> bool { + self.each(|k, _| f(k)) + } + + /// Visit all values in order + #[inline] + pub fn each_value<'a>(&'a self, f: &fn(&'a T) -> bool) -> bool { + self.each(|_, v| f(v)) + } + + /// Iterate over the map and mutate the contained values + #[inline] + pub fn mutate_values(&mut self, f: &fn(&uint, &mut T) -> bool) -> bool { + self.root.mutate_values(f) + } + /// Visit all keys in reverse order #[inline] pub fn each_key_reverse(&self, f: &fn(&uint) -> bool) -> bool { @@ -176,30 +176,14 @@ pub struct TrieSet { priv map: TrieMap<()> } -impl BaseIter<uint> for TrieSet { - /// Visit all values in order - #[inline] - fn each(&self, f: &fn(&uint) -> bool) -> bool { self.map.each_key(f) } - #[inline] - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - -impl ReverseIter<uint> for TrieSet { - /// Visit all values in reverse order - #[inline] - fn each_reverse(&self, f: &fn(&uint) -> bool) -> bool { - self.map.each_key_reverse(f) - } -} - impl Container for TrieSet { /// Return the number of elements in the set #[inline] - fn len(&const self) -> uint { self.map.len() } + fn len(&self) -> uint { self.map.len() } /// Return true if the set contains no elements #[inline] - fn is_empty(&const self) -> bool { self.map.is_empty() } + fn is_empty(&self) -> bool { self.map.is_empty() } } impl Mutable for TrieSet { @@ -234,6 +218,16 @@ impl TrieSet { pub fn remove(&mut self, value: &uint) -> bool { self.map.remove(value) } + + /// Visit all values in order + #[inline] + pub fn each(&self, f: &fn(&uint) -> bool) -> bool { self.map.each_key(f) } + + /// Visit all values in reverse order + #[inline] + pub fn each_reverse(&self, f: &fn(&uint) -> bool) -> bool { + self.map.each_key_reverse(f) + } } struct TrieNode<T> { @@ -257,7 +251,7 @@ impl<T> TrieNode<T> { fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range(0, self.children.len()) |idx| { match self.children[idx] { - Internal(ref x) => if !x.each(f) { return false }, + Internal(ref x) => if !x.each(|i,t| f(i,t)) { return false }, External(k, ref v) => if !f(&k, v) { return false }, Nothing => () } @@ -268,7 +262,7 @@ impl<T> TrieNode<T> { fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range_rev(self.children.len(), 0) |idx| { match self.children[idx - 1] { - Internal(ref x) => if !x.each_reverse(f) { return false }, + Internal(ref x) => if !x.each_reverse(|i,t| f(i,t)) { return false }, External(k, ref v) => if !f(&k, v) { return false }, Nothing => () } @@ -279,7 +273,7 @@ impl<T> TrieNode<T> { fn mutate_values<'a>(&'a mut self, f: &fn(&uint, &mut T) -> bool) -> bool { for self.children.mut_iter().advance |child| { match *child { - Internal(ref mut x) => if !x.mutate_values(f) { + Internal(ref mut x) => if !x.mutate_values(|i,t| f(i,t)) { return false }, External(k, ref mut v) => if !f(&k, v) { return false }, @@ -373,7 +367,7 @@ pub fn check_integrity<T>(trie: &TrieNode<T>) { let mut sum = 0; - for trie.children.each |x| { + for trie.children.iter().advance |x| { match *x { Nothing => (), Internal(ref y) => { diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index fefd55c3541..45702546278 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -14,6 +14,8 @@ use kinds::Copy; use vec; +use vec::ImmutableVector; +use iterator::IteratorUtil; pub use self::inner::*; @@ -96,7 +98,7 @@ impl<'self,A:Copy,B:Copy> ExtendedTupleOps<A,B> for (&'self [A], &'self [B]) { fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] { match *self { (ref a, ref b) => { - vec::map_zip(*a, *b, f) + a.iter().zip(b.iter()).transform(|(aa, bb)| f(aa, bb)).collect() } } } @@ -116,7 +118,7 @@ impl<A:Copy,B:Copy> ExtendedTupleOps<A,B> for (~[A], ~[B]) { fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] { match *self { (ref a, ref b) => { - vec::map_zip(*a, *b, f) + a.iter().zip(b.iter()).transform(|(aa, bb)| f(aa, bb)).collect() } } } diff --git a/src/libstd/unicode.rs b/src/libstd/unicode.rs index f8f56c75a29..1e2d5c76fea 100644 --- a/src/libstd/unicode.rs +++ b/src/libstd/unicode.rs @@ -16,9 +16,9 @@ pub mod general_category { fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { use cmp::{Equal, Less, Greater}; - use vec::bsearch; + use vec::ImmutableVector; use option::None; - (do bsearch(r) |&(lo,hi)| { + (do r.bsearch |&(lo,hi)| { if lo <= c && c <= hi { Equal } else if hi < c { Less } else { Greater } @@ -1447,15 +1447,13 @@ pub mod general_category { } } - pub mod derived_property { - fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { use cmp::{Equal, Less, Greater}; - use vec::bsearch; + use vec::ImmutableVector; use option::None; - (do bsearch(r) |&(lo,hi)| { + (do r.bsearch |&(lo,hi)| { if lo <= c && c <= hi { Equal } else if hi < c { Less } else { Greater } @@ -2641,4 +2639,5 @@ pub mod derived_property { pub fn XID_Start(c: char) -> bool { bsearch_range_table(c, XID_Start_table) } + } diff --git a/src/libstd/unstable/atomics.rs b/src/libstd/unstable/atomics.rs index 6e7a7e2b129..1e5ac305df3 100644 --- a/src/libstd/unstable/atomics.rs +++ b/src/libstd/unstable/atomics.rs @@ -62,6 +62,7 @@ pub struct AtomicPtr<T> { /** * An owned atomic pointer. Ensures that only a single reference to the data is held at any time. */ +#[unsafe_no_drop_flag] pub struct AtomicOption<T> { priv p: *mut c_void } @@ -275,7 +276,7 @@ impl<T> AtomicOption<T> { #[unsafe_destructor] impl<T> Drop for AtomicOption<T> { - fn finalize(&self) { + fn drop(&self) { // This will ensure that the contained data is // destroyed, unless it's null. unsafe { diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs index 64dd5bba6bc..e01f99adc94 100644 --- a/src/libstd/unstable/dynamic_lib.rs +++ b/src/libstd/unstable/dynamic_lib.rs @@ -25,7 +25,7 @@ use result::*; pub struct DynamicLibrary { priv handle: *libc::c_void } impl Drop for DynamicLibrary { - fn finalize(&self) { + fn drop(&self) { match do dl::check_for_errors_in { unsafe { dl::close(self.handle) @@ -164,7 +164,6 @@ mod dl { use libc; use path; use ptr; - use str; use task; use result::*; @@ -175,7 +174,7 @@ mod dl { } pub unsafe fn open_internal() -> *libc::c_void { - let mut handle = ptr::null(); + let handle = ptr::null(); GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void); handle } diff --git a/src/libstd/unstable/exchange_alloc.rs b/src/libstd/unstable/exchange_alloc.rs deleted file mode 100644 index 3b35c2fb804..00000000000 --- a/src/libstd/unstable/exchange_alloc.rs +++ /dev/null @@ -1,83 +0,0 @@ -// 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. - -use sys::{TypeDesc, size_of}; -use libc::{c_void, size_t}; -use c_malloc = libc::malloc; -use c_free = libc::free; -use managed::raw::{BoxHeaderRepr, BoxRepr}; -use cast::transmute; -use unstable::intrinsics::{atomic_xadd,atomic_xsub}; -use ptr::null; -use intrinsic::TyDesc; - -pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void { - assert!(td.is_not_null()); - - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert!(p.is_not_null()); - - // FIXME #3475: Converting between our two different tydesc types - let td: *TyDesc = transmute(td); - - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); - - let exchange_count = &mut *rust_get_exchange_count_ptr(); - atomic_xadd(exchange_count, 1); - - return transmute(box); -} -/** -Thin wrapper around libc::malloc, none of the box header -stuff in exchange_alloc::malloc -*/ -pub unsafe fn malloc_raw(size: uint) -> *c_void { - let p = c_malloc(size as size_t); - if p.is_null() { - fail!("Failure in malloc_raw: result ptr is null"); - } - p -} - -pub unsafe fn free(ptr: *c_void) { - let exchange_count = &mut *rust_get_exchange_count_ptr(); - atomic_xsub(exchange_count, 1); - - assert!(ptr.is_not_null()); - c_free(ptr); -} -///Thin wrapper around libc::free, as with exchange_alloc::malloc_raw -pub unsafe fn free_raw(ptr: *c_void) { - c_free(ptr); -} - -fn get_box_size(body_size: uint, body_align: uint) -> uint { - let header_size = size_of::<BoxHeaderRepr>(); - // FIXME (#2699): This alignment calculation is suspicious. Is it right? - let total_size = align_to(header_size, body_align) + body_size; - return total_size; -} - -// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power -// of two. -fn align_to(size: uint, align: uint) -> uint { - assert!(align != 0); - (size + align - 1) & !(align - 1) -} - -extern { - #[rust_stack] - fn rust_get_exchange_count_ptr() -> *mut int; -} diff --git a/src/libstd/unstable/extfmt.rs b/src/libstd/unstable/extfmt.rs index d466488ce5e..624062a7ec4 100644 --- a/src/libstd/unstable/extfmt.rs +++ b/src/libstd/unstable/extfmt.rs @@ -94,6 +94,7 @@ use iterator::IteratorUtil; #[doc(hidden)] pub mod ct { use char; + use container::Container; use prelude::*; use str; @@ -350,7 +351,7 @@ pub mod ct { #[test] fn test_parse_flags() { fn pack(fs: &[Flag]) -> uint { - fs.foldl(0, |&p, &f| p | (1 << f as uint)) + fs.iter().fold(0, |p, &f| p | (1 << f as uint)) } fn test(s: &str, flags: &[Flag], next: uint) { diff --git a/src/libstd/unstable/finally.rs b/src/libstd/unstable/finally.rs index b15bceddb1c..10db664450e 100644 --- a/src/libstd/unstable/finally.rs +++ b/src/libstd/unstable/finally.rs @@ -64,7 +64,7 @@ struct Finallyalizer<'self> { #[unsafe_destructor] impl<'self> Drop for Finallyalizer<'self> { - fn finalize(&self) { + fn drop(&self) { (self.dtor)(); } } diff --git a/src/libstd/unstable/global.rs b/src/libstd/unstable/global.rs index f81252274c4..285a8114cc2 100644 --- a/src/libstd/unstable/global.rs +++ b/src/libstd/unstable/global.rs @@ -27,7 +27,7 @@ avoid hitting the mutex. use cast::{transmute}; use clone::Clone; -use kinds::Owned; +use kinds::Send; use libc::{c_void}; use option::{Option, Some, None}; use ops::Drop; @@ -43,7 +43,7 @@ use sys::Closure; pub type GlobalDataKey<'self,T> = &'self fn(v: T); -pub unsafe fn global_data_clone_create<T:Owned + Clone>( +pub unsafe fn global_data_clone_create<T:Send + Clone>( key: GlobalDataKey<T>, create: &fn() -> ~T) -> T { /*! * Clone a global value or, if it has not been created, @@ -59,7 +59,7 @@ pub unsafe fn global_data_clone_create<T:Owned + Clone>( global_data_clone_create_(key_ptr(key), create) } -unsafe fn global_data_clone_create_<T:Owned + Clone>( +unsafe fn global_data_clone_create_<T:Send + Clone>( key: uint, create: &fn() -> ~T) -> T { let mut clone_value: Option<T> = None; @@ -79,13 +79,13 @@ unsafe fn global_data_clone_create_<T:Owned + Clone>( return clone_value.unwrap(); } -unsafe fn global_data_modify<T:Owned>( +unsafe fn global_data_modify<T:Send>( key: GlobalDataKey<T>, op: &fn(Option<~T>) -> Option<~T>) { global_data_modify_(key_ptr(key), op) } -unsafe fn global_data_modify_<T:Owned>( +unsafe fn global_data_modify_<T:Send>( key: uint, op: &fn(Option<~T>) -> Option<~T>) { let mut old_dtor = None; @@ -124,7 +124,7 @@ unsafe fn global_data_modify_<T:Owned>( } } -pub unsafe fn global_data_clone<T:Owned + Clone>( +pub unsafe fn global_data_clone<T:Send + Clone>( key: GlobalDataKey<T>) -> Option<T> { let mut maybe_clone: Option<T> = None; do global_data_modify(key) |current| { @@ -147,7 +147,7 @@ struct GlobalState { } impl Drop for GlobalState { - fn finalize(&self) { + fn drop(&self) { for self.map.each_value |v| { match v { &(_, ref dtor) => (*dtor)() @@ -220,7 +220,7 @@ fn get_global_state() -> Exclusive<GlobalState> { } } -fn key_ptr<T:Owned>(key: GlobalDataKey<T>) -> uint { +fn key_ptr<T:Send>(key: GlobalDataKey<T>) -> uint { unsafe { let closure: Closure = transmute(key); return transmute(closure.code); diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 13425007785..500143fb577 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -32,6 +32,130 @@ A quick refresher on memory ordering: */ +// This is needed to prevent duplicate lang item definitions. +#[cfg(test)] +pub use realstd::unstable::intrinsics::{TyDesc, Opaque, TyVisitor}; + +#[cfg(not(stage0))] +pub type GlueFn = extern "Rust" fn(*i8); + +#[cfg(stage0)] +pub type GlueFn = extern "Rust" fn(**TyDesc, *i8); + +// NB: this has to be kept in sync with the Rust ABI. +#[lang="ty_desc"] +#[cfg(not(test))] +pub struct TyDesc { + size: uint, + align: uint, + take_glue: GlueFn, + drop_glue: GlueFn, + free_glue: GlueFn, + visit_glue: GlueFn, +} + +#[lang="opaque"] +#[cfg(not(test))] +pub enum Opaque { } + +#[lang="ty_visitor"] +#[cfg(not(test))] +pub trait TyVisitor { + fn visit_bot(&self) -> bool; + fn visit_nil(&self) -> bool; + fn visit_bool(&self) -> bool; + + fn visit_int(&self) -> bool; + fn visit_i8(&self) -> bool; + fn visit_i16(&self) -> bool; + fn visit_i32(&self) -> bool; + fn visit_i64(&self) -> bool; + + fn visit_uint(&self) -> bool; + fn visit_u8(&self) -> bool; + fn visit_u16(&self) -> bool; + fn visit_u32(&self) -> bool; + fn visit_u64(&self) -> bool; + + fn visit_float(&self) -> bool; + fn visit_f32(&self) -> bool; + fn visit_f64(&self) -> bool; + + fn visit_char(&self) -> bool; + fn visit_str(&self) -> bool; + + fn visit_estr_box(&self) -> bool; + fn visit_estr_uniq(&self) -> bool; + fn visit_estr_slice(&self) -> bool; + fn visit_estr_fixed(&self, n: uint, sz: uint, align: uint) -> bool; + + fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool; + + fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint, + mtbl: uint, inner: *TyDesc) -> bool; + + fn visit_enter_rec(&self, n_fields: uint, + sz: uint, align: uint) -> bool; + fn visit_rec_field(&self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool; + fn visit_leave_rec(&self, n_fields: uint, + sz: uint, align: uint) -> bool; + + fn visit_enter_class(&self, n_fields: uint, + sz: uint, align: uint) -> bool; + fn visit_class_field(&self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool; + fn visit_leave_class(&self, n_fields: uint, + sz: uint, align: uint) -> bool; + + fn visit_enter_tup(&self, n_fields: uint, + sz: uint, align: uint) -> bool; + fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool; + fn visit_leave_tup(&self, n_fields: uint, + sz: uint, align: uint) -> bool; + + fn visit_enter_enum(&self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> int, + sz: uint, align: uint) -> bool; + fn visit_enter_enum_variant(&self, variant: uint, + disr_val: int, + n_fields: uint, + name: &str) -> bool; + fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool; + fn visit_leave_enum_variant(&self, variant: uint, + disr_val: int, + n_fields: uint, + name: &str) -> bool; + fn visit_leave_enum(&self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> int, + sz: uint, align: uint) -> bool; + + fn visit_enter_fn(&self, purity: uint, proto: uint, + n_inputs: uint, retstyle: uint) -> bool; + fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool; + fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool; + fn visit_leave_fn(&self, purity: uint, proto: uint, + n_inputs: uint, retstyle: uint) -> bool; + + fn visit_trait(&self) -> bool; + fn visit_var(&self) -> bool; + fn visit_var_integral(&self) -> bool; + fn visit_param(&self, i: uint) -> bool; + fn visit_self(&self) -> bool; + fn visit_type(&self) -> bool; + fn visit_opaque_box(&self) -> bool; + fn visit_constr(&self, inner: *TyDesc) -> bool; + fn visit_closure_ptr(&self, ck: uint) -> bool; +} + #[abi = "rust-intrinsic"] pub extern "rust-intrinsic" { @@ -42,22 +166,32 @@ pub extern "rust-intrinsic" { /// Atomic compare and exchange, release ordering. pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int; + pub fn atomic_cxchg_acqrel(dst: &mut int, old: int, src: int) -> int; + pub fn atomic_cxchg_relaxed(dst: &mut int, old: int, src: int) -> int; + + /// Atomic load, sequentially consistent. pub fn atomic_load(src: &int) -> int; /// Atomic load, acquire ordering. pub fn atomic_load_acq(src: &int) -> int; + pub fn atomic_load_relaxed(src: &int) -> int; + /// Atomic store, sequentially consistent. pub fn atomic_store(dst: &mut int, val: int); /// Atomic store, release ordering. pub fn atomic_store_rel(dst: &mut int, val: int); + pub fn atomic_store_relaxed(dst: &mut int, val: int); + /// Atomic exchange, sequentially consistent. pub fn atomic_xchg(dst: &mut int, src: int) -> int; /// Atomic exchange, acquire ordering. pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int; /// Atomic exchange, release ordering. pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int; + pub fn atomic_xchg_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_xchg_relaxed(dst: &mut int, src: int) -> int; /// Atomic addition, sequentially consistent. pub fn atomic_xadd(dst: &mut int, src: int) -> int; @@ -65,6 +199,8 @@ pub extern "rust-intrinsic" { pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int; /// Atomic addition, release ordering. pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int; + pub fn atomic_xadd_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_xadd_relaxed(dst: &mut int, src: int) -> int; /// Atomic subtraction, sequentially consistent. pub fn atomic_xsub(dst: &mut int, src: int) -> int; @@ -72,6 +208,56 @@ pub extern "rust-intrinsic" { pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int; /// Atomic subtraction, release ordering. pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int; + pub fn atomic_xsub_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_xsub_relaxed(dst: &mut int, src: int) -> int; + + pub fn atomic_and(dst: &mut int, src: int) -> int; + pub fn atomic_and_acq(dst: &mut int, src: int) -> int; + pub fn atomic_and_rel(dst: &mut int, src: int) -> int; + pub fn atomic_and_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_and_relaxed(dst: &mut int, src: int) -> int; + + pub fn atomic_nand(dst: &mut int, src: int) -> int; + pub fn atomic_nand_acq(dst: &mut int, src: int) -> int; + pub fn atomic_nand_rel(dst: &mut int, src: int) -> int; + pub fn atomic_nand_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_nand_relaxed(dst: &mut int, src: int) -> int; + + pub fn atomic_or(dst: &mut int, src: int) -> int; + pub fn atomic_or_acq(dst: &mut int, src: int) -> int; + pub fn atomic_or_rel(dst: &mut int, src: int) -> int; + pub fn atomic_or_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_or_relaxed(dst: &mut int, src: int) -> int; + + pub fn atomic_xor(dst: &mut int, src: int) -> int; + pub fn atomic_xor_acq(dst: &mut int, src: int) -> int; + pub fn atomic_xor_rel(dst: &mut int, src: int) -> int; + pub fn atomic_xor_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_xor_relaxed(dst: &mut int, src: int) -> int; + + pub fn atomic_max(dst: &mut int, src: int) -> int; + pub fn atomic_max_acq(dst: &mut int, src: int) -> int; + pub fn atomic_max_rel(dst: &mut int, src: int) -> int; + pub fn atomic_max_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_max_relaxed(dst: &mut int, src: int) -> int; + + pub fn atomic_min(dst: &mut int, src: int) -> int; + pub fn atomic_min_acq(dst: &mut int, src: int) -> int; + pub fn atomic_min_rel(dst: &mut int, src: int) -> int; + pub fn atomic_min_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_min_relaxed(dst: &mut int, src: int) -> int; + + pub fn atomic_umin(dst: &mut int, src: int) -> int; + pub fn atomic_umin_acq(dst: &mut int, src: int) -> int; + pub fn atomic_umin_rel(dst: &mut int, src: int) -> int; + pub fn atomic_umin_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_umin_relaxed(dst: &mut int, src: int) -> int; + + pub fn atomic_umax(dst: &mut int, src: int) -> int; + pub fn atomic_umax_acq(dst: &mut int, src: int) -> int; + pub fn atomic_umax_rel(dst: &mut int, src: int) -> int; + pub fn atomic_umax_acqrel(dst: &mut int, src: int) -> int; + pub fn atomic_umax_relaxed(dst: &mut int, src: int) -> int; /// The size of a type in bytes. /// @@ -97,6 +283,9 @@ pub extern "rust-intrinsic" { pub fn pref_align_of<T>() -> uint; /// Get a static pointer to a type descriptor. + #[cfg(not(stage0))] + pub fn get_tydesc<T>() -> *TyDesc; + #[cfg(stage0)] pub fn get_tydesc<T>() -> *(); /// Create a value initialized to zero. @@ -119,9 +308,12 @@ pub extern "rust-intrinsic" { /// Returns `true` if a type requires drop glue. pub fn needs_drop<T>() -> bool; - // XXX: intrinsic uses legacy modes and has reference to TyDesc - // and TyVisitor which are in librustc - //fn visit_tydesc(++td: *TyDesc, &&tv: TyVisitor) -> (); + /// Returns `true` if a type is managed (will be allocated on the local heap) + #[cfg(not(stage0))] + pub fn contains_managed<T>() -> bool; + + #[cfg(not(stage0))] + pub fn visit_tydesc(td: *TyDesc, tv: @TyVisitor); pub fn frame_address(f: &once fn(*u8)); diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index 3a071af5d4c..66bb46b8991 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -10,27 +10,21 @@ //! Runtime calls emitted by the compiler. -use iterator::IteratorUtil; -use uint; use cast::transmute; -use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int, STDERR_FILENO}; +use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int}; use str; use sys; use rt::{context, OldTaskContext}; use rt::task::Task; use rt::local::Local; -use option::{Option, Some, None}; -use io; -use rt::global_heap; use rt::borrowck; -use borrow::to_uint; #[allow(non_camel_case_types)] pub type rust_task = c_void; pub mod rustrt { use unstable::lang::rust_task; - use libc::{c_void, c_char, uintptr_t}; + use libc::{c_char, uintptr_t}; pub extern { #[rust_stack] @@ -66,22 +60,6 @@ pub fn fail_bounds_check(file: *c_char, line: size_t, } } -// FIXME #4942: Make these signatures agree with exchange_alloc's signatures -#[lang="exchange_malloc"] -#[inline] -pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { - transmute(global_heap::malloc(transmute(td), transmute(size))) -} - -// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from -// inside a landing pad may corrupt the state of the exception handler. If a -// problem occurs, call exit instead. -#[lang="exchange_free"] -#[inline] -pub unsafe fn exchange_free(ptr: *c_char) { - global_heap::free(transmute(ptr)) -} - #[lang="malloc"] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { match context() { diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index 162891124f6..0da05dd167d 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -17,7 +17,7 @@ use unstable::finally::Finally; use unstable::intrinsics; use ops::Drop; use clone::Clone; -use kinds::Owned; +use kinds::Send; /// An atomically reference counted pointer. /// @@ -31,7 +31,7 @@ struct AtomicRcBoxData<T> { data: Option<T>, } -impl<T: Owned> UnsafeAtomicRcBox<T> { +impl<T: Send> UnsafeAtomicRcBox<T> { pub fn new(data: T) -> UnsafeAtomicRcBox<T> { unsafe { let data = ~AtomicRcBoxData { count: 1, data: Some(data) }; @@ -61,7 +61,7 @@ impl<T: Owned> UnsafeAtomicRcBox<T> { } } -impl<T: Owned> Clone for UnsafeAtomicRcBox<T> { +impl<T: Send> Clone for UnsafeAtomicRcBox<T> { fn clone(&self) -> UnsafeAtomicRcBox<T> { unsafe { let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data); @@ -75,7 +75,7 @@ impl<T: Owned> Clone for UnsafeAtomicRcBox<T> { #[unsafe_destructor] impl<T> Drop for UnsafeAtomicRcBox<T>{ - fn finalize(&self) { + fn drop(&self) { unsafe { do task::unkillable { let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data); @@ -102,7 +102,7 @@ struct LittleLock { } impl Drop for LittleLock { - fn finalize(&self) { + fn drop(&self) { unsafe { rust_destroy_little_lock(self.l); } @@ -144,7 +144,7 @@ pub struct Exclusive<T> { x: UnsafeAtomicRcBox<ExData<T>> } -pub fn exclusive<T:Owned>(user_data: T) -> Exclusive<T> { +pub fn exclusive<T:Send>(user_data: T) -> Exclusive<T> { let data = ExData { lock: LittleLock(), failed: false, @@ -155,14 +155,14 @@ pub fn exclusive<T:Owned>(user_data: T) -> Exclusive<T> { } } -impl<T:Owned> Clone for Exclusive<T> { +impl<T:Send> Clone for Exclusive<T> { // Duplicate an exclusive ARC, as std::arc::clone. fn clone(&self) -> Exclusive<T> { Exclusive { x: self.x.clone() } } } -impl<T:Owned> Exclusive<T> { +impl<T:Send> Exclusive<T> { // Exactly like std::arc::mutex_arc,access(), but with the little_lock // instead of a proper mutex. Same reason for being unsafe. // @@ -282,7 +282,7 @@ mod tests { } }; - for futures.each |f| { f.recv() } + for futures.iter().advance |f| { f.recv() } do total.with |total| { assert!(**total == num_tasks * count) diff --git a/src/libstd/util.rs b/src/libstd/util.rs index 2a5d44c9ce2..fd29d7dc14b 100644 --- a/src/libstd/util.rs +++ b/src/libstd/util.rs @@ -75,18 +75,14 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T { } /// A non-copyable dummy type. +#[deriving(Eq, TotalEq, Ord, TotalOrd)] +#[unsafe_no_drop_flag] pub struct NonCopyable; -impl NonCopyable { - /// Creates a dummy non-copyable structure and returns it for use. - pub fn new() -> NonCopyable { NonCopyable } -} - impl Drop for NonCopyable { - fn finalize(&self) { } + fn drop(&self) { } } - /// A type with no inhabitants pub enum Void { } @@ -130,39 +126,73 @@ pub fn unreachable() -> ! { #[cfg(test)] mod tests { + use super::*; use option::{None, Some}; - use util::{Void, NonCopyable, id, replace, swap}; use either::{Either, Left, Right}; + use sys::size_of; + use kinds::Drop; #[test] - pub fn identity_crisis() { + fn identity_crisis() { // Writing a test for the identity function. How did it come to this? let x = ~[(5, false)]; //FIXME #3387 assert!(x.eq(id(copy x))); let y = copy x; assert!(x.eq(&id(y))); } + #[test] - pub fn test_swap() { + fn test_swap() { let mut x = 31337; let mut y = 42; swap(&mut x, &mut y); assert_eq!(x, 42); assert_eq!(y, 31337); } + #[test] - pub fn test_replace() { - let mut x = Some(NonCopyable::new()); + fn test_replace() { + let mut x = Some(NonCopyable); let y = replace(&mut x, None); assert!(x.is_none()); assert!(y.is_some()); } + #[test] - pub fn test_uninhabited() { + fn test_uninhabited() { let could_only_be_coin : Either <Void, ()> = Right (()); match could_only_be_coin { Right (coin) => coin, Left (is_void) => is_void.uninhabited () } } + + #[test] + fn test_noncopyable() { + assert_eq!(size_of::<NonCopyable>(), 0); + + // verify that `#[unsafe_no_drop_flag]` works as intended on a zero-size struct + + // NOTE: uncomment after snapshot, will not parse yet + //static mut did_run: bool = false; + + struct Foo { five: int } + + impl Drop for Foo { + fn drop(&self) { + assert_eq!(self.five, 5); + // NOTE: uncomment after snapshot, will not parse yet + //unsafe { + //did_run = true; + //} + } + } + + { + let _a = (NonCopyable, Foo { five: 5 }, NonCopyable); + } + + // NOTE: uncomment after snapshot, will not parse yet + //unsafe { assert_eq!(did_run, true); } + } } diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 4339153c43e..1180ac883e7 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -15,113 +15,45 @@ use cast::transmute; use cast; use container::{Container, Mutable}; +use cmp; use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use clone::Clone; -use old_iter::BaseIter; -use old_iter; -use iterator::{Iterator}; +use iterator::{FromIterator, Iterator, IteratorUtil}; use iter::FromIter; use kinds::Copy; -use libc; +use libc::c_void; use num::Zero; -use old_iter::CopyableIter; +use ops::Add; use option::{None, Option, Some}; use ptr::to_unsafe_ptr; use ptr; use ptr::RawPtr; +use rt::global_heap::realloc_raw; use sys; +use sys::size_of; use uint; use unstable::intrinsics; +#[cfg(stage0)] +use intrinsic::{get_tydesc}; +#[cfg(not(stage0))] +use unstable::intrinsics::{get_tydesc, contains_managed}; use vec; use util; #[cfg(not(test))] use cmp::Equiv; -pub mod rustrt { - use libc; - use sys; - use vec::raw; - - #[abi = "cdecl"] - pub extern { - // These names are terrible. reserve_shared applies - // to ~[] and reserve_shared_actual applies to @[]. - #[fast_ffi] - unsafe fn vec_reserve_shared(t: *sys::TypeDesc, - v: *mut *mut raw::VecRepr, - n: libc::size_t); - } -} - /// Returns true if two vectors have the same length -pub fn same_length<T, U>(xs: &const [T], ys: &const [U]) -> bool { +pub fn same_length<T, U>(xs: &[T], ys: &[U]) -> bool { xs.len() == ys.len() } /** - * Reserves capacity for exactly `n` elements in the given vector. - * - * If the capacity for `v` is already equal to or greater than the requested - * capacity, then no action is taken. - * - * # Arguments - * - * * v - A vector - * * n - The number of elements to reserve space for - */ -#[inline] -pub fn reserve<T>(v: &mut ~[T], n: uint) { - // Only make the (slow) call into the runtime if we have to - use managed; - if capacity(v) < n { - unsafe { - let ptr: *mut *mut raw::VecRepr = cast::transmute(v); - let td = sys::get_type_desc::<T>(); - if ((**ptr).box_header.ref_count == - managed::raw::RC_MANAGED_UNIQUE) { - ::at_vec::raw::reserve_raw(td, ptr, n); - } else { - rustrt::vec_reserve_shared(td, ptr, n as libc::size_t); - } - } - } -} - -/** - * Reserves capacity for at least `n` elements in the given vector. - * - * This function will over-allocate in order to amortize the allocation costs - * in scenarios where the caller may need to repeatedly reserve additional - * space. - * - * If the capacity for `v` is already equal to or greater than the requested - * capacity, then no action is taken. - * - * # Arguments - * - * * v - A vector - * * n - The number of elements to reserve space for - */ -pub fn reserve_at_least<T>(v: &mut ~[T], n: uint) { - reserve(v, uint::next_power_of_two(n)); -} - -/// Returns the number of elements the vector can hold without reallocating -#[inline] -pub fn capacity<T>(v: &const ~[T]) -> uint { - unsafe { - let repr: **raw::VecRepr = transmute(v); - (**repr).unboxed.alloc / sys::nonzero_size_of::<T>() - } -} - -/** * Creates and initializes an owned vector. * * Creates an owned vector of size `n_elts` and initializes the elements * to the value returned by the function `op`. */ -pub fn from_fn<T>(n_elts: uint, op: old_iter::InitOp<T>) -> ~[T] { +pub fn from_fn<T>(n_elts: uint, op: &fn(uint) -> T) -> ~[T] { unsafe { let mut v = with_capacity(n_elts); do as_mut_buf(v) |p, _len| { @@ -169,7 +101,7 @@ pub fn to_owned<T:Copy>(t: &[T]) -> ~[T] { /// Creates a new vector with a capacity of `capacity` pub fn with_capacity<T>(capacity: uint) -> ~[T] { let mut vec = ~[]; - reserve(&mut vec, capacity); + vec.reserve(capacity); vec } @@ -228,85 +160,6 @@ pub fn build_sized_opt<A>(size: Option<uint>, // Accessors -/// Returns the first element of a vector -pub fn head<'r,T>(v: &'r [T]) -> &'r T { - if v.len() == 0 { fail!("head: empty vector") } - &v[0] -} - -/// Returns `Some(x)` where `x` is the first element of the slice `v`, -/// or `None` if the vector is empty. -pub fn head_opt<'r,T>(v: &'r [T]) -> Option<&'r T> { - if v.len() == 0 { None } else { Some(&v[0]) } -} - -/// Returns a vector containing all but the first element of a slice -pub fn tail<'r,T>(v: &'r [T]) -> &'r [T] { slice(v, 1, v.len()) } - -/// Returns a vector containing all but the first `n` elements of a slice -pub fn tailn<'r,T>(v: &'r [T], n: uint) -> &'r [T] { slice(v, n, v.len()) } - -/// Returns a vector containing all but the last element of a slice -pub fn init<'r,T>(v: &'r [T]) -> &'r [T] { slice(v, 0, v.len() - 1) } - -/// Returns a vector containing all but the last `n' elements of a slice -pub fn initn<'r,T>(v: &'r [T], n: uint) -> &'r [T] { - slice(v, 0, v.len() - n) -} - -/// Returns the last element of the slice `v`, failing if the slice is empty. -pub fn last<'r,T>(v: &'r [T]) -> &'r T { - if v.len() == 0 { fail!("last: empty vector") } - &v[v.len() - 1] -} - -/// Returns `Some(x)` where `x` is the last element of the slice `v`, or -/// `None` if the vector is empty. -pub fn last_opt<'r,T>(v: &'r [T]) -> Option<&'r T> { - if v.len() == 0 { None } else { Some(&v[v.len() - 1]) } -} - -/// Return a slice that points into another slice. -#[inline] -pub fn slice<'r,T>(v: &'r [T], start: uint, end: uint) -> &'r [T] { - assert!(start <= end); - assert!(end <= v.len()); - do as_imm_buf(v) |p, _len| { - unsafe { - transmute((ptr::offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) - } - } -} - -/// Return a slice that points into another slice. -#[inline] -pub fn mut_slice<'r,T>(v: &'r mut [T], start: uint, end: uint) - -> &'r mut [T] { - assert!(start <= end); - assert!(end <= v.len()); - do as_mut_buf(v) |p, _len| { - unsafe { - transmute((ptr::mut_offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) - } - } -} - -/// Return a slice that points into another slice. -#[inline] -pub fn const_slice<'r,T>(v: &'r const [T], start: uint, end: uint) - -> &'r const [T] { - assert!(start <= end); - assert!(end <= v.len()); - do as_const_buf(v) |p, _len| { - unsafe { - transmute((ptr::const_offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) - } - } -} - /// Copies /// Split the vector `v` by applying each element against the predicate `f`. @@ -317,15 +170,15 @@ pub fn split<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[~[T]] { let mut start = 0u; let mut result = ~[]; while start < ln { - match position_between(v, start, ln, f) { + match v.slice(start, ln).iter().position_(|t| f(t)) { None => break, Some(i) => { - result.push(slice(v, start, i).to_vec()); - start = i + 1u; + result.push(v.slice(start, start + i).to_owned()); + start += i + 1u; } } } - result.push(slice(v, start, ln).to_vec()); + result.push(v.slice(start, ln).to_owned()); result } @@ -341,17 +194,17 @@ pub fn splitn<T:Copy>(v: &[T], n: uint, f: &fn(t: &T) -> bool) -> ~[~[T]] { let mut count = n; let mut result = ~[]; while start < ln && count > 0u { - match position_between(v, start, ln, f) { + match v.slice(start, ln).iter().position_(|t| f(t)) { None => break, Some(i) => { - result.push(slice(v, start, i).to_vec()); + result.push(v.slice(start, start + i).to_owned()); // Make sure to skip the separator. - start = i + 1u; + start += i + 1u; count -= 1u; } } } - result.push(slice(v, start, ln).to_vec()); + result.push(v.slice(start, ln).to_owned()); result } @@ -366,16 +219,16 @@ pub fn rsplit<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[~[T]] { let mut end = ln; let mut result = ~[]; while end > 0 { - match rposition_between(v, 0, end, f) { + match v.slice(0, end).rposition(|t| f(t)) { None => break, Some(i) => { - result.push(slice(v, i + 1, end).to_vec()); + result.push(v.slice(i + 1, end).to_owned()); end = i; } } } - result.push(slice(v, 0u, end).to_vec()); - reverse(result); + result.push(v.slice(0u, end).to_owned()); + result.reverse(); result } @@ -391,151 +244,21 @@ pub fn rsplitn<T:Copy>(v: &[T], n: uint, f: &fn(t: &T) -> bool) -> ~[~[T]] { let mut count = n; let mut result = ~[]; while end > 0u && count > 0u { - match rposition_between(v, 0u, end, f) { + match v.slice(0, end).rposition(|t| f(t)) { None => break, Some(i) => { - result.push(slice(v, i + 1u, end).to_vec()); + result.push(v.slice(i + 1u, end).to_owned()); // Make sure to skip the separator. end = i; count -= 1u; } } } - result.push(slice(v, 0u, end).to_vec()); - reverse(result); + result.push(v.slice(0u, end).to_owned()); + result.reverse(); result } -/** - * Partitions a vector into two new vectors: those that satisfies the - * predicate, and those that do not. - */ -pub fn partition<T>(v: ~[T], f: &fn(&T) -> bool) -> (~[T], ~[T]) { - let mut lefts = ~[]; - let mut rights = ~[]; - - // FIXME (#4355 maybe): using v.consume here crashes - // do v.consume |_, elt| { - do consume(v) |_, elt| { - if f(&elt) { - lefts.push(elt); - } else { - rights.push(elt); - } - } - - (lefts, rights) -} - -/** - * Partitions a vector into two new vectors: those that satisfies the - * predicate, and those that do not. - */ -pub fn partitioned<T:Copy>(v: &[T], f: &fn(&T) -> bool) -> (~[T], ~[T]) { - let mut lefts = ~[]; - let mut rights = ~[]; - - for each(v) |elt| { - if f(elt) { - lefts.push(copy *elt); - } else { - rights.push(copy *elt); - } - } - - (lefts, rights) -} - -// Mutators - -/// Removes the first element from a vector and return it -pub fn shift<T>(v: &mut ~[T]) -> T { - unsafe { - assert!(!v.is_empty()); - - if v.len() == 1 { return v.pop() } - - if v.len() == 2 { - let last = v.pop(); - let first = v.pop(); - v.push(last); - return first; - } - - let ln = v.len(); - let next_ln = v.len() - 1; - - // Save the last element. We're going to overwrite its position - let work_elt = v.pop(); - // We still should have room to work where what last element was - assert!(capacity(v) >= ln); - // Pretend like we have the original length so we can use - // the vector copy_memory to overwrite the hole we just made - raw::set_len(&mut *v, ln); - - // Memcopy the head element (the one we want) to the location we just - // popped. For the moment it unsafely exists at both the head and last - // positions - { - let first_slice = slice(*v, 0, 1); - let last_slice = slice(*v, next_ln, ln); - raw::copy_memory(transmute(last_slice), first_slice, 1); - } - - // Memcopy everything to the left one element - { - let init_slice = slice(*v, 0, next_ln); - let tail_slice = slice(*v, 1, ln); - raw::copy_memory(transmute(init_slice), - tail_slice, - next_ln); - } - - // Set the new length. Now the vector is back to normal - raw::set_len(&mut *v, next_ln); - - // Swap out the element we want from the end - let vp = raw::to_mut_ptr(*v); - let vp = ptr::mut_offset(vp, next_ln - 1); - - ptr::replace_ptr(vp, work_elt) - } -} - -/// Prepend an element to the vector -pub fn unshift<T>(v: &mut ~[T], x: T) { - let vv = util::replace(v, ~[x]); - v.push_all_move(vv); -} - -/// Insert an element at position i within v, shifting all -/// elements after position i one position to the right. -pub fn insert<T>(v: &mut ~[T], i: uint, x: T) { - let len = v.len(); - assert!(i <= len); - - v.push(x); - let mut j = len; - while j > i { - swap(*v, j, j - 1); - j -= 1; - } -} - -/// Remove and return the element at position i within v, shifting -/// all elements after position i one position to the left. -pub fn remove<T>(v: &mut ~[T], i: uint) -> T { - let len = v.len(); - assert!(i < len); - - let mut j = i; - while j < len - 1 { - swap(*v, j, j + 1); - j += 1; - } - v.pop() -} - /// Consumes all elements, in a vector, moving them out into the / closure /// provided. The vector is traversed from the start to the end. /// @@ -597,174 +320,12 @@ pub fn consume_reverse<T>(mut v: ~[T], f: &fn(uint, v: T)) { } } -/// Remove the last element from a vector and return it -pub fn pop<T>(v: &mut ~[T]) -> T { - let ln = v.len(); - if ln == 0 { - fail!("sorry, cannot vec::pop an empty vector") - } - let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]); - unsafe { - let val = ptr::replace_ptr(valptr, intrinsics::init()); - raw::set_len(v, ln - 1u); - val - } -} - -/** - * Remove an element from anywhere in the vector and return it, replacing it - * with the last element. This does not preserve ordering, but is O(1). - * - * Fails if index >= length. - */ -pub fn swap_remove<T>(v: &mut ~[T], index: uint) -> T { - let ln = v.len(); - if index >= ln { - fail!("vec::swap_remove - index %u >= length %u", index, ln); - } - if index < ln - 1 { - swap(*v, index, ln - 1); - } - v.pop() -} - -/// Append an element to a vector -#[inline] -pub fn push<T>(v: &mut ~[T], initval: T) { - unsafe { - let repr: **raw::VecRepr = transmute(&mut *v); - let fill = (**repr).unboxed.fill; - if (**repr).unboxed.alloc > fill { - push_fast(v, initval); - } - else { - push_slow(v, initval); - } - } -} - -// This doesn't bother to make sure we have space. -#[inline] // really pretty please -unsafe fn push_fast<T>(v: &mut ~[T], initval: T) { - let repr: **mut raw::VecRepr = transmute(v); - let fill = (**repr).unboxed.fill; - (**repr).unboxed.fill += sys::nonzero_size_of::<T>(); - let p = to_unsafe_ptr(&((**repr).unboxed.data)); - let p = ptr::offset(p, fill) as *mut T; - intrinsics::move_val_init(&mut(*p), initval); -} - -#[inline(never)] -fn push_slow<T>(v: &mut ~[T], initval: T) { - let new_len = v.len() + 1; - reserve_at_least(&mut *v, new_len); - unsafe { push_fast(v, initval) } -} - -/// Iterates over the slice `rhs`, copies each element, and then appends it to -/// the vector provided `v`. The `rhs` vector is traversed in-order. -/// -/// # Example -/// -/// ~~~ {.rust} -/// let mut a = ~[1]; -/// vec::push_all(&mut a, [2, 3, 4]); -/// assert!(a == ~[1, 2, 3, 4]); -/// ~~~ -#[inline] -pub fn push_all<T:Copy>(v: &mut ~[T], rhs: &const [T]) { - let new_len = v.len() + rhs.len(); - reserve(&mut *v, new_len); - - for uint::range(0u, rhs.len()) |i| { - push(&mut *v, unsafe { raw::get(rhs, i) }) - } -} - -/// Takes ownership of the vector `rhs`, moving all elements into the specified -/// vector `v`. This does not copy any elements, and it is illegal to use the -/// `rhs` vector after calling this method (because it is moved here). -/// -/// # Example -/// -/// ~~~ {.rust} -/// let mut a = ~[~1]; -/// vec::push_all_move(&mut a, ~[~2, ~3, ~4]); -/// assert!(a == ~[~1, ~2, ~3, ~4]); -/// ~~~ -#[inline] -pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) { - let new_len = v.len() + rhs.len(); - reserve(&mut *v, new_len); - unsafe { - do as_mut_buf(rhs) |p, len| { - for uint::range(0, len) |i| { - let x = ptr::replace_ptr(ptr::mut_offset(p, i), - intrinsics::uninit()); - push(&mut *v, x); - } - } - raw::set_len(&mut rhs, 0); - } -} - -/// Shorten a vector, dropping excess elements. -pub fn truncate<T>(v: &mut ~[T], newlen: uint) { - do as_mut_buf(*v) |p, oldlen| { - assert!(newlen <= oldlen); - unsafe { - // This loop is optimized out for non-drop types. - for uint::range(newlen, oldlen) |i| { - ptr::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit()); - } - } - } - unsafe { raw::set_len(&mut *v, newlen); } -} - -/** - * Remove consecutive repeated elements from a vector; if the vector is - * sorted, this removes all duplicates. - */ -pub fn dedup<T:Eq>(v: &mut ~[T]) { - unsafe { - if v.len() < 1 { return; } - let mut (last_written, next_to_read) = (0, 1); - do as_const_buf(*v) |p, ln| { - // We have a mutable reference to v, so we can make arbitrary - // changes. (cf. push and pop) - let p = p as *mut T; - // last_written < next_to_read <= ln - while next_to_read < ln { - // last_written < next_to_read < ln - if *ptr::mut_offset(p, next_to_read) == - *ptr::mut_offset(p, last_written) { - ptr::replace_ptr(ptr::mut_offset(p, next_to_read), - intrinsics::uninit()); - } else { - last_written += 1; - // last_written <= next_to_read < ln - if next_to_read != last_written { - ptr::swap_ptr(ptr::mut_offset(p, last_written), - ptr::mut_offset(p, next_to_read)); - } - } - // last_written <= next_to_read < ln - next_to_read += 1; - // last_written < next_to_read <= ln - } - } - // last_written < next_to_read == ln - raw::set_len(v, last_written + 1); - } -} - // Appending /// Iterates over the `rhs` vector, copying each element and appending it to the /// `lhs`. Afterwards, the `lhs` is then returned for use again. #[inline] -pub fn append<T:Copy>(lhs: ~[T], rhs: &const [T]) -> ~[T] { +pub fn append<T:Copy>(lhs: ~[T], rhs: &[T]) -> ~[T] { let mut v = lhs; v.push_all(rhs); v @@ -779,74 +340,8 @@ pub fn append_one<T>(lhs: ~[T], x: T) -> ~[T] { v } -/** - * Expands a vector in place, initializing the new elements to a given value - * - * # Arguments - * - * * v - The vector to grow - * * n - The number of elements to add - * * initval - The value for the new elements - */ -pub fn grow<T:Copy>(v: &mut ~[T], n: uint, initval: &T) { - let new_len = v.len() + n; - reserve_at_least(&mut *v, new_len); - let mut i: uint = 0u; - - while i < n { - v.push(copy *initval); - i += 1u; - } -} - -/** - * Expands a vector in place, initializing the new elements to the result of - * a function - * - * Function `init_op` is called `n` times with the values [0..`n`) - * - * # Arguments - * - * * v - The vector to grow - * * n - The number of elements to add - * * init_op - A function to call to retreive each appended element's - * value - */ -pub fn grow_fn<T>(v: &mut ~[T], n: uint, op: old_iter::InitOp<T>) { - let new_len = v.len() + n; - reserve_at_least(&mut *v, new_len); - let mut i: uint = 0u; - while i < n { - v.push(op(i)); - i += 1u; - } -} - -/** - * Sets the value of a vector element at a given index, growing the vector as - * needed - * - * Sets the element at position `index` to `val`. If `index` is past the end - * of the vector, expands the vector by replicating `initval` to fill the - * intervening space. - */ -pub fn grow_set<T:Copy>(v: &mut ~[T], index: uint, initval: &T, val: T) { - let l = v.len(); - if index >= l { grow(&mut *v, index - l + 1u, initval); } - v[index] = val; -} - // Functional utilities -/// Apply a function to each element of a vector and return the results -pub fn map<T, U>(v: &[T], f: &fn(t: &T) -> U) -> ~[U] { - let mut result = with_capacity(v.len()); - for each(v) |elem| { - result.push(f(elem)); - } - result -} - /// Consumes a vector, mapping it into a different vector. This function takes /// ownership of the supplied vector `v`, moving each element into the closure /// provided to generate a new element. The vector of new elements is then @@ -861,43 +356,16 @@ pub fn map_consume<T, U>(v: ~[T], f: &fn(v: T) -> U) -> ~[U] { } result } - -/// Apply a function to each element of a vector and return the results -pub fn mapi<T, U>(v: &[T], f: &fn(uint, t: &T) -> U) -> ~[U] { - let mut i = 0; - do map(v) |e| { - i += 1; - f(i - 1, e) - } -} - /** * Apply a function to each element of a vector and return a concatenation * of each result vector */ pub fn flat_map<T, U>(v: &[T], f: &fn(t: &T) -> ~[U]) -> ~[U] { let mut result = ~[]; - for each(v) |elem| { result.push_all_move(f(elem)); } + for v.iter().advance |elem| { result.push_all_move(f(elem)); } result } -/** - * Apply a function to each pair of elements and return the results. - * Equivalent to `map(zip(v0, v1), f)`. - */ -pub fn map_zip<T:Copy,U:Copy,V>(v0: &[T], v1: &[U], - f: &fn(t: &T, v: &U) -> V) -> ~[V] { - let v0_len = v0.len(); - if v0_len != v1.len() { fail!(); } - let mut u: ~[V] = ~[]; - let mut i = 0u; - while i < v0_len { - u.push(f(&v0[i], &v1[i])); - i += 1u; - } - u -} - pub fn filter_map<T, U>( v: ~[T], f: &fn(t: T) -> Option<U>) -> ~[U] @@ -930,7 +398,7 @@ pub fn filter_mapped<T, U: Copy>( */ let mut result = ~[]; - for each(v) |elem| { + for v.iter().advance |elem| { match f(elem) { None => {/* no-op */ } Some(result_elem) => { result.push(result_elem); } @@ -965,32 +433,12 @@ pub fn filter<T>(v: ~[T], f: &fn(t: &T) -> bool) -> ~[T] { */ pub fn filtered<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[T] { let mut result = ~[]; - for each(v) |elem| { + for v.iter().advance |elem| { if f(elem) { result.push(copy *elem); } } result } -/** - * Like `filter()`, but in place. Preserves order of `v`. Linear time. - */ -pub fn retain<T>(v: &mut ~[T], f: &fn(t: &T) -> bool) { - let len = v.len(); - let mut deleted: uint = 0; - - for uint::range(0, len) |i| { - if !f(&v[i]) { - deleted += 1; - } else if deleted > 0 { - swap(*v, i - deleted, i); - } - } - - if deleted > 0 { - v.truncate(len - deleted); - } -} - /// Flattens a vector of vectors of T into a single vector of T. pub fn concat<T:Copy>(v: &[~[T]]) -> ~[T] { v.concat_vec() } @@ -1021,7 +469,7 @@ impl<'self, T:Copy> VectorVector<T> for &'self [~[T]] { pub fn connect_vec(&self, sep: &T) -> ~[T] { let mut r = ~[]; let mut first = true; - for self.each |&inner| { + for self.iter().advance |&inner| { if first { first = false; } else { r.push(copy *sep); } r.push_all(inner); } @@ -1039,7 +487,7 @@ impl<'self, T:Copy> VectorVector<T> for &'self [&'self [T]] { pub fn connect_vec(&self, sep: &T) -> ~[T] { let mut r = ~[]; let mut first = true; - for self.each |&inner| { + for self.iter().advance |&inner| { if first { first = false; } else { r.push(copy *sep); } r.push_all(inner); } @@ -1047,172 +495,6 @@ impl<'self, T:Copy> VectorVector<T> for &'self [&'self [T]] { } } -/// Return true if a vector contains an element with the given value -pub fn contains<T:Eq>(v: &[T], x: &T) -> bool { - for each(v) |elt| { if *x == *elt { return true; } } - false -} - -/** - * Search for the first element that matches a given predicate - * - * Apply function `f` to each element of `v`, starting from the first. - * When function `f` returns true then an option containing the element - * is returned. If `f` matches no elements then none is returned. - */ -pub fn find<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> Option<T> { - find_between(v, 0u, v.len(), f) -} - -/** - * Search for the first element that matches a given predicate within a range - * - * Apply function `f` to each element of `v` within the range - * [`start`, `end`). When function `f` returns true then an option containing - * the element is returned. If `f` matches no elements then none is returned. - */ -pub fn find_between<T:Copy>(v: &[T], start: uint, end: uint, - f: &fn(t: &T) -> bool) -> Option<T> { - position_between(v, start, end, f).map(|i| copy v[*i]) -} - -/** - * Search for the last element that matches a given predicate - * - * Apply function `f` to each element of `v` in reverse order. When function - * `f` returns true then an option containing the element is returned. If `f` - * matches no elements then none is returned. - */ -pub fn rfind<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> Option<T> { - rfind_between(v, 0u, v.len(), f) -} - -/** - * Search for the last element that matches a given predicate within a range - * - * Apply function `f` to each element of `v` in reverse order within the range - * [`start`, `end`). When function `f` returns true then an option containing - * the element is returned. If `f` matches no elements then none is return. - */ -pub fn rfind_between<T:Copy>(v: &[T], - start: uint, - end: uint, - f: &fn(t: &T) -> bool) - -> Option<T> { - rposition_between(v, start, end, f).map(|i| copy v[*i]) -} - -/// Find the first index containing a matching value -pub fn position_elem<T:Eq>(v: &[T], x: &T) -> Option<uint> { - position(v, |y| *x == *y) -} - -/** - * Find the first index matching some predicate - * - * Apply function `f` to each element of `v`. When function `f` returns true - * then an option containing the index is returned. If `f` matches no elements - * then none is returned. - */ -pub fn position<T>(v: &[T], f: &fn(t: &T) -> bool) -> Option<uint> { - position_between(v, 0u, v.len(), f) -} - -/** - * Find the first index matching some predicate within a range - * - * Apply function `f` to each element of `v` between the range - * [`start`, `end`). When function `f` returns true then an option containing - * the index is returned. If `f` matches no elements then none is returned. - */ -pub fn position_between<T>(v: &[T], - start: uint, - end: uint, - f: &fn(t: &T) -> bool) - -> Option<uint> { - assert!(start <= end); - assert!(end <= v.len()); - let mut i = start; - while i < end { if f(&v[i]) { return Some::<uint>(i); } i += 1u; } - None -} - -/// Find the last index containing a matching value -pub fn rposition_elem<T:Eq>(v: &[T], x: &T) -> Option<uint> { - rposition(v, |y| *x == *y) -} - -/** - * Find the last index matching some predicate - * - * Apply function `f` to each element of `v` in reverse order. When function - * `f` returns true then an option containing the index is returned. If `f` - * matches no elements then none is returned. - */ -pub fn rposition<T>(v: &[T], f: &fn(t: &T) -> bool) -> Option<uint> { - rposition_between(v, 0u, v.len(), f) -} - -/** - * Find the last index matching some predicate within a range - * - * Apply function `f` to each element of `v` in reverse order between the - * range [`start`, `end`). When function `f` returns true then an option - * containing the index is returned. If `f` matches no elements then none is - * returned. - */ -pub fn rposition_between<T>(v: &[T], start: uint, end: uint, - f: &fn(t: &T) -> bool) -> Option<uint> { - assert!(start <= end); - assert!(end <= v.len()); - let mut i = end; - while i > start { - if f(&v[i - 1u]) { return Some::<uint>(i - 1u); } - i -= 1u; - } - None -} - - - -/** - * Binary search a sorted vector with a comparator function. - * - * The comparator should implement an order consistent with the sort - * order of the underlying vector, returning an order code that indicates - * whether its argument is `Less`, `Equal` or `Greater` the desired target. - * - * Returns the index where the comparator returned `Equal`, or `None` if - * not found. - */ -pub fn bsearch<T>(v: &[T], f: &fn(&T) -> Ordering) -> Option<uint> { - let mut base : uint = 0; - let mut lim : uint = v.len(); - - while lim != 0 { - let ix = base + (lim >> 1); - match f(&v[ix]) { - Equal => return Some(ix), - Less => { - base = ix + 1; - lim -= 1; - } - Greater => () - } - lim >>= 1; - } - return None; -} - -/** - * Binary search a sorted vector for a given element. - * - * Returns the index of the element or None if not found. - */ -pub fn bsearch_elem<T:TotalOrd>(v: &[T], x: &T) -> Option<uint> { - bsearch(v, |p| p.cmp(x)) -} - // FIXME: if issue #586 gets implemented, could have a postcondition // saying the two result lists have the same length -- or, could // return a nominal record with a constraint saying that, instead of @@ -1221,8 +503,9 @@ pub fn bsearch_elem<T:TotalOrd>(v: &[T], x: &T) -> Option<uint> { * Convert a vector of pairs into a pair of vectors, by reference. As unzip(). */ pub fn unzip_slice<T:Copy,U:Copy>(v: &[(T, U)]) -> (~[T], ~[U]) { - let mut (ts, us) = (~[], ~[]); - for each(v) |p| { + let mut ts = ~[]; + let mut us = ~[]; + for v.iter().advance |p| { let (t, u) = copy *p; ts.push(t); us.push(u); @@ -1239,7 +522,8 @@ pub fn unzip_slice<T:Copy,U:Copy>(v: &[(T, U)]) -> (~[T], ~[U]) { * of the i-th tuple of the input vector. */ pub fn unzip<T,U>(v: ~[(T, U)]) -> (~[T], ~[U]) { - let mut (ts, us) = (~[], ~[]); + let mut ts = ~[]; + let mut us = ~[]; do consume(v) |_i, p| { let (t, u) = p; ts.push(t); @@ -1251,7 +535,7 @@ pub fn unzip<T,U>(v: ~[(T, U)]) -> (~[T], ~[U]) { /** * Convert two vectors to a vector of pairs, by reference. As zip(). */ -pub fn zip_slice<T:Copy,U:Copy>(v: &const [T], u: &const [U]) +pub fn zip_slice<T:Copy,U:Copy>(v: &[T], u: &[U]) -> ~[(T, U)] { let mut zipped = ~[]; let sz = v.len(); @@ -1278,80 +562,12 @@ pub fn zip<T, U>(mut v: ~[T], mut u: ~[U]) -> ~[(T, U)] { w.push((v.pop(),u.pop())); i -= 1; } - reverse(w); + w.reverse(); w } -/** - * Swaps two elements in a vector - * - * # Arguments - * - * * v The input vector - * * a - The index of the first element - * * b - The index of the second element - */ -#[inline] -pub fn swap<T>(v: &mut [T], a: uint, b: uint) { - unsafe { - // Can't take two mutable loans from one vector, so instead just cast - // them to their raw pointers to do the swap - let pa: *mut T = &mut v[a]; - let pb: *mut T = &mut v[b]; - ptr::swap_ptr(pa, pb); - } -} - -/// Reverse the order of elements in a vector, in place -pub fn reverse<T>(v: &mut [T]) { - let mut i: uint = 0; - let ln = v.len(); - while i < ln / 2 { - swap(v, i, ln - i - 1); - i += 1; - } -} - -/** - * Reverse part of a vector in place. - * - * Reverse the elements in the vector between `start` and `end - 1`. - * - * If either start or end do not represent valid positions in the vector, the - * vector is returned unchanged. - * - * # Arguments - * - * * `v` - The mutable vector to be modified - * - * * `start` - Index of the first element of the slice - * - * * `end` - Index one past the final element to be reversed. - * - * # Example - * - * Assume a mutable vector `v` contains `[1,2,3,4,5]`. After the call: - * - * ~~~ {.rust} - * reverse_part(v, 1, 4); - * ~~~ - * - * `v` now contains `[1,4,3,2,5]`. - */ -pub fn reverse_part<T>(v: &mut [T], start: uint, end : uint) { - let sz = v.len(); - if start >= sz || end > sz { return; } - let mut i = start; - let mut j = end - 1; - while i < j { - vec::swap(v, i, j); - i += 1; - j -= 1; - } -} - /// Returns a vector with the order of elements reversed -pub fn reversed<T:Copy>(v: &const [T]) -> ~[T] { +pub fn reversed<T:Copy>(v: &[T]) -> ~[T] { let mut rs: ~[T] = ~[]; let mut i = v.len(); if i == 0 { return (rs); } else { i -= 1; } @@ -1361,99 +577,6 @@ pub fn reversed<T:Copy>(v: &const [T]) -> ~[T] { } /** - * Iterates over a vector, yielding each element to a closure. - * - * # Arguments - * - * * `v` - A vector, to be iterated over - * * `f` - A closure to do the iterating. Within this closure, return true to - * * continue iterating, false to break. - * - * # Examples - * - * ~~~ {.rust} - * [1,2,3].each(|&i| { - * io::println(int::str(i)); - * true - * }); - * ~~~ - * - * ~~~ {.rust} - * [1,2,3,4,5].each(|&i| { - * if i < 4 { - * io::println(int::str(i)); - * true - * } - * else { - * false - * } - * }); - * ~~~ - * - * You probably will want to use each with a `for`/`do` expression, depending - * on your iteration needs: - * - * ~~~ {.rust} - * for [1,2,3].each |&i| { - * io::println(int::str(i)); - * } - * ~~~ - */ -#[inline] -pub fn each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) -> bool { - // ^^^^ - // NB---this CANNOT be &const [T]! The reason - // is that you are passing it to `f()` using - // an immutable. - - let mut broke = false; - do as_imm_buf(v) |p, n| { - let mut n = n; - let mut p = p; - while n > 0u { - unsafe { - let q = cast::copy_lifetime_vec(v, &*p); - if !f(q) { break; } - p = ptr::offset(p, 1u); - } - n -= 1u; - } - broke = n > 0; - } - return !broke; -} - -/// Like `each()`, but for the case where you have a vector that *may or may -/// not* have mutable contents. -#[inline] -pub fn each_const<T>(v: &const [T], f: &fn(elem: &const T) -> bool) -> bool { - let mut i = 0; - let n = v.len(); - while i < n { - if !f(&const v[i]) { - return false; - } - i += 1; - } - return true; -} - -/** - * Iterates over a vector's elements and indices - * - * Return true to continue, false to break. - */ -#[inline] -pub fn eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) -> bool { - let mut i = 0; - for each(v) |p| { - if !f(i, p) { return false; } - i += 1; - } - return true; -} - -/** * Iterate over all permutations of vector `v`. * * Permutations are produced in lexicographic order with respect to the order @@ -1498,8 +621,8 @@ pub fn each_permutation<T:Copy>(values: &[T], fun: &fn(perm : &[T]) -> bool) -> } // swap indices[k] and indices[l]; sort indices[k+1..] // (they're just reversed) - vec::swap(indices, k, l); - reverse_part(indices, k+1, length); + indices.swap(k, l); + indices.mut_slice(k+1, length).reverse(); // fixup permutation based on indices for uint::range(k, length) |i| { permutation[i] = copy values[indices[i]]; @@ -1554,16 +677,6 @@ pub fn as_imm_buf<T,U>(s: &[T], } } -/// Similar to `as_imm_buf` but passing a `*const T` -#[inline] -pub fn as_const_buf<T,U>(s: &const [T], f: &fn(*const T, uint) -> U) -> U { - unsafe { - let v : *(*const T,uint) = transmute(&s); - let (buf,len) = *v; - f(buf, len / sys::nonzero_size_of::<T>()) - } -} - /// Similar to `as_imm_buf` but passing a `*mut T` #[inline] pub fn as_mut_buf<T,U>(s: &mut [T], f: &fn(*mut T, uint) -> U) -> U { @@ -1744,30 +857,24 @@ impl<T:Ord> Ord for @[T] { } #[cfg(not(test))] -pub mod traits { - use kinds::Copy; - use ops::Add; - use vec::append; - - impl<'self,T:Copy> Add<&'self const [T],~[T]> for ~[T] { - #[inline] - fn add(&self, rhs: & &'self const [T]) -> ~[T] { - append(copy *self, (*rhs)) - } +impl<'self,T:Copy> Add<&'self [T], ~[T]> for ~[T] { + #[inline] + fn add(&self, rhs: & &'self [T]) -> ~[T] { + append(copy *self, (*rhs)) } } -impl<'self, T> Container for &'self const [T] { +impl<'self, T> Container for &'self [T] { /// Returns true if a vector contains no elements #[inline] fn is_empty(&self) -> bool { - as_const_buf(*self, |_p, len| len == 0u) + as_imm_buf(*self, |_p, len| len == 0u) } /// Returns the length of a vector #[inline] fn len(&self) -> uint { - as_const_buf(*self, |_p, len| len) + as_imm_buf(*self, |_p, len| len) } } @@ -1775,13 +882,13 @@ impl<T> Container for ~[T] { /// Returns true if a vector contains no elements #[inline] fn is_empty(&self) -> bool { - as_const_buf(*self, |_p, len| len == 0u) + as_imm_buf(*self, |_p, len| len == 0u) } /// Returns the length of a vector #[inline] fn len(&self) -> uint { - as_const_buf(*self, |_p, len| len) + as_imm_buf(*self, |_p, len| len) } } @@ -1795,13 +902,11 @@ impl<'self,T:Copy> CopyableVector<T> for &'self [T] { /// Returns a copy of `v`. #[inline] fn to_owned(&self) -> ~[T] { - let mut result = ~[]; - reserve(&mut result, self.len()); - for self.each |e| { + let mut result = with_capacity(self.len()); + for self.iter().advance |e| { result.push(copy *e); } result - } } @@ -1818,14 +923,14 @@ pub trait ImmutableVector<'self, T> { fn initn(&self, n: uint) -> &'self [T]; fn last(&self) -> &'self T; fn last_opt(&self) -> Option<&'self T>; - fn position(&self, f: &fn(t: &T) -> bool) -> Option<uint>; fn rposition(&self, f: &fn(t: &T) -> bool) -> Option<uint>; - fn map<U>(&self, f: &fn(t: &T) -> U) -> ~[U]; - fn mapi<U>(&self, f: &fn(uint, t: &T) -> U) -> ~[U]; - fn map_r<U>(&self, f: &fn(x: &T) -> U) -> ~[U]; fn flat_map<U>(&self, f: &fn(t: &T) -> ~[U]) -> ~[U]; fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U]; unsafe fn unsafe_ref(&self, index: uint) -> *T; + + fn bsearch(&self, f: &fn(&T) -> Ordering) -> Option<uint>; + + fn map<U>(&self, &fn(t: &T) -> U) -> ~[U]; } /// Extension methods for vectors @@ -1833,7 +938,14 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { /// Return a slice that points into another slice. #[inline] fn slice(&self, start: uint, end: uint) -> &'self [T] { - slice(*self, start, end) + assert!(start <= end); + assert!(end <= self.len()); + do as_imm_buf(*self) |p, _len| { + unsafe { + transmute((ptr::offset(p, start), + (end - start) * sys::nonzero_size_of::<T>())) + } + } } #[inline] @@ -1856,46 +968,48 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { /// Returns the first element of a vector, failing if the vector is empty. #[inline] - fn head(&self) -> &'self T { head(*self) } + fn head(&self) -> &'self T { + if self.len() == 0 { fail!("head: empty vector") } + &self[0] + } - /// Returns the first element of a vector + /// Returns the first element of a vector, or `None` if it is empty #[inline] - fn head_opt(&self) -> Option<&'self T> { head_opt(*self) } + fn head_opt(&self) -> Option<&'self T> { + if self.len() == 0 { None } else { Some(&self[0]) } + } /// Returns all but the first element of a vector #[inline] - fn tail(&self) -> &'self [T] { tail(*self) } + fn tail(&self) -> &'self [T] { self.slice(1, self.len()) } /// Returns all but the first `n' elements of a vector #[inline] - fn tailn(&self, n: uint) -> &'self [T] { tailn(*self, n) } + fn tailn(&self, n: uint) -> &'self [T] { self.slice(n, self.len()) } - /// Returns all but the last elemnt of a vector + /// Returns all but the last element of a vector #[inline] - fn init(&self) -> &'self [T] { init(*self) } + fn init(&self) -> &'self [T] { + self.slice(0, self.len() - 1) + } /// Returns all but the last `n' elemnts of a vector #[inline] - fn initn(&self, n: uint) -> &'self [T] { initn(*self, n) } - - /// Returns the last element of a `v`, failing if the vector is empty. - #[inline] - fn last(&self) -> &'self T { last(*self) } + fn initn(&self, n: uint) -> &'self [T] { + self.slice(0, self.len() - n) + } - /// Returns the last element of a `v`, failing if the vector is empty. + /// Returns the last element of a vector, failing if the vector is empty. #[inline] - fn last_opt(&self) -> Option<&'self T> { last_opt(*self) } + fn last(&self) -> &'self T { + if self.len() == 0 { fail!("last: empty vector") } + &self[self.len() - 1] + } - /** - * Find the first index matching some predicate - * - * Apply function `f` to each element of `v`. When function `f` returns - * true then an option containing the index is returned. If `f` matches no - * elements then none is returned. - */ + /// Returns the last element of a vector, or `None` if it is empty. #[inline] - fn position(&self, f: &fn(t: &T) -> bool) -> Option<uint> { - position(*self, f) + fn last_opt(&self) -> Option<&'self T> { + if self.len() == 0 { None } else { Some(&self[self.len() - 1]) } } /** @@ -1903,34 +1017,14 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { * * Apply function `f` to each element of `v` in reverse order. When * function `f` returns true then an option containing the index is - * returned. If `f` matches no elements then none is returned. + * returned. If `f` matches no elements then None is returned. */ #[inline] fn rposition(&self, f: &fn(t: &T) -> bool) -> Option<uint> { - rposition(*self, f) - } - - /// Apply a function to each element of a vector and return the results - #[inline] - fn map<U>(&self, f: &fn(t: &T) -> U) -> ~[U] { map(*self, f) } - - /** - * Apply a function to the index and value of each element in the vector - * and return the results - */ - fn mapi<U>(&self, f: &fn(uint, t: &T) -> U) -> ~[U] { - mapi(*self, f) - } - - #[inline] - fn map_r<U>(&self, f: &fn(x: &T) -> U) -> ~[U] { - let mut r = ~[]; - let mut i = 0; - while i < self.len() { - r.push(f(&self[i])); - i += 1; + for self.rev_iter().enumerate().advance |(i, t)| { + if f(t) { return Some(self.len() - i - 1); } } - r + None } /** @@ -1959,32 +1053,90 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { let (ptr, _): (*T, uint) = transmute(*self); ptr.offset(index) } + + /** + * Binary search a sorted vector with a comparator function. + * + * The comparator should implement an order consistent with the sort + * order of the underlying vector, returning an order code that indicates + * whether its argument is `Less`, `Equal` or `Greater` the desired target. + * + * Returns the index where the comparator returned `Equal`, or `None` if + * not found. + */ + fn bsearch(&self, f: &fn(&T) -> Ordering) -> Option<uint> { + let mut base : uint = 0; + let mut lim : uint = self.len(); + + while lim != 0 { + let ix = base + (lim >> 1); + match f(&self[ix]) { + Equal => return Some(ix), + Less => { + base = ix + 1; + lim -= 1; + } + Greater => () + } + lim >>= 1; + } + return None; + } + + /// Deprecated, use iterators where possible + /// (`self.iter().transform(f)`). Apply a function to each element + /// of a vector and return the results. + fn map<U>(&self, f: &fn(t: &T) -> U) -> ~[U] { + self.iter().transform(f).collect() + } } #[allow(missing_doc)] pub trait ImmutableEqVector<T:Eq> { fn position_elem(&self, t: &T) -> Option<uint>; fn rposition_elem(&self, t: &T) -> Option<uint>; + fn contains(&self, x: &T) -> bool; } impl<'self,T:Eq> ImmutableEqVector<T> for &'self [T] { /// Find the first index containing a matching value #[inline] fn position_elem(&self, x: &T) -> Option<uint> { - position_elem(*self, x) + self.iter().position_(|y| *x == *y) } /// Find the last index containing a matching value #[inline] fn rposition_elem(&self, t: &T) -> Option<uint> { - rposition_elem(*self, t) + self.rposition(|x| *x == *t) + } + + /// Return true if a vector contains an element with the given value + fn contains(&self, x: &T) -> bool { + for self.iter().advance |elt| { if *x == *elt { return true; } } + false + } +} + +#[allow(missing_doc)] +pub trait ImmutableTotalOrdVector<T: TotalOrd> { + fn bsearch_elem(&self, x: &T) -> Option<uint>; +} + +impl<'self, T: TotalOrd> ImmutableTotalOrdVector<T> for &'self [T] { + /** + * Binary search a sorted vector for a given element. + * + * Returns the index of the element or None if not found. + */ + fn bsearch_elem(&self, x: &T) -> Option<uint> { + self.bsearch(|p| p.cmp(x)) } } #[allow(missing_doc)] pub trait ImmutableCopyableVector<T> { fn filtered(&self, f: &fn(&T) -> bool) -> ~[T]; - fn rfind(&self, f: &fn(t: &T) -> bool) -> Option<T>; fn partitioned(&self, f: &fn(&T) -> bool) -> (~[T], ~[T]); unsafe fn unsafe_get(&self, elem: uint) -> T; } @@ -2004,24 +1156,23 @@ impl<'self,T:Copy> ImmutableCopyableVector<T> for &'self [T] { } /** - * Search for the last element that matches a given predicate - * - * Apply function `f` to each element of `v` in reverse order. When - * function `f` returns true then an option containing the element is - * returned. If `f` matches no elements then none is returned. - */ - #[inline] - fn rfind(&self, f: &fn(t: &T) -> bool) -> Option<T> { - rfind(*self, f) - } - - /** * Partitions the vector into those that satisfies the predicate, and * those that do not. */ #[inline] fn partitioned(&self, f: &fn(&T) -> bool) -> (~[T], ~[T]) { - partitioned(*self, f) + let mut lefts = ~[]; + let mut rights = ~[]; + + for self.iter().advance |elt| { + if f(elt) { + lefts.push(copy *elt); + } else { + rights.push(copy *elt); + } + } + + (lefts, rights) } /// Returns the element at the given index, without doing bounds checking. @@ -2033,7 +1184,13 @@ impl<'self,T:Copy> ImmutableCopyableVector<T> for &'self [T] { #[allow(missing_doc)] pub trait OwnedVector<T> { + fn reserve(&mut self, n: uint); + fn reserve_at_least(&mut self, n: uint); + fn capacity(&self) -> uint; + fn push(&mut self, t: T); + unsafe fn push_fast(&mut self, t: T); + fn push_all_move(&mut self, rhs: ~[T]); fn pop(&mut self) -> T; fn shift(&mut self) -> T; @@ -2047,58 +1204,316 @@ pub trait OwnedVector<T> { fn consume_reverse(self, f: &fn(uint, v: T)); fn filter(self, f: &fn(t: &T) -> bool) -> ~[T]; fn partition(self, f: &fn(&T) -> bool) -> (~[T], ~[T]); - fn grow_fn(&mut self, n: uint, op: old_iter::InitOp<T>); + fn grow_fn(&mut self, n: uint, op: &fn(uint) -> T); } impl<T> OwnedVector<T> for ~[T] { + /** + * Reserves capacity for exactly `n` elements in the given vector. + * + * If the capacity for `self` is already equal to or greater than the requested + * capacity, then no action is taken. + * + * # Arguments + * + * * n - The number of elements to reserve space for + */ #[inline] - fn push(&mut self, t: T) { - push(self, t); + #[cfg(stage0)] + fn reserve(&mut self, n: uint) { + // Only make the (slow) call into the runtime if we have to + use managed; + if self.capacity() < n { + unsafe { + let ptr: *mut *mut raw::VecRepr = cast::transmute(self); + let td = get_tydesc::<T>(); + if ((**ptr).box_header.ref_count == + managed::raw::RC_MANAGED_UNIQUE) { + // XXX transmute shouldn't be necessary + let td = cast::transmute(td); + ::at_vec::raw::reserve_raw(td, ptr, n); + } else { + let alloc = n * sys::nonzero_size_of::<T>(); + *ptr = realloc_raw(*ptr as *mut c_void, alloc + size_of::<raw::VecRepr>()) + as *mut raw::VecRepr; + (**ptr).unboxed.alloc = alloc; + } + } + } + } + + /** + * Reserves capacity for exactly `n` elements in the given vector. + * + * If the capacity for `self` is already equal to or greater than the requested + * capacity, then no action is taken. + * + * # Arguments + * + * * n - The number of elements to reserve space for + */ + #[inline] + #[cfg(not(stage0))] + fn reserve(&mut self, n: uint) { + // Only make the (slow) call into the runtime if we have to + if self.capacity() < n { + unsafe { + let ptr: *mut *mut raw::VecRepr = cast::transmute(self); + let td = get_tydesc::<T>(); + if contains_managed::<T>() { + ::at_vec::raw::reserve_raw(td, ptr, n); + } else { + let alloc = n * sys::nonzero_size_of::<T>(); + *ptr = realloc_raw(*ptr as *mut c_void, alloc + size_of::<raw::VecRepr>()) + as *mut raw::VecRepr; + (**ptr).unboxed.alloc = alloc; + } + } + } + } + + /** + * Reserves capacity for at least `n` elements in the given vector. + * + * This function will over-allocate in order to amortize the allocation costs + * in scenarios where the caller may need to repeatedly reserve additional + * space. + * + * If the capacity for `self` is already equal to or greater than the requested + * capacity, then no action is taken. + * + * # Arguments + * + * * n - The number of elements to reserve space for + */ + fn reserve_at_least(&mut self, n: uint) { + self.reserve(uint::next_power_of_two(n)); } + /// Returns the number of elements the vector can hold without reallocating. #[inline] - fn push_all_move(&mut self, rhs: ~[T]) { - push_all_move(self, rhs); + fn capacity(&self) -> uint { + unsafe { + let repr: **raw::VecRepr = transmute(self); + (**repr).unboxed.alloc / sys::nonzero_size_of::<T>() + } } + /// Append an element to a vector #[inline] + fn push(&mut self, t: T) { + unsafe { + let repr: **raw::VecRepr = transmute(&mut *self); + let fill = (**repr).unboxed.fill; + if (**repr).unboxed.alloc <= fill { + // need more space + reserve_no_inline(self); + } + + self.push_fast(t); + } + + // this peculiar function is because reserve_at_least is very + // large (because of reserve), and will be inlined, which + // makes push too large. + #[inline(never)] + fn reserve_no_inline<T>(v: &mut ~[T]) { + let new_len = v.len() + 1; + v.reserve_at_least(new_len); + } + } + + // This doesn't bother to make sure we have space. + #[inline] // really pretty please + unsafe fn push_fast(&mut self, t: T) { + let repr: **mut raw::VecRepr = transmute(self); + let fill = (**repr).unboxed.fill; + (**repr).unboxed.fill += sys::nonzero_size_of::<T>(); + let p = to_unsafe_ptr(&((**repr).unboxed.data)); + let p = ptr::offset(p, fill) as *mut T; + intrinsics::move_val_init(&mut(*p), t); + } + + /// Takes ownership of the vector `rhs`, moving all elements into + /// the current vector. This does not copy any elements, and it is + /// illegal to use the `rhs` vector after calling this method + /// (because it is moved here). + /// + /// # Example + /// + /// ~~~ {.rust} + /// let mut a = ~[~1]; + /// a.push_all_move(~[~2, ~3, ~4]); + /// assert!(a == ~[~1, ~2, ~3, ~4]); + /// ~~~ + #[inline] + fn push_all_move(&mut self, mut rhs: ~[T]) { + let new_len = self.len() + rhs.len(); + self.reserve(new_len); + unsafe { + do as_mut_buf(rhs) |p, len| { + for uint::range(0, len) |i| { + let x = ptr::replace_ptr(ptr::mut_offset(p, i), + intrinsics::uninit()); + self.push(x); + } + } + raw::set_len(&mut rhs, 0); + } + } + + /// Remove the last element from a vector and return it fn pop(&mut self) -> T { - pop(self) + let ln = self.len(); + if ln == 0 { + fail!("sorry, cannot pop an empty vector") + } + let valptr = ptr::to_mut_unsafe_ptr(&mut self[ln - 1u]); + unsafe { + let val = ptr::replace_ptr(valptr, intrinsics::init()); + raw::set_len(self, ln - 1u); + val + } } - #[inline] + /// Removes the first element from a vector and return it fn shift(&mut self) -> T { - shift(self) + unsafe { + assert!(!self.is_empty()); + + if self.len() == 1 { return self.pop() } + + if self.len() == 2 { + let last = self.pop(); + let first = self.pop(); + self.push(last); + return first; + } + + let ln = self.len(); + let next_ln = self.len() - 1; + + // Save the last element. We're going to overwrite its position + let work_elt = self.pop(); + // We still should have room to work where what last element was + assert!(self.capacity() >= ln); + // Pretend like we have the original length so we can use + // the vector copy_memory to overwrite the hole we just made + raw::set_len(self, ln); + + // Memcopy the head element (the one we want) to the location we just + // popped. For the moment it unsafely exists at both the head and last + // positions + { + let first_slice = self.slice(0, 1); + let last_slice = self.slice(next_ln, ln); + raw::copy_memory(transmute(last_slice), first_slice, 1); + } + + // Memcopy everything to the left one element + { + let init_slice = self.slice(0, next_ln); + let tail_slice = self.slice(1, ln); + raw::copy_memory(transmute(init_slice), + tail_slice, + next_ln); + } + + // Set the new length. Now the vector is back to normal + raw::set_len(self, next_ln); + + // Swap out the element we want from the end + let vp = raw::to_mut_ptr(*self); + let vp = ptr::mut_offset(vp, next_ln - 1); + + ptr::replace_ptr(vp, work_elt) + } } - #[inline] + /// Prepend an element to the vector fn unshift(&mut self, x: T) { - unshift(self, x) + let v = util::replace(self, ~[x]); + self.push_all_move(v); } - #[inline] + /// Insert an element at position i within v, shifting all + /// elements after position i one position to the right. fn insert(&mut self, i: uint, x:T) { - insert(self, i, x) + let len = self.len(); + assert!(i <= len); + + self.push(x); + let mut j = len; + while j > i { + self.swap(j, j - 1); + j -= 1; + } } - #[inline] + /// Remove and return the element at position i within v, shifting + /// all elements after position i one position to the left. fn remove(&mut self, i: uint) -> T { - remove(self, i) + let len = self.len(); + assert!(i < len); + + let mut j = i; + while j < len - 1 { + self.swap(j, j + 1); + j += 1; + } + self.pop() } - #[inline] + /** + * Remove an element from anywhere in the vector and return it, replacing it + * with the last element. This does not preserve ordering, but is O(1). + * + * Fails if index >= length. + */ fn swap_remove(&mut self, index: uint) -> T { - swap_remove(self, index) + let ln = self.len(); + if index >= ln { + fail!("vec::swap_remove - index %u >= length %u", index, ln); + } + if index < ln - 1 { + self.swap(index, ln - 1); + } + self.pop() } - #[inline] + /// Shorten a vector, dropping excess elements. fn truncate(&mut self, newlen: uint) { - truncate(self, newlen); + do as_mut_buf(*self) |p, oldlen| { + assert!(newlen <= oldlen); + unsafe { + // This loop is optimized out for non-drop types. + for uint::range(newlen, oldlen) |i| { + ptr::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit()); + } + } + } + unsafe { raw::set_len(self, newlen); } } - #[inline] + + /** + * Like `filter()`, but in place. Preserves order of `v`. Linear time. + */ fn retain(&mut self, f: &fn(t: &T) -> bool) { - retain(self, f); + let len = self.len(); + let mut deleted: uint = 0; + + for uint::range(0, len) |i| { + if !f(&self[i]) { + deleted += 1; + } else if deleted > 0 { + self.swap(i - deleted, i); + } + } + + if deleted > 0 { + self.truncate(len - deleted); + } } #[inline] @@ -2122,12 +1537,40 @@ impl<T> OwnedVector<T> for ~[T] { */ #[inline] fn partition(self, f: &fn(&T) -> bool) -> (~[T], ~[T]) { - partition(self, f) + let mut lefts = ~[]; + let mut rights = ~[]; + + do self.consume |_, elt| { + if f(&elt) { + lefts.push(elt); + } else { + rights.push(elt); + } + } + + (lefts, rights) } - #[inline] - fn grow_fn(&mut self, n: uint, op: old_iter::InitOp<T>) { - grow_fn(self, n, op); + /** + * Expands a vector in place, initializing the new elements to the result of + * a function + * + * Function `init_op` is called `n` times with the values [0..`n`) + * + * # Arguments + * + * * n - The number of elements to add + * * init_op - A function to call to retreive each appended element's + * value + */ + fn grow_fn(&mut self, n: uint, op: &fn(uint) -> T) { + let new_len = self.len() + n; + self.reserve_at_least(new_len); + let mut i: uint = 0u; + while i < n { + self.push(op(i)); + i += 1u; + } } } @@ -2138,37 +1581,105 @@ impl<T> Mutable for ~[T] { #[allow(missing_doc)] pub trait OwnedCopyableVector<T:Copy> { - fn push_all(&mut self, rhs: &const [T]); + fn push_all(&mut self, rhs: &[T]); fn grow(&mut self, n: uint, initval: &T); fn grow_set(&mut self, index: uint, initval: &T, val: T); } impl<T:Copy> OwnedCopyableVector<T> for ~[T] { + /// Iterates over the slice `rhs`, copies each element, and then appends it to + /// the vector provided `v`. The `rhs` vector is traversed in-order. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let mut a = ~[1]; + /// a.push_all([2, 3, 4]); + /// assert!(a == ~[1, 2, 3, 4]); + /// ~~~ #[inline] - fn push_all(&mut self, rhs: &const [T]) { - push_all(self, rhs); + fn push_all(&mut self, rhs: &[T]) { + let new_len = self.len() + rhs.len(); + self.reserve(new_len); + + for uint::range(0u, rhs.len()) |i| { + self.push(unsafe { raw::get(rhs, i) }) + } } - #[inline] + /** + * Expands a vector in place, initializing the new elements to a given value + * + * # Arguments + * + * * n - The number of elements to add + * * initval - The value for the new elements + */ fn grow(&mut self, n: uint, initval: &T) { - grow(self, n, initval); + let new_len = self.len() + n; + self.reserve_at_least(new_len); + let mut i: uint = 0u; + + while i < n { + self.push(copy *initval); + i += 1u; + } } - #[inline] + /** + * Sets the value of a vector element at a given index, growing the vector as + * needed + * + * Sets the element at position `index` to `val`. If `index` is past the end + * of the vector, expands the vector by replicating `initval` to fill the + * intervening space. + */ fn grow_set(&mut self, index: uint, initval: &T, val: T) { - grow_set(self, index, initval, val); + let l = self.len(); + if index >= l { self.grow(index - l + 1u, initval); } + self[index] = val; } } #[allow(missing_doc)] -trait OwnedEqVector<T:Eq> { +pub trait OwnedEqVector<T:Eq> { fn dedup(&mut self); } impl<T:Eq> OwnedEqVector<T> for ~[T] { - #[inline] - fn dedup(&mut self) { - dedup(self) + /** + * Remove consecutive repeated elements from a vector; if the vector is + * sorted, this removes all duplicates. + */ + pub fn dedup(&mut self) { + unsafe { + if self.len() == 0 { return; } + let mut last_written = 0; + let mut next_to_read = 1; + do as_mut_buf(*self) |p, ln| { + // last_written < next_to_read <= ln + while next_to_read < ln { + // last_written < next_to_read < ln + if *ptr::mut_offset(p, next_to_read) == + *ptr::mut_offset(p, last_written) { + ptr::replace_ptr(ptr::mut_offset(p, next_to_read), + intrinsics::uninit()); + } else { + last_written += 1; + // last_written <= next_to_read < ln + if next_to_read != last_written { + ptr::swap_ptr(ptr::mut_offset(p, last_written), + ptr::mut_offset(p, next_to_read)); + } + } + // last_written <= next_to_read < ln + next_to_read += 1; + // last_written < next_to_read <= ln + } + } + // last_written < next_to_read == ln + raw::set_len(self, last_written + 1); + } } } @@ -2178,14 +1689,41 @@ pub trait MutableVector<'self, T> { fn mut_iter(self) -> VecMutIterator<'self, T>; fn mut_rev_iter(self) -> VecMutRevIterator<'self, T>; + fn swap(self, a: uint, b: uint); + + fn reverse(self); + + /** + * Consumes `src` and moves as many elements as it can into `self` + * from the range [start,end). + * + * Returns the number of elements copied (the shorter of self.len() + * and end - start). + * + * # Arguments + * + * * src - A mutable vector of `T` + * * start - The index into `src` to start copying from + * * end - The index into `str` to stop copying from + */ + fn move_from(self, src: ~[T], start: uint, end: uint) -> uint; + unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T; unsafe fn unsafe_set(&self, index: uint, val: T); } impl<'self,T> MutableVector<'self, T> for &'self mut [T] { + /// Return a slice that points into another slice. #[inline] fn mut_slice(self, start: uint, end: uint) -> &'self mut [T] { - mut_slice(self, start, end) + assert!(start <= end); + assert!(end <= self.len()); + do as_mut_buf(self) |p, _len| { + unsafe { + transmute((ptr::mut_offset(p, start), + (end - start) * sys::nonzero_size_of::<T>())) + } + } } #[inline] @@ -2206,6 +1744,42 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { } } + /** + * Swaps two elements in a vector + * + * # Arguments + * + * * a - The index of the first element + * * b - The index of the second element + */ + fn swap(self, a: uint, b: uint) { + unsafe { + // Can't take two mutable loans from one vector, so instead just cast + // them to their raw pointers to do the swap + let pa: *mut T = &mut self[a]; + let pb: *mut T = &mut self[b]; + ptr::swap_ptr(pa, pb); + } + } + + /// Reverse the order of elements in a vector, in place + fn reverse(self) { + let mut i: uint = 0; + let ln = self.len(); + while i < ln / 2 { + self.swap(i, ln - i - 1); + i += 1; + } + } + + #[inline] + fn move_from(self, mut src: ~[T], start: uint, end: uint) -> uint { + for self.mut_iter().zip(src.mut_slice(start, end).mut_iter()).advance |(a, b)| { + util::swap(a, b); + } + cmp::min(self.len(), end-start) + } + #[inline] unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T { let pair_ptr: &(*mut T, uint) = transmute(self); @@ -2219,6 +1793,23 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { } } +/// Trait for ~[T] where T is Cloneable +pub trait MutableCloneableVector<T> { + /// Copies as many elements from `src` as it can into `self` + /// (the shorter of self.len() and src.len()). Returns the number of elements copied. + fn copy_from(self, &[T]) -> uint; +} + +impl<'self, T:Clone> MutableCloneableVector<T> for &'self mut [T] { + #[inline] + fn copy_from(self, src: &[T]) -> uint { + for self.mut_iter().zip(src.iter()).advance |(a, b)| { + *a = b.clone(); + } + cmp::min(self.len(), src.len()) + } +} + /** * Constructs a vector from an unsafe pointer to a buffer * @@ -2249,7 +1840,7 @@ pub mod raw { use ptr; use sys; use unstable::intrinsics; - use vec::{UnboxedVecRepr, as_const_buf, as_mut_buf, with_capacity}; + use vec::{UnboxedVecRepr, as_imm_buf, as_mut_buf, with_capacity}; use util; /// The internal representation of a (boxed) vector @@ -2299,15 +1890,6 @@ pub mod raw { /** see `to_ptr()` */ #[inline] - pub fn to_const_ptr<T>(v: &const [T]) -> *const T { - unsafe { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) - } - } - - /** see `to_ptr()` */ - #[inline] pub fn to_mut_ptr<T>(v: &mut [T]) -> *mut T { unsafe { let repr: **SliceRepr = transmute(&v); @@ -2345,8 +1927,8 @@ pub mod raw { * Unchecked vector indexing. */ #[inline] - pub unsafe fn get<T:Copy>(v: &const [T], i: uint) -> T { - as_const_buf(v, |p, _len| copy *ptr::const_offset(p, i)) + pub unsafe fn get<T:Copy>(v: &[T], i: uint) -> T { + as_imm_buf(v, |p, _len| copy *ptr::offset(p, i)) } /** @@ -2388,13 +1970,13 @@ pub mod raw { * may overlap. */ #[inline] - pub unsafe fn copy_memory<T>(dst: &mut [T], src: &const [T], + pub unsafe fn copy_memory<T>(dst: &mut [T], src: &[T], count: uint) { assert!(dst.len() >= count); assert!(src.len() >= count); do as_mut_buf(dst) |p_dst, _len_dst| { - do as_const_buf(src) |p_src, _len_src| { + do as_imm_buf(src) |p_src, _len_src| { ptr::copy_memory(p_dst, p_src, count) } } @@ -2407,6 +1989,22 @@ pub mod bytes { use uint; use vec::raw; use vec; + use ptr; + + /// A trait for operations on mutable operations on `[u8]` + pub trait MutableByteVector { + /// Sets all bytes of the receiver to the given value. + pub fn set_memory(self, value: u8); + } + + impl<'self> MutableByteVector for &'self mut [u8] { + #[inline] + fn set_memory(self, value: u8) { + do vec::as_mut_buf(self) |p, len| { + unsafe { ptr::set_memory(p, value, len) }; + } + } + } /// Bytewise string comparison pub fn memcmp(a: &~[u8], b: &~[u8]) -> int { @@ -2454,174 +2052,16 @@ pub mod bytes { * may overlap. */ #[inline] - pub fn copy_memory(dst: &mut [u8], src: &const [u8], count: uint) { + pub fn copy_memory(dst: &mut [u8], src: &[u8], count: uint) { // Bound checks are done at vec::raw::copy_memory. unsafe { vec::raw::copy_memory(dst, src, count) } } } -// ___________________________________________________________________________ -// ITERATION TRAIT METHODS - -impl<'self,A> old_iter::BaseIter<A> for &'self [A] { - #[inline] - fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) -> bool { - each(*self, blk) - } - #[inline] - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - -// FIXME(#4148): This should be redundant -impl<A> old_iter::BaseIter<A> for ~[A] { - #[inline] - fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) -> bool { - each(*self, blk) - } - #[inline] - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - -// FIXME(#4148): This should be redundant -impl<A> old_iter::BaseIter<A> for @[A] { - #[inline] - fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) -> bool { - each(*self, blk) - } - #[inline] - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - -impl<'self,A> old_iter::ExtendedIter<A> for &'self [A] { - pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool { - old_iter::eachi(self, blk) - } - pub fn all(&self, blk: &fn(&A) -> bool) -> bool { - old_iter::all(self, blk) - } - pub fn any(&self, blk: &fn(&A) -> bool) -> bool { - old_iter::any(self, blk) - } - pub fn foldl<B>(&self, b0: B, blk: &fn(&B, &A) -> B) -> B { - old_iter::foldl(self, b0, blk) - } - pub fn position(&self, f: &fn(&A) -> bool) -> Option<uint> { - old_iter::position(self, f) - } - fn map_to_vec<B>(&self, op: &fn(&A) -> B) -> ~[B] { - old_iter::map_to_vec(self, op) - } - fn flat_map_to_vec<B,IB:BaseIter<B>>(&self, op: &fn(&A) -> IB) - -> ~[B] { - old_iter::flat_map_to_vec(self, op) - } -} - -// FIXME(#4148): This should be redundant -impl<A> old_iter::ExtendedIter<A> for ~[A] { - pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool { - old_iter::eachi(self, blk) - } - pub fn all(&self, blk: &fn(&A) -> bool) -> bool { - old_iter::all(self, blk) - } - pub fn any(&self, blk: &fn(&A) -> bool) -> bool { - old_iter::any(self, blk) - } - pub fn foldl<B>(&self, b0: B, blk: &fn(&B, &A) -> B) -> B { - old_iter::foldl(self, b0, blk) - } - pub fn position(&self, f: &fn(&A) -> bool) -> Option<uint> { - old_iter::position(self, f) - } - fn map_to_vec<B>(&self, op: &fn(&A) -> B) -> ~[B] { - old_iter::map_to_vec(self, op) - } - fn flat_map_to_vec<B,IB:BaseIter<B>>(&self, op: &fn(&A) -> IB) - -> ~[B] { - old_iter::flat_map_to_vec(self, op) - } -} - -// FIXME(#4148): This should be redundant -impl<A> old_iter::ExtendedIter<A> for @[A] { - pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool { - old_iter::eachi(self, blk) - } - pub fn all(&self, blk: &fn(&A) -> bool) -> bool { - old_iter::all(self, blk) - } - pub fn any(&self, blk: &fn(&A) -> bool) -> bool { - old_iter::any(self, blk) - } - pub fn foldl<B>(&self, b0: B, blk: &fn(&B, &A) -> B) -> B { - old_iter::foldl(self, b0, blk) - } - pub fn position(&self, f: &fn(&A) -> bool) -> Option<uint> { - old_iter::position(self, f) - } - fn map_to_vec<B>(&self, op: &fn(&A) -> B) -> ~[B] { - old_iter::map_to_vec(self, op) - } - fn flat_map_to_vec<B,IB:BaseIter<B>>(&self, op: &fn(&A) -> IB) - -> ~[B] { - old_iter::flat_map_to_vec(self, op) - } -} - -impl<'self,A:Eq> old_iter::EqIter<A> for &'self [A] { - pub fn contains(&self, x: &A) -> bool { old_iter::contains(self, x) } - pub fn count(&self, x: &A) -> uint { old_iter::count(self, x) } -} - -// FIXME(#4148): This should be redundant -impl<A:Eq> old_iter::EqIter<A> for ~[A] { - pub fn contains(&self, x: &A) -> bool { old_iter::contains(self, x) } - pub fn count(&self, x: &A) -> uint { old_iter::count(self, x) } -} - -// FIXME(#4148): This should be redundant -impl<A:Eq> old_iter::EqIter<A> for @[A] { - pub fn contains(&self, x: &A) -> bool { old_iter::contains(self, x) } - pub fn count(&self, x: &A) -> uint { old_iter::count(self, x) } -} - -impl<'self,A:Copy> old_iter::CopyableIter<A> for &'self [A] { - fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A] { - old_iter::filter_to_vec(self, pred) - } - fn to_vec(&self) -> ~[A] { old_iter::to_vec(self) } - pub fn find(&self, f: &fn(&A) -> bool) -> Option<A> { - old_iter::find(self, f) - } -} - -// FIXME(#4148): This should be redundant -impl<A:Copy> old_iter::CopyableIter<A> for ~[A] { - fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A] { - old_iter::filter_to_vec(self, pred) - } - fn to_vec(&self) -> ~[A] { old_iter::to_vec(self) } - pub fn find(&self, f: &fn(&A) -> bool) -> Option<A> { - old_iter::find(self, f) - } -} - -// FIXME(#4148): This should be redundant -impl<A:Copy> old_iter::CopyableIter<A> for @[A] { - fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A] { - old_iter::filter_to_vec(self, pred) - } - fn to_vec(&self) -> ~[A] { old_iter::to_vec(self) } - pub fn find(&self, f: &fn(&A) -> bool) -> Option<A> { - old_iter::find(self, f) - } -} - impl<A:Clone> Clone for ~[A] { #[inline] fn clone(&self) -> ~[A] { - self.map(|item| item.clone()) + self.iter().transform(|item| item.clone()).collect() } } @@ -2665,6 +2105,12 @@ macro_rules! iterator { } } } + + #[inline] + fn size_hint(&self) -> (Option<uint>, Option<uint>) { + let exact = Some(((self.end as uint) - (self.ptr as uint)) / size_of::<$elem>()); + (exact, exact) + } } } } @@ -2714,6 +2160,31 @@ impl<T> FromIter<T> for ~[T]{ } } +#[cfg(stage0)] +impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] { + pub fn from_iterator(iterator: &mut T) -> ~[A] { + let mut xs = ~[]; + for iterator.advance |x| { + xs.push(x); + } + xs + } +} + + +#[cfg(not(stage0))] +impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] { + pub fn from_iterator(iterator: &mut T) -> ~[A] { + let (lower, _) = iterator.size_hint(); + let mut xs = with_capacity(lower.get_or_zero()); + for iterator.advance |x| { + xs.push(x); + } + xs + } +} + + #[cfg(test)] mod tests { use option::{None, Option, Some}; @@ -2942,7 +2413,7 @@ mod tests { fn test_slice() { // Test fixed length vector. let vec_fixed = [1, 2, 3, 4]; - let v_a = slice(vec_fixed, 1u, vec_fixed.len()).to_vec(); + let v_a = vec_fixed.slice(1u, vec_fixed.len()).to_owned(); assert_eq!(v_a.len(), 3u); assert_eq!(v_a[0], 2); assert_eq!(v_a[1], 3); @@ -2950,14 +2421,14 @@ mod tests { // Test on stack. let vec_stack = &[1, 2, 3]; - let v_b = slice(vec_stack, 1u, 3u).to_vec(); + let v_b = vec_stack.slice(1u, 3u).to_owned(); assert_eq!(v_b.len(), 2u); assert_eq!(v_b[0], 2); assert_eq!(v_b[1], 3); // Test on managed heap. let vec_managed = @[1, 2, 3, 4, 5]; - let v_c = slice(vec_managed, 0u, 3u).to_vec(); + let v_c = vec_managed.slice(0u, 3u).to_owned(); assert_eq!(v_c.len(), 3u); assert_eq!(v_c[0], 1); assert_eq!(v_c[1], 2); @@ -2965,7 +2436,7 @@ mod tests { // Test on exchange heap. let vec_unique = ~[1, 2, 3, 4, 5, 6]; - let v_d = slice(vec_unique, 1u, 6u).to_vec(); + let v_d = vec_unique.slice(1u, 6u).to_owned(); assert_eq!(v_d.len(), 5u); assert_eq!(v_d[0], 2); assert_eq!(v_d[1], 3); @@ -3137,16 +2608,16 @@ mod tests { #[test] fn test_map() { // Test on-stack map. - let mut v = ~[1u, 2u, 3u]; - let mut w = map(v, square_ref); + let v = &[1u, 2u, 3u]; + let mut w = v.map(square_ref); assert_eq!(w.len(), 3u); assert_eq!(w[0], 1u); assert_eq!(w[1], 4u); assert_eq!(w[2], 9u); // Test on-heap map. - v = ~[1u, 2u, 3u, 4u, 5u]; - w = map(v, square_ref); + let v = ~[1u, 2u, 3u, 4u, 5u]; + w = v.map(square_ref); assert_eq!(w.len(), 5u); assert_eq!(w[0], 1u); assert_eq!(w[1], 4u); @@ -3156,17 +2627,6 @@ mod tests { } #[test] - fn test_map_zip() { - fn times(x: &int, y: &int) -> int { *x * *y } - let f = times; - let v0 = ~[1, 2, 3, 4, 5]; - let v1 = ~[5, 4, 3, 2, 1]; - let u = map_zip::<int, int, int>(v0, v1, f); - let mut i = 0; - while i < 5 { assert!(v0[i] * v1[i] == u[i]); i += 1; } - } - - #[test] fn test_filter_mapped() { // Test on-stack filter-map. let mut v = ~[1u, 2u, 3u]; @@ -3197,7 +2657,7 @@ mod tests { let mix: ~[int] = ~[9, 2, 6, 7, 1, 0, 0, 3]; let mix_dest: ~[int] = ~[1, 3, 0, 0]; assert!(filter_mapped(all_even, halve) == - map(all_even, halve_for_sure)); + all_even.map(halve_for_sure)); assert_eq!(filter_mapped(all_odd1, halve), ~[]); assert_eq!(filter_mapped(all_odd2, halve), ~[]); assert_eq!(filter_mapped(mix, halve), mix_dest); @@ -3235,7 +2695,7 @@ mod tests { let mix: ~[int] = ~[9, 2, 6, 7, 1, 0, 0, 3]; let mix_dest: ~[int] = ~[1, 3, 0, 0]; assert!(filter_map(all_even, halve) == - map(all_even0, halve_for_sure)); + all_even0.map(halve_for_sure)); assert_eq!(filter_map(all_odd1, halve), ~[]); assert_eq!(filter_map(all_odd2, halve), ~[]); assert_eq!(filter_map(mix, halve), mix_dest); @@ -3255,47 +2715,6 @@ mod tests { } #[test] - fn test_each_empty() { - for each::<int>([]) |_v| { - fail!(); // should never be executed - } - } - - #[test] - fn test_each_nonempty() { - let mut i = 0; - for each([1, 2, 3]) |v| { - i += *v; - } - assert_eq!(i, 6); - } - - #[test] - fn test_eachi() { - let mut i = 0; - for eachi([1, 2, 3]) |j, v| { - if i == 0 { assert!(*v == 1); } - assert_eq!(j + 1u, *v as uint); - i += *v; - } - assert_eq!(i, 6); - } - - #[test] - fn test_each_ret_len0() { - let a0 : [int, .. 0] = []; - assert_eq!(each(a0, |_p| fail!()), true); - } - - #[test] - fn test_each_ret_len1() { - let a1 = [17]; - assert_eq!(each(a1, |_p| true), true); - assert_eq!(each(a1, |_p| false), false); - } - - - #[test] fn test_each_permutation() { let mut results: ~[~[int]]; @@ -3337,218 +2756,68 @@ mod tests { #[test] fn test_position_elem() { - assert!(position_elem([], &1).is_none()); + assert!([].position_elem(&1).is_none()); let v1 = ~[1, 2, 3, 3, 2, 5]; - assert_eq!(position_elem(v1, &1), Some(0u)); - assert_eq!(position_elem(v1, &2), Some(1u)); - assert_eq!(position_elem(v1, &5), Some(5u)); - assert!(position_elem(v1, &4).is_none()); - } - - #[test] - fn test_position() { - fn less_than_three(i: &int) -> bool { *i < 3 } - fn is_eighteen(i: &int) -> bool { *i == 18 } - - assert!(position([], less_than_three).is_none()); - - let v1 = ~[5, 4, 3, 2, 1]; - assert_eq!(position(v1, less_than_three), Some(3u)); - assert!(position(v1, is_eighteen).is_none()); - } - - #[test] - fn test_position_between() { - assert!(position_between([], 0u, 0u, f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert!(position_between(v, 0u, 0u, f).is_none()); - assert!(position_between(v, 0u, 1u, f).is_none()); - assert_eq!(position_between(v, 0u, 2u, f), Some(1u)); - assert_eq!(position_between(v, 0u, 3u, f), Some(1u)); - assert_eq!(position_between(v, 0u, 4u, f), Some(1u)); - - assert!(position_between(v, 1u, 1u, f).is_none()); - assert_eq!(position_between(v, 1u, 2u, f), Some(1u)); - assert_eq!(position_between(v, 1u, 3u, f), Some(1u)); - assert_eq!(position_between(v, 1u, 4u, f), Some(1u)); - - assert!(position_between(v, 2u, 2u, f).is_none()); - assert!(position_between(v, 2u, 3u, f).is_none()); - assert_eq!(position_between(v, 2u, 4u, f), Some(3u)); - - assert!(position_between(v, 3u, 3u, f).is_none()); - assert_eq!(position_between(v, 3u, 4u, f), Some(3u)); - - assert!(position_between(v, 4u, 4u, f).is_none()); - } - - #[test] - fn test_find() { - assert!(find([], f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert_eq!(find(v, f), Some((1, 'b'))); - assert!(find(v, g).is_none()); - } - - #[test] - fn test_find_between() { - assert!(find_between([], 0u, 0u, f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert!(find_between(v, 0u, 0u, f).is_none()); - assert!(find_between(v, 0u, 1u, f).is_none()); - assert_eq!(find_between(v, 0u, 2u, f), Some((1, 'b'))); - assert_eq!(find_between(v, 0u, 3u, f), Some((1, 'b'))); - assert_eq!(find_between(v, 0u, 4u, f), Some((1, 'b'))); - - assert!(find_between(v, 1u, 1u, f).is_none()); - assert_eq!(find_between(v, 1u, 2u, f), Some((1, 'b'))); - assert_eq!(find_between(v, 1u, 3u, f), Some((1, 'b'))); - assert_eq!(find_between(v, 1u, 4u, f), Some((1, 'b'))); - - assert!(find_between(v, 2u, 2u, f).is_none()); - assert!(find_between(v, 2u, 3u, f).is_none()); - assert_eq!(find_between(v, 2u, 4u, f), Some((3, 'b'))); - - assert!(find_between(v, 3u, 3u, f).is_none()); - assert_eq!(find_between(v, 3u, 4u, f), Some((3, 'b'))); - - assert!(find_between(v, 4u, 4u, f).is_none()); + assert_eq!(v1.position_elem(&1), Some(0u)); + assert_eq!(v1.position_elem(&2), Some(1u)); + assert_eq!(v1.position_elem(&5), Some(5u)); + assert!(v1.position_elem(&4).is_none()); } #[test] fn test_rposition() { - assert!(find([], f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert_eq!(position(v, f), Some(1u)); - assert!(position(v, g).is_none()); - } - - #[test] - fn test_rposition_between() { - assert!(rposition_between([], 0u, 0u, f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert!(rposition_between(v, 0u, 0u, f).is_none()); - assert!(rposition_between(v, 0u, 1u, f).is_none()); - assert_eq!(rposition_between(v, 0u, 2u, f), Some(1u)); - assert_eq!(rposition_between(v, 0u, 3u, f), Some(1u)); - assert_eq!(rposition_between(v, 0u, 4u, f), Some(3u)); - - assert!(rposition_between(v, 1u, 1u, f).is_none()); - assert_eq!(rposition_between(v, 1u, 2u, f), Some(1u)); - assert_eq!(rposition_between(v, 1u, 3u, f), Some(1u)); - assert_eq!(rposition_between(v, 1u, 4u, f), Some(3u)); - - assert!(rposition_between(v, 2u, 2u, f).is_none()); - assert!(rposition_between(v, 2u, 3u, f).is_none()); - assert_eq!(rposition_between(v, 2u, 4u, f), Some(3u)); - - assert!(rposition_between(v, 3u, 3u, f).is_none()); - assert_eq!(rposition_between(v, 3u, 4u, f), Some(3u)); - - assert!(rposition_between(v, 4u, 4u, f).is_none()); - } - - #[test] - fn test_rfind() { - assert!(rfind([], f).is_none()); - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - assert_eq!(rfind(v, f), Some((3, 'b'))); - assert!(rfind(v, g).is_none()); - } - - #[test] - fn test_rfind_between() { - assert!(rfind_between([], 0u, 0u, f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert!(rfind_between(v, 0u, 0u, f).is_none()); - assert!(rfind_between(v, 0u, 1u, f).is_none()); - assert_eq!(rfind_between(v, 0u, 2u, f), Some((1, 'b'))); - assert_eq!(rfind_between(v, 0u, 3u, f), Some((1, 'b'))); - assert_eq!(rfind_between(v, 0u, 4u, f), Some((3, 'b'))); - - assert!(rfind_between(v, 1u, 1u, f).is_none()); - assert_eq!(rfind_between(v, 1u, 2u, f), Some((1, 'b'))); - assert_eq!(rfind_between(v, 1u, 3u, f), Some((1, 'b'))); - assert_eq!(rfind_between(v, 1u, 4u, f), Some((3, 'b'))); - - assert!(rfind_between(v, 2u, 2u, f).is_none()); - assert!(rfind_between(v, 2u, 3u, f).is_none()); - assert_eq!(rfind_between(v, 2u, 4u, f), Some((3, 'b'))); - - assert!(rfind_between(v, 3u, 3u, f).is_none()); - assert_eq!(rfind_between(v, 3u, 4u, f), Some((3, 'b'))); - - assert!(rfind_between(v, 4u, 4u, f).is_none()); + assert_eq!(v.rposition(f), Some(3u)); + assert!(v.rposition(g).is_none()); } #[test] fn test_bsearch_elem() { - assert_eq!(bsearch_elem([1,2,3,4,5], &5), Some(4)); - assert_eq!(bsearch_elem([1,2,3,4,5], &4), Some(3)); - assert_eq!(bsearch_elem([1,2,3,4,5], &3), Some(2)); - assert_eq!(bsearch_elem([1,2,3,4,5], &2), Some(1)); - assert_eq!(bsearch_elem([1,2,3,4,5], &1), Some(0)); + assert_eq!([1,2,3,4,5].bsearch_elem(&5), Some(4)); + assert_eq!([1,2,3,4,5].bsearch_elem(&4), Some(3)); + assert_eq!([1,2,3,4,5].bsearch_elem(&3), Some(2)); + assert_eq!([1,2,3,4,5].bsearch_elem(&2), Some(1)); + assert_eq!([1,2,3,4,5].bsearch_elem(&1), Some(0)); - assert_eq!(bsearch_elem([2,4,6,8,10], &1), None); - assert_eq!(bsearch_elem([2,4,6,8,10], &5), None); - assert_eq!(bsearch_elem([2,4,6,8,10], &4), Some(1)); - assert_eq!(bsearch_elem([2,4,6,8,10], &10), Some(4)); + assert_eq!([2,4,6,8,10].bsearch_elem(&1), None); + assert_eq!([2,4,6,8,10].bsearch_elem(&5), None); + assert_eq!([2,4,6,8,10].bsearch_elem(&4), Some(1)); + assert_eq!([2,4,6,8,10].bsearch_elem(&10), Some(4)); - assert_eq!(bsearch_elem([2,4,6,8], &1), None); - assert_eq!(bsearch_elem([2,4,6,8], &5), None); - assert_eq!(bsearch_elem([2,4,6,8], &4), Some(1)); - assert_eq!(bsearch_elem([2,4,6,8], &8), Some(3)); + assert_eq!([2,4,6,8].bsearch_elem(&1), None); + assert_eq!([2,4,6,8].bsearch_elem(&5), None); + assert_eq!([2,4,6,8].bsearch_elem(&4), Some(1)); + assert_eq!([2,4,6,8].bsearch_elem(&8), Some(3)); - assert_eq!(bsearch_elem([2,4,6], &1), None); - assert_eq!(bsearch_elem([2,4,6], &5), None); - assert_eq!(bsearch_elem([2,4,6], &4), Some(1)); - assert_eq!(bsearch_elem([2,4,6], &6), Some(2)); + assert_eq!([2,4,6].bsearch_elem(&1), None); + assert_eq!([2,4,6].bsearch_elem(&5), None); + assert_eq!([2,4,6].bsearch_elem(&4), Some(1)); + assert_eq!([2,4,6].bsearch_elem(&6), Some(2)); - assert_eq!(bsearch_elem([2,4], &1), None); - assert_eq!(bsearch_elem([2,4], &5), None); - assert_eq!(bsearch_elem([2,4], &2), Some(0)); - assert_eq!(bsearch_elem([2,4], &4), Some(1)); + assert_eq!([2,4].bsearch_elem(&1), None); + assert_eq!([2,4].bsearch_elem(&5), None); + assert_eq!([2,4].bsearch_elem(&2), Some(0)); + assert_eq!([2,4].bsearch_elem(&4), Some(1)); - assert_eq!(bsearch_elem([2], &1), None); - assert_eq!(bsearch_elem([2], &5), None); - assert_eq!(bsearch_elem([2], &2), Some(0)); + assert_eq!([2].bsearch_elem(&1), None); + assert_eq!([2].bsearch_elem(&5), None); + assert_eq!([2].bsearch_elem(&2), Some(0)); - assert_eq!(bsearch_elem([], &1), None); - assert_eq!(bsearch_elem([], &5), None); + assert_eq!([].bsearch_elem(&1), None); + assert_eq!([].bsearch_elem(&5), None); - assert!(bsearch_elem([1,1,1,1,1], &1) != None); - assert!(bsearch_elem([1,1,1,1,2], &1) != None); - assert!(bsearch_elem([1,1,1,2,2], &1) != None); - assert!(bsearch_elem([1,1,2,2,2], &1) != None); - assert_eq!(bsearch_elem([1,2,2,2,2], &1), Some(0)); + assert!([1,1,1,1,1].bsearch_elem(&1) != None); + assert!([1,1,1,1,2].bsearch_elem(&1) != None); + assert!([1,1,1,2,2].bsearch_elem(&1) != None); + assert!([1,1,2,2,2].bsearch_elem(&1) != None); + assert_eq!([1,2,2,2,2].bsearch_elem(&1), Some(0)); - assert_eq!(bsearch_elem([1,2,3,4,5], &6), None); - assert_eq!(bsearch_elem([1,2,3,4,5], &0), None); + assert_eq!([1,2,3,4,5].bsearch_elem(&6), None); + assert_eq!([1,2,3,4,5].bsearch_elem(&0), None); } #[test] @@ -3556,7 +2825,7 @@ mod tests { let mut v: ~[int] = ~[10, 20]; assert_eq!(v[0], 10); assert_eq!(v[1], 20); - reverse(v); + v.reverse(); assert_eq!(v[0], 20); assert_eq!(v[1], 10); let v2 = reversed::<int>([10, 20]); @@ -3569,7 +2838,7 @@ mod tests { let v4 = reversed::<int>([]); assert_eq!(v4, ~[]); let mut v3: ~[int] = ~[]; - reverse::<int>(v3); + v3.reverse(); } #[test] @@ -3625,11 +2894,10 @@ mod tests { #[test] fn test_partition() { - // FIXME (#4355 maybe): using v.partition here crashes - assert_eq!(partition(~[], |x: &int| *x < 3), (~[], ~[])); - assert_eq!(partition(~[1, 2, 3], |x: &int| *x < 4), (~[1, 2, 3], ~[])); - assert_eq!(partition(~[1, 2, 3], |x: &int| *x < 2), (~[1], ~[2, 3])); - assert_eq!(partition(~[1, 2, 3], |x: &int| *x < 0), (~[], ~[1, 2, 3])); + assert_eq!((~[]).partition(|x: &int| *x < 3), (~[], ~[])); + assert_eq!((~[1, 2, 3]).partition(|x: &int| *x < 4), (~[1, 2, 3], ~[])); + assert_eq!((~[1, 2, 3]).partition(|x: &int| *x < 2), (~[1], ~[2, 3])); + assert_eq!((~[1, 2, 3]).partition(|x: &int| *x < 0), (~[], ~[1, 2, 3])); } #[test] @@ -3749,11 +3017,11 @@ mod tests { #[test] fn test_capacity() { let mut v = ~[0u64]; - reserve(&mut v, 10u); - assert_eq!(capacity(&v), 10u); + v.reserve(10u); + assert_eq!(v.capacity(), 10u); let mut v = ~[0u32]; - reserve(&mut v, 10u); - assert_eq!(capacity(&v), 10u); + v.reserve(10u); + assert_eq!(v.capacity(), 10u); } #[test] @@ -3959,7 +3227,7 @@ mod tests { fn test_map_fail() { let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; let mut i = 0; - do map(v) |_elt| { + do v.map |_elt| { if i == 2 { fail!() } @@ -3986,41 +3254,10 @@ mod tests { #[test] #[ignore(windows)] #[should_fail] - fn test_mapi_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do mapi(v) |_i, _elt| { - if i == 2 { - fail!() - } - i += 0; - ~[(~0, @0)] - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] fn test_flat_map_fail() { let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; let mut i = 0; - do map(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - ~[(~0, @0)] - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_map_zip_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do map_zip(v, v) |_elt1, _elt2| { + do flat_map(v) |_elt| { if i == 2 { fail!() } @@ -4064,71 +3301,10 @@ mod tests { #[test] #[ignore(windows)] #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_find_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do find(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_position_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do position(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] fn test_rposition_fail() { let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; let mut i = 0; - do rposition(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_each_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do each(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_eachi_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do eachi(v) |_i, _elt| { + do v.rposition |_elt| { if i == 2 { fail!() } @@ -4163,16 +3339,6 @@ mod tests { } #[test] - #[ignore(windows)] - #[should_fail] - fn test_as_const_buf_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - do as_const_buf(v) |_buf, _i| { - fail!() - } - } - - #[test] #[ignore(cfg(windows))] #[should_fail] fn test_as_mut_buf_fail() { @@ -4206,13 +3372,19 @@ mod tests { fn test_iterator() { use iterator::*; let xs = [1, 2, 5, 10, 11]; - let ys = [1, 2, 5, 10, 11, 19]; let mut it = xs.iter(); - let mut i = 0; - for it.advance |&x| { - assert_eq!(x, ys[i]); - i += 1; - } + assert_eq!(it.size_hint(), (Some(5), Some(5))); + assert_eq!(it.next().unwrap(), &1); + assert_eq!(it.size_hint(), (Some(4), Some(4))); + assert_eq!(it.next().unwrap(), &2); + assert_eq!(it.size_hint(), (Some(3), Some(3))); + assert_eq!(it.next().unwrap(), &5); + assert_eq!(it.size_hint(), (Some(2), Some(2))); + assert_eq!(it.next().unwrap(), &10); + assert_eq!(it.size_hint(), (Some(1), Some(1))); + assert_eq!(it.next().unwrap(), &11); + assert_eq!(it.size_hint(), (Some(0), Some(0))); + assert!(it.next().is_none()); } #[test] @@ -4250,9 +3422,41 @@ mod tests { } #[test] + fn test_move_from() { + let mut a = [1,2,3,4,5]; + let b = ~[6,7,8]; + assert_eq!(a.move_from(b, 0, 3), 3); + assert_eq!(a, [6,7,8,4,5]); + let mut a = [7,2,8,1]; + let b = ~[3,1,4,1,5,9]; + assert_eq!(a.move_from(b, 0, 6), 4); + assert_eq!(a, [3,1,4,1]); + let mut a = [1,2,3,4]; + let b = ~[5,6,7,8,9,0]; + assert_eq!(a.move_from(b, 2, 3), 1); + assert_eq!(a, [7,2,3,4]); + let mut a = [1,2,3,4,5]; + let b = ~[5,6,7,8,9,0]; + assert_eq!(a.mut_slice(2,4).move_from(b,1,6), 2); + assert_eq!(a, [1,2,6,7,5]); + } + + #[test] + fn test_copy_from() { + let mut a = [1,2,3,4,5]; + let b = [6,7,8]; + assert_eq!(a.copy_from(b), 3); + assert_eq!(a, [6,7,8,4,5]); + let mut c = [7,2,8,1]; + let d = [3,1,4,1,5,9]; + assert_eq!(c.copy_from(d), 4); + assert_eq!(c, [3,1,4,1]); + } + + #[test] fn test_reverse_part() { let mut values = [1,2,3,4,5]; - reverse_part(values,1,4); + values.mut_slice(1, 4).reverse(); assert_eq!(values, [1,4,3,2,5]); } @@ -4300,15 +3504,25 @@ mod tests { fn test_vec_zero() { use num::Zero; macro_rules! t ( - ($ty:ty) => { + ($ty:ty) => {{ let v: $ty = Zero::zero(); assert!(v.is_empty()); assert!(v.is_zero()); - } + }} ); t!(&[int]); t!(@[int]); t!(~[int]); } + + #[test] + fn test_bytes_set_memory() { + use vec::bytes::MutableByteVector; + let mut values = [1u8,2,3,4,5]; + values.mut_slice(0,5).set_memory(0xAB); + assert_eq!(values, [0xAB, 0xAB, 0xAB, 0xAB, 0xAB]); + values.mut_slice(2,4).set_memory(0xFF); + assert_eq!(values, [0xAB, 0xAB, 0xFF, 0xFF, 0xAB]); + } } diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 53729dbd115..fadd2faf0eb 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - -use core::to_bytes; +use std::to_bytes; #[deriving(Eq)] pub enum Abi { @@ -87,7 +85,7 @@ fn each_abi(op: &fn(abi: Abi) -> bool) -> bool { * Iterates through each of the defined ABIs. */ - AbiDatas.each(|abi_data| op(abi_data.abi)) + AbiDatas.iter().advance(|abi_data| op(abi_data.abi)) } pub fn lookup(name: &str) -> Option<Abi> { @@ -211,9 +209,9 @@ impl AbiSet { let mut abis = ~[]; for self.each |abi| { abis.push(abi); } - for abis.eachi |i, abi| { + for abis.iter().enumerate().advance |(i, abi)| { let data = abi.data(); - for abis.slice(0, i).each |other_abi| { + for abis.slice(0, i).iter().advance |other_abi| { let other_data = other_abi.data(); debug!("abis=(%?,%?) datas=(%?,%?)", abi, data.abi_arch, @@ -374,7 +372,7 @@ fn abi_to_str_rust() { #[test] fn indices_are_correct() { - for AbiDatas.eachi |i, abi_data| { + for AbiDatas.iter().enumerate().advance |(i, abi_data)| { assert!(i == abi_data.abi.index()); } @@ -389,7 +387,7 @@ fn indices_are_correct() { #[cfg(test)] fn check_arch(abis: &[Abi], arch: Architecture, expect: Option<Abi>) { let mut set = AbiSet::empty(); - for abis.each |&abi| { + for abis.iter().advance |&abi| { set.add(abi); } let r = set.for_arch(arch); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1758433aa73..2603cbb2dd7 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -10,26 +10,21 @@ // The Rust abstract syntax tree. -use core::prelude::*; - use codemap::{span, spanned}; use abi::AbiSet; use opt_vec::OptVec; use parse::token::{interner_get, str_to_ident}; -use core::hashmap::HashMap; -use core::option::Option; -use core::to_bytes::IterBytes; -use core::to_bytes; -use core::to_str::ToStr; +use std::hashmap::HashMap; +use std::option::Option; +use std::to_str::ToStr; use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; - // an identifier contains a Name (index into the interner // table) and a SyntaxContext to track renaming and // macro expansion per Flatt et al., "Macros // That Work Together" -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct ident { name: Name, ctxt: SyntaxContext } /// Construct an identifier with the given name and an empty context: @@ -59,7 +54,7 @@ pub struct SCTable { pub static empty_ctxt : uint = 0; pub static illegal_ctxt : uint = 1; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum SyntaxContext_ { EmptyCtxt, Mark (Mrk,SyntaxContext), @@ -88,42 +83,28 @@ impl<S:Encoder> Encodable<S> for ident { } } +#[deriving(IterBytes)] impl<D:Decoder> Decodable<D> for ident { fn decode(d: &mut D) -> ident { str_to_ident(d.read_str()) } } -impl to_bytes::IterBytes for ident { - #[inline] - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.name.iter_bytes(lsb0, f) - } -} - // Functions may or may not have names. pub type fn_ident = Option<ident>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct Lifetime { id: node_id, span: span, ident: ident } -impl to_bytes::IterBytes for Lifetime { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.id.iter_bytes(lsb0, f) && - self.span.iter_bytes(lsb0, f) && - self.ident.iter_bytes(lsb0, f) - } -} - // a "Path" is essentially Rust's notion of a name; // for instance: core::cmp::Eq . It's represented // as a sequence of identifiers, along with a bunch // of supporting information. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct Path { span: span, global: bool, @@ -136,7 +117,7 @@ pub type crate_num = int; pub type node_id = int; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct def_id { crate: crate_num, node: node_id, @@ -145,24 +126,24 @@ pub struct def_id { pub static local_crate: crate_num = 0; pub static crate_node_id: node_id = 0; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] // The AST represents all type param bounds as types. // typeck::collect::compute_bounds matches these against // the "special" built-in traits (see middle::lang_items) and -// detects Copy, Send, Owned, and Const. +// detects Copy, Send, Send, and Freeze. pub enum TyParamBound { TraitTyParamBound(@trait_ref), RegionTyParamBound } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct TyParam { ident: ident, id: node_id, bounds: @OptVec<TyParamBound> } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct Generics { lifetimes: OptVec<Lifetime>, ty_params: OptVec<TyParam> @@ -180,7 +161,7 @@ impl Generics { } } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum def { def_fn(def_id, purity), def_static_method(/* method */ def_id, @@ -190,7 +171,7 @@ pub enum def { def_self_ty(/* trait id */ node_id), def_mod(def_id), def_foreign_mod(def_id), - def_const(def_id), + def_static(def_id, bool /* is_mutbl */), def_arg(node_id, bool /* is_mutbl */), def_local(node_id, bool /* is_mutbl */), def_variant(def_id /* enum */, def_id /* variant */), @@ -207,7 +188,8 @@ pub enum def { def_struct(def_id), def_typaram_binder(node_id), /* struct, impl or trait with ty params */ def_region(node_id), - def_label(node_id) + def_label(node_id), + def_method(def_id /* method */, Option<def_id> /* trait */), } @@ -217,7 +199,7 @@ pub type crate_cfg = ~[@meta_item]; pub type crate = spanned<crate_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct crate_ { module: _mod, attrs: ~[attribute], @@ -226,7 +208,7 @@ pub struct crate_ { pub type meta_item = spanned<meta_item_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum meta_item_ { meta_word(@str), meta_list(@str, ~[@meta_item]), @@ -235,7 +217,7 @@ pub enum meta_item_ { pub type blk = spanned<blk_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct blk_ { view_items: ~[@view_item], stmts: ~[@stmt], @@ -244,40 +226,26 @@ pub struct blk_ { rules: blk_check_mode, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct pat { id: node_id, node: pat_, span: span, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct field_pat { ident: ident, pat: @pat, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum binding_mode { bind_by_ref(mutability), bind_infer } -impl to_bytes::IterBytes for binding_mode { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - bind_by_ref(ref m) => { - 0u8.iter_bytes(lsb0, f) && m.iter_bytes(lsb0, f) - } - - bind_infer => { - 1u8.iter_bytes(lsb0, f) - } - } - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum pat_ { pat_wild, // A pat_ident may either be a new bound variable, @@ -302,28 +270,16 @@ pub enum pat_ { pat_vec(~[@pat], Option<@pat>, ~[@pat]) } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum mutability { m_mutbl, m_imm, m_const, } -impl to_bytes::IterBytes for mutability { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum Sigil { BorrowedSigil, OwnedSigil, ManagedSigil } -impl to_bytes::IterBytes for Sigil { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as uint).iter_bytes(lsb0, f) - } -} - impl ToStr for Sigil { fn to_str(&self) -> ~str { match *self { @@ -334,7 +290,7 @@ impl ToStr for Sigil { } } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum vstore { // FIXME (#3469): Change uint to @expr (actually only constant exprs) vstore_fixed(Option<uint>), // [1,2,3,4] @@ -343,7 +299,7 @@ pub enum vstore { vstore_slice(Option<@Lifetime>) // &'foo? [1,2,3,4] } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum expr_vstore { expr_vstore_uniq, // ~[1,2,3,4] expr_vstore_box, // @[1,2,3,4] @@ -352,7 +308,7 @@ pub enum expr_vstore { expr_vstore_mut_slice, // &mut [1,2,3,4] } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum binop { add, subtract, @@ -374,10 +330,10 @@ pub enum binop { gt, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum unop { box(mutability), - uniq(mutability), + uniq, deref, not, neg @@ -385,7 +341,7 @@ pub enum unop { pub type stmt = spanned<stmt_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum stmt_ { // could be an item or a local (let) binding: stmt_decl(@decl, node_id), @@ -402,7 +358,7 @@ pub enum stmt_ { // FIXME (pending discussion of #1697, #2178...): local should really be // a refinement on pat. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct local_ { is_mutbl: bool, ty: @Ty, @@ -415,7 +371,7 @@ pub type local = spanned<local_>; pub type decl = spanned<decl_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum decl_ { // a local (let) binding: decl_local(@local), @@ -423,14 +379,14 @@ pub enum decl_ { decl_item(@item), } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct arm { pats: ~[@pat], guard: Option<@expr>, body: blk, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct field_ { ident: ident, expr: @expr, @@ -438,10 +394,10 @@ pub struct field_ { pub type field = spanned<field_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum blk_check_mode { default_blk, unsafe_blk, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct expr { id: node_id, node: expr_, @@ -461,14 +417,14 @@ impl expr { } } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum CallSugar { NoSugar, DoSugar, ForSugar } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum expr_ { expr_vstore(@expr, expr_vstore), expr_vec(~[@expr], mutability), @@ -539,7 +495,7 @@ pub enum expr_ { // else knows what to do with them, so you'll probably get a syntax // error. // -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] #[doc="For macro invocations; parsing is delegated to the macro"] pub enum token_tree { // a single token @@ -612,7 +568,7 @@ pub enum token_tree { // pub type matcher = spanned<matcher_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum matcher_ { // match one token match_tok(::parse::token::Token), @@ -625,14 +581,14 @@ pub enum matcher_ { pub type mac = spanned<mac_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum mac_ { mac_invoc_tt(@Path,~[token_tree]), // new macro-invocation } pub type lit = spanned<lit_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum lit_ { lit_str(@str), lit_int(i64, int_ty), @@ -646,13 +602,13 @@ pub enum lit_ { // NB: If you change this, you'll probably want to change the corresponding // type structure in middle/ty.rs as well. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct mt { ty: @Ty, mutbl: mutability, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct ty_field_ { ident: ident, mt: mt, @@ -660,7 +616,7 @@ pub struct ty_field_ { pub type ty_field = spanned<ty_field_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct ty_method { ident: ident, attrs: ~[attribute], @@ -672,7 +628,7 @@ pub struct ty_method { span: span, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] // A trait method is either required (meaning it doesn't have an // implementation, just a signature) or provided (meaning it has a default // implementation). @@ -681,7 +637,7 @@ pub enum trait_method { provided(@method), } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, } impl ToStr for int_ty { @@ -690,13 +646,7 @@ impl ToStr for int_ty { } } -impl to_bytes::IterBytes for int_ty { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum uint_ty { ty_u, ty_u8, ty_u16, ty_u32, ty_u64, } impl ToStr for uint_ty { @@ -705,13 +655,7 @@ impl ToStr for uint_ty { } } -impl to_bytes::IterBytes for uint_ty { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum float_ty { ty_f, ty_f32, ty_f64, } impl ToStr for float_ty { @@ -720,14 +664,8 @@ impl ToStr for float_ty { } } -impl to_bytes::IterBytes for float_ty { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - // NB Eq method appears below. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct Ty { id: node_id, node: ty_, @@ -735,7 +673,7 @@ pub struct Ty { } // Not represented directly in the AST, referred to by name through a ty_path. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum prim_ty { ty_int(int_ty), ty_uint(uint_ty), @@ -744,12 +682,13 @@ pub enum prim_ty { ty_bool, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum Onceness { Once, Many } +#[deriving(IterBytes)] impl ToStr for Onceness { fn to_str(&self) -> ~str { match *self { @@ -759,13 +698,7 @@ impl ToStr for Onceness { } } -impl to_bytes::IterBytes for Onceness { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as uint).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct TyClosure { sigil: Sigil, region: Option<@Lifetime>, @@ -773,10 +706,14 @@ pub struct TyClosure { purity: purity, onceness: Onceness, decl: fn_decl, - bounds: OptVec<TyParamBound> + // Optional optvec distinguishes between "fn()" and "fn:()" so we can + // implement issue #7264. None means "fn()", which means infer a default + // bound based on pointer sigil during typeck. Some(Empty) means "fn:()", + // which means use no bounds (e.g., not even Owned on a ~fn()). + bounds: Option<OptVec<TyParamBound>>, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct TyBareFn { purity: purity, abis: AbiSet, @@ -784,7 +721,7 @@ pub struct TyBareFn { decl: fn_decl } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum ty_ { ty_nil, ty_bot, /* bottom type */ @@ -797,7 +734,7 @@ pub enum ty_ { ty_closure(@TyClosure), ty_bare_fn(@TyBareFn), ty_tup(~[@Ty]), - ty_path(@Path, node_id), + ty_path(@Path, @Option<OptVec<TyParamBound>>, node_id), // for #7264; see above ty_mac(mac), // ty_infer means the type should be inferred instead of it having been // specified. This should only appear at the "top level" of a type and not @@ -805,19 +742,13 @@ pub enum ty_ { ty_infer, } -impl to_bytes::IterBytes for Ty { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.span.lo.iter_bytes(lsb0, f) && self.span.hi.iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum asm_dialect { asm_att, asm_intel } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct inline_asm { asm: @str, clobbers: @str, @@ -828,7 +759,7 @@ pub struct inline_asm { dialect: asm_dialect } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct arg { is_mutbl: bool, ty: @Ty, @@ -836,81 +767,50 @@ pub struct arg { id: node_id, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct fn_decl { inputs: ~[arg], output: @Ty, cf: ret_style, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum purity { - pure_fn, // declared with "pure fn" unsafe_fn, // declared with "unsafe fn" impure_fn, // declared with "fn" extern_fn, // declared with "extern fn" } +#[deriving(IterBytes)] impl ToStr for purity { fn to_str(&self) -> ~str { match *self { impure_fn => ~"impure", unsafe_fn => ~"unsafe", - pure_fn => ~"pure", extern_fn => ~"extern" } } } -impl to_bytes::IterBytes for purity { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum ret_style { noreturn, // functions with return type _|_ that always // raise an error or exit (i.e. never return to the caller) return_val, // everything else } -impl to_bytes::IterBytes for ret_style { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum explicit_self_ { sty_static, // no self sty_value, // `self` sty_region(Option<@Lifetime>, mutability), // `&'lt self` sty_box(mutability), // `@self` - sty_uniq(mutability) // `~self` -} - -impl to_bytes::IterBytes for explicit_self_ { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - sty_static => 0u8.iter_bytes(lsb0, f), - sty_value => 1u8.iter_bytes(lsb0, f), - sty_region(ref lft, ref mutbl) => { - 2u8.iter_bytes(lsb0, f) && lft.iter_bytes(lsb0, f) && mutbl.iter_bytes(lsb0, f) - } - sty_box(ref mutbl) => { - 3u8.iter_bytes(lsb0, f) && mutbl.iter_bytes(lsb0, f) - } - sty_uniq(ref mutbl) => { - 4u8.iter_bytes(lsb0, f) && mutbl.iter_bytes(lsb0, f) - } - } - } + sty_uniq // `~self` } pub type explicit_self = spanned<explicit_self_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct method { ident: ident, attrs: ~[attribute], @@ -925,17 +825,17 @@ pub struct method { vis: visibility, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct _mod { view_items: ~[@view_item], items: ~[@item], } // Foreign mods can be named or anonymous -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum foreign_mod_sort { named, anonymous } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct foreign_mod { sort: foreign_mod_sort, abis: AbiSet, @@ -943,24 +843,24 @@ pub struct foreign_mod { items: ~[@foreign_item], } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct variant_arg { ty: @Ty, id: node_id, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum variant_kind { tuple_variant_kind(~[variant_arg]), struct_variant_kind(@struct_def), } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct enum_def { variants: ~[variant], } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct variant_ { name: ident, attrs: ~[attribute], @@ -972,7 +872,7 @@ pub struct variant_ { pub type variant = spanned<variant_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct path_list_ident_ { name: ident, id: node_id, @@ -982,7 +882,7 @@ pub type path_list_ident = spanned<path_list_ident_>; pub type view_path = spanned<view_path_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum view_path_ { // quux = foo::bar::baz @@ -999,7 +899,7 @@ pub enum view_path_ { view_path_list(@Path, ~[path_list_ident], node_id) } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct view_item { node: view_item_, attrs: ~[attribute], @@ -1007,7 +907,7 @@ pub struct view_item { span: span, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum view_item_ { view_item_extern_mod(ident, ~[@meta_item], node_id), view_item_use(~[@view_path]), @@ -1019,11 +919,11 @@ pub type attribute = spanned<attribute_>; // Distinguishes between attributes that decorate items and attributes that // are contained as statements within items. These two cases need to be // distinguished for pretty-printing. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum attr_style { attr_outer, attr_inner, } // doc-comments are promoted to attributes that have is_sugared_doc = true -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct attribute_ { style: attr_style, value: @meta_item, @@ -1037,17 +937,17 @@ pub struct attribute_ { If this impl is an item_impl, the impl_id is redundant (it could be the same as the impl's node id). */ -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct trait_ref { path: @Path, ref_id: node_id, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum visibility { public, private, inherited } impl visibility { - fn inherit_from(&self, parent_visibility: visibility) -> visibility { + pub fn inherit_from(&self, parent_visibility: visibility) -> visibility { match self { &inherited => parent_visibility, &public | &private => *self @@ -1055,7 +955,7 @@ impl visibility { } } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct struct_field_ { kind: struct_field_kind, id: node_id, @@ -1065,13 +965,13 @@ pub struct struct_field_ { pub type struct_field = spanned<struct_field_>; -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum struct_field_kind { named_field(ident, visibility), unnamed_field // element of a tuple-like struct } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct struct_def { fields: ~[@struct_field], /* fields, not including ctor */ /* ID of the constructor. This is only used for tuple- or enum-like @@ -1083,7 +983,7 @@ pub struct struct_def { FIXME (#3300): Should allow items to be anonymous. Right now we just use dummy names for anon items. */ -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct item { ident: ident, attrs: ~[attribute], @@ -1093,9 +993,9 @@ pub struct item { span: span, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum item_ { - item_const(@Ty, @expr), + item_static(@Ty, mutability, @expr), item_fn(fn_decl, purity, AbiSet, Generics, blk), item_mod(_mod), item_foreign_mod(foreign_mod), @@ -1111,7 +1011,7 @@ pub enum item_ { item_mac(mac), } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct foreign_item { ident: ident, attrs: ~[attribute], @@ -1121,16 +1021,16 @@ pub struct foreign_item { vis: visibility, } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum foreign_item_ { foreign_item_fn(fn_decl, purity, Generics), - foreign_item_const(@Ty) + foreign_item_static(@Ty, /* is_mutbl */ bool), } // The data we save and restore about an inlined item or method. This is not // part of the AST that we parse from a file, but it becomes part of the tree // that we trans. -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub enum inlined_item { ii_item(@item), ii_method(def_id /* impl id */, @method), diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index a7c29e8a869..3abbe397054 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use abi::AbiSet; use ast::*; use ast; @@ -22,9 +20,9 @@ use print::pprust; use visit; use syntax::parse::token::special_idents; -use core::cmp; -use core::hashmap::HashMap; -use core::vec; +use std::cmp; +use std::hashmap::HashMap; +use std::vec; pub enum path_elt { path_mod(ident), @@ -126,7 +124,7 @@ pub fn mk_ast_map_visitor() -> vt { }); } -pub fn map_crate(diag: @span_handler, c: @crate) -> map { +pub fn map_crate(diag: @span_handler, c: &crate) -> map { let cx = @mut Ctx { map: @mut HashMap::new(), path: ~[], @@ -185,7 +183,7 @@ pub fn map_fn( (cx,v): (@mut Ctx, visit::vt<@mut Ctx>) ) { - for decl.inputs.each |a| { + for decl.inputs.iter().advance |a| { cx.map.insert(a.id, node_arg); } visit::visit_fn(fk, decl, body, sp, id, (cx, v)); @@ -220,19 +218,19 @@ pub fn map_item(i: @item, (cx, v): (@mut Ctx, visit::vt<@mut Ctx>)) { match i.node { item_impl(_, _, _, ref ms) => { let impl_did = ast_util::local_def(i.id); - for ms.each |m| { + for ms.iter().advance |m| { map_method(impl_did, extend(cx, i.ident), *m, cx); } } item_enum(ref enum_definition, _) => { - for (*enum_definition).variants.each |v| { + for (*enum_definition).variants.iter().advance |v| { cx.map.insert(v.node.id, node_variant( /* FIXME (#2543) */ copy *v, i, extend(cx, i.ident))); } } item_foreign_mod(ref nm) => { - for nm.items.each |nitem| { + for nm.items.iter().advance |nitem| { // Compute the visibility for this native item. let visibility = match nitem.vis { public => public, @@ -266,10 +264,10 @@ pub fn map_item(i: @item, (cx, v): (@mut Ctx, visit::vt<@mut Ctx>)) { ); } item_trait(_, ref traits, ref methods) => { - for traits.each |p| { + for traits.iter().advance |p| { cx.map.insert(p.ref_id, node_item(i, item_path)); } - for methods.each |tm| { + for methods.iter().advance |tm| { let id = ast_util::trait_method_to_ty_method(tm).id; let d_id = ast_util::local_def(i.id); cx.map.insert( @@ -339,7 +337,7 @@ pub fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str { Some(&node_item(item, path)) => { let path_str = path_ident_to_str(path, item.ident, itr); let item_str = match item.node { - item_const(*) => ~"const", + item_static(*) => ~"static", item_fn(*) => ~"fn", item_mod(*) => ~"mod", item_foreign_mod(*) => ~"foreign mod", diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index a4ded8fea8c..529d5bfe70b 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -8,22 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast::*; use ast; use ast_util; use codemap::{span, spanned}; -use core::cast; -use core::local_data; use opt_vec; use parse::token; use visit; -use core::hashmap::HashMap; -use core::int; -use core::option; -use core::to_bytes; +use std::hashmap::HashMap; +use std::int; +use std::option; +use std::cast; +use std::local_data; pub fn path_name_i(idents: &[ident]) -> ~str { // FIXME: Bad copies (#2543 -- same for everything else that says "bad") @@ -59,9 +56,9 @@ pub fn variant_def_ids(d: def) -> Option<(def_id, def_id)> { pub fn def_id_of_def(d: def) -> def_id { match d { def_fn(id, _) | def_static_method(id, _, _) | def_mod(id) | - def_foreign_mod(id) | def_const(id) | + def_foreign_mod(id) | def_static(id, _) | def_variant(_, id) | def_ty(id) | def_ty_param(id, _) | - def_use(id) | def_struct(id) | def_trait(id) => { + def_use(id) | def_struct(id) | def_trait(id) | def_method(id, _) => { id } def_arg(id, _) | def_local(id, _) | def_self(id, _) | def_self_ty(id) @@ -138,7 +135,7 @@ pub fn is_shift_binop(b: binop) -> bool { pub fn unop_to_str(op: unop) -> ~str { match op { box(mt) => if mt == m_mutbl { ~"@mut " } else { ~"@" }, - uniq(mt) => if mt == m_mutbl { ~"~mut " } else { ~"~" }, + uniq => ~"~", deref => ~"*", not => ~"!", neg => ~"-" @@ -196,14 +193,6 @@ pub fn is_call_expr(e: @expr) -> bool { match e.node { expr_call(*) => true, _ => false } } -// This makes def_id hashable -impl to_bytes::IterBytes for def_id { - #[inline] - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.crate.iter_bytes(lsb0, f) && self.node.iter_bytes(lsb0, f) - } -} - pub fn block_from_expr(e: @expr) -> blk { let blk_ = default_block(~[], option::Some::<@expr>(e), e.id); return spanned {node: blk_, span: e.span}; @@ -281,7 +270,7 @@ pub fn split_trait_methods(trait_methods: &[trait_method]) -> (~[ty_method], ~[@method]) { let mut reqd = ~[]; let mut provd = ~[]; - for trait_methods.each |trt_method| { + for trait_methods.iter().advance |trt_method| { match *trt_method { required(ref tm) => reqd.push(copy *tm), provided(m) => provd.push(m) @@ -394,10 +383,10 @@ impl id_range { pub fn id_visitor<T: Copy>(vfn: @fn(node_id, T)) -> visit::vt<T> { let visit_generics: @fn(&Generics, T) = |generics, t| { - for generics.ty_params.each |p| { + for generics.ty_params.iter().advance |p| { vfn(p.id, copy t); } - for generics.lifetimes.each |p| { + for generics.lifetimes.iter().advance |p| { vfn(p.id, copy t); } }; @@ -411,13 +400,13 @@ pub fn id_visitor<T: Copy>(vfn: @fn(node_id, T)) -> visit::vt<T> { match vi.node { view_item_extern_mod(_, _, id) => vfn(id, copy t), view_item_use(ref vps) => { - for vps.each |vp| { + for vps.iter().advance |vp| { match vp.node { view_path_simple(_, _, id) => vfn(id, copy t), view_path_glob(_, id) => vfn(id, copy t), view_path_list(_, ref paths, id) => { vfn(id, copy t); - for paths.each |p| { + for paths.iter().advance |p| { vfn(p.node.id, copy t); } } @@ -437,7 +426,7 @@ pub fn id_visitor<T: Copy>(vfn: @fn(node_id, T)) -> visit::vt<T> { vfn(i.id, copy t); match i.node { item_enum(ref enum_definition, _) => - for (*enum_definition).variants.each |v| { vfn(v.node.id, copy t); }, + for (*enum_definition).variants.iter().advance |v| { vfn(v.node.id, copy t); }, _ => () } visit::visit_item(i, (t, vt)); @@ -473,7 +462,7 @@ pub fn id_visitor<T: Copy>(vfn: @fn(node_id, T)) -> visit::vt<T> { visit_ty: |ty, (t, vt)| { match ty.node { - ty_path(_, id) => vfn(id, copy t), + ty_path(_, _, id) => vfn(id, copy t), _ => { /* fall through */ } } visit::visit_ty(ty, (t, vt)); @@ -500,7 +489,7 @@ pub fn id_visitor<T: Copy>(vfn: @fn(node_id, T)) -> visit::vt<T> { } } - for d.inputs.each |arg| { + for d.inputs.iter().advance |arg| { vfn(arg.id, copy t) } visit::visit_fn(fk, d, a, b, id, (copy t, vt)); @@ -546,18 +535,18 @@ pub fn walk_pat(pat: @pat, it: &fn(@pat) -> bool) -> bool { match pat.node { pat_ident(_, _, Some(p)) => walk_pat(p, it), pat_struct(_, ref fields, _) => { - fields.each(|f| walk_pat(f.pat, it)) + fields.iter().advance(|f| walk_pat(f.pat, |p| it(p))) } pat_enum(_, Some(ref s)) | pat_tup(ref s) => { - s.each(|&p| walk_pat(p, it)) + s.iter().advance(|&p| walk_pat(p, |p| it(p))) } pat_box(s) | pat_uniq(s) | pat_region(s) => { walk_pat(s, it) } pat_vec(ref before, ref slice, ref after) => { - before.each(|&p| walk_pat(p, it)) && - slice.iter().advance(|&p| walk_pat(p, it)) && - after.iter().advance(|&p| walk_pat(p, it)) + before.iter().advance(|&p| walk_pat(p, |p| it(p))) && + slice.iter().advance(|&p| walk_pat(p, |p| it(p))) && + after.iter().advance(|&p| walk_pat(p, |p| it(p))) } pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, _, _) | pat_enum(_, _) => { @@ -567,11 +556,11 @@ pub fn walk_pat(pat: @pat, it: &fn(@pat) -> bool) -> bool { } pub trait EachViewItem { - pub fn each_view_item(&self, f: @fn(@ast::view_item) -> bool) -> bool; + pub fn each_view_item(&self, f: @fn(&ast::view_item) -> bool) -> bool; } impl EachViewItem for ast::crate { - fn each_view_item(&self, f: @fn(@ast::view_item) -> bool) -> bool { + fn each_view_item(&self, f: @fn(&ast::view_item) -> bool) -> bool { let broke = @mut false; let vtor: visit::vt<()> = visit::mk_simple_visitor(@visit::SimpleVisitor { visit_view_item: |vi| { *broke = f(vi); }, ..*visit::default_simple_visitor() @@ -581,7 +570,7 @@ impl EachViewItem for ast::crate { } } -pub fn view_path_id(p: @view_path) -> node_id { +pub fn view_path_id(p: &view_path) -> node_id { match p.node { view_path_simple(_, _, id) | view_path_glob(_, id) | @@ -621,6 +610,15 @@ pub enum Privacy { Public } +/// Returns true if the given pattern consists solely of an identifier +/// and false otherwise. +pub fn pat_is_ident(pat: @ast::pat) -> bool { + match pat.node { + ast::pat_ident(*) => true, + _ => false, + } +} + // HYGIENE FUNCTIONS /// Construct an identifier with the given name and an empty context: @@ -697,7 +695,7 @@ pub fn new_sctable_internal() -> SCTable { pub fn get_sctable() -> @mut SCTable { unsafe { let sctable_key = (cast::transmute::<(uint, uint), - &fn(v: @@mut SCTable)>( + &fn:Copy(v: @@mut SCTable)>( (-4 as uint, 0u))); match local_data::local_data_get(sctable_key) { None => { @@ -793,7 +791,7 @@ pub fn getLast(arr: &~[Mrk]) -> uint { mod test { use ast::*; use super::*; - use core::io; + use std::io; #[test] fn xorpush_test () { let mut s = ~[]; @@ -816,7 +814,7 @@ mod test { // convert a list of uints to an @[ident] // (ignores the interner completely) fn uints_to_idents (uints: &~[uint]) -> @~[ident] { - @uints.map(|u|{ ident {name:*u, ctxt: empty_ctxt} }) + @uints.map(|u| ident {name:*u, ctxt: empty_ctxt}) } fn id (u : uint, s: SyntaxContext) -> ident { diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index e096711262f..a1a0c700628 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -10,7 +10,7 @@ // Functions dealing with attributes and meta_items -use core::prelude::*; +use extra; use ast; use codemap::{spanned, dummy_spanned}; @@ -19,10 +19,8 @@ use codemap::BytePos; use diagnostic::span_handler; use parse::comments::{doc_comment_style, strip_doc_comment_decoration}; -use core::hashmap::HashSet; -use core::vec; -use extra; - +use std::hashmap::HashSet; +use std::vec; /* Constructors */ pub fn mk_name_value_item_str(name: @str, value: @str) @@ -158,7 +156,7 @@ pub fn find_attrs_by_name(attrs: &[ast::attribute], name: &str) -> pub fn find_meta_items_by_name(metas: &[@ast::meta_item], name: &str) -> ~[@ast::meta_item] { let mut rs = ~[]; - for metas.each |mi| { + for metas.iter().advance |mi| { if name == get_meta_item_name(*mi) { rs.push(*mi) } @@ -172,7 +170,7 @@ pub fn find_meta_items_by_name(metas: &[@ast::meta_item], name: &str) -> */ pub fn contains(haystack: &[@ast::meta_item], needle: @ast::meta_item) -> bool { - for haystack.each |item| { + for haystack.iter().advance |item| { if eq(*item, needle) { return true; } } return false; @@ -193,8 +191,8 @@ fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool { ast::meta_list(ref na, ref misa) => match b.node { ast::meta_list(ref nb, ref misb) => { if na != nb { return false; } - for misa.each |mi| { - if !misb.contains(mi) { return false; } + for misa.iter().advance |mi| { + if !misb.iter().any_(|x| x == mi) { return false; } } true } @@ -334,7 +332,7 @@ pub fn find_inline_attr(attrs: &[ast::attribute]) -> inline_attr { pub fn require_unique_names(diagnostic: @span_handler, metas: &[@ast::meta_item]) { let mut set = HashSet::new(); - for metas.each |meta| { + for metas.iter().advance |meta| { let name = get_meta_item_name(*meta); // FIXME: How do I silence the warnings? --pcw (#2619) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 0c09a001d48..bcf617c56ae 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -21,11 +21,8 @@ source code snippets, etc. */ -use core::prelude::*; - -use core::cmp; -use core::to_bytes; -use core::uint; +use std::cmp; +use std::uint; use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; pub trait Pos { @@ -34,12 +31,12 @@ pub trait Pos { } /// A byte offset -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct BytePos(uint); /// A character offset. Because of multibyte utf8 characters, a byte offset /// is not equivalent to a character offset. The CodeMap will convert BytePos /// values to CharPos values as necessary. -#[deriving(Eq)] +#[deriving(Eq,IterBytes)] pub struct CharPos(uint); // XXX: Lots of boilerplate in these impls, but so far my attempts to fix @@ -69,12 +66,6 @@ impl Sub<BytePos, BytePos> for BytePos { } } -impl to_bytes::IterBytes for BytePos { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (**self).iter_bytes(lsb0, f) - } -} - impl Pos for CharPos { fn from_uint(n: uint) -> CharPos { CharPos(n) } fn to_uint(&self) -> uint { **self } @@ -87,12 +78,6 @@ impl cmp::Ord for CharPos { fn gt(&self, other: &CharPos) -> bool { **self > **other } } -impl to_bytes::IterBytes for CharPos { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - (**self).iter_bytes(lsb0, f) - } -} - impl Add<CharPos,CharPos> for CharPos { fn add(&self, rhs: &CharPos) -> CharPos { CharPos(**self + **rhs) @@ -111,13 +96,14 @@ are *absolute* positions from the beginning of the codemap, not positions relative to FileMaps. Methods on the CodeMap can be used to relate spans back to the original source. */ +#[deriving(IterBytes)] pub struct span { lo: BytePos, hi: BytePos, expn_info: Option<@ExpnInfo> } -#[deriving(Eq, Encodable, Decodable)] +#[deriving(Eq, Encodable, Decodable,IterBytes)] pub struct spanned<T> { node: T, span: span } impl cmp::Eq for span { @@ -140,14 +126,6 @@ impl<D:Decoder> Decodable<D> for span { } } -impl to_bytes::IterBytes for span { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.lo.iter_bytes(lsb0, f) && - self.hi.iter_bytes(lsb0, f) && - self.expn_info.iter_bytes(lsb0, f) - } -} - pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> spanned<T> { respan(mk_sp(lo, hi), t) } @@ -193,40 +171,21 @@ pub struct LocWithOpt { // used to be structural records. Better names, anyone? pub struct FileMapAndLine {fm: @FileMap, line: uint} pub struct FileMapAndBytePos {fm: @FileMap, pos: BytePos} +#[deriving(IterBytes)] pub struct NameAndSpan {name: @str, span: Option<span>} -impl to_bytes::IterBytes for NameAndSpan { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.name.iter_bytes(lsb0, f) && self.span.iter_bytes(lsb0, f) - } -} - +#[deriving(IterBytes)] pub struct CallInfo { call_site: span, callee: NameAndSpan } -impl to_bytes::IterBytes for CallInfo { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - self.call_site.iter_bytes(lsb0, f) && self.callee.iter_bytes(lsb0, f) - } -} - /// Extra information for tracking macro expansion of spans +#[deriving(IterBytes)] pub enum ExpnInfo { ExpandedFrom(CallInfo) } -impl to_bytes::IterBytes for ExpnInfo { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool { - match *self { - ExpandedFrom(ref call_info) => { - 0u8.iter_bytes(lsb0, f) && call_info.iter_bytes(lsb0, f) - } - } - } -} - pub type FileName = @str; pub struct FileLines @@ -422,7 +381,7 @@ impl CodeMap { } pub fn get_filemap(&self, filename: &str) -> @FileMap { - for self.files.each |fm| { if filename == fm.name { return *fm; } } + for self.files.iter().advance |fm| { if filename == fm.name { return *fm; } } //XXjdm the following triggers a mismatched type bug // (or expected function, found _|_) fail!(); // ("asking for " + filename + " which we don't know about"); @@ -508,7 +467,7 @@ impl CodeMap { // The number of extra bytes due to multibyte chars in the FileMap let mut total_extra_bytes = 0; - for map.multibyte_chars.each |mbc| { + for map.multibyte_chars.iter().advance |mbc| { debug!("codemap: %?-byte char at %?", mbc.bytes, mbc.pos); if mbc.pos < bpos { total_extra_bytes += mbc.bytes; diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index e67ca5260b8..ab7d3fda501 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -8,14 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use codemap::{Pos, span}; use codemap; -use core::io; -use core::uint; -use core::vec; +use std::io; +use std::uint; use extra::term; pub type Emitter = @fn(cmsp: Option<(@codemap::CodeMap, span)>, @@ -180,39 +177,45 @@ fn diagnosticstr(lvl: level) -> ~str { } } -fn diagnosticcolor(lvl: level) -> u8 { +fn diagnosticcolor(lvl: level) -> term::color::Color { match lvl { - fatal => term::color_bright_red, - error => term::color_bright_red, - warning => term::color_bright_yellow, - note => term::color_bright_green + fatal => term::color::bright_red, + error => term::color::bright_red, + warning => term::color::bright_yellow, + note => term::color::bright_green } } -fn print_diagnostic(topic: &str, lvl: level, msg: &str) { - let t = term::Terminal::new(io::stderr()); - +fn print_maybe_colored(msg: &str, color: term::color::Color) { let stderr = io::stderr(); - if !topic.is_empty() { - stderr.write_str(fmt!("%s ", topic)); - } + let t = term::Terminal::new(stderr); match t { Ok(term) => { if stderr.get_type() == io::Screen { - term.fg(diagnosticcolor(lvl)); - stderr.write_str(fmt!("%s: ", diagnosticstr(lvl))); + term.fg(color); + stderr.write_str(msg); term.reset(); - stderr.write_str(fmt!("%s\n", msg)); } else { - stderr.write_str(fmt!("%s: %s\n", diagnosticstr(lvl), msg)); + stderr.write_str(msg); } }, - _ => stderr.write_str(fmt!("%s: %s\n", diagnosticstr(lvl), msg)) + _ => stderr.write_str(msg) } } +fn print_diagnostic(topic: &str, lvl: level, msg: &str) { + let stderr = io::stderr(); + + if !topic.is_empty() { + stderr.write_str(fmt!("%s ", topic)); + } + + print_maybe_colored(fmt!("%s: ", diagnosticstr(lvl)), diagnosticcolor(lvl)); + stderr.write_str(fmt!("%s\n", msg)); +} + pub fn collect(messages: @mut ~[~str]) -> @fn(Option<(@codemap::CodeMap, span)>, &str, level) { let f: @fn(Option<(@codemap::CodeMap, span)>, &str, level) = @@ -227,7 +230,7 @@ pub fn emit(cmsp: Option<(@codemap::CodeMap, span)>, msg: &str, lvl: level) { let ss = cm.span_to_str(sp); let lines = cm.span_to_lines(sp); print_diagnostic(ss, lvl, msg); - highlight_lines(cm, sp, lines); + highlight_lines(cm, sp, lvl, lines); print_macro_backtrace(cm, sp); } None => { @@ -237,7 +240,7 @@ pub fn emit(cmsp: Option<(@codemap::CodeMap, span)>, msg: &str, lvl: level) { } fn highlight_lines(cm: @codemap::CodeMap, - sp: span, + sp: span, lvl: level, lines: @codemap::FileLines) { let fm = lines.file; @@ -246,11 +249,11 @@ fn highlight_lines(cm: @codemap::CodeMap, let mut elided = false; let mut display_lines = /* FIXME (#2543) */ copy lines.lines; if display_lines.len() > max_lines { - display_lines = vec::slice(display_lines, 0u, max_lines).to_vec(); + display_lines = display_lines.slice(0u, max_lines).to_owned(); elided = true; } // Print the offending lines - for display_lines.each |line| { + for display_lines.iter().advance |line| { io::stderr().write_str(fmt!("%s:%u ", fm.name, *line + 1u)); let s = fm.get_line(*line as int) + "\n"; io::stderr().write_str(s); @@ -260,8 +263,11 @@ fn highlight_lines(cm: @codemap::CodeMap, let s = fmt!("%s:%u ", fm.name, last_line + 1u); let mut indent = s.len(); let mut out = ~""; - while indent > 0u { out += " "; indent -= 1u; } - out += "...\n"; + while indent > 0u { + out.push_char(' '); + indent -= 1u; + } + out.push_str("...\n"); io::stderr().write_str(out); } @@ -282,24 +288,31 @@ fn highlight_lines(cm: @codemap::CodeMap, // part of the 'filename:line ' part of the previous line. let skip = fm.name.len() + digits + 3u; for skip.times() { - s += " "; + s.push_char(' '); } let orig = fm.get_line(lines.lines[0] as int); for uint::range(0u,left-skip) |pos| { let curChar = (orig[pos] as char); - s += match curChar { // Whenever a tab occurs on the previous - '\t' => "\t", // line, we insert one on the error-point- - _ => " " // -squigly-line as well (instead of a - }; // space). This way the squigly-line will - } // usually appear in the correct position. - s += "^"; + // Whenever a tab occurs on the previous line, we insert one on + // the error-point-squiggly-line as well (instead of a space). + // That way the squiggly line will usually appear in the correct + // position. + match curChar { + '\t' => s.push_char('\t'), + _ => s.push_char(' '), + }; + } + io::stderr().write_str(s); + let mut s = ~"^"; let hi = cm.lookup_char_pos(sp.hi); if hi.col != lo.col { // the ^ already takes up one space - let num_squiglies = hi.col.to_uint()-lo.col.to_uint()-1u; - for num_squiglies.times() { s += "~"; } + let num_squigglies = hi.col.to_uint()-lo.col.to_uint()-1u; + for num_squigglies.times() { + s.push_char('~') + } } - io::stderr().write_str(s + "\n"); + print_maybe_colored(s + "\n", diagnosticcolor(lvl)); } } diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index febb6b324b9..532757346d0 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -12,9 +12,6 @@ * Inline assembly support. */ -use core::prelude::*; - -use core::vec; use ast; use codemap::span; use ext::base; @@ -22,6 +19,8 @@ use ext::base::*; use parse; use parse::token; +use std::vec; + enum State { Asm, Outputs, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 997f4e2621f..78fdb99753d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - -use core::vec; use ast; use ast::Name; use codemap; @@ -22,7 +19,8 @@ use parse; use parse::token; use parse::token::{ident_to_str, intern, str_to_ident}; -use core::hashmap::HashMap; +use std::vec; +use std::hashmap::HashMap; // new-style macro! tt code: // @@ -511,7 +509,7 @@ impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{ } }, ConsMapChain (~ref mut map, rest) => { - if satisfies_pred(map,&n,pred) { + if satisfies_pred(map,&n,|v|pred(v)) { map.insert(key,ext); } else { rest.insert_into_frame(key,ext,n,pred) @@ -535,7 +533,7 @@ fn satisfies_pred<K : Eq + Hash + IterBytes,V>(map : &mut HashMap<K,V>, #[cfg(test)] mod test { use super::MapChain; - use core::hashmap::HashMap; + use std::hashmap::HashMap; #[test] fn testenv () { let mut a = HashMap::new(); diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index dc31a248065..2c1b4cfc591 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use abi::AbiSet; use ast::ident; use ast; @@ -48,7 +46,7 @@ pub trait AstBuilder { fn ty_mt(&self, ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt; fn ty(&self, span: span, ty: ast::ty_) -> @ast::Ty; - fn ty_path(&self, @ast::Path) -> @ast::Ty; + fn ty_path(&self, @ast::Path, @Option<OptVec<ast::TyParamBound>>) -> @ast::Ty; fn ty_ident(&self, span: span, idents: ast::ident) -> @ast::Ty; fn ty_rptr(&self, span: span, @@ -267,14 +265,17 @@ impl AstBuilder for @ExtCtxt { } } - fn ty_path(&self, path: @ast::Path) -> @ast::Ty { + fn ty_path(&self, path: @ast::Path, bounds: @Option<OptVec<ast::TyParamBound>>) + -> @ast::Ty { self.ty(path.span, - ast::ty_path(path, self.next_id())) + ast::ty_path(path, bounds, self.next_id())) } + // Might need to take bounds as an argument in the future, if you ever want + // to generate a bounded existential trait type. fn ty_ident(&self, span: span, ident: ast::ident) -> @ast::Ty { - self.ty_path(self.path_ident(span, ident)) + self.ty_path(self.path_ident(span, ident), @None) } fn ty_rptr(&self, @@ -304,7 +305,8 @@ impl AstBuilder for @ExtCtxt { self.ident_of("Option") ], None, - ~[ ty ])) + ~[ ty ]), + @None) } fn ty_field_imm(&self, span: span, name: ident, ty: @ast::Ty) -> ast::ty_field { @@ -342,7 +344,7 @@ impl AstBuilder for @ExtCtxt { fn ty_vars_global(&self, ty_params: &OptVec<ast::TyParam>) -> ~[@ast::Ty] { opt_vec::take_vec( ty_params.map(|p| self.ty_path( - self.path_global(dummy_sp(), ~[p.ident])))) + self.path_global(dummy_sp(), ~[p.ident]), @None))) } fn strip_bounds(&self, generics: &Generics) -> Generics { diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs index 59a9ec407b0..3f64654dd80 100644 --- a/src/libsyntax/ext/bytes.rs +++ b/src/libsyntax/ext/bytes.rs @@ -21,7 +21,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) -> bas let exprs = get_exprs_from_tts(cx, tts); let mut bytes = ~[]; - for exprs.each |expr| { + for exprs.iter().advance |expr| { match expr.node { // expression is a literal ast::expr_lit(lit) => match lit.node { diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index bfb234106b8..7df8874076e 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast; use codemap::span; use ext::base::*; @@ -20,7 +18,7 @@ use parse::token::{str_to_ident}; pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { let mut res_str = ~""; - for tts.eachi |i, e| { + for tts.iter().enumerate().advance |(i, e)| { if i & 1 == 1 { match *e { ast::tt_tok(_, token::COMMA) => (), @@ -28,8 +26,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) } } else { match *e { - ast::tt_tok(_, token::IDENT(ident,_)) => - res_str += cx.str_of(ident), + ast::tt_tok(_, token::IDENT(ident,_)) => res_str.push_str(cx.str_of(ident)), _ => cx.span_fatal(sp, "concat_idents! requires ident args.") } } diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 4fc67f2f52e..edaf2b8cae6 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast::{meta_item, item, expr}; use codemap::span; use ext::base::ExtCtxt; diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index 5fc75511e57..cea88bb7bbb 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast::{meta_item, item, expr}; use codemap::span; use ext::base::ExtCtxt; diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index c60b589dfc3..3b9691cd42c 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast; use ast::{meta_item, item, expr}; use codemap::span; diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs index acd2073b273..70ac4d3d4c1 100644 --- a/src/libsyntax/ext/deriving/cmp/totaleq.rs +++ b/src/libsyntax/ext/deriving/cmp/totaleq.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast::{meta_item, item, expr}; use codemap::span; use ext::base::ExtCtxt; diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs index 94407cd6e72..84d7320fe1c 100644 --- a/src/libsyntax/ext/deriving/cmp/totalord.rs +++ b/src/libsyntax/ext/deriving/cmp/totalord.rs @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast::{meta_item, item, expr}; use codemap::span; use ext::base::ExtCtxt; use ext::build::AstBuilder; use ext::deriving::generic::*; -use core::cmp::{Ordering, Equal, Less, Greater}; +use std::cmp::{Ordering, Equal, Less, Greater}; pub fn expand_deriving_totalord(cx: @ExtCtxt, span: span, diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index abea7912fc8..405f9e3438b 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -13,9 +13,8 @@ The compiler code necessary for #[deriving(Decodable)]. See encodable.rs for more. */ -use core::prelude::*; -use core::vec; -use core::uint; +use std::vec; +use std::uint; use ast::{meta_item, item, expr, m_mutbl}; use codemap::span; @@ -92,9 +91,9 @@ fn decodable_substructure(cx: @ExtCtxt, span: span, } } Right(ref fields) => { - let fields = do fields.mapi |i, f| { + let fields = do fields.iter().enumerate().transform |(i, f)| { cx.field_imm(span, *f, getarg(cx.str_of(*f), i)) - }; + }.collect(); cx.expr_struct_ident(span, substr.type_ident, fields) } }; @@ -111,7 +110,7 @@ fn decodable_substructure(cx: @ExtCtxt, span: span, let mut variants = ~[]; let rvariant_arg = cx.ident_of("read_enum_variant_arg"); - for fields.eachi |i, f| { + for fields.iter().enumerate().advance |(i, f)| { let (name, parts) = match *f { (i, ref p) => (i, p) }; variants.push(cx.expr_str(span, cx.str_of(name))); @@ -134,9 +133,9 @@ fn decodable_substructure(cx: @ExtCtxt, span: span, } } Right(ref fields) => { - let fields = do fields.mapi |i, f| { + let fields = do fields.iter().enumerate().transform |(i, f)| { cx.field_imm(span, *f, getarg(i)) - }; + }.collect(); cx.expr_struct_ident(span, name, fields) } }; diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index d7e64caa5c8..5514fd0b6ab 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -75,8 +75,6 @@ would yield functions like: } */ -use core::prelude::*; - use ast::{meta_item, item, expr, m_imm, m_mutbl}; use codemap::span; use ext::base::ExtCtxt; @@ -124,7 +122,7 @@ fn encodable_substructure(cx: @ExtCtxt, span: span, Struct(ref fields) => { let emit_struct_field = cx.ident_of("emit_struct_field"); let mut stmts = ~[]; - for fields.eachi |i, f| { + for fields.iter().enumerate().advance |(i, f)| { let (name, val) = match *f { (Some(id), e, _) => (cx.str_of(id), e), (None, e, _) => (fmt!("_field%u", i).to_managed(), e) @@ -155,7 +153,7 @@ fn encodable_substructure(cx: @ExtCtxt, span: span, let encoder = cx.expr_ident(span, blkarg); let emit_variant_arg = cx.ident_of("emit_enum_variant_arg"); let mut stmts = ~[]; - for fields.eachi |i, f| { + for fields.iter().enumerate().advance |(i, f)| { let val = match *f { (_, e, _) => e }; let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]); let lambda = cx.lambda_expr_1(span, enc, blkarg); diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 22ce305b857..0e4fc9d96fa 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -162,8 +162,6 @@ StaticEnum(<ast::enum_def of C>, ~[(<ident of C0>, Left(1)), */ -use core::prelude::*; - use ast; use ast::{enum_def, expr, ident, Generics, struct_def}; @@ -172,8 +170,8 @@ use ext::build::AstBuilder; use codemap::{span,respan}; use opt_vec; -use core::uint; -use core::vec; +use std::uint; +use std::vec; pub use self::ty::*; mod ty; @@ -195,7 +193,7 @@ pub struct TraitDef<'self> { pub struct MethodDef<'self> { /// name of the method name: &'self str, - /// List of generics, e.g. `R: core::rand::Rng` + /// List of generics, e.g. `R: std::rand::Rng` generics: LifetimeBounds<'self>, /// Whether there is a self argument (outer Option) i.e. whether @@ -286,7 +284,7 @@ impl<'self> TraitDef<'self> { _mitem: @ast::meta_item, in_items: ~[@ast::item]) -> ~[@ast::item] { let mut result = ~[]; - for in_items.each |item| { + for in_items.iter().advance |item| { result.push(*item); match item.node { ast::item_struct(struct_def, ref generics) => { @@ -324,11 +322,11 @@ impl<'self> TraitDef<'self> { let mut trait_generics = self.generics.to_generics(cx, span, type_ident, generics); // Copy the lifetimes - for generics.lifetimes.each |l| { + for generics.lifetimes.iter().advance |l| { trait_generics.lifetimes.push(copy *l) }; // Create the type parameters. - for generics.ty_params.each |ty_param| { + for generics.ty_params.iter().advance |ty_param| { // I don't think this can be moved out of the loop, since // a TyParamBound requires an ast id let mut bounds = opt_vec::from( @@ -358,7 +356,8 @@ impl<'self> TraitDef<'self> { // Create the type of `self`. let self_type = cx.ty_path(cx.path_all(span, false, ~[ type_ident ], self_lifetime, - opt_vec::take_vec(self_ty_params))); + opt_vec::take_vec(self_ty_params)), + @None); let doc_attr = cx.attribute( span, @@ -487,7 +486,7 @@ impl<'self> MethodDef<'self> { None => respan(span, ast::sty_static), }; - for self.args.eachi |i, ty| { + for self.args.iter().enumerate().advance |(i, ty)| { let ast_ty = ty.to_ty(cx, span, type_ident, generics); let ident = cx.ident_of(fmt!("__arg_%u", i)); arg_tys.push((ident, ast_ty)); @@ -592,14 +591,14 @@ impl<'self> MethodDef<'self> { // transpose raw_fields let fields = match raw_fields { [self_arg, .. rest] => { - do self_arg.mapi |i, &(opt_id, field)| { + do self_arg.iter().enumerate().transform |(i, &(opt_id, field))| { let other_fields = do rest.map |l| { match &l[i] { &(_, ex) => ex } }; (opt_id, field, other_fields) - } + }.collect() } [] => { cx.span_bug(span, "No self arguments to non-static \ method in generic `deriving`") } @@ -740,16 +739,17 @@ impl<'self> MethodDef<'self> { let mut enum_matching_fields = vec::from_elem(self_vec.len(), ~[]); - for matches_so_far.tail().each |&(_, _, other_fields)| { - for other_fields.eachi |i, &(_, other_field)| { + for matches_so_far.tail().iter().advance |&(_, _, other_fields)| { + for other_fields.iter().enumerate().advance |(i, &(_, other_field))| { enum_matching_fields[i].push(other_field); } } let field_tuples = - do vec::map_zip(*self_vec, - enum_matching_fields) |&(id, self_f), &other| { + do self_vec.iter() + .zip(enum_matching_fields.iter()) + .transform |(&(id, self_f), &other)| { (id, self_f, other) - }; + }.collect(); substructure = EnumMatching(variant_index, variant, field_tuples); } None => { @@ -809,7 +809,7 @@ impl<'self> MethodDef<'self> { } } else { // create an arm matching on each variant - for enum_def.variants.eachi |index, variant| { + for enum_def.variants.iter().enumerate().advance |(index, variant)| { let (pattern, idents) = create_enum_variant_pattern(cx, span, variant, current_match_str, @@ -870,7 +870,7 @@ fn summarise_struct(cx: @ExtCtxt, span: span, struct_def: &struct_def) -> Either<uint, ~[ident]> { let mut named_idents = ~[]; let mut unnamed_count = 0; - for struct_def.fields.each |field| { + for struct_def.fields.iter().advance |field| { match field.node.kind { ast::named_field(ident, _) => named_idents.push(ident), ast::unnamed_field => unnamed_count += 1, @@ -923,7 +923,7 @@ fn create_struct_pattern(cx: @ExtCtxt, let mut ident_expr = ~[]; let mut struct_type = Unknown; - for struct_def.fields.eachi |i, struct_field| { + for struct_def.fields.iter().enumerate().advance |(i, struct_field)| { let opt_id = match struct_field.node.kind { ast::named_field(ident, _) if (struct_type == Unknown || struct_type == Record) => { diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs index 83cff70d459..15fb6ee9ff7 100644 --- a/src/libsyntax/ext/deriving/iter_bytes.rs +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast::{meta_item, item, expr, and}; use codemap::span; use ext::base::ExtCtxt; @@ -45,15 +43,21 @@ pub fn expand_deriving_iter_bytes(cx: @ExtCtxt, } fn iter_bytes_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { - let lsb0_f = match substr.nonself_args { - [l, f] => ~[l, f], + let (lsb0, f)= match substr.nonself_args { + [l, f] => (l, f), _ => cx.span_bug(span, "Incorrect number of arguments in `deriving(IterBytes)`") }; + // Build the "explicitly borrowed" stack closure, "|_buf| f(_buf)". + let blk_arg = cx.ident_of("_buf"); + let borrowed_f = + cx.lambda_expr_1(span, cx.expr_call(span, f, ~[cx.expr_ident(span, blk_arg)]), + blk_arg); + let iter_bytes_ident = substr.method_ident; let call_iterbytes = |thing_expr| { cx.expr_method_call(span, thing_expr, iter_bytes_ident, - copy lsb0_f) + ~[lsb0, borrowed_f]) }; let mut exprs = ~[]; let fields; @@ -76,7 +80,7 @@ fn iter_bytes_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @ _ => cx.span_bug(span, "Impossible substructure in `deriving(IterBytes)`") } - for fields.each |&(_, field, _)| { + for fields.iter().advance |&(_, field, _)| { exprs.push(call_iterbytes(field)); } diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index f5170d284c6..537d9efbb26 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -18,8 +18,6 @@ library. */ -use core::prelude::*; - use ast::{enum_def, ident, item, Generics, meta_item, struct_def}; use ext::base::ExtCtxt; use ext::build::AstBuilder; diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index b890623b963..cc2050d9bd7 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast; use ast::{meta_item, item, expr, ident}; use codemap::span; @@ -17,7 +15,7 @@ use ext::base::ExtCtxt; use ext::build::{AstBuilder, Duplicate}; use ext::deriving::generic::*; -use core::vec; +use std::vec; pub fn expand_deriving_rand(cx: @ExtCtxt, span: span, @@ -93,7 +91,7 @@ fn rand_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { let rand_variant = cx.expr_binary(span, ast::rem, rv_call, variant_count); - let mut arms = do variants.mapi |i, id_sum| { + let mut arms = do variants.iter().enumerate().transform |(i, id_sum)| { let i_expr = cx.expr_uint(span, i); let pat = cx.pat_lit(span, i_expr); @@ -101,10 +99,10 @@ fn rand_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { (ident, ref summary) => { cx.arm(span, ~[ pat ], - rand_thing(cx, span, ident, summary, rand_call)) + rand_thing(cx, span, ident, summary, || rand_call())) } } - }; + }.collect::<~[ast::arm]>(); // _ => {} at the end. Should never occur arms.push(cx.arm_unreachable(span)); diff --git a/src/libsyntax/ext/deriving/to_str.rs b/src/libsyntax/ext/deriving/to_str.rs index 41be3a775c1..c9d63d2c416 100644 --- a/src/libsyntax/ext/deriving/to_str.rs +++ b/src/libsyntax/ext/deriving/to_str.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - +use ast; use ast::{meta_item, item, expr}; use codemap::span; use ext::base::ExtCtxt; @@ -31,7 +30,7 @@ pub fn expand_deriving_to_str(cx: @ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: ~[], - ret_ty: Ptr(~Literal(Path::new_local("str")), Owned), + ret_ty: Ptr(~Literal(Path::new_local("str")), Send), const_nonmatching: false, combine_substructure: to_str_substructure } @@ -40,16 +39,68 @@ pub fn expand_deriving_to_str(cx: @ExtCtxt, trait_def.expand(cx, span, mitem, in_items) } -fn to_str_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { - match substr.self_args { - [self_obj] => { - let self_addr = cx.expr_addr_of(span, self_obj); - cx.expr_call_global(span, - ~[cx.ident_of("std"), - cx.ident_of("sys"), - cx.ident_of("log_str")], - ~[self_addr]) +// It used to be the case that this deriving implementation invoked +// std::sys::log_str, but this isn't sufficient because it doesn't invoke the +// to_str() method on each field. Hence we mirror the logic of the log_str() +// method, but with tweaks to call to_str() on sub-fields. +fn to_str_substructure(cx: @ExtCtxt, span: span, + substr: &Substructure) -> @expr { + let to_str = cx.ident_of("to_str"); + + let doit = |start: &str, end: @str, name: ast::ident, + fields: &[(Option<ast::ident>, @expr, ~[@expr])]| { + if fields.len() == 0 { + cx.expr_str_uniq(span, cx.str_of(name)) + } else { + let buf = cx.ident_of("buf"); + let start = cx.str_of(name) + start; + let init = cx.expr_str_uniq(span, start.to_managed()); + let mut stmts = ~[cx.stmt_let(span, true, buf, init)]; + let push_str = cx.ident_of("push_str"); + + let push = |s: @expr| { + let ebuf = cx.expr_ident(span, buf); + let call = cx.expr_method_call(span, ebuf, push_str, ~[s]); + stmts.push(cx.stmt_expr(call)); + }; + + for fields.iter().enumerate().advance |(i, &(name, e, _))| { + if i > 0 { + push(cx.expr_str(span, @", ")); + } + match name { + None => {} + Some(id) => { + let name = cx.str_of(id) + ": "; + push(cx.expr_str(span, name.to_managed())); + } + } + push(cx.expr_method_call(span, e, to_str, ~[])); + } + push(cx.expr_str(span, end)); + + cx.expr_blk(cx.blk(span, stmts, Some(cx.expr_ident(span, buf)))) } - _ => cx.span_bug(span, "Invalid number of arguments in `deriving(ToStr)`") - } + }; + + return match *substr.fields { + Struct(ref fields) => { + if fields.len() == 0 || fields[0].n0_ref().is_none() { + doit("(", @")", substr.type_ident, *fields) + } else { + doit("{", @"}", substr.type_ident, *fields) + } + } + + EnumMatching(_, variant, ref fields) => { + match variant.node.kind { + ast::tuple_variant_kind(*) => + doit("(", @")", variant.node.name, *fields), + ast::struct_variant_kind(*) => + doit("{", @"}", variant.node.name, *fields), + } + } + + _ => cx.bug("expected Struct or EnumMatching in deriving(ToStr)") + }; } diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index 3b39cb691a6..e210853bfb4 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -13,8 +13,6 @@ A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use when specifying impls to be derived. */ -use core::prelude::*; - use ast; use ast::{expr,Generics,ident}; use ext::base::ExtCtxt; @@ -24,12 +22,12 @@ use opt_vec; /// The types of pointers pub enum PtrTy<'self> { - Owned, // ~ + Send, // ~ Managed(ast::mutability), // @[mut] Borrowed(Option<&'self str>, ast::mutability), // &['lifetime] [mut] } -/// A path, e.g. `::core::option::Option::<int>` (global). Has support +/// A path, e.g. `::std::option::Option::<int>` (global). Has support /// for type parameters and a lifetime. pub struct Path<'self> { path: ~[&'self str], @@ -65,7 +63,7 @@ impl<'self> Path<'self> { self_generics: &Generics) -> @ast::Ty { cx.ty_path(self.to_path(cx, span, - self_ty, self_generics)) + self_ty, self_generics), @None) } pub fn to_path(&self, cx: @ExtCtxt, @@ -130,7 +128,7 @@ impl<'self> Ty<'self> { Ptr(ref ty, ref ptr) => { let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); match *ptr { - Owned => { + Send => { cx.ty_uniq(span, raw_ty) } Managed(mutbl) => { @@ -144,7 +142,8 @@ impl<'self> Ty<'self> { } Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) } Self => { - cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) + cx.ty_path(self.to_path(cx, span, self_ty, self_generics), + @None) } Tuple(ref fields) => { let ty = if fields.is_empty() { @@ -249,7 +248,7 @@ pub fn get_explicit_self(cx: @ExtCtxt, span: span, self_ptr: &Option<PtrTy>) let self_ty = respan( span, match *ptr { - Owned => ast::sty_uniq(ast::m_imm), + Send => ast::sty_uniq, Managed(mutbl) => ast::sty_box(mutbl), Borrowed(ref lt, mutbl) => { let lt = lt.map(|s| @cx.lifetime(span, diff --git a/src/libsyntax/ext/deriving/zero.rs b/src/libsyntax/ext/deriving/zero.rs index 121d8351ee4..471e7212352 100644 --- a/src/libsyntax/ext/deriving/zero.rs +++ b/src/libsyntax/ext/deriving/zero.rs @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast::{meta_item, item, expr}; use codemap::span; use ext::base::ExtCtxt; use ext::build::AstBuilder; use ext::deriving::generic::*; -use core::vec; +use std::vec; pub fn expand_deriving_zero(cx: @ExtCtxt, span: span, diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index 34be6fc8143..a6cb6155878 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -14,15 +14,13 @@ * interface. */ -use core::prelude::*; - use ast; use codemap::span; use ext::base::*; use ext::base; use ext::build::AstBuilder; -use core::os; +use std::os; pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 2e7e8240bc0..15f915ba4d8 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast::{blk_, attribute_, attr_outer, meta_word}; use ast::{crate, expr_, expr_mac, mac_invoc_tt}; use ast::{item_mac, stmt_, stmt_mac, stmt_expr, stmt_semi}; @@ -27,7 +25,7 @@ use parse::token::{ident_to_str, intern}; use visit; use visit::Visitor; -use core::vec; +use std::vec; pub fn expand_expr(extsbox: @mut SyntaxEnv, cx: @ExtCtxt, @@ -200,7 +198,7 @@ pub fn expand_item(extsbox: @mut SyntaxEnv, // does this attribute list contain "macro_escape" ? pub fn contains_macro_escape (attrs: &[ast::attribute]) -> bool { - attrs.any(|attr| "macro_escape" == attr::get_attr_name(attr)) + attrs.iter().any_(|attr| "macro_escape" == attr::get_attr_name(attr)) } // Support for item-position macro invocations, exactly the same @@ -425,8 +423,8 @@ fn renames_to_fold(renames : @mut ~[(ast::ident,ast::Name)]) -> @ast_fold { fold_ident: |id,_| { // the individual elements are memoized... it would // also be possible to memoize on the whole list at once. - let new_ctxt = renames.foldl(id.ctxt,|ctxt,&(from,to)| { - new_rename(from,to,*ctxt) + let new_ctxt = renames.iter().fold(id.ctxt,|ctxt,&(from,to)| { + new_rename(from,to,ctxt) }); ast::ident{name:id.name,ctxt:new_ctxt} }, @@ -646,7 +644,7 @@ pub fn core_macros() -> @str { } pub fn expand_crate(parse_sess: @mut parse::ParseSess, - cfg: ast::crate_cfg, c: @crate) -> @crate { + cfg: ast::crate_cfg, c: &crate) -> @crate { // adding *another* layer of indirection here so that the block // visitor can swap out one exts table for another for the duration // of the block. The cleaner alternative would be to thread the @@ -697,7 +695,7 @@ pub fn expand_crate(parse_sess: @mut parse::ParseSess, // as it registers all the core macros as expanders. f.fold_item(cm); - @f.fold_crate(&*c) + @f.fold_crate(c) } // given a function from idents to idents, produce @@ -758,8 +756,6 @@ mod test { use util::parser_testing::{string_to_item, string_to_pat, strs_to_idents}; use visit::{mk_vt}; - use core::option::{None, Some}; - // make sure that fail! is present #[test] fn fail_exists_test () { let src = @"fn main() { fail!(\"something appropriately gloomy\");}"; diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 74496ac5359..76073199f64 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -14,17 +14,15 @@ * compiler syntax extension plugin interface. */ -use core::prelude::*; - use ast; use codemap::span; use ext::base::*; use ext::base; use ext::build::AstBuilder; -use core::option; -use core::unstable::extfmt::ct::*; -use core::vec; +use std::option; +use std::unstable::extfmt::ct::*; +use std::vec; use parse::token::{str_to_ident}; pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) @@ -70,7 +68,7 @@ fn pieces_to_expr(cx: @ExtCtxt, sp: span, fn make_rt_conv_expr(cx: @ExtCtxt, sp: span, cnv: &Conv) -> @ast::expr { fn make_flags(cx: @ExtCtxt, sp: span, flags: &[Flag]) -> @ast::expr { let mut tmp_expr = make_rt_path_expr(cx, sp, "flag_none"); - for flags.each |f| { + for flags.iter().advance |f| { let fstr = match *f { FlagLeftJustify => "flag_left_justify", FlagLeftZeroPad => "flag_left_zero_pad", @@ -156,7 +154,7 @@ fn pieces_to_expr(cx: @ExtCtxt, sp: span, option::None => (), _ => cx.span_unimpl(sp, unsupported) } - for cnv.flags.each |f| { + for cnv.flags.iter().advance |f| { match *f { FlagLeftJustify => (), FlagSignAlways => { @@ -205,7 +203,7 @@ fn pieces_to_expr(cx: @ExtCtxt, sp: span, Some(p) => { debug!("param: %s", p.to_str()); } _ => debug!("param: none") } - for c.flags.each |f| { + for c.flags.iter().advance |f| { match *f { FlagLeftJustify => debug!("flag: left justify"), FlagLeftZeroPad => debug!("flag: left zero pad"), @@ -249,6 +247,11 @@ fn pieces_to_expr(cx: @ExtCtxt, sp: span, } } + /* Short circuit an easy case up front (won't work otherwise) */ + if pieces.len() == 0 { + return cx.expr_str_uniq(args[0].span, @""); + } + let fmt_sp = args[0].span; let mut n = 0u; let nargs = args.len(); @@ -262,7 +265,7 @@ fn pieces_to_expr(cx: @ExtCtxt, sp: span, let mut stms = ~[]; /* Translate each piece (portion of the fmt expression) by invoking the - corresponding function in core::unstable::extfmt. Each function takes a + corresponding function in std::unstable::extfmt. Each function takes a buffer to insert data into along with the data being formatted. */ let npieces = pieces.len(); do vec::consume(pieces) |i, pc| { diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index 4b61d4da218..5b789cbc26c 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - -use core::vec; use ast; use codemap; use ext::base::*; @@ -18,7 +15,8 @@ use ext::base; use print; use parse::token::{get_ident_interner}; -use core::io; +use std::vec; +use std::io; pub fn expand_syntax_ext(cx: @ExtCtxt, sp: codemap::span, diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs index 99ffd78d7ba..1af6e7810a5 100644 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ b/src/libsyntax/ext/pipes/ast_builder.rs @@ -13,13 +13,11 @@ // To start with, it will be use dummy spans, but it might someday do // something smarter. -use core::prelude::*; - use ast::ident; use ast; use codemap::span; -use core::vec; +use std::vec; // Transitional reexports so qquote can find the paths it is looking for mod syntax { diff --git a/src/libsyntax/ext/pipes/check.rs b/src/libsyntax/ext/pipes/check.rs index c1b9b051ec9..8c2898737a3 100644 --- a/src/libsyntax/ext/pipes/check.rs +++ b/src/libsyntax/ext/pipes/check.rs @@ -29,8 +29,6 @@ that. */ -use core::prelude::*; - use ast; use codemap::span; use ext::base::ExtCtxt; diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs index 1076c5d0b98..b1f98d78fb3 100644 --- a/src/libsyntax/ext/pipes/liveness.rs +++ b/src/libsyntax/ext/pipes/liveness.rs @@ -37,8 +37,6 @@ updating the states using rule (2) until there are no changes. */ -use core::prelude::*; - use ext::base::ExtCtxt; use ext::pipes::proto::{protocol_}; @@ -47,13 +45,13 @@ use extra::bitv::Bitv; pub fn analyze(proto: @mut protocol_, _cx: @ExtCtxt) { debug!("initializing colive analysis"); let num_states = proto.num_states(); - let mut colive = do (copy proto.states).map_to_vec |state| { + let mut colive: ~[~Bitv] = do (copy proto.states).iter().transform() |state| { let mut bv = ~Bitv::new(num_states, false); for state.reachable |s| { bv.set(s.id, true); } bv - }; + }.collect(); let mut i = 0; let mut changed = true; @@ -61,7 +59,7 @@ pub fn analyze(proto: @mut protocol_, _cx: @ExtCtxt) { changed = false; debug!("colive iteration %?", i); let mut new_colive = ~[]; - for colive.eachi |i, this_colive| { + for colive.iter().enumerate().advance |(i, this_colive)| { let mut result = this_colive.clone(); let this = proto.get_state_by_id(i); for this_colive.ones |j| { @@ -80,7 +78,7 @@ pub fn analyze(proto: @mut protocol_, _cx: @ExtCtxt) { // Determine if we're bounded let mut self_live = ~[]; - for colive.eachi |i, bv| { + for colive.iter().enumerate().advance |(i, bv)| { if bv.get(i) { self_live.push(proto.get_state_by_id(i)) } diff --git a/src/libsyntax/ext/pipes/mod.rs b/src/libsyntax/ext/pipes/mod.rs index 3f4b5ee54f1..165d3c39c6b 100644 --- a/src/libsyntax/ext/pipes/mod.rs +++ b/src/libsyntax/ext/pipes/mod.rs @@ -52,7 +52,6 @@ use ext::pipes::pipec::gen_init; use ext::pipes::proto::visit; use parse::lexer::{new_tt_reader, reader}; use parse::parser::Parser; -use core::option::None; pub mod ast_builder; pub mod parse_proto; diff --git a/src/libsyntax/ext/pipes/parse_proto.rs b/src/libsyntax/ext/pipes/parse_proto.rs index 11db1a5da29..21bb8266239 100644 --- a/src/libsyntax/ext/pipes/parse_proto.rs +++ b/src/libsyntax/ext/pipes/parse_proto.rs @@ -10,8 +10,6 @@ // Parsing pipes protocols from token trees. -use core::prelude::*; - use ast_util; use ext::pipes::proto::*; use parse::common::SeqSep; diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index 9adbbb7d7f3..0e24725ea99 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -10,8 +10,6 @@ // A protocol compiler for Rust. -use core::prelude::*; - use ast; use codemap::{dummy_sp, spanned}; use ext::base::ExtCtxt; @@ -23,7 +21,7 @@ use ext::quote::rt::*; use opt_vec; use opt_vec::OptVec; -use core::vec; +use std::vec; pub trait gen_send { fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item; @@ -56,19 +54,20 @@ impl gen_send for message { let next = this.proto.get_state(next_state.state); assert!(next_state.tys.len() == next.generics.ty_params.len()); - let arg_names = tys.mapi(|i, _ty| cx.ident_of(~"x_"+i.to_str())); - let args_ast = vec::map_zip(arg_names, *tys, |n, t| cx.arg(span, *n, *t)); + let arg_names = vec::from_fn(tys.len(), |i| cx.ident_of("x_"+i.to_str())); + let args_ast: ~[ast::arg] = arg_names.iter().zip(tys.iter()) + .transform(|(n, t)| cx.arg(span, *n, *t)).collect(); let pipe_ty = cx.ty_path( path(~[this.data_name()], span) - .add_tys(cx.ty_vars(&this.generics.ty_params))); + .add_tys(cx.ty_vars(&this.generics.ty_params)), @None); let args_ast = vec::append( ~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)], args_ast); let mut body = ~"{\n"; - body += fmt!("use super::%s;\n", name); - body += "let mut pipe = pipe;\n"; + body.push_str(fmt!("use super::%s;\n", name)); + body.push_str("let mut pipe = pipe;\n"); if this.proto.is_bounded() { let (sp, rp) = match (this.dir, next.dir) { @@ -78,13 +77,15 @@ impl gen_send for message { (recv, recv) => (~"c", ~"s") }; - body += "let mut b = pipe.reuse_buffer();\n"; - body += fmt!("let %s = ::std::pipes::SendPacketBuffered(\ - &mut (b.buffer.data.%s));\n", - sp, next.name); - body += fmt!("let %s = ::std::pipes::RecvPacketBuffered(\ - &mut (b.buffer.data.%s));\n", - rp, next.name); + body.push_str("let mut b = pipe.reuse_buffer();\n"); + body.push_str(fmt!("let %s = ::std::pipes::SendPacketBuffered(\ + &mut (b.buffer.data.%s));\n", + sp, + next.name)); + body.push_str(fmt!("let %s = ::std::pipes::RecvPacketBuffered(\ + &mut (b.buffer.data.%s));\n", + rp, + next.name)); } else { let pat = match (this.dir, next.dir) { @@ -94,30 +95,29 @@ impl gen_send for message { (recv, recv) => "(s, c)" }; - body += fmt!("let %s = ::std::pipes::entangle();\n", pat); + body.push_str(fmt!("let %s = ::std::pipes::entangle();\n", pat)); } - body += fmt!("let message = %s(%s);\n", - name, - vec::append_one( - arg_names.map(|x| cx.str_of(*x)), - @"s").connect(", ")); + body.push_str(fmt!("let message = %s(%s);\n", + name, + vec::append_one(arg_names.map(|x| cx.str_of(*x)), @"s") + .connect(", "))); if !try { - body += fmt!("::std::pipes::send(pipe, message);\n"); + body.push_str(fmt!("::std::pipes::send(pipe, message);\n")); // return the new channel - body += "c }"; + body.push_str("c }"); } else { - body += fmt!("if ::std::pipes::send(pipe, message) {\n \ + body.push_str(fmt!("if ::std::pipes::send(pipe, message) {\n \ ::std::pipes::rt::make_some(c) \ - } else { ::std::pipes::rt::make_none() } }"); + } else { ::std::pipes::rt::make_none() } }")); } let body = cx.parse_expr(body.to_managed()); let mut rty = cx.ty_path(path(~[next.data_name()], span) - .add_tys(copy next_state.tys)); + .add_tys(copy next_state.tys), @None); if try { rty = cx.ty_option(rty); } @@ -134,11 +134,10 @@ impl gen_send for message { message(ref _id, span, ref tys, this, None) => { debug!("pipec: no next state"); - let arg_names = tys.mapi(|i, _ty| (~"x_" + i.to_str())); + let arg_names = vec::from_fn(tys.len(), |i| "x_" + i.to_str()); - let args_ast = do vec::map_zip(arg_names, *tys) |n, t| { - cx.arg(span, cx.ident_of(*n), *t) - }; + let args_ast: ~[ast::arg] = arg_names.iter().zip(tys.iter()) + .transform(|(n, t)| cx.arg(span, cx.ident_of(*n), *t)).collect(); let args_ast = vec::append( ~[cx.arg(span, @@ -146,7 +145,7 @@ impl gen_send for message { cx.ty_path( path(~[this.data_name()], span) .add_tys(cx.ty_vars( - &this.generics.ty_params))))], + &this.generics.ty_params)), @None))], args_ast); let message_args = if arg_names.len() == 0 { @@ -157,19 +156,19 @@ impl gen_send for message { }; let mut body = ~"{ "; - body += fmt!("use super::%s;\n", name); - body += fmt!("let message = %s%s;\n", name, message_args); + body.push_str(fmt!("use super::%s;\n", name)); + body.push_str(fmt!("let message = %s%s;\n", name, message_args)); if !try { - body += fmt!("::std::pipes::send(pipe, message);\n"); - body += " }"; + body.push_str(fmt!("::std::pipes::send(pipe, message);\n")); + body.push_str(" }"); } else { - body += fmt!("if ::std::pipes::send(pipe, message) \ + body.push_str(fmt!("if ::std::pipes::send(pipe, message) \ { \ ::std::pipes::rt::make_some(()) \ } else { \ ::std::pipes::rt::make_none() \ - } }"); + } }")); } let body = cx.parse_expr(body.to_managed()); @@ -192,7 +191,7 @@ impl gen_send for message { fn to_ty(&mut self, cx: @ExtCtxt) -> @ast::Ty { cx.ty_path(path(~[cx.ident_of(self.name())], self.span()) - .add_tys(cx.ty_vars(&self.get_generics().ty_params))) + .add_tys(cx.ty_vars(&self.get_generics().ty_params)), @None) } } @@ -209,7 +208,7 @@ impl to_type_decls for state { let mut items_msg = ~[]; - for self.messages.each |m| { + for self.messages.iter().advance |m| { let message(name, span, tys, this, next) = copy *m; let tys = match next { @@ -226,7 +225,7 @@ impl to_type_decls for state { cx.ty_path( path(~[cx.ident_of(dir), cx.ident_of(next_name)], span) - .add_tys(copy next_state.tys))) + .add_tys(copy next_state.tys), @None)) } None => tys }; @@ -279,7 +278,8 @@ impl to_type_decls for state { self.data_name()], dummy_sp()) .add_tys(cx.ty_vars( - &self.generics.ty_params))))), + &self.generics.ty_params)), @None)), + @None), cx.strip_bounds(&self.generics))); } else { @@ -298,8 +298,8 @@ impl to_type_decls for state { self.data_name()], dummy_sp()) .add_tys(cx.ty_vars_global( - &self.generics.ty_params))), - self.proto.buffer_ty_path(cx)])), + &self.generics.ty_params)), @None), + self.proto.buffer_ty_path(cx)]), @None), cx.strip_bounds(&self.generics))); }; items @@ -333,14 +333,14 @@ impl gen_init for protocol { dummy_sp(), path(~[ext_cx.ident_of("__Buffer")], dummy_sp()), - self.states.map_to_vec(|s| { + self.states.iter().transform(|s| { let fty = s.to_ty(ext_cx); ext_cx.field_imm(dummy_sp(), ext_cx.ident_of(s.name), quote_expr!( ::std::pipes::mk_packet::<$fty>() )) - })) + }).collect()) } fn gen_init_bounded(&self, ext_cx: @ExtCtxt) -> @ast::expr { @@ -354,10 +354,10 @@ impl gen_init for protocol { let entangle_body = ext_cx.expr_blk( ext_cx.blk( dummy_sp(), - self.states.map_to_vec( + self.states.iter().transform( |s| ext_cx.parse_stmt( fmt!("data.%s.set_buffer(buffer)", - s.name).to_managed())), + s.name).to_managed())).collect(), Some(ext_cx.parse_expr(fmt!( "::std::ptr::to_mut_unsafe_ptr(&mut (data.%s))", self.states[0].name).to_managed())))); @@ -372,9 +372,9 @@ impl gen_init for protocol { fn buffer_ty_path(&self, cx: @ExtCtxt) -> @ast::Ty { let mut params: OptVec<ast::TyParam> = opt_vec::Empty; - for (copy self.states).each |s| { - for s.generics.ty_params.each |tp| { - match params.find(|tpp| tp.ident == tpp.ident) { + for (copy self.states).iter().advance |s| { + for s.generics.ty_params.iter().advance |tp| { + match params.iter().find_(|tpp| tp.ident == tpp.ident) { None => params.push(*tp), _ => () } @@ -384,15 +384,15 @@ impl gen_init for protocol { cx.ty_path(path(~[cx.ident_of("super"), cx.ident_of("__Buffer")], copy self.span) - .add_tys(cx.ty_vars_global(¶ms))) + .add_tys(cx.ty_vars_global(¶ms)), @None) } fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item { let ext_cx = cx; let mut params: OptVec<ast::TyParam> = opt_vec::Empty; - let fields = do (copy self.states).map_to_vec |s| { - for s.generics.ty_params.each |tp| { - match params.find(|tpp| tp.ident == tpp.ident) { + let fields = do (copy self.states).iter().transform |s| { + for s.generics.ty_params.iter().advance |tp| { + match params.iter().find_(|tpp| tp.ident == tpp.ident) { None => params.push(*tp), _ => () } @@ -411,7 +411,7 @@ impl gen_init for protocol { }, span: dummy_sp() } - }; + }.collect(); let generics = Generics { lifetimes: opt_vec::Empty, @@ -433,11 +433,11 @@ impl gen_init for protocol { let mut client_states = ~[]; let mut server_states = ~[]; - for (copy self.states).each |s| { - items += s.to_type_decls(cx); + for (copy self.states).iter().advance |s| { + items.push_all_move(s.to_type_decls(cx)); - client_states += s.to_endpoint_decls(cx, send); - server_states += s.to_endpoint_decls(cx, recv); + client_states.push_all_move(s.to_endpoint_decls(cx, send)); + server_states.push_all_move(s.to_endpoint_decls(cx, recv)); } if self.is_bounded() { diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs index 32714f37272..0525c666478 100644 --- a/src/libsyntax/ext/pipes/proto.rs +++ b/src/libsyntax/ext/pipes/proto.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast; use codemap::span; use ext::base::ExtCtxt; @@ -101,13 +99,13 @@ impl state_ { pub fn to_ty(&self, cx: @ExtCtxt) -> @ast::Ty { cx.ty_path (path(~[cx.ident_of(self.name)],self.span).add_tys( - cx.ty_vars(&self.generics.ty_params))) + cx.ty_vars(&self.generics.ty_params)), @None) } /// Iterate over the states that can be reached in one message /// from this state. pub fn reachable(&self, f: &fn(state) -> bool) -> bool { - for self.messages.each |m| { + for self.messages.iter().advance |m| { match *m { message(_, _, _, _, Some(next_state { state: ref id, _ })) => { let state = self.proto.get_state((*id)); @@ -146,13 +144,13 @@ pub struct protocol_ { impl protocol_ { /// Get a state. pub fn get_state(&self, name: &str) -> state { - self.states.find(|i| name == i.name).get() + *self.states.iter().find_(|i| name == i.name).get() } pub fn get_state_by_id(&self, id: uint) -> state { self.states[id] } pub fn has_state(&self, name: &str) -> bool { - self.states.find(|i| name == i.name).is_some() + self.states.iter().find_(|i| name == i.name).is_some() } pub fn filename(&self) -> ~str { @@ -165,7 +163,7 @@ impl protocol_ { } pub fn has_ty_params(&self) -> bool { - for self.states.each |s| { + for self.states.iter().advance |s| { if s.generics.ty_params.len() > 0 { return true; } @@ -216,12 +214,12 @@ pub fn visit<Tproto, Tstate, Tmessage, V: visitor<Tproto, Tstate, Tmessage>>( proto: protocol, visitor: V) -> Tproto { // the copy keywords prevent recursive use of dvec - let states = do (copy proto.states).map_to_vec |&s| { - let messages = do (copy s.messages).map_to_vec |&m| { + let states: ~[Tstate] = do (copy proto.states).iter().transform |&s| { + let messages: ~[Tmessage] = do (copy s.messages).iter().transform |&m| { let message(name, span, tys, this, next) = m; visitor.visit_message(name, span, tys, this, next) - }; + }.collect(); visitor.visit_state(s, messages) - }; + }.collect(); visitor.visit_proto(proto, states) } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 44e480dc7df..db1902753a3 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - -use core::vec; use ast; use codemap::{BytePos, Pos, span}; use ext::base::ExtCtxt; @@ -20,6 +17,8 @@ use parse::token::*; use parse::token; use parse; +use std::vec; + /** * * Quasiquoting works via token trees. @@ -32,8 +31,6 @@ use parse; */ pub mod rt { - use core::prelude::*; - use ast; use ext::base::ExtCtxt; use parse; @@ -637,7 +634,7 @@ fn mk_tt(cx: @ExtCtxt, sp: span, tt: &ast::token_tree) fn mk_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) -> ~[@ast::stmt] { let mut ss = ~[]; - for tts.each |tt| { + for tts.iter().advance |tt| { ss.push_all_move(mk_tt(cx, sp, tt)); } ss diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index d92f4e8458b..f6325c2eb2c 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast; use codemap; use codemap::{Pos, ExpandedFrom, span}; @@ -21,9 +19,8 @@ use parse; use parse::token::{get_ident_interner}; use print::pprust; -use core::io; -use core::result; -use core::vec; +use std::io; +use std::result; // These macros all relate to the file system; they either return // the column/row/filename of the expression, or they include @@ -108,9 +105,7 @@ pub fn expand_include_bin(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) let file = get_single_str_from_tts(cx, sp, tts, "include_bin!"); match io::read_whole_file(&res_rel_file(cx, sp, &Path(file))) { result::Ok(src) => { - let u8_exprs = vec::map(src, |char| { - cx.expr_u8(sp, *char) - }); + let u8_exprs: ~[@ast::expr] = src.iter().transform(|char| cx.expr_u8(sp, *char)).collect(); base::MRExpr(cx.expr_vec(sp, u8_exprs)) } result::Err(ref e) => { diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs index 09965b921c1..299706b2d40 100644 --- a/src/libsyntax/ext/trace_macros.rs +++ b/src/libsyntax/ext/trace_macros.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - -use core::vec; use ast; use codemap::span; use ext::base::ExtCtxt; @@ -19,6 +16,8 @@ use parse::lexer::{new_tt_reader, reader}; use parse::parser::Parser; use parse::token::keywords; +use std::vec; + pub fn expand_trace_macros(cx: @ExtCtxt, sp: span, tt: &[ast::token_tree]) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 3fb94bbce38..cddba358373 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -10,8 +10,6 @@ // Earley-like parser for macros. -use core::prelude::*; - use ast; use ast::{matcher, match_tok, match_seq, match_nonterminal, ident}; use codemap::{BytePos, mk_sp}; @@ -22,9 +20,9 @@ use parse::parser::Parser; use parse::token::{Token, EOF, to_str, nonterminal, get_ident_interner, ident_to_str}; use parse::token; -use core::hashmap::HashMap; -use core::uint; -use core::vec; +use std::hashmap::HashMap; +use std::uint; +use std::vec; /* This is an Earley-like parser, without support for in-grammar nonterminals, only by calling out to the main rust parser for named nonterminals (which it @@ -138,7 +136,7 @@ pub fn count_names(ms: &[matcher]) -> uint { pub fn initial_matcher_pos(ms: ~[matcher], sep: Option<Token>, lo: BytePos) -> ~MatcherPos { let mut match_idx_hi = 0u; - for ms.each |elt| { + for ms.iter().advance |elt| { match elt.node { match_tok(_) => (), match_seq(_,_,_,_,hi) => { @@ -195,7 +193,7 @@ pub fn nameize(p_s: @mut ParseSess, ms: &[matcher], res: &[@named_match]) match *m { codemap::spanned {node: match_tok(_), _} => (), codemap::spanned {node: match_seq(ref more_ms, _, _, _, _), _} => { - for more_ms.each |next_m| { + for more_ms.iter().advance |next_m| { n_rec(p_s, next_m, res, ret_val) }; } @@ -211,8 +209,8 @@ pub fn nameize(p_s: @mut ParseSess, ms: &[matcher], res: &[@named_match]) } } let mut ret_val = HashMap::new(); - for ms.each |m| { n_rec(p_s, m, res, &mut ret_val) } - return ret_val; + for ms.iter().advance |m| { n_rec(p_s, m, res, &mut ret_val) } + ret_val } pub enum parse_result { @@ -328,8 +326,7 @@ pub fn parse( cur_eis.push(new_ei); } - let matches = vec::map(ei.matches, // fresh, same size: - |_m| ~[]); + let matches = vec::from_elem(ei.matches.len(), ~[]); let ei_t = ei; cur_eis.push(~MatcherPos { elts: copy *matchers, diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 7cca7162fc8..80dd0c7247b 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - -use core::vec; use ast::{ident, matcher_, matcher, match_tok, match_nonterminal, match_seq}; use ast::{tt_delim}; use ast; @@ -26,7 +23,8 @@ use parse::token::{get_ident_interner, special_idents, gensym_ident, ident_to_st use parse::token::{FAT_ARROW, SEMI, nt_matchers, nt_tt}; use print; -use core::io; +use std::vec; +use std::io; pub fn add_new_extension(cx: @ExtCtxt, sp: span, @@ -94,7 +92,7 @@ pub fn add_new_extension(cx: @ExtCtxt, let s_d = cx.parse_sess().span_diagnostic; - for lhses.eachi |i, lhs| { // try each arm's matchers + for lhses.iter().enumerate().advance |(i, lhs)| { // try each arm's matchers match *lhs { @matched_nonterminal(nt_matchers(ref mtcs)) => { // `none` is because we're not interpolating diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index abefbedaff0..92feaa154fe 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast; use ast::{token_tree, tt_delim, tt_tok, tt_seq, tt_nonterminal,ident}; use codemap::{span, dummy_sp}; @@ -19,8 +17,8 @@ use parse::token::{EOF, INTERPOLATED, IDENT, Token, nt_ident}; use parse::token::{ident_to_str}; use parse::lexer::TokenAndSpan; -use core::hashmap::HashMap; -use core::option; +use std::hashmap::HashMap; +use std::option; ///an unzipping of `token_tree`s struct TtFrame { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index c1bf979cd31..4e145123996 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast::*; use ast; use codemap::{span, spanned}; use parse::token; use opt_vec::OptVec; -use core::vec; +use std::vec; pub trait ast_fold { fn fold_crate(@self, &crate) -> crate; @@ -236,8 +234,8 @@ fn noop_fold_foreign_item(ni: @foreign_item, fld: @ast_fold) purity, fold_generics(generics, fld)) } - foreign_item_const(t) => { - foreign_item_const(fld.fold_ty(t)) + foreign_item_static(t, m) => { + foreign_item_static(fld.fold_ty(t), m) } }, id: fld.new_id(ni.id), @@ -270,7 +268,7 @@ fn noop_fold_struct_field(sf: @struct_field, fld: @ast_fold) pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ { match *i { - item_const(t, e) => item_const(fld.fold_ty(t), fld.fold_expr(e)), + item_static(t, m, e) => item_static(fld.fold_ty(t), m, fld.fold_expr(e)), item_fn(ref decl, purity, abi, ref generics, ref body) => { item_fn( fold_fn_decl(decl, fld), @@ -378,7 +376,7 @@ fn noop_fold_method(m: @method, fld: @ast_fold) -> @method { pub fn noop_fold_block(b: &blk_, fld: @ast_fold) -> blk_ { let view_items = b.view_items.map(|x| fld.fold_view_item(*x)); let mut stmts = ~[]; - for b.stmts.each |stmt| { + for b.stmts.iter().advance |stmt| { match fld.fold_stmt(*stmt) { None => {} Some(stmt) => stmts.push(stmt) @@ -653,6 +651,12 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ { span: fld.new_span(f.span), } } + fn fold_opt_bounds(b: &Option<OptVec<TyParamBound>>, fld: @ast_fold) + -> Option<OptVec<TyParamBound>> { + do b.map |bounds| { + do bounds.map |bound| { fold_ty_param_bound(bound, fld) } + } + } match *t { ty_nil | ty_bot | ty_infer => copy *t, ty_box(ref mt) => ty_box(fold_mt(mt, fld)), @@ -666,7 +670,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ { purity: f.purity, region: f.region, onceness: f.onceness, - bounds: f.bounds.map(|x| fold_ty_param_bound(x, fld)), + bounds: fold_opt_bounds(&f.bounds, fld), decl: fold_fn_decl(&f.decl, fld), lifetimes: copy f.lifetimes, }) @@ -680,7 +684,8 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ { }) } ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(*ty))), - ty_path(path, id) => ty_path(fld.fold_path(path), fld.new_id(id)), + ty_path(path, bounds, id) => + ty_path(fld.fold_path(path), @fold_opt_bounds(bounds, fld), fld.new_id(id)), ty_fixed_length_vec(ref mt, e) => { ty_fixed_length_vec( fold_mt(mt, fld), @@ -694,7 +699,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ { // ...nor do modules pub fn noop_fold_mod(m: &_mod, fld: @ast_fold) -> _mod { ast::_mod { - view_items: vec::map(m.view_items, |x| fld.fold_view_item(*x)), + view_items: m.view_items.iter().transform(|x| fld.fold_view_item(*x)).collect(), items: vec::filter_mapped(m.items, |x| fld.fold_item(*x)), } } @@ -703,8 +708,8 @@ fn noop_fold_foreign_mod(nm: &foreign_mod, fld: @ast_fold) -> foreign_mod { ast::foreign_mod { sort: nm.sort, abis: nm.abis, - view_items: vec::map(nm.view_items, |x| fld.fold_view_item(*x)), - items: vec::map(nm.items, |x| fld.fold_foreign_item(*x)), + view_items: nm.view_items.iter().transform(|x| fld.fold_view_item(*x)).collect(), + items: nm.items.iter().transform(|x| fld.fold_foreign_item(*x)).collect(), } } @@ -723,8 +728,8 @@ fn noop_fold_variant(v: &variant_, fld: @ast_fold) -> variant_ { } struct_variant_kind(struct_def) => { kind = struct_variant_kind(@ast::struct_def { - fields: vec::map(struct_def.fields, - |f| fld.fold_struct_field(*f)), + fields: struct_def.fields.iter() + .transform(|f| fld.fold_struct_field(*f)).collect(), ctor_id: struct_def.ctor_id.map(|c| fld.new_id(*c)) }) } @@ -819,8 +824,7 @@ impl ast_fold for AstFoldFns { @view_item { @ast::view_item { node: (self.fold_view_item)(&x.node, self as @ast_fold), - attrs: vec::map(x.attrs, |a| - fold_attribute_(*a, self as @ast_fold)), + attrs: x.attrs.iter().transform(|a| fold_attribute_(*a, self as @ast_fold)).collect(), vis: x.vis, span: (self.new_span)(x.span), } @@ -1009,5 +1013,4 @@ mod test { token::get_ident_interner()), ~"zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))"); } - } diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 81f540fd69f..bf8c5ae462b 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -16,12 +16,9 @@ * other useful things like `push()` and `len()`. */ -use core::prelude::*; +use std::vec::VecIterator; -use core::old_iter; -use core::old_iter::BaseIter; - -#[deriving(Encodable, Decodable)] +#[deriving(Encodable, Decodable,IterBytes)] pub enum OptVec<T> { Empty, Vec(~[T]) @@ -78,6 +75,28 @@ impl<T> OptVec<T> { Vec(ref v) => v.len() } } + + #[inline] + fn iter<'r>(&'r self) -> OptVecIterator<'r, T> { + match *self { + Empty => OptVecIterator{iter: None}, + Vec(ref v) => OptVecIterator{iter: Some(v.iter())} + } + } + + #[inline] + fn map_to_vec<B>(&self, op: &fn(&T) -> B) -> ~[B] { + self.iter().transform(op).collect() + } + + fn mapi_to_vec<B>(&self, op: &fn(uint, &T) -> B) -> ~[B] { + let mut index = 0; + self.map_to_vec(|a| { + let i = index; + index += 1; + op(i, a) + }) + } } pub fn take_vec<T>(v: OptVec<T>) -> ~[T] { @@ -96,22 +115,6 @@ impl<T:Copy> OptVec<T> { } return Vec(v0); } - - fn push_all<I: BaseIter<T>>(&mut self, from: &I) { - for from.each |e| { - self.push(copy *e); - } - } - - #[inline] - fn mapi_to_vec<B>(&self, op: &fn(uint, &T) -> B) -> ~[B] { - let mut index = 0; - old_iter::map_to_vec(self, |a| { - let i = index; - index += 1; - op(i, a) - }) - } } impl<A:Eq> Eq for OptVec<A> { @@ -131,68 +134,16 @@ impl<A:Eq> Eq for OptVec<A> { } } -impl<A> BaseIter<A> for OptVec<A> { - fn each(&self, blk: &fn(v: &A) -> bool) -> bool { - match *self { - Empty => true, - Vec(ref v) => v.each(blk) - } - } - - fn size_hint(&self) -> Option<uint> { - Some(self.len()) - } +pub struct OptVecIterator<'self, T> { + priv iter: Option<VecIterator<'self, T>> } -impl<A> old_iter::ExtendedIter<A> for OptVec<A> { - #[inline] - fn eachi(&self, blk: &fn(v: uint, v: &A) -> bool) -> bool { - old_iter::eachi(self, blk) - } - #[inline] - fn all(&self, blk: &fn(&A) -> bool) -> bool { - old_iter::all(self, blk) - } +impl<'self, T> Iterator<&'self T> for OptVecIterator<'self, T> { #[inline] - fn any(&self, blk: &fn(&A) -> bool) -> bool { - old_iter::any(self, blk) - } - #[inline] - fn foldl<B>(&self, b0: B, blk: &fn(&B, &A) -> B) -> B { - old_iter::foldl(self, b0, blk) - } - #[inline] - fn position(&self, f: &fn(&A) -> bool) -> Option<uint> { - old_iter::position(self, f) - } - #[inline] - fn map_to_vec<B>(&self, op: &fn(&A) -> B) -> ~[B] { - old_iter::map_to_vec(self, op) - } - #[inline] - fn flat_map_to_vec<B,IB:BaseIter<B>>(&self, op: &fn(&A) -> IB) - -> ~[B] { - old_iter::flat_map_to_vec(self, op) - } - -} - -impl<A: Eq> old_iter::EqIter<A> for OptVec<A> { - #[inline] - fn contains(&self, x: &A) -> bool { old_iter::contains(self, x) } - #[inline] - fn count(&self, x: &A) -> uint { old_iter::count(self, x) } -} - -impl<A: Copy> old_iter::CopyableIter<A> for OptVec<A> { - #[inline] - fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A] { - old_iter::filter_to_vec(self, pred) - } - #[inline] - fn to_vec(&self) -> ~[A] { old_iter::to_vec(self) } - #[inline] - fn find(&self, f: &fn(&A) -> bool) -> Option<A> { - old_iter::find(self, f) + fn next(&mut self) -> Option<&'self T> { + match self.iter { + Some(ref mut x) => x.next(), + None => None + } } } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index ddcad5c3e8f..d33b72ae3c9 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -42,7 +42,7 @@ impl parser_attr for Parser { if self.look_ahead(1u) != token::LBRACKET { break; } - attrs += [self.parse_attribute(ast::attr_outer)]; + attrs.push(self.parse_attribute(ast::attr_outer)); } token::DOC_COMMENT(s) => { let attr = ::attr::mk_sugared_doc_attr( @@ -53,7 +53,7 @@ impl parser_attr for Parser { if attr.node.style != ast::attr_outer { self.fatal("expected outer comment"); } - attrs += [attr]; + attrs.push(attr); self.bump(); } _ => break @@ -77,9 +77,7 @@ impl parser_attr for Parser { self.expect(&token::RBRACKET); let hi = self.span.hi; return spanned(lo, hi, ast::attribute_ { style: style, - value: meta_item, - is_sugared_doc: false }); - } + value: meta_item, is_sugared_doc: false }); } // Parse attributes that appear after the opening of an item, each // terminated by a semicolon. In addition to a vector of inner attributes, @@ -105,7 +103,7 @@ impl parser_attr for Parser { let attr = self.parse_attribute(ast::attr_inner); if *self.token == token::SEMI { self.bump(); - inner_attrs += [attr]; + inner_attrs.push(attr); } else { // It's not really an inner attribute let outer_attr = @@ -113,7 +111,7 @@ impl parser_attr for Parser { ast::attribute_ { style: ast::attr_outer, value: attr.node.value, is_sugared_doc: false }); - next_outer_attrs += [outer_attr]; + next_outer_attrs.push(outer_attr); break; } } @@ -125,9 +123,9 @@ impl parser_attr for Parser { ); self.bump(); if attr.node.style == ast::attr_inner { - inner_attrs += [attr]; + inner_attrs.push(attr); } else { - next_outer_attrs += [attr]; + next_outer_attrs.push(attr); break; } } diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs index 472f807cd8b..01af33b13b8 100644 --- a/src/libsyntax/parse/comments.rs +++ b/src/libsyntax/parse/comments.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast; use codemap::{BytePos, CharPos, CodeMap, Pos}; use diagnostic; @@ -20,9 +18,9 @@ use parse::lexer; use parse::token; use parse::token::{get_ident_interner}; -use core::io; -use core::str; -use core::uint; +use std::io; +use std::str; +use std::uint; #[deriving(Eq)] pub enum cmnt_style { @@ -256,7 +254,7 @@ fn read_block_comment(rdr: @mut StringReader, bump(rdr); } if !is_eof(rdr) { - curr_line += "*/"; + curr_line.push_str("*/"); bump(rdr); bump(rdr); } @@ -280,13 +278,13 @@ fn read_block_comment(rdr: @mut StringReader, if rdr.curr == '/' && nextch(rdr) == '*' { bump(rdr); bump(rdr); - curr_line += "*"; + curr_line.push_char('*'); level += 1; } else { if rdr.curr == '*' && nextch(rdr) == '/' { bump(rdr); bump(rdr); - curr_line += "/"; + curr_line.push_char('/'); level -= 1; } else { bump(rdr); } } diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index 0956fa7225f..12e32731fcc 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -8,19 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - -use ast; -use codemap::{BytePos, spanned}; -use parse::lexer::reader; -use parse::parser::Parser; -use parse::token::keywords; use parse::token; use parse::token::{get_ident_interner}; -use opt_vec; -use opt_vec::OptVec; - // SeqSep : a sequence separator (token) // and whether a trailing separator is allowed. pub struct SeqSep { @@ -53,251 +43,3 @@ pub fn token_to_str(token: &token::Token) -> ~str { token::to_str(get_ident_interner(), token) } -impl Parser { - // convert a token to a string using self's reader - pub fn token_to_str(&self, token: &token::Token) -> ~str { - token::to_str(get_ident_interner(), token) - } - - // convert the current token to a string using self's reader - pub fn this_token_to_str(&self) -> ~str { - self.token_to_str(self.token) - } - - pub fn unexpected_last(&self, t: &token::Token) -> ! { - self.span_fatal( - *self.last_span, - fmt!( - "unexpected token: `%s`", - self.token_to_str(t) - ) - ); - } - - pub fn unexpected(&self) -> ! { - self.fatal( - fmt!( - "unexpected token: `%s`", - self.this_token_to_str() - ) - ); - } - - // expect and consume the token t. Signal an error if - // the next token is not t. - pub fn expect(&self, t: &token::Token) { - if *self.token == *t { - self.bump(); - } else { - self.fatal( - fmt!( - "expected `%s` but found `%s`", - self.token_to_str(t), - self.this_token_to_str() - ) - ) - } - } - - pub fn parse_ident(&self) -> ast::ident { - self.check_strict_keywords(); - self.check_reserved_keywords(); - match *self.token { - token::IDENT(i, _) => { - self.bump(); - i - } - token::INTERPOLATED(token::nt_ident(*)) => { - self.bug("ident interpolation not converted to real token"); - } - _ => { - self.fatal( - fmt!( - "expected ident, found `%s`", - self.this_token_to_str() - ) - ); - } - } - } - - pub fn parse_path_list_ident(&self) -> ast::path_list_ident { - let lo = self.span.lo; - let ident = self.parse_ident(); - let hi = self.last_span.hi; - spanned(lo, hi, ast::path_list_ident_ { name: ident, - id: self.get_id() }) - } - - // consume token 'tok' if it exists. Returns true if the given - // token was present, false otherwise. - pub fn eat(&self, tok: &token::Token) -> bool { - return if *self.token == *tok { self.bump(); true } else { false }; - } - - pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { - token::is_keyword(kw, self.token) - } - - // if the next token is the given keyword, eat it and return - // true. Otherwise, return false. - pub fn eat_keyword(&self, kw: keywords::Keyword) -> bool { - let is_kw = match *self.token { - token::IDENT(sid, false) => kw.to_ident().name == sid.name, - _ => false - }; - if is_kw { self.bump() } - is_kw - } - - // if the given word is not a keyword, signal an error. - // if the next token is not the given word, signal an error. - // otherwise, eat it. - pub fn expect_keyword(&self, kw: keywords::Keyword) { - if !self.eat_keyword(kw) { - self.fatal( - fmt!( - "expected `%s`, found `%s`", - self.id_to_str(kw.to_ident()), - self.this_token_to_str() - ) - ); - } - } - - // signal an error if the given string is a strict keyword - pub fn check_strict_keywords(&self) { - if token::is_strict_keyword(self.token) { - self.span_err(*self.last_span, - fmt!("found `%s` in ident position", self.this_token_to_str())); - } - } - - // signal an error if the current token is a reserved keyword - pub fn check_reserved_keywords(&self) { - if token::is_reserved_keyword(self.token) { - self.fatal(fmt!("`%s` is a reserved keyword", self.this_token_to_str())); - } - } - - // expect and consume a GT. if a >> is seen, replace it - // with a single > and continue. If a GT is not seen, - // signal an error. - pub fn expect_gt(&self) { - if *self.token == token::GT { - self.bump(); - } else if *self.token == token::BINOP(token::SHR) { - self.replace_token( - token::GT, - self.span.lo + BytePos(1u), - self.span.hi - ); - } else { - let mut s: ~str = ~"expected `"; - s += self.token_to_str(&token::GT); - s += "`, found `"; - s += self.this_token_to_str(); - s += "`"; - self.fatal(s); - } - } - - // parse a sequence bracketed by '<' and '>', stopping - // before the '>'. - pub fn parse_seq_to_before_gt<T: Copy>(&self, - sep: Option<token::Token>, - f: &fn(&Parser) -> T) - -> OptVec<T> { - let mut first = true; - let mut v = opt_vec::Empty; - while *self.token != token::GT - && *self.token != token::BINOP(token::SHR) { - match sep { - Some(ref t) => { - if first { first = false; } - else { self.expect(t); } - } - _ => () - } - v.push(f(self)); - } - return v; - } - - pub fn parse_seq_to_gt<T: Copy>(&self, - sep: Option<token::Token>, - f: &fn(&Parser) -> T) - -> OptVec<T> { - let v = self.parse_seq_to_before_gt(sep, f); - self.expect_gt(); - return v; - } - - // parse a sequence, including the closing delimiter. The function - // f must consume tokens until reaching the next separator or - // closing bracket. - pub fn parse_seq_to_end<T: Copy>(&self, - ket: &token::Token, - sep: SeqSep, - f: &fn(&Parser) -> T) - -> ~[T] { - let val = self.parse_seq_to_before_end(ket, sep, f); - self.bump(); - val - } - - // parse a sequence, not including the closing delimiter. The function - // f must consume tokens until reaching the next separator or - // closing bracket. - pub fn parse_seq_to_before_end<T: Copy>(&self, - ket: &token::Token, - sep: SeqSep, - f: &fn(&Parser) -> T) - -> ~[T] { - let mut first: bool = true; - let mut v: ~[T] = ~[]; - while *self.token != *ket { - match sep.sep { - Some(ref t) => { - if first { first = false; } - else { self.expect(t); } - } - _ => () - } - if sep.trailing_sep_allowed && *self.token == *ket { break; } - v.push(f(self)); - } - return v; - } - - // parse a sequence, including the closing delimiter. The function - // f must consume tokens until reaching the next separator or - // closing bracket. - pub fn parse_unspanned_seq<T: Copy>(&self, - bra: &token::Token, - ket: &token::Token, - sep: SeqSep, - f: &fn(&Parser) -> T) - -> ~[T] { - self.expect(bra); - let result = self.parse_seq_to_before_end(ket, sep, f); - self.bump(); - result - } - - // NB: Do not use this function unless you actually plan to place the - // spanned list in the AST. - pub fn parse_seq<T: Copy>(&self, - bra: &token::Token, - ket: &token::Token, - sep: SeqSep, - f: &fn(&Parser) -> T) - -> spanned<~[T]> { - let lo = self.span.lo; - self.expect(bra); - let result = self.parse_seq_to_before_end(ket, sep, f); - let hi = self.span.hi; - self.bump(); - spanned(lo, hi, result) - } -} diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index ccc1cbd0d89..4a872832952 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast; use codemap::{BytePos, CharPos, CodeMap, Pos, span}; use codemap; @@ -19,9 +17,9 @@ use ext::tt::transcribe::{dup_tt_reader}; use parse::token; use parse::token::{str_to_ident}; -use core::char; -use core::either; -use core::u64; +use std::char; +use std::either; +use std::u64; pub use ext::tt::transcribe::{TtReader, new_tt_reader}; @@ -182,7 +180,7 @@ pub fn bump(rdr: &mut StringReader) { let byte_offset_diff = next.next - current_byte_offset; rdr.pos = rdr.pos + BytePos(byte_offset_diff); rdr.curr = next.ch; - rdr.col += CharPos(1u); + rdr.col = rdr.col + CharPos(1u); if last_char == '\n' { rdr.filemap.next_line(rdr.last_pos); rdr.col = CharPos(0u); @@ -450,8 +448,8 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token { is_float = true; bump(rdr); let dec_part = scan_digits(rdr, 10u); - num_str += "."; - num_str += dec_part; + num_str.push_char('.'); + num_str.push_str(dec_part); } if is_float { match base { @@ -463,7 +461,7 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token { match scan_exponent(rdr) { Some(ref s) => { is_float = true; - num_str += (*s); + num_str.push_str(*s); } None => () } @@ -789,7 +787,6 @@ mod test { use ast; use codemap::{BytePos, CodeMap, span}; - use core::option::None; use diagnostic; use parse::token; use parse::token::{str_to_ident}; @@ -835,7 +832,7 @@ mod test { // check that the given reader produces the desired stream // of tokens (stop checking after exhausting the expected vec) fn check_tokenization (env: Env, expected: ~[token::Token]) { - for expected.each |expected_tok| { + for expected.iter().advance |expected_tok| { let TokenAndSpan {tok:actual_tok, sp: _} = env.string_reader.next_token(); assert_eq!(&actual_tok,expected_tok); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 5edd2ec4d47..6dd8d4880e3 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -20,10 +20,8 @@ use parse::attr::parser_attr; use parse::lexer::reader; use parse::parser::Parser; -use core::io; -use core::option::{None, Option, Some}; -use core::path::Path; -use core::result::{Err, Ok}; +use std::io; +use std::path::Path; pub mod lexer; pub mod parser; @@ -335,9 +333,7 @@ mod test { use super::*; use extra::serialize::Encodable; use extra; - use core::io; - use core::option::Some; - use core::option::None; + use std::io; use codemap::{span, BytePos, spanned}; use opt_vec; use ast; @@ -494,7 +490,7 @@ mod test { idents:~[str_to_ident("int")], rp: None, types: ~[]}, - 2), + @None, 2), span:sp(4,7)}, pat: @ast::pat{id:1, node: ast::pat_ident(ast::bind_infer, @@ -530,7 +526,7 @@ mod test { idents:~[str_to_ident("int")], rp: None, types: ~[]}, - 2), + @None, 2), span:sp(10,13)}, pat: @ast::pat{id:1, // fixme node: ast::pat_ident( diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index bb315bf2933..fff4c125af6 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -17,8 +17,6 @@ Obsolete syntax that becomes too hard to parse can be removed. */ -use core::prelude::*; - use ast::{expr, expr_lit, lit_nil, attribute}; use ast; use codemap::{span, respan}; @@ -26,8 +24,8 @@ use parse::parser::Parser; use parse::token::{keywords, Token}; use parse::token; -use core::str; -use core::to_bytes; +use std::str; +use std::to_bytes; /// The specific types of unsupported syntax #[deriving(Eq)] @@ -46,7 +44,6 @@ pub enum ObsoleteSyntax { ObsoleteUnsafeBlock, ObsoleteUnenforcedBound, ObsoleteImplSyntax, - ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer, ObsoleteMutVector, ObsoleteImplVisibility, @@ -65,6 +62,8 @@ pub enum ObsoleteSyntax { ObsoleteFixedLengthVectorType, ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl, + ObsoleteMutWithMultipleBindings, + ObsoletePatternCopyKeyword, } impl to_bytes::IterBytes for ObsoleteSyntax { @@ -74,7 +73,26 @@ impl to_bytes::IterBytes for ObsoleteSyntax { } } -impl Parser { +pub trait ParserObsoleteMethods { + /// Reports an obsolete syntax non-fatal error. + fn obsolete(&self, sp: span, kind: ObsoleteSyntax); + // Reports an obsolete syntax non-fatal error, and returns + // a placeholder expression + fn obsolete_expr(&self, sp: span, kind: ObsoleteSyntax) -> @expr; + fn report(&self, + sp: span, + kind: ObsoleteSyntax, + kind_str: &str, + desc: &str); + fn token_is_obsolete_ident(&self, ident: &str, token: &Token) -> bool; + fn is_obsolete_ident(&self, ident: &str) -> bool; + fn eat_obsolete_ident(&self, ident: &str) -> bool; + fn try_parse_obsolete_struct_ctor(&self) -> bool; + fn try_parse_obsolete_with(&self) -> bool; + fn try_parse_obsolete_priv_section(&self, attrs: &[attribute]) -> bool; +} + +impl ParserObsoleteMethods for Parser { /// Reports an obsolete syntax non-fatal error. pub fn obsolete(&self, sp: span, kind: ObsoleteSyntax) { let (kind_str, desc) = match kind { @@ -128,7 +146,7 @@ impl Parser { ), ObsoleteSwap => ( "swap", - "Use core::util::{swap, replace} instead" + "Use std::util::{swap, replace} instead" ), ObsoleteUnsafeBlock => ( "non-standalone unsafe block", @@ -143,10 +161,6 @@ impl Parser { "colon-separated impl syntax", "write `impl Trait for Type`" ), - ObsoleteTraitBoundSeparator => ( - "space-separated trait bounds", - "write `+` between trait bounds" - ), ObsoleteMutOwnedPointer => ( "const or mutable owned pointer", "mutability inherits through `~` pointers; place the `~` box @@ -230,6 +244,15 @@ impl Parser { "instead of e.g. `let a = 1, b = 2`, write \ `let (a, b) = (1, 2)`." ), + ObsoleteMutWithMultipleBindings => ( + "`mut` with multiple bindings", + "use multiple local declarations instead of e.g. `let mut \ + (x, y) = ...`." + ), + ObsoletePatternCopyKeyword => ( + "`copy` in patterns", + "`copy` in patterns no longer has any effect" + ), }; self.report(sp, kind, kind_str, desc); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4e52b6b7367..cc0baa28e20 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use abi; use abi::AbiSet; use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil}; @@ -33,8 +31,8 @@ use ast::{expr_vec, expr_vstore, expr_vstore_mut_box}; use ast::{expr_vstore_slice, expr_vstore_box}; use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl}; use ast::{expr_vstore_uniq, Onceness, Once, Many}; -use ast::{foreign_item, foreign_item_const, foreign_item_fn, foreign_mod}; -use ast::{ident, impure_fn, inherited, item, item_, item_const}; +use ast::{foreign_item, foreign_item_static, foreign_item_fn, foreign_mod}; +use ast::{ident, impure_fn, inherited, item, item_, item_static}; use ast::{item_enum, item_fn, item_foreign_mod, item_impl}; use ast::{item_mac, item_mod, item_struct, item_trait, item_ty, lit, lit_}; use ast::{lit_bool, lit_float, lit_float_unsuffixed, lit_int}; @@ -60,13 +58,13 @@ use ast::{view_item_, view_item_extern_mod, view_item_use}; use ast::{view_path, view_path_glob, view_path_list, view_path_simple}; use ast::visibility; use ast; -use ast_util::{as_prec, ident_to_path, operator_prec}; +use ast_util::{as_prec, operator_prec}; use ast_util; use codemap::{span, BytePos, spanned, mk_sp}; use codemap; use parse::attr::parser_attr; use parse::classify; -use parse::common::{seq_sep_none}; +use parse::common::{SeqSep, seq_sep_none}; use parse::common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed}; use parse::lexer::reader; use parse::lexer::TokenAndSpan; @@ -75,7 +73,7 @@ use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator}; use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap}; use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds}; use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax}; -use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer}; +use parse::obsolete::{ObsoleteMutOwnedPointer}; use parse::obsolete::{ObsoleteMutVector, ObsoleteImplVisibility}; use parse::obsolete::{ObsoleteRecordType, ObsoleteRecordPattern}; use parse::obsolete::{ObsoletePostFnTySigil}; @@ -85,17 +83,21 @@ use parse::obsolete::{ObsoleteLifetimeNotation, ObsoleteConstManagedPointer}; use parse::obsolete::{ObsoletePurity, ObsoleteStaticMethod}; use parse::obsolete::{ObsoleteConstItem, ObsoleteFixedLengthVectorType}; use parse::obsolete::{ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl}; -use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident, is_ident_or_path}; -use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents, token_to_binop}; +use parse::obsolete::{ObsoleteMutWithMultipleBindings}; +use parse::obsolete::{ObsoletePatternCopyKeyword, ParserObsoleteMethods}; +use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident}; +use parse::token::{is_ident_or_path}; +use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents}; +use parse::token::{token_to_binop}; use parse::token; use parse::{new_sub_parser_from_file, next_node_id, ParseSess}; use opt_vec; use opt_vec::OptVec; -use core::either::Either; -use core::either; -use core::hashmap::HashSet; -use core::vec; +use std::either::Either; +use std::either; +use std::hashmap::HashSet; +use std::vec; #[deriving(Eq)] enum restriction { @@ -268,10 +270,257 @@ pub struct Parser { #[unsafe_destructor] impl Drop for Parser { /* do not copy the parser; its state is tied to outside state */ - fn finalize(&self) {} + fn drop(&self) {} } impl Parser { + // convert a token to a string using self's reader + pub fn token_to_str(&self, token: &token::Token) -> ~str { + token::to_str(get_ident_interner(), token) + } + + // convert the current token to a string using self's reader + pub fn this_token_to_str(&self) -> ~str { + self.token_to_str(self.token) + } + + pub fn unexpected_last(&self, t: &token::Token) -> ! { + self.span_fatal( + *self.last_span, + fmt!( + "unexpected token: `%s`", + self.token_to_str(t) + ) + ); + } + + pub fn unexpected(&self) -> ! { + self.fatal( + fmt!( + "unexpected token: `%s`", + self.this_token_to_str() + ) + ); + } + + // expect and consume the token t. Signal an error if + // the next token is not t. + pub fn expect(&self, t: &token::Token) { + if *self.token == *t { + self.bump(); + } else { + self.fatal( + fmt!( + "expected `%s` but found `%s`", + self.token_to_str(t), + self.this_token_to_str() + ) + ) + } + } + + pub fn parse_ident(&self) -> ast::ident { + self.check_strict_keywords(); + self.check_reserved_keywords(); + match *self.token { + token::IDENT(i, _) => { + self.bump(); + i + } + token::INTERPOLATED(token::nt_ident(*)) => { + self.bug("ident interpolation not converted to real token"); + } + _ => { + self.fatal( + fmt!( + "expected ident, found `%s`", + self.this_token_to_str() + ) + ); + } + } + } + + pub fn parse_path_list_ident(&self) -> ast::path_list_ident { + let lo = self.span.lo; + let ident = self.parse_ident(); + let hi = self.last_span.hi; + spanned(lo, hi, ast::path_list_ident_ { name: ident, + id: self.get_id() }) + } + + // consume token 'tok' if it exists. Returns true if the given + // token was present, false otherwise. + pub fn eat(&self, tok: &token::Token) -> bool { + return if *self.token == *tok { self.bump(); true } else { false }; + } + + pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { + token::is_keyword(kw, self.token) + } + + // if the next token is the given keyword, eat it and return + // true. Otherwise, return false. + pub fn eat_keyword(&self, kw: keywords::Keyword) -> bool { + let is_kw = match *self.token { + token::IDENT(sid, false) => kw.to_ident().name == sid.name, + _ => false + }; + if is_kw { self.bump() } + is_kw + } + + // if the given word is not a keyword, signal an error. + // if the next token is not the given word, signal an error. + // otherwise, eat it. + pub fn expect_keyword(&self, kw: keywords::Keyword) { + if !self.eat_keyword(kw) { + self.fatal( + fmt!( + "expected `%s`, found `%s`", + self.id_to_str(kw.to_ident()).to_str(), + self.this_token_to_str() + ) + ); + } + } + + // signal an error if the given string is a strict keyword + pub fn check_strict_keywords(&self) { + if token::is_strict_keyword(self.token) { + self.span_err(*self.last_span, + fmt!("found `%s` in ident position", self.this_token_to_str())); + } + } + + // signal an error if the current token is a reserved keyword + pub fn check_reserved_keywords(&self) { + if token::is_reserved_keyword(self.token) { + self.fatal(fmt!("`%s` is a reserved keyword", self.this_token_to_str())); + } + } + + // expect and consume a GT. if a >> is seen, replace it + // with a single > and continue. If a GT is not seen, + // signal an error. + pub fn expect_gt(&self) { + if *self.token == token::GT { + self.bump(); + } else if *self.token == token::BINOP(token::SHR) { + self.replace_token( + token::GT, + self.span.lo + BytePos(1u), + self.span.hi + ); + } else { + let mut s: ~str = ~"expected `"; + s.push_str(self.token_to_str(&token::GT)); + s.push_str("`, found `"); + s.push_str(self.this_token_to_str()); + s.push_str("`"); + self.fatal(s); + } + } + + // parse a sequence bracketed by '<' and '>', stopping + // before the '>'. + pub fn parse_seq_to_before_gt<T: Copy>(&self, + sep: Option<token::Token>, + f: &fn(&Parser) -> T) + -> OptVec<T> { + let mut first = true; + let mut v = opt_vec::Empty; + while *self.token != token::GT + && *self.token != token::BINOP(token::SHR) { + match sep { + Some(ref t) => { + if first { first = false; } + else { self.expect(t); } + } + _ => () + } + v.push(f(self)); + } + return v; + } + + pub fn parse_seq_to_gt<T: Copy>(&self, + sep: Option<token::Token>, + f: &fn(&Parser) -> T) + -> OptVec<T> { + let v = self.parse_seq_to_before_gt(sep, f); + self.expect_gt(); + return v; + } + + // parse a sequence, including the closing delimiter. The function + // f must consume tokens until reaching the next separator or + // closing bracket. + pub fn parse_seq_to_end<T: Copy>(&self, + ket: &token::Token, + sep: SeqSep, + f: &fn(&Parser) -> T) + -> ~[T] { + let val = self.parse_seq_to_before_end(ket, sep, f); + self.bump(); + val + } + + // parse a sequence, not including the closing delimiter. The function + // f must consume tokens until reaching the next separator or + // closing bracket. + pub fn parse_seq_to_before_end<T: Copy>(&self, + ket: &token::Token, + sep: SeqSep, + f: &fn(&Parser) -> T) + -> ~[T] { + let mut first: bool = true; + let mut v: ~[T] = ~[]; + while *self.token != *ket { + match sep.sep { + Some(ref t) => { + if first { first = false; } + else { self.expect(t); } + } + _ => () + } + if sep.trailing_sep_allowed && *self.token == *ket { break; } + v.push(f(self)); + } + return v; + } + + // parse a sequence, including the closing delimiter. The function + // f must consume tokens until reaching the next separator or + // closing bracket. + pub fn parse_unspanned_seq<T: Copy>(&self, + bra: &token::Token, + ket: &token::Token, + sep: SeqSep, + f: &fn(&Parser) -> T) + -> ~[T] { + self.expect(bra); + let result = self.parse_seq_to_before_end(ket, sep, f); + self.bump(); + result + } + + // NB: Do not use this function unless you actually plan to place the + // spanned list in the AST. + pub fn parse_seq<T: Copy>(&self, + bra: &token::Token, + ket: &token::Token, + sep: SeqSep, + f: &fn(&Parser) -> T) + -> spanned<~[T]> { + let lo = self.span.lo; + self.expect(bra); + let result = self.parse_seq_to_before_end(ket, sep, f); + let hi = self.span.hi; + self.bump(); + spanned(lo, hi, result) + } + // advance the parser by one token pub fn bump(&self) { *self.last_span = copy *self.span; @@ -710,8 +959,8 @@ impl Parser { } else if *self.token == token::MOD_SEP || is_ident_or_path(self.token) { // NAMED TYPE - let path = self.parse_path_with_tps(false); - ty_path(path, self.get_id()) + let (path, bounds) = self.parse_type_path(); + ty_path(path, @bounds, self.get_id()) } else { self.fatal(fmt!("expected type, found token %?", *self.token)); @@ -823,6 +1072,11 @@ impl Parser { self.parse_arg_mode(); is_mutbl = self.eat_keyword(keywords::Mut); let pat = self.parse_pat(); + + if is_mutbl && !ast_util::pat_is_ident(pat) { + self.obsolete(*self.span, ObsoleteMutWithMultipleBindings) + } + self.expect(&token::COLON); pat } else { @@ -974,10 +1228,8 @@ impl Parser { types: ~[] } } - // parse a path optionally with type parameters. If 'colons' - // is true, then type parameters must be preceded by colons, - // as in a::t::<t1,t2> - pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path { + pub fn parse_bounded_path_with_tps(&self, colons: bool, + before_tps: Option<&fn()>) -> @ast::Path { debug!("parse_path_with_tps(colons=%b)", colons); maybe_whole!(self, nt_path); @@ -987,6 +1239,10 @@ impl Parser { return path; } + // If the path might have bounds on it, they should be parsed before + // the parameters, e.g. module::TraitName:B1+B2<T> + before_tps.map_consume(|callback| callback()); + // Parse the (obsolete) trailing region parameter, if any, which will // be written "foo/&x" let rp_slash = { @@ -1038,6 +1294,25 @@ impl Parser { .. copy *path } } + // parse a path optionally with type parameters. If 'colons' + // is true, then type parameters must be preceded by colons, + // as in a::t::<t1,t2> + pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path { + self.parse_bounded_path_with_tps(colons, None) + } + + // Like the above, but can also parse kind bounds in the case of a + // path to be used as a type that might be a trait. + pub fn parse_type_path(&self) -> (@ast::Path, Option<OptVec<TyParamBound>>) { + let mut bounds = None; + let path = self.parse_bounded_path_with_tps(false, Some(|| { + // Note: this closure might not even get called in the case of a + // macro-generated path. But that's the macro parser's job. + bounds = self.parse_optional_ty_param_bounds(); + })); + (path, bounds) + } + /// parses 0 or 1 lifetime pub fn parse_opt_lifetime(&self) -> Option<@ast::Lifetime> { match *self.token { @@ -1796,9 +2071,8 @@ impl Parser { ex = match e.node { expr_vec(*) | expr_lit(@codemap::spanned { node: lit_str(_), span: _}) | - expr_repeat(*) - if m == m_imm => expr_vstore(e, expr_vstore_uniq), - _ => self.mk_unary(uniq(m), e) + expr_repeat(*) => expr_vstore(e, expr_vstore_uniq), + _ => self.mk_unary(uniq, e) }; } _ => return self.parse_dot_or_call_expr() @@ -2418,8 +2692,7 @@ impl Parser { pat = self.parse_pat_ident(bind_by_ref(mutbl)); } else if self.eat_keyword(keywords::Copy) { // parse copy pat - self.warn("copy keyword in patterns no longer has any effect, \ - remove it"); + self.obsolete(*self.span, ObsoletePatternCopyKeyword); pat = self.parse_pat_ident(bind_infer); } else { let can_be_enum_or_struct; @@ -2541,6 +2814,11 @@ impl Parser { fn parse_local(&self, is_mutbl: bool) -> @local { let lo = self.span.lo; let pat = self.parse_pat(); + + if is_mutbl && !ast_util::pat_is_ident(pat) { + self.obsolete(*self.span, ObsoleteMutWithMultipleBindings) + } + let mut ty = @Ty { id: self.get_id(), node: ty_infer, @@ -2746,7 +3024,7 @@ impl Parser { } = self.parse_items_and_view_items(first_item_attrs, false, false); - for items.each |item| { + for items.iter().advance |item| { let decl = @spanned(item.span.lo, item.span.hi, decl_item(*item)); stmts.push(@spanned(item.span.lo, item.span.hi, stmt_decl(decl, self.get_id()))); @@ -2847,16 +3125,6 @@ impl Parser { spanned(lo, hi, bloc) } - fn mk_ty_path(&self, i: ident) -> @Ty { - @Ty { - id: self.get_id(), - node: ty_path( - ident_to_path(*self.last_span, i), - self.get_id()), - span: *self.last_span, - } - } - fn parse_optional_purity(&self) -> ast::purity { if self.eat_keyword(keywords::Pure) { self.obsolete(*self.last_span, ObsoletePurity); @@ -2875,9 +3143,13 @@ impl Parser { // matches optbounds = ( ( : ( boundseq )? )? ) // where boundseq = ( bound + boundseq ) | bound // and bound = 'static | ty - fn parse_optional_ty_param_bounds(&self) -> OptVec<TyParamBound> { + // Returns "None" if there's no colon (e.g. "T"); + // Returns "Some(Empty)" if there's a colon but nothing after (e.g. "T:") + // Returns "Some(stuff)" otherwise (e.g. "T:stuff"). + // NB: The None/Some distinction is important for issue #7264. + fn parse_optional_ty_param_bounds(&self) -> Option<OptVec<TyParamBound>> { if !self.eat(&token::COLON) { - return opt_vec::Empty; + return None; } let mut result = opt_vec::Empty; @@ -2921,23 +3193,20 @@ impl Parser { _ => break, } - if self.eat(&token::BINOP(token::PLUS)) { - loop; - } - - if is_ident_or_path(self.token) { - self.obsolete(*self.span, - ObsoleteTraitBoundSeparator); + if !self.eat(&token::BINOP(token::PLUS)) { + break; } } - return result; + return Some(result); } // matches typaram = IDENT optbounds fn parse_ty_param(&self) -> TyParam { let ident = self.parse_ident(); - let bounds = @self.parse_optional_ty_param_bounds(); + let opt_bounds = self.parse_optional_ty_param_bounds(); + // For typarams we don't care about the difference b/w "<T>" and "<T:>". + let bounds = @opt_bounds.get_or_default(opt_vec::Empty); ast::TyParam { ident: ident, id: self.get_id(), bounds: bounds } } @@ -3096,7 +3365,12 @@ impl Parser { maybe_parse_explicit_self(sty_box, self) } token::TILDE => { - maybe_parse_explicit_self(sty_uniq, self) + maybe_parse_explicit_self(|mutability| { + if mutability != m_imm { + self.obsolete(*self.last_span, ObsoleteMutOwnedPointer); + } + sty_uniq + }, self) } token::IDENT(*) if self.is_self_ident() => { self.bump(); @@ -3284,14 +3558,19 @@ impl Parser { let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) { // New-style trait. Reinterpret the type as a trait. let opt_trait_ref = match ty.node { - ty_path(path, node_id) => { + ty_path(path, @None, node_id) => { Some(@trait_ref { path: path, ref_id: node_id }) } + ty_path(*) => { + self.span_err(ty.span, + "bounded traits are only valid in type position"); + None + } _ => { - self.span_err(*self.span, "not a trait"); + self.span_err(ty.span, "not a trait"); None } }; @@ -3356,7 +3635,8 @@ impl Parser { is_tuple_like = false; fields = ~[]; while *self.token != token::RBRACE { - for self.parse_struct_decl_field().each |struct_field| { + let r = self.parse_struct_decl_field(); + for r.iter().advance |struct_field| { fields.push(*struct_field) } } @@ -3544,13 +3824,14 @@ impl Parser { } fn parse_item_const(&self) -> item_info { + let m = if self.eat_keyword(keywords::Mut) {m_mutbl} else {m_imm}; let id = self.parse_ident(); self.expect(&token::COLON); let ty = self.parse_ty(false); self.expect(&token::EQ); let e = self.parse_expr(); self.expect(&token::SEMI); - (id, item_const(ty, e), None) + (id, item_static(ty, m, e), None) } // parse a mod { ...} item @@ -3671,6 +3952,7 @@ impl Parser { } else { self.expect_keyword(keywords::Static); } + let mutbl = self.eat_keyword(keywords::Mut); let ident = self.parse_ident(); self.expect(&token::COLON); @@ -3679,7 +3961,7 @@ impl Parser { self.expect(&token::SEMI); @ast::foreign_item { ident: ident, attrs: attrs, - node: foreign_item_const(ty), + node: foreign_item_static(ty, mutbl), id: self.get_id(), span: mk_sp(lo, hi), vis: vis } @@ -3825,7 +4107,8 @@ impl Parser { fn parse_struct_def(&self) -> @struct_def { let mut fields: ~[@struct_field] = ~[]; while *self.token != token::RBRACE { - for self.parse_struct_decl_field().each |struct_field| { + let r = self.parse_struct_decl_field(); + for r.iter().advance |struct_field| { fields.push(*struct_field); } } @@ -3865,7 +4148,7 @@ impl Parser { seq_sep_trailing_disallowed(token::COMMA), |p| p.parse_ty(false) ); - for arg_tys.each |ty| { + for arg_tys.iter().advance |ty| { args.push(ast::variant_arg { ty: *ty, id: self.get_id(), @@ -4225,8 +4508,12 @@ impl Parser { // FAILURE TO PARSE ITEM if visibility != inherited { let mut s = ~"unmatched visibility `"; - s += if visibility == public { "pub" } else { "priv" }; - s += "`"; + if visibility == public { + s.push_str("pub") + } else { + s.push_str("priv") + } + s.push_char('`'); self.span_fatal(*self.last_span, s); } return iovi_none; @@ -4401,7 +4688,8 @@ impl Parser { let mut attrs = vec::append(first_item_attrs, self.parse_outer_attributes()); // First, parse view items. - let mut (view_items, items) = (~[], ~[]); + let mut view_items = ~[]; + let mut items = ~[]; let mut done = false; // I think this code would probably read better as a single // loop with a mutable three-state-variable (for extern mods, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 273a59f0a3d..a50fa416832 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use ast; use ast::Name; use ast_util; @@ -17,14 +15,13 @@ use parse::token; use util::interner::StrInterner; use util::interner; -use core::cast; -use core::char; -use core::cmp::Equiv; -use core::local_data; -use core::rand; -use core::rand::RngUtil; +use std::cast; +use std::cmp::Equiv; +use std::local_data; +use std::rand; +use std::rand::RngUtil; -#[deriving(Encodable, Decodable, Eq)] +#[deriving(Encodable, Decodable, Eq, IterBytes)] pub enum binop { PLUS, MINUS, @@ -38,7 +35,7 @@ pub enum binop { SHR, } -#[deriving(Encodable, Decodable, Eq)] +#[deriving(Encodable, Decodable, Eq, IterBytes)] pub enum Token { /* Expression-operator symbols. */ EQ, @@ -99,7 +96,7 @@ pub enum Token { EOF, } -#[deriving(Encodable, Decodable, Eq)] +#[deriving(Encodable, Decodable, Eq, IterBytes)] /// For interpolation during macro expansion. pub enum nonterminal { nt_item(@ast::item), @@ -168,7 +165,12 @@ pub fn to_str(in: @ident_interner, t: &Token) -> ~str { /* Literals */ LIT_INT(c, ast::ty_char) => { - ~"'" + char::escape_default(c as char) + "'" + let mut res = ~"'"; + do (c as char).escape_default |c| { + res.push_char(c); + } + res.push_char('\''); + res } LIT_INT(i, t) => { i.to_str() + ast_util::int_ty_to_str(t) @@ -180,14 +182,14 @@ pub fn to_str(in: @ident_interner, t: &Token) -> ~str { LIT_FLOAT(ref s, t) => { let mut body = ident_to_str(s).to_owned(); if body.ends_with(".") { - body += "0"; // `10.f` is not a float literal + body.push_char('0'); // `10.f` is not a float literal } body + ast_util::float_ty_to_str(t) } LIT_FLOAT_UNSUFFIXED(ref s) => { let mut body = ident_to_str(s).to_owned(); if body.ends_with(".") { - body += "0"; // `10.f` is not a float literal + body.push_char('0'); // `10.f` is not a float literal } body } @@ -331,21 +333,18 @@ pub mod special_idents { pub static str : ident = ident { name: 19, ctxt: 0}; // for the type /* outside of libsyntax */ - pub static ty_visitor : ident = ident { name: 20, ctxt: 0}; - pub static arg : ident = ident { name: 21, ctxt: 0}; - pub static descrim : ident = ident { name: 22, ctxt: 0}; - pub static clownshoe_abi : ident = ident { name: 23, ctxt: 0}; - pub static clownshoe_stack_shim : ident = ident { name: 24, ctxt: 0}; - pub static tydesc : ident = ident { name: 25, ctxt: 0}; - pub static main : ident = ident { name: 26, ctxt: 0}; - pub static opaque : ident = ident { name: 27, ctxt: 0}; - pub static blk : ident = ident { name: 28, ctxt: 0}; - pub static statik : ident = ident { name: 29, ctxt: 0}; - pub static intrinsic : ident = ident { name: 30, ctxt: 0}; - pub static clownshoes_foreign_mod: ident = ident { name: 31, ctxt: 0}; - pub static unnamed_field: ident = ident { name: 32, ctxt: 0}; - pub static c_abi: ident = ident { name: 33, ctxt: 0}; - pub static type_self: ident = ident { name: 34, ctxt: 0}; // `Self` + pub static arg : ident = ident { name: 20, ctxt: 0}; + pub static descrim : ident = ident { name: 21, ctxt: 0}; + pub static clownshoe_abi : ident = ident { name: 22, ctxt: 0}; + pub static clownshoe_stack_shim : ident = ident { name: 23, ctxt: 0}; + pub static main : ident = ident { name: 24, ctxt: 0}; + pub static opaque : ident = ident { name: 25, ctxt: 0}; + pub static blk : ident = ident { name: 26, ctxt: 0}; + pub static statik : ident = ident { name: 27, ctxt: 0}; + pub static clownshoes_foreign_mod: ident = ident { name: 28, ctxt: 0}; + pub static unnamed_field: ident = ident { name: 29, ctxt: 0}; + pub static c_abi: ident = ident { name: 30, ctxt: 0}; + pub static type_self: ident = ident { name: 31, ctxt: 0}; // `Self` } /** @@ -426,59 +425,56 @@ fn mk_fresh_ident_interner() -> @ident_interner { "tt", // 17 "matchers", // 18 "str", // 19 - "TyVisitor", // 20 - "arg", // 21 - "descrim", // 22 - "__rust_abi", // 23 - "__rust_stack_shim", // 24 - "TyDesc", // 25 - "main", // 26 - "<opaque>", // 27 - "blk", // 28 - "static", // 29 - "intrinsic", // 30 - "__foreign_mod__", // 31 - "__field__", // 32 - "C", // 33 - "Self", // 34 - - "as", // 35 - "break", // 36 - "const", // 37 - "copy", // 38 - "do", // 39 - "else", // 40 - "enum", // 41 - "extern", // 42 - "false", // 43 - "fn", // 44 - "for", // 45 - "if", // 46 - "impl", // 47 - "let", // 48 - "__log", // 49 - "loop", // 50 - "match", // 51 - "mod", // 52 - "mut", // 53 - "once", // 54 - "priv", // 55 - "pub", // 56 - "pure", // 57 - "ref", // 58 - "return", // 59 - "static", // 29 -- also a special ident + "arg", // 20 + "descrim", // 21 + "__rust_abi", // 22 + "__rust_stack_shim", // 23 + "main", // 24 + "<opaque>", // 25 + "blk", // 26 + "static", // 27 + "__foreign_mod__", // 28 + "__field__", // 29 + "C", // 30 + "Self", // 31 + + "as", // 32 + "break", // 33 + "const", // 34 + "copy", // 35 + "do", // 36 + "else", // 37 + "enum", // 38 + "extern", // 39 + "false", // 40 + "fn", // 41 + "for", // 42 + "if", // 43 + "impl", // 44 + "let", // 45 + "__log", // 46 + "loop", // 47 + "match", // 48 + "mod", // 49 + "mut", // 50 + "once", // 51 + "priv", // 52 + "pub", // 53 + "pure", // 54 + "ref", // 55 + "return", // 56 + "static", // 27 -- also a special ident "self", // 8 -- also a special ident - "struct", // 60 - "super", // 61 - "true", // 62 - "trait", // 63 - "type", // 64 - "unsafe", // 65 - "use", // 66 - "while", // 67 - - "be", // 68 + "struct", // 57 + "super", // 58 + "true", // 59 + "trait", // 60 + "type", // 61 + "unsafe", // 62 + "use", // 63 + "while", // 64 + + "be", // 65 ]; @ident_interner { @@ -492,7 +488,7 @@ pub fn get_ident_interner() -> @ident_interner { unsafe { let key = (cast::transmute::<(uint, uint), - &fn(v: @@::parse::token::ident_interner)>( + &fn:Copy(v: @@::parse::token::ident_interner)>( (-3 as uint, 0u))); match local_data::local_data_get(key) { Some(interner) => *interner, @@ -612,42 +608,42 @@ pub mod keywords { impl Keyword { pub fn to_ident(&self) -> ident { match *self { - As => ident { name: 35, ctxt: 0 }, - Break => ident { name: 36, ctxt: 0 }, - Const => ident { name: 37, ctxt: 0 }, - Copy => ident { name: 38, ctxt: 0 }, - Do => ident { name: 39, ctxt: 0 }, - Else => ident { name: 40, ctxt: 0 }, - Enum => ident { name: 41, ctxt: 0 }, - Extern => ident { name: 42, ctxt: 0 }, - False => ident { name: 43, ctxt: 0 }, - Fn => ident { name: 44, ctxt: 0 }, - For => ident { name: 45, ctxt: 0 }, - If => ident { name: 46, ctxt: 0 }, - Impl => ident { name: 47, ctxt: 0 }, - Let => ident { name: 48, ctxt: 0 }, - __Log => ident { name: 49, ctxt: 0 }, - Loop => ident { name: 50, ctxt: 0 }, - Match => ident { name: 51, ctxt: 0 }, - Mod => ident { name: 52, ctxt: 0 }, - Mut => ident { name: 53, ctxt: 0 }, - Once => ident { name: 54, ctxt: 0 }, - Priv => ident { name: 55, ctxt: 0 }, - Pub => ident { name: 56, ctxt: 0 }, - Pure => ident { name: 57, ctxt: 0 }, - Ref => ident { name: 58, ctxt: 0 }, - Return => ident { name: 59, ctxt: 0 }, - Static => ident { name: 29, ctxt: 0 }, + As => ident { name: 32, ctxt: 0 }, + Break => ident { name: 33, ctxt: 0 }, + Const => ident { name: 34, ctxt: 0 }, + Copy => ident { name: 35, ctxt: 0 }, + Do => ident { name: 36, ctxt: 0 }, + Else => ident { name: 37, ctxt: 0 }, + Enum => ident { name: 38, ctxt: 0 }, + Extern => ident { name: 39, ctxt: 0 }, + False => ident { name: 40, ctxt: 0 }, + Fn => ident { name: 41, ctxt: 0 }, + For => ident { name: 42, ctxt: 0 }, + If => ident { name: 43, ctxt: 0 }, + Impl => ident { name: 44, ctxt: 0 }, + Let => ident { name: 45, ctxt: 0 }, + __Log => ident { name: 46, ctxt: 0 }, + Loop => ident { name: 47, ctxt: 0 }, + Match => ident { name: 48, ctxt: 0 }, + Mod => ident { name: 49, ctxt: 0 }, + Mut => ident { name: 50, ctxt: 0 }, + Once => ident { name: 51, ctxt: 0 }, + Priv => ident { name: 52, ctxt: 0 }, + Pub => ident { name: 53, ctxt: 0 }, + Pure => ident { name: 54, ctxt: 0 }, + Ref => ident { name: 55, ctxt: 0 }, + Return => ident { name: 56, ctxt: 0 }, + Static => ident { name: 27, ctxt: 0 }, Self => ident { name: 8, ctxt: 0 }, - Struct => ident { name: 60, ctxt: 0 }, - Super => ident { name: 61, ctxt: 0 }, - True => ident { name: 62, ctxt: 0 }, - Trait => ident { name: 63, ctxt: 0 }, - Type => ident { name: 64, ctxt: 0 }, - Unsafe => ident { name: 65, ctxt: 0 }, - Use => ident { name: 66, ctxt: 0 }, - While => ident { name: 67, ctxt: 0 }, - Be => ident { name: 68, ctxt: 0 }, + Struct => ident { name: 57, ctxt: 0 }, + Super => ident { name: 58, ctxt: 0 }, + True => ident { name: 59, ctxt: 0 }, + Trait => ident { name: 60, ctxt: 0 }, + Type => ident { name: 61, ctxt: 0 }, + Unsafe => ident { name: 62, ctxt: 0 }, + Use => ident { name: 63, ctxt: 0 }, + While => ident { name: 64, ctxt: 0 }, + Be => ident { name: 65, ctxt: 0 }, } } } @@ -663,7 +659,7 @@ pub fn is_keyword(kw: keywords::Keyword, tok: &Token) -> bool { pub fn is_any_keyword(tok: &Token) -> bool { match *tok { token::IDENT(sid, false) => match sid.name { - 8 | 29 | 35 .. 68 => true, + 8 | 27 | 32 .. 65 => true, _ => false, }, _ => false @@ -673,7 +669,7 @@ pub fn is_any_keyword(tok: &Token) -> bool { pub fn is_strict_keyword(tok: &Token) -> bool { match *tok { token::IDENT(sid, false) => match sid.name { - 8 | 29 | 35 .. 67 => true, + 8 | 27 | 32 .. 64 => true, _ => false, }, _ => false, @@ -683,7 +679,7 @@ pub fn is_strict_keyword(tok: &Token) -> bool { pub fn is_reserved_keyword(tok: &Token) -> bool { match *tok { token::IDENT(sid, false) => match sid.name { - 68 => true, + 65 => true, _ => false, }, _ => false, diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 7853e7e312d..7cd3faf9a90 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -61,10 +61,8 @@ * avoid combining it with other lines and making matters even worse. */ -use core::prelude::*; - -use core::io; -use core::vec; +use std::io; +use std::vec; #[deriving(Eq)] pub enum breaks { consistent, inconsistent, } @@ -124,12 +122,14 @@ pub fn buf_str(toks: ~[token], szs: ~[int], left: uint, right: uint, let mut s = ~"["; while i != right && L != 0u { L -= 1u; - if i != left { s += ", "; } - s += fmt!("%d=%s", szs[i], tok_str(toks[i])); + if i != left { + s.push_str(", "); + } + s.push_str(fmt!("%d=%s", szs[i], tok_str(toks[i]))); i += 1u; i %= n; } - s += "]"; + s.push_char(']'); return s; } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e72d9b502dc..5e685d85f95 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use abi::AbiSet; use ast::{RegionTyParamBound, TraitTyParamBound, required, provided}; use ast; @@ -29,10 +27,9 @@ use print::pp::{breaks, consistent, inconsistent, eof}; use print::pp; use print::pprust; -use core::char; -use core::io; -use core::u64; -use core::uint; +use std::io; +use std::u64; +use std::uint; // The @ps is stored here to prevent recursive type. pub enum ann_node<'self> { @@ -320,7 +317,7 @@ pub fn synth_comment(s: @ps, text: ~str) { pub fn commasep<IN: Copy>(s: @ps, b: breaks, elts: &[IN], op: &fn(@ps, IN)) { box(s, 0u, b); let mut first = true; - for elts.each |elt| { + for elts.iter().advance |elt| { if first { first = false; } else { word_space(s, ","); } op(s, copy *elt); } @@ -333,7 +330,7 @@ pub fn commasep_cmnt<IN: Copy>(s: @ps, b: breaks, elts: &[IN], op: &fn(@ps, IN), box(s, 0u, b); let len = elts.len(); let mut i = 0u; - for elts.each |elt| { + for elts.iter().advance |elt| { maybe_print_comment(s, get_span(copy *elt).hi); op(s, copy *elt); i += 1u; @@ -354,19 +351,19 @@ pub fn commasep_exprs(s: @ps, b: breaks, exprs: &[@ast::expr]) { pub fn print_mod(s: @ps, _mod: &ast::_mod, attrs: &[ast::attribute]) { print_inner_attributes(s, attrs); - for _mod.view_items.each |vitem| { + for _mod.view_items.iter().advance |vitem| { print_view_item(s, *vitem); } - for _mod.items.each |item| { print_item(s, *item); } + for _mod.items.iter().advance |item| { print_item(s, *item); } } pub fn print_foreign_mod(s: @ps, nmod: &ast::foreign_mod, attrs: &[ast::attribute]) { print_inner_attributes(s, attrs); - for nmod.view_items.each |vitem| { + for nmod.view_items.iter().advance |vitem| { print_view_item(s, *vitem); } - for nmod.items.each |item| { print_foreign_item(s, *item); } + for nmod.items.iter().advance |item| { print_foreign_item(s, *item); } } pub fn print_opt_lifetime(s: @ps, lifetime: Option<@ast::Lifetime>) { @@ -412,17 +409,17 @@ pub fn print_type(s: @ps, ty: @ast::Ty) { let generics = ast::Generics {lifetimes: copy f.lifetimes, ty_params: opt_vec::Empty}; print_ty_fn(s, Some(f.abis), None, None, - f.purity, ast::Many, &f.decl, None, + f.purity, ast::Many, &f.decl, None, &None, Some(&generics), None); } ast::ty_closure(f) => { let generics = ast::Generics {lifetimes: copy f.lifetimes, ty_params: opt_vec::Empty}; print_ty_fn(s, None, Some(f.sigil), f.region, - f.purity, f.onceness, &f.decl, None, + f.purity, f.onceness, &f.decl, None, &f.bounds, Some(&generics), None); } - ast::ty_path(path, _) => print_path(s, path, false), + ast::ty_path(path, bounds, _) => print_bounded_path(s, path, bounds), ast::ty_fixed_length_vec(ref mt, v) => { word(s.s, "["); match mt.mutbl { @@ -458,8 +455,11 @@ pub fn print_foreign_item(s: @ps, item: @ast::foreign_item) { word(s.s, ";"); end(s); // end the outer fn box } - ast::foreign_item_const(t) => { + ast::foreign_item_static(t, m) => { head(s, "static"); + if m { + word_space(s, "mut"); + } print_ident(s, item.ident); word_space(s, ":"); print_type(s, t); @@ -477,8 +477,11 @@ pub fn print_item(s: @ps, item: @ast::item) { let ann_node = node_item(s, item); (s.ann.pre)(ann_node); match item.node { - ast::item_const(ty, expr) => { + ast::item_static(ty, m, expr) => { head(s, visibility_qualified(item.vis, "static")); + if m == ast::m_mutbl { + word_space(s, "mut"); + } print_ident(s, item.ident); word_space(s, ":"); print_type(s, ty); @@ -580,7 +583,7 @@ pub fn print_item(s: @ps, item: @ast::item) { word(s.s, ";"); } else { bopen(s); - for methods.each |meth| { + for methods.iter().advance |meth| { print_method(s, *meth); } bclose(s, item.span); @@ -592,7 +595,7 @@ pub fn print_item(s: @ps, item: @ast::item) { print_generics(s, generics); if traits.len() != 0u { word(s.s, ":"); - for traits.eachi |i, trait_| { + for traits.iter().enumerate().advance |(i, trait_)| { nbsp(s); if i != 0 { word_space(s, "+"); @@ -602,7 +605,7 @@ pub fn print_item(s: @ps, item: @ast::item) { } word(s.s, " "); bopen(s); - for methods.each |meth| { + for methods.iter().advance |meth| { print_trait_method(s, meth); } bclose(s, item.span); @@ -641,7 +644,7 @@ pub fn print_variants(s: @ps, variants: &[ast::variant], span: codemap::span) { bopen(s); - for variants.each |v| { + for variants.iter().advance |v| { space_if_not_bol(s); maybe_print_comment(s, v.span.lo); print_outer_attributes(s, v.node.attrs); @@ -706,7 +709,7 @@ pub fn print_struct(s: @ps, bopen(s); hardbreak_if_not_bol(s); - for struct_def.fields.each |field| { + for struct_def.fields.iter().advance |field| { match field.node.kind { ast::unnamed_field => fail!("unexpected unnamed field"), ast::named_field(ident, visibility) => { @@ -741,7 +744,7 @@ pub fn print_tt(s: @ps, tt: &ast::token_tree) { } ast::tt_seq(_, ref tts, ref sep, zerok) => { word(s.s, "$("); - for (*tts).each() |tt_elt| { print_tt(s, tt_elt); } + for (*tts).iter().advance |tt_elt| { print_tt(s, tt_elt); } word(s.s, ")"); match (*sep) { Some(ref tk) => word(s.s, parse::token::to_str(s.intr, tk)), @@ -758,7 +761,7 @@ pub fn print_tt(s: @ps, tt: &ast::token_tree) { pub fn print_tts(s: @ps, tts: &[ast::token_tree]) { ibox(s, 0); - for tts.eachi |i, tt| { + for tts.iter().enumerate().advance |(i, tt)| { if i != 0 { space(s.s); } @@ -802,7 +805,7 @@ pub fn print_ty_method(s: @ps, m: &ast::ty_method) { maybe_print_comment(s, m.span.lo); print_outer_attributes(s, m.attrs); print_ty_fn(s, None, None, None, m.purity, ast::Many, - &m.decl, Some(m.ident), Some(&m.generics), + &m.decl, Some(m.ident), &None, Some(&m.generics), Some(/*bad*/ copy m.explicit_self.node)); word(s.s, ";"); } @@ -827,7 +830,7 @@ pub fn print_method(s: @ps, meth: @ast::method) { pub fn print_outer_attributes(s: @ps, attrs: &[ast::attribute]) { let mut count = 0; - for attrs.each |attr| { + for attrs.iter().advance |attr| { match attr.node.style { ast::attr_outer => { print_attribute(s, *attr); count += 1; } _ => {/* fallthrough */ } @@ -838,7 +841,7 @@ pub fn print_outer_attributes(s: @ps, attrs: &[ast::attribute]) { pub fn print_inner_attributes(s: @ps, attrs: &[ast::attribute]) { let mut count = 0; - for attrs.each |attr| { + for attrs.iter().advance |attr| { match attr.node.style { ast::attr_inner => { print_attribute(s, *attr); @@ -944,8 +947,8 @@ pub fn print_possibly_embedded_block_(s: @ps, print_inner_attributes(s, attrs); - for blk.node.view_items.each |vi| { print_view_item(s, *vi); } - for blk.node.stmts.each |st| { + for blk.node.view_items.iter().advance |vi| { print_view_item(s, *vi); } + for blk.node.stmts.iter().advance |st| { print_stmt(s, *st); } match blk.node.expr { @@ -1229,12 +1232,12 @@ pub fn print_expr(s: @ps, expr: @ast::expr) { space(s.s); bopen(s); let len = arms.len(); - for arms.eachi |i, arm| { + for arms.iter().enumerate().advance |(i, arm)| { space(s.s); cbox(s, indent_unit); ibox(s, 0u); let mut first = true; - for arm.pats.each |p| { + for arm.pats.iter().advance |p| { if first { first = false; } else { space(s.s); word_space(s, "|"); } @@ -1401,7 +1404,7 @@ pub fn print_expr(s: @ps, expr: @ast::expr) { popen(s); print_string(s, a.asm); word_space(s, ":"); - for a.outputs.each |&(co, o)| { + for a.outputs.iter().advance |&(co, o)| { print_string(s, co); popen(s); print_expr(s, o); @@ -1409,7 +1412,7 @@ pub fn print_expr(s: @ps, expr: @ast::expr) { word_space(s, ","); } word_space(s, ":"); - for a.inputs.each |&(co, o)| { + for a.inputs.iter().advance |&(co, o)| { print_string(s, co); popen(s); print_expr(s, o); @@ -1483,14 +1486,18 @@ pub fn print_for_decl(s: @ps, loc: @ast::local, coll: @ast::expr) { print_expr(s, coll); } -pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) { +fn print_path_(s: @ps, path: @ast::Path, colons_before_params: bool, + opt_bounds: &Option<OptVec<ast::TyParamBound>>) { maybe_print_comment(s, path.span.lo); if path.global { word(s.s, "::"); } let mut first = true; - for path.idents.each |id| { + for path.idents.iter().advance |id| { if first { first = false; } else { word(s.s, "::"); } print_ident(s, *id); } + do opt_bounds.map |bounds| { + print_bounds(s, bounds, true); + }; if path.rp.is_some() || !path.types.is_empty() { if colons_before_params { word(s.s, "::"); } @@ -1511,6 +1518,15 @@ pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) { } } +pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) { + print_path_(s, path, colons_before_params, &None) +} + +pub fn print_bounded_path(s: @ps, path: @ast::Path, + bounds: &Option<OptVec<ast::TyParamBound>>) { + print_path_(s, path, false, bounds) +} + pub fn print_irrefutable_pat(s: @ps, pat: @ast::pat) { print_pat(s, pat, false) } @@ -1636,6 +1652,7 @@ pub fn print_explicit_self(s: @ps, explicit_self: ast::explicit_self_) -> bool { match explicit_self { ast::sty_static => { return false; } ast::sty_value => { word(s.s, "self"); } + ast::sty_uniq => { word(s.s, "~self"); } ast::sty_region(lt, m) => { word(s.s, "&"); print_opt_lifetime(s, lt); @@ -1645,9 +1662,6 @@ pub fn print_explicit_self(s: @ps, explicit_self: ast::explicit_self_) -> bool { ast::sty_box(m) => { word(s.s, "@"); print_mutability(s, m); word(s.s, "self"); } - ast::sty_uniq(m) => { - word(s.s, "~"); print_mutability(s, m); word(s.s, "self"); - } } return true; } @@ -1678,7 +1692,7 @@ pub fn print_fn_args(s: @ps, decl: &ast::fn_decl, first = !print_explicit_self(s, *explicit_self); } - for decl.inputs.each |arg| { + for decl.inputs.iter().advance |arg| { if first { first = false; } else { word_space(s, ","); } print_arg(s, *arg); } @@ -1720,11 +1734,12 @@ pub fn print_fn_block_args(s: @ps, decl: &ast::fn_decl) { maybe_print_comment(s, decl.output.span.lo); } -pub fn print_bounds(s: @ps, bounds: @OptVec<ast::TyParamBound>) { +pub fn print_bounds(s: @ps, bounds: &OptVec<ast::TyParamBound>, + print_colon_anyway: bool) { if !bounds.is_empty() { word(s.s, ":"); let mut first = true; - for bounds.each |bound| { + for bounds.iter().advance |bound| { nbsp(s); if first { first = false; @@ -1737,6 +1752,8 @@ pub fn print_bounds(s: @ps, bounds: @OptVec<ast::TyParamBound>) { RegionTyParamBound => word(s.s, "'static"), } } + } else if print_colon_anyway { + word(s.s, ":"); } } @@ -1757,7 +1774,7 @@ pub fn print_generics(s: @ps, generics: &ast::Generics) { let idx = idx - generics.lifetimes.len(); let param = generics.ty_params.get(idx); print_ident(s, param.ident); - print_bounds(s, param.bounds); + print_bounds(s, param.bounds, false); } } @@ -1900,6 +1917,7 @@ pub fn print_ty_fn(s: @ps, onceness: ast::Onceness, decl: &ast::fn_decl, id: Option<ast::ident>, + opt_bounds: &Option<OptVec<ast::TyParamBound>>, generics: Option<&ast::Generics>, opt_explicit_self: Option<ast::explicit_self_>) { ibox(s, indent_unit); @@ -1913,6 +1931,7 @@ pub fn print_ty_fn(s: @ps, print_onceness(s, onceness); word(s.s, "fn"); match id { Some(id) => { word(s.s, " "); print_ident(s, id); } _ => () } + do opt_bounds.map |bounds| { print_bounds(s, bounds, true); }; match generics { Some(g) => print_generics(s, g), _ => () } zerobreak(s.s); @@ -1924,7 +1943,7 @@ pub fn print_ty_fn(s: @ps, for opt_explicit_self.iter().advance |explicit_self| { first = !print_explicit_self(s, *explicit_self); } - for decl.inputs.each |arg| { + for decl.inputs.iter().advance |arg| { if first { first = false; } else { word_space(s, ","); } print_arg(s, *arg); } @@ -1996,7 +2015,12 @@ pub fn print_literal(s: @ps, lit: @ast::lit) { match lit.node { ast::lit_str(st) => print_string(s, st), ast::lit_int(ch, ast::ty_char) => { - word(s.s, ~"'" + char::escape_default(ch as char) + "'"); + let mut res = ~"'"; + do (ch as char).escape_default |c| { + res.push_char(c); + } + res.push_char('\''); + word(s.s, res); } ast::lit_int(i, t) => { if i < 0_i64 { @@ -2075,7 +2099,7 @@ pub fn print_comment(s: @ps, cmnt: &comments::cmnt) { } comments::isolated => { pprust::hardbreak_if_not_bol(s); - for cmnt.lines.each |line| { + for cmnt.lines.iter().advance |line| { // Don't print empty lines because they will end up as trailing // whitespace if !line.is_empty() { word(s.s, *line); } @@ -2089,7 +2113,7 @@ pub fn print_comment(s: @ps, cmnt: &comments::cmnt) { hardbreak(s.s); } else { ibox(s, 0u); - for cmnt.lines.each |line| { + for cmnt.lines.iter().advance |line| { if !line.is_empty() { word(s.s, *line); } hardbreak(s.s); } @@ -2188,26 +2212,29 @@ pub fn print_fn_header_info(s: @ps, print_opt_sigil(s, opt_sigil); } -pub fn opt_sigil_to_str(opt_p: Option<ast::Sigil>) -> ~str { +pub fn opt_sigil_to_str(opt_p: Option<ast::Sigil>) -> &'static str { match opt_p { - None => ~"fn", - Some(p) => fmt!("fn%s", p.to_str()) + None => "fn", + Some(p) => match p { + ast::BorrowedSigil => "fn&", + ast::OwnedSigil => "fn~", + ast::ManagedSigil => "fn@" + } } } -pub fn purity_to_str(p: ast::purity) -> ~str { +pub fn purity_to_str(p: ast::purity) -> &'static str { match p { - ast::impure_fn => ~"impure", - ast::unsafe_fn => ~"unsafe", - ast::pure_fn => ~"pure", - ast::extern_fn => ~"extern" + ast::impure_fn => "impure", + ast::unsafe_fn => "unsafe", + ast::extern_fn => "extern" } } -pub fn onceness_to_str(o: ast::Onceness) -> ~str { +pub fn onceness_to_str(o: ast::Onceness) -> &'static str { match o { - ast::Once => ~"once", - ast::Many => ~"many" + ast::Once => "once", + ast::Many => "many" } } @@ -2232,8 +2259,6 @@ mod test { use ast; use ast_util; use codemap; - use core::cmp::Eq; - use core::option::None; use parse::token; fn string_check<T:Eq> (given : &T, expected: &T) { diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rs index 278600bc039..830ca569455 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rs @@ -14,7 +14,7 @@ */ #[link(name = "syntax", - vers = "0.7-pre", + vers = "0.7", uuid = "9311401b-d6ea-4cd9-a1d9-61f89499c645")]; #[license = "MIT/ASL2"]; @@ -23,16 +23,7 @@ #[allow(non_camel_case_types)]; #[deny(deprecated_pattern)]; -#[no_core]; -#[no_std]; - -extern mod core(name = "std"); -extern mod extra(name = "extra"); - -// For deriving(Encodable) purposes... -extern mod std(name = "std"); - -use core::prelude::*; +extern mod extra; pub mod util { pub mod interner; diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index bd5c178e7fe..3cdc4fd0fa1 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -12,13 +12,8 @@ // allows bidirectional lookup; i.e. given a value, one can easily find the // type, and vice versa. -// allow the interner_key macro to escape this module: -#[macro_escape]; - -use core::prelude::*; - -use core::cmp::Equiv; -use core::hashmap::HashMap; +use std::cmp::Equiv; +use std::hashmap::HashMap; pub struct Interner<T> { priv map: @mut HashMap<T, uint>, @@ -26,7 +21,7 @@ pub struct Interner<T> { } // when traits can extend traits, we should extend index<uint,T> to get [] -impl<T:Eq + IterBytes + Hash + Const + Copy> Interner<T> { +impl<T:Eq + IterBytes + Hash + Freeze + Copy> Interner<T> { pub fn new() -> Interner<T> { Interner { map: @mut HashMap::new(), @@ -36,7 +31,7 @@ impl<T:Eq + IterBytes + Hash + Const + Copy> Interner<T> { pub fn prefill(init: &[T]) -> Interner<T> { let rv = Interner::new(); - for init.each() |v| { rv.intern(copy *v); } + for init.iter().advance |v| { rv.intern(copy *v); } rv } @@ -94,7 +89,7 @@ impl StrInterner { pub fn prefill(init: &[&str]) -> StrInterner { let rv = StrInterner::new(); - for init.each |&v| { rv.intern(v); } + for init.iter().advance |&v| { rv.intern(v); } rv } diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index d0961ddbc70..4340d6bb6a2 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::option::{Option,None}; use ast; use parse::{new_parse_sess}; use parse::{ParseSess,string_to_filemap,filemap_to_tts}; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f24c393d7b4..9fcffc11013 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use abi::AbiSet; use ast::*; use ast; @@ -41,7 +39,7 @@ pub enum fn_kind<'self> { // fn foo(&self) fk_method(ident, &'self Generics, &'self method), - // fn@(x, y) { ... } + // @fn(x, y) { ... } fk_anon(ast::Sigil), // |x, y| ... @@ -127,13 +125,13 @@ pub fn visit_crate<E: Copy>(c: &crate, (e, v): (E, vt<E>)) { } pub fn visit_mod<E: Copy>(m: &_mod, _sp: span, _id: node_id, (e, v): (E, vt<E>)) { - for m.view_items.each |vi| { (v.visit_view_item)(*vi, (copy e, v)); } - for m.items.each |i| { (v.visit_item)(*i, (copy e, v)); } + for m.view_items.iter().advance |vi| { (v.visit_view_item)(*vi, (copy e, v)); } + for m.items.iter().advance |i| { (v.visit_item)(*i, (copy e, v)); } } -pub fn visit_view_item<E>(_vi: @view_item, (_e, _v): (E, vt<E>)) { } +pub fn visit_view_item<E>(_vi: &view_item, (_e, _v): (E, vt<E>)) { } -pub fn visit_local<E: Copy>(loc: @local, (e, v): (E, vt<E>)) { +pub fn visit_local<E: Copy>(loc: &local, (e, v): (E, vt<E>)) { (v.visit_pat)(loc.node.pat, (copy e, v)); (v.visit_ty)(loc.node.ty, (copy e, v)); match loc.node.init { @@ -142,13 +140,13 @@ pub fn visit_local<E: Copy>(loc: @local, (e, v): (E, vt<E>)) { } } -fn visit_trait_ref<E: Copy>(tref: @ast::trait_ref, (e, v): (E, vt<E>)) { +fn visit_trait_ref<E: Copy>(tref: &ast::trait_ref, (e, v): (E, vt<E>)) { visit_path(tref.path, (e, v)); } -pub fn visit_item<E: Copy>(i: @item, (e, v): (E, vt<E>)) { +pub fn visit_item<E: Copy>(i: &item, (e, v): (E, vt<E>)) { match i.node { - item_const(t, ex) => { + item_static(t, _, ex) => { (v.visit_ty)(t, (copy e, v)); (v.visit_expr)(ex, (copy e, v)); } @@ -170,8 +168,8 @@ pub fn visit_item<E: Copy>(i: @item, (e, v): (E, vt<E>)) { } item_mod(ref m) => (v.visit_mod)(m, i.span, i.id, (e, v)), item_foreign_mod(ref nm) => { - for nm.view_items.each |vi| { (v.visit_view_item)(*vi, (copy e, v)); } - for nm.items.each |ni| { (v.visit_foreign_item)(*ni, (copy e, v)); } + for nm.view_items.iter().advance |vi| { (v.visit_view_item)(*vi, (copy e, v)); } + for nm.items.iter().advance |ni| { (v.visit_foreign_item)(*ni, (copy e, v)); } } item_ty(t, ref tps) => { (v.visit_ty)(t, (copy e, v)); @@ -191,7 +189,7 @@ pub fn visit_item<E: Copy>(i: @item, (e, v): (E, vt<E>)) { visit_trait_ref(p, (copy e, v)); } (v.visit_ty)(ty, (copy e, v)); - for methods.each |m| { + for methods.iter().advance |m| { visit_method_helper(*m, (copy e, v)) } } @@ -201,8 +199,8 @@ pub fn visit_item<E: Copy>(i: @item, (e, v): (E, vt<E>)) { } item_trait(ref generics, ref traits, ref methods) => { (v.visit_generics)(generics, (copy e, v)); - for traits.each |p| { visit_path(p.path, (copy e, v)); } - for methods.each |m| { + for traits.iter().advance |p| { visit_path(p.path, (copy e, v)); } + for methods.iter().advance |m| { (v.visit_trait_method)(m, (copy e, v)); } } @@ -213,10 +211,10 @@ pub fn visit_item<E: Copy>(i: @item, (e, v): (E, vt<E>)) { pub fn visit_enum_def<E: Copy>(enum_definition: &ast::enum_def, tps: &Generics, (e, v): (E, vt<E>)) { - for enum_definition.variants.each |vr| { + for enum_definition.variants.iter().advance |vr| { match vr.node.kind { tuple_variant_kind(ref variant_args) => { - for variant_args.each |va| { + for variant_args.iter().advance |va| { (v.visit_ty)(va.ty, (copy e, v)); } } @@ -232,28 +230,36 @@ pub fn visit_enum_def<E: Copy>(enum_definition: &ast::enum_def, } } -pub fn skip_ty<E>(_t: @Ty, (_e,_v): (E, vt<E>)) {} +pub fn skip_ty<E>(_t: &Ty, (_e,_v): (E, vt<E>)) {} -pub fn visit_ty<E: Copy>(t: @Ty, (e, v): (E, vt<E>)) { +pub fn visit_ty<E: Copy>(t: &Ty, (e, v): (E, vt<E>)) { match t.node { ty_box(mt) | ty_uniq(mt) | ty_vec(mt) | ty_ptr(mt) | ty_rptr(_, mt) => { (v.visit_ty)(mt.ty, (e, v)); }, ty_tup(ref ts) => { - for ts.each |tt| { + for ts.iter().advance |tt| { (v.visit_ty)(*tt, (copy e, v)); } }, ty_closure(ref f) => { - for f.decl.inputs.each |a| { (v.visit_ty)(a.ty, (copy e, v)); } - (v.visit_ty)(f.decl.output, (e, v)); + for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); } + (v.visit_ty)(f.decl.output, (copy e, v)); + do f.bounds.map |bounds| { + visit_ty_param_bounds(bounds, (copy e, v)); + }; }, ty_bare_fn(ref f) => { - for f.decl.inputs.each |a| { (v.visit_ty)(a.ty, (copy e, v)); } + for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); } (v.visit_ty)(f.decl.output, (e, v)); }, - ty_path(p, _) => visit_path(p, (e, v)), + ty_path(p, bounds, _) => { + visit_path(p, (copy e, v)); + do bounds.map |bounds| { + visit_ty_param_bounds(bounds, (copy e, v)); + }; + }, ty_fixed_length_vec(ref mt, ex) => { (v.visit_ty)(mt.ty, (copy e, v)); (v.visit_expr)(ex, (copy e, v)); @@ -262,11 +268,11 @@ pub fn visit_ty<E: Copy>(t: @Ty, (e, v): (E, vt<E>)) { } } -pub fn visit_path<E: Copy>(p: @Path, (e, v): (E, vt<E>)) { - for p.types.each |tp| { (v.visit_ty)(*tp, (copy e, v)); } +pub fn visit_path<E: Copy>(p: &Path, (e, v): (E, vt<E>)) { + for p.types.iter().advance |tp| { (v.visit_ty)(*tp, (copy e, v)); } } -pub fn visit_pat<E: Copy>(p: @pat, (e, v): (E, vt<E>)) { +pub fn visit_pat<E: Copy>(p: &pat, (e, v): (E, vt<E>)) { match p.node { pat_enum(path, ref children) => { visit_path(path, (copy e, v)); @@ -278,12 +284,12 @@ pub fn visit_pat<E: Copy>(p: @pat, (e, v): (E, vt<E>)) { } pat_struct(path, ref fields, _) => { visit_path(path, (copy e, v)); - for fields.each |f| { + for fields.iter().advance |f| { (v.visit_pat)(f.pat, (copy e, v)); } } pat_tup(ref elts) => { - for elts.each |elt| { + for elts.iter().advance |elt| { (v.visit_pat)(*elt, (copy e, v)) } }, @@ -303,34 +309,34 @@ pub fn visit_pat<E: Copy>(p: @pat, (e, v): (E, vt<E>)) { } pat_wild => (), pat_vec(ref before, ref slice, ref after) => { - for before.each |elt| { + for before.iter().advance |elt| { (v.visit_pat)(*elt, (copy e, v)); } for slice.iter().advance |elt| { (v.visit_pat)(*elt, (copy e, v)); } - for after.each |tail| { + for after.iter().advance |tail| { (v.visit_pat)(*tail, (copy e, v)); } } } } -pub fn visit_foreign_item<E: Copy>(ni: @foreign_item, (e, v): (E, vt<E>)) { +pub fn visit_foreign_item<E: Copy>(ni: &foreign_item, (e, v): (E, vt<E>)) { match ni.node { foreign_item_fn(ref fd, _, ref generics) => { visit_fn_decl(fd, (copy e, v)); (v.visit_generics)(generics, (e, v)); } - foreign_item_const(t) => { + foreign_item_static(t, _) => { (v.visit_ty)(t, (e, v)); } } } -pub fn visit_ty_param_bounds<E: Copy>(bounds: @OptVec<TyParamBound>, +pub fn visit_ty_param_bounds<E: Copy>(bounds: &OptVec<TyParamBound>, (e, v): (E, vt<E>)) { - for bounds.each |bound| { + for bounds.iter().advance |bound| { match *bound { TraitTyParamBound(ty) => visit_trait_ref(ty, (copy e, v)), RegionTyParamBound => {} @@ -339,13 +345,13 @@ pub fn visit_ty_param_bounds<E: Copy>(bounds: @OptVec<TyParamBound>, } pub fn visit_generics<E: Copy>(generics: &Generics, (e, v): (E, vt<E>)) { - for generics.ty_params.each |tp| { + for generics.ty_params.iter().advance |tp| { visit_ty_param_bounds(tp.bounds, (copy e, v)); } } pub fn visit_fn_decl<E: Copy>(fd: &fn_decl, (e, v): (E, vt<E>)) { - for fd.inputs.each |a| { + for fd.inputs.iter().advance |a| { (v.visit_pat)(a.pat, (copy e, v)); (v.visit_ty)(a.ty, (copy e, v)); } @@ -380,7 +386,7 @@ pub fn visit_fn<E: Copy>(fk: &fn_kind, decl: &fn_decl, body: &blk, _sp: span, } pub fn visit_ty_method<E: Copy>(m: &ty_method, (e, v): (E, vt<E>)) { - for m.decl.inputs.each |a| { (v.visit_ty)(a.ty, (copy e, v)); } + for m.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); } (v.visit_generics)(&m.generics, (copy e, v)); (v.visit_ty)(m.decl.output, (e, v)); } @@ -399,30 +405,30 @@ pub fn visit_struct_def<E: Copy>( _id: node_id, (e, v): (E, vt<E>) ) { - for sd.fields.each |f| { + for sd.fields.iter().advance |f| { (v.visit_struct_field)(*f, (copy e, v)); } } -pub fn visit_struct_field<E: Copy>(sf: @struct_field, (e, v): (E, vt<E>)) { +pub fn visit_struct_field<E: Copy>(sf: &struct_field, (e, v): (E, vt<E>)) { (v.visit_ty)(sf.node.ty, (e, v)); } -pub fn visit_struct_method<E: Copy>(m: @method, (e, v): (E, vt<E>)) { +pub fn visit_struct_method<E: Copy>(m: &method, (e, v): (E, vt<E>)) { visit_method_helper(m, (e, v)); } pub fn visit_block<E: Copy>(b: &blk, (e, v): (E, vt<E>)) { - for b.node.view_items.each |vi| { + for b.node.view_items.iter().advance |vi| { (v.visit_view_item)(*vi, (copy e, v)); } - for b.node.stmts.each |s| { + for b.node.stmts.iter().advance |s| { (v.visit_stmt)(*s, (copy e, v)); } visit_expr_opt(b.node.expr, (e, v)); } -pub fn visit_stmt<E>(s: @stmt, (e, v): (E, vt<E>)) { +pub fn visit_stmt<E>(s: &stmt, (e, v): (E, vt<E>)) { match s.node { stmt_decl(d, _) => (v.visit_decl)(d, (e, v)), stmt_expr(ex, _) => (v.visit_expr)(ex, (e, v)), @@ -431,7 +437,7 @@ pub fn visit_stmt<E>(s: @stmt, (e, v): (E, vt<E>)) { } } -pub fn visit_decl<E: Copy>(d: @decl, (e, v): (E, vt<E>)) { +pub fn visit_decl<E: Copy>(d: &decl, (e, v): (E, vt<E>)) { match d.node { decl_local(ref loc) => (v.visit_local)(*loc, (e, v)), decl_item(it) => (v.visit_item)(it, (e, v)) @@ -443,7 +449,7 @@ pub fn visit_expr_opt<E>(eo: Option<@expr>, (e, v): (E, vt<E>)) { } pub fn visit_exprs<E: Copy>(exprs: &[@expr], (e, v): (E, vt<E>)) { - for exprs.each |ex| { (v.visit_expr)(*ex, (copy e, v)); } + for exprs.iter().advance |ex| { (v.visit_expr)(*ex, (copy e, v)); } } pub fn visit_mac<E>(_m: &mac, (_e, _v): (E, vt<E>)) { @@ -460,13 +466,13 @@ pub fn visit_expr<E: Copy>(ex: @expr, (e, v): (E, vt<E>)) { } expr_struct(p, ref flds, base) => { visit_path(p, (copy e, v)); - for flds.each |f| { + for flds.iter().advance |f| { (v.visit_expr)(f.node.expr, (copy e, v)); } visit_expr_opt(base, (copy e, v)); } expr_tup(ref elts) => { - for elts.each |el| { (v.visit_expr)(*el, (copy e, v)) } + for elts.iter().advance |el| { (v.visit_expr)(*el, (copy e, v)) } } expr_call(callee, ref args, _) => { visit_exprs(*args, (copy e, v)); @@ -474,7 +480,7 @@ pub fn visit_expr<E: Copy>(ex: @expr, (e, v): (E, vt<E>)) { } expr_method_call(_, callee, _, ref tys, ref args, _) => { visit_exprs(*args, (copy e, v)); - for tys.each |tp| { + for tys.iter().advance |tp| { (v.visit_ty)(*tp, (copy e, v)); } (v.visit_expr)(callee, (copy e, v)); @@ -502,7 +508,7 @@ pub fn visit_expr<E: Copy>(ex: @expr, (e, v): (E, vt<E>)) { expr_loop(ref b, _) => (v.visit_block)(b, (copy e, v)), expr_match(x, ref arms) => { (v.visit_expr)(x, (copy e, v)); - for arms.each |a| { (v.visit_arm)(a, (copy e, v)); } + for arms.iter().advance |a| { (v.visit_arm)(a, (copy e, v)); } } expr_fn_block(ref decl, ref body) => { (v.visit_fn)( @@ -526,7 +532,7 @@ pub fn visit_expr<E: Copy>(ex: @expr, (e, v): (E, vt<E>)) { } expr_field(x, _, ref tys) => { (v.visit_expr)(x, (copy e, v)); - for tys.each |tp| { + for tys.iter().advance |tp| { (v.visit_ty)(*tp, (copy e, v)); } } @@ -546,10 +552,10 @@ pub fn visit_expr<E: Copy>(ex: @expr, (e, v): (E, vt<E>)) { expr_mac(ref mac) => visit_mac(mac, (copy e, v)), expr_paren(x) => (v.visit_expr)(x, (copy e, v)), expr_inline_asm(ref a) => { - for a.inputs.each |&(_, in)| { + for a.inputs.iter().advance |&(_, in)| { (v.visit_expr)(in, (copy e, v)); } - for a.outputs.each |&(_, out)| { + for a.outputs.iter().advance |&(_, out)| { (v.visit_expr)(out, (copy e, v)); } } diff --git a/src/rt/jemalloc/Makefile.in b/src/rt/jemalloc/Makefile.in index 74810472d11..e3cecb0e840 100644 --- a/src/rt/jemalloc/Makefile.in +++ b/src/rt/jemalloc/Makefile.in @@ -9,6 +9,7 @@ vpath % . SHELL := /bin/sh CC := @CC@ +AR := @AR@ # Configuration parameters. DESTDIR = diff --git a/src/rt/jemalloc/configure b/src/rt/jemalloc/configure index 67f3dc30902..428ac770a22 100755 --- a/src/rt/jemalloc/configure +++ b/src/rt/jemalloc/configure @@ -4453,7 +4453,7 @@ PIC_CFLAGS='-fPIC -DPIC' CTARGET='-o $@' LDTARGET='-o $@' EXTRA_LDFLAGS= -MKLIB='ar crus $@' +MKLIB='$(AR) crus $@' CC_MM=1 default_munmap="1" diff --git a/src/rt/rust_android_dummy.cpp b/src/rt/rust_android_dummy.cpp index 437893594a5..add7af8a6e3 100644 --- a/src/rt/rust_android_dummy.cpp +++ b/src/rt/rust_android_dummy.cpp @@ -83,4 +83,29 @@ extern "C" int pthread_atfork(void (*prefork)(void), return 0; } +extern "C" int mlockall(int flags) +{ + return 0; +} + +extern "C" int munlockall(void) +{ + return 0; +} + +extern "C" int shm_open(const char *name, int oflag, mode_t mode) +{ + return 0; +} + +extern "C" int shm_unlink(const char *name) +{ + return 0; +} + +extern "C" int posix_madvise(void *addr, size_t len, int advice) +{ + return 0; +} + #endif diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 51e2849eb54..8dc773a4d39 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -74,13 +74,6 @@ rust_local_realloc(rust_opaque_box *ptr, size_t size) { return task->boxed.realloc(ptr, size); } -// This is completely misnamed. -extern "C" CDECL void -vec_reserve_shared(type_desc* ty, rust_vec_box** vp, - size_t n_elts) { - reserve_vec_exact(vp, n_elts * ty->size); -} - extern "C" CDECL size_t rand_seed_size() { return rng_seed_size(); @@ -153,6 +146,16 @@ debug_abi_2(floats f) { return ff; } +extern "C" int +debug_static_mut; + +int debug_static_mut = 3; + +extern "C" void +debug_static_mut_check_four() { + assert(debug_static_mut == 4); +} + /* Debug builtins for std::dbg. */ static void @@ -734,15 +737,6 @@ rust_task_deref(rust_task *task) { task->deref(); } -// Must call on rust stack. -extern "C" CDECL void -rust_call_tydesc_glue(void *root, size_t *tydesc, size_t glue_index) { - void (*glue_fn)(void *, void *, void *) = - (void (*)(void *, void *, void *))tydesc[glue_index]; - if (glue_fn) - glue_fn(0, 0, root); -} - // Don't run on the Rust stack! extern "C" void rust_log_str(uint32_t level, const char *str, size_t size) { diff --git a/src/rt/rust_exchange_alloc.cpp b/src/rt/rust_exchange_alloc.cpp index 89257dc9f6e..658d97031ce 100644 --- a/src/rt/rust_exchange_alloc.cpp +++ b/src/rt/rust_exchange_alloc.cpp @@ -15,16 +15,10 @@ #include <string.h> #include <stdio.h> -extern uintptr_t rust_exchange_count; -uintptr_t rust_exchange_count = 0; - void * rust_exchange_alloc::malloc(size_t size) { void *value = ::malloc(size); assert(value); - - sync::increment(rust_exchange_count); - return value; } @@ -37,15 +31,5 @@ rust_exchange_alloc::realloc(void *ptr, size_t size) { void rust_exchange_alloc::free(void *ptr) { - sync::decrement(rust_exchange_count); ::free(ptr); } - -void -rust_check_exchange_count_on_exit() { - if (rust_exchange_count != 0) { - printf("exchange heap not empty on exit\n"); - printf("%d dangling allocations\n", (int)rust_exchange_count); - abort(); - } -} diff --git a/src/rt/rust_exchange_alloc.h b/src/rt/rust_exchange_alloc.h index 767caf01323..9699ef6b5e9 100644 --- a/src/rt/rust_exchange_alloc.h +++ b/src/rt/rust_exchange_alloc.h @@ -21,10 +21,4 @@ class rust_exchange_alloc { void free(void *mem); }; -extern "C" uintptr_t * -rust_get_exchange_count_ptr(); - -void -rust_check_exchange_count_on_exit(); - #endif diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index c1c40222f1a..583f836c0d6 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -211,7 +211,6 @@ rust_kernel::run() { assert(osmain_driver != NULL); osmain_driver->start_main_loop(); sched_reaper.join(); - rust_check_exchange_count_on_exit(); return rval; } diff --git a/src/rt/rust_sched_loop.h b/src/rt/rust_sched_loop.h index a099c5e0c74..e0101c46fb9 100644 --- a/src/rt/rust_sched_loop.h +++ b/src/rt/rust_sched_loop.h @@ -211,12 +211,13 @@ rust_sched_loop::return_c_stack(stk_seg *stack) { // NB: Runs on the Rust stack. Might return NULL! inline stk_seg * rust_sched_loop::borrow_big_stack() { - assert(cached_big_stack); stk_seg *your_stack; if (extra_big_stack) { your_stack = extra_big_stack; extra_big_stack = NULL; } else { + // NB: This may be null if we're asking for a *second* + // big stack, in which case the caller will fall back to a slow path your_stack = cached_big_stack; cached_big_stack = NULL; } diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index fe1b4622137..4d6d2567cd4 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -54,8 +54,7 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state, disallow_yield(0), c_stack(NULL), next_c_sp(0), - next_rust_sp(0), - big_stack(NULL) + next_rust_sp(0) { LOGPTR(sched_loop, "new task", (uintptr_t)this); DLOG(sched_loop, task, "sizeof(task) = %d (0x%x)", @@ -183,7 +182,11 @@ void task_start_wrapper(spawn_args *a) if(env) { // free the environment (which should be a unique closure). const type_desc *td = env->td; - td->drop_glue(NULL, NULL, box_body(env)); + td->drop_glue(NULL, +#ifdef _RUST_STAGE0 + NULL, +#endif + box_body(env)); task->kernel->region()->free(env); } @@ -562,14 +565,8 @@ rust_task::cleanup_after_turn() { while (stk->next) { stk_seg *new_next = stk->next->next; - - if (stk->next->is_big) { - assert (big_stack == stk->next); - sched_loop->return_big_stack(big_stack); - big_stack = NULL; - } else { - free_stack(stk->next); - } + assert (!stk->next->is_big); + free_stack(stk->next); stk->next = new_next; } @@ -580,38 +577,20 @@ rust_task::cleanup_after_turn() { bool rust_task::new_big_stack() { assert(stk); - // If we have a cached big stack segment, use it. - if (big_stack) { - // Check to see if we're already on the big stack. - stk_seg *ss = stk; - while (ss != NULL) { - if (ss == big_stack) - return false; - ss = ss->prev; - } - // Unlink the big stack. - if (big_stack->next) - big_stack->next->prev = big_stack->prev; - if (big_stack->prev) - big_stack->prev->next = big_stack->next; - } else { - stk_seg *borrowed_big_stack = sched_loop->borrow_big_stack(); - if (!borrowed_big_stack) { - abort(); - } else { - big_stack = borrowed_big_stack; - } + stk_seg *borrowed_big_stack = sched_loop->borrow_big_stack(); + if (!borrowed_big_stack) { + return false; } - big_stack->task = this; - big_stack->next = stk->next; - if (big_stack->next) - big_stack->next->prev = big_stack; - big_stack->prev = stk; - stk->next = big_stack; + borrowed_big_stack->task = this; + borrowed_big_stack->next = stk->next; + if (borrowed_big_stack->next) + borrowed_big_stack->next->prev = borrowed_big_stack; + borrowed_big_stack->prev = stk; + stk->next = borrowed_big_stack; - stk = big_stack; + stk = borrowed_big_stack; return true; } @@ -636,10 +615,9 @@ void rust_task::reset_stack_limit() { uintptr_t sp = get_sp(); while (!sp_in_stk_seg(sp, stk)) { - stk = stk->prev; + prev_stack(); assert(stk != NULL && "Failed to find the current stack"); } - record_stack_limit(); } void @@ -663,8 +641,6 @@ rust_task::delete_all_stacks() { stk = prev; } - - big_stack = NULL; } /* diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 982102cdde0..1735d35b065 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -278,9 +278,6 @@ private: uintptr_t next_c_sp; uintptr_t next_rust_sp; - // The big stack. - stk_seg *big_stack; - // Called when the atomic refcount reaches zero void delete_this(); @@ -607,7 +604,21 @@ rust_task::prev_stack() { // require switching to the C stack and be costly. Instead we'll just move // up the link list and clean up later, either in new_stack or after our // turn ends on the scheduler. - stk = stk->prev; + if (stk->is_big) { + stk_seg *ss = stk; + stk = stk->prev; + + // Unlink the big stack. + if (ss->next) + ss->next->prev = ss->prev; + if (ss->prev) + ss->prev->next = ss->next; + + sched_loop->return_big_stack(ss); + } else { + stk = stk->prev; + } + record_stack_limit(); } diff --git a/src/rt/rust_type.h b/src/rt/rust_type.h index 6d36d2c960a..30ff5f1fa54 100644 --- a/src/rt/rust_type.h +++ b/src/rt/rust_type.h @@ -25,7 +25,11 @@ typedef void (*CDECL spawn_fn)(rust_opaque_box*, void *); struct type_desc; -typedef void CDECL (glue_fn)(void *, const type_desc **, void *); +typedef void CDECL (glue_fn)(void *, +#ifdef _RUST_STAGE0 + const type_desc **, +#endif + void *); // Corresponds to the boxed data in the @ region. The body follows the // header; you can obtain a ptr via box_body() below. @@ -57,8 +61,6 @@ struct type_desc { glue_fn *drop_glue; glue_fn *free_glue; glue_fn *visit_glue; - const uint8_t *unused; - const uint8_t *unused2; }; extern "C" type_desc *rust_clone_type_desc(type_desc*); diff --git a/src/rt/rust_util.cpp b/src/rt/rust_util.cpp index 8d80a344063..4a15830e529 100644 --- a/src/rt/rust_util.cpp +++ b/src/rt/rust_util.cpp @@ -21,8 +21,6 @@ struct type_desc str_body_tydesc = { NULL, // drop_glue NULL, // free_glue NULL, // visit_glue - NULL, // shape - NULL, // shape_tables }; // diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index a08a142df77..ff89fdbfb7c 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -7,6 +7,8 @@ debug_tydesc debug_get_stk_seg debug_abi_1 debug_abi_2 +debug_static_mut +debug_static_mut_check_four get_task_id get_time rust_tzset @@ -54,7 +56,6 @@ rust_get_c_stack rust_log_str start_task rust_local_realloc -vec_reserve_shared task_clear_event_reject task_wait_event task_signal_event @@ -175,7 +176,6 @@ rust_set_task_local_data rust_task_local_data_atexit rust_task_ref rust_task_deref -rust_call_tydesc_glue tdefl_compress_mem_to_heap tinfl_decompress_mem_to_heap rust_gc_metadata @@ -197,7 +197,6 @@ rust_register_exit_function rust_get_global_data_ptr rust_inc_kernel_live_count rust_dec_kernel_live_count -rust_exchange_count rust_get_rt_tls_key swap_registers rust_readdir @@ -247,4 +246,4 @@ rust_get_num_cpus rust_get_global_args_ptr rust_current_boxed_region rust_take_global_args_lock -rust_drop_global_args_lock \ No newline at end of file +rust_drop_global_args_lock diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger new file mode 100644 index 00000000000..fbd687778ae --- /dev/null +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -0,0 +1,4 @@ +# If this file is modified, then llvm will be forcibly cleaned and then rebuilt. +# The actual contents of this file do not matter, but to trigger a change on the +# build bots then the contents should be changed so git updates the mtime. +6-29-2013 diff --git a/src/snapshots.txt b/src/snapshots.txt index 1aaf5fee26a..910de5f66b7 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2013-06-23 f827561 + macos-i386 63ffbcf99b6853d7840bdfe01380068518d0e466 + macos-x86_64 b34fdf3845f8ef4760817007d8ef820cd32f2e07 + winnt-i386 6602150074ec442fd376fddb2eaf63f5da6fdff9 + freebsd-x86_64 a05bdda2d9ec0e66336d81b98bee8a95442a501f + linux-i386 b8f4a0f0c2250aa4d76ec1eb57c83bfae5725f93 + linux-x86_64 caea3402663334d0a3967c21f58a860c060d5474 + S 2013-06-21 6759ce4 macos-i386 6e5395d2fda1db356f64af28ba525031bf9871c7 macos-x86_64 7b8ded4e1ba1e999a5614eea3a4acacb2c7cef1d diff --git a/src/test/auxiliary/cci_capture_clause.rs b/src/test/auxiliary/cci_capture_clause.rs index e45bfc8ea5d..beca0adbe3c 100644 --- a/src/test/auxiliary/cci_capture_clause.rs +++ b/src/test/auxiliary/cci_capture_clause.rs @@ -11,7 +11,7 @@ use std::comm::*; use std::task; -pub fn foo<T:Owned + Copy>(x: T) -> Port<T> { +pub fn foo<T:Send + Copy>(x: T) -> Port<T> { let (p, c) = stream(); do task::spawn() { c.send(copy x); diff --git a/src/test/auxiliary/cci_nested_lib.rs b/src/test/auxiliary/cci_nested_lib.rs index c0b98f2af07..2c9b28e6282 100644 --- a/src/test/auxiliary/cci_nested_lib.rs +++ b/src/test/auxiliary/cci_nested_lib.rs @@ -24,7 +24,7 @@ pub fn alist_add<A:Copy,B:Copy>(lst: &alist<A,B>, k: A, v: B) { pub fn alist_get<A:Copy,B:Copy>(lst: &alist<A,B>, k: A) -> B { let eq_fn = lst.eq_fn; - for lst.data.each |entry| { + for lst.data.iter().advance |entry| { if eq_fn(copy entry.key, copy k) { return copy entry.value; } } fail!(); diff --git a/src/test/auxiliary/issue-2526.rs b/src/test/auxiliary/issue-2526.rs index bbc0f1ad3e5..8c491a4dfc8 100644 --- a/src/test/auxiliary/issue-2526.rs +++ b/src/test/auxiliary/issue-2526.rs @@ -20,17 +20,17 @@ struct arc_destruct<T> { } #[unsafe_destructor] -impl<T:Const> Drop for arc_destruct<T> { - fn finalize(&self) {} +impl<T:Freeze> Drop for arc_destruct<T> { + fn drop(&self) {} } -fn arc_destruct<T:Const>(data: int) -> arc_destruct<T> { +fn arc_destruct<T:Freeze>(data: int) -> arc_destruct<T> { arc_destruct { _data: data } } -fn arc<T:Const>(_data: T) -> arc_destruct<T> { +fn arc<T:Freeze>(_data: T) -> arc_destruct<T> { arc_destruct(0) } @@ -45,7 +45,7 @@ struct context_res { } impl Drop for context_res { - fn finalize(&self) {} + fn drop(&self) {} } fn context_res() -> context_res { diff --git a/src/test/auxiliary/issue-3012-1.rs b/src/test/auxiliary/issue-3012-1.rs index ce40afff3ae..9c9b3d9f243 100644 --- a/src/test/auxiliary/issue-3012-1.rs +++ b/src/test/auxiliary/issue-3012-1.rs @@ -19,7 +19,7 @@ pub mod socket { } impl Drop for socket_handle { - fn finalize(&self) { + fn drop(&self) { /* c::close(self.sockfd); */ } } diff --git a/src/test/auxiliary/issue2170lib.rs b/src/test/auxiliary/issue2170lib.rs index 0690a017449..ec5d8baf259 100644 --- a/src/test/auxiliary/issue2170lib.rs +++ b/src/test/auxiliary/issue2170lib.rs @@ -16,7 +16,7 @@ pub struct rsrc { } impl Drop for rsrc { - fn finalize(&self) { + fn drop(&self) { foo(self.x); } } diff --git a/src/test/auxiliary/moves_based_on_type_lib.rs b/src/test/auxiliary/moves_based_on_type_lib.rs index b3a9b3e1ee9..cd72468511e 100644 --- a/src/test/auxiliary/moves_based_on_type_lib.rs +++ b/src/test/auxiliary/moves_based_on_type_lib.rs @@ -15,7 +15,7 @@ pub struct S { } impl Drop for S { - fn finalize(&self) { + fn drop(&self) { println("goodbye"); } } diff --git a/src/test/auxiliary/static_mut_xc.rs b/src/test/auxiliary/static_mut_xc.rs new file mode 100644 index 00000000000..8dc45c681bf --- /dev/null +++ b/src/test/auxiliary/static_mut_xc.rs @@ -0,0 +1 @@ +pub static mut a: int = 3; diff --git a/src/test/auxiliary/trait_default_method_xc_aux.rs b/src/test/auxiliary/trait_default_method_xc_aux.rs new file mode 100644 index 00000000000..5ee243179df --- /dev/null +++ b/src/test/auxiliary/trait_default_method_xc_aux.rs @@ -0,0 +1,34 @@ +#[allow(default_methods)]; + +pub trait A { + fn f(&self) -> int; + fn g(&self) -> int { 10 } + fn h(&self) -> int { 10 } +} + + +impl A for int { + fn f(&self) -> int { 10 } +} + +trait B<T> { + fn thing<U>(&self, x: T, y: U) -> (T, U) { (x, y) } +} + +impl<T> B<T> for int { } +impl B<float> for bool { } + + + +pub trait TestEquality { + fn test_eq(&self, rhs: &Self) -> bool; + fn test_neq(&self, rhs: &Self) -> bool { + !self.test_eq(rhs) + } +} + +impl TestEquality for int { + fn test_eq(&self, rhs: &int) -> bool { + *self == *rhs + } +} diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 287daf68eff..c4d89a698c1 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -29,7 +29,7 @@ macro_rules! bench ( fn main() { let argv = os::args(); - let tests = vec::slice(argv, 1, argv.len()); + let tests = argv.slice(1, argv.len()); bench!(shift_push); bench!(read_line); @@ -44,7 +44,7 @@ fn maybe_run_test(argv: &[~str], name: ~str, test: &fn()) { if os::getenv(~"RUST_BENCH").is_some() { run_test = true } else if argv.len() > 0 { - run_test = argv.contains(&~"all") || argv.contains(&name) + run_test = argv.iter().any_(|x| x == &~"all") || argv.iter().any_(|x| x == &name) } if !run_test { @@ -87,9 +87,8 @@ fn vec_plus() { while i < 1500 { let rv = vec::from_elem(r.gen_uint_range(0, i + 1), i); if r.gen() { - v += rv; - } - else { + v.push_all_move(rv); + } else { v = rv + v; } i += 1; diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs index 8b7f5829cbe..bc5efc5fca1 100644 --- a/src/test/bench/graph500-bfs.rs +++ b/src/test/bench/graph500-bfs.rs @@ -86,7 +86,7 @@ fn make_graph(N: uint, edges: ~[(node_id, node_id)]) -> graph { HashSet::new() }; - for vec::each(edges) |e| { + for edges.iter().advance |e| { match *e { (i, j) => { graph[i].insert(j); @@ -141,7 +141,7 @@ fn bfs(graph: graph, key: node_id) -> bfs_result { while !q.is_empty() { let t = q.pop_front(); - do graph[t].each() |k| { + do graph[t].iter().advance |k| { if marks[*k] == -1i64 { marks[*k] = t; q.add_back(*k); @@ -191,17 +191,17 @@ fn bfs2(graph: graph, key: node_id) -> bfs_result { // Do the BFS. info!("PBFS iteration %?", i); i += 1; - colors = do colors.mapi() |i, c| { + colors = do colors.iter().enumerate().transform |(i, c)| { let c : color = *c; match c { white => { let i = i as node_id; - let neighbors = copy graph[i]; + let neighbors = &graph[i]; let mut color = white; - do neighbors.each() |k| { + do neighbors.iter().advance |k| { if is_gray(&colors[*k]) { color = gray(*k); false @@ -214,17 +214,17 @@ fn bfs2(graph: graph, key: node_id) -> bfs_result { gray(parent) => { black(parent) } black(parent) => { black(parent) } } - } + }.collect() } // Convert the results. - do vec::map(colors) |c| { + do colors.iter().transform |c| { match *c { white => { -1i64 } black(parent) => { parent } _ => { fail!("Found remaining gray nodes in BFS") } } - } + }.collect() } /// A parallel version of the bfs function. @@ -286,7 +286,7 @@ fn pbfs(graph: &arc::ARC<graph>, key: node_id) -> bfs_result { let mut color = white; - do neighbors.each() |k| { + do neighbors.iter().advance |k| { if is_gray(&colors[*k]) { color = gray(*k); false @@ -341,7 +341,7 @@ fn validate(edges: ~[(node_id, node_id)], } else { while parent != root { - if vec::contains(path, &parent) { + if path.contains(&parent) { status = false; } @@ -378,7 +378,7 @@ fn validate(edges: ~[(node_id, node_id)], info!(~"Verifying graph edges..."); - let status = do edges.all() |e| { + let status = do edges.iter().all |e| { let (u, v) = *e; abs(level[u] - level[v]) <= 1 @@ -402,7 +402,7 @@ fn validate(edges: ~[(node_id, node_id)], if *v == -1i64 || u == root { true } else { - edges.contains(&(u, *v)) || edges.contains(&(*v, u)) + edges.iter().any_(|x| x == &(u, *v)) || edges.iter().any_(|x| x == &(*v, u)) } }; result @@ -441,7 +441,7 @@ fn main() { let stop = time::precise_time_s(); let mut total_edges = 0; - vec::each(graph, |edges| { total_edges += edges.len(); true }); + for graph.iter().advance |edges| { total_edges += edges.len(); } io::stdout().write_line(fmt!("Generated graph with %? edges in %? seconds.", total_edges / 2, diff --git a/src/test/bench/msgsend-pipes-shared.rs b/src/test/bench/msgsend-pipes-shared.rs index 7a9be754884..102f7f17065 100644 --- a/src/test/bench/msgsend-pipes-shared.rs +++ b/src/test/bench/msgsend-pipes-shared.rs @@ -83,7 +83,7 @@ fn run(args: &[~str]) { server(&from_parent, &to_parent); } - for vec::each(worker_results) |r| { + for worker_results.iter().advance |r| { r.recv(); } diff --git a/src/test/bench/msgsend-pipes.rs b/src/test/bench/msgsend-pipes.rs index 796072c8485..b8d91bb93e2 100644 --- a/src/test/bench/msgsend-pipes.rs +++ b/src/test/bench/msgsend-pipes.rs @@ -79,7 +79,7 @@ fn run(args: &[~str]) { server(&from_parent, &to_parent); } - for vec::each(worker_results) |r| { + for worker_results.iter().advance |r| { r.recv(); } diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 25bdf7dc3fe..b65a6429f2c 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -118,10 +118,10 @@ fn main() { }; }; - /*for int::range(0, 256) |y| { + for int::range(0, 256) |y| { for int::range(0, 256) |x| { - io::print(symbols[pixels[y*256+x] / 0.2f32 as int]); + print(symbols[pixels[y*256+x] / 0.2f32 as int]); } - io::println(""); - }*/ + println(""); + } } diff --git a/src/test/bench/pingpong.rs b/src/test/bench/pingpong.rs index 63e4174a0fc..1d32a78303a 100644 --- a/src/test/bench/pingpong.rs +++ b/src/test/bench/pingpong.rs @@ -82,7 +82,7 @@ endpoint. The send endpoint is returned to the caller and the receive endpoint is passed to the new task. */ -pub fn spawn_service<T:Owned,Tb:Owned>( +pub fn spawn_service<T:Send,Tb:Send>( init: extern fn() -> (RecvPacketBuffered<T, Tb>, SendPacketBuffered<T, Tb>), service: ~fn(v: RecvPacketBuffered<T, Tb>)) @@ -103,7 +103,7 @@ pub fn spawn_service<T:Owned,Tb:Owned>( receive state. */ -pub fn spawn_service_recv<T:Owned,Tb:Owned>( +pub fn spawn_service_recv<T:Send,Tb:Send>( init: extern fn() -> (SendPacketBuffered<T, Tb>, RecvPacketBuffered<T, Tb>), service: ~fn(v: SendPacketBuffered<T, Tb>)) @@ -120,7 +120,7 @@ pub fn spawn_service_recv<T:Owned,Tb:Owned>( client } -fn switch<T:Owned,Tb:Owned,U>(endp: std::pipes::RecvPacketBuffered<T, Tb>, +fn switch<T:Send,Tb:Send,U>(endp: std::pipes::RecvPacketBuffered<T, Tb>, f: &fn(v: Option<T>) -> U) -> U { f(std::pipes::try_recv(endp)) diff --git a/src/test/bench/shootout-binarytrees.rs b/src/test/bench/shootout-binarytrees.rs index e7aed911cb0..76ef4c12380 100644 --- a/src/test/bench/shootout-binarytrees.rs +++ b/src/test/bench/shootout-binarytrees.rs @@ -1,8 +1,4 @@ -// xfail-test - -// Broken due to arena API problems. - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -15,33 +11,35 @@ extern mod extra; use extra::arena; -enum tree<'self> { - nil, - node(&'self tree<'self>, &'self tree<'self>, int), +enum Tree<'self> { + Nil, + Node(&'self Tree<'self>, &'self Tree<'self>, int), } -fn item_check(t: &tree) -> int { +fn item_check(t: &Tree) -> int { match *t { - nil => { return 0; } - node(left, right, item) => { + Nil => { return 0; } + Node(left, right, item) => { return item + item_check(left) - item_check(right); } } } -fn bottom_up_tree<'r>(arena: &'r mut arena::Arena, item: int, depth: int) - -> &'r tree<'r> { +fn bottom_up_tree<'r>(arena: &'r arena::Arena, item: int, depth: int) + -> &'r Tree<'r> { if depth > 0 { return arena.alloc( - || node(bottom_up_tree(arena, 2 * item - 1, depth - 1), + || Node(bottom_up_tree(arena, 2 * item - 1, depth - 1), bottom_up_tree(arena, 2 * item, depth - 1), item)); } - return arena.alloc(|| nil); + return arena.alloc(|| Nil); } fn main() { - let args = os::args(); + use std::os; + use std::int; + let args = std::os::args(); let args = if os::getenv(~"RUST_BENCH").is_some() { ~[~"", ~"17"] } else if args.len() <= 1u { @@ -59,34 +57,34 @@ fn main() { max_depth = n; } - let mut stretch_arena = arena::Arena(); + let stretch_arena = arena::Arena(); let stretch_depth = max_depth + 1; - let stretch_tree = bottom_up_tree(&mut stretch_arena, 0, stretch_depth); + let stretch_tree = bottom_up_tree(&stretch_arena, 0, stretch_depth); - io::println(fmt!("stretch tree of depth %d\t check: %d", + println(fmt!("stretch tree of depth %d\t check: %d", stretch_depth, item_check(stretch_tree))); - let mut long_lived_arena = arena::Arena(); - let long_lived_tree = bottom_up_tree(&mut long_lived_arena, 0, max_depth); + let long_lived_arena = arena::Arena(); + let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth); let mut depth = min_depth; while depth <= max_depth { let iterations = int::pow(2, (max_depth - depth + min_depth) as uint); let mut chk = 0; let mut i = 1; while i <= iterations { - let mut temp_tree = bottom_up_tree(&mut long_lived_arena, i, depth); + let mut temp_tree = bottom_up_tree(&long_lived_arena, i, depth); chk += item_check(temp_tree); - temp_tree = bottom_up_tree(&mut long_lived_arena, -i, depth); + temp_tree = bottom_up_tree(&long_lived_arena, -i, depth); chk += item_check(temp_tree); i += 1; } - io::println(fmt!("%d\t trees of depth %d\t check: %d", + println(fmt!("%d\t trees of depth %d\t check: %d", iterations * 2, depth, chk)); depth += 2; } - io::println(fmt!("long lived trees of depth %d\t check: %d", + println(fmt!("long lived tree of depth %d\t check: %d", max_depth, item_check(long_lived_tree))); } diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 53b47b12144..deb2d4b300b 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -23,11 +23,11 @@ use std::uint; use std::vec; fn print_complements() { - let all = ~[Blue, Red, Yellow]; - for vec::each(all) |aa| { - for vec::each(all) |bb| { - io::println(show_color(*aa) + " + " + show_color(*bb) + - " -> " + show_color(transform(*aa, *bb))); + let all = [Blue, Red, Yellow]; + for all.iter().advance |aa| { + for all.iter().advance |bb| { + println(show_color(*aa) + " + " + show_color(*bb) + + " -> " + show_color(transform(*aa, *bb))); } } } @@ -49,9 +49,9 @@ fn show_color(cc: color) -> ~str { fn show_color_list(set: ~[color]) -> ~str { let mut out = ~""; - for vec::eachi(set) |_ii, col| { - out += " "; - out += show_color(*col); + for set.iter().advance |col| { + out.push_char(' '); + out.push_str(show_color(*col)); } return out; } @@ -85,7 +85,7 @@ fn show_number(nn: uint) -> ~str { out = show_digit(dig) + " " + out; } - return out; + return ~" " + out; } fn transform(aa: color, bb: color) -> color { @@ -152,7 +152,7 @@ fn rendezvous(nn: uint, set: ~[color]) { // these channels will allow us to talk to each creature by 'name'/index let to_creature: ~[Chan<Option<CreatureInfo>>] = - vec::mapi(set, |ii, col| { + set.iter().enumerate().transform(|(ii, col)| { // create each creature as a listener with a port, and // give us a channel to talk to each let ii = ii; @@ -166,7 +166,7 @@ fn rendezvous(nn: uint, set: ~[color]) { to_rendezvous_log.clone()); } to_creature - }); + }).collect(); let mut creatures_met = 0; @@ -182,13 +182,13 @@ fn rendezvous(nn: uint, set: ~[color]) { } // tell each creature to stop - for vec::eachi(to_creature) |_ii, to_one| { + for to_creature.iter().advance |to_one| { to_one.send(None); } // save each creature's meeting stats let mut report = ~[]; - for vec::each(to_creature) |_to_one| { + for to_creature.iter().advance |_to_one| { report.push(from_creatures_log.recv()); } @@ -196,7 +196,7 @@ fn rendezvous(nn: uint, set: ~[color]) { io::println(show_color_list(set)); // print each creature's stats - for vec::each(report) |rep| { + for report.iter().advance |rep| { io::println(*rep); } diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index 8c8b26afa08..5ebcfe164ce 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -59,7 +59,7 @@ static HOMO_SAPIENS: [AminoAcid, ..4] = [ fn sum_and_scale(a: &'static [AminoAcid]) -> ~[AminoAcid] { let mut result = ~[]; let mut p = 0f32; - for a.each |a_i| { + for a.iter().advance |a_i| { let mut a_i = *a_i; p += a_i.p; a_i.p = p * LOOKUP_SCALE; @@ -96,7 +96,7 @@ impl RepeatFasta { copy_memory(buf, alu, alu_len); let buf_len = buf.len(); - copy_memory(vec::mut_slice(buf, alu_len, buf_len), + copy_memory(buf.mut_slice(alu_len, buf_len), alu, LINE_LEN); @@ -151,7 +151,7 @@ impl RandomFasta { fn nextc(&mut self) -> u8 { let r = self.rng(1.0); - for self.lookup.each |a| { + for self.lookup.iter().advance |a| { if a.p >= r { return a.c; } diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 5c77e698bec..da8d65a1dcb 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -19,16 +19,14 @@ extern mod extra; use std::int; use std::io; -use std::option; use std::os; use std::rand::Rng; use std::rand; use std::result; use std::str; use std::uint; -use std::vec; -fn LINE_LENGTH() -> uint { return 60u; } +static LINE_LENGTH: uint = 60u; struct MyRandom { last: u32 @@ -47,11 +45,11 @@ struct AminoAcids { fn make_cumulative(aa: ~[AminoAcids]) -> ~[AminoAcids] { let mut cp: u32 = 0u32; let mut ans: ~[AminoAcids] = ~[]; - for aa.each |a| { + for aa.iter().advance |a| { cp += a.prob; - ans += [AminoAcids {ch: a.ch, prob: cp}]; + ans.push(AminoAcids {ch: a.ch, prob: cp}); } - return ans; + ans } fn select_random(r: u32, genelist: ~[AminoAcids]) -> char { @@ -64,7 +62,7 @@ fn select_random(r: u32, genelist: ~[AminoAcids]) -> char { } else { return bisect(v, mid, hi, target); } } else { return v[hi].ch; } } - return bisect(copy genelist, 0, genelist.len() - 1, r); + bisect(copy genelist, 0, genelist.len() - 1, r) } fn make_random_fasta(wr: @io::Writer, @@ -81,7 +79,7 @@ fn make_random_fasta(wr: @io::Writer, for uint::range(0u, n as uint) |_i| { op.push_char(select_random(myrandom_next(rng, 100u32), copy genelist)); - if op.len() >= LINE_LENGTH() { + if op.len() >= LINE_LENGTH { wr.write_line(op); op = ~""; } @@ -90,28 +88,28 @@ fn make_random_fasta(wr: @io::Writer, } fn make_repeat_fasta(wr: @io::Writer, id: ~str, desc: ~str, s: ~str, n: int) { - unsafe { - wr.write_line(~">" + id + " " + desc); - let mut op: ~str = ~""; - let sl: uint = s.len(); - for uint::range(0u, n as uint) |i| { - str::raw::push_byte(&mut op, s[i % sl]); - if op.len() >= LINE_LENGTH() { - wr.write_line(op); - op = ~""; - } + wr.write_line(~">" + id + " " + desc); + let mut op = str::with_capacity( LINE_LENGTH ); + let sl = s.len(); + for uint::range(0u, n as uint) |i| { + if (op.len() >= LINE_LENGTH) { + wr.write_line( op ); + op = str::with_capacity( LINE_LENGTH ); } - if op.len() > 0u { wr.write_line(op); } + op.push_char( s[i % sl] as char ); + } + if op.len() > 0 { + wr.write_line(op) } } fn acid(ch: char, prob: u32) -> AminoAcids { - return AminoAcids {ch: ch, prob: prob}; + AminoAcids {ch: ch, prob: prob} } fn main() { let args = os::args(); - let args = if os::getenv(~"RUST_BENCH").is_some() { + let args = if os::getenv("RUST_BENCH").is_some() { // alioth tests k-nucleotide with this data at 25,000,000 ~[~"", ~"5000000"] } else if args.len() <= 1u { @@ -120,9 +118,9 @@ fn main() { args }; - let writer = if os::getenv(~"RUST_BENCH").is_some() { + let writer = if os::getenv("RUST_BENCH").is_some() { result::get(&io::file_writer(&Path("./shootout-fasta.data"), - ~[io::Truncate, io::Create])) + [io::Truncate, io::Create])) } else { io::stdout() }; diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index e12df5811ee..974cdb0a0ef 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-pretty (extra blank line is inserted in vec::mapi call) +// xfail-pretty the `let to_child` line gets an extra newline // multi tasking k-nucleotide extern mod extra; @@ -56,7 +56,7 @@ fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str { let mut pairs = ~[]; // map -> [(k,%)] - for mm.each |&key, &val| { + for mm.iter().advance |(&key, &val)| { pairs.push((key, pct(val, total))); } @@ -64,13 +64,13 @@ fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str { let mut buffer = ~""; - for pairs_sorted.each |kv| { + for pairs_sorted.iter().advance |kv| { let (k,v) = copy *kv; unsafe { let b = str::raw::from_bytes(k); // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use // to_ascii_consume and to_str_consume to not do a unnecessary copy. - buffer += (fmt!("%s %0.3f\n", b.to_ascii().to_upper().to_str_ascii(), v)); + buffer.push_str(fmt!("%s %0.3f\n", b.to_ascii().to_upper().to_str_ascii(), v)); } } @@ -90,7 +90,7 @@ fn find(mm: &HashMap<~[u8], uint>, key: ~str) -> uint { // given a map, increment the counter for a key fn update_freq(mm: &mut HashMap<~[u8], uint>, key: &[u8]) { - let key = vec::slice(key, 0, key.len()).to_vec(); + let key = key.to_owned(); let newval = match mm.pop(&key) { Some(v) => v + 1, None => 1 @@ -107,11 +107,11 @@ fn windows_with_carry(bb: &[u8], nn: uint, let len = bb.len(); while ii < len - (nn - 1u) { - it(vec::slice(bb, ii, ii+nn)); + it(bb.slice(ii, ii+nn)); ii += 1u; } - return vec::slice(bb, len - (nn - 1u), len).to_vec(); + return bb.slice(len - (nn - 1u), len).to_owned(); } fn make_sequence_processor(sz: uint, @@ -163,14 +163,13 @@ fn main() { - // initialize each sequence sorter - let sizes = ~[1,2,3,4,6,12,18]; - let streams = vec::map(sizes, |_sz| Some(stream())); - let mut streams = streams; + // initialize each sequence sorter + let sizes = ~[1u,2,3,4,6,12,18]; + let mut streams = vec::from_fn(sizes.len(), |_| Some(stream::<~str>())); let mut from_child = ~[]; - let to_child = vec::mapi(sizes, |ii, sz| { + let to_child = do sizes.iter().zip(streams.mut_iter()).transform |(sz, stream_ref)| { let sz = *sz; - let stream = util::replace(&mut streams[ii], None); + let stream = util::replace(stream_ref, None); let (from_child_, to_parent_) = stream.unwrap(); from_child.push(from_child_); @@ -182,7 +181,7 @@ fn main() { }; to_child - }); + }.collect::<~[Chan<~[u8]>]>(); // latch stores true after we've started @@ -211,7 +210,7 @@ fn main() { (_, true) => { let line_bytes = line.as_bytes(); - for sizes.eachi |ii, _sz| { + for sizes.iter().enumerate().advance |(ii, _sz)| { let mut lb = line_bytes.to_owned(); to_child[ii].send(lb); } @@ -223,12 +222,12 @@ fn main() { } // finish... - for sizes.eachi |ii, _sz| { + for sizes.iter().enumerate().advance |(ii, _sz)| { to_child[ii].send(~[]); } // now fetch and print result messages - for sizes.eachi |ii, _sz| { + for sizes.iter().enumerate().advance |(ii, _sz)| { io::println(from_child[ii].recv()); } } diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index 646b9788f70..405aa68c483 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -8,7 +8,7 @@ use std::libc::{STDIN_FILENO, c_int, fdopen, fgets, fileno, fopen, fstat}; use std::libc::{stat, strlen}; use std::ptr::null; use std::unstable::intrinsics::init; -use std::vec::{reverse, slice}; +use std::vec::{reverse}; use extra::sort::quick_sort3; static LINE_LEN: uint = 80; @@ -194,7 +194,7 @@ fn unpack_symbol(c: u8) -> u8 { fn next_char<'a>(mut buf: &'a [u8]) -> &'a [u8] { loop { - buf = slice(buf, 1, buf.len()); + buf = buf.slice(1, buf.len()); if buf.len() == 0 { break; } @@ -226,7 +226,7 @@ fn read_stdin() -> ~[u8] { fgets(transmute(&mut window[0]), LINE_LEN as c_int, stdin); { - if vec::slice(window, 0, 6) == header { + if window.slice(0, 6) == header { break; } } @@ -235,9 +235,7 @@ fn read_stdin() -> ~[u8] { while fgets(transmute(&mut window[0]), LINE_LEN as c_int, stdin) != null() { - window = vec::mut_slice(window, - strlen(transmute(&window[0])) as uint, - window.len()); + window = window.mut_slice(strlen(transmute(&window[0])) as uint, window.len()); } } diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index 70f56f5c5a3..b79ecd03c0c 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -23,7 +23,10 @@ fn main() { for range(0, h) |y| { let y = y as f64; for range(0, w) |x| { - let mut (Zr, Zi, Tr, Ti) = (0f64, 0f64, 0f64, 0f64); + let mut Zr = 0f64; + let mut Zi = 0f64; + let mut Tr = 0f64; + let mut Ti = 0f64; let Cr = 2.0 * (x as f64) / (w as f64) - 1.5; let Ci = 2.0 * (y as f64) / (h as f64) - 1.0; diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index b869aa0e342..295211e03a1 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -32,7 +32,6 @@ use std::str; use std::task; use std::u64; use std::uint; -use std::vec; fn fib(n: int) -> int { fn pfib(c: &Chan<int>, n: int) { @@ -62,7 +61,7 @@ struct Config { fn parse_opts(argv: ~[~str]) -> Config { let opts = ~[getopts::optflag(~"stress")]; - let opt_args = vec::slice(argv, 1, argv.len()); + let opt_args = argv.slice(1, argv.len()); match getopts::getopts(opt_args, opts) { Ok(ref m) => { @@ -91,7 +90,7 @@ fn stress(num_tasks: int) { stress_task(i); } } - for results.each |r| { + for results.iter().advance |r| { r.recv(); } } diff --git a/src/test/bench/shootout-reverse-complement.rs b/src/test/bench/shootout-reverse-complement.rs index 9893785ecfa..e57dee06c75 100644 --- a/src/test/bench/shootout-reverse-complement.rs +++ b/src/test/bench/shootout-reverse-complement.rs @@ -5,7 +5,6 @@ use std::cast::transmute; use std::libc::{STDOUT_FILENO, c_int, fdopen, fgets, fopen, fputc, fwrite}; use std::libc::{size_t}; use std::ptr::null; -use std::vec::{capacity, reserve, reserve_at_least}; use std::vec::raw::set_len; static LINE_LEN: u32 = 80; @@ -103,13 +102,13 @@ fn main() { let stdout = fdopen(STDOUT_FILENO as c_int, transmute(&mode[0])); let mut out: ~[u8] = ~[]; - reserve(&mut out, 12777888); + out.reserve(12777888); let mut pos = 0; loop { let needed = pos + (LINE_LEN as uint) + 1; - if capacity(&out) < needed { - reserve_at_least(&mut out, needed); + if out.capacity() < needed { + out.reserve_at_least(needed); } let mut ptr = out.unsafe_mut_ref(pos); diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index 95139239517..35a37e55332 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -1,3 +1,13 @@ +// Copyright 2012-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. + use std::f64; use std::from_str::FromStr; use std::os; @@ -10,7 +20,7 @@ fn A(i: i32, j: i32) -> i32 { fn dot(v: &[f64], u: &[f64]) -> f64 { let mut sum = 0.0; - for v.eachi |i, &v_i| { + for v.iter().enumerate().advance |(i, &v_i)| { sum += v_i * u[i]; } sum diff --git a/src/test/bench/shootout-threadring.rs b/src/test/bench/shootout-threadring.rs index 213c5140ccf..97168de5d43 100644 --- a/src/test/bench/shootout-threadring.rs +++ b/src/test/bench/shootout-threadring.rs @@ -10,18 +10,20 @@ // Based on threadring.erlang by Jira Isa -// xfail-test FIXME #5985 OOM's on the mac bot +use std::os; fn start(n_tasks: int, token: int) { - let mut (p, ch1) = comm::stream(); + let (p, ch1) = stream(); + let mut p = p; + let mut ch1 = ch1; ch1.send(token); // XXX could not get this to work with a range closure let mut i = 2; while i <= n_tasks { - let (next_p, ch) = comm::stream(); + let (next_p, ch) = stream(); let imm_i = i; let imm_p = p; - do task::spawn { + do spawn { roundtrip(imm_i, n_tasks, &imm_p, &ch); }; p = next_p; @@ -29,16 +31,16 @@ fn start(n_tasks: int, token: int) { } let imm_p = p; let imm_ch = ch1; - do task::spawn { + do spawn { roundtrip(1, n_tasks, &imm_p, &imm_ch); } } -fn roundtrip(id: int, n_tasks: int, p: &comm::Port<int>, ch: &comm::Chan<int>) { +fn roundtrip(id: int, n_tasks: int, p: &Port<int>, ch: &Chan<int>) { while (true) { match p.recv() { 1 => { - io::println(fmt!("%d\n", id)); + println(fmt!("%d\n", id)); return; } token => { @@ -60,13 +62,13 @@ fn main() { os::args() }; let token = if args.len() > 1u { - int::from_str(args[1]).get() + FromStr::from_str(args[1]).get() } else { 1000 }; let n_tasks = if args.len() > 2u { - int::from_str(args[2]).get() + FromStr::from_str(args[2]).get() } else { 503 diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index f66de385374..2396d6efc5c 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -103,7 +103,9 @@ impl Sudoku { for u8::range(0u8, 9u8) |row| { for u8::range(0u8, 9u8) |col| { let color = self.grid[row][col]; - if color == 0u8 { work += [(row, col)]; } + if color == 0u8 { + work.push((row, col)); + } } } diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs index 7a04a06d6a6..e245ab894f5 100644 --- a/src/test/bench/task-perf-alloc-unwind.rs +++ b/src/test/bench/task-perf-alloc-unwind.rs @@ -60,7 +60,7 @@ struct r { #[unsafe_destructor] impl Drop for r { - fn finalize(&self) {} + fn drop(&self) {} } fn r(l: @nillist) -> r { diff --git a/src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs index 82868647e57..b00b701191e 100644 --- a/src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: reference is not valid outside of its lifetime +// error-pattern: lifetime of return value does not outlive the function call extern mod extra; use extra::arc; fn main() { diff --git a/src/test/compile-fail/arc-rw-state-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-state-shouldnt-escape.rs index 6bd32866f89..001e6cf922f 100644 --- a/src/test/compile-fail/arc-rw-state-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-state-shouldnt-escape.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: reference is not valid outside of its lifetime extern mod extra; use extra::arc; fn main() { let x = ~arc::RWARC(1); - let mut y = None; + let mut y = None; //~ ERROR lifetime of variable does not enclose its declaration do x.write |one| { y = Some(one); } *y.unwrap() = 2; + //~^ ERROR lifetime of return value does not outlive the function call + //~^^ ERROR dereference of reference outside its lifetime } diff --git a/src/test/compile-fail/arc-rw-write-mode-cond-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-write-mode-cond-shouldnt-escape.rs index 53447531903..59e899dbbf2 100644 --- a/src/test/compile-fail/arc-rw-write-mode-cond-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-write-mode-cond-shouldnt-escape.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: reference is not valid outside of its lifetime +// error-pattern: lifetime of variable does not enclose its declaration extern mod extra; use extra::arc; fn main() { diff --git a/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs index decb7b8af9f..2599fb4dfa0 100644 --- a/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: reference is not valid outside of its lifetime +// error-pattern: lifetime of variable does not enclose its declaration extern mod extra; use extra::arc; fn main() { diff --git a/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-1.rs index e9bc4a5e195..6353d7c6581 100644 --- a/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-1.rs +++ b/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-1.rs @@ -11,7 +11,7 @@ struct X { x: () } impl Drop for X { - fn finalize(&self) { + fn drop(&self) { error!("destructor runs"); } } diff --git a/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-2.rs b/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-2.rs index 6548adddf19..6ea5f85797f 100644 --- a/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-2.rs +++ b/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-2.rs @@ -11,7 +11,7 @@ struct X { x: (), } impl Drop for X { - fn finalize(&self) { + fn drop(&self) { error!("destructor runs"); } } diff --git a/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-3.rs b/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-3.rs index aaa9d9f920a..8f0642896f1 100644 --- a/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-3.rs +++ b/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-3.rs @@ -11,7 +11,7 @@ struct X { x: (), } impl Drop for X { - fn finalize(&self) { + fn drop(&self) { error!("destructor runs"); } } diff --git a/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-4.rs b/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-4.rs index b5686b64c81..859bf7bd26d 100644 --- a/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-4.rs +++ b/src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-4.rs @@ -11,7 +11,7 @@ struct X { x: (), } impl Drop for X { - fn finalize(&self) { + fn drop(&self) { error!("destructor runs"); } } diff --git a/src/test/compile-fail/bind-by-move-no-lvalues-1.rs b/src/test/compile-fail/bind-by-move-no-lvalues-1.rs index c8537afa190..3f96d568a55 100644 --- a/src/test/compile-fail/bind-by-move-no-lvalues-1.rs +++ b/src/test/compile-fail/bind-by-move-no-lvalues-1.rs @@ -13,7 +13,7 @@ struct X { x: (), } impl Drop for X { - fn finalize(&self) { + fn drop(&self) { error!("destructor runs"); } } diff --git a/src/test/compile-fail/bind-by-move-no-lvalues-2.rs b/src/test/compile-fail/bind-by-move-no-lvalues-2.rs index 26b1084c091..c17a444ce6e 100644 --- a/src/test/compile-fail/bind-by-move-no-lvalues-2.rs +++ b/src/test/compile-fail/bind-by-move-no-lvalues-2.rs @@ -13,7 +13,7 @@ struct X { x: (), } impl Drop for X { - fn finalize(&self) { + fn drop(&self) { error!("destructor runs"); } } diff --git a/src/test/compile-fail/bind-by-move-no-sub-bindings.rs b/src/test/compile-fail/bind-by-move-no-sub-bindings.rs index c86158be5ea..a1243dd01d9 100644 --- a/src/test/compile-fail/bind-by-move-no-sub-bindings.rs +++ b/src/test/compile-fail/bind-by-move-no-sub-bindings.rs @@ -11,7 +11,7 @@ struct X { x: (), } impl Drop for X { - fn finalize(&self) { + fn drop(&self) { error!("destructor runs"); } } diff --git a/src/test/compile-fail/block-must-not-have-result-for.rs b/src/test/compile-fail/block-must-not-have-result-for.rs index 778309122cb..1aa05a9477d 100644 --- a/src/test/compile-fail/block-must-not-have-result-for.rs +++ b/src/test/compile-fail/block-must-not-have-result-for.rs @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::vec; - fn main() { - for vec::each(~[0]) |_i| { //~ ERROR A for-loop body must return (), but + for 2.times { //~ ERROR A for-loop body must return (), but true } } diff --git a/src/test/compile-fail/block-must-not-have-result-res.rs b/src/test/compile-fail/block-must-not-have-result-res.rs index 8b8bb04c08b..c9b627f55f8 100644 --- a/src/test/compile-fail/block-must-not-have-result-res.rs +++ b/src/test/compile-fail/block-must-not-have-result-res.rs @@ -13,7 +13,7 @@ struct r; impl Drop for r { - fn finalize(&self) { + fn drop(&self) { true } } diff --git a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs index 1e5c4c5cc41..98099360f3c 100644 --- a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs +++ b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs @@ -14,7 +14,7 @@ struct defer<'self> { #[unsafe_destructor] impl<'self> Drop for defer<'self> { - fn finalize(&self) { + fn drop(&self) { unsafe { error!("%?", self.x); } diff --git a/src/test/compile-fail/borrowck-insert-during-each.rs b/src/test/compile-fail/borrowck-insert-during-each.rs index 1a0bec7d723..189a0ef9d70 100644 --- a/src/test/compile-fail/borrowck-insert-during-each.rs +++ b/src/test/compile-fail/borrowck-insert-during-each.rs @@ -16,7 +16,7 @@ struct Foo { impl Foo { pub fn foo(&mut self, fun: &fn(&int)) { - for self.n.each |f| { + for self.n.iter().advance |f| { fun(f); } } diff --git a/src/test/compile-fail/borrowck-move-by-capture.rs b/src/test/compile-fail/borrowck-move-by-capture.rs index 0efde1df6c2..4ee824d1d49 100644 --- a/src/test/compile-fail/borrowck-move-by-capture.rs +++ b/src/test/compile-fail/borrowck-move-by-capture.rs @@ -1,6 +1,4 @@ -extern mod extra; - -fn main() { +pub fn main() { let foo = ~3; let _pfoo = &foo; let _f: @fn() -> int = || *foo + 5; diff --git a/src/test/compile-fail/borrowck-mut-boxed-vec.rs b/src/test/compile-fail/borrowck-mut-boxed-vec.rs index 716f70b2913..dd72a71b215 100644 --- a/src/test/compile-fail/borrowck-mut-boxed-vec.rs +++ b/src/test/compile-fail/borrowck-mut-boxed-vec.rs @@ -10,7 +10,7 @@ fn main() { let v = @mut [ 1, 2, 3 ]; - for v.each |_x| { + for v.iter().advance |_x| { v[1] = 4; //~ ERROR cannot assign } } diff --git a/src/test/compile-fail/class-cast-to-trait.rs b/src/test/compile-fail/class-cast-to-trait.rs index 7f7c58a60df..0d1582bf857 100644 --- a/src/test/compile-fail/class-cast-to-trait.rs +++ b/src/test/compile-fail/class-cast-to-trait.rs @@ -58,5 +58,5 @@ fn cat(in_x : uint, in_y : int, in_name: ~str) -> cat { fn main() { let nyan : @noisy = @cat(0, 2, ~"nyan") as @noisy; - nyan.eat(); //~ ERROR type `@noisy` does not implement any method in scope named `eat` + nyan.eat(); //~ ERROR does not implement any method in scope named `eat` } diff --git a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs new file mode 100644 index 00000000000..098a395f017 --- /dev/null +++ b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs @@ -0,0 +1,20 @@ +// 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. + +struct X { + field: @fn:Copy(), +} + +fn foo(blk: @fn:()) -> X { + return X { field: blk }; //~ ERROR expected bounds `Copy` but found no bounds +} + +fn main() { +} diff --git a/src/test/compile-fail/closure-bounds-copy-cant-capture-noncopyable.rs b/src/test/compile-fail/closure-bounds-copy-cant-capture-noncopyable.rs new file mode 100644 index 00000000000..0b11da14e71 --- /dev/null +++ b/src/test/compile-fail/closure-bounds-copy-cant-capture-noncopyable.rs @@ -0,0 +1,26 @@ +// 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. + +use std::comm; + +// If this were legal you could use it to copy captured noncopyables. +// Issue (#2828) + +fn foo(blk: ~fn:Copy()) { + blk(); +} + +fn main() { + let (p,c) = comm::stream(); + do foo { + c.send(()); //~ ERROR does not fulfill `Copy` + } + p.recv(); +} diff --git a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs new file mode 100644 index 00000000000..cac1244a560 --- /dev/null +++ b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs @@ -0,0 +1,21 @@ +// 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. + +fn bar(blk: &fn:'static()) { +} + +fn foo(x: &()) { + do bar { + let _ = x; //~ ERROR does not fulfill `'static` + } +} + +fn main() { +} diff --git a/src/test/compile-fail/closure-bounds-subtype.rs b/src/test/compile-fail/closure-bounds-subtype.rs index ebec113cedc..0c9220d18ab 100644 --- a/src/test/compile-fail/closure-bounds-subtype.rs +++ b/src/test/compile-fail/closure-bounds-subtype.rs @@ -1,34 +1,39 @@ -fn take_any(_: &fn()) { + +fn take_any(_: &fn:()) { } fn take_copyable(_: &fn:Copy()) { } -fn take_copyable_owned(_: &fn:Copy+Owned()) { +fn take_copyable_owned(_: &fn:Copy+Send()) { +} + +fn take_const_owned(_: &fn:Freeze+Send()) { } -fn give_any(f: &fn()) { +fn give_any(f: &fn:()) { take_any(f); take_copyable(f); //~ ERROR expected bounds `Copy` but found no bounds - take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found no bounds + take_copyable_owned(f); //~ ERROR expected bounds `Copy+Send` but found no bounds } fn give_copyable(f: &fn:Copy()) { take_any(f); take_copyable(f); - take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found bounds `Copy` + take_copyable_owned(f); //~ ERROR expected bounds `Copy+Send` but found bounds `Copy` } -fn give_owned(f: &fn:Owned()) { +fn give_owned(f: &fn:Send()) { take_any(f); - take_copyable(f); //~ ERROR expected bounds `Copy` but found bounds `Owned` - take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found bounds `Owned` + take_copyable(f); //~ ERROR expected bounds `Copy` but found bounds `Send` + take_copyable_owned(f); //~ ERROR expected bounds `Copy+Send` but found bounds `Send` } -fn give_copyable_owned(f: &fn:Copy+Owned()) { +fn give_copyable_owned(f: &fn:Copy+Send()) { take_any(f); take_copyable(f); take_copyable_owned(f); + take_const_owned(f); //~ ERROR expected bounds `Send+Freeze` but found bounds `Copy+Send` } -fn main() {} \ No newline at end of file +fn main() {} diff --git a/src/test/compile-fail/copy-a-resource.rs b/src/test/compile-fail/copy-a-resource.rs index 2767447d819..f709ddc0e0d 100644 --- a/src/test/compile-fail/copy-a-resource.rs +++ b/src/test/compile-fail/copy-a-resource.rs @@ -13,7 +13,7 @@ struct foo { } impl Drop for foo { - fn finalize(&self) {} + fn drop(&self) {} } fn foo(i:int) -> foo { diff --git a/src/test/compile-fail/disallowed-deconstructing-destructing-struct-let.rs b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-let.rs index c363f172d2f..e550475d64f 100644 --- a/src/test/compile-fail/disallowed-deconstructing-destructing-struct-let.rs +++ b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-let.rs @@ -14,7 +14,7 @@ struct X { } impl Drop for X { - fn finalize(&self) { + fn drop(&self) { error!("value: %s", self.x); } } diff --git a/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs index 478a56c0301..748114a4f12 100644 --- a/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs +++ b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs @@ -13,7 +13,7 @@ struct X { } impl Drop for X { - fn finalize(&self) { + fn drop(&self) { error!("value: %s", self.x); } } diff --git a/src/test/compile-fail/drop-on-non-struct.rs b/src/test/compile-fail/drop-on-non-struct.rs index 5e422d26753..2eb58d49612 100644 --- a/src/test/compile-fail/drop-on-non-struct.rs +++ b/src/test/compile-fail/drop-on-non-struct.rs @@ -12,7 +12,7 @@ type Foo = @[u8]; impl Drop for Foo { //~ ERROR the Drop trait may only be implemented //~^ ERROR cannot provide an extension implementation - fn finalize(&self) { + fn drop(&self) { println("kaboom"); } } diff --git a/src/test/run-pass/issue-4325.rs b/src/test/compile-fail/dup-struct-enum-struct-variant.rs index 8e65c15f1c4..69e6b5c6856 100644 --- a/src/test/run-pass/issue-4325.rs +++ b/src/test/compile-fail/dup-struct-enum-struct-variant.rs @@ -8,18 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Node<'self, T> { - val: T, - next: Option<&'self Node<'self, T>> -} +enum Foo { C { a: int, b: int } } +struct C { a: int, b: int } //~ ERROR error: duplicate definition of type `C` -impl<'self, T> Node<'self, T> { - fn get(&self) -> &'self T { - match self.next { - Some(ref next) => next.get(), - None => &self.val - } - } -} +struct A { x: int } +enum Bar { A { x: int } } //~ ERROR error: duplicate definition of type `A` fn main() {} diff --git a/src/test/compile-fail/explicit-call-to-dtor.rs b/src/test/compile-fail/explicit-call-to-dtor.rs index ce2942c3146..5ffc9ea08ed 100644 --- a/src/test/compile-fail/explicit-call-to-dtor.rs +++ b/src/test/compile-fail/explicit-call-to-dtor.rs @@ -13,12 +13,12 @@ struct Foo { } impl Drop for Foo { - fn finalize(&self) { + fn drop(&self) { println("kaboom"); } } fn main() { let x = Foo { x: 3 }; - x.finalize(); //~ ERROR explicit call to destructor + x.drop(); //~ ERROR explicit call to destructor } diff --git a/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs b/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs index 1a5eb696fa2..ace31183d76 100644 --- a/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs +++ b/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs @@ -17,14 +17,14 @@ trait Bar : Drop { } impl Drop for Foo { - fn finalize(&self) { + fn drop(&self) { println("kaboom"); } } impl Bar for Foo { fn blah(&self) { - self.finalize(); //~ ERROR explicit call to destructor + self.drop(); //~ ERROR explicit call to destructor } } diff --git a/src/test/compile-fail/extern-wrong-value-type.rs b/src/test/compile-fail/extern-wrong-value-type.rs index 4daa7f71adf..fbb0f6e46a1 100644 --- a/src/test/compile-fail/extern-wrong-value-type.rs +++ b/src/test/compile-fail/extern-wrong-value-type.rs @@ -13,5 +13,5 @@ extern fn f() { fn main() { // extern functions are *u8 types - let _x: &fn() = f; //~ ERROR mismatched types: expected `&fn()` but found `*u8` + let _x: &fn() = f; //~ ERROR found `*u8` } diff --git a/src/test/compile-fail/if-branch-types.rs b/src/test/compile-fail/if-branch-types.rs index 74baceb39d3..1c6dd0ef9f6 100644 --- a/src/test/compile-fail/if-branch-types.rs +++ b/src/test/compile-fail/if-branch-types.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:mismatched types - -fn main() { let x = if true { 10i } else { 10u }; } +fn main() { + let x = if true { 10i } else { 10u }; + //~^ ERROR if and else have incompatible types: expected `int` but found `uint` +} diff --git a/src/test/compile-fail/impl-bounds-checking.rs b/src/test/compile-fail/impl-bounds-checking.rs new file mode 100644 index 00000000000..00c415a860d --- /dev/null +++ b/src/test/compile-fail/impl-bounds-checking.rs @@ -0,0 +1,24 @@ +// 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. + +pub trait Clone2 { + fn clone(&self) -> Self; +} + + +trait Getter<T: Clone2> { + fn get(&self) -> T; +} + +impl Getter<int> for int { //~ ERROR failed to find an implementation of trait Clone2 for int + fn get(&self) -> int { *self } +} + +fn main() { } diff --git a/src/test/compile-fail/impl-duplicate-methods.rs b/src/test/compile-fail/impl-duplicate-methods.rs index ec766e5ce9b..c6ce4d04e10 100644 --- a/src/test/compile-fail/impl-duplicate-methods.rs +++ b/src/test/compile-fail/impl-duplicate-methods.rs @@ -11,7 +11,7 @@ struct Foo; impl Foo { fn orange(&self){} - fn orange(&self){} //~ ERROR error: duplicate definition of method `orange` + fn orange(&self){} //~ ERROR error: duplicate definition of value `orange` } fn main() {} diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index cdc8d546dd8..b5a5eed6a35 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -15,7 +15,7 @@ trait vec_monad<A> { impl<A> vec_monad<A> for ~[A] { fn bind<B>(&self, f: &fn(A) -> ~[B]) { let mut r = fail!(); - for self.each |elt| { r += f(*elt); } + for self.iter().advance |elt| { r = r + f(*elt); } //~^ WARNING unreachable expression //~^^ ERROR the type of this value must be known } diff --git a/src/test/compile-fail/issue-2150.rs b/src/test/compile-fail/issue-2150.rs index 0b35104841e..59789223bf2 100644 --- a/src/test/compile-fail/issue-2150.rs +++ b/src/test/compile-fail/issue-2150.rs @@ -14,7 +14,7 @@ fn fail_len(v: ~[int]) -> uint { let mut i = 3; fail!(); - for v.each |x| { i += 1u; } + for v.iter().advance |x| { i += 1u; } //~^ ERROR: unreachable statement return i; } diff --git a/src/test/compile-fail/issue-2151.rs b/src/test/compile-fail/issue-2151.rs index 8f4bbe4eabc..5559ba344ed 100644 --- a/src/test/compile-fail/issue-2151.rs +++ b/src/test/compile-fail/issue-2151.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::vec; - fn main() { - for vec::each(fail!()) |i| { - let _ = i * 2; //~ ERROR the type of this value must be known - }; + let x = fail!(); + x.clone(); //~ ERROR the type of this value must be known in this context } diff --git a/src/test/compile-fail/issue-2548.rs b/src/test/compile-fail/issue-2548.rs index 2f690008440..314f282355d 100644 --- a/src/test/compile-fail/issue-2548.rs +++ b/src/test/compile-fail/issue-2548.rs @@ -18,7 +18,7 @@ struct foo { #[unsafe_destructor] impl Drop for foo { - fn finalize(&self) { + fn drop(&self) { unsafe { println("Goodbye, World!"); *self.x += 1; diff --git a/src/test/compile-fail/issue-2611-4.rs b/src/test/compile-fail/issue-2611-4.rs index 2385be5723e..531d4eab535 100644 --- a/src/test/compile-fail/issue-2611-4.rs +++ b/src/test/compile-fail/issue-2611-4.rs @@ -20,7 +20,7 @@ struct E { } impl A for E { - fn b<F:Copy + Const,G>(_x: F) -> F { fail!() } //~ ERROR type parameter 0 requires `Const` + fn b<F:Copy + Freeze,G>(_x: F) -> F { fail!() } //~ ERROR type parameter 0 requires `Freeze` } fn main() {} diff --git a/src/test/compile-fail/issue-2766-a.rs b/src/test/compile-fail/issue-2766-a.rs index 91ae0e1c07a..c5d13c81b7c 100644 --- a/src/test/compile-fail/issue-2766-a.rs +++ b/src/test/compile-fail/issue-2766-a.rs @@ -9,12 +9,12 @@ // except according to those terms. pub mod stream { - pub enum Stream<T:Owned> { send(T, ::stream::server::Stream<T>), } + pub enum Stream<T:Send> { send(T, ::stream::server::Stream<T>), } pub mod server { use std::option; use std::pipes; - impl<T:Owned> Stream<T> { + impl<T:Send> Stream<T> { pub fn recv() -> extern fn(v: Stream<T>) -> ::stream::Stream<T> { // resolve really should report just one error here. // Change the test case when it changes. @@ -28,7 +28,7 @@ pub mod stream { } } - pub type Stream<T:Owned> = pipes::RecvPacket<::stream::Stream<T>>; + pub type Stream<T:Send> = pipes::RecvPacket<::stream::Stream<T>>; } } diff --git a/src/test/compile-fail/issue-2823.rs b/src/test/compile-fail/issue-2823.rs index b29b19b406f..7d1f64b9dd2 100644 --- a/src/test/compile-fail/issue-2823.rs +++ b/src/test/compile-fail/issue-2823.rs @@ -13,7 +13,7 @@ struct C { } impl Drop for C { - fn finalize(&self) { + fn drop(&self) { error!("dropping: %?", self.x); } } diff --git a/src/test/compile-fail/issue-3099-b.rs b/src/test/compile-fail/issue-3099-b.rs index 3d22a59d6bd..5502b18f094 100644 --- a/src/test/compile-fail/issue-3099-b.rs +++ b/src/test/compile-fail/issue-3099-b.rs @@ -10,6 +10,6 @@ pub mod a {} -pub mod a {} //~ ERROR duplicate definition of type `a` +pub mod a {} //~ ERROR duplicate definition of module `a` fn main() {} diff --git a/src/test/compile-fail/issue-3177-mutable-struct.rs b/src/test/compile-fail/issue-3177-mutable-struct.rs index 31c0dc7d9c4..180f13d0371 100644 --- a/src/test/compile-fail/issue-3177-mutable-struct.rs +++ b/src/test/compile-fail/issue-3177-mutable-struct.rs @@ -10,7 +10,7 @@ // xfail-test // error-pattern: instantiating a type parameter with an incompatible type -struct S<T:Const> { +struct S<T:Freeze> { s: T, cant_nest: () } diff --git a/src/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs index 2dd58906ddb..8eb110e6ce9 100644 --- a/src/test/compile-fail/issue-3214.rs +++ b/src/test/compile-fail/issue-3214.rs @@ -15,7 +15,7 @@ fn foo<T>() { } impl<T> Drop for foo<T> { - fn finalize(&self) {} + fn drop(&self) {} } } fn main() { } diff --git a/src/test/compile-fail/issue-4523.rs b/src/test/compile-fail/issue-4523.rs index 6d072ce210e..332db60c836 100644 --- a/src/test/compile-fail/issue-4523.rs +++ b/src/test/compile-fail/issue-4523.rs @@ -10,7 +10,7 @@ fn foopy() {} -static f: &'static fn() = foopy; //~ ERROR mismatched types: expected `&'static fn()` +static f: &'static fn() = foopy; //~ ERROR found extern fn fn main () { f(); diff --git a/src/test/compile-fail/issue-4972.rs b/src/test/compile-fail/issue-4972.rs index bd74199dabd..fcd15a21219 100644 --- a/src/test/compile-fail/issue-4972.rs +++ b/src/test/compile-fail/issue-4972.rs @@ -16,8 +16,8 @@ pub enum TraitWrapper { fn get_tw_map<'lt>(tw: &'lt TraitWrapper) -> &'lt MyTrait { match *tw { - A(~ref map) => map, //~ ERROR mismatched types: expected `~MyTrait` but found a ~-box pattern + A(~ref map) => map, //~ ERROR found a ~-box pattern } } -pub fn main() {} \ No newline at end of file +pub fn main() {} diff --git a/src/test/compile-fail/issue-5060-fail.rs b/src/test/compile-fail/issue-5060-fail.rs new file mode 100644 index 00000000000..c1795d31485 --- /dev/null +++ b/src/test/compile-fail/issue-5060-fail.rs @@ -0,0 +1,29 @@ +// 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. + + +use std::io; + +macro_rules! print_hd_tl ( + ($field_hd:ident, $($field_tl:ident),+) => ({ + io::print(stringify!($field)); //~ ERROR unknown macro variable + io::print("::["); + $( + io::print(stringify!($field_tl)); + io::print(", "); + )+ + io::print("]\n"); + }) +) + +fn main() { + print_hd_tl!(x, y, z, w) +} + diff --git a/src/test/compile-fail/issue-5100.rs b/src/test/compile-fail/issue-5100.rs index 8cc047230dc..7a6b8c5606b 100644 --- a/src/test/compile-fail/issue-5100.rs +++ b/src/test/compile-fail/issue-5100.rs @@ -37,7 +37,7 @@ fn main() { ('c', 'd'), ('e', 'f')]; - for v.each |&(x,y)| {} // should be OK + for v.iter().advance |&(x,y)| {} // should be OK // Make sure none of the errors above were fatal let x: char = true; //~ ERROR expected `char` but found `bool` diff --git a/src/test/compile-fail/kindck-destructor-owned.rs b/src/test/compile-fail/kindck-destructor-owned.rs index faad36a15d2..07adc3d81e5 100644 --- a/src/test/compile-fail/kindck-destructor-owned.rs +++ b/src/test/compile-fail/kindck-destructor-owned.rs @@ -2,8 +2,8 @@ struct Foo { f: @mut int, } -impl Drop for Foo { //~ ERROR cannot implement a destructor on a struct that is not Owned - fn finalize(&self) { +impl Drop for Foo { //~ ERROR cannot implement a destructor on a structure that does not satisfy Send + fn drop(&self) { *self.f = 10; } } diff --git a/src/test/compile-fail/kindck-nonsendable-1.rs b/src/test/compile-fail/kindck-nonsendable-1.rs index 928abae2423..99057ba940c 100644 --- a/src/test/compile-fail/kindck-nonsendable-1.rs +++ b/src/test/compile-fail/kindck-nonsendable-1.rs @@ -12,7 +12,7 @@ fn foo(_x: @uint) {} fn main() { let x = @3u; - let _: ~fn() = || foo(x); //~ ERROR value has non-owned type `@uint` - let _: ~fn() = || foo(x); //~ ERROR value has non-owned type `@uint` - let _: ~fn() = || foo(x); //~ ERROR value has non-owned type `@uint` + let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Send` + let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Send` + let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Send` } diff --git a/src/test/compile-fail/kindck-owned-trait-contains.rs b/src/test/compile-fail/kindck-owned-trait-contains.rs index 6bb90bff228..33e122867bb 100644 --- a/src/test/compile-fail/kindck-owned-trait-contains.rs +++ b/src/test/compile-fail/kindck-owned-trait-contains.rs @@ -23,13 +23,13 @@ fn main() { // Error results because the type of is inferred to be // @repeat<&'blk int> where blk is the lifetime of the block below. - let y = { //~ ERROR reference is not valid + let y = { //~ ERROR lifetime of variable does not enclose its declaration let x: &'blk int = &3; repeater(@x) }; - assert!(3 == *(y.get())); //~ ERROR dereference of reference outside its lifetime - //~^ ERROR reference is not valid outside of its lifetime - //~^^ ERROR reference is not valid outside of its lifetime - //~^^^ ERROR reference is not valid outside of its lifetime + assert!(3 == *(y.get())); + //~^ ERROR dereference of reference outside its lifetime + //~^^ ERROR automatically borrowed pointer is not valid at the time of borrow + //~^^^ ERROR lifetime of return value does not outlive the function call //~^^^^ ERROR cannot infer an appropriate lifetime } diff --git a/src/test/compile-fail/kindck-owned-trait.rs b/src/test/compile-fail/kindck-owned-trait.rs index 857c71db72c..c2352e35a46 100644 --- a/src/test/compile-fail/kindck-owned-trait.rs +++ b/src/test/compile-fail/kindck-owned-trait.rs @@ -11,7 +11,9 @@ trait foo { fn foo(&self); } fn to_foo<T:Copy + foo>(t: T) -> @foo { - @t as @foo //~ ERROR value may contain borrowed pointers; add `'static` bound + @t as @foo + //~^ ERROR value may contain borrowed pointers; add `'static` bound + //~^^ ERROR cannot pack type } fn to_foo2<T:Copy + foo + 'static>(t: T) -> @foo { diff --git a/src/test/compile-fail/kindck-owned.rs b/src/test/compile-fail/kindck-owned.rs index ec84551f7b0..848fd95a560 100644 --- a/src/test/compile-fail/kindck-owned.rs +++ b/src/test/compile-fail/kindck-owned.rs @@ -9,8 +9,7 @@ // except according to those terms. fn copy1<T:Copy>(t: T) -> @fn() -> T { - let result: @fn() -> T = || copy t; - //~^ ERROR value may contain borrowed pointers + let result: @fn() -> T = || copy t; //~ ERROR does not fulfill `'static` result } @@ -30,6 +29,6 @@ fn main() { copy2(boxed); let owned: ~fn() = || {}; copy2(owned); //~ ERROR does not fulfill `Copy` - let borrowed: &fn() = || {}; + let borrowed: &fn:Copy() = || {}; copy2(borrowed); //~ ERROR does not fulfill `'static` } diff --git a/src/test/compile-fail/lint-change-warnings.rs b/src/test/compile-fail/lint-change-warnings.rs new file mode 100644 index 00000000000..977abc4dc0d --- /dev/null +++ b/src/test/compile-fail/lint-change-warnings.rs @@ -0,0 +1,30 @@ +// 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. + +#[deny(warnings)]; + +fn main() { + while true {} //~ ERROR: infinite +} + +#[allow(warnings)] +fn foo() { + while true {} +} + +#[warn(warnings)] +fn bar() { + while true {} //~ WARNING: infinite +} + +#[forbid(warnings)] +fn baz() { + while true {} //~ ERROR: warnings +} diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index 4a748cc5670..e61de0ac11f 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -30,7 +30,7 @@ use std::io::WriterUtil; // Make sure this import is warned about when at least one of its imported names // is unused -use std::vec::{filter, map}; //~ ERROR unused import +use std::vec::{filter, from_elem}; //~ ERROR unused import mod foo { pub struct Point{x: int, y: int} @@ -58,7 +58,5 @@ fn main() { let a = 3; ignore(a); io::stdout().write_str("a"); - let _a = do map([2]) |&x| { - x + 2 - }; + let _a = from_elem(0, 0); } diff --git a/src/test/compile-fail/liveness-issue-2163.rs b/src/test/compile-fail/liveness-issue-2163.rs index ec4f3f9a3fd..fbb6d03b220 100644 --- a/src/test/compile-fail/liveness-issue-2163.rs +++ b/src/test/compile-fail/liveness-issue-2163.rs @@ -12,7 +12,7 @@ use std::vec; fn main() { let a: ~[int] = ~[]; - vec::each(a, |_| -> bool { + a.iter().advance(|_| -> bool { //~^ ERROR mismatched types }); } diff --git a/src/test/compile-fail/liveness-use-after-send.rs b/src/test/compile-fail/liveness-use-after-send.rs index 23d3fff01cf..72555d7e851 100644 --- a/src/test/compile-fail/liveness-use-after-send.rs +++ b/src/test/compile-fail/liveness-use-after-send.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn send<T:Owned>(ch: _chan<T>, data: T) { +fn send<T:Send>(ch: _chan<T>, data: T) { debug!(ch); debug!(data); fail!(); diff --git a/src/test/compile-fail/lub-if.rs b/src/test/compile-fail/lub-if.rs new file mode 100644 index 00000000000..358c6192147 --- /dev/null +++ b/src/test/compile-fail/lub-if.rs @@ -0,0 +1,52 @@ +// 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. + +// Test that we correctly consider the type of `match` to be the LUB +// of the various arms, particularly in the case where regions are +// involved. + +pub fn opt_str0<'a>(maybestr: &'a Option<~str>) -> &'a str { + if maybestr.is_none() { + "(none)" + } else { + let s: &'a str = *maybestr.get_ref(); + s + } +} + +pub fn opt_str1<'a>(maybestr: &'a Option<~str>) -> &'a str { + if maybestr.is_some() { + let s: &'a str = *maybestr.get_ref(); + s + } else { + "(none)" + } +} + +pub fn opt_str2<'a>(maybestr: &'a Option<~str>) -> &'static str { + if maybestr.is_none() { //~ ERROR mismatched types + "(none)" + } else { + let s: &'a str = *maybestr.get_ref(); + s + } +} + +pub fn opt_str3<'a>(maybestr: &'a Option<~str>) -> &'static str { + if maybestr.is_some() { //~ ERROR mismatched types + let s: &'a str = *maybestr.get_ref(); + s + } else { + "(none)" + } +} + + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/lub-match.rs b/src/test/compile-fail/lub-match.rs new file mode 100644 index 00000000000..2a61b72997d --- /dev/null +++ b/src/test/compile-fail/lub-match.rs @@ -0,0 +1,55 @@ +// 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. + +// Test that we correctly consider the type of `match` to be the LUB +// of the various arms, particularly in the case where regions are +// involved. + +pub fn opt_str0<'a>(maybestr: &'a Option<~str>) -> &'a str { + match *maybestr { + Some(ref s) => { + let s: &'a str = *s; + s + } + None => "(none)", + } +} + +pub fn opt_str1<'a>(maybestr: &'a Option<~str>) -> &'a str { + match *maybestr { + None => "(none)", + Some(ref s) => { + let s: &'a str = *s; + s + } + } +} + +pub fn opt_str2<'a>(maybestr: &'a Option<~str>) -> &'static str { + match *maybestr { //~ ERROR mismatched types + None => "(none)", + Some(ref s) => { + let s: &'a str = *s; + s + } + } +} + +pub fn opt_str3<'a>(maybestr: &'a Option<~str>) -> &'static str { + match *maybestr { //~ ERROR mismatched types + Some(ref s) => { + let s: &'a str = *s; + s + } + None => "(none)", + } +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs index f5d6e95fe2f..f6fd8e29a4f 100644 --- a/src/test/compile-fail/map-types.rs +++ b/src/test/compile-fail/map-types.rs @@ -17,5 +17,5 @@ fn main() { let x: @Map<~str, ~str> = @HashMap::new::<~str, ~str>() as @Map<~str, ~str>; let y: @Map<uint, ~str> = @x; - //~^ ERROR mismatched types: expected `@std::container::Map<uint,~str>` + //~^ ERROR expected trait std::container::Map but found @-ptr } diff --git a/src/test/compile-fail/missing-do.rs b/src/test/compile-fail/missing-do.rs index b5789d73771..e6a7698d0f0 100644 --- a/src/test/compile-fail/missing-do.rs +++ b/src/test/compile-fail/missing-do.rs @@ -13,7 +13,7 @@ fn foo(f: &fn()) { f() } fn main() { - ~"" || 42; //~ ERROR binary operation || cannot be applied to type `~str` - foo || {}; //~ ERROR binary operation || cannot be applied to type `extern "Rust" fn(&fn())` + ~"" || 42; //~ ERROR binary operation || cannot be applied to type + foo || {}; //~ ERROR binary operation || cannot be applied to type //~^ NOTE did you forget the `do` keyword for the call? } diff --git a/src/test/compile-fail/moves-based-on-type-exprs.rs b/src/test/compile-fail/moves-based-on-type-exprs.rs index 38718006d8b..fec0f89adba 100644 --- a/src/test/compile-fail/moves-based-on-type-exprs.rs +++ b/src/test/compile-fail/moves-based-on-type-exprs.rs @@ -1,8 +1,6 @@ // Tests that references to move-by-default values trigger moves when // they occur as part of various kinds of expressions. -use std::vec; - struct Foo<A> { f: A } fn guard(_s: ~str) -> bool {fail!()} fn touch<A>(_a: &A) {} @@ -92,7 +90,7 @@ fn f110() { fn f120() { let mut x = ~[~"hi", ~"ho"]; - vec::swap(x, 0, 1); + x.swap(0, 1); touch(&x[0]); touch(&x[1]); } diff --git a/src/test/compile-fail/mutable-enum.rs b/src/test/compile-fail/mutable-enum.rs index 2368e5eb5c5..35842a53a31 100644 --- a/src/test/compile-fail/mutable-enum.rs +++ b/src/test/compile-fail/mutable-enum.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[mutable] +#[no_freeze] enum Foo { A } -fn bar<T: Const>(_: T) {} +fn bar<T: Freeze>(_: T) {} fn main() { let x = A; - bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Const` + bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Freeze` } diff --git a/src/test/compile-fail/mutable-struct.rs b/src/test/compile-fail/mutable-struct.rs index ee040506c40..6f29fcfd96d 100644 --- a/src/test/compile-fail/mutable-struct.rs +++ b/src/test/compile-fail/mutable-struct.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[mutable] +#[no_freeze] struct Foo { a: int } -fn bar<T: Const>(_: T) {} +fn bar<T: Freeze>(_: T) {} fn main() { let x = Foo { a: 5 }; - bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Const` + bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Freeze` } diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs index 5e18a40a99c..5f0d4bc60ac 100644 --- a/src/test/compile-fail/no-send-res-ports.rs +++ b/src/test/compile-fail/no-send-res-ports.rs @@ -20,7 +20,7 @@ fn main() { #[unsafe_destructor] impl Drop for foo { - fn finalize(&self) {} + fn drop(&self) {} } fn foo(x: Port<()>) -> foo { @@ -32,7 +32,7 @@ fn main() { let x = Cell::new(foo(Port(@()))); do task::spawn { - let y = x.take(); //~ ERROR value has non-owned type + let y = x.take(); //~ ERROR does not fulfill `Send` error!(y); } } diff --git a/src/test/compile-fail/non_owned-enum.rs b/src/test/compile-fail/non_owned-enum.rs index 79c2be8183a..b436bfb8b0f 100644 --- a/src/test/compile-fail/non_owned-enum.rs +++ b/src/test/compile-fail/non_owned-enum.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[non_owned] +#[no_send] enum Foo { A } -fn bar<T: Owned>(_: T) {} +fn bar<T: Send>(_: T) {} fn main() { let x = A; - bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Owned` + bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Send` } diff --git a/src/test/compile-fail/non_owned-struct.rs b/src/test/compile-fail/non_owned-struct.rs index 2d0bc9a7e8e..542c3aa212b 100644 --- a/src/test/compile-fail/non_owned-struct.rs +++ b/src/test/compile-fail/non_owned-struct.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[non_owned] +#[no_send] struct Foo { a: int } -fn bar<T: Owned>(_: T) {} +fn bar<T: Send>(_: T) {} fn main() { let x = Foo { a: 5 }; - bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Owned` + bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Send` } diff --git a/src/test/compile-fail/noncopyable-class.rs b/src/test/compile-fail/noncopyable-class.rs index 77e62497d07..aa7100f0aad 100644 --- a/src/test/compile-fail/noncopyable-class.rs +++ b/src/test/compile-fail/noncopyable-class.rs @@ -15,7 +15,7 @@ struct bar { } impl Drop for bar { - fn finalize(&self) {} + fn drop(&self) {} } fn bar(x:int) -> bar { diff --git a/src/test/compile-fail/once-cant-call-twice-on-heap.rs b/src/test/compile-fail/once-cant-call-twice-on-heap.rs new file mode 100644 index 00000000000..4436675d69a --- /dev/null +++ b/src/test/compile-fail/once-cant-call-twice-on-heap.rs @@ -0,0 +1,29 @@ +// 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. + +// Testing guarantees provided by once functions. +// This program would segfault if it were legal. + +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: ~once fn()) { + blk(); + blk(); //~ ERROR use of moved value +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); + } +} diff --git a/src/test/compile-fail/once-cant-call-twice-on-stack.rs b/src/test/compile-fail/once-cant-call-twice-on-stack.rs new file mode 100644 index 00000000000..10877be549e --- /dev/null +++ b/src/test/compile-fail/once-cant-call-twice-on-stack.rs @@ -0,0 +1,30 @@ +// 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. + +// Testing guarantees provided by once functions. +// This program would segfault if it were legal. + +// compile-flags:-Z once-fns +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: &once fn()) { + blk(); + blk(); //~ ERROR use of moved value +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); + } +} diff --git a/src/test/compile-fail/once-cant-copy-stack-once-fn-copy.rs b/src/test/compile-fail/once-cant-copy-stack-once-fn-copy.rs new file mode 100644 index 00000000000..6f524c0068b --- /dev/null +++ b/src/test/compile-fail/once-cant-copy-stack-once-fn-copy.rs @@ -0,0 +1,20 @@ +// 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. + +// Though it should be legal to copy a heap-allocated "once fn:Copy", +// stack closures are not deep-copied, so (counterintuitively) it should be +// illegal to copy them. + +fn foo<'r>(blk: &'r once fn:Copy()) -> (&'r once fn:Copy(), &'r once fn:Copy()) { + (copy blk, blk) //~ ERROR copying a value of non-copyable type +} + +fn main() { +} diff --git a/src/test/compile-fail/once-cant-move-out-of-non-once-on-heap.rs b/src/test/compile-fail/once-cant-move-out-of-non-once-on-heap.rs new file mode 100644 index 00000000000..61f158cec27 --- /dev/null +++ b/src/test/compile-fail/once-cant-move-out-of-non-once-on-heap.rs @@ -0,0 +1,29 @@ +// 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. + +// Testing guarantees provided by once functions. +// This program would segfault if it were legal. + +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: ~fn()) { + blk(); + blk(); +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); //~ ERROR cannot move out of captured outer variable + } +} diff --git a/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs b/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs new file mode 100644 index 00000000000..42c8b9a9998 --- /dev/null +++ b/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs @@ -0,0 +1,29 @@ +// 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. + +// Testing guarantees provided by once functions. +// This program would segfault if it were legal. + +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: &fn()) { + blk(); + blk(); +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); //~ ERROR cannot move out of captured outer variable + } +} diff --git a/src/test/compile-fail/pinned-deep-copy.rs b/src/test/compile-fail/pinned-deep-copy.rs index 17e23360a5b..2e48992e81e 100644 --- a/src/test/compile-fail/pinned-deep-copy.rs +++ b/src/test/compile-fail/pinned-deep-copy.rs @@ -14,7 +14,7 @@ struct r { #[unsafe_destructor] impl Drop for r { - fn finalize(&self) { + fn drop(&self) { unsafe { *(self.i) = *(self.i) + 1; } diff --git a/src/test/compile-fail/rcmut-not-const-and-not-owned.rs b/src/test/compile-fail/rcmut-not-const-and-not-owned.rs index 9e7236a67d9..45cb137b084 100644 --- a/src/test/compile-fail/rcmut-not-const-and-not-owned.rs +++ b/src/test/compile-fail/rcmut-not-const-and-not-owned.rs @@ -10,11 +10,11 @@ extern mod extra; -fn o<T: Owned>(_: &T) {} -fn c<T: Const>(_: &T) {} +fn o<T: Send>(_: &T) {} +fn c<T: Freeze>(_: &T) {} fn main() { let x = extra::rc::rc_mut_from_owned(0); - o(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Owned` - c(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Const` + o(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Send` + c(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Freeze` } diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index ab2620d46fd..ab2ac6cc0e5 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -16,11 +16,13 @@ struct an_enum<'self>(&'self int); struct a_class<'self> { x:&'self int } fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> { - return e; //~ ERROR mismatched types: expected `an_enum/&'b ` but found `an_enum/&'a ` + return e; //~ ERROR mismatched types: expected `an_enum<'b>` but found `an_enum<'a>` + //~^ ERROR cannot infer an appropriate lifetime } fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { - return e; //~ ERROR mismatched types: expected `a_class/&'b ` but found `a_class/&'a ` + return e; //~ ERROR mismatched types: expected `a_class<'b>` but found `a_class<'a>` + //~^ ERROR cannot infer an appropriate lifetime } fn a_fn4<'a,'b>() { diff --git a/src/test/compile-fail/regions-creating-enums.rs b/src/test/compile-fail/regions-creating-enums.rs index 2ab0c14b49b..c2d8427d5eb 100644 --- a/src/test/compile-fail/regions-creating-enums.rs +++ b/src/test/compile-fail/regions-creating-enums.rs @@ -33,8 +33,8 @@ fn map_nums(x: &ast, f: &fn(uint) -> uint) -> &ast { return &num(f(x)); //~ ERROR borrowed value does not live long enough } add(x, y) => { - let m_x = map_nums(x, f); - let m_y = map_nums(y, f); + let m_x = map_nums(x, |z| f(z)); + let m_y = map_nums(y, |z| f(z)); return &add(m_x, m_y); //~ ERROR borrowed value does not live long enough } } diff --git a/src/test/compile-fail/regions-escape-bound-fn-2.rs b/src/test/compile-fail/regions-escape-bound-fn-2.rs index 9cee55643f8..305aa685284 100644 --- a/src/test/compile-fail/regions-escape-bound-fn-2.rs +++ b/src/test/compile-fail/regions-escape-bound-fn-2.rs @@ -15,6 +15,6 @@ fn with_int(f: &fn(x: &int)) { fn main() { let mut x = None; - //~^ ERROR reference is not valid outside of its lifetime + //~^ ERROR lifetime of variable does not enclose its declaration with_int(|y| x = Some(y)); } diff --git a/src/test/compile-fail/regions-escape-via-trait-or-not.rs b/src/test/compile-fail/regions-escape-via-trait-or-not.rs index aa431d6b81c..5b6dc1b2f4f 100644 --- a/src/test/compile-fail/regions-escape-via-trait-or-not.rs +++ b/src/test/compile-fail/regions-escape-via-trait-or-not.rs @@ -23,7 +23,7 @@ fn with<R:deref>(f: &fn(x: &int) -> R) -> int { } fn return_it() -> int { - with(|o| o) //~ ERROR reference is not valid outside of its lifetime + with(|o| o) //~ ERROR lifetime of function argument does not outlive the function call } fn main() { diff --git a/src/test/compile-fail/regions-free-region-ordering-incorrect.rs b/src/test/compile-fail/regions-free-region-ordering-incorrect.rs new file mode 100644 index 00000000000..c2bd64fddaf --- /dev/null +++ b/src/test/compile-fail/regions-free-region-ordering-incorrect.rs @@ -0,0 +1,32 @@ +// 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. + +// Test that free regions ordering only goes one way. That is, +// we have `&'a Node<'self, T>`, which implies that `'a <= 'self`, +// but not `'self <= 'a`. Hence returning `&self.val` (which has lifetime +// `'a`) where `'self` is expected yields an error. +// +// This test began its life as a test for issue #4325. + +struct Node<'self, T> { + val: T, + next: Option<&'self Node<'self, T>> +} + +impl<'self, T> Node<'self, T> { + fn get<'a>(&'a self) -> &'self T { + match self.next { + Some(ref next) => next.get(), + None => &self.val //~ ERROR cannot infer an appropriate lifetime + } + } +} + +fn main() {} diff --git a/src/test/compile-fail/regions-infer-at-fn-not-param.rs b/src/test/compile-fail/regions-infer-at-fn-not-param.rs index c8813b73e6b..488d1f3940d 100644 --- a/src/test/compile-fail/regions-infer-at-fn-not-param.rs +++ b/src/test/compile-fail/regions-infer-at-fn-not-param.rs @@ -20,7 +20,10 @@ struct not_parameterized2 { g: @fn() } -fn take1(p: parameterized1) -> parameterized1 { p } //~ ERROR mismatched types +fn take1(p: parameterized1) -> parameterized1 { p } +//~^ ERROR mismatched types +//~^^ ERROR cannot infer an appropriate lifetime + fn take3(p: not_parameterized1) -> not_parameterized1 { p } fn take4(p: not_parameterized2) -> not_parameterized2 { p } diff --git a/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs b/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs index 85cc6e6ce24..c33ca2dab2e 100644 --- a/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs +++ b/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs @@ -22,6 +22,7 @@ fn to_same_lifetime<'r>(bi: covariant<'r>) { fn to_shorter_lifetime<'r>(bi: covariant<'r>) { let bj: covariant<'blk> = bi; //~ ERROR mismatched types + //~^ ERROR cannot infer an appropriate lifetime } fn to_longer_lifetime<'r>(bi: covariant<'r>) -> covariant<'static> { diff --git a/src/test/compile-fail/regions-infer-not-param.rs b/src/test/compile-fail/regions-infer-not-param.rs index a0ecb08a089..fa853b82d9e 100644 --- a/src/test/compile-fail/regions-infer-not-param.rs +++ b/src/test/compile-fail/regions-infer-not-param.rs @@ -23,6 +23,11 @@ struct indirect2<'self> { } fn take_direct(p: direct) -> direct { p } //~ ERROR mismatched types +//~^ ERROR cannot infer an appropriate lifetime + fn take_indirect1(p: indirect1) -> indirect1 { p } + fn take_indirect2(p: indirect2) -> indirect2 { p } //~ ERROR mismatched types +//~^ ERROR cannot infer an appropriate lifetime + fn main() {} diff --git a/src/test/compile-fail/regions-infer-paramd-indirect.rs b/src/test/compile-fail/regions-infer-paramd-indirect.rs index e8d66ab297b..0b4aa44010b 100644 --- a/src/test/compile-fail/regions-infer-paramd-indirect.rs +++ b/src/test/compile-fail/regions-infer-paramd-indirect.rs @@ -30,6 +30,7 @@ impl<'self> set_f<'self> for c<'self> { fn set_f_bad(&self, b: @b) { self.f = b; //~ ERROR mismatched types: expected `@@&'self int` but found `@@&int` + //~^ ERROR cannot infer an appropriate lifetime } } diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index 74399967446..244e9cc06a1 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -22,6 +22,7 @@ fn nested<'x>(x: &'x int) { ignore::<&fn<'z>(&'z int) -> &'z int>(|z| { if false { return x; } //~ ERROR mismatched types + //~^ ERROR cannot infer an appropriate lifetime if false { return ay; } return z; }); diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index a572d90313b..54271168719 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -18,6 +18,8 @@ fn with<'a, R>(f: &fn(x: &'a int) -> R) -> R { fn return_it<'a>() -> &'a int { with(|o| o) //~ ERROR mismatched types + //~^ ERROR lifetime of return value does not outlive the function call + //~^^ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs index ec9a908ba98..4d646aa364a 100644 --- a/src/test/compile-fail/regions-ret-borrowed.rs +++ b/src/test/compile-fail/regions-ret-borrowed.rs @@ -21,6 +21,8 @@ fn with<R>(f: &fn(x: &int) -> R) -> R { fn return_it() -> &int { with(|o| o) //~ ERROR mismatched types + //~^ ERROR lifetime of return value does not outlive the function call + //~^^ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/repeat-to-run-dtor-twice.rs b/src/test/compile-fail/repeat-to-run-dtor-twice.rs index 0dd12822dfa..c997ce2a281 100644 --- a/src/test/compile-fail/repeat-to-run-dtor-twice.rs +++ b/src/test/compile-fail/repeat-to-run-dtor-twice.rs @@ -17,7 +17,7 @@ struct Foo { } impl Drop for Foo { - fn finalize(&self) { + fn drop(&self) { println("Goodbye!"); } } diff --git a/src/test/compile-fail/static-mut-bad-types.rs b/src/test/compile-fail/static-mut-bad-types.rs new file mode 100644 index 00000000000..7aed3ce30bc --- /dev/null +++ b/src/test/compile-fail/static-mut-bad-types.rs @@ -0,0 +1,17 @@ +// 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. + +static mut a: int = 3; + +fn main() { + unsafe { + a = true; //~ ERROR: mismatched types + } +} diff --git a/src/test/compile-fail/static-mut-foreign-requires-unsafe.rs b/src/test/compile-fail/static-mut-foreign-requires-unsafe.rs new file mode 100644 index 00000000000..7b371cf708d --- /dev/null +++ b/src/test/compile-fail/static-mut-foreign-requires-unsafe.rs @@ -0,0 +1,21 @@ +// 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. + +use std::libc; + +extern { + static mut a: libc::c_int; +} + +fn main() { + a += 3; //~ ERROR: requires unsafe + a = 4; //~ ERROR: requires unsafe + let _b = a; //~ ERROR: requires unsafe +} diff --git a/src/test/compile-fail/static-mut-not-constant.rs b/src/test/compile-fail/static-mut-not-constant.rs new file mode 100644 index 00000000000..61d3ed7fd18 --- /dev/null +++ b/src/test/compile-fail/static-mut-not-constant.rs @@ -0,0 +1,13 @@ +// 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. + +static mut a: ~int = ~3; //~ ERROR: disallowed operator in constant + +fn main() {} diff --git a/src/test/compile-fail/static-mut-not-pat.rs b/src/test/compile-fail/static-mut-not-pat.rs new file mode 100644 index 00000000000..997003a28d4 --- /dev/null +++ b/src/test/compile-fail/static-mut-not-pat.rs @@ -0,0 +1,26 @@ +// 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. + +// Constants (static variables) can be used to match in patterns, but mutable +// statics cannot. This ensures that there's some form of error if this is +// attempted. + +static mut a: int = 3; + +fn main() { + // If they can't be matched against, then it's possible to capture the same + // name as a variable, hence this should be an unreachable pattern situation + // instead of spitting out a custom error about some identifier collisions + // (we should allow shadowing) + match 4 { + a => {} + _ => {} //~ ERROR: unreachable pattern + } +} diff --git a/src/test/compile-fail/static-mut-requires-unsafe.rs b/src/test/compile-fail/static-mut-requires-unsafe.rs new file mode 100644 index 00000000000..7337920cce6 --- /dev/null +++ b/src/test/compile-fail/static-mut-requires-unsafe.rs @@ -0,0 +1,17 @@ +// 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. + +static mut a: int = 3; + +fn main() { + a += 3; //~ ERROR: requires unsafe + a = 4; //~ ERROR: requires unsafe + let _b = a; //~ ERROR: requires unsafe +} diff --git a/src/test/compile-fail/struct-fields-decl-dupe.rs b/src/test/compile-fail/struct-fields-decl-dupe.rs new file mode 100644 index 00000000000..78216d5f4af --- /dev/null +++ b/src/test/compile-fail/struct-fields-decl-dupe.rs @@ -0,0 +1,17 @@ +// 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. + +struct BuildData { + foo: int, + foo: int, //~ ERROR field `foo` is already declared +} + +fn main() { +} diff --git a/src/test/compile-fail/sync-cond-shouldnt-escape.rs b/src/test/compile-fail/sync-cond-shouldnt-escape.rs index b22d4d3b2e2..2006027e797 100644 --- a/src/test/compile-fail/sync-cond-shouldnt-escape.rs +++ b/src/test/compile-fail/sync-cond-shouldnt-escape.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: reference is not valid outside of its lifetime +// error-pattern: lifetime of variable does not enclose its declaration extern mod extra; use extra::sync; diff --git a/src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs b/src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs index 518e67800d7..4108201f911 100644 --- a/src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs +++ b/src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: reference is not valid outside of its lifetime +// error-pattern: lifetime of method receiver does not outlive the method call extern mod extra; use extra::sync; fn main() { diff --git a/src/test/compile-fail/sync-rwlock-write-mode-cond-shouldnt-escape.rs b/src/test/compile-fail/sync-rwlock-write-mode-cond-shouldnt-escape.rs index 09b83887bcf..43b4d9aabb8 100644 --- a/src/test/compile-fail/sync-rwlock-write-mode-cond-shouldnt-escape.rs +++ b/src/test/compile-fail/sync-rwlock-write-mode-cond-shouldnt-escape.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: reference is not valid outside of its lifetime +// error-pattern: lifetime of variable does not enclose its declaration extern mod extra; use extra::sync; fn main() { diff --git a/src/test/compile-fail/sync-rwlock-write-mode-shouldnt-escape.rs b/src/test/compile-fail/sync-rwlock-write-mode-shouldnt-escape.rs index 679c4a72598..15af7be5246 100644 --- a/src/test/compile-fail/sync-rwlock-write-mode-shouldnt-escape.rs +++ b/src/test/compile-fail/sync-rwlock-write-mode-shouldnt-escape.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: reference is not valid outside of its lifetime +// error-pattern: lifetime of variable does not enclose its declaration extern mod extra; use extra::sync; fn main() { diff --git a/src/test/compile-fail/the-case-of-the-recurring-closure-2.rs b/src/test/compile-fail/the-case-of-the-recurring-closure-2.rs new file mode 100644 index 00000000000..bfb1e910495 --- /dev/null +++ b/src/test/compile-fail/the-case-of-the-recurring-closure-2.rs @@ -0,0 +1,44 @@ +// 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. + +// Tests correct kind-checking of the reason stack closures without the :Copy +// bound must be noncopyable. For details see +// http://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closure/ + +struct R<'self> { + // This struct is needed to create the + // otherwise infinite type of a fn that + // accepts itself as argument: + c: &'self fn:Copy(&R, bool) +} + +fn innocent_looking_victim() { + let mut x = Some(~"hello"); + do conspirator |f, writer| { + if writer { + x = None; //~ ERROR cannot implicitly borrow + } else { + match x { + Some(ref msg) => { + (f.c)(f, true); + println(fmt!("%?", msg)); + }, + None => fail!("oops"), + } + } + } +} + +fn conspirator(f: &fn:Copy(&R, bool)) { + let r = R {c: f}; + f(&r, false) +} + +fn main() { innocent_looking_victim() } diff --git a/src/test/compile-fail/the-case-of-the-recurring-closure.rs b/src/test/compile-fail/the-case-of-the-recurring-closure.rs new file mode 100644 index 00000000000..f05c30c3355 --- /dev/null +++ b/src/test/compile-fail/the-case-of-the-recurring-closure.rs @@ -0,0 +1,44 @@ +// 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. + +// Tests correct kind-checking of the reason stack closures without the :Copy +// bound must be noncopyable. For details see +// http://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closure/ + +struct R<'self> { + // This struct is needed to create the + // otherwise infinite type of a fn that + // accepts itself as argument: + c: &'self fn(&R, bool) +} + +fn innocent_looking_victim() { + let mut x = Some(~"hello"); + do conspirator |f, writer| { + if writer { + x = None; + } else { + match x { + Some(ref msg) => { + (f.c)(f, true); + println(fmt!("%?", msg)); + }, + None => fail!("oops"), + } + } + } +} + +fn conspirator(f: &fn(&R, bool)) { + let r = R {c: f}; + f(&r, false) //~ ERROR use of moved value +} + +fn main() { innocent_looking_victim() } diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs new file mode 100644 index 00000000000..a96da398f5a --- /dev/null +++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs @@ -0,0 +1,28 @@ +// 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. + +trait Foo { +} + +fn a(_x: ~Foo:Send) { +} + +fn b(_x: ~Foo:Send+Copy) { +} + +fn c(x: ~Foo:Freeze+Send) { + b(x); //~ ERROR expected bounds `Copy+Send` +} + +fn d(x: ~Foo:) { + a(x); //~ ERROR found no bounds +} + +fn main() { } diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs new file mode 100644 index 00000000000..d7c98ec4e9d --- /dev/null +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -0,0 +1,19 @@ +// 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. + +trait Foo { +} + +// This should emit the less confusing error, not the more confusing one. + +fn foo(_x: Foo:Send) { //~ERROR reference to trait `Foo` where a type is expected +} + +fn main() { } diff --git a/src/test/compile-fail/trait-bounds-not-on-impl.rs b/src/test/compile-fail/trait-bounds-not-on-impl.rs new file mode 100644 index 00000000000..ac88b21b456 --- /dev/null +++ b/src/test/compile-fail/trait-bounds-not-on-impl.rs @@ -0,0 +1,19 @@ +// 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. + +trait Foo { +} + +struct Bar; + +impl Foo:Owned for Bar { //~ ERROR bounded traits are only valid in type position +} + +fn main() { } diff --git a/src/test/compile-fail/trait-bounds-not-on-struct.rs b/src/test/compile-fail/trait-bounds-not-on-struct.rs new file mode 100644 index 00000000000..ebffd0303e0 --- /dev/null +++ b/src/test/compile-fail/trait-bounds-not-on-struct.rs @@ -0,0 +1,15 @@ +// 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. + +struct Foo; + +fn foo(_x: ~Foo:Send) { } //~ ERROR kind bounds can only be used on trait types + +fn main() { } diff --git a/src/test/compile-fail/trait-bounds-sugar.rs b/src/test/compile-fail/trait-bounds-sugar.rs new file mode 100644 index 00000000000..68a0ae90014 --- /dev/null +++ b/src/test/compile-fail/trait-bounds-sugar.rs @@ -0,0 +1,37 @@ +// 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. + +// Tests for "default" bounds inferred for traits with no bounds list. + +trait Foo { +} + +fn a(_x: ~Foo) { // should be same as ~Foo:Send +} + +fn b(_x: @Foo) { // should be same as ~Foo:'static +} + +fn c(_x: &'static Foo) { // should be same as &'static Foo:'static +} + +fn d(x: ~Foo:Freeze) { + a(x); //~ ERROR expected bounds `Send` +} + +fn e(x: @Foo:Freeze) { + b(x); //~ ERROR expected bounds `'static` +} + +fn f(x: &'static Foo:Freeze) { + c(x); //~ ERROR expected bounds `'static` +} + +fn main() { } diff --git a/src/test/compile-fail/trait-duplicate-methods.rs b/src/test/compile-fail/trait-duplicate-methods.rs index e2ba5267eba..ba8101d16ab 100644 --- a/src/test/compile-fail/trait-duplicate-methods.rs +++ b/src/test/compile-fail/trait-duplicate-methods.rs @@ -10,7 +10,7 @@ trait Foo { fn orange(&self); - fn orange(&self); //~ ERROR error: duplicate definition of method `orange` + fn orange(&self); //~ ERROR error: duplicate definition of value `orange` } fn main() {} diff --git a/src/test/compile-fail/trait-or-new-type-instead.rs b/src/test/compile-fail/trait-or-new-type-instead.rs index f687a6f9702..c44887593ab 100644 --- a/src/test/compile-fail/trait-or-new-type-instead.rs +++ b/src/test/compile-fail/trait-or-new-type-instead.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: implement a trait or new type instead +// error-pattern: found value name used as a type impl<T> Option<T> { pub fn foo(&self) { } } diff --git a/src/test/compile-fail/unique-object-noncopyable.rs b/src/test/compile-fail/unique-object-noncopyable.rs index 3844dab726e..dacfd466040 100644 --- a/src/test/compile-fail/unique-object-noncopyable.rs +++ b/src/test/compile-fail/unique-object-noncopyable.rs @@ -17,7 +17,7 @@ struct Bar { } impl Drop for Bar { - fn finalize(&self) {} + fn drop(&self) {} } impl Foo for Bar { diff --git a/src/test/compile-fail/unique-pinned-nocopy.rs b/src/test/compile-fail/unique-pinned-nocopy.rs index a08f03d5628..1deb850741e 100644 --- a/src/test/compile-fail/unique-pinned-nocopy.rs +++ b/src/test/compile-fail/unique-pinned-nocopy.rs @@ -13,7 +13,7 @@ struct r { } impl Drop for r { - fn finalize(&self) {} + fn drop(&self) {} } fn main() { diff --git a/src/test/compile-fail/unique-unique-kind.rs b/src/test/compile-fail/unique-unique-kind.rs index 26058bf89ca..d51df4979e3 100644 --- a/src/test/compile-fail/unique-unique-kind.rs +++ b/src/test/compile-fail/unique-unique-kind.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f<T:Owned>(_i: T) { +fn f<T:Send>(_i: T) { } fn main() { let i = ~@100; - f(i); //~ ERROR does not fulfill `Owned` + f(i); //~ ERROR does not fulfill `Send` } diff --git a/src/test/compile-fail/unique-vec-res.rs b/src/test/compile-fail/unique-vec-res.rs index 003e8ccf309..e231e5e5037 100644 --- a/src/test/compile-fail/unique-vec-res.rs +++ b/src/test/compile-fail/unique-vec-res.rs @@ -14,7 +14,7 @@ struct r { #[unsafe_destructor] impl Drop for r { - fn finalize(&self) { + fn drop(&self) { unsafe { *(self.i) = *(self.i) + 1; } diff --git a/src/test/compile-fail/unsendable-class.rs b/src/test/compile-fail/unsendable-class.rs index 58de0926f7c..de089dcf914 100644 --- a/src/test/compile-fail/unsendable-class.rs +++ b/src/test/compile-fail/unsendable-class.rs @@ -27,6 +27,6 @@ fn foo(i:int, j: @~str) -> foo { fn main() { let cat = ~"kitty"; - let (_, ch) = comm::stream(); //~ ERROR does not fulfill `Owned` - ch.send(foo(42, @(cat))); //~ ERROR does not fulfill `Owned` + let (_, ch) = comm::stream(); //~ ERROR does not fulfill `Send` + ch.send(foo(42, @(cat))); //~ ERROR does not fulfill `Send` } diff --git a/src/test/compile-fail/use-after-move-self-based-on-type.rs b/src/test/compile-fail/use-after-move-self-based-on-type.rs index 5b4d67fb0ce..0622c028c63 100644 --- a/src/test/compile-fail/use-after-move-self-based-on-type.rs +++ b/src/test/compile-fail/use-after-move-self-based-on-type.rs @@ -3,7 +3,7 @@ struct S { } impl Drop for S { - fn finalize(&self) {} + fn drop(&self) {} } impl S { diff --git a/src/test/compile-fail/vec-res-add.rs b/src/test/compile-fail/vec-res-add.rs index 938e8c41e79..d881750bd3c 100644 --- a/src/test/compile-fail/vec-res-add.rs +++ b/src/test/compile-fail/vec-res-add.rs @@ -17,7 +17,7 @@ struct r { fn r(i:int) -> r { r { i: i } } impl Drop for r { - fn finalize(&self) {} + fn drop(&self) {} } fn main() { diff --git a/src/test/debug-info/basic-types.rs b/src/test/debug-info/basic-types.rs index 616740c850c..7125ebe8d56 100644 --- a/src/test/debug-info/basic-types.rs +++ b/src/test/debug-info/basic-types.rs @@ -26,8 +26,8 @@ // check:$2 = -1 // debugger:print c // check:$3 = 97 -// debugger:print i8 -// check:$4 = 68 'D' +// debugger:print/d i8 +// check:$4 = 68 // debugger:print i16 // check:$5 = -16 // debugger:print i32 @@ -36,8 +36,8 @@ // check:$7 = -64 // debugger:print u // check:$8 = 1 -// debugger:print u8 -// check:$9 = 100 'd' +// debugger:print/d u8 +// check:$9 = 100 // debugger:print u16 // check:$10 = 16 // debugger:print u32 diff --git a/src/test/debug-info/tuple.rs b/src/test/debug-info/destructured-local.rs index a50996871ce..bf53d95b588 100644 --- a/src/test/debug-info/tuple.rs +++ b/src/test/debug-info/destructured-local.rs @@ -8,19 +8,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 +// xfail-test + +// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical +// value. // compile-flags:-Z extra-debug-info -// debugger:set print pretty off -// debugger:break _zzz +// debugger:break zzz // debugger:run // debugger:finish -// debugger:print t -// check:$1 = {4, 5.5, true} + +// debugger:print a +// check:$1 = 9898 + +// debugger:print b +// check:$2 = false fn main() { - let t = (4, 5.5, true); - _zzz(); + let (a, b) : (int, bool) = (9898, false); + + zzz(); } -fn _zzz() {()} \ No newline at end of file +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/function-arguments.rs b/src/test/debug-info/function-arguments.rs new file mode 100644 index 00000000000..f5563cda259 --- /dev/null +++ b/src/test/debug-info/function-arguments.rs @@ -0,0 +1,51 @@ +// 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. + +// xfail-test + +// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical +// value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print x +// check:$1 = 111102 +// debugger:print y +// check:$2 = true + +// debugger:continue +// debugger:finish + +// debugger:print a +// check:$3 = 2000 +// debugger:print b +// check:$4 = 3000 + +fn main() { + + fun(111102, true); + nested(2000, 3000); + + fn nested(a: i32, b: i64) -> (i32, i64) { + zzz() + (a, b) + } +} + +fn fun(x: int, y: bool) -> (int, bool) { + zzz(); + + (x, y) +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-basic.rs b/src/test/debug-info/reference-to-basic.rs new file mode 100644 index 00000000000..dfd0fbf8655 --- /dev/null +++ b/src/test/debug-info/reference-to-basic.rs @@ -0,0 +1,116 @@ +// 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. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// Caveats - gdb prints any 8-bit value (meaning rust i8 and u8 values) +// as its numerical value along with its associated ASCII char, there +// doesn't seem to be any way around this. Also, gdb doesn't know +// about UTF-32 character encoding and will print a rust char as only +// its numerical value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish +// debugger:print *bool_ref +// check:$1 = true + +// debugger:print *int_ref +// check:$2 = -1 + +// debugger:print *char_ref +// check:$3 = 97 + +// debugger:print *i8_ref +// check:$4 = 68 'D' + +// debugger:print *i16_ref +// check:$5 = -16 + +// debugger:print *i32_ref +// check:$6 = -32 + +// debugger:print *i64_ref +// check:$7 = -64 + +// debugger:print *uint_ref +// check:$8 = 1 + +// debugger:print *u8_ref +// check:$9 = 100 'd' + +// debugger:print *u16_ref +// check:$10 = 16 + +// debugger:print *u32_ref +// check:$11 = 32 + +// debugger:print *u64_ref +// check:$12 = 64 + +// debugger:print *float_ref +// check:$13 = 1.5 + +// debugger:print *f32_ref +// check:$14 = 2.5 + +// debugger:print *f64_ref +// check:$15 = 3.5 + +fn main() { + let bool_val: bool = true; + let bool_ref : &bool = &bool_val; + + let int_val: int = -1; + let int_ref : &int = &int_val; + + let char_val: char = 'a'; + let char_ref : &char = &char_val; + + let i8_val: i8 = 68; + let i8_ref : &i8 = &i8_val; + + let i16_val: i16 = -16; + let i16_ref : &i16 = &i16_val; + + let i32_val: i32 = -32; + let i32_ref : &i32 = &i32_val; + + let uint_val: i64 = -64; + let i64_ref : &i64 = &uint_val; + + let uint_val: uint = 1; + let uint_ref : &uint = &uint_val; + + let u8_val: u8 = 100; + let u8_ref : &u8 = &u8_val; + + let u16_val: u16 = 16; + let u16_ref : &u16 = &u16_val; + + let u32_val: u32 = 32; + let u32_ref : &u32 = &u32_val; + + let u64_val: u64 = 64; + let u64_ref : &u64 = &u64_val; + + let float_val: float = 1.5; + let float_ref : &float = &float_val; + + let f32_val: f32 = 2.5; + let f32_ref : &f32 = &f32_val; + + let f64_val: f64 = 3.5; + let f64_ref : &f64 = &f64_val; + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-managed-basic.rs b/src/test/debug-info/reference-to-managed-basic.rs new file mode 100644 index 00000000000..e3951c94b6f --- /dev/null +++ b/src/test/debug-info/reference-to-managed-basic.rs @@ -0,0 +1,114 @@ +// 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. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// Gdb doesn't know about UTF-32 character encoding and will print a rust char as only +// its numerical value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish +// debugger:print *bool_ref +// check:$1 = true + +// debugger:print *int_ref +// check:$2 = -1 + +// debugger:print *char_ref +// check:$3 = 97 + +// debugger:print/d *i8_ref +// check:$4 = 68 + +// debugger:print *i16_ref +// check:$5 = -16 + +// debugger:print *i32_ref +// check:$6 = -32 + +// debugger:print *i64_ref +// check:$7 = -64 + +// debugger:print *uint_ref +// check:$8 = 1 + +// debugger:print/d *u8_ref +// check:$9 = 100 + +// debugger:print *u16_ref +// check:$10 = 16 + +// debugger:print *u32_ref +// check:$11 = 32 + +// debugger:print *u64_ref +// check:$12 = 64 + +// debugger:print *float_ref +// check:$13 = 1.5 + +// debugger:print *f32_ref +// check:$14 = 2.5 + +// debugger:print *f64_ref +// check:$15 = 3.5 + + +fn main() { + let bool_box: @bool = @true; + let bool_ref : &bool = bool_box; + + let int_box: @int = @-1; + let int_ref : &int = int_box; + + let char_box: @char = @'a'; + let char_ref : &char = char_box; + + let i8_box: @i8 = @68; + let i8_ref : &i8 = i8_box; + + let i16_box: @i16 = @-16; + let i16_ref : &i16 = i16_box; + + let i32_box: @i32 = @-32; + let i32_ref : &i32 = i32_box; + + let i64_box: @i64 = @-64; + let i64_ref : &i64 = i64_box; + + let uint_box: @uint = @1; + let uint_ref : &uint = uint_box; + + let u8_box: @u8 = @100; + let u8_ref : &u8 = u8_box; + + let u16_box: @u16 = @16; + let u16_ref : &u16 = u16_box; + + let u32_box: @u32 = @32; + let u32_ref : &u32 = u32_box; + + let u64_box: @u64 = @64; + let u64_ref : &u64 = u64_box; + + let float_box: @float = @1.5; + let float_ref : &float = float_box; + + let f32_box: @f32 = @2.5; + let f32_ref : &f32 = f32_box; + + let f64_box: @f64 = @3.5; + let f64_ref : &f64 = f64_box; + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-struct.rs b/src/test/debug-info/reference-to-struct.rs new file mode 100644 index 00000000000..f00872c00b0 --- /dev/null +++ b/src/test/debug-info/reference-to-struct.rs @@ -0,0 +1,78 @@ +// 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. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical +// value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print *stack_val_ref +// check:$1 = {x = 10, y = 23.5} + +// debugger:print *stack_val_interior_ref_1 +// check:$2 = 10 + +// debugger:print *stack_val_interior_ref_2 +// check:$3 = 23.5 + +// debugger:print *ref_to_unnamed +// check:$4 = {x = 11, y = 24.5} + +// debugger:print *managed_val_ref +// check:$5 = {x = 12, y = 25.5} + +// debugger:print *managed_val_interior_ref_1 +// check:$6 = 12 + +// debugger:print *managed_val_interior_ref_2 +// check:$7 = 25.5 + +// debugger:print *unique_val_ref +// check:$8 = {x = 13, y = 26.5} + +// debugger:print *unique_val_interior_ref_1 +// check:$9 = 13 + +// debugger:print *unique_val_interior_ref_2 +// check:$10 = 26.5 + + + +struct SomeStruct { + x: int, + y: f64 +} + +fn main() { + let stack_val: SomeStruct = SomeStruct { x: 10, y: 23.5 }; + let stack_val_ref : &SomeStruct = &stack_val; + let stack_val_interior_ref_1 : &int = &stack_val.x; + let stack_val_interior_ref_2 : &f64 = &stack_val.y; + let ref_to_unnamed : &SomeStruct = &SomeStruct { x: 11, y: 24.5 }; + + let managed_val = @SomeStruct { x: 12, y: 25.5 }; + let managed_val_ref : &SomeStruct = managed_val; + let managed_val_interior_ref_1 : &int = &managed_val.x; + let managed_val_interior_ref_2 : &f64 = &managed_val.y; + + let unique_val = ~SomeStruct { x: 13, y: 26.5 }; + let unique_val_ref : &SomeStruct = unique_val; + let unique_val_interior_ref_1 : &int = &unique_val.x; + let unique_val_interior_ref_2 : &f64 = &unique_val.y; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-tuple.rs b/src/test/debug-info/reference-to-tuple.rs new file mode 100644 index 00000000000..86d02185bda --- /dev/null +++ b/src/test/debug-info/reference-to-tuple.rs @@ -0,0 +1,47 @@ +// 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. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical +// value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print *stack_val_ref +// check:$1 = {-14, -19} + +// debugger:print *ref_to_unnamed +// check:$2 = {-15, -20} + +// debugger:print *managed_val_ref +// check:$3 = {-16, -21} + +// debugger:print *unique_val_ref +// check:$4 = {-17, -22} + +fn main() { + let stack_val: (i16, f32) = (-14, -19f32); + let stack_val_ref : &(i16, f32) = &stack_val; + let ref_to_unnamed : &(i16, f32) = &(-15, -20f32); + + let managed_val : @(i16, f32) = @(-16, -21f32); + let managed_val_ref : &(i16, f32) = managed_val; + + let unique_val: ~(i16, f32) = ~(-17, -22f32); + let unique_val_ref : &(i16, f32) = unique_val; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-unique-basic.rs b/src/test/debug-info/reference-to-unique-basic.rs new file mode 100644 index 00000000000..ce5b50459f6 --- /dev/null +++ b/src/test/debug-info/reference-to-unique-basic.rs @@ -0,0 +1,115 @@ +// 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. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// Gdb doesn't know +// about UTF-32 character encoding and will print a rust char as only +// its numerical value. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish +// debugger:print *bool_ref +// check:$1 = true + +// debugger:print *int_ref +// check:$2 = -1 + +// debugger:print *char_ref +// check:$3 = 97 + +// debugger:print/d *i8_ref +// check:$4 = 68 + +// debugger:print *i16_ref +// check:$5 = -16 + +// debugger:print *i32_ref +// check:$6 = -32 + +// debugger:print *i64_ref +// check:$7 = -64 + +// debugger:print *uint_ref +// check:$8 = 1 + +// debugger:print/d *u8_ref +// check:$9 = 100 + +// debugger:print *u16_ref +// check:$10 = 16 + +// debugger:print *u32_ref +// check:$11 = 32 + +// debugger:print *u64_ref +// check:$12 = 64 + +// debugger:print *float_ref +// check:$13 = 1.5 + +// debugger:print *f32_ref +// check:$14 = 2.5 + +// debugger:print *f64_ref +// check:$15 = 3.5 + + +fn main() { + let bool_box: ~bool = ~true; + let bool_ref : &bool = bool_box; + + let int_box: ~int = ~-1; + let int_ref : &int = int_box; + + let char_box: ~char = ~'a'; + let char_ref : &char = char_box; + + let i8_box: ~i8 = ~68; + let i8_ref : &i8 = i8_box; + + let i16_box: ~i16 = ~-16; + let i16_ref : &i16 = i16_box; + + let i32_box: ~i32 = ~-32; + let i32_ref : &i32 = i32_box; + + let i64_box: ~i64 = ~-64; + let i64_ref : &i64 = i64_box; + + let uint_box: ~uint = ~1; + let uint_ref : &uint = uint_box; + + let u8_box: ~u8 = ~100; + let u8_ref : &u8 = u8_box; + + let u16_box: ~u16 = ~16; + let u16_ref : &u16 = u16_box; + + let u32_box: ~u32 = ~32; + let u32_ref : &u32 = u32_box; + + let u64_box: ~u64 = ~64; + let u64_ref : &u64 = u64_box; + + let float_box: ~float = ~1.5; + let float_ref : &float = float_box; + + let f32_box: ~f32 = ~2.5; + let f32_ref : &f32 = f32_box; + + let f64_box: ~f64 = ~3.5; + let f64_ref : &f64 = f64_box; + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/simple-struct.rs b/src/test/debug-info/simple-struct.rs new file mode 100644 index 00000000000..49e7bc255c1 --- /dev/null +++ b/src/test/debug-info/simple-struct.rs @@ -0,0 +1,84 @@ +// 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. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print no_padding16 +// check:$1 = {x = 10000, y = -10001} + +// debugger:print no_padding32 +// check:$2 = {x = -10002, y = -10003.5, z = 10004} + +// debugger:print no_padding64 +// check:$3 = {x = -10005.5, y = 10006, z = 10007} + +// debugger:print no_padding163264 +// check:$4 = {a = -10008, b = 10009, c = 10010, d = 10011} + +// debugger:print internal_padding +// check:$5 = {x = 10012, y = -10013} + +// debugger:print padding_at_end +// check:$6 = {x = -10014, y = 10015} + + +struct NoPadding16 { + x: u16, + y: i16 +} + +struct NoPadding32 { + x: i32, + y: f32, + z: u32 +} + +struct NoPadding64 { + x: f64, + y: i64, + z: u64 +} + +struct NoPadding163264 { + a: i16, + b: u16, + c: i32, + d: u64 +} + +struct InternalPadding { + x: u16, + y: i64 +} + +struct PaddingAtEnd { + x: i64, + y: u16 +} + +fn main() { + let no_padding16 = NoPadding16 { x: 10000, y: -10001 }; + let no_padding32 = NoPadding32 { x: -10002, y: -10003.5, z: 10004 }; + let no_padding64 = NoPadding64 { x: -10005.5, y: 10006, z: 10007 }; + let no_padding163264 = NoPadding163264 { a: -10008, b: 10009, c: 10010, d: 10011 }; + + let internal_padding = InternalPadding { x: 10012, y: -10013 }; + let padding_at_end = PaddingAtEnd { x: -10014, y: 10015 }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/simple-tuple.rs b/src/test/debug-info/simple-tuple.rs new file mode 100644 index 00000000000..84c736fab6b --- /dev/null +++ b/src/test/debug-info/simple-tuple.rs @@ -0,0 +1,51 @@ +// 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. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print/d noPadding8 +// check:$1 = {-100, 100} +// debugger:print noPadding16 +// check:$2 = {0, 1, 2} +// debugger:print noPadding32 +// check:$3 = {3, 4.5, 5} +// debugger:print noPadding64 +// check:$4 = {6, 7.5, 8} + +// debugger:print internalPadding1 +// check:$5 = {9, 10} +// debugger:print internalPadding2 +// check:$6 = {11, 12, 13, 14} + +// debugger:print paddingAtEnd +// check:$7 = {15, 16} + + +fn main() { + let noPadding8 : (i8, u8) = (-100, 100); + let noPadding16 : (i16, i16, u16) = (0, 1, 2); + let noPadding32 : (i32, f32, u32) = (3, 4.5, 5); + let noPadding64 : (i64, f64, u64) = (6, 7.5, 8); + + let internalPadding1 : (i16, i32) = (9, 10); + let internalPadding2 : (i16, i32, u32, u64) = (11, 12, 13, 14); + + let paddingAtEnd : (i32, i16) = (15, 16); + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/struct-in-struct.rs b/src/test/debug-info/struct-in-struct.rs new file mode 100644 index 00000000000..04c5eec610b --- /dev/null +++ b/src/test/debug-info/struct-in-struct.rs @@ -0,0 +1,145 @@ +// 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. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print three_simple_structs +// check:$1 = {x = {x = 1}, y = {x = 2}, z = {x = 3}} + +// debugger:print internal_padding_parent +// check:$2 = {x = {x = 4, y = 5}, y = {x = 6, y = 7}, z = {x = 8, y = 9}} + +// debugger:print padding_at_end_parent +// check:$3 = {x = {x = 10, y = 11}, y = {x = 12, y = 13}, z = {x = 14, y = 15}} + + +struct Simple { + x: i32 +} + +struct InternalPadding { + x: i32, + y: i64 +} + +struct PaddingAtEnd { + x: i64, + y: i32 +} + +struct ThreeSimpleStructs { + x: Simple, + y: Simple, + z: Simple +} + +struct InternalPaddingParent { + x: InternalPadding, + y: InternalPadding, + z: InternalPadding +} + +struct PaddingAtEndParent { + x: PaddingAtEnd, + y: PaddingAtEnd, + z: PaddingAtEnd +} + +struct Mixed { + x: PaddingAtEnd, + y: InternalPadding, + z: Simple, + w: i16 +} + +struct Bag { + x: Simple +} + +struct BagInBag { + x: Bag +} + +struct ThatsJustOverkill { + x: BagInBag +} + +struct Tree { + x: Simple, + y: InternalPaddingParent, + z: BagInBag +} + +fn main() { + + let three_simple_structs = ThreeSimpleStructs { + x: Simple { x: 1 }, + y: Simple { x: 2 }, + z: Simple { x: 3 } + }; + + let internal_padding_parent = InternalPaddingParent { + x: InternalPadding { x: 4, y: 5 }, + y: InternalPadding { x: 6, y: 7 }, + z: InternalPadding { x: 8, y: 9 } + }; + + let padding_at_end_parent = PaddingAtEndParent { + x: PaddingAtEnd { x: 10, y: 11 }, + y: PaddingAtEnd { x: 12, y: 13 }, + z: PaddingAtEnd { x: 14, y: 15 } + }; + + let mixed = Mixed { + x: PaddingAtEnd { x: 16, y: 17 }, + y: InternalPadding { x: 18, y: 19 }, + z: Simple { x: 20 }, + w: 21 + }; + + let bag = Bag { x: Simple { x: 22 } }; + let bag_in_bag = BagInBag { + x: Bag { + x: Simple { x: 23 } + } + }; + + let tjo = ThatsJustOverkill { + x: BagInBag { + x: Bag { + x: Simple { x: 24 } + } + } + }; + + let tree = Tree { + x: Simple { x: 25 }, + y: InternalPaddingParent { + x: InternalPadding { x: 26, y: 27 }, + y: InternalPadding { x: 28, y: 29 }, + z: InternalPadding { x: 30, y: 31 } + }, + z: BagInBag { + x: Bag { + x: Simple { x: 32 } + } + } + }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/struct-with-destructor.rs b/src/test/debug-info/struct-with-destructor.rs new file mode 100644 index 00000000000..f8281bba49e --- /dev/null +++ b/src/test/debug-info/struct-with-destructor.rs @@ -0,0 +1,88 @@ +// 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. + +// xfail-test + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish +// debugger:print simple +// check:$1 = {x = 10, y = 20} + +// debugger:print noDestructor +// check:$2 = {a = {x = 10, y = 20}, guard = -1} + +// debugger:print withDestructor +// check:$3 = {a = {x = 10, y = 20}, guard = -1} + +struct NoDestructor { + x : i32, + y : i64 +} + +struct WithDestructor { + x : i32, + y : i64 +} + +impl Drop for WithDestructor { + fn finalize(&self) {} +} + +struct NoDestructorGuarded { + a: NoDestructor, + guard: i64 +} + +struct WithDestructorGuarded { + a: WithDestructor, + guard: i64 +} + + +// The compiler adds a 'destructed' boolean field to structs implementing Drop. This field is used +// at runtime to prevent drop() to be executed more than once (see middle::trans::adt). +// This field must be incorporated by the debug info generation. Otherwise the debugger assumes a +// wrong size/layout for the struct. +fn main() { + + let simple = WithDestructor { x: 10, y: 20 }; + + let noDestructor = NoDestructorGuarded { + a: NoDestructor { x: 10, y: 20 }, + guard: -1 + }; + + // If the destructor flag field is not incorporated into the debug info for 'WithDestructor' + // then the debugger will have an invalid offset for the field 'guard' and thus should not be + // able to read its value correctly (dots are padding bytes, D is the boolean destructor flag): + // + // NoDestructorGuarded = 0000....00000000FFFFFFFF + // <--------------><------> + // NoDestructor guard + // + // + // withDestructorGuarded = 0000....00000000D.......FFFFFFFF + // <--------------><------> // How debug info says it is + // WithDestructor guard + // + // <----------------------><------> // How it actually is + // WithDestructor guard + // + let withDestructor = WithDestructorGuarded { + a: WithDestructor { x: 10, y: 20 }, + guard: -1 + }; + + zzz(); +} + +fn zzz() {()} diff --git a/src/test/debug-info/tuple-in-struct.rs b/src/test/debug-info/tuple-in-struct.rs new file mode 100644 index 00000000000..369c9fd28cc --- /dev/null +++ b/src/test/debug-info/tuple-in-struct.rs @@ -0,0 +1,151 @@ +// 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. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print no_padding1 +// check:$1 = {x = {0, 1}, y = 2, z = {3, 4, 5}} +// debugger:print no_padding2 +// check:$2 = {x = {6, 7}, y = {{8, 9}, 10}} + +// debugger:print tuple_internal_padding +// check:$3 = {x = {11, 12}, y = {13, 14}} +// debugger:print struct_internal_padding +// check:$4 = {x = {15, 16}, y = {17, 18}} +// debugger:print both_internally_padded +// check:$5 = {x = {19, 20, 21}, y = {22, 23}} + +// debugger:print single_tuple +// check:$6 = {x = {24, 25, 26}} + +// debugger:print tuple_padded_at_end +// check:$7 = {x = {27, 28}, y = {29, 30}} +// debugger:print struct_padded_at_end +// check:$8 = {x = {31, 32}, y = {33, 34}} +// debugger:print both_padded_at_end +// check:$9 = {x = {35, 36, 37}, y = {38, 39}} + +// debugger:print mixed_padding +// check:$10 = {x = {{40, 41, 42}, {43, 44}}, y = {45, 46, 47, 48}} + +struct NoPadding1 { + x: (i32, i32), + y: i32, + z: (i32, i32, i32) +} + +struct NoPadding2 { + x: (i32, i32), + y: ((i32, i32), i32) +} + +struct TupleInternalPadding { + x: (i16, i32), + y: (i32, i64) +} + +struct StructInternalPadding { + x: (i16, i16), + y: (i64, i64) +} + +struct BothInternallyPadded { + x: (i16, i32, i32), + y: (i32, i64) +} + +struct SingleTuple { + x: (i16, i32, i64) +} + +struct TuplePaddedAtEnd { + x: (i32, i16), + y: (i64, i32) +} + +struct StructPaddedAtEnd { + x: (i64, i64), + y: (i16, i16) +} + +struct BothPaddedAtEnd { + x: (i32, i32, i16), + y: (i64, i32) +} + +// Data-layout (padding signified by dots, one column = 2 bytes): +// [a.bbc...ddddee..ffffg.hhi...] +struct MixedPadding { + x: ((i16, i32, i16), (i64, i32)), + y: (i64, i16, i32, i16) +} + + +fn main() { + let no_padding1 = NoPadding1 { + x: (0, 1), + y: 2, + z: (3, 4, 5) + }; + + let no_padding2 = NoPadding2 { + x: (6, 7), + y: ((8, 9), 10) + }; + + let tuple_internal_padding = TupleInternalPadding { + x: (11, 12), + y: (13, 14) + }; + + let struct_internal_padding = StructInternalPadding { + x: (15, 16), + y: (17, 18) + }; + + let both_internally_padded = BothInternallyPadded { + x: (19, 20, 21), + y: (22, 23) + }; + + let single_tuple = SingleTuple { + x: (24, 25, 26) + }; + + let tuple_padded_at_end = TuplePaddedAtEnd { + x: (27, 28), + y: (29, 30) + }; + + let struct_padded_at_end = StructPaddedAtEnd { + x: (31, 32), + y: (33, 34) + }; + + let both_padded_at_end = BothPaddedAtEnd { + x: (35, 36, 37), + y: (38, 39) + }; + + let mixed_padding = MixedPadding { + x: ((40, 41, 42), (43, 44)), + y: (45, 46, 47, 48) + }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/tuple-in-tuple.rs b/src/test/debug-info/tuple-in-tuple.rs new file mode 100644 index 00000000000..13f8719694e --- /dev/null +++ b/src/test/debug-info/tuple-in-tuple.rs @@ -0,0 +1,50 @@ +// 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. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print no_padding1 +// check:$1 = {{0, 1}, 2, 3} +// debugger:print no_padding2 +// check:$2 = {4, {5, 6}, 7} +// debugger:print no_padding3 +// check:$3 = {8, 9, {10, 11}} + +// debugger:print internal_padding1 +// check:$4 = {12, {13, 14}} +// debugger:print internal_padding2 +// check:$5 = {15, {16, 17}} + +// debugger:print padding_at_end1 +// check:$6 = {18, {19, 20}} +// debugger:print padding_at_end2 +// check:$7 = {{21, 22}, 23} + +fn main() { + let no_padding1 : ((u32, u32), u32, u32) = ((0, 1), 2, 3); + let no_padding2 : (u32, (u32, u32), u32) = (4, (5, 6), 7); + let no_padding3 : (u32, u32, (u32, u32)) = (8, 9, (10, 11)); + + let internal_padding1 : (i16, (i32, i32)) = (12, (13, 14)); + let internal_padding2 : (i16, (i16, i32)) = (15, (16, 17)); + + let padding_at_end1 : (i32, (i32, i16)) = (18, (19, 20)); + let padding_at_end2 : ((i32, i16), i32) = ((21, 22), 23); + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/struct.rs b/src/test/debug-info/variable-scope.rs index ddfac9cbeea..dd3a1671b78 100644 --- a/src/test/debug-info/struct.rs +++ b/src/test/debug-info/variable-scope.rs @@ -8,28 +8,42 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 +// xfail-test // compile-flags:-Z extra-debug-info -// debugger:set print pretty off -// debugger:break _zzz +// debugger:break zzz // debugger:run // debugger:finish -// debugger:print pair -// check:$1 = {x = 1, y = 2} -// debugger:print pair.x -// check:$2 = 1 -// debugger:print pair.y -// check:$3 = 2 - -struct Pair { - x: int, - y: int -} +// debugger:print x +// check:$1 = false +// debugger:print y +// check:$2 = true + +// debugger:continue +// debugger:finish +// debugger:print x +// check:$3 = 10 + +// debugger:continue +// debugger:finish +// debugger:print x +// check:$4 = false +// debugger:print y +// check:$5 = 11 fn main() { - let pair = Pair { x: 1, y: 2 }; - _zzz(); + let x = false; + let y = true; + + zzz(); + + { + let x = 10; + zzz(); + } + + let y = 11; + zzz(); } -fn _zzz() {()} \ No newline at end of file +fn zzz() {()} diff --git a/src/test/pretty/block-comment-wchar.pp b/src/test/pretty/block-comment-wchar.pp index 911de166e8f..dbf28caecf2 100644 --- a/src/test/pretty/block-comment-wchar.pp +++ b/src/test/pretty/block-comment-wchar.pp @@ -109,7 +109,7 @@ fn main() { '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200A', '\u2028', '\u2029', '\u202F', '\u205F', '\u3000']; // <= bugs in pretty-printer? - for chars.each |c| { + for chars.iter().advance |c| { let ws = c.is_whitespace(); println(fmt!("%? %?" , c , ws)); } diff --git a/src/test/pretty/block-comment-wchar.rs b/src/test/pretty/block-comment-wchar.rs index d8a820542a7..148b50d9c91 100644 --- a/src/test/pretty/block-comment-wchar.rs +++ b/src/test/pretty/block-comment-wchar.rs @@ -102,7 +102,7 @@ fn main() { '\xA0', '\u1680', '\u180E', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200A', '\u2028', '\u2029', '\u202F', '\u205F', '\u3000']; - for chars.each |c| { + for chars.iter().advance |c| { let ws = c.is_whitespace(); println(fmt!("%? %?", c , ws)); // <= bugs in pretty-printer? } diff --git a/src/test/run-fail/bug-811.rs b/src/test/run-fail/bug-811.rs index b497b0224b9..992747187f6 100644 --- a/src/test/run-fail/bug-811.rs +++ b/src/test/run-fail/bug-811.rs @@ -19,6 +19,6 @@ struct chan_t<T> { port: port_id, } -fn send<T:Owned>(ch: chan_t<T>, data: T) { fail!(); } +fn send<T:Send>(ch: chan_t<T>, data: T) { fail!(); } fn main() { fail!("quux"); } diff --git a/src/test/run-fail/extern-fail.rs b/src/test/run-fail/extern-fail.rs index 2be41d3bed0..3d15ea16241 100644 --- a/src/test/run-fail/extern-fail.rs +++ b/src/test/run-fail/extern-fail.rs @@ -13,7 +13,6 @@ // Instead the failure will be delivered after the callbacks return. use std::libc; -use std::old_iter; use std::task; mod rustrt { diff --git a/src/test/run-fail/issue-2061.rs b/src/test/run-fail/issue-2061.rs index cee3546acfa..3e78fd1f7db 100644 --- a/src/test/run-fail/issue-2061.rs +++ b/src/test/run-fail/issue-2061.rs @@ -15,7 +15,7 @@ struct R { } impl Drop for R { - fn finalize(&self) { + fn drop(&self) { let _y = R { b: self.b }; } } diff --git a/src/test/run-fail/issue-3029.rs b/src/test/run-fail/issue-3029.rs index 6f4a3f5ab1d..caee0002788 100644 --- a/src/test/run-fail/issue-3029.rs +++ b/src/test/run-fail/issue-3029.rs @@ -10,9 +10,9 @@ // error-pattern:so long fn main() { - let x = ~[]; + let mut x = ~[]; let y = ~[3]; fail!("so long"); - x += y; + x.push_all_move(y); ~"good" + ~"bye"; } diff --git a/src/test/run-fail/morestack2.rs b/src/test/run-fail/morestack2.rs index d03433d5872..37bc3b6de8a 100644 --- a/src/test/run-fail/morestack2.rs +++ b/src/test/run-fail/morestack2.rs @@ -44,7 +44,7 @@ struct and_then_get_big_again { } impl Drop for and_then_get_big_again { - fn finalize(&self) { + fn drop(&self) { fn getbig(i: int) { if i != 0 { getbig(i - 1); diff --git a/src/test/run-fail/morestack3.rs b/src/test/run-fail/morestack3.rs index d2e17d28561..4e059c5bd3c 100644 --- a/src/test/run-fail/morestack3.rs +++ b/src/test/run-fail/morestack3.rs @@ -30,7 +30,7 @@ struct and_then_get_big_again { } impl Drop for and_then_get_big_again { - fn finalize(&self) { + fn drop(&self) { fn getbig(i: int) { if i != 0 { getbig(i - 1); diff --git a/src/test/run-fail/morestack4.rs b/src/test/run-fail/morestack4.rs index c4f7de49555..db46438ea3c 100644 --- a/src/test/run-fail/morestack4.rs +++ b/src/test/run-fail/morestack4.rs @@ -30,7 +30,7 @@ struct and_then_get_big_again { } impl Drop for and_then_get_big_again { - fn finalize(&self) {} + fn drop(&self) {} } fn and_then_get_big_again(x:int) -> and_then_get_big_again { diff --git a/src/test/run-fail/rt-set-exit-status-fail2.rs b/src/test/run-fail/rt-set-exit-status-fail2.rs index 3d0341d01f4..ee268f409a5 100644 --- a/src/test/run-fail/rt-set-exit-status-fail2.rs +++ b/src/test/run-fail/rt-set-exit-status-fail2.rs @@ -21,7 +21,7 @@ struct r { // failed has no effect and the process exits with the // runtime's exit code impl Drop for r { - fn finalize(&self) { + fn drop(&self) { os::set_exit_status(50); } } diff --git a/src/test/run-fail/too-much-recursion-unwinding.rs b/src/test/run-fail/too-much-recursion-unwinding.rs index 1c668dfc90d..16d0fe34668 100644 --- a/src/test/run-fail/too-much-recursion-unwinding.rs +++ b/src/test/run-fail/too-much-recursion-unwinding.rs @@ -24,7 +24,7 @@ struct r { } impl Drop for r { - fn finalize(&self) { + fn drop(&self) { unsafe { if !*(self.recursed) { *(self.recursed) = true; diff --git a/src/test/run-fail/unwind-box-res.rs b/src/test/run-fail/unwind-box-res.rs index a1e1ee433bb..7f022d5761c 100644 --- a/src/test/run-fail/unwind-box-res.rs +++ b/src/test/run-fail/unwind-box-res.rs @@ -21,7 +21,7 @@ struct r { } impl Drop for r { - fn finalize(&self) { + fn drop(&self) { unsafe { let _v2: ~int = cast::transmute(self.v); } diff --git a/src/test/run-fail/unwind-resource-fail.rs b/src/test/run-fail/unwind-resource-fail.rs index 486c2dd3b36..b4b0150013a 100644 --- a/src/test/run-fail/unwind-resource-fail.rs +++ b/src/test/run-fail/unwind-resource-fail.rs @@ -15,7 +15,7 @@ struct r { } impl Drop for r { - fn finalize(&self) { fail!("squirrel") } + fn drop(&self) { fail!("squirrel") } } fn r(i: int) -> r { r { i: i } } diff --git a/src/test/run-fail/unwind-resource-fail2.rs b/src/test/run-fail/unwind-resource-fail2.rs index ca98a61f234..6ebb4a742c4 100644 --- a/src/test/run-fail/unwind-resource-fail2.rs +++ b/src/test/run-fail/unwind-resource-fail2.rs @@ -16,7 +16,7 @@ struct r { } impl Drop for r { - fn finalize(&self) { fail!("wombat") } + fn drop(&self) { fail!("wombat") } } fn r(i: int) -> r { r { i: i } } diff --git a/src/test/run-fail/unwind-resource-fail3.rs b/src/test/run-fail/unwind-resource-fail3.rs index 9d6f877293b..2de9d4cec77 100644 --- a/src/test/run-fail/unwind-resource-fail3.rs +++ b/src/test/run-fail/unwind-resource-fail3.rs @@ -19,7 +19,7 @@ fn faily_box(i: @int) -> faily_box { faily_box { i: i } } #[unsafe_destructor] impl Drop for faily_box { - fn finalize(&self) { + fn drop(&self) { fail!("quux"); } } diff --git a/src/test/run-pass/alignment-gep-tup-like-2.rs b/src/test/run-pass/alignment-gep-tup-like-2.rs index 753e5339de9..24709fb2974 100644 --- a/src/test/run-pass/alignment-gep-tup-like-2.rs +++ b/src/test/run-pass/alignment-gep-tup-like-2.rs @@ -23,7 +23,7 @@ fn make_cycle<A:Copy>(a: A) { g.rec = Some(g); } -fn f<A:Owned + Copy,B:Owned + Copy>(a: A, b: B) -> @fn() -> (A, B) { +fn f<A:Send + Copy,B:Send + Copy>(a: A, b: B) -> @fn() -> (A, B) { let result: @fn() -> (A, B) = || (copy a, copy b); result } diff --git a/src/test/run-pass/assignability-trait.rs b/src/test/run-pass/assignability-trait.rs index 5d2341ae42d..b65b18e1ab3 100644 --- a/src/test/run-pass/assignability-trait.rs +++ b/src/test/run-pass/assignability-trait.rs @@ -12,21 +12,19 @@ // making method calls, but only if there aren't any matches without // it. -use std::vec; - trait iterable<A> { fn iterate(&self, blk: &fn(x: &A) -> bool) -> bool; } impl<'self,A> iterable<A> for &'self [A] { fn iterate(&self, f: &fn(x: &A) -> bool) -> bool { - vec::each(*self, f) + self.iter().advance(f) } } impl<A> iterable<A> for ~[A] { fn iterate(&self, f: &fn(x: &A) -> bool) -> bool { - vec::each(*self, f) + self.iter().advance(f) } } diff --git a/src/test/run-pass/block-vec-map_zip.rs b/src/test/run-pass/attr-no-drop-flag-size.rs index 739dbab4d3a..87c476d781e 100644 --- a/src/test/run-pass/block-vec-map_zip.rs +++ b/src/test/run-pass/attr-no-drop-flag-size.rs @@ -8,13 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::vec; +use std::sys::size_of; -pub fn main() { - let v = - vec::map_zip(~[1, 2, 3, 4, 5], - ~[true, false, false, true, true], - |i, b| if *b { -(*i) } else { *i } ); - error!(v.clone()); - assert_eq!(v, ~[-1, 2, 3, -4, -5]); +#[unsafe_no_drop_flag] +struct Test<T> { + a: T +} + +#[unsafe_destructor] +impl<T> Drop for Test<T> { + fn drop(&self) { } +} + +fn main() { + assert_eq!(size_of::<int>(), size_of::<Test<int>>()); } diff --git a/src/test/run-pass/auto-loop.rs b/src/test/run-pass/auto-loop.rs index f148c509d4d..185a5a6407c 100644 --- a/src/test/run-pass/auto-loop.rs +++ b/src/test/run-pass/auto-loop.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::vec; - pub fn main() { let mut sum = 0; - for vec::each(~[1, 2, 3, 4, 5]) |x| { + let xs = ~[1, 2, 3, 4, 5]; + for xs.iter().advance |x| { sum += *x; } assert_eq!(sum, 15); diff --git a/src/test/run-pass/autoderef-method-priority.rs b/src/test/run-pass/autoderef-method-priority.rs index 9cfdac0a330..0fe30059ef6 100644 --- a/src/test/run-pass/autoderef-method-priority.rs +++ b/src/test/run-pass/autoderef-method-priority.rs @@ -1,6 +1,4 @@ -// xfail-test -// xfail'd because of a problem with by-value self. - +// xfail-test #5321 // 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. diff --git a/src/test/run-pass/block-arg.rs b/src/test/run-pass/block-arg.rs index d860c84dfce..8ea2a88fa09 100644 --- a/src/test/run-pass/block-arg.rs +++ b/src/test/run-pass/block-arg.rs @@ -15,7 +15,7 @@ pub fn main() { let v = ~[-1f, 0f, 1f, 2f, 3f]; // Statement form does not require parentheses: - for vec::each(v) |i| { + for v.iter().advance |i| { info!("%?", *i); } @@ -28,7 +28,7 @@ pub fn main() { assert!(any_negative); // Higher precedence than unary operations: - let abs_v = do vec::map(v) |e| { e.abs() }; + let abs_v = do v.iter().transform |e| { e.abs() }.collect::<~[float]>(); assert!(do abs_v.iter().all |e| { e.is_positive() }); assert!(!do abs_v.iter().any_ |e| { e.is_negative() }); diff --git a/src/test/run-pass/block-iter-1.rs b/src/test/run-pass/block-iter-1.rs index 34b77b4a844..6da1f9131a5 100644 --- a/src/test/run-pass/block-iter-1.rs +++ b/src/test/run-pass/block-iter-1.rs @@ -10,7 +10,7 @@ // xfail-fast -fn iter_vec<T>(v: ~[T], f: &fn(&T)) { for v.each |x| { f(x); } } +fn iter_vec<T>(v: ~[T], f: &fn(&T)) { for v.iter().advance |x| { f(x); } } pub fn main() { let v = ~[1, 2, 3, 4, 5, 6, 7]; diff --git a/src/test/run-pass/block-iter-2.rs b/src/test/run-pass/block-iter-2.rs index dc4ff5a054f..3092cd5338c 100644 --- a/src/test/run-pass/block-iter-2.rs +++ b/src/test/run-pass/block-iter-2.rs @@ -10,7 +10,7 @@ // xfail-fast -fn iter_vec<T>(v: ~[T], f: &fn(&T)) { for v.each |x| { f(x); } } +fn iter_vec<T>(v: ~[T], f: &fn(&T)) { for v.iter().advance |x| { f(x); } } pub fn main() { let v = ~[1, 2, 3, 4, 5]; diff --git a/src/test/run-pass/borrowck-borrow-from-at-vec.rs b/src/test/run-pass/borrowck-borrow-from-at-vec.rs index fb91e9a787e..21ea875b2f4 100644 --- a/src/test/run-pass/borrowck-borrow-from-at-vec.rs +++ b/src/test/run-pass/borrowck-borrow-from-at-vec.rs @@ -10,7 +10,7 @@ fn sum_slice(x: &[int]) -> int { let mut sum = 0; - for x.each |i| { sum += *i; } + for x.iter().advance |i| { sum += *i; } return sum; } diff --git a/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs b/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs index d63ebf7d24d..8f74e6cdc29 100644 --- a/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs +++ b/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::vec; - fn want_slice(v: &[int]) -> int { let mut sum = 0; - for vec::each(v) |i| { sum += *i; } - return sum; + for v.iter().advance |i| { sum += *i; } + sum } fn has_mut_vec(v: ~[int]) -> int { diff --git a/src/test/run-pass/borrowck-unary-move-2.rs b/src/test/run-pass/borrowck-unary-move-2.rs index c74fd4a68e7..c52371de54a 100644 --- a/src/test/run-pass/borrowck-unary-move-2.rs +++ b/src/test/run-pass/borrowck-unary-move-2.rs @@ -13,7 +13,7 @@ struct noncopyable { } impl Drop for noncopyable { - fn finalize(&self) { + fn drop(&self) { error!("dropped"); } } diff --git a/src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs b/src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs index 284db7af66b..612a472cde5 100644 --- a/src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs +++ b/src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs @@ -4,7 +4,7 @@ struct Wizard { impl Wizard { pub fn cast(&mut self) { - for self.spells.each |&spell| { + for self.spells.iter().advance |&spell| { println(spell); } } diff --git a/src/test/run-pass/break.rs b/src/test/run-pass/break.rs index 2edb270762c..85c6f90a742 100644 --- a/src/test/run-pass/break.rs +++ b/src/test/run-pass/break.rs @@ -16,7 +16,8 @@ pub fn main() { assert_eq!(i, 10); loop { i += 1; if i == 20 { break; } } assert_eq!(i, 20); - for vec::each(~[1, 2, 3, 4, 5, 6]) |x| { + let xs = [1, 2, 3, 4, 5, 6]; + for xs.iter().advance |x| { if *x == 3 { break; } assert!((*x <= 3)); } i = 0; @@ -26,7 +27,8 @@ pub fn main() { i += 1; if i % 2 == 0 { loop; } assert!((i % 2 != 0)); if i >= 10 { break; } } - for vec::each(~[1, 2, 3, 4, 5, 6]) |x| { + let ys = ~[1, 2, 3, 4, 5, 6]; + for ys.iter().advance |x| { if *x % 2 == 0 { loop; } assert!((*x % 2 != 0)); } diff --git a/src/test/run-pass/bug-7183-generics.rs b/src/test/run-pass/bug-7183-generics.rs new file mode 100644 index 00000000000..4fc5587e7f3 --- /dev/null +++ b/src/test/run-pass/bug-7183-generics.rs @@ -0,0 +1,45 @@ +// 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. + +#[allow(default_methods)] +trait Speak { + fn say(&self, s:&str) -> ~str; + fn hi(&self) -> ~str { hello(self) } +} + +fn hello<S:Speak>(s:&S) -> ~str{ + s.say("hello") +} + +impl Speak for int { + fn say(&self, s:&str) -> ~str { + fmt!("%s: %d", s, *self) + } +} + +impl<T: Speak> Speak for Option<T> { + fn say(&self, s:&str) -> ~str { + match *self { + None => fmt!("%s - none", s), + Some(ref x) => { ~"something!" + x.say(s) } + } + } +} + + +fn main() { + assert_eq!(3.hi(), ~"hello: 3"); + assert_eq!(Some(Some(3)).hi(), ~"something!something!hello: 3"); + assert_eq!(None::<int>.hi(), ~"hello - none"); + + // These fail because of a bug in monomorphization's ID generation. + //assert_eq!(Some(None::<int>).hi(), ~"something!hello - none"); + //assert_eq!(Some(3).hi(), ~"something!hello: 3"); +} diff --git a/src/test/run-pass/vec-position.rs b/src/test/run-pass/bug-7295.rs index aaf232f2046..080a0dbd91a 100644 --- a/src/test/run-pass/vec-position.rs +++ b/src/test/run-pass/bug-7295.rs @@ -8,9 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(default_methods)]; +pub trait Foo<T> { + pub fn func1<U>(&self, t: U); + + pub fn func2<U>(&self, t: U) { + self.func1(t); + } +} + pub fn main() { - let mut v = ~[1, 2, 3]; - assert!(v.position(|x| *x == 1) == Some(0)); - assert!(v.position(|x| *x == 3) == Some(2)); - assert!(v.position(|x| *x == 17) == None); + } diff --git a/src/test/run-pass/cfg-macros-foo.rs b/src/test/run-pass/cfg-macros-foo.rs new file mode 100644 index 00000000000..8dfb7190c21 --- /dev/null +++ b/src/test/run-pass/cfg-macros-foo.rs @@ -0,0 +1,35 @@ +// 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. + +// xfail-fast compile-flags directive doesn't work for check-fast +// compile-flags: --cfg foo + +// check that cfg correctly chooses between the macro impls (see also +// cfg-macros-notfoo.rs) + +#[cfg(foo)] +#[macro_escape] +mod foo { + macro_rules! bar { + () => { true } + } +} + +#[cfg(not(foo))] +#[macro_escape] +mod foo { + macro_rules! bar { + () => { false } + } +} + +fn main() { + assert!(bar!()) +} diff --git a/src/test/run-pass/cfg-macros-notfoo.rs b/src/test/run-pass/cfg-macros-notfoo.rs new file mode 100644 index 00000000000..8ede6eff2dd --- /dev/null +++ b/src/test/run-pass/cfg-macros-notfoo.rs @@ -0,0 +1,35 @@ +// 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. + +// xfail-fast compile-flags directive doesn't work for check-fast +// compile-flags: + +// check that cfg correctly chooses between the macro impls (see also +// cfg-macros-foo.rs) + +#[cfg(foo)] +#[macro_escape] +mod foo { + macro_rules! bar { + () => { true } + } +} + +#[cfg(not(foo))] +#[macro_escape] +mod foo { + macro_rules! bar { + () => { false } + } +} + +fn main() { + assert!(!bar!()) +} diff --git a/src/test/run-pass/class-attributes-1.rs b/src/test/run-pass/class-attributes-1.rs index b7ecb622e7f..108ae023e12 100644 --- a/src/test/run-pass/class-attributes-1.rs +++ b/src/test/run-pass/class-attributes-1.rs @@ -16,7 +16,7 @@ struct cat { impl Drop for cat { #[cat_dropper] - fn finalize(&self) { error!("%s landed on hir feet" , self . name); } + fn drop(&self) { error!("%s landed on hir feet" , self . name); } } diff --git a/src/test/run-pass/class-attributes-2.rs b/src/test/run-pass/class-attributes-2.rs index 8636699c482..02279677276 100644 --- a/src/test/run-pass/class-attributes-2.rs +++ b/src/test/run-pass/class-attributes-2.rs @@ -17,7 +17,7 @@ impl Drop for cat { /** Actually, cats don't always land on their feet when you drop them. */ - fn finalize(&self) { + fn drop(&self) { error!("%s landed on hir feet", self.name); } } diff --git a/src/test/run-pass/class-cast-to-trait-cross-crate.rs b/src/test/run-pass/class-cast-to-trait-cross-crate.rs deleted file mode 100644 index 6674147e147..00000000000 --- a/src/test/run-pass/class-cast-to-trait-cross-crate.rs +++ /dev/null @@ -1,60 +0,0 @@ -// 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. - -// xfail-test - -use to_str::*; -use to_str::to_str; - -class cat : to_str { - priv { - let mut meows : uint; - fn meow() { - error!("Meow"); - self.meows += 1u; - if self.meows % 5u == 0u { - self.how_hungry += 1; - } - } - } - - let mut how_hungry : int; - let name : str; - - new(in_x : uint, in_y : int, in_name: str) - { self.meows = in_x; self.how_hungry = in_y; self.name = in_name; } - - fn speak() { self.meow(); } - - fn eat() -> bool { - if self.how_hungry > 0 { - error!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - error!("Not hungry!"); - return false; - } - } - - fn to_str() -> str { self.name } -} - -fn print_out<T:to_str>(thing: T, expected: str) { - let actual = thing.to_str(); - debug!("%s", actual); - assert_eq!(actual, expected); -} - -pub fn main() { - let nyan : to_str = cat(0u, 2, "nyan") as to_str; - print_out(nyan, "nyan"); -} diff --git a/src/test/run-pass/class-dtor.rs b/src/test/run-pass/class-dtor.rs index 229c683706d..c294670faa3 100644 --- a/src/test/run-pass/class-dtor.rs +++ b/src/test/run-pass/class-dtor.rs @@ -14,7 +14,7 @@ struct cat { } impl Drop for cat { - fn finalize(&self) { + fn drop(&self) { (self.done)(self.meows); } } diff --git a/src/test/run-pass/class-impl-parameterized-trait.rs b/src/test/run-pass/class-impl-parameterized-trait.rs index 09967f0ab36..655a9d4a0c0 100644 --- a/src/test/run-pass/class-impl-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-parameterized-trait.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-test FIXME #7307 // xfail-fast extern mod extra; diff --git a/src/test/run-pass/class-impl-very-parameterized-trait.rs b/src/test/run-pass/class-impl-very-parameterized-trait.rs index 88686bcdbfa..2805fec6fce 100644 --- a/src/test/run-pass/class-impl-very-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-very-parameterized-trait.rs @@ -13,7 +13,6 @@ use std::cmp; use std::container::{Container, Mutable, Map}; use std::int; -use std::old_iter::BaseIter; use std::uint; enum cat_type { tuxedo, tabby, tortoiseshell } @@ -62,29 +61,8 @@ impl<T> Mutable for cat<T> { } impl<T> Map<int, T> for cat<T> { - fn each<'a>(&'a self, f: &fn(&int, &'a T) -> bool) -> bool { - let mut n = int::abs(self.meows); - while n > 0 { - if !f(&n, &self.name) { return false; } - n -= 1; - } - return true; - } - fn contains_key(&self, k: &int) -> bool { *k <= self.meows } - fn each_key(&self, f: &fn(v: &int) -> bool) -> bool { - self.each(|k, _| f(k)) - } - - fn each_value<'a>(&'a self, f: &fn(v: &'a T) -> bool) -> bool { - self.each(|_, v| f(v)) - } - - fn mutate_values(&mut self, _f: &fn(&int, &mut T) -> bool) -> bool { - fail!("nope") - } - fn insert(&mut self, k: int, _: T) -> bool { self.meows += k; true diff --git a/src/test/run-pass/class-implements-multiple-traits.rs b/src/test/run-pass/class-implements-multiple-traits.rs index 7a3045db91f..8565ab03841 100644 --- a/src/test/run-pass/class-implements-multiple-traits.rs +++ b/src/test/run-pass/class-implements-multiple-traits.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-test FIXME #7305 extern mod extra; use extra::oldmap::*; diff --git a/src/test/run-pass/class-trait-bounded-param.rs b/src/test/run-pass/class-trait-bounded-param.rs deleted file mode 100644 index 75c62abcb0d..00000000000 --- a/src/test/run-pass/class-trait-bounded-param.rs +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -// xfail-test - -extern mod extra; -use extra::oldmap::{map, hashmap, int_hash}; - -class keys<K:Copy,V:Copy,M:Copy + map<K,V>> - : old_iter::base_iter<K> { - - let map: M; - - new(map: M) { - self.map = map; - } - - fn each(blk: &fn(K) -> bool) { self.map.each(|k, _v| blk(k) ) } - fn size_hint() -> Option<uint> { Some(self.map.size()) } - fn eachi(blk: &fn(uint, K) -> bool) { old_iter::eachi(self, blk) } -} - -pub fn main() { - let m = int_hash(); - m.insert(1, 2); - m.insert(3, 4); - assert_eq!(old_iter::to_vec(keys(m)), ~[1, 3]); -} diff --git a/src/test/run-pass/closure-bounds-can-capture-chan.rs b/src/test/run-pass/closure-bounds-can-capture-chan.rs new file mode 100644 index 00000000000..95b0c9d79b7 --- /dev/null +++ b/src/test/run-pass/closure-bounds-can-capture-chan.rs @@ -0,0 +1,23 @@ +// 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. + +use std::comm; + +fn foo(blk: ~fn:Send()) { + blk(); +} + +fn main() { + let (p,c) = comm::stream(); + do foo { + c.send(()); + } + p.recv(); +} diff --git a/src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs b/src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs new file mode 100644 index 00000000000..8c2ae22e8ed --- /dev/null +++ b/src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs @@ -0,0 +1,23 @@ +// 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. + +// Tests correct copying of heap closures' environments. + +fn foo(x: ~fn:Copy()) -> (~fn:(), ~fn:()) { + (copy x, x) +} +fn main() { + let v = ~[~[1,2,3],~[4,5,6]]; // shouldn't get double-freed + let (f1,f2) = do foo { + assert!(v.len() == 2); + }; + f1(); + f2(); +} diff --git a/src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs b/src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs new file mode 100644 index 00000000000..88d474a51e1 --- /dev/null +++ b/src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs @@ -0,0 +1,26 @@ +// 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. + +// Tests correct copying of heap closures' environments. + +fn bar<T: Copy>(x: T) -> (T, T) { + (copy x, x) +} +fn foo(x: ~fn:Copy()) -> (~fn:(), ~fn:()) { + bar(x) +} +fn main() { + let v = ~[~[1,2,3],~[4,5,6]]; // shouldn't get double-freed + let (f1,f2) = do foo { + assert!(v.len() == 2); + }; + f1(); + f2(); +} diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs index 3f12c0d6353..f0c5b58d155 100644 --- a/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs +++ b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs @@ -1,8 +1,6 @@ -// xfail-test - fn sum(x: &[int]) -> int { let mut sum = 0; - for x.each |y| { sum += *y; } + for x.iter().advance |y| { sum += *y; } return sum; } @@ -14,8 +12,10 @@ fn sum_imm(y: &[int]) -> int { sum(y) } +/* FIXME #7304 fn sum_const(y: &const [int]) -> int { sum(y) } +*/ pub fn main() {} diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs index 7ab80920849..590cd825020 100644 --- a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs @@ -1,20 +1,20 @@ -// xfail-test - +/* FIXME #7302 fn foo(v: &const [uint]) -> ~[uint] { - v.to_vec() + v.to_owned() } +*/ fn bar(v: &mut [uint]) -> ~[uint] { - v.to_vec() + v.to_owned() } fn bip(v: &[uint]) -> ~[uint] { - v.to_vec() + v.to_owned() } pub fn main() { - let mut the_vec = ~[1, 2, 3, 100]; - assert_eq!(the_vec, foo(the_vec)); - assert_eq!(the_vec, bar(the_vec)); - assert_eq!(the_vec, bip(the_vec)); + let mut the_vec = ~[1u, 2, 3, 100]; +// assert_eq!(the_vec.clone(), foo(the_vec)); + assert_eq!(the_vec.clone(), bar(the_vec)); + assert_eq!(the_vec.clone(), bip(the_vec)); } diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs index 3d216c1885f..356c1596186 100644 --- a/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs +++ b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs @@ -1,13 +1,11 @@ -use std::vec; - -trait Reverser { - fn reverse(&self); +fn reverse(v: &mut [uint]) { + v.reverse(); } fn bar(v: &mut [uint]) { - vec::reverse(v); - vec::reverse(v); - vec::reverse(v); + reverse(v); + reverse(v); + reverse(v); } pub fn main() { diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs index d62ed77fdab..556d70f3c88 100644 --- a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs @@ -1,15 +1,3 @@ -use std::vec; - -trait Reverser { - fn reverse(self); -} - -impl<'self> Reverser for &'self mut [uint] { - fn reverse(self) { - vec::reverse(self); - } -} - fn bar(v: &mut [uint]) { v.reverse(); v.reverse(); diff --git a/src/test/run-pass/const-bound.rs b/src/test/run-pass/const-bound.rs index 685d86c740d..05f586f76e9 100644 --- a/src/test/run-pass/const-bound.rs +++ b/src/test/run-pass/const-bound.rs @@ -12,7 +12,7 @@ // are const. -fn foo<T:Copy + Const>(x: T) -> T { x } +fn foo<T:Copy + Freeze>(x: T) -> T { x } struct F { field: int } diff --git a/src/test/run-pass/const-vec-of-fns.rs b/src/test/run-pass/const-vec-of-fns.rs index deb1a0769f7..45302363c38 100644 --- a/src/test/run-pass/const-vec-of-fns.rs +++ b/src/test/run-pass/const-vec-of-fns.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test +// FIXME: #7385: hits a codegen bug on OS X x86_64 + /*! * Try to double-check that static fns have the right size (with or * without dummy env ptr, as appropriate) by iterating a size-2 array. @@ -21,6 +24,6 @@ struct S<'self>(&'self fn()); static closures: &'static [S<'static>] = &[S(f), S(f)]; pub fn main() { - for bare_fns.each |&bare_fn| { bare_fn() } - for closures.each |&closure| { (*closure)() } + for bare_fns.iter().advance |&bare_fn| { bare_fn() } + for closures.iter().advance |&closure| { (*closure)() } } diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index 81cdb926e5f..64f9ecc9de2 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -42,12 +42,18 @@ fn test_destroy_actually_kills(force: bool) { #[cfg(windows)] static BLOCK_COMMAND: &'static str = "cmd"; - #[cfg(unix)] + #[cfg(unix,not(target_os="android"))] fn process_exists(pid: libc::pid_t) -> bool { let run::ProcessOutput {output, _} = run::process_output("ps", [~"-p", pid.to_str()]); str::from_bytes(output).contains(pid.to_str()) } + #[cfg(unix,target_os="android")] + fn process_exists(pid: libc::pid_t) -> bool { + let run::ProcessOutput {output, _} = run::process_output("/system/bin/ps", [pid.to_str()]); + str::from_bytes(output).contains(~"root") + } + #[cfg(windows)] fn process_exists(pid: libc::pid_t) -> bool { diff --git a/src/test/run-pass/deriving-cmp-generic-enum.rs b/src/test/run-pass/deriving-cmp-generic-enum.rs index e3cca832b75..e5cf1536771 100644 --- a/src/test/run-pass/deriving-cmp-generic-enum.rs +++ b/src/test/run-pass/deriving-cmp-generic-enum.rs @@ -25,8 +25,8 @@ pub fn main() { // in order for both Ord and TotalOrd let es = [e0, e11, e12, e21, e22]; - for es.eachi |i, e1| { - for es.eachi |j, e2| { + for es.iter().enumerate().advance |(i, e1)| { + for es.iter().enumerate().advance |(j, e2)| { let ord = i.cmp(&j); let eq = i == j; diff --git a/src/test/run-pass/deriving-cmp-generic-struct.rs b/src/test/run-pass/deriving-cmp-generic-struct.rs index 4e49ecb8991..426bfd7eb2f 100644 --- a/src/test/run-pass/deriving-cmp-generic-struct.rs +++ b/src/test/run-pass/deriving-cmp-generic-struct.rs @@ -21,8 +21,8 @@ pub fn main() { // in order for both Ord and TotalOrd let ss = [s1, s2]; - for ss.eachi |i, s1| { - for ss.eachi |j, s2| { + for ss.iter().enumerate().advance |(i, s1)| { + for ss.iter().enumerate().advance |(j, s2)| { let ord = i.cmp(&j); let eq = i == j; diff --git a/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs b/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs index f119b8b1c48..0acebdf05f4 100644 --- a/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs +++ b/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs @@ -19,8 +19,8 @@ pub fn main() { // in order for both Ord and TotalOrd let tss = [ts1, ts2]; - for tss.eachi |i, ts1| { - for tss.eachi |j, ts2| { + for tss.iter().enumerate().advance |(i, ts1)| { + for tss.iter().enumerate().advance |(j, ts2)| { let ord = i.cmp(&j); let eq = i == j; diff --git a/src/test/run-pass/deriving-global.rs b/src/test/run-pass/deriving-global.rs index 3d5bacee71c..7804ce48c70 100644 --- a/src/test/run-pass/deriving-global.rs +++ b/src/test/run-pass/deriving-global.rs @@ -1,4 +1,5 @@ -// xfail-test #7103 `extern mod` does not work on windows +// xfail-fast #7103 `extern mod` does not work on windows +// xfail-pretty - does not converge // Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at diff --git a/src/test/run-pass/deriving-meta-empty-trait-list.rs b/src/test/run-pass/deriving-meta-empty-trait-list.rs index 8e7afffaf0d..955e02d4d2d 100644 --- a/src/test/run-pass/deriving-meta-empty-trait-list.rs +++ b/src/test/run-pass/deriving-meta-empty-trait-list.rs @@ -10,6 +10,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-fast + #[deriving] //~ WARNING empty trait list in `deriving` struct Foo; diff --git a/src/test/run-pass/deriving-to-str.rs b/src/test/run-pass/deriving-to-str.rs index fcf0a009d9b..1fc1d6815f5 100644 --- a/src/test/run-pass/deriving-to-str.rs +++ b/src/test/run-pass/deriving-to-str.rs @@ -1,5 +1,4 @@ -// xfail-fast #6330 -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -9,39 +8,42 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::rand; +#[deriving(ToStr)] +enum A {} +#[deriving(ToStr)] +enum B { B1, B2, B3 } +#[deriving(ToStr)] +enum C { C1(int), C2(B), C3(~str) } +#[deriving(ToStr)] +enum D { D1{ a: int } } +#[deriving(ToStr)] +struct E; +#[deriving(ToStr)] +struct F(int); +#[deriving(ToStr)] +struct G(int, int); +#[deriving(ToStr)] +struct H { a: int } +#[deriving(ToStr)] +struct I { a: int, b: int } +#[deriving(ToStr)] +struct J(Custom); -#[deriving(Rand,ToStr)] -struct A; - -#[deriving(Rand,ToStr)] -struct B(int, int); - -#[deriving(Rand,ToStr)] -struct C { - x: f64, - y: (u8, u8) -} - -#[deriving(Rand,ToStr)] -enum D { - D0, - D1(uint), - D2 { x: (), y: () } +struct Custom; +impl ToStr for Custom { + fn to_str(&self) -> ~str { ~"yay" } } fn main() { - macro_rules! t( - ($ty:ty) => {{ - let x =rand::random::<$ty>(); - assert_eq!(x.to_str(), fmt!("%?", x)); - }} - ); - - for 20.times { - t!(A); - t!(B); - t!(C); - t!(D); - } + assert_eq!(B1.to_str(), ~"B1"); + assert_eq!(B2.to_str(), ~"B2"); + assert_eq!(C1(3).to_str(), ~"C1(3)"); + assert_eq!(C2(B2).to_str(), ~"C2(B2)"); + assert_eq!(D1{ a: 2 }.to_str(), ~"D1{a: 2}"); + assert_eq!(E.to_str(), ~"E"); + assert_eq!(F(3).to_str(), ~"F(3)"); + assert_eq!(G(3, 4).to_str(), ~"G(3, 4)"); + assert_eq!(G(3, 4).to_str(), ~"G(3, 4)"); + assert_eq!(I{ a: 2, b: 4 }.to_str(), ~"I{a: 2, b: 4}"); + assert_eq!(J(Custom).to_str(), ~"J(yay)"); } diff --git a/src/test/run-pass/drop-trait-generic.rs b/src/test/run-pass/drop-trait-generic.rs index 894c387b036..557a153bce2 100644 --- a/src/test/run-pass/drop-trait-generic.rs +++ b/src/test/run-pass/drop-trait-generic.rs @@ -14,7 +14,7 @@ struct S<T> { #[unsafe_destructor] impl<T> ::std::ops::Drop for S<T> { - fn finalize(&self) { + fn drop(&self) { println("bye"); } } diff --git a/src/test/run-pass/drop-trait.rs b/src/test/run-pass/drop-trait.rs index 258a0f88ab5..0ed5a27eb19 100644 --- a/src/test/run-pass/drop-trait.rs +++ b/src/test/run-pass/drop-trait.rs @@ -13,7 +13,7 @@ struct Foo { } impl Drop for Foo { - fn finalize(&self) { + fn drop(&self) { println("bye"); } } diff --git a/src/test/run-pass/explicit-self-closures.rs b/src/test/run-pass/explicit-self-closures.rs index eb62c8a91d2..1b87c16b4b9 100644 --- a/src/test/run-pass/explicit-self-closures.rs +++ b/src/test/run-pass/explicit-self-closures.rs @@ -16,10 +16,10 @@ struct Box { impl Box { pub fn set_many(&mut self, xs: &[uint]) { - for xs.each |x| { self.x = *x; } + for xs.iter().advance |x| { self.x = *x; } } pub fn set_many2(@mut self, xs: &[uint]) { - for xs.each |x| { self.x = *x; } + for xs.iter().advance |x| { self.x = *x; } } } diff --git a/src/test/run-pass/extern-mod-url.rs b/src/test/run-pass/extern-mod-url.rs index 457c61067e3..363c54f6812 100644 --- a/src/test/run-pass/extern-mod-url.rs +++ b/src/test/run-pass/extern-mod-url.rs @@ -10,7 +10,7 @@ // Just a test that new-style extern mods parse -// xfail-test +// xfail-test FIXME #6407 extern mod test = "github.com/catamorphism/test-pkg"; -fn main() {} \ No newline at end of file +fn main() {} diff --git a/src/test/run-pass/extern-pub.rs b/src/test/run-pass/extern-pub.rs index e722c4f5c6a..27c45893930 100644 --- a/src/test/run-pass/extern-pub.rs +++ b/src/test/run-pass/extern-pub.rs @@ -1,7 +1,5 @@ -use std::libc; - extern { - pub unsafe fn debug_get_stk_seg() -> *libc::c_void; + pub unsafe fn free(p: *u8); } pub fn main() { diff --git a/src/test/run-pass/fixed-point-bind-unique.rs b/src/test/run-pass/fixed-point-bind-unique.rs index 53f9c723a47..c7b64fde3fd 100644 --- a/src/test/run-pass/fixed-point-bind-unique.rs +++ b/src/test/run-pass/fixed-point-bind-unique.rs @@ -10,11 +10,11 @@ // xfail-fast -fn fix_help<A:'static,B:Owned>(f: extern fn(@fn(A) -> B, A) -> B, x: A) -> B { +fn fix_help<A:'static,B:Send>(f: extern fn(@fn(A) -> B, A) -> B, x: A) -> B { return f(|a| fix_help(f, a), x); } -fn fix<A:'static,B:Owned>(f: extern fn(@fn(A) -> B, A) -> B) -> @fn(A) -> B { +fn fix<A:'static,B:Send>(f: extern fn(@fn(A) -> B, A) -> B) -> @fn(A) -> B { return |a| fix_help(f, a); } diff --git a/src/test/run-pass/fn-bare-size.rs b/src/test/run-pass/fn-bare-size.rs index dc47dda420c..144cc7c1e28 100644 --- a/src/test/run-pass/fn-bare-size.rs +++ b/src/test/run-pass/fn-bare-size.rs @@ -8,12 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - -extern mod extra; +use std::sys; pub fn main() { // Bare functions should just be a pointer - assert!(sys::rustrt::size_of::<fn()>() == - sys::rustrt::size_of::<int>()); + assert_eq!(sys::size_of::<extern "Rust" fn()>(), sys::size_of::<int>()); } diff --git a/src/test/run-pass/fn-bare-spawn.rs b/src/test/run-pass/fn-bare-spawn.rs index 4f0f451a08c..e9954be9357 100644 --- a/src/test/run-pass/fn-bare-spawn.rs +++ b/src/test/run-pass/fn-bare-spawn.rs @@ -10,7 +10,7 @@ // This is what the signature to spawn should look like with bare functions -fn spawn<T:Owned>(val: T, f: extern fn(T)) { +fn spawn<T:Send>(val: T, f: extern fn(T)) { f(val); } diff --git a/src/test/run-pass/fn-pattern-expected-type-2.rs b/src/test/run-pass/fn-pattern-expected-type-2.rs index ee1e7311024..bb8df4bb33f 100644 --- a/src/test/run-pass/fn-pattern-expected-type-2.rs +++ b/src/test/run-pass/fn-pattern-expected-type-2.rs @@ -10,7 +10,7 @@ pub fn main() { let v : &[(int,int)] = &[ (1, 2), (3, 4), (5, 6) ]; - for v.each |&(x, y)| { + for v.iter().advance |&(x, y)| { println(y.to_str()); println(x.to_str()); } diff --git a/src/test/run-pass/for-destruct.rs b/src/test/run-pass/for-destruct.rs index 4926dbd0086..dd1cda22e65 100644 --- a/src/test/run-pass/for-destruct.rs +++ b/src/test/run-pass/for-destruct.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test: #3511: does not currently compile, due to rvalue issues + use std::vec; struct Pair { x: int, y: int } - pub fn main() { for vec::each(~[Pair {x: 10, y: 20}, Pair {x: 30, y: 0}]) |elt| { assert_eq!(elt.x + elt.y, 30); diff --git a/src/test/run-pass/for-loop-fail.rs b/src/test/run-pass/for-loop-fail.rs index cf69d754f37..bf916dfa2bd 100644 --- a/src/test/run-pass/for-loop-fail.rs +++ b/src/test/run-pass/for-loop-fail.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub fn main() { let x: ~[int] = ~[]; for x.each |_i| { fail!("moop"); } } +pub fn main() { let x: ~[int] = ~[]; for x.iter().advance |_| { fail!("moop"); } } diff --git a/src/test/run-pass/foreign-mod.rc b/src/test/run-pass/foreign-mod.rc index 390de827657..a11e89f37be 100644 --- a/src/test/run-pass/foreign-mod.rc +++ b/src/test/run-pass/foreign-mod.rc @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-test FIXME #7308 // -*- rust -*- native mod libc = target_libc { diff --git a/src/test/run-pass/generic-alias-unique.rs b/src/test/run-pass/generic-alias-unique.rs index ad271186639..815cc1bc79b 100644 --- a/src/test/run-pass/generic-alias-unique.rs +++ b/src/test/run-pass/generic-alias-unique.rs @@ -10,7 +10,7 @@ -fn id<T:Copy + Owned>(t: T) -> T { return t; } +fn id<T:Copy + Send>(t: T) -> T { return t; } pub fn main() { let expected = ~100; diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index eae2f507c51..ecf6546e741 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -31,7 +31,7 @@ mod map_reduce { enum ctrl_proto { find_reducer(~[u8], Chan<int>), mapper_done, } fn start_mappers(ctrl: SharedChan<ctrl_proto>, inputs: ~[~str]) { - for inputs.each |i| { + for inputs.iter().advance |i| { let ctrl = ctrl.clone(); let i = i.clone(); task::spawn(|| map_task(ctrl.clone(), i.clone()) ); diff --git a/src/test/run-pass/init-res-into-things.rs b/src/test/run-pass/init-res-into-things.rs index 5e10419da6e..cad6661bbce 100644 --- a/src/test/run-pass/init-res-into-things.rs +++ b/src/test/run-pass/init-res-into-things.rs @@ -19,7 +19,7 @@ struct Box { x: r } #[unsafe_destructor] impl Drop for r { - fn finalize(&self) { + fn drop(&self) { unsafe { *(self.i) = *(self.i) + 1; } diff --git a/src/test/run-pass/intrinsic-alignment.rs b/src/test/run-pass/intrinsic-alignment.rs index 7a54b87404e..27767db8733 100644 --- a/src/test/run-pass/intrinsic-alignment.rs +++ b/src/test/run-pass/intrinsic-alignment.rs @@ -60,7 +60,7 @@ mod m { pub fn main() { unsafe { assert_eq!(::rusti::pref_align_of::<u64>(), 8u); - assert_eq!(::rusti::min_align_of::<u64>(), 4u); + assert_eq!(::rusti::min_align_of::<u64>(), 8u); } } } diff --git a/src/test/run-pass/issue-1866.rs b/src/test/run-pass/issue-1866.rs index cb5e9b11166..530f40c6a83 100644 --- a/src/test/run-pass/issue-1866.rs +++ b/src/test/run-pass/issue-1866.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-test FIXME #1866 mod a { pub type rust_task = uint; pub mod rustrt { + use super::rust_task; pub extern { pub fn rust_task_is_unwinding(rt: *rust_task) -> bool; } @@ -21,6 +22,7 @@ mod a { mod b { pub type rust_task = bool; pub mod rustrt { + use super::rust_task; pub extern { pub fn rust_task_is_unwinding(rt: *rust_task) -> bool; } diff --git a/src/test/run-pass/issue-2101.rs b/src/test/run-pass/issue-2101.rs deleted file mode 100644 index 423888c1cf5..00000000000 --- a/src/test/run-pass/issue-2101.rs +++ /dev/null @@ -1,30 +0,0 @@ -// 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. - -// xfail-test -extern mod extra; -use extra::arena; -use extra::arena::Arena; - -enum hold { s(str) } - -fn init(ar: &a.arena::Arena, str: str) -> &a.hold { - new(*ar) s(str) -} - -pub fn main(args: ~[str]) { - let ar = arena::Arena(); - let leak = init(&ar, args[0]); - match *leak { - s(astr) { - io::println(fmt!("%?", astr)); - } - }; -} diff --git a/src/test/run-pass/issue-2190-2.rs b/src/test/run-pass/issue-2190-2.rs index 3842e073faf..d5ee712d412 100644 --- a/src/test/run-pass/issue-2190-2.rs +++ b/src/test/run-pass/issue-2190-2.rs @@ -8,23 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-test FIXME #2190 mod a { -fn foo(f: &fn()) { f() } -fn bar() {} -pub fn main() { foo(||bar()); } + fn foo(f: &fn()) { f() } + fn bar() {} + pub fn main() { foo(||bar()); } } mod b { -fn foo(f: Option<&fn()>) { f.iter(|x|x()) } -fn bar() {} -pub fn main() { foo(Some(bar)); } + fn foo(f: Option<&fn()>) { f.iter(|x|x()) } + fn bar() {} + pub fn main() { foo(Some(bar)); } } mod c { -fn foo(f: Option<&fn()>) { f.iter(|x|x()) } -fn bar() {} -pub fn main() { foo(Some(||bar())); } + fn foo(f: Option<&fn()>) { f.iter(|x|x()) } + fn bar() {} + pub fn main() { foo(Some(||bar())); } } pub fn main() { diff --git a/src/test/run-pass/issue-2487-a.rs b/src/test/run-pass/issue-2487-a.rs index 5e5fb70bcd4..0f9f1102aea 100644 --- a/src/test/run-pass/issue-2487-a.rs +++ b/src/test/run-pass/issue-2487-a.rs @@ -14,7 +14,7 @@ struct socket { } impl Drop for socket { - fn finalize(&self) {} + fn drop(&self) {} } impl socket { diff --git a/src/test/run-pass/issue-2611-3.rs b/src/test/run-pass/issue-2611-3.rs index acc6ffd0dd1..7f653552631 100644 --- a/src/test/run-pass/issue-2611-3.rs +++ b/src/test/run-pass/issue-2611-3.rs @@ -12,7 +12,7 @@ // than the traits require. trait A { - fn b<C:Copy + Const,D>(x: C) -> C; + fn b<C:Copy + Freeze,D>(x: C) -> C; } struct E { diff --git a/src/test/run-pass/issue-2611.rs b/src/test/run-pass/issue-2611.rs deleted file mode 100644 index d7508bca41e..00000000000 --- a/src/test/run-pass/issue-2611.rs +++ /dev/null @@ -1,24 +0,0 @@ -// 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. - -use std::old_iter::BaseIter; -use std::old_iter; - -trait FlatMapToVec<A> { - fn flat_map_to_vec<B, IB:BaseIter<B>>(&self, op: &fn(&A) -> IB) -> ~[B]; -} - -impl<A:Copy> FlatMapToVec<A> for ~[A] { - fn flat_map_to_vec<B, IB:BaseIter<B>>(&self, op: &fn(&A) -> IB) -> ~[B] { - old_iter::flat_map_to_vec(self, op) - } -} - -pub fn main() {} diff --git a/src/test/run-pass/issue-2708.rs b/src/test/run-pass/issue-2708.rs index 9e8438efad5..44ace16fb95 100644 --- a/src/test/run-pass/issue-2708.rs +++ b/src/test/run-pass/issue-2708.rs @@ -16,7 +16,7 @@ struct Font { } impl Drop for Font { - fn finalize(&self) {} + fn drop(&self) {} } fn Font() -> Font { diff --git a/src/test/run-pass/issue-2718.rs b/src/test/run-pass/issue-2718.rs index 014aebeff9d..14915555889 100644 --- a/src/test/run-pass/issue-2718.rs +++ b/src/test/run-pass/issue-2718.rs @@ -39,7 +39,7 @@ pub mod pipes { payload: Option<T> } - pub fn packet<T:Owned>() -> *packet<T> { + pub fn packet<T:Send>() -> *packet<T> { unsafe { let p: *packet<T> = cast::transmute(~Stuff{ state: empty, @@ -74,7 +74,7 @@ pub mod pipes { } } - pub fn send<T:Owned>(mut p: send_packet<T>, payload: T) { + pub fn send<T:Send>(mut p: send_packet<T>, payload: T) { let mut p = p.unwrap(); let mut p = unsafe { uniquify(p) }; assert!((*p).payload.is_none()); @@ -100,7 +100,7 @@ pub mod pipes { } } - pub fn recv<T:Owned>(mut p: recv_packet<T>) -> Option<T> { + pub fn recv<T:Send>(mut p: recv_packet<T>) -> Option<T> { let mut p = p.unwrap(); let mut p = unsafe { uniquify(p) }; loop { @@ -120,7 +120,7 @@ pub mod pipes { } } - pub fn sender_terminate<T:Owned>(mut p: *packet<T>) { + pub fn sender_terminate<T:Send>(mut p: *packet<T>) { let mut p = unsafe { uniquify(p) }; match swap_state_rel(&mut (*p).state, terminated) { empty | blocked => { @@ -137,7 +137,7 @@ pub mod pipes { } } - pub fn receiver_terminate<T:Owned>(mut p: *packet<T>) { + pub fn receiver_terminate<T:Send>(mut p: *packet<T>) { let mut p = unsafe { uniquify(p) }; match swap_state_rel(&mut (*p).state, terminated) { empty => { @@ -159,8 +159,8 @@ pub mod pipes { } #[unsafe_destructor] - impl<T:Owned> Drop for send_packet<T> { - fn finalize(&self) { + impl<T:Send> Drop for send_packet<T> { + fn drop(&self) { unsafe { if self.p != None { let self_p: &mut Option<*packet<T>> = @@ -172,13 +172,13 @@ pub mod pipes { } } - impl<T:Owned> send_packet<T> { + impl<T:Send> send_packet<T> { pub fn unwrap(&mut self) -> *packet<T> { util::replace(&mut self.p, None).unwrap() } } - pub fn send_packet<T:Owned>(p: *packet<T>) -> send_packet<T> { + pub fn send_packet<T:Send>(p: *packet<T>) -> send_packet<T> { send_packet { p: Some(p) } @@ -189,8 +189,8 @@ pub mod pipes { } #[unsafe_destructor] - impl<T:Owned> Drop for recv_packet<T> { - fn finalize(&self) { + impl<T:Send> Drop for recv_packet<T> { + fn drop(&self) { unsafe { if self.p != None { let self_p: &mut Option<*packet<T>> = @@ -202,19 +202,19 @@ pub mod pipes { } } - impl<T:Owned> recv_packet<T> { + impl<T:Send> recv_packet<T> { pub fn unwrap(&mut self) -> *packet<T> { util::replace(&mut self.p, None).unwrap() } } - pub fn recv_packet<T:Owned>(p: *packet<T>) -> recv_packet<T> { + pub fn recv_packet<T:Send>(p: *packet<T>) -> recv_packet<T> { recv_packet { p: Some(p) } } - pub fn entangle<T:Owned>() -> (send_packet<T>, recv_packet<T>) { + pub fn entangle<T:Send>() -> (send_packet<T>, recv_packet<T>) { let p = packet(); (send_packet(p), recv_packet(p)) } diff --git a/src/test/run-pass/issue-2735-2.rs b/src/test/run-pass/issue-2735-2.rs index ca584e1a6e3..b44d50921a5 100644 --- a/src/test/run-pass/issue-2735-2.rs +++ b/src/test/run-pass/issue-2735-2.rs @@ -15,7 +15,7 @@ struct defer { #[unsafe_destructor] impl Drop for defer { - fn finalize(&self) { + fn drop(&self) { *self.b = true; } } diff --git a/src/test/run-pass/issue-2735-3.rs b/src/test/run-pass/issue-2735-3.rs index 44ca5d6929b..902b2f69d61 100644 --- a/src/test/run-pass/issue-2735-3.rs +++ b/src/test/run-pass/issue-2735-3.rs @@ -15,7 +15,7 @@ struct defer { #[unsafe_destructor] impl Drop for defer { - fn finalize(&self) { + fn drop(&self) { *self.b = true; } } diff --git a/src/test/run-pass/issue-2834.rs b/src/test/run-pass/issue-2834.rs index 5d3a2d2331c..b0ddccf2894 100644 --- a/src/test/run-pass/issue-2834.rs +++ b/src/test/run-pass/issue-2834.rs @@ -12,7 +12,7 @@ // proto! streamp ( - open:send<T:Owned> { + open:send<T:Send> { data(T) -> open<T> } ) diff --git a/src/test/run-pass/issue-2895.rs b/src/test/run-pass/issue-2895.rs index e6b3f9f6f35..a80a079b695 100644 --- a/src/test/run-pass/issue-2895.rs +++ b/src/test/run-pass/issue-2895.rs @@ -19,7 +19,7 @@ struct Kitty { } impl Drop for Kitty { - fn finalize(&self) {} + fn drop(&self) {} } #[cfg(target_arch = "x86_64")] diff --git a/src/test/run-pass/issue-2904.rs b/src/test/run-pass/issue-2904.rs index 6af19188048..bd4e3f84719 100644 --- a/src/test/run-pass/issue-2904.rs +++ b/src/test/run-pass/issue-2904.rs @@ -73,7 +73,7 @@ fn read_board_grid<rdr:'static + io::Reader>(in: rdr) -> ~[~[square]] { grid.push(row) } let width = grid[0].len(); - for grid.each |row| { assert!(row.len() == width) } + for grid.iter().advance |row| { assert!(row.len() == width) } grid } diff --git a/src/test/run-pass/issue-2930.rs b/src/test/run-pass/issue-2930.rs index cfce19826d7..10a19d62bd9 100644 --- a/src/test/run-pass/issue-2930.rs +++ b/src/test/run-pass/issue-2930.rs @@ -9,7 +9,7 @@ // except according to those terms. proto! stream ( - Stream:send<T:Owned> { + Stream:send<T:Send> { send(T) -> Stream<T> } ) diff --git a/src/test/run-pass/issue-3220.rs b/src/test/run-pass/issue-3220.rs index 9cc5e591043..dce6d8f0bf1 100644 --- a/src/test/run-pass/issue-3220.rs +++ b/src/test/run-pass/issue-3220.rs @@ -11,7 +11,7 @@ struct thing { x: int, } impl Drop for thing { - fn finalize(&self) {} + fn drop(&self) {} } fn thing() -> thing { diff --git a/src/test/run-pass/issue-3290.rs b/src/test/run-pass/issue-3290.rs index 3f8ce032d0d..5cdc4238eaf 100644 --- a/src/test/run-pass/issue-3290.rs +++ b/src/test/run-pass/issue-3290.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-test FIXME #3290 fn main() { let mut x = ~3; x = x; diff --git a/src/test/run-pass/issue-3389.rs b/src/test/run-pass/issue-3389.rs index d9919b1695d..8dcf4ed4a48 100644 --- a/src/test/run-pass/issue-3389.rs +++ b/src/test/run-pass/issue-3389.rs @@ -14,7 +14,7 @@ struct trie_node { } fn print_str_vector(vector: ~[~str]) { - for vector.each() |string| { + for vector.iter().advance |string| { println(*string); } } diff --git a/src/test/run-pass/issue-3563-2.rs b/src/test/run-pass/issue-3563-2.rs index 52d6792f401..7d0ba866faf 100644 --- a/src/test/run-pass/issue-3563-2.rs +++ b/src/test/run-pass/issue-3563-2.rs @@ -12,7 +12,7 @@ trait Canvas { fn add_point(&self, point: &int); fn add_points(&self, shapes: &[int]) { - for shapes.each |pt| { + for shapes.iter().advance |pt| { self.add_point(pt) } } diff --git a/src/test/run-pass/issue-3563-3.rs b/src/test/run-pass/issue-3563-3.rs index 36872560716..a24800e4dbb 100644 --- a/src/test/run-pass/issue-3563-3.rs +++ b/src/test/run-pass/issue-3563-3.rs @@ -34,14 +34,12 @@ struct Point { // Represents an offset on a canvas. (This has the same structure as a Point. // but different semantics). -struct Size -{ +struct Size { width: int, height: int, } -struct Rect -{ +struct Rect { top_left: Point, size: Size, } @@ -49,8 +47,7 @@ struct Rect // TODO: operators // Contains the information needed to do shape rendering via ASCII art. -struct AsciiArt -{ +struct AsciiArt { width: uint, height: uint, priv fill: char, @@ -61,24 +58,18 @@ struct AsciiArt } impl Drop for AsciiArt { - fn finalize(&self) {} + fn drop(&self) {} } // It's common to define a constructor sort of function to create struct instances. // If there is a canonical constructor it is typically named the same as the type. // Other constructor sort of functions are typically named from_foo, from_bar, etc. -fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt -{ +fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt { // Use an anonymous function to build a vector of vectors containing // blank characters for each position in our canvas. - let mut lines = do vec::build_sized(height) - |push| - { - for height.times - { - let mut line = ~[]; - vec::grow_set(&mut line, width-1, &'.', '.'); - push(line); + let mut lines = do vec::build_sized(height) |push| { + for height.times { + push(vec::from_elem(width, '.')); } }; @@ -88,14 +79,10 @@ fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt } // Methods particular to the AsciiArt struct. -impl AsciiArt -{ - fn add_pt(&mut self, x: int, y: int) - { - if x >= 0 && x < self.width as int - { - if y >= 0 && y < self.height as int - { +impl AsciiArt { + fn add_pt(&mut self, x: int, y: int) { + if x >= 0 && x < self.width as int { + if y >= 0 && y < self.height as int { // Note that numeric types don't implicitly convert to each other. let v = y as uint; let h = x as uint; @@ -127,16 +114,14 @@ impl ToStr for AsciiArt { // This is similar to an interface in other languages: it defines a protocol which // developers can implement for arbitrary concrete types. #[allow(default_methods)] -trait Canvas -{ +trait Canvas { fn add_point(&mut self, shape: Point); fn add_rect(&mut self, shape: Rect); // Unlike interfaces traits support default implementations. // Got an ICE as soon as I added this method. - fn add_points(&mut self, shapes: &[Point]) - { - for shapes.each |pt| {self.add_point(*pt)}; + fn add_points(&mut self, shapes: &[Point]) { + for shapes.iter().advance |pt| {self.add_point(*pt)}; } } @@ -144,25 +129,19 @@ trait Canvas // Other implementations could also be provided (e.g. for PDF or Apple's Quartz) // and code can use them polymorphically via the Canvas trait. impl Canvas for AsciiArt { - fn add_point(&mut self, shape: Point) - { + fn add_point(&mut self, shape: Point) { self.add_pt(shape.x, shape.y); } - fn add_rect(&mut self, shape: Rect) - { + fn add_rect(&mut self, shape: Rect) { // Add the top and bottom lines. - for int::range(shape.top_left.x, shape.top_left.x + shape.size.width) - |x| - { + for int::range(shape.top_left.x, shape.top_left.x + shape.size.width) |x| { self.add_pt(x, shape.top_left.y); self.add_pt(x, shape.top_left.y + shape.size.height - 1); } // Add the left and right lines. - for int::range(shape.top_left.y, shape.top_left.y + shape.size.height) - |y| - { + for int::range(shape.top_left.y, shape.top_left.y + shape.size.height) |y|{ self.add_pt(shape.top_left.x, y); self.add_pt(shape.top_left.x + shape.size.width - 1, y); } @@ -171,10 +150,8 @@ impl Canvas for AsciiArt { // Rust's unit testing framework is currently a bit under-developed so we'll use // this little helper. -pub fn check_strs(actual: &str, expected: &str) -> bool -{ - if actual != expected - { +pub fn check_strs(actual: &str, expected: &str) -> bool { + if actual != expected { io::stderr().write_line(fmt!("Found:\n%s\nbut expected\n%s", actual, expected)); return false; } @@ -182,15 +159,13 @@ pub fn check_strs(actual: &str, expected: &str) -> bool } -fn test_ascii_art_ctor() -{ +fn test_ascii_art_ctor() { let art = AsciiArt(3, 3, '*'); assert!(check_strs(art.to_str(), "...\n...\n...")); } -fn test_add_pt() -{ +fn test_add_pt() { let mut art = AsciiArt(3, 3, '*'); art.add_pt(0, 0); art.add_pt(0, -10); @@ -199,8 +174,7 @@ fn test_add_pt() } -fn test_shapes() -{ +fn test_shapes() { let mut art = AsciiArt(4, 4, '*'); art.add_rect(Rect {top_left: Point {x: 0, y: 0}, size: Size {width: 4, height: 4}}); art.add_point(Point {x: 2, y: 2}); diff --git a/src/test/run-pass/issue-3796.rs b/src/test/run-pass/issue-3796.rs index 0091c096255..5f440939139 100644 --- a/src/test/run-pass/issue-3796.rs +++ b/src/test/run-pass/issue-3796.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-test FIXME #3796 #[deny(dead_assignment)]; fn main() { let mut x = 1; diff --git a/src/test/run-pass/issue-3874.rs b/src/test/run-pass/issue-3874.rs index f54d2f9fafc..e293e40ac69 100644 --- a/src/test/run-pass/issue-3874.rs +++ b/src/test/run-pass/issue-3874.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-test FIXME #3874 enum PureCounter { PureCounter(uint) } fn each(self: PureCounter, blk: &fn(v: &uint)) { diff --git a/src/test/run-pass/issue-3888-2.rs b/src/test/run-pass/issue-3888-2.rs index 60c50624435..c9f6733fa25 100644 --- a/src/test/run-pass/issue-3888-2.rs +++ b/src/test/run-pass/issue-3888-2.rs @@ -8,12 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::vec; - fn vec_peek<'r, T>(v: &'r [T]) -> &'r [T] { -// This doesn't work, and should. -// v.slice(1, 5) - vec::slice(v, 1, 5) + v.slice(1, 5) } pub fn main() {} diff --git a/src/test/run-pass/issue-3979-2.rs b/src/test/run-pass/issue-3979-2.rs index a04e3510802..9a8b90db185 100644 --- a/src/test/run-pass/issue-3979-2.rs +++ b/src/test/run-pass/issue-3979-2.rs @@ -9,16 +9,17 @@ // except according to those terms. // xfail-test + trait A { - fn a_method(); + fn a_method(&self); } trait B: A { - fn b_method(); + fn b_method(&self); } trait C: B { - fn c_method() { + fn c_method(&self) { self.a_method(); } } diff --git a/src/test/run-pass/issue-3979-generics.rs b/src/test/run-pass/issue-3979-generics.rs index b91ec5711cf..5884a35a1a1 100644 --- a/src/test/run-pass/issue-3979-generics.rs +++ b/src/test/run-pass/issue-3979-generics.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-test FIXME #5946 trait Positioned<S> { fn SetX(&mut self, S); fn X(&self) -> S; diff --git a/src/test/run-pass/issue-4241.rs b/src/test/run-pass/issue-4241.rs index 23e5f3945b1..5b668d710dd 100644 --- a/src/test/run-pass/issue-4241.rs +++ b/src/test/run-pass/issue-4241.rs @@ -8,11 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-fast + extern mod extra; use extra::net::tcp::TcpSocketBuf; +use std::io; +use std::int; + use std::io::{ReaderUtil,WriterUtil}; enum Result { @@ -97,9 +101,9 @@ priv fn cmd_to_str(cmd: ~[~str]) -> ~str { let mut res = ~"*"; res.push_str(cmd.len().to_str()); res.push_str("\r\n"); - for cmd.each |s| { + for cmd.iter().advance |s| { res.push_str([~"$", s.len().to_str(), ~"\r\n", - copy *s, ~"\r\n"].concat())); + copy *s, ~"\r\n"].concat() ); } res } diff --git a/src/test/run-pass/issue-4252.rs b/src/test/run-pass/issue-4252.rs index f3b73c84714..de1f630a245 100644 --- a/src/test/run-pass/issue-4252.rs +++ b/src/test/run-pass/issue-4252.rs @@ -26,7 +26,7 @@ impl X for Y { } impl<T: X> Drop for Z<T> { - fn finalize(&self) { + fn drop(&self) { self.x.call(); // Adding this statement causes an ICE. } } diff --git a/src/test/run-pass/issue-4446.rs b/src/test/run-pass/issue-4446.rs new file mode 100644 index 00000000000..2f44f9783e1 --- /dev/null +++ b/src/test/run-pass/issue-4446.rs @@ -0,0 +1,21 @@ +// 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. + +use std::{pipes, io, task, comm}; + +fn main() { + let (port, chan) = comm::stream(); + + do task::spawn { + io::println(port.recv()); + } + + chan.send("hello, world"); +} diff --git a/src/test/run-pass/issue-4541.rs b/src/test/run-pass/issue-4541.rs index 24a8adfcb1a..7b80974313e 100644 --- a/src/test/run-pass/issue-4541.rs +++ b/src/test/run-pass/issue-4541.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +use std::io; + fn parse_args() -> ~str { - let args = std::os::args(); + let args = ::std::os::args(); let mut n = 0; while n < args.len() { diff --git a/src/test/run-pass/issue-4542.rs b/src/test/run-pass/issue-4542.rs index a5e5b10d076..4aa83b853de 100644 --- a/src/test/run-pass/issue-4542.rs +++ b/src/test/run-pass/issue-4542.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +use std::os; + pub fn main() { - for os::args().each |arg| { + let x = os::args(); + for x.iter().advance |arg| { match arg.clone() { s => { } } diff --git a/src/test/run-pass/issue-4735.rs b/src/test/run-pass/issue-4735.rs index 057622d2251..3da90ba1edc 100644 --- a/src/test/run-pass/issue-4735.rs +++ b/src/test/run-pass/issue-4735.rs @@ -15,7 +15,7 @@ use std::libc::c_void; struct NonCopyable(*c_void); impl Drop for NonCopyable { - fn finalize(&self) { + fn drop(&self) { let p = **self; let v = unsafe { transmute::<*c_void, ~int>(p) }; } diff --git a/src/test/run-pass/issue-5060.rs b/src/test/run-pass/issue-5060.rs new file mode 100644 index 00000000000..0922f555bea --- /dev/null +++ b/src/test/run-pass/issue-5060.rs @@ -0,0 +1,28 @@ +// 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. + +use std::io; + +macro_rules! print_hd_tl ( + ($field_hd:ident, $($field_tl:ident),+) => ({ + io::print(stringify!($field_hd)); + io::print("::["); + $( + io::print(stringify!($field_tl)); + io::print(", "); + )+ + io::print("]\n"); + }) +) + +fn main() { + print_hd_tl!(x, y, z, w) +} + diff --git a/src/test/run-pass/issue-5192.rs b/src/test/run-pass/issue-5192.rs new file mode 100644 index 00000000000..d5a1a779d45 --- /dev/null +++ b/src/test/run-pass/issue-5192.rs @@ -0,0 +1,44 @@ +// 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. + +pub trait EventLoop { +} + +pub struct UvEventLoop { + uvio: int +} + +impl UvEventLoop { + pub fn new() -> UvEventLoop { + UvEventLoop { + uvio: 0 + } + } +} + +impl EventLoop for UvEventLoop { +} + +pub struct Scheduler { + event_loop: ~EventLoop, +} + +impl Scheduler { + + pub fn new(event_loop: ~EventLoop) -> Scheduler { + Scheduler { + event_loop: event_loop, + } + } +} + +fn main() { + let mut sched = Scheduler::new(~UvEventLoop::new() as ~EventLoop); +} diff --git a/src/test/run-pass/issue-5280.rs b/src/test/run-pass/issue-5280.rs new file mode 100644 index 00000000000..72bf0cee05d --- /dev/null +++ b/src/test/run-pass/issue-5280.rs @@ -0,0 +1,27 @@ +// 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. + +// xfail-test + +type FontTableTag = u32; + +trait FontTableTagConversions { + fn tag_to_str(self); +} + +impl FontTableTagConversions for FontTableTag { + fn tag_to_str(self) { + &self; + } +} + +fn main() { + 5.tag_to_str(); +} diff --git a/src/test/run-pass/issue-5321-immediates-with-bare-self.rs b/src/test/run-pass/issue-5321-immediates-with-bare-self.rs new file mode 100644 index 00000000000..7b809c39cb8 --- /dev/null +++ b/src/test/run-pass/issue-5321-immediates-with-bare-self.rs @@ -0,0 +1,25 @@ +// 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. + +trait Fooable { + fn yes(self); +} + +impl Fooable for uint { + fn yes(self) { + for self.times { + println("yes"); + } + } +} + +fn main() { + 2.yes(); +} diff --git a/src/test/run-pass/issue-6341.rs b/src/test/run-pass/issue-6341.rs index 394345556fc..29fc0744305 100644 --- a/src/test/run-pass/issue-6341.rs +++ b/src/test/run-pass/issue-6341.rs @@ -12,7 +12,7 @@ struct A { x: uint } impl Drop for A { - fn finalize(&self) {} + fn drop(&self) {} } fn main() {} \ No newline at end of file diff --git a/src/test/run-pass/issue-6344-let.rs b/src/test/run-pass/issue-6344-let.rs index 916131b6b71..bb0c71d6d55 100644 --- a/src/test/run-pass/issue-6344-let.rs +++ b/src/test/run-pass/issue-6344-let.rs @@ -11,7 +11,7 @@ struct A { x: uint } impl Drop for A { - fn finalize(&self) {} + fn drop(&self) {} } fn main() { diff --git a/src/test/run-pass/issue-6344-match.rs b/src/test/run-pass/issue-6344-match.rs index 5bf57aa7116..7987f9689fa 100644 --- a/src/test/run-pass/issue-6344-match.rs +++ b/src/test/run-pass/issue-6344-match.rs @@ -10,7 +10,7 @@ struct A { x: uint } impl Drop for A { - fn finalize(&self) {} + fn drop(&self) {} } fn main() { diff --git a/src/test/run-pass/issue-979.rs b/src/test/run-pass/issue-979.rs index 20bb8ea965b..34a9055ae83 100644 --- a/src/test/run-pass/issue-979.rs +++ b/src/test/run-pass/issue-979.rs @@ -14,7 +14,7 @@ struct r { #[unsafe_destructor] impl Drop for r { - fn finalize(&self) { + fn drop(&self) { unsafe { *(self.b) += 1; } diff --git a/src/test/run-pass/issue_3882.rs b/src/test/run-pass/issue_3882.rs index 7b1af0d151f..202385681ce 100644 --- a/src/test/run-pass/issue_3882.rs +++ b/src/test/run-pass/issue_3882.rs @@ -1,5 +1,3 @@ -// xfail-test - // 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. @@ -10,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test // aux-build:issue_3882.rc extern mod linenoise; use linenoise::issue_3882::*; diff --git a/src/test/run-pass/istr.rs b/src/test/run-pass/istr.rs index a82b2639449..ab89a357d34 100644 --- a/src/test/run-pass/istr.rs +++ b/src/test/run-pass/istr.rs @@ -44,19 +44,19 @@ fn test_heap_add() { fn test_append() { let mut s = ~""; - s += ~"a"; + s.push_str(~"a"); assert_eq!(s, ~"a"); let mut s = ~"a"; - s += ~"b"; + s.push_str(~"b"); debug!(s.clone()); assert_eq!(s, ~"ab"); let mut s = ~"c"; - s += ~"offee"; + s.push_str(~"offee"); assert!(s == ~"coffee"); - s += ~"&tea"; + s.push_str(~"&tea"); assert!(s == ~"coffee&tea"); } diff --git a/src/test/run-pass/kindck-owned-trait-contains-1.rs b/src/test/run-pass/kindck-owned-trait-contains-1.rs index c51094d26c8..e733400527b 100644 --- a/src/test/run-pass/kindck-owned-trait-contains-1.rs +++ b/src/test/run-pass/kindck-owned-trait-contains-1.rs @@ -14,9 +14,9 @@ impl<A:Copy> repeat<A> for @A { fn get(&self) -> A { copy **self } } -fn repeater<A:Copy>(v: @A) -> @repeat<A> { +fn repeater<A:Copy>(v: @A) -> @repeat:<A> { // Note: owned kind is not necessary as A appears in the trait type - @v as @repeat<A> // No + @v as @repeat:<A> // No } pub fn main() { diff --git a/src/test/run-pass/labeled-break.rs b/src/test/run-pass/labeled-break.rs index 32cd7f0c7f8..b6b6e0e1437 100644 --- a/src/test/run-pass/labeled-break.rs +++ b/src/test/run-pass/labeled-break.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-fast -// xfail-test - pub fn main() { 'foo: loop { loop { diff --git a/src/test/run-pass/let-destruct-fresh-mem.rs b/src/test/run-pass/let-destruct-fresh-mem.rs index 500502320df..2615396653d 100644 --- a/src/test/run-pass/let-destruct-fresh-mem.rs +++ b/src/test/run-pass/let-destruct-fresh-mem.rs @@ -13,7 +13,9 @@ struct A { a: int } pub fn main() { let u = X {x: 10, y: @A {a: 20}}; - let mut X {x: x, y: @A {a: a}} = u; + let X {x: x, y: @A {a: a}} = u; + let mut x = x; + let mut a = a; x = 100; a = 100; assert_eq!(x, 100); diff --git a/src/test/run-pass/linear-for-loop.rs b/src/test/run-pass/linear-for-loop.rs index 6d157b38a3f..71b87b3311b 100644 --- a/src/test/run-pass/linear-for-loop.rs +++ b/src/test/run-pass/linear-for-loop.rs @@ -11,7 +11,7 @@ pub fn main() { let x = ~[1, 2, 3]; let mut y = 0; - for x.each |i| { debug!(*i); y += *i; } + for x.iter().advance |i| { debug!(*i); y += *i; } debug!(y); assert_eq!(y, 6); let s = ~"hello there"; diff --git a/src/test/run-pass/liveness-move-in-loop.rs b/src/test/run-pass/liveness-move-in-loop.rs index acdf388a8ff..d910ac9a4e7 100644 --- a/src/test/run-pass/liveness-move-in-loop.rs +++ b/src/test/run-pass/liveness-move-in-loop.rs @@ -15,7 +15,7 @@ fn the_loop() { loop { let x = 5; if x > 3 { - list += ~[take(x)]; + list.push(take(x)); } else { break; } diff --git a/src/test/run-pass/loop-scope.rs b/src/test/run-pass/loop-scope.rs index 07be3bd6c81..aec16e2d47b 100644 --- a/src/test/run-pass/loop-scope.rs +++ b/src/test/run-pass/loop-scope.rs @@ -11,6 +11,6 @@ pub fn main() { let x = ~[10, 20, 30]; let mut sum = 0; - for x.each |x| { sum += *x; } + for x.iter().advance |x| { sum += *x; } assert_eq!(sum, 60); } diff --git a/src/test/run-pass/match-borrowed_str.rs b/src/test/run-pass/match-borrowed_str.rs index 1a58174a3fb..7a30f5152d0 100644 --- a/src/test/run-pass/match-borrowed_str.rs +++ b/src/test/run-pass/match-borrowed_str.rs @@ -1,53 +1,60 @@ -// xfail-test -// xfail-fast -// -*- rust -*- -fn f1(ref_string: &str) { +// 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. + +fn f1(ref_string: &str) -> ~str { match ref_string { - "a" => io::println("found a"), - "b" => io::println("found b"), - _ => io::println("not found") + "a" => ~"found a", + "b" => ~"found b", + _ => ~"not found" } } -fn f2(ref_string: &str) { +fn f2(ref_string: &str) -> ~str { match ref_string { - "a" => io::println("found a"), - "b" => io::println("found b"), - s => io::println(fmt!("not found (%s)", s)) + "a" => ~"found a", + "b" => ~"found b", + s => fmt!("not found (%s)", s) } } -fn g1(ref_1: &str, ref_2: &str) { +fn g1(ref_1: &str, ref_2: &str) -> ~str { match (ref_1, ref_2) { - ("a", "b") => io::println("found a,b"), - ("b", "c") => io::println("found b,c"), - _ => io::println("not found") + ("a", "b") => ~"found a,b", + ("b", "c") => ~"found b,c", + _ => ~"not found" } } -fn g2(ref_1: &str, ref_2: &str) { +fn g2(ref_1: &str, ref_2: &str) -> ~str { match (ref_1, ref_2) { - ("a", "b") => io::println("found a,b"), - ("b", "c") => io::println("found b,c"), - (s1, s2) => io::println(fmt!("not found (%s, %s)", s1, s2)) + ("a", "b") => ~"found a,b", + ("b", "c") => ~"found b,c", + (s1, s2) => fmt!("not found (%s, %s)", s1, s2) } } pub fn main() { - f1(@"a"); - f1(~"b"); - f1(&"c"); - f1("d"); - f2(@"a"); - f2(~"b"); - f2(&"c"); - f2("d"); - g1(@"a", @"b"); - g1(~"b", ~"c"); - g1(&"c", &"d"); - g1("d", "e"); - g2(@"a", @"b"); - g2(~"b", ~"c"); - g2(&"c", &"d"); - g2("d", "e"); + assert_eq!(f1(@"a"), ~"found a"); + assert_eq!(f1(~"b"), ~"found b"); + assert_eq!(f1(&"c"), ~"not found"); + assert_eq!(f1("d"), ~"not found"); + assert_eq!(f2(@"a"), ~"found a"); + assert_eq!(f2(~"b"), ~"found b"); + assert_eq!(f2(&"c"), ~"not found (c)"); + assert_eq!(f2("d"), ~"not found (d)"); + assert_eq!(g1(@"a", @"b"), ~"found a,b"); + assert_eq!(g1(~"b", ~"c"), ~"found b,c"); + assert_eq!(g1(&"c", &"d"), ~"not found"); + assert_eq!(g1("d", "e"), ~"not found"); + assert_eq!(g2(@"a", @"b"), ~"found a,b"); + assert_eq!(g2(~"b", ~"c"), ~"found b,c"); + assert_eq!(g2(&"c", &"d"), ~"not found (c, d)"); + assert_eq!(g2("d", "e"), ~"not found (d, e)"); } diff --git a/src/test/run-pass/match-join.rs b/src/test/run-pass/match-join.rs index 66b64768060..5ac62bae392 100644 --- a/src/test/run-pass/match-join.rs +++ b/src/test/run-pass/match-join.rs @@ -23,7 +23,7 @@ fn foo<T>(y: Option<T>) { None::<T> => x = 17, _ => x = 42 } - rs += ~[x]; + rs.push(x); } return; } diff --git a/src/test/run-pass/monad.rs b/src/test/run-pass/monad.rs index 69545238db4..fe06c973dbf 100644 --- a/src/test/run-pass/monad.rs +++ b/src/test/run-pass/monad.rs @@ -19,7 +19,9 @@ trait vec_monad<A> { impl<A> vec_monad<A> for ~[A] { fn bind<B:Copy>(&self, f: &fn(&A) -> ~[B]) -> ~[B] { let mut r = ~[]; - for self.each |elt| { r += f(elt); } + for self.iter().advance |elt| { + r.push_all_move(f(elt)); + } r } } diff --git a/src/test/run-pass/morestack6.rs b/src/test/run-pass/morestack6.rs index 0e0bf2a13e1..a46b7a3dfcf 100644 --- a/src/test/run-pass/morestack6.rs +++ b/src/test/run-pass/morestack6.rs @@ -65,7 +65,7 @@ pub fn main() { calllink10 ]; let mut rng = rand::rng(); - for fns.each |f| { + for fns.iter().advance |f| { let f = *f; let sz = rng.next() % 256u32 + 256u32; let frame_backoff = rng.next() % 10u32 + 1u32; diff --git a/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs b/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs index 06d3736849d..b0ce6556cb6 100644 --- a/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs +++ b/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs @@ -17,7 +17,7 @@ fn test1() { fn test2() { let mut ints = [0, ..32]; for ints.mut_iter().advance |i| { *i += 22; } - for ints.each |i| { assert!(*i == 22); } + for ints.iter().advance |i| { assert!(*i == 22); } } pub fn main() { diff --git a/src/test/run-pass/mutable-alias-vec.rs b/src/test/run-pass/mutable-alias-vec.rs index 1d9e7d3c649..538aedcf7c8 100644 --- a/src/test/run-pass/mutable-alias-vec.rs +++ b/src/test/run-pass/mutable-alias-vec.rs @@ -13,7 +13,9 @@ extern mod extra; use std::vec; -fn grow(v: &mut ~[int]) { *v += ~[1]; } +fn grow(v: &mut ~[int]) { + v.push(1); +} pub fn main() { let mut v: ~[int] = ~[]; diff --git a/src/test/run-pass/newlambdas-ret-infer2.rs b/src/test/run-pass/newlambdas-ret-infer2.rs index 4b580e7fa79..4dfe3575eb5 100644 --- a/src/test/run-pass/newlambdas-ret-infer2.rs +++ b/src/test/run-pass/newlambdas-ret-infer2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test ~fn is not inferred // Test that the lambda kind is inferred correctly as a return // expression diff --git a/src/test/run-pass/newtype-struct-drop-run.rs b/src/test/run-pass/newtype-struct-drop-run.rs index dd5da3b09bb..b7fdfabff9a 100644 --- a/src/test/run-pass/newtype-struct-drop-run.rs +++ b/src/test/run-pass/newtype-struct-drop-run.rs @@ -14,7 +14,7 @@ struct Foo(@mut int); #[unsafe_destructor] impl Drop for Foo { - fn finalize(&self) { + fn drop(&self) { ***self = 23; } } diff --git a/src/test/run-pass/newtype-struct-with-dtor.rs b/src/test/run-pass/newtype-struct-with-dtor.rs index 0e36f27aa92..6062f3075e2 100644 --- a/src/test/run-pass/newtype-struct-with-dtor.rs +++ b/src/test/run-pass/newtype-struct-with-dtor.rs @@ -4,7 +4,7 @@ use std::libc; pub struct Fd(c_int); impl Drop for Fd { - fn finalize(&self) { + fn drop(&self) { unsafe { libc::close(**self); } diff --git a/src/test/run-pass/once-move-out-on-heap.rs b/src/test/run-pass/once-move-out-on-heap.rs new file mode 100644 index 00000000000..38b23fd128d --- /dev/null +++ b/src/test/run-pass/once-move-out-on-heap.rs @@ -0,0 +1,29 @@ +// 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. + +// Testing guarantees provided by once functions. + +// xfail-fast + +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: ~once fn()) { + blk(); +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); + } +} diff --git a/src/test/run-pass/once-move-out-on-stack.rs b/src/test/run-pass/once-move-out-on-stack.rs new file mode 100644 index 00000000000..e881f576673 --- /dev/null +++ b/src/test/run-pass/once-move-out-on-stack.rs @@ -0,0 +1,30 @@ +// 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. + +// Testing guarantees provided by once functions. + +// xfail-fast + +// compile-flags:-Z once-fns +extern mod extra; +use extra::arc; +use std::util; + +fn foo(blk: &once fn()) { + blk(); +} + +fn main() { + let x = arc::ARC(true); + do foo { + assert!(*x.get()); + util::ignore(x); + } +} diff --git a/src/test/run-pass/operator-overloading.rs b/src/test/run-pass/operator-overloading.rs index e75af5729d5..05aa1e74608 100644 --- a/src/test/run-pass/operator-overloading.rs +++ b/src/test/run-pass/operator-overloading.rs @@ -57,7 +57,7 @@ impl cmp::Eq for Point { pub fn main() { let mut p = Point {x: 10, y: 20}; - p += Point {x: 101, y: 102}; + p = p + Point {x: 101, y: 102}; p = p - Point {x: 100, y: 100}; assert_eq!(p + Point {x: 5, y: 5}, Point {x: 16, y: 27}); assert_eq!(-p, Point {x: -11, y: -22}); diff --git a/src/test/run-pass/option-unwrap.rs b/src/test/run-pass/option-unwrap.rs index ea8a6f236cd..5c8cfd68240 100644 --- a/src/test/run-pass/option-unwrap.rs +++ b/src/test/run-pass/option-unwrap.rs @@ -15,7 +15,7 @@ struct dtor { #[unsafe_destructor] impl Drop for dtor { - fn finalize(&self) { + fn drop(&self) { // abuse access to shared mutable state to write this code unsafe { *self.x -= 1; diff --git a/src/test/run-pass/overload-index-operator.rs b/src/test/run-pass/overload-index-operator.rs index 1838cfe2519..b995e9c9ed2 100644 --- a/src/test/run-pass/overload-index-operator.rs +++ b/src/test/run-pass/overload-index-operator.rs @@ -30,7 +30,7 @@ impl<K,V> AssociationList<K,V> { impl<K:Eq,V:Copy> Index<K,V> for AssociationList<K,V> { fn index(&self, index: &K) -> V { - for self.pairs.each |pair| { + for self.pairs.iter().advance |pair| { if pair.key == *index { return copy pair.value; } diff --git a/src/test/run-pass/owned-trait-objects.rs b/src/test/run-pass/owned-trait-objects.rs new file mode 100644 index 00000000000..50b6666a20b --- /dev/null +++ b/src/test/run-pass/owned-trait-objects.rs @@ -0,0 +1,37 @@ +// 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. + +use std::uint::{range}; + +trait FooTrait { + fn foo(&self) -> uint; +} + +struct BarStruct { + x: uint +} + +impl FooTrait for BarStruct { + fn foo(&self) -> uint { + self.x + } +} + +pub fn main() { + let foos: ~[ ~FooTrait ] = ~[ + ~BarStruct{ x: 0 } as ~FooTrait, + ~BarStruct{ x: 1 } as ~FooTrait, + ~BarStruct{ x: 2 } as ~FooTrait + ]; + + for range(0, foos.len()) |i| { + assert_eq!(i, foos[i].foo()); + } +} diff --git a/src/test/run-pass/packed-struct-vec.rs b/src/test/run-pass/packed-struct-vec.rs index 1f3d4c26bd2..de34d589afc 100644 --- a/src/test/run-pass/packed-struct-vec.rs +++ b/src/test/run-pass/packed-struct-vec.rs @@ -27,7 +27,7 @@ fn main() { assert_eq!(foos[i], Foo { bar: 1, baz: 2}); } - for foos.each |&foo| { + for foos.iter().advance |&foo| { assert_eq!(foo, Foo { bar: 1, baz: 2 }); } } diff --git a/src/test/run-pass/pipe-bank-proto.rs b/src/test/run-pass/pipe-bank-proto.rs index 7ac38966faa..11c43b93901 100644 --- a/src/test/run-pass/pipe-bank-proto.rs +++ b/src/test/run-pass/pipe-bank-proto.rs @@ -45,8 +45,8 @@ proto! bank ( } ) -fn switch<T:Owned,U>(endp: pipes::RecvPacket<T>, - f: &fn(v: Option<T>) -> U) -> U { +fn switch<T:Send,U>(endp: pipes::RecvPacket<T>, + f: &fn(v: Option<T>) -> U) -> U { f(pipes::try_recv(endp)) } diff --git a/src/test/run-pass/pipe-peek.rs b/src/test/run-pass/pipe-peek.rs index 8d8c96c6f51..cbc822060ce 100644 --- a/src/test/run-pass/pipe-peek.rs +++ b/src/test/run-pass/pipe-peek.rs @@ -22,7 +22,9 @@ proto! oneshot ( ) pub fn main() { - let mut (p, c) = oneshot::init(); + let (p, c) = oneshot::init(); + let mut p = p; + let mut c = c; assert!(!pipes::peek(&mut p)); diff --git a/src/test/run-pass/pipe-presentation-examples.rs b/src/test/run-pass/pipe-presentation-examples.rs index 54cf8ba9c0a..65e0537dfb7 100644 --- a/src/test/run-pass/pipe-presentation-examples.rs +++ b/src/test/run-pass/pipe-presentation-examples.rs @@ -85,7 +85,7 @@ pub struct Buffer { } impl Drop for Buffer { - fn finalize(&self) {} + fn drop(&self) {} } proto! double_buffer ( diff --git a/src/test/run-pass/pipe-select-macro.rs b/src/test/run-pass/pipe-select-macro.rs index a77e6acbb25..2db66054145 100644 --- a/src/test/run-pass/pipe-select-macro.rs +++ b/src/test/run-pass/pipe-select-macro.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// FIXME #7303: xfail-test // Protocols proto! foo ( diff --git a/src/test/run-pass/pipe-select.rs b/src/test/run-pass/pipe-select.rs index 0a860d0a1e2..36f144152f2 100644 --- a/src/test/run-pass/pipe-select.rs +++ b/src/test/run-pass/pipe-select.rs @@ -29,12 +29,12 @@ proto! oneshot ( ) proto! stream ( - Stream:send<T:Owned> { + Stream:send<T:Send> { send(T) -> Stream<T> } ) -pub fn spawn_service<T:Owned,Tb:Owned>( +pub fn spawn_service<T:Send,Tb:Send>( init: extern fn() -> (RecvPacketBuffered<T, Tb>, SendPacketBuffered<T, Tb>), service: ~fn(v: RecvPacketBuffered<T, Tb>)) diff --git a/src/test/run-pass/pipe-sleep.rs b/src/test/run-pass/pipe-sleep.rs index dc88f36ba11..dbf860cd040 100644 --- a/src/test/run-pass/pipe-sleep.rs +++ b/src/test/run-pass/pipe-sleep.rs @@ -33,7 +33,7 @@ endpoint. The send endpoint is returned to the caller and the receive endpoint is passed to the new task. */ -pub fn spawn_service<T:Owned,Tb:Owned>( +pub fn spawn_service<T:Send,Tb:Send>( init: extern fn() -> (RecvPacketBuffered<T, Tb>, SendPacketBuffered<T, Tb>), service: ~fn(v: RecvPacketBuffered<T, Tb>)) diff --git a/src/test/run-pass/preempt.rs b/src/test/run-pass/preempt.rs index 3d3e178f064..aa750c21d45 100644 --- a/src/test/run-pass/preempt.rs +++ b/src/test/run-pass/preempt.rs @@ -11,23 +11,30 @@ // xfail-test // This checks that preemption works. -fn starve_main(alive: chan<int>) { +// note: halfway done porting to modern rust +extern mod extra; + +use std::comm; +use extra::comm; + +fn starve_main(alive: Port<int>) { debug!("signalling main"); - alive.recv(1); + alive.recv(); debug!("starving main"); - let i: int = 0; + let mut i: int = 0; loop { i += 1; } } pub fn main() { - let alive: port<int> = port(); + let (port, chan) = stream(); + debug!("main started"); - let s: task = do task::spawn { - starve_main(chan(alive)); + do spawn { + starve_main(port); }; - let i: int; + let mut i: int = 0; debug!("main waiting for alive signal"); - alive.send(i); + chan.send(i); debug!("main got alive signal"); while i < 50 { debug!("main iterated"); i += 1; } debug!("main completed"); diff --git a/src/test/run-pass/rcvr-borrowed-to-region.rs b/src/test/run-pass/rcvr-borrowed-to-region.rs index fbd7d851fa3..c8e87af9ec0 100644 --- a/src/test/run-pass/rcvr-borrowed-to-region.rs +++ b/src/test/run-pass/rcvr-borrowed-to-region.rs @@ -1,6 +1,3 @@ -// xfail-test -// xfail'd due to segfaults with by-value self. - // 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. @@ -15,26 +12,24 @@ trait get { fn get(self) -> int; } -// Note: impl on a slice -impl get for &'self int { +// FIXME #7302: Note: impl on a slice +impl<'self> get for &'self int { fn get(self) -> int { - return **self; + return *self; } } pub fn main() { - /* let x = @mut 6; let y = x.get(); assert_eq!(y, 6); - */ let x = @6; let y = x.get(); debug!("y=%d", y); assert_eq!(y, 6); - let mut x = ~6; + let x = ~6; let y = x.get(); debug!("y=%d", y); assert_eq!(y, 6); diff --git a/src/test/run-pass/rcvr-borrowed-to-slice.rs b/src/test/run-pass/rcvr-borrowed-to-slice.rs index 5eaf12f6a51..b62475ded54 100644 --- a/src/test/run-pass/rcvr-borrowed-to-slice.rs +++ b/src/test/run-pass/rcvr-borrowed-to-slice.rs @@ -18,7 +18,7 @@ trait sum { impl<'self> sum for &'self [int] { fn sum(self) -> int { let mut sum = 0; - for vec::each(self) |e| { sum += *e; } + for self.iter().advance |e| { sum += *e; } return sum; } } diff --git a/src/test/run-pass/rec-align-u64.rs b/src/test/run-pass/rec-align-u64.rs index 8c67b971243..7bc7a8583b9 100644 --- a/src/test/run-pass/rec-align-u64.rs +++ b/src/test/run-pass/rec-align-u64.rs @@ -63,8 +63,8 @@ mod m { mod m { #[cfg(target_arch = "arm")] pub mod m { - pub fn align() -> uint { 4u } - pub fn size() -> uint { 12u } + pub fn align() -> uint { 8u } + pub fn size() -> uint { 16u } } } diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index e091554a357..176e49e0ea1 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -10,15 +10,14 @@ // xfail-fast -use std::bool; use std::int; use std::libc::c_void; use std::ptr; use std::sys; use std::vec::UnboxedVecRepr; -use intrinsic::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Opaque}; +use std::unstable::intrinsics::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Opaque}; -#[doc = "High-level interfaces to `intrinsic::visit_ty` reflection system."] +#[doc = "High-level interfaces to `std::unstable::intrinsics::visit_ty` reflection system."] /// Trait for visitor that wishes to reflect on data. trait movable_ptr { @@ -637,7 +636,9 @@ impl TyVisitor for my_visitor { } fn get_tydesc_for<T>(_t: T) -> *TyDesc { - get_tydesc::<T>() + unsafe { + get_tydesc::<T>() + } } struct Triple { x: int, y: int, z: int } @@ -651,17 +652,17 @@ pub fn main() { vals: ~[]}); let v = ptr_visit_adaptor(Inner {inner: u}); let td = get_tydesc_for(r); - unsafe { error!("tydesc sz: %u, align: %u", - (*td).size, (*td).align); } + error!("tydesc sz: %u, align: %u", + (*td).size, (*td).align); let v = @v as @TyVisitor; visit_tydesc(td, v); - for (u.vals.clone()).each |s| { + let r = u.vals.clone(); + for r.iter().advance |s| { println(fmt!("val: %s", *s)); } error!("%?", u.vals.clone()); - assert!(u.vals == ~[ - ~"1", ~"2", ~"3", ~"true", ~"false", ~"5", ~"4", ~"3", ~"12" - ]); + assert_eq!(u.vals.clone(), + ~[ ~"1", ~"2", ~"3", ~"true", ~"false", ~"5", ~"4", ~"3", ~"12"]); } - } +} diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs index 8a7fef95614..bb1c92dfa8a 100644 --- a/src/test/run-pass/reflect-visit-type.rs +++ b/src/test/run-pass/reflect-visit-type.rs @@ -8,141 +8,153 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test -use intrinsic::{TyDesc, get_tydesc, visit_tydesc, TyVisitor}; -struct my_visitor(@mut { types: ~[str] }); +use std::unstable::intrinsics::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Opaque}; -impl TyVisitor for my_visitor { - fn visit_bot() -> bool { - self.types += ~["bot"]; +struct MyVisitor { + types: @mut ~[~str], +} + +impl TyVisitor for MyVisitor { + fn visit_bot(&self) -> bool { + self.types.push(~"bot"); error!("visited bot type"); true } - fn visit_nil() -> bool { - self.types += ~["nil"]; + fn visit_nil(&self) -> bool { + self.types.push(~"nil"); error!("visited nil type"); true } - fn visit_bool() -> bool { - self.types += ~["bool"]; + fn visit_bool(&self) -> bool { + self.types.push(~"bool"); error!("visited bool type"); true } - fn visit_int() -> bool { - self.types += ~["int"]; + fn visit_int(&self) -> bool { + self.types.push(~"int"); error!("visited int type"); true } - fn visit_i8() -> bool { - self.types += ~["i8"]; + fn visit_i8(&self) -> bool { + self.types.push(~"i8"); error!("visited i8 type"); true } - fn visit_i16() -> bool { - self.types += ~["i16"]; + fn visit_i16(&self) -> bool { + self.types.push(~"i16"); error!("visited i16 type"); true } - fn visit_i32() -> bool { true } - fn visit_i64() -> bool { true } - - fn visit_uint() -> bool { true } - fn visit_u8() -> bool { true } - fn visit_u16() -> bool { true } - fn visit_u32() -> bool { true } - fn visit_u64() -> bool { true } - - fn visit_float() -> bool { true } - fn visit_f32() -> bool { true } - fn visit_f64() -> bool { true } - - fn visit_char() -> bool { true } - fn visit_str() -> bool { true } - - fn visit_estr_box() -> bool { true } - fn visit_estr_uniq() -> bool { true } - fn visit_estr_slice() -> bool { true } - fn visit_estr_fixed(_sz: uint, _sz: uint, + fn visit_i32(&self) -> bool { true } + fn visit_i64(&self) -> bool { true } + + fn visit_uint(&self) -> bool { true } + fn visit_u8(&self) -> bool { true } + fn visit_u16(&self) -> bool { true } + fn visit_u32(&self) -> bool { true } + fn visit_u64(&self) -> bool { true } + + fn visit_float(&self) -> bool { true } + fn visit_f32(&self) -> bool { true } + fn visit_f64(&self) -> bool { true } + + fn visit_char(&self) -> bool { true } + fn visit_str(&self) -> bool { true } + + fn visit_estr_box(&self) -> bool { true } + fn visit_estr_uniq(&self) -> bool { true } + fn visit_estr_slice(&self) -> bool { true } + fn visit_estr_fixed(&self, + _sz: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_box(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_uniq(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_ptr(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_rptr(_mtbl: uint, _inner: *TyDesc) -> bool { true } - - fn visit_vec(_mtbl: uint, inner: *TyDesc) -> bool { - self.types += ~["["]; - visit_tydesc(inner, my_visitor(*self) as TyVisitor); - self.types += ~["]"]; + fn visit_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_rptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + + fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_unboxed_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_uniq(&self, _mtbl: uint, inner: *TyDesc) -> bool { + self.types.push(~"["); + unsafe { + visit_tydesc(inner, (@*self) as @TyVisitor); + } + self.types.push(~"]"); true } - fn visit_unboxed_vec(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_box(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_uniq(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_slice(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_fixed(_n: uint, _sz: uint, _align: uint, + fn visit_evec_slice(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_fixed(&self, _n: uint, _sz: uint, _align: uint, _mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_enter_rec(_n_fields: uint, + fn visit_enter_rec(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_rec_field(_i: uint, _name: &str, + fn visit_rec_field(&self, _i: uint, _name: &str, _mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_leave_rec(_n_fields: uint, + fn visit_leave_rec(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_class(_n_fields: uint, + fn visit_enter_class(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_class_field(_i: uint, _name: &str, + fn visit_class_field(&self, _i: uint, _name: &str, _mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_leave_class(_n_fields: uint, + fn visit_leave_class(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_tup(_n_fields: uint, + fn visit_enter_tup(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_tup_field(_i: uint, _inner: *TyDesc) -> bool { true } - fn visit_leave_tup(_n_fields: uint, + fn visit_tup_field(&self, _i: uint, _inner: *TyDesc) -> bool { true } + fn visit_leave_tup(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_enum(_n_variants: uint, + fn visit_enter_enum(&self, _n_variants: uint, + _get_disr: extern unsafe fn(ptr: *Opaque) -> int, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_enum_variant(_variant: uint, + fn visit_enter_enum_variant(&self, + _variant: uint, _disr_val: int, _n_fields: uint, _name: &str) -> bool { true } - fn visit_enum_variant_field(_i: uint, _inner: *TyDesc) -> bool { true } - fn visit_leave_enum_variant(_variant: uint, + fn visit_enum_variant_field(&self, _i: uint, _offset: uint, _inner: *TyDesc) -> bool { true } + fn visit_leave_enum_variant(&self, + _variant: uint, _disr_val: int, _n_fields: uint, _name: &str) -> bool { true } - fn visit_leave_enum(_n_variants: uint, + fn visit_leave_enum(&self, + _n_variants: uint, + _get_disr: extern unsafe fn(ptr: *Opaque) -> int, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_fn(_purity: uint, _proto: uint, + fn visit_enter_fn(&self, _purity: uint, _proto: uint, _n_inputs: uint, _retstyle: uint) -> bool { true } - fn visit_fn_input(_i: uint, _mode: uint, _inner: *TyDesc) -> bool { true } - fn visit_fn_output(_retstyle: uint, _inner: *TyDesc) -> bool { true } - fn visit_leave_fn(_purity: uint, _proto: uint, + fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool { true } + fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool { true } + fn visit_leave_fn(&self, _purity: uint, _proto: uint, _n_inputs: uint, _retstyle: uint) -> bool { true } - fn visit_trait() -> bool { true } - fn visit_var() -> bool { true } - fn visit_var_integral() -> bool { true } - fn visit_param(_i: uint) -> bool { true } - fn visit_self() -> bool { true } - fn visit_type() -> bool { true } - fn visit_opaque_box() -> bool { true } - fn visit_constr(_inner: *TyDesc) -> bool { true } - fn visit_closure_ptr(_ck: uint) -> bool { true } + fn visit_trait(&self) -> bool { true } + fn visit_var(&self) -> bool { true } + fn visit_var_integral(&self) -> bool { true } + fn visit_param(&self, _i: uint) -> bool { true } + fn visit_self(&self) -> bool { true } + fn visit_type(&self) -> bool { true } + fn visit_opaque_box(&self) -> bool { true } + fn visit_constr(&self, _inner: *TyDesc) -> bool { true } + fn visit_closure_ptr(&self, _ck: uint) -> bool { true } } -fn visit_ty<T>(v: TyVisitor) { - visit_tydesc(get_tydesc::<T>(), v); +fn visit_ty<T>(v: @TyVisitor) { + unsafe { + visit_tydesc(get_tydesc::<T>(), v); + } } pub fn main() { - let v = my_visitor(@mut {types: ~[]}); - let vv = v as TyVisitor; + let v = @MyVisitor {types: @mut ~[]}; + let vv = v as @TyVisitor; visit_ty::<bool>(vv); visit_ty::<int>(vv); @@ -150,9 +162,8 @@ pub fn main() { visit_ty::<i16>(vv); visit_ty::<~[int]>(vv); - for (v.types.clone()).each {|s| - io::println(fmt!("type: %s", s)); + for v.types.iter().advance |&s| { + println(fmt!("type: %s", s)); } - assert!(v.types == ["bool", "int", "i8", "i16", - "[", "int", "]"]); + assert_eq!((*v.types).clone(), ~[~"bool", ~"int", ~"i8", ~"i16", ~"[", ~"int", ~"]"]); } diff --git a/src/test/run-pass/regions-borrow-evec-at.rs b/src/test/run-pass/regions-borrow-evec-at.rs index a018dad64b3..45e5b1ad9c9 100644 --- a/src/test/run-pass/regions-borrow-evec-at.rs +++ b/src/test/run-pass/regions-borrow-evec-at.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - fn foo(x: &[uint]) -> uint { x[0] } diff --git a/src/test/run-pass/regions-trait.rs b/src/test/run-pass/regions-trait.rs index b5b13efa634..049d5305ca4 100644 --- a/src/test/run-pass/regions-trait.rs +++ b/src/test/run-pass/regions-trait.rs @@ -22,7 +22,7 @@ impl<'self> get_ctxt<'self> for HasCtxt<'self> { } } -fn get_v(gc: @get_ctxt) -> uint { +fn get_v(gc: @get_ctxt:) -> uint { gc.get_ctxt().v } @@ -30,5 +30,5 @@ pub fn main() { let ctxt = Ctxt { v: 22 }; let hc = HasCtxt { c: &ctxt }; - assert_eq!(get_v(@hc as @get_ctxt), 22); + assert_eq!(get_v(@hc as @get_ctxt:), 22); } diff --git a/src/test/run-pass/resolve-issue-2428.rs b/src/test/run-pass/resolve-issue-2428.rs index 6d00210898b..57f6596d1d7 100644 --- a/src/test/run-pass/resolve-issue-2428.rs +++ b/src/test/run-pass/resolve-issue-2428.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - static foo: int = 4 >> 1; enum bs { thing = foo } pub fn main() { assert!((thing as int == foo)); } diff --git a/src/test/run-pass/resource-assign-is-not-copy.rs b/src/test/run-pass/resource-assign-is-not-copy.rs index edd692196ec..112c6be560d 100644 --- a/src/test/run-pass/resource-assign-is-not-copy.rs +++ b/src/test/run-pass/resource-assign-is-not-copy.rs @@ -14,7 +14,7 @@ struct r { #[unsafe_destructor] impl Drop for r { - fn finalize(&self) { + fn drop(&self) { unsafe { *(self.i) += 1; } diff --git a/src/test/run-pass/resource-cycle.rs b/src/test/run-pass/resource-cycle.rs index 3ce5ea66781..e48b841144a 100644 --- a/src/test/run-pass/resource-cycle.rs +++ b/src/test/run-pass/resource-cycle.rs @@ -17,7 +17,7 @@ struct r { } impl Drop for r { - fn finalize(&self) { + fn drop(&self) { unsafe { debug!("r's dtor: self = %x, self.v = %x, self.v's value = %x", cast::transmute::<*r, uint>(self), diff --git a/src/test/run-pass/resource-cycle2.rs b/src/test/run-pass/resource-cycle2.rs index 0f031424ad4..1a82e321bd7 100644 --- a/src/test/run-pass/resource-cycle2.rs +++ b/src/test/run-pass/resource-cycle2.rs @@ -23,7 +23,7 @@ struct r { } impl Drop for r { - fn finalize(&self) { + fn drop(&self) { unsafe { let v2: ~int = cast::transmute(self.v.c); } diff --git a/src/test/run-pass/resource-cycle3.rs b/src/test/run-pass/resource-cycle3.rs index f3ca932778a..1e0d8447aeb 100644 --- a/src/test/run-pass/resource-cycle3.rs +++ b/src/test/run-pass/resource-cycle3.rs @@ -27,7 +27,7 @@ struct R { } impl Drop for R { - fn finalize(&self) { + fn drop(&self) { unsafe { let _v2: ~int = cast::transmute(self.v.c); // let _v3: ~int = cast::transmute_copy(self.x); diff --git a/src/test/run-pass/resource-destruct.rs b/src/test/run-pass/resource-destruct.rs index c240c6708a4..7eac25535a8 100644 --- a/src/test/run-pass/resource-destruct.rs +++ b/src/test/run-pass/resource-destruct.rs @@ -14,7 +14,7 @@ struct shrinky_pointer { #[unsafe_destructor] impl Drop for shrinky_pointer { - fn finalize(&self) { + fn drop(&self) { unsafe { error!(~"Hello!"); **(self.i) -= 1; } diff --git a/src/test/run-pass/resource-generic.rs b/src/test/run-pass/resource-generic.rs index 7a18cd02c2d..75d978b0d05 100644 --- a/src/test/run-pass/resource-generic.rs +++ b/src/test/run-pass/resource-generic.rs @@ -18,7 +18,7 @@ struct finish<T> { #[unsafe_destructor] impl<T:Copy> Drop for finish<T> { - fn finalize(&self) { + fn drop(&self) { unsafe { (self.arg.fin)(copy self.arg.val); } diff --git a/src/test/run-pass/resource-in-struct.rs b/src/test/run-pass/resource-in-struct.rs index d74ec61d3c0..836b49f9a15 100644 --- a/src/test/run-pass/resource-in-struct.rs +++ b/src/test/run-pass/resource-in-struct.rs @@ -20,7 +20,7 @@ struct close_res { #[unsafe_destructor] impl Drop for close_res { - fn finalize(&self) { + fn drop(&self) { unsafe { *(self.i) = false; } diff --git a/src/test/run-pass/send-resource.rs b/src/test/run-pass/send-resource.rs index a2cee0082b5..e450e1f48c0 100644 --- a/src/test/run-pass/send-resource.rs +++ b/src/test/run-pass/send-resource.rs @@ -16,7 +16,7 @@ struct test { } impl Drop for test { - fn finalize(&self) {} + fn drop(&self) {} } fn test(f: int) -> test { diff --git a/src/test/run-pass/send-type-inference.rs b/src/test/run-pass/send-type-inference.rs index bdb1fbaf422..4fcbc789f57 100644 --- a/src/test/run-pass/send-type-inference.rs +++ b/src/test/run-pass/send-type-inference.rs @@ -16,7 +16,7 @@ struct Command<K, V> { val: V } -fn cache_server<K:Owned,V:Owned>(c: Chan<Chan<Command<K, V>>>) { +fn cache_server<K:Send,V:Send>(c: Chan<Chan<Command<K, V>>>) { let (ctrl_port, ctrl_chan) = stream(); c.send(ctrl_chan); } diff --git a/src/test/run-pass/shadow.rs b/src/test/run-pass/shadow.rs index 99553cfcf79..d0c58b50e2c 100644 --- a/src/test/run-pass/shadow.rs +++ b/src/test/run-pass/shadow.rs @@ -15,14 +15,14 @@ fn foo(c: ~[int]) { match none::<int> { - some::<int>(_) => { - for c.each |i| { - debug!(a); - let a = 17; - b += ~[a]; + some::<int>(_) => { + for c.iter().advance |i| { + debug!(a); + let a = 17; + b.push(a); + } } - } - _ => { } + _ => { } } } diff --git a/src/test/run-pass/shape_intrinsic_tag_then_rec.rs b/src/test/run-pass/shape_intrinsic_tag_then_rec.rs index f29d0c6f108..34afc12f02e 100644 --- a/src/test/run-pass/shape_intrinsic_tag_then_rec.rs +++ b/src/test/run-pass/shape_intrinsic_tag_then_rec.rs @@ -1,5 +1,3 @@ -// xfail-fast - // 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. @@ -14,9 +12,6 @@ // on x86_64: when there is a enum embedded in an // interior record which is then itself interior to // something else, shape calculations were off. -extern mod extra; -use extra::list; -use extra::list::list; enum opt_span { diff --git a/src/test/run-pass/static-impl.rs b/src/test/run-pass/static-impl.rs index 3d3f1404dc2..0ddc39d6b18 100644 --- a/src/test/run-pass/static-impl.rs +++ b/src/test/run-pass/static-impl.rs @@ -48,10 +48,12 @@ trait vec_utils<T> { impl<T> vec_utils<T> for ~[T] { fn length_(&self) -> uint { self.len() } - fn iter_(&self, f: &fn(&T)) { for self.each |x| { f(x); } } + fn iter_(&self, f: &fn(&T)) { for self.iter().advance |x| { f(x); } } fn map_<U:Copy>(&self, f: &fn(&T) -> U) -> ~[U] { let mut r = ~[]; - for self.each |elt| { r += ~[f(elt)]; } + for self.iter().advance |elt| { + r.push(f(elt)); + } r } } diff --git a/src/test/run-pass/static-method-test.rs b/src/test/run-pass/static-method-test.rs deleted file mode 100644 index 2d6b2141c5c..00000000000 --- a/src/test/run-pass/static-method-test.rs +++ /dev/null @@ -1,94 +0,0 @@ -// 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. - -// xfail-fast - -use std::at_vec; -use std::uint; -use std::vec; - -// A trait for objects that can be used to do an if-then-else -// (No actual need for this to be static, but it is a simple test.) -trait bool_like { - fn select<A>(b: Self, x1: A, x2: A) -> A; -} - -fn andand<T:bool_like + Copy>(x1: T, x2: T) -> T { - bool_like::select(copy x1, x2, x1) -} - -impl bool_like for bool { - fn select<A>(b: bool, x1: A, x2: A) -> A { - if b { x1 } else { x2 } - } -} - -impl bool_like for int { - fn select<A>(b: int, x1: A, x2: A) -> A { - if b != 0 { x1 } else { x2 } - } -} - -// A trait for sequences that can be constructed imperatively. -trait buildable<A> { - fn build_sized(size: uint, builder: &fn(push: &fn(v: A))) -> Self; -} - - -impl<A> buildable<A> for @[A] { - #[inline(always)] - fn build_sized(size: uint, builder: &fn(push: &fn(v: A))) -> @[A] { - at_vec::build_sized(size, builder) - } -} -impl<A> buildable<A> for ~[A] { - #[inline(always)] - fn build_sized(size: uint, builder: &fn(push: &fn(v: A))) -> ~[A] { - vec::build_sized(size, builder) - } -} - -#[inline(always)] -fn build<A, B: buildable<A>>(builder: &fn(push: &fn(v: A))) -> B { - buildable::build_sized(4, builder) -} - -/// Apply a function to each element of an iterable and return the results -fn map<T, IT: BaseIter<T>, U, BU: buildable<U>> - (v: IT, f: &fn(&T) -> U) -> BU { - do build |push| { - for v.each() |elem| { - push(f(elem)); - } - } -} - -fn seq_range<BT:buildable<int>>(lo: uint, hi: uint) -> BT { - do buildable::build_sized(hi-lo) |push| { - for uint::range(lo, hi) |i| { - push(i as int); - } - } -} - -pub fn main() { - let v: @[int] = seq_range(0, 10); - assert_eq!(v, @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - - let v: @[int] = map(&[1,2,3], |&x| 1+x); - assert_eq!(v, @[2, 3, 4]); - let v: ~[int] = map(&[1,2,3], |&x| 1+x); - assert_eq!(v, ~[2, 3, 4]); - - assert_eq!(bool_like::select(true, 9, 14), 9); - assert!(!andand(true, false)); - assert_eq!(andand(7, 12), 12); - assert_eq!(andand(0, 12), 0); -} diff --git a/src/test/run-pass/static-mut-foreign.rs b/src/test/run-pass/static-mut-foreign.rs new file mode 100644 index 00000000000..7af143a1529 --- /dev/null +++ b/src/test/run-pass/static-mut-foreign.rs @@ -0,0 +1,46 @@ +// 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. + +// Constants (static variables) can be used to match in patterns, but mutable +// statics cannot. This ensures that there's some form of error if this is +// attempted. + +use std::libc; + +#[nolink] +extern { + static mut debug_static_mut: libc::c_int; + pub fn debug_static_mut_check_four(); +} + +unsafe fn static_bound(_: &'static libc::c_int) {} + +fn static_bound_set(a: &'static mut libc::c_int) { + *a = 3; +} + +unsafe fn run() { + assert!(debug_static_mut == 3); + debug_static_mut = 4; + assert!(debug_static_mut == 4); + debug_static_mut_check_four(); + debug_static_mut += 1; + assert!(debug_static_mut == 5); + debug_static_mut *= 3; + assert!(debug_static_mut == 15); + debug_static_mut = -3; + assert!(debug_static_mut == -3); + static_bound(&debug_static_mut); + static_bound_set(&mut debug_static_mut); +} + +pub fn main() { + unsafe { run() } +} diff --git a/src/test/run-pass/static-mut-xc.rs b/src/test/run-pass/static-mut-xc.rs new file mode 100644 index 00000000000..ab6bdc20c49 --- /dev/null +++ b/src/test/run-pass/static-mut-xc.rs @@ -0,0 +1,46 @@ +// 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. + +// Constants (static variables) can be used to match in patterns, but mutable +// statics cannot. This ensures that there's some form of error if this is +// attempted. + +// xfail-fast +// aux-build:static_mut_xc.rs + +extern mod static_mut_xc; + +unsafe fn static_bound(_: &'static int) {} + +fn static_bound_set(a: &'static mut int) { + *a = 3; +} + +unsafe fn run() { + assert!(static_mut_xc::a == 3); + static_mut_xc::a = 4; + assert!(static_mut_xc::a == 4); + static_mut_xc::a += 1; + assert!(static_mut_xc::a == 5); + static_mut_xc::a *= 3; + assert!(static_mut_xc::a == 15); + static_mut_xc::a = -3; + assert!(static_mut_xc::a == -3); + static_bound(&static_mut_xc::a); + static_bound_set(&mut static_mut_xc::a); +} + +pub fn main() { + unsafe { run() } +} + +pub mod inner { + pub static mut a: int = 4; +} diff --git a/src/test/run-pass/str-append.rs b/src/test/run-pass/str-append.rs index 4fdf7dde031..556247eb426 100644 --- a/src/test/run-pass/str-append.rs +++ b/src/test/run-pass/str-append.rs @@ -15,7 +15,7 @@ extern mod extra; fn test1() { let mut s: ~str = ~"hello"; - s += ~"world"; + s.push_str("world"); debug!(s.clone()); assert_eq!(s[9], 'd' as u8); } diff --git a/src/test/run-pass/str-growth.rs b/src/test/run-pass/str-growth.rs index 6938b52eee8..0cdf1841331 100644 --- a/src/test/run-pass/str-growth.rs +++ b/src/test/run-pass/str-growth.rs @@ -12,11 +12,11 @@ pub fn main() { let mut s = ~"a"; - s += ~"b"; + s.push_char('b'); assert_eq!(s[0], 'a' as u8); assert_eq!(s[1], 'b' as u8); - s += ~"c"; - s += ~"d"; + s.push_char('c'); + s.push_char('d'); assert_eq!(s[0], 'a' as u8); assert_eq!(s[1], 'b' as u8); assert_eq!(s[2], 'c' as u8); diff --git a/src/test/run-pass/struct-literal-dtor.rs b/src/test/run-pass/struct-literal-dtor.rs index 9f5b8cf27dd..2fc6833242f 100644 --- a/src/test/run-pass/struct-literal-dtor.rs +++ b/src/test/run-pass/struct-literal-dtor.rs @@ -13,7 +13,7 @@ struct foo { } impl Drop for foo { - fn finalize(&self) { + fn drop(&self) { error!("%s", self.x); } } diff --git a/src/test/run-pass/swap-2.rs b/src/test/run-pass/swap-2.rs index cf3a465d812..2ec2eb3c45b 100644 --- a/src/test/run-pass/swap-2.rs +++ b/src/test/run-pass/swap-2.rs @@ -9,11 +9,10 @@ // except according to those terms. use std::util; -use std::vec; pub fn main() { let mut a: ~[int] = ~[0, 1, 2, 3, 4, 5, 6]; - vec::swap(a, 2, 4); + a.swap(2, 4); assert_eq!(a[2], 4); assert_eq!(a[4], 2); let mut n = 42; diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs index 67573fce2cd..fe7b510cfe7 100644 --- a/src/test/run-pass/syntax-extension-fmt.rs +++ b/src/test/run-pass/syntax-extension-fmt.rs @@ -58,6 +58,9 @@ fn part1() { test(fmt!("%x", 0xffffffff_u), ~"ffffffff"); test(fmt!("%o", 0xffffffff_u), ~"37777777777"); test(fmt!("%t", 0xffffffff_u), ~"11111111111111111111111111111111"); + + // Don't result in a compilation error + test(fmt!(""), ~""); } fn part2() { // Widths diff --git a/src/test/run-pass/tag-align-dyn-variants.rs b/src/test/run-pass/tag-align-dyn-variants.rs index cd94bd30c21..85a4f98d198 100644 --- a/src/test/run-pass/tag-align-dyn-variants.rs +++ b/src/test/run-pass/tag-align-dyn-variants.rs @@ -10,6 +10,8 @@ // xfail-test +use std::ptr; + enum a_tag<A,B> { varA(A), varB(B) diff --git a/src/test/run-pass/tag-align-u64.rs b/src/test/run-pass/tag-align-u64.rs index ea60f389663..28088aa571e 100644 --- a/src/test/run-pass/tag-align-u64.rs +++ b/src/test/run-pass/tag-align-u64.rs @@ -10,6 +10,8 @@ // xfail-test +use std::ptr; + enum a_tag { a_tag(u64) } diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index dd8168ff947..f94b5487374 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -54,7 +54,7 @@ fn test00() { // Read from spawned tasks... let mut sum = 0; - for results.each |r| { + for results.iter().advance |r| { i = 0; while i < number_of_messages { let value = po.recv(); @@ -64,7 +64,7 @@ fn test00() { } // Join spawned tasks... - for results.each |r| { r.recv(); } + for results.iter().advance |r| { r.recv(); } debug!("Completed: Final number is: "); error!(sum); diff --git a/src/test/run-pass/task-killjoin-rsrc.rs b/src/test/run-pass/task-killjoin-rsrc.rs index 2025a5c304c..aa37f5e9ce9 100644 --- a/src/test/run-pass/task-killjoin-rsrc.rs +++ b/src/test/run-pass/task-killjoin-rsrc.rs @@ -24,7 +24,7 @@ struct notify { #[unsafe_destructor] impl Drop for notify { - fn finalize(&self) { + fn drop(&self) { unsafe { error!("notify: task=%? v=%x unwinding=%b b=%b", task::get_task(), diff --git a/src/test/run-pass/trait-bounds-basic.rs b/src/test/run-pass/trait-bounds-basic.rs new file mode 100644 index 00000000000..e0d60d62bb5 --- /dev/null +++ b/src/test/run-pass/trait-bounds-basic.rs @@ -0,0 +1,32 @@ +// 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. + +trait Foo { +} + +fn a(_x: ~Foo:) { +} + +fn b(_x: ~Foo:Send) { +} + +fn c(x: ~Foo:Freeze+Send) { + a(x); +} + +fn d(x: ~Foo:Send+Copy) { + b(x); +} + +fn e(x: ~Foo) { // sugar for ~Foo:Owned + b(x); +} + +fn main() { } diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs new file mode 100644 index 00000000000..a3b2ea02db3 --- /dev/null +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -0,0 +1,103 @@ +// 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. + +// Tests that a heterogeneous list of existential types can be put inside an ARC +// and shared between tasks as long as all types fulfill Freeze+Send. + +// xfail-fast + +extern mod extra; +use extra::arc; +use std::comm; +use std::task; +use std::cell; + +trait Pet { + fn name(&self, blk: &fn(&str)); + fn num_legs(&self) -> uint; + fn of_good_pedigree(&self) -> bool; +} + +struct Catte { + num_whiskers: uint, + name: ~str, +} + +struct Dogge { + bark_decibels: uint, + tricks_known: uint, + name: ~str, +} + +struct Goldfyshe { + swim_speed: uint, + name: ~str, +} + +impl Pet for Catte { + fn name(&self, blk: &fn(&str)) { blk(self.name) } + fn num_legs(&self) -> uint { 4 } + fn of_good_pedigree(&self) -> bool { self.num_whiskers >= 4 } +} +impl Pet for Dogge { + fn name(&self, blk: &fn(&str)) { blk(self.name) } + fn num_legs(&self) -> uint { 4 } + fn of_good_pedigree(&self) -> bool { + self.bark_decibels < 70 || self.tricks_known > 20 + } +} +impl Pet for Goldfyshe { + fn name(&self, blk: &fn(&str)) { blk(self.name) } + fn num_legs(&self) -> uint { 0 } + fn of_good_pedigree(&self) -> bool { self.swim_speed >= 500 } +} + +fn main() { + let catte = Catte { num_whiskers: 7, name: ~"alonzo_church" }; + let dogge1 = Dogge { bark_decibels: 100, tricks_known: 42, name: ~"alan_turing" }; + let dogge2 = Dogge { bark_decibels: 55, tricks_known: 11, name: ~"albert_einstein" }; + let fishe = Goldfyshe { swim_speed: 998, name: ~"alec_guinness" }; + let arc = arc::ARC(~[~catte as ~Pet:Freeze+Send, + ~dogge1 as ~Pet:Freeze+Send, + ~fishe as ~Pet:Freeze+Send, + ~dogge2 as ~Pet:Freeze+Send]); + let (p1,c1) = comm::stream(); + let arc1 = cell::Cell::new(arc.clone()); + do task::spawn { check_legs(arc1.take()); c1.send(()); } + let (p2,c2) = comm::stream(); + let arc2 = cell::Cell::new(arc.clone()); + do task::spawn { check_names(arc2.take()); c2.send(()); } + let (p3,c3) = comm::stream(); + let arc3 = cell::Cell::new(arc.clone()); + do task::spawn { check_pedigree(arc3.take()); c3.send(()); } + p1.recv(); + p2.recv(); + p3.recv(); +} + +fn check_legs(arc: arc::ARC<~[~Pet:Freeze+Send]>) { + let mut legs = 0; + for arc.get().iter().advance |pet| { + legs += pet.num_legs(); + } + assert!(legs == 12); +} +fn check_names(arc: arc::ARC<~[~Pet:Freeze+Send]>) { + for arc.get().iter().advance |pet| { + do pet.name |name| { + assert!(name[0] == 'a' as u8 && name[1] == 'l' as u8); + } + } +} +fn check_pedigree(arc: arc::ARC<~[~Pet:Freeze+Send]>) { + for arc.get().iter().advance |pet| { + assert!(pet.of_good_pedigree()); + } +} diff --git a/src/test/run-pass/trait-cast.rs b/src/test/run-pass/trait-cast.rs index f21ea06697d..637fc7a70f5 100644 --- a/src/test/run-pass/trait-cast.rs +++ b/src/test/run-pass/trait-cast.rs @@ -1,4 +1,4 @@ -// xfail-test +// xfail-test FIXME #5882 // Weird borrow check bug // Copyright 2012 The Rust Project Developers. See the COPYRIGHT @@ -17,45 +17,45 @@ struct Tree(@mut TreeR); struct TreeR { left: Option<Tree>, right: Option<Tree>, - val: to_str + val: ~to_str } trait to_str { - fn to_str(&self) -> ~str; + fn to_str_(&self) -> ~str; } impl<T:to_str> to_str for Option<T> { - fn to_str(&self) -> ~str { + fn to_str_(&self) -> ~str { match *self { None => { ~"none" } - Some(ref t) => { ~"some(" + t.to_str() + ~")" } + Some(ref t) => { ~"some(" + t.to_str_() + ~")" } } } } impl to_str for int { - fn to_str(&self) -> ~str { int::str(*self) } + fn to_str_(&self) -> ~str { self.to_str() } } impl to_str for Tree { - fn to_str(&self) -> ~str { - let l = self.left, r = self.right; + fn to_str_(&self) -> ~str { + let (l, r) = (self.left, self.right); let val = &self.val; - fmt!("[%s, %s, %s]", val.to_str(), l.to_str(), r.to_str()) + fmt!("[%s, %s, %s]", val.to_str_(), l.to_str_(), r.to_str_()) } } -fn foo<T:to_str>(x: T) -> ~str { x.to_str() } +fn foo<T:to_str>(x: T) -> ~str { x.to_str_() } pub fn main() { let t1 = Tree(@mut TreeR{left: None, right: None, - val: 1 as to_str }); + val: ~1 as ~to_str }); let t2 = Tree(@mut TreeR{left: Some(t1), right: Some(t1), - val: 2 as to_str }); + val: ~2 as ~to_str }); let expected = ~"[2, some([1, none, none]), some([1, none, none])]"; - assert_eq!(t2.to_str(), expected); - assert_eq!(foo(t2 as to_str), expected); + assert!(t2.to_str_() == expected); + assert!(foo(t2) == expected); t1.left = Some(t2); // create cycle } diff --git a/src/test/run-pass/trait-default-method-bound-subst.rs b/src/test/run-pass/trait-default-method-bound-subst.rs index adabafc082a..9dbbcee0f77 100644 --- a/src/test/run-pass/trait-default-method-bound-subst.rs +++ b/src/test/run-pass/trait-default-method-bound-subst.rs @@ -15,6 +15,7 @@ trait A<T> { } impl A<int> for int { } +impl<T> A<T> for uint { } fn f<T, U, V: A<T>>(i: V, j: T, k: U) -> (T, U) { i.g(j, k) @@ -22,4 +23,5 @@ fn f<T, U, V: A<T>>(i: V, j: T, k: U) -> (T, U) { pub fn main () { assert_eq!(f(0, 1, 2), (1, 2)); + assert_eq!(f(0u, 1, 2), (1, 2)); } diff --git a/src/test/run-pass/trait-default-method-xc.rs b/src/test/run-pass/trait-default-method-xc.rs new file mode 100644 index 00000000000..f6c119c4fae --- /dev/null +++ b/src/test/run-pass/trait-default-method-xc.rs @@ -0,0 +1,71 @@ +// xfail-fast +// aux-build:trait_default_method_xc_aux.rs + +#[allow(default_methods)]; + +extern mod aux(name = "trait_default_method_xc_aux"); +use aux::{A, B, TestEquality}; + + +fn f<T: aux::A>(i: T) { + assert_eq!(i.g(), 10); +} + + +pub struct thing { x: int } +impl A for thing { + fn f(&self) -> int { 10 } +} + +fn g<T, U, V: B<T>>(i: V, j: T, k: U) -> (T, U) { + i.thing(j, k) +} + +fn eq<T: TestEquality>(lhs: &T, rhs: &T) -> bool { + lhs.test_eq(rhs) +} +fn neq<T: TestEquality>(lhs: &T, rhs: &T) -> bool { + lhs.test_neq(rhs) +} + + +impl TestEquality for thing { + fn test_eq(&self, rhs: &thing) -> bool { + //self.x.test_eq(&rhs.x) + eq(&self.x, &rhs.x) + } +} + + +fn main () { + // Some tests of random things + f(0); + + let a = thing { x: 0 }; + let b = thing { x: 1 }; + + //assert_eq!(0i.g(), 10); + assert_eq!(a.g(), 10); + assert_eq!(a.h(), 10); + + + //assert_eq!(0i.thing(3.14, 1), (3.14, 1)); + + assert_eq!(g(0i, 3.14, 1), (3.14, 1)); + assert_eq!(g(false, 3.14, 1), (3.14, 1)); + + let obj = @0i as @A; + assert_eq!(obj.h(), 10); + + + // Trying out a real one + //assert!(12.test_neq(&10)); + //assert!(!10.test_neq(&10)); + assert!(a.test_neq(&b)); + assert!(!a.test_neq(&a)); + + assert!(neq(&12, &10)); + assert!(!neq(&10, &10)); + assert!(neq(&a, &b)); + assert!(!neq(&a, &a)); +} diff --git a/src/test/run-pass/trait-generic.rs b/src/test/run-pass/trait-generic.rs index 3aa30aab7c2..5952afa6676 100644 --- a/src/test/run-pass/trait-generic.rs +++ b/src/test/run-pass/trait-generic.rs @@ -31,7 +31,10 @@ trait map<T> { impl<T> map<T> for ~[T] { fn map<U:Copy>(&self, f: &fn(&T) -> U) -> ~[U] { let mut r = ~[]; - for self.each |x| { r += ~[f(x)]; } + // FIXME: #7355 generates bad code with Iterator + for std::uint::range(0, self.len()) |i| { + r.push(f(&self[i])); + } r } } diff --git a/src/test/run-pass/trait-to-str.rs b/src/test/run-pass/trait-to-str.rs index 4029bd18338..3e4cfdc105c 100644 --- a/src/test/run-pass/trait-to-str.rs +++ b/src/test/run-pass/trait-to-str.rs @@ -15,7 +15,9 @@ extern mod std; use std::str::StrVector; -use std::{int, vec}; +use std::vec::ImmutableVector; +use std::iterator::IteratorUtil; +use std::int; trait to_str { fn to_str(&self) -> ~str; @@ -27,7 +29,7 @@ impl to_str for int { impl<T:to_str> to_str for ~[T] { fn to_str(&self) -> ~str { - ~"[" + vec::map(*self, |e| e.to_str()).connect(", ") + "]" + fmt!("[%s]", self.iter().transform(|e| e.to_str()).collect::<~[~str]>().connect(", ")) } } diff --git a/src/test/run-pass/trait-with-bounds-default.rs b/src/test/run-pass/trait-with-bounds-default.rs new file mode 100644 index 00000000000..b3ddbbb9dc1 --- /dev/null +++ b/src/test/run-pass/trait-with-bounds-default.rs @@ -0,0 +1,41 @@ +// 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. + +pub trait Clone2 { + /// Returns a copy of the value. The contents of owned pointers + /// are copied to maintain uniqueness, while the contents of + /// managed pointers are not copied. + fn clone(&self) -> Self; +} + +#[allow(default_methods)] +trait Getter<T: Clone> { + fn do_get(&self) -> T; + + fn do_get2(&self) -> (T, T) { + let x = self.do_get(); + (x.clone(), x.clone()) + } + +} + +impl Getter<int> for int { + fn do_get(&self) -> int { *self } +} + +impl<T: Clone> Getter<T> for Option<T> { + fn do_get(&self) -> T { self.get_ref().clone() } +} + + +fn main() { + assert_eq!(3.do_get2(), (3, 3)); + assert_eq!(Some(~"hi").do_get2(), (~"hi", ~"hi")); +} diff --git a/src/test/run-pass/traits.rs b/src/test/run-pass/traits.rs deleted file mode 100644 index ba3e8e082b3..00000000000 --- a/src/test/run-pass/traits.rs +++ /dev/null @@ -1,55 +0,0 @@ -// 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. - -//xfail-test - -// Sketching traits. - -// methods with no implementation are required; methods with an -// implementation are provided. No "req" keyword necessary. -trait Eq { - fn eq(a: self) -> bool; - - fn neq(a: self) -> bool { - !self.eq(a) - } -} - -// The `<` is pronounced `extends`. Also under consideration is `<:`. -// Just using `:` is frowned upon, because (paraphrasing dherman) `:` -// is supposed to separate things from different universes. -trait Ord < Eq { - - fn lt(a: self) -> bool; - - fn lte(a: self) -> bool { - self.lt(a) || self.eq(a) - } - - fn gt(a: self) -> bool { - !self.lt(a) && !self.eq(a) - } - - fn gte(a: self) -> bool { - !self.lt(a) - } -} - -// pronounced "impl of Ord for int" -- not sold on this yet -impl Ord for int { - fn lt(a: &int) -> bool { - self < (*a) - } - - // is this the place to put this? - fn eq(a: &int) -> bool { - self == (*a) - } -} diff --git a/src/test/run-pass/type-param-constraints.rs b/src/test/run-pass/type-param-constraints.rs index bd6165806c2..216a7a939fe 100644 --- a/src/test/run-pass/type-param-constraints.rs +++ b/src/test/run-pass/type-param-constraints.rs @@ -12,14 +12,14 @@ fn p_foo<T>(pinned: T) { } fn s_foo<T:Copy>(shared: T) { } -fn u_foo<T:Owned>(unique: T) { } +fn u_foo<T:Send>(unique: T) { } struct r { i: int, } impl Drop for r { - fn finalize(&self) {} + fn drop(&self) {} } fn r(i:int) -> r { diff --git a/src/test/run-pass/unconstrained-region.rs b/src/test/run-pass/unconstrained-region.rs index b6e2ba553df..2341ee8d100 100644 --- a/src/test/run-pass/unconstrained-region.rs +++ b/src/test/run-pass/unconstrained-region.rs @@ -9,14 +9,15 @@ // except according to those terms. // xfail-test -// See #3283 -fn foo(blk: &fn(p: &'a fn() -> &'a fn())) { - let mut state = 0; - let statep = &mut state; +// FIXME: #7336: codegen bug makes this segfault on Linux x86_64 + +fn foo<'a>(blk: &fn(p: &'a fn() -> &'a fn())) { + let mut state = 0; + let statep = &mut state; do blk { || { *statep = 1; } } } fn main() { do foo |p| { p()() } -} \ No newline at end of file +} diff --git a/src/test/run-pass/unfoldr-cross-crate.rs b/src/test/run-pass/unfoldr-cross-crate.rs index 4e98543ae82..7fcae90a8d1 100644 --- a/src/test/run-pass/unfoldr-cross-crate.rs +++ b/src/test/run-pass/unfoldr-cross-crate.rs @@ -24,7 +24,7 @@ fn main() { } } - let mut it = UnfoldrIterator::new(count, 0); + let mut it = UnfoldrIterator::new(0, count); let mut i = 0; for it.advance |counted| { assert_eq!(counted, i); diff --git a/src/test/run-pass/uniq-cc-generic.rs b/src/test/run-pass/uniq-cc-generic.rs index b54b3b52692..2c3424d1f06 100644 --- a/src/test/run-pass/uniq-cc-generic.rs +++ b/src/test/run-pass/uniq-cc-generic.rs @@ -20,7 +20,7 @@ struct Pointy { d : ~fn() -> uint, } -fn make_uniq_closure<A:Owned + Copy>(a: A) -> ~fn() -> uint { +fn make_uniq_closure<A:Send + Copy>(a: A) -> ~fn() -> uint { let result: ~fn() -> uint = || ptr::to_unsafe_ptr(&a) as uint; result } diff --git a/src/test/run-pass/unique-kinds.rs b/src/test/run-pass/unique-kinds.rs index b3ce71dcbff..391881deff6 100644 --- a/src/test/run-pass/unique-kinds.rs +++ b/src/test/run-pass/unique-kinds.rs @@ -12,11 +12,11 @@ use std::cmp::Eq; fn sendable() { - fn f<T:Owned + Eq>(i: T, j: T) { + fn f<T:Send + Eq>(i: T, j: T) { assert_eq!(i, j); } - fn g<T:Owned + Eq>(i: T, j: T) { + fn g<T:Send + Eq>(i: T, j: T) { assert!(i != j); } diff --git a/src/test/run-pass/unique-pinned-nocopy-2.rs b/src/test/run-pass/unique-pinned-nocopy-2.rs index 197f26f897d..b0ad7f50420 100644 --- a/src/test/run-pass/unique-pinned-nocopy-2.rs +++ b/src/test/run-pass/unique-pinned-nocopy-2.rs @@ -14,7 +14,7 @@ struct r { #[unsafe_destructor] impl Drop for r { - fn finalize(&self) { + fn drop(&self) { unsafe { *(self.i) = *(self.i) + 1; } diff --git a/src/test/run-pass/unit-like-struct-drop-run.rs b/src/test/run-pass/unit-like-struct-drop-run.rs index b19a0aa1e98..41b971d64d0 100644 --- a/src/test/run-pass/unit-like-struct-drop-run.rs +++ b/src/test/run-pass/unit-like-struct-drop-run.rs @@ -16,7 +16,7 @@ use std::task; struct Foo; impl Drop for Foo { - fn finalize(&self) { + fn drop(&self) { fail!("This failure should happen."); } } diff --git a/src/test/run-pass/unwind-resource.rs b/src/test/run-pass/unwind-resource.rs index 4b71d79ccc4..450e81bee33 100644 --- a/src/test/run-pass/unwind-resource.rs +++ b/src/test/run-pass/unwind-resource.rs @@ -19,7 +19,7 @@ struct complainer { } impl Drop for complainer { - fn finalize(&self) { + fn drop(&self) { error!("About to send!"); self.c.send(true); error!("Sent!"); diff --git a/src/test/run-pass/unwind-resource2.rs b/src/test/run-pass/unwind-resource2.rs index b5a496eb206..841fb37d29d 100644 --- a/src/test/run-pass/unwind-resource2.rs +++ b/src/test/run-pass/unwind-resource2.rs @@ -19,7 +19,7 @@ struct complainer { #[unsafe_destructor] impl Drop for complainer { - fn finalize(&self) {} + fn drop(&self) {} } fn complainer(c: @int) -> complainer { diff --git a/src/test/run-pass/use.rs b/src/test/run-pass/use.rs index d73eb6641fa..d73abc803cd 100644 --- a/src/test/run-pass/use.rs +++ b/src/test/run-pass/use.rs @@ -13,7 +13,7 @@ #[no_std]; extern mod std; extern mod zed(name = "std"); -extern mod bar(name = "std", vers = "0.7-pre"); +extern mod bar(name = "std", vers = "0.7"); use std::str; diff --git a/src/test/run-pass/vec-growth.rs b/src/test/run-pass/vec-growth.rs index 816228b62c6..c9a4c57cc9d 100644 --- a/src/test/run-pass/vec-growth.rs +++ b/src/test/run-pass/vec-growth.rs @@ -12,10 +12,10 @@ pub fn main() { let mut v = ~[1]; - v += ~[2]; - v += ~[3]; - v += ~[4]; - v += ~[5]; + v.push(2); + v.push(3); + v.push(4); + v.push(5); assert_eq!(v[0], 1); assert_eq!(v[1], 2); assert_eq!(v[2], 3); diff --git a/src/test/run-pass/vec-slice-drop.rs b/src/test/run-pass/vec-slice-drop.rs index 695441daf28..54626e52d23 100644 --- a/src/test/run-pass/vec-slice-drop.rs +++ b/src/test/run-pass/vec-slice-drop.rs @@ -15,7 +15,7 @@ struct foo { #[unsafe_destructor] impl Drop for foo { - fn finalize(&self) { + fn drop(&self) { unsafe { *self.x += 1; } diff --git a/src/test/run-pass/vec-slice.rs b/src/test/run-pass/vec-slice.rs index 8448e4e0532..e3012b08621 100644 --- a/src/test/run-pass/vec-slice.rs +++ b/src/test/run-pass/vec-slice.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::vec; - pub fn main() { let v = ~[1,2,3,4,5]; - let v2 = vec::slice(v, 1, 3); + let v2 = v.slice(1, 3); assert_eq!(v2[0], 2); assert_eq!(v2[1], 3); } diff --git a/src/test/run-pass/while-prelude-drop.rs b/src/test/run-pass/while-prelude-drop.rs index 082f2db259a..503e37fcd76 100644 --- a/src/test/run-pass/while-prelude-drop.rs +++ b/src/test/run-pass/while-prelude-drop.rs @@ -17,7 +17,7 @@ fn make(i: int) -> t { let mut s = ~"hello"; // Ensure s is non-const. - s += ~"there"; + s.push_str("there"); return b(s); } |
