diff options
100 files changed, 2058 insertions, 1829 deletions
diff --git a/doc/tutorial-container.md b/doc/tutorial-container.md index 1b195e99979..148afb4bda9 100644 --- a/doc/tutorial-container.md +++ b/doc/tutorial-container.md @@ -108,12 +108,14 @@ impl Iterator<int> for ZeroStream { ## Container iterators Containers implement iteration over the contained elements by returning an -iterator object. For example, vector slices have four iterators available: +iterator object. For example, vector slices several 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 +* `iter()` and `rev_iter()`, for immutable references to the elements +* `mut_iter()` and `mut_rev_iter()`, for mutable references to the elements +* `consume_iter()` and `consume_rev_iter`, to move the elements out by-value + +A typical mutable container will implement at least `iter()`, `mut_iter()` and +`consume_iter()` along with the reverse variants if it maintains an order. ### Freezing diff --git a/mk/target.mk b/mk/target.mk index 75482aed0d8..b9221a56b9d 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -84,6 +84,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)): \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): CFG_COMPILER_TRIPLE = $(2) $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): \ $$(COMPILER_CRATE) $$(COMPILER_INPUTS) \ + $$(TSREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)) \ | $$(TLIB$(1)_T_$(2)_H_$(3))/ @@ -94,6 +95,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): \ $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \ $$(DRIVER_CRATE) \ + $$(TSREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)) \ | $$(TBIN$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) diff --git a/mk/tests.mk b/mk/tests.mk index 770e7280491..9e0ccb5dbee 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -319,18 +319,21 @@ endif $(3)/stage$(1)/test/stdtest-$(2)$$(X_$(2)): \ $$(STDLIB_CRATE) $$(STDLIB_INPUTS) \ + $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(STDTESTDEP_$(1)_$(2)_$(3)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test $(3)/stage$(1)/test/extratest-$(2)$$(X_$(2)): \ $$(EXTRALIB_CRATE) $$(EXTRALIB_INPUTS) \ + $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(STDTESTDEP_$(1)_$(2)_$(3)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test $(3)/stage$(1)/test/syntaxtest-$(2)$$(X_$(2)): \ $$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \ + $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(STDTESTDEP_$(1)_$(2)_$(3)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test @@ -338,6 +341,7 @@ $(3)/stage$(1)/test/syntaxtest-$(2)$$(X_$(2)): \ $(3)/stage$(1)/test/rustctest-$(2)$$(X_$(2)): CFG_COMPILER_TRIPLE = $(2) $(3)/stage$(1)/test/rustctest-$(2)$$(X_$(2)): \ $$(COMPILER_CRATE) $$(COMPILER_INPUTS) \ + $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUSTLLVM_$(2)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) @$$(call E, compile_and_link: $$@) @@ -345,24 +349,28 @@ $(3)/stage$(1)/test/rustctest-$(2)$$(X_$(2)): \ $(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \ $$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS) \ + $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test $(3)/stage$(1)/test/rustitest-$(2)$$(X_$(2)): \ $$(RUSTI_LIB) $$(RUSTI_INPUTS) \ + $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test $(3)/stage$(1)/test/rusttest-$(2)$$(X_$(2)): \ $$(RUST_LIB) $$(RUST_INPUTS) \ + $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test $(3)/stage$(1)/test/rustdoctest-$(2)$$(X_$(2)): \ $$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS) \ + $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test @@ -537,6 +545,10 @@ TEST_SREQ$(1)_T_$(2)_H_$(3) = \ # Rules for the cfail/rfail/rpass/bench/perf test runner +# The tests select when to use debug configuration on their own; +# remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898). +CTEST_RUSTC_FLAGS = $$(subst --cfg debug,,$$(CFG_RUSTC_FLAGS)) + CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --compile-lib-path $$(HLIB$(1)_H_$(3)) \ --run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \ @@ -548,7 +560,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --target $(2) \ --adb-path=$(CFG_ADB) \ --adb-test-dir=$(CFG_ADB_TEST_DIR) \ - --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \ + --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CTEST_RUSTC_FLAGS) --target=$(2)" \ $$(CTEST_TESTARGS) CTEST_DEPS_rpass_$(1)-T-$(2)-H-$(3) = $$(RPASS_TESTS) diff --git a/mk/tools.mk b/mk/tools.mk index 5afabbcb336..56aad4f10a2 100644 --- a/mk/tools.mk +++ b/mk/tools.mk @@ -37,18 +37,14 @@ define TOOLS_STAGE_N_TARGET $$(TBIN$(1)_T_$(4)_H_$(3))/compiletest$$(X_$(4)): \ $$(COMPILETEST_CRATE) $$(COMPILETEST_INPUTS) \ - $$(TSREQ$(1)_T_$(4)_H_$(3)) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \ + $$(SREQ$(1)_T_$(4)_H_$(3)) \ | $$(TBIN$(1)_T_$(4)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)): \ $$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS) \ - $$(TSREQ$(1)_T_$(4)_H_$(3)) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \ + $$(SREQ$(1)_T_$(4)_H_$(3)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \ | $$(TLIB$(1)_T_$(4)_H_$(3))/ @$$(call E, compile_and_link: $$@) @@ -58,16 +54,15 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)): \ $$(TBIN$(1)_T_$(4)_H_$(3))/rustpkg$$(X_$(4)): \ $$(DRIVER_CRATE) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)) \ + $$(TSREQ$(1)_T_$(4)_H_$(3)) \ + $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)) \ | $$(TBIN$(1)_T_$(4)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rustpkg -o $$@ $$< $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)): \ $$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS) \ - $$(TSREQ$(1)_T_$(4)_H_$(3)) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \ + $$(SREQ$(1)_T_$(4)_H_$(3)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \ | $$(TLIB$(1)_T_$(4)_H_$(3))/ @$$(call E, compile_and_link: $$@) @@ -77,6 +72,7 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)): \ $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)): \ $$(DRIVER_CRATE) \ + $$(TSREQ$(1)_T_$(4)_H_$(3)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)) \ | $$(TBIN$(1)_T_$(4)_H_$(3))/ @$$(call E, compile_and_link: $$@) @@ -84,9 +80,7 @@ $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)): \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)): \ $$(RUSTI_LIB) $$(RUSTI_INPUTS) \ - $$(TSREQ$(1)_T_$(4)_H_$(3)) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \ + $$(SREQ$(1)_T_$(4)_H_$(3)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \ | $$(TLIB$(1)_T_$(4)_H_$(3))/ @$$(call E, compile_and_link: $$@) @@ -96,6 +90,7 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)): \ $$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X_$(4)): \ $$(DRIVER_CRATE) \ + $$(TSREQ$(1)_T_$(4)_H_$(3)) \ $$(TLIB$(1)_T_$(4)_H_$(4))/$(CFG_LIBRUSTI_$(4)) \ | $$(TBIN$(1)_T_$(4)_H_$(3))/ @$$(call E, compile_and_link: $$@) @@ -103,9 +98,7 @@ $$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X_$(4)): \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUST_$(4)): \ $$(RUST_LIB) $$(RUST_INPUTS) \ - $$(TSREQ$(1)_T_$(4)_H_$(3)) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \ + $$(SREQ$(1)_T_$(4)_H_$(3)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)) \ @@ -118,6 +111,7 @@ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUST_$(4)): \ $$(TBIN$(1)_T_$(4)_H_$(3))/rust$$(X_$(4)): \ $$(DRIVER_CRATE) \ + $$(TSREQ$(1)_T_$(4)_H_$(3)) \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUST_$(4)) \ | $$(TBIN$(1)_T_$(4)_H_$(3))/ @$$(call E, compile_and_link: $$@) diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 7cd73c82530..4b2f1850b79 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -681,7 +681,7 @@ fn make_out_name(config: &config, testfile: &Path, extension: &str) -> Path { } fn aux_output_dir_name(config: &config, testfile: &Path) -> Path { - output_base_name(config, testfile).with_filetype("libaux") + Path(output_base_name(config, testfile).to_str() + ".libaux") } fn output_testname(testfile: &Path) -> Path { diff --git a/src/etc/emacs/Makefile b/src/etc/emacs/Makefile deleted file mode 100644 index c79e7a9719b..00000000000 --- a/src/etc/emacs/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -E=@echo -TEMP=temp.el - -EMACS ?= emacs - -all: $(TEMP) - $(EMACS) -batch -q -no-site-file -l ./$(TEMP) -f rustmode-compile - rm -f $(TEMP) -$(TEMP): - $(E) '(setq load-path (cons "." load-path))' >> $(TEMP) - $(E) '(defun rustmode-compile () (mapcar (lambda (x) (byte-compile-file x))' >> $(TEMP) - $(E) ' (list "cm-mode.el" "rust-mode.el")))' >> $(TEMP) -clean: - rm -f *.elc $(TEMP) diff --git a/src/etc/emacs/README.md b/src/etc/emacs/README.md index 02c2c248d36..508ac7f1af2 100644 --- a/src/etc/emacs/README.md +++ b/src/etc/emacs/README.md @@ -13,21 +13,8 @@ file: (add-to-list 'load-path "/path/to/rust-mode/") (require 'rust-mode) -Make sure you byte-compile the .el files first, or the mode will be -painfully slow. There is an included `Makefile` which will do it for -you, so in the simplest case you can just run `make` and everything -should Just Work. - -If for some reason that doesn't work, you can byte compile manually, -by pasting this in your `*scratch*` buffer, moving the cursor below -it, and pressing `C-j`: - - (progn - (byte-compile-file "/path/to/rust-mode/cm-mode.el" t) - (byte-compile-file "/path/to/rust-mode/rust-mode.el" t)) - -Rust mode will automatically be associated with .rs and .rc files. To -enable it explicitly, do `M-x rust-mode`. +Rust mode will automatically be associated with .rs files. To enable it +explicitly, do `M-x rust-mode`. ### package.el installation via Marmalade or MELPA @@ -67,24 +54,6 @@ should upgrade in order to support installation from multiple sources. The ELPA archive is deprecated and no longer accepting new packages, so the version there (1.7.1) is very outdated. -#### Important - -In order to have cm-mode properly initialized after compilation prior -to rust-mode.el compilation you will need to add these `advices` to -your init file or if you are a melpa user install the `melpa` package. - -```lisp -(defadvice package-download-tar - (after package-download-tar-initialize activate compile) - "initialize the package after compilation" - (package-initialize)) - -(defadvice package-download-single - (after package-download-single-initialize activate compile) - "initialize the package after compilation" - (package-initialize)) -``` - #### Install rust-mode From there you can install rust-mode or any other modes by choosing diff --git a/src/etc/emacs/cm-mode.el b/src/etc/emacs/cm-mode.el deleted file mode 100644 index 0303f994172..00000000000 --- a/src/etc/emacs/cm-mode.el +++ /dev/null @@ -1,194 +0,0 @@ -;;; cm-mode.el --- Wrapper for CodeMirror-style Emacs modes - -;; Version: 0.1.0 -;; Author: Mozilla -;; Url: https://github.com/mozilla/rust -;; Highlighting is done by running a stateful parser (with first-class -;; state object) over the buffer, line by line, using the output to -;; add 'face properties, and storing the parser state at the end of -;; each line. Indentation is done based on the parser state at the -;; start of the line. - -(eval-when-compile (require 'cl)) - -;; Mode data structure - -(defun make-cm-mode (token &optional start-state copy-state - compare-state indent) - (vector token - (or start-state (lambda () 'null)) - (or copy-state 'cm-default-copy-state) - (or compare-state 'eq) - indent)) -(defmacro cm-mode-token (x) `(aref ,x 0)) -(defmacro cm-mode-start-state (x) `(aref ,x 1)) -(defmacro cm-mode-copy-state (x) `(aref ,x 2)) -(defmacro cm-mode-compare-state (x) `(aref ,x 3)) -(defmacro cm-mode-indent (x) `(aref ,x 4)) - -(defvar cm-cur-mode nil) -(defvar cm-worklist nil) - -(defun cm-default-copy-state (state) - (if (consp state) (copy-sequence state) state)) - -(defun cm-clear-work-items (from to) - (let ((prev-cons nil) - (rem cm-worklist)) - (while rem - (let ((pos (marker-position (car rem)))) - (cond ((or (< pos from) (> pos to)) (setf prev-cons rem)) - (prev-cons (setf (cdr prev-cons) (cdr rem))) - (t (setf cm-worklist (cdr rem)))) - (setf rem (cdr rem)))))) - -(defun cm-min-worklist-item () - (let ((rest cm-worklist) (min most-positive-fixnum)) - (while rest - (let ((pos (marker-position (car rest)))) - (when (< pos min) (setf min pos))) - (setf rest (cdr rest))) - min)) - -;; Indentation - -(defun cm-indent () - (let (indent-pos) - (save-excursion - (beginning-of-line) - (let* ((buf (current-buffer)) - (state (cm-preserve-state buf 'cm-state-for-point)) - (old-indent (current-indentation))) - (back-to-indentation) - (setf indent-pos (point)) - (let ((new-indent (funcall (cm-mode-indent cm-cur-mode) state))) - (unless (= old-indent new-indent) - (indent-line-to new-indent) - (setf indent-pos (point)) - (beginning-of-line) - (cm-preserve-state buf - (lambda () - (cm-highlight-line state) - (when (< (point) (point-max)) - (put-text-property (point) (+ (point) 1) 'cm-parse-state state)))))))) - (when (< (point) indent-pos) - (goto-char indent-pos)))) - -(defun cm-backtrack-to-state () - (let ((backtracked 0) - (min-indent most-positive-fixnum) - min-indented) - (loop - (when (= (point) (point-min)) - (return (funcall (cm-mode-start-state cm-cur-mode)))) - (let ((st (get-text-property (- (point) 1) 'cm-parse-state))) - (when (and st (save-excursion - (backward-char) - (beginning-of-line) - (not (looking-at "[ ]*$")))) - (return (funcall (cm-mode-copy-state cm-cur-mode) st)))) - (let ((i (current-indentation))) - (when (< i min-indent) - (setf min-indent i min-indented (point)))) - (when (> (incf backtracked) 30) - (goto-char min-indented) - (return (funcall (cm-mode-start-state cm-cur-mode)))) - (forward-line -1)))) - -(defun cm-state-for-point () - (let ((pos (point)) - (state (cm-backtrack-to-state))) - (while (< (point) pos) - (cm-highlight-line state) - (put-text-property (point) (+ (point) 1) 'cm-parse-state - (funcall (cm-mode-copy-state cm-cur-mode) state)) - (forward-char)) - state)) - -;; Highlighting - -(defun cm-highlight-line (state) - (let ((eol (point-at-eol))) - (remove-text-properties (point) eol '(face)) - (loop - (let ((p (point))) - (when (= p eol) (return)) - (let ((style (funcall (cm-mode-token cm-cur-mode) state))) - (when (= p (point)) (print (point)) (error "Nothing consumed.")) - (when (> p eol) (error "Parser moved past EOL")) - (when style - (put-text-property p (point) 'face style))))))) - -(defun cm-find-state-before-point () - (loop - (beginning-of-line) - (when (= (point) 1) - (return (funcall (cm-mode-start-state cm-cur-mode)))) - (let ((cur (get-text-property (- (point) 1) 'cm-parse-state))) - (when cur (return (funcall (cm-mode-copy-state cm-cur-mode) cur)))) - (backward-char))) - -(defun cm-schedule-work (delay) - (run-with-idle-timer delay nil 'cm-preserve-state (current-buffer) 'cm-do-some-work)) - -(defun cm-preserve-state (buffer f &rest args) - (with-current-buffer buffer - (let ((modified (buffer-modified-p)) - (buffer-undo-list t) - (inhibit-read-only t) - (inhibit-point-motion-hooks t) - (inhibit-modification-hooks t)) - (unwind-protect (apply f args) - (unless modified - (restore-buffer-modified-p nil)))))) - -(defun cm-do-some-work-inner () - (let ((end-time (time-add (current-time) (list 0 0 500))) - (quitting nil)) - (while (and (not quitting) cm-worklist) - (goto-char (cm-min-worklist-item)) - (let ((state (cm-find-state-before-point)) - (startpos (point)) - (timer-idle-list nil)) - (loop - (cm-highlight-line state) - (when (= (point) (point-max)) (return)) - (let ((old (get-text-property (point) 'cm-parse-state))) - (when (and old (funcall (cm-mode-compare-state cm-cur-mode) state old)) - (return)) - (put-text-property (point) (+ (point) 1) 'cm-parse-state - (funcall (cm-mode-copy-state cm-cur-mode) state))) - (when (or (let ((timer-idle-list nil)) (input-pending-p)) - (time-less-p end-time (current-time))) - (setf quitting t) (return)) - (forward-char)) - (cm-clear-work-items startpos (point))) - (when quitting - (push (copy-marker (+ (point) 1)) cm-worklist) - (cm-schedule-work 0.05))))) - -(defun cm-do-some-work () - (save-excursion - (condition-case cnd (cm-do-some-work-inner) - (error (print cnd) (error cnd))))) - -(defun cm-after-change-function (from to oldlen) - (cm-preserve-state (current-buffer) 'remove-text-properties from to '(cm-parse-state)) - (push (copy-marker from) cm-worklist) - (cm-schedule-work 0.2)) - -;; Entry function - -;;;###autoload -(defun cm-mode (mode) - (set (make-local-variable 'cm-cur-mode) mode) - (set (make-local-variable 'cm-worklist) (list (copy-marker 1))) - (when (cm-mode-indent mode) - (set (make-local-variable 'indent-line-function) 'cm-indent)) - (add-hook 'after-change-functions 'cm-after-change-function t t) - (add-hook 'after-revert-hook (lambda () (cm-after-change-function 1 (point-max) nil)) t t) - (cm-schedule-work 0.05)) - -(provide 'cm-mode) - -;;; cm-mode.el ends here diff --git a/src/etc/emacs/rust-mode.el b/src/etc/emacs/rust-mode.el index a1b8423ae3b..106cdbfd5f4 100644 --- a/src/etc/emacs/rust-mode.el +++ b/src/etc/emacs/rust-mode.el @@ -1,331 +1,222 @@ ;;; rust-mode.el --- A major emacs mode for editing Rust source code -;; Version: 0.1.0 +;; Version: 0.2.0 ;; Author: Mozilla -;; Package-Requires: ((cm-mode "0.1.0")) ;; Url: https://github.com/mozilla/rust -(require 'cm-mode) -(require 'cc-mode) (eval-when-compile (require 'cl)) -(defun rust-electric-brace (arg) - (interactive "*P") - (self-insert-command (prefix-numeric-value arg)) - (when (and c-electric-flag - (not (member (get-text-property (point) 'face) - '(font-lock-comment-face font-lock-string-face)))) - (cm-indent))) - -(defcustom rust-capitalized-idents-are-types t - "If non-nil, capitalized identifiers will be treated as types for the purposes of font-lock mode" - :type 'boolean - :require 'rust-mode - :group 'rust-mode) - -(defcustom rust-indent-unit 4 - "Amount of offset per level of indentation" - :type 'integer - :require 'rust-mode - :group 'rust-mode) - -(defvar rust-syntax-table (let ((table (make-syntax-table))) - (c-populate-syntax-table table) - table)) - -(defun make-rust-state () - (vector 'rust-token-base - (list (vector 'top (- rust-indent-unit) nil nil nil)) - 0 - nil)) -(defmacro rust-state-tokenize (x) `(aref ,x 0)) -(defmacro rust-state-context (x) `(aref ,x 1)) -(defmacro rust-state-indent (x) `(aref ,x 2)) -(defmacro rust-state-last-token (x) `(aref ,x 3)) - -(defmacro rust-context-type (x) `(aref ,x 0)) -(defmacro rust-context-indent (x) `(aref ,x 1)) -(defmacro rust-context-column (x) `(aref ,x 2)) -(defmacro rust-context-align (x) `(aref ,x 3)) -(defmacro rust-context-info (x) `(aref ,x 4)) - -(defun rust-push-context (st type &optional align-column auto-align) - (let ((ctx (vector type (rust-state-indent st) align-column - (if align-column (if auto-align t 'unset) nil) nil))) - (push ctx (rust-state-context st)) - ctx)) -(defun rust-pop-context (st) - (let ((old (pop (rust-state-context st)))) - (setf (rust-state-indent st) (rust-context-indent old)) - old)) -(defun rust-dup-context (st) - (let* ((list (rust-state-context st)) - (dup (copy-sequence (car list)))) - (setf (rust-state-context st) (cons dup (cdr list))) - dup)) - -(defvar rust-operator-chars "-+/%=<>!*&|@~^") -(defvar rust-punc-chars "()[].,{}:;") -(defvar rust-value-keywords - (let ((table (make-hash-table :test 'equal))) - (dolist (word '("mod" "const" "class" "type" - "trait" "struct" "fn" "enum" - "impl")) - (puthash word 'def table)) - (dolist (word '("as" "break" - "copy" "do" "drop" "else" - "extern" "for" "if" "let" "log" - "loop" "once" "priv" "pub" "pure" - "ref" "return" "static" "unsafe" "use" - "while" "while" - "assert" - "mut")) - (puthash word t table)) - (puthash "match" 'alt table) - (dolist (word '("self" "true" "false")) (puthash word 'atom table)) +;; Syntax definitions and helpers +(defvar rust-mode-syntax-table + (let ((table (make-syntax-table))) + + ;; Operators + (loop for i in '(?+ ?- ?* ?/ ?& ?| ?^ ?! ?< ?> ?~ ?@) + do (modify-syntax-entry i "." table)) + + ;; Strings + (modify-syntax-entry ?\" "\"" table) + (modify-syntax-entry ?\\ "\\" table) + + ;; _ is a word-char + (modify-syntax-entry ?_ "w" table) + + ;; Comments + (modify-syntax-entry ?/ ". 124b" table) + (modify-syntax-entry ?* ". 23" table) + (modify-syntax-entry ?\n "> b" table) + (modify-syntax-entry ?\^m "> b" table) + table)) -;; FIXME type-context keywords - -(defvar rust-tcat nil "Kludge for multiple returns without consing") - -(defmacro rust-eat-re (re) - `(when (looking-at ,re) (goto-char (match-end 0)) t)) - -(defvar rust-char-table - (let ((table (make-char-table 'syntax-table))) - (macrolet ((def (range &rest body) - `(let ((--b (lambda (st) ,@body))) - ,@(mapcar (lambda (elt) - (if (consp elt) - `(loop for ch from ,(car elt) to ,(cdr elt) collect - (set-char-table-range table ch --b)) - `(set-char-table-range table ',elt --b))) - (if (consp range) range (list range)))))) - (def t (forward-char) nil) - (def (32 ?\t) (skip-chars-forward " \t") nil) - (def ?\" (forward-char) - (rust-push-context st 'string (current-column) t) - (setf (rust-state-tokenize st) 'rust-token-string) - (rust-token-string st)) - (def ?\' (rust-single-quote)) - (def ?/ (forward-char) - (case (char-after) - (?/ (end-of-line) 'font-lock-comment-face) - (?* (forward-char) - (rust-push-context st 'comment) - (setf (rust-state-tokenize st) 'rust-token-comment) - (rust-token-comment st)) - (t (skip-chars-forward rust-operator-chars) (setf rust-tcat 'op) nil))) - (def ?# (forward-char) - (cond ((eq (char-after) ?\[) (forward-char) (setf rust-tcat 'open-attr)) - ((rust-eat-re "[a-z_]+") (setf rust-tcat 'macro))) - 'font-lock-preprocessor-face) - (def ((?a . ?z) (?A . ?Z) ?_) - (rust-token-identifier)) - (def ((?0 . ?9)) - (rust-eat-re "0x[0-9a-fA-F_]+\\|0b[01_]+\\|[0-9_]+\\(\\.[0-9_]+\\)?\\(e[+\\-]?[0-9_]+\\)?") - (setf rust-tcat 'atom) - (rust-eat-re "[iuf][0-9_]*") - 'font-lock-constant-face) - (def ?. (forward-char) - (cond ((rust-eat-re "[0-9]+\\(e[+\\-]?[0-9]+\\)?") - (setf rust-tcat 'atom) - (rust-eat-re "f[0-9]+") - 'font-lock-constant-face) - (t (setf rust-tcat (char-before)) nil))) - (def (?\( ?\) ?\[ ?\] ?\{ ?\} ?: ?\; ?,) - (forward-char) - (setf rust-tcat (char-before)) nil) - (def ?| - (skip-chars-forward rust-operator-chars) - (setf rust-tcat 'pipe) nil) - (def (?+ ?- ?% ?= ?< ?> ?! ?* ?& ?@ ?~) - (skip-chars-forward rust-operator-chars) - (setf rust-tcat 'op) nil) - table))) - -(defun rust-token-identifier () - (rust-eat-re "[a-zA-Z_][a-zA-Z0-9_]*") - (setf rust-tcat 'ident) - (if (and (eq (char-after) ?:) (eq (char-after (+ (point) 1)) ?:) - (not (eq (char-after (+ (point) 2)) ?:))) - (progn (forward-char 2) 'font-lock-builtin-face) - (match-string 0))) - -(defun rust-single-quote () - (forward-char) - (setf rust-tcat 'atom) - ; Is this a lifetime? - (if (or (looking-at "[a-zA-Z_]$") - (looking-at "[a-zA-Z_][^']")) - ; If what we see is 'abc, use font-lock-builtin-face: - (progn (rust-eat-re "[a-zA-Z_][a-zA-Z_0-9]*") - 'font-lock-builtin-face) - ; Otherwise, handle as a character constant: - (let ((is-escape (eq (char-after) ?\\)) - (start (point))) - (if (not (rust-eat-until-unescaped ?\')) - 'font-lock-warning-face - (if (or is-escape (= (point) (+ start 2))) - 'font-lock-string-face 'font-lock-warning-face))))) - -(defun rust-token-base (st) - (funcall (char-table-range rust-char-table (char-after)) st)) - -(defun rust-eat-until-unescaped (ch) - (let (escaped) - (loop - (let ((cur (char-after))) - (when (or (eq cur ?\n) (not cur)) (return nil)) - (forward-char) - (when (and (eq cur ch) (not escaped)) (return t)) - (setf escaped (and (not escaped) (eq cur ?\\))))))) - -(defun rust-token-string (st) - (setf rust-tcat 'atom) - (cond ((rust-eat-until-unescaped ?\") - (setf (rust-state-tokenize st) 'rust-token-base) - (rust-pop-context st)) - (t (let ((align (eq (char-before) ?\\))) - (unless (eq align (rust-context-align (car (rust-state-context st)))) - (setf (rust-context-align (rust-dup-context st)) align))))) - 'font-lock-string-face) - -(defun rust-token-comment (st) - (let ((eol (point-at-eol))) - (loop - (unless (re-search-forward "\\(/\\*\\)\\|\\(\\*/\\)" eol t) - (goto-char eol) - (return)) - (if (match-beginning 1) - (push (car (rust-state-context st)) (rust-state-context st)) - (rust-pop-context st) - (unless (eq (rust-context-type (car (rust-state-context st))) 'comment) - (setf (rust-state-tokenize st) 'rust-token-base) - (return)))) - 'font-lock-comment-face)) - -(defun rust-next-block-info (st) - (dolist (cx (rust-state-context st)) - (when (eq (rust-context-type cx) ?\}) (return (rust-context-info cx))))) - -(defun rust-is-capitalized (string) - (let ((case-fold-search nil)) - (string-match-p "[A-Z]" string))) - -(defun rust-token (st) - (let ((cx (car (rust-state-context st)))) - (when (bolp) - (setf (rust-state-indent st) (current-indentation)) - (when (eq (rust-context-align cx) 'unset) - (setf (rust-context-align cx) nil))) - (setf rust-tcat nil) - (let* ((tok (funcall (rust-state-tokenize st) st)) - (tok-id (or tok rust-tcat)) - (cur-cx (rust-context-type cx)) - (cx-info (rust-context-info cx))) - (when (stringp tok) - (setf tok-id (gethash tok rust-value-keywords nil)) - (setf tok (cond ((eq tok-id 'atom) 'font-lock-constant-face) - (tok-id 'font-lock-keyword-face) - ((equal (rust-state-last-token st) 'def) 'font-lock-function-name-face) - ((and rust-capitalized-idents-are-types - (rust-is-capitalized tok)) 'font-lock-type-face) - (t nil)))) - (when rust-tcat - (when (eq (rust-context-align cx) 'unset) - (setf (rust-context-align cx) t)) - (when (eq cx-info 'alt-1) - (setf cx (rust-dup-context st)) - (setf (rust-context-info cx) 'alt-2)) - (when (and (eq rust-tcat 'pipe) (eq (rust-state-last-token st) ?{)) - (setf cx (rust-dup-context st)) - (setf (rust-context-info cx) 'block)) - (case rust-tcat - ((?\; ?,) (when (eq cur-cx 'statement) (rust-pop-context st))) - (?\{ - (when (and (eq cur-cx 'statement) (not (member cx-info '(alt-1 alt-2)))) - (rust-pop-context st)) - (when (eq cx-info 'alt-2) - (setf cx (rust-dup-context st)) - (setf (rust-context-info cx) nil)) - (let ((next-info (rust-next-block-info st)) - (newcx (rust-push-context st ?\} (current-column)))) - (cond ((eq cx-info 'alt-2) (setf (rust-context-info newcx) 'alt-outer)) - ((eq next-info 'alt-outer) (setf (rust-context-info newcx) 'alt-inner))))) - ((?\[ open-attr) - (let ((newcx (rust-push-context st ?\] (current-column)))) - (when (eq rust-tcat 'open-attr) - (setf (rust-context-info newcx) 'attr)))) - (?\( (rust-push-context st ?\) (current-column)) - (when (eq (rust-context-info cx) 'attr) - (setf (rust-context-info (car (rust-state-context st))) 'attr))) - (?\} (when (eq cur-cx 'statement) (rust-pop-context st)) - (when (eq (rust-context-type (car (rust-state-context st))) ?}) - (rust-pop-context st)) - (setf cx (car (rust-state-context st))) - (when (and (eq (rust-context-type cx) 'statement) - (not (eq (rust-context-info cx) 'alt-2))) - (rust-pop-context st))) - (t (cond ((eq cur-cx rust-tcat) - (when (eq (rust-context-info (rust-pop-context st)) 'attr) - (setf tok 'font-lock-preprocessor-face) - (when (eq (rust-context-type (car (rust-state-context st))) 'statement) - (rust-pop-context st)))) - ((or (and (eq cur-cx ?\}) (not (eq (rust-context-info cx) 'alt-outer))) - (eq cur-cx 'top)) - (rust-push-context st 'statement))))) - (setf (rust-state-last-token st) tok-id)) - (setf cx (car (rust-state-context st))) - (when (and (eq tok-id 'alt) (eq (rust-context-type cx) 'statement)) - (setf (rust-context-info cx) 'alt-1)) - (when (and (eq (rust-state-last-token st) 'pipe) - (eq (rust-next-block-info st) 'block) (eolp)) - (when (eq (rust-context-type cx) 'statement) (rust-pop-context st)) - (setf cx (rust-dup-context st) - (rust-context-info cx) nil - (rust-context-align cx) nil)) - (if (eq (rust-context-info cx) 'attr) - 'font-lock-preprocessor-face - tok)))) - -(defun rust-indent (st) - (let ((cx (car (rust-state-context st))) - (parent (cadr (rust-state-context st)))) - (when (and (eq (rust-context-type cx) 'statement) - (or (eq (char-after) ?\}) (looking-at "with \\|{[ ]*$"))) - (setf cx parent parent (caddr (rust-state-context st)))) - (let* ((tp (rust-context-type cx)) - (closing (eq tp (char-after))) - (unit rust-indent-unit) - (base (if (and (eq tp 'statement) parent (rust-context-align parent)) - (rust-context-column parent) (rust-context-indent cx)))) - (cond ((eq tp 'comment) base) - ((eq tp 'string) (if (rust-context-align cx) (rust-context-column cx) 0)) - ((eq tp 'statement) (+ base (if (eq (char-after) ?\}) 0 unit))) - ((eq (rust-context-align cx) t) (+ (rust-context-column cx) (if closing -1 0))) - (t (+ base (if closing 0 unit))))))) + +(defun rust-paren-level () (nth 0 (syntax-ppss))) +(defun rust-in-str-or-cmnt () (nth 8 (syntax-ppss))) +(defun rust-rewind-past-str-cmnt () (goto-char (nth 8 (syntax-ppss)))) +(defun rust-rewind-irrelevant () + (let ((starting (point))) + (skip-chars-backward "[:space:]\n") + (if (looking-back "\\*/") (backward-char)) + (if (rust-in-str-or-cmnt) + (rust-rewind-past-str-cmnt)) + (if (/= starting (point)) + (rust-rewind-irrelevant)))) + +(defun rust-mode-indent-line () + (interactive) + (let ((indent + (save-excursion + (back-to-indentation) + (let ((level (rust-paren-level))) + (cond + ;; A function return type is 1 level indented + ((looking-at "->") (* default-tab-width (+ level 1))) + + ;; A closing brace is 1 level unindended + ((looking-at "}") (* default-tab-width (- level 1))) + + ;; If we're in any other token-tree / sexp, then: + ;; - [ or ( means line up with the opening token + ;; - { means indent to either nesting-level * tab width, + ;; or one further indent from that if either current line + ;; begins with 'else', or previous line didn't end in + ;; semi, comma or brace, and wasn't an attribute. PHEW. + ((> level 0) + (let ((pt (point))) + (rust-rewind-irrelevant) + (backward-up-list) + (if (looking-at "[[(]") + (+ 1 (current-column)) + (progn + (goto-char pt) + (back-to-indentation) + (if (looking-at "\\<else\\>") + (* default-tab-width (+ 1 level)) + (progn + (goto-char pt) + (beginning-of-line) + (rust-rewind-irrelevant) + (end-of-line) + (if (looking-back "[{};,]") + (* default-tab-width level) + (back-to-indentation) + (if (looking-at "#") + (* default-tab-width level) + (* default-tab-width (+ 1 level)))))))))) + + ;; Otherwise we're in a column-zero definition + (t 0)))))) + (cond + ;; If we're to the left of the indentation, reindent and jump to it. + ((<= (current-column) indent) + (indent-line-to indent)) + + ;; We're to the right; if it needs indent, do so but save excursion. + ((not (eq (current-indentation) indent)) + (save-excursion (indent-line-to indent)))))) + + +;; Font-locking definitions and helpers +(defconst rust-mode-keywords + '("as" + "break" + "do" + "else" "enum" "extern" + "false" "fn" "for" + "if" "impl" + "let" "loop" + "match" "mod" "mut" + "priv" "pub" + "ref" "return" + "self" "static" "struct" "super" + "true" "trait" "type" + "unsafe" "use" + "while")) + +(defconst rust-special-types + '("u8" "i8" + "u16" "i16" + "u32" "i32" + "u64" "i64" + + "f32" "f64" + "float" "int" "uint" + "bool" + "str" "char")) + +(defconst rust-re-ident "[[:word:][:multibyte:]_][[:word:][:multibyte:]_[:digit:]]*") +(defconst rust-re-CamelCase "[[:upper:]][[:word:][:multibyte:]_[:digit:]]*") +(defun rust-re-word (inner) (concat "\\<" inner "\\>")) +(defun rust-re-grab (inner) (concat "\\(" inner "\\)")) +(defun rust-re-grabword (inner) (rust-re-grab (rust-re-word inner))) +(defun rust-re-item-def (itype) + (concat (rust-re-word itype) "[[:space:]]+" (rust-re-grab rust-re-ident))) + +(defvar rust-mode-font-lock-keywords + (append + `( + ;; Keywords proper + (,(regexp-opt rust-mode-keywords 'words) . font-lock-keyword-face) + + ;; Special types + (,(regexp-opt rust-special-types 'words) . font-lock-type-face) + + ;; Attributes like `#[bar(baz)]` + (,(rust-re-grab (concat "#\\[" rust-re-ident "[^]]*\\]")) + 1 font-lock-preprocessor-face) + + ;; Syntax extension invocations like `foo!`, highlight including the ! + (,(concat (rust-re-grab (concat rust-re-ident "!")) "[({[:space:]]") + 1 font-lock-preprocessor-face) + + ;; Field names like `foo:`, highlight excluding the : + (,(concat (rust-re-grab rust-re-ident) ":[^:]") 1 font-lock-variable-name-face) + + ;; Module names like `foo::`, highlight including the :: + (,(rust-re-grab (concat rust-re-ident "::")) 1 font-lock-type-face) + + ;; Lifetimes like `'foo` + (,(concat "'" (rust-re-grab rust-re-ident) "[^']") 1 font-lock-variable-name-face) + + ;; Character constants, since they're not treated as strings + ;; in order to have sufficient leeway to parse 'lifetime above. + (,(rust-re-grab "'[^']'") 1 font-lock-string-face) + (,(rust-re-grab "'\\\\[nrt]'") 1 font-lock-string-face) + (,(rust-re-grab "'\\\\x[[:xdigit:]]\\{2\\}'") 1 font-lock-string-face) + (,(rust-re-grab "'\\\\u[[:xdigit:]]\\{4\\}'") 1 font-lock-string-face) + (,(rust-re-grab "'\\\\U[[:xdigit:]]\\{8\\}'") 1 font-lock-string-face) + + ;; CamelCase Means Type Or Constructor + (,(rust-re-grabword rust-re-CamelCase) 1 font-lock-type-face) + ) + + ;; Item definitions + (loop for (item . face) in + + '(("enum" . font-lock-type-face) + ("struct" . font-lock-type-face) + ("type" . font-lock-type-face) + ("mod" . font-lock-type-face) + ("use" . font-lock-type-face) + ("fn" . font-lock-function-name-face) + ("static" . font-lock-constant-face)) + + collect `(,(rust-re-item-def item) 1 ,face)))) + + +;; For compatibility with Emacs < 24, derive conditionally +(defalias 'rust-parent-mode + (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode)) + ;;;###autoload -(define-derived-mode rust-mode fundamental-mode "Rust" - "Major mode for editing Rust source files." - (set-syntax-table rust-syntax-table) - (setq major-mode 'rust-mode mode-name "Rust") - (run-hooks 'rust-mode-hook) - (set (make-local-variable 'indent-tabs-mode) nil) - (let ((par "[ ]*\\(//+\\|\\**\\)[ ]*$")) - (set (make-local-variable 'paragraph-start) par) - (set (make-local-variable 'paragraph-separate) par)) - (set (make-local-variable 'comment-start) "//") - (cm-mode (make-cm-mode 'rust-token 'make-rust-state 'copy-sequence 'equal 'rust-indent))) - -(define-key rust-mode-map "}" 'rust-electric-brace) -(define-key rust-mode-map "{" 'rust-electric-brace) +(define-derived-mode rust-mode rust-parent-mode "Rust" + "Major mode for Rust code." + + ;; Basic syntax + (set-syntax-table rust-mode-syntax-table) + + ;; Indentation + (set (make-local-variable 'indent-line-function) + 'rust-mode-indent-line) + + ;; Fonts + (set (make-local-variable 'font-lock-defaults) + '(rust-mode-font-lock-keywords nil nil nil nil)) + + ;; Misc + (set (make-local-variable 'comment-start) "// ") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'indent-tabs-mode) nil)) + ;;;###autoload -(progn - (add-to-list 'auto-mode-alist '("\\.rs$" . rust-mode)) - (add-to-list 'auto-mode-alist '("\\.rc$" . rust-mode))) +(add-to-list 'auto-mode-alist '("\\.rs$" . rust-mode)) + +(defun rust-mode-reload () + (interactive) + (unload-feature 'rust-mode) + (require 'rust-mode) + (rust-mode)) (provide 'rust-mode) diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index d940b6d6667..46a74457274 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -732,6 +732,11 @@ impl Ord for Sign { } } +impl TotalEq for Sign { + fn equals(&self, other: &Sign) -> bool { + *self == *other + } +} impl TotalOrd for Sign { fn cmp(&self, other: &Sign) -> Ordering { diff --git a/src/libextra/num/rational.rs b/src/libextra/num/rational.rs index 6733599d1ea..ff14009e556 100644 --- a/src/libextra/num/rational.rs +++ b/src/libextra/num/rational.rs @@ -110,6 +110,25 @@ cmp_impl!(impl TotalEq, equals) cmp_impl!(impl Ord, lt, gt, le, ge) cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering) +impl<T: Clone + Integer + Ord> Orderable for Ratio<T> { + #[inline] + fn min(&self, other: &Ratio<T>) -> Ratio<T> { + if *self < *other { self.clone() } else { other.clone() } + } + + #[inline] + fn max(&self, other: &Ratio<T>) -> Ratio<T> { + if *self > *other { self.clone() } else { other.clone() } + } + + #[inline] + fn clamp(&self, mn: &Ratio<T>, mx: &Ratio<T>) -> Ratio<T> { + if *self > *mx { mx.clone()} else + if *self < *mn { mn.clone() } else { self.clone() } + } +} + + /* Arithmetic */ // a/b * c/d = (a*c)/(b*d) impl<T: Clone + Integer + Ord> diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 645188ce5a4..1c5d202d4d9 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -180,6 +180,7 @@ pub static tag_misc_info: uint = 0x7f; pub static tag_misc_info_crate_items: uint = 0x80; pub static tag_item_method_provided_source: uint = 0x81; +pub static tag_item_impl_vtables: uint = 0x82; pub struct LinkMeta { name: @str, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 97344ee91ad..6f7feae4479 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -16,6 +16,7 @@ use metadata::cstore; use metadata::decoder; use metadata; use middle::ty; +use middle::typeck; use std::vec; use reader = extra::ebml::reader; @@ -216,6 +217,14 @@ pub fn get_impl_trait(tcx: ty::ctxt, decoder::get_impl_trait(cdata, def.node, tcx) } +// Given a def_id for an impl, return information about its vtables +pub fn get_impl_vtables(tcx: ty::ctxt, + def: ast::def_id) -> typeck::impl_res { + let cstore = tcx.cstore; + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_impl_vtables(cdata, def.node, tcx) +} + pub fn get_impl_method(cstore: @mut cstore::CStore, def: ast::def_id, mname: ast::ident) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 6e166cfbfc8..01c5019154f 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -21,9 +21,12 @@ use metadata::tydecode::{parse_ty_data, parse_def_id, parse_type_param_def_data, parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::ty; +use middle::typeck; +use middle::astencode::vtable_decoder_helpers; + use std::hash::HashUtil; -use std::int; +use std::uint; use std::io::WriterUtil; use std::io; use std::option; @@ -200,9 +203,9 @@ fn each_reexport(d: ebml::Doc, f: &fn(ebml::Doc) -> bool) -> bool { return true; } -fn variant_disr_val(d: ebml::Doc) -> Option<int> { +fn variant_disr_val(d: ebml::Doc) -> Option<uint> { do reader::maybe_get_doc(d, tag_disr_val).chain |val_doc| { - do reader::with_doc_data(val_doc) |data| { int::parse_bytes(data, 10u) } + do reader::with_doc_data(val_doc) |data| { uint::parse_bytes(data, 10u) } } } @@ -410,6 +413,21 @@ pub fn get_impl_trait(cdata: cmd, } } +pub fn get_impl_vtables(cdata: cmd, + id: ast::node_id, + tcx: ty::ctxt) -> typeck::impl_res +{ + let item_doc = lookup_item(id, cdata.data); + let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables); + let mut decoder = reader::Decoder(vtables_doc); + + typeck::impl_res { + trait_vtables: decoder.read_vtable_res(tcx, cdata), + self_vtables: decoder.read_vtable_param_res(tcx, cdata) + } +} + + pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, name: ast::ident) -> Option<ast::def_id> { let items = reader::get_doc(reader::Doc(cdata.data), tag_items); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 78e1a579d74..d6287d457c1 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -17,11 +17,12 @@ use metadata::decoder; use metadata::tyencode; use middle::ty::{node_id_to_type, lookup_item_type}; use middle::ty; +use middle::typeck; +use middle::astencode; use middle; use std::hash::HashUtil; use std::hashmap::{HashMap, HashSet}; -use std::int; use std::io; use std::str; use std::uint; @@ -162,6 +163,15 @@ fn encode_trait_ref(ebml_w: &mut writer::Encoder, ebml_w.end_tag(); } +fn encode_impl_vtables(ebml_w: &mut writer::Encoder, + ecx: &EncodeContext, + vtables: &typeck::impl_res) { + ebml_w.start_tag(tag_item_impl_vtables); + astencode::encode_vtable_res(ecx, ebml_w, vtables.trait_vtables); + astencode::encode_vtable_param_res(ecx, ebml_w, vtables.self_vtables); + ebml_w.end_tag(); +} + // Item info table encoding fn encode_family(ebml_w: &mut writer::Encoder, c: char) { ebml_w.start_tag(tag_items_data_item_family); @@ -290,9 +300,9 @@ fn encode_discriminant(ecx: &EncodeContext, fn encode_disr_val(_: &EncodeContext, ebml_w: &mut writer::Encoder, - disr_val: int) { + disr_val: uint) { ebml_w.start_tag(tag_disr_val); - let s = int::to_str(disr_val); + let s = uint::to_str(disr_val); ebml_w.writer.write(s.as_bytes()); ebml_w.end_tag(); } @@ -1009,6 +1019,8 @@ fn encode_info_for_item(ecx: &EncodeContext, let trait_ref = ty::node_id_to_trait_ref( tcx, ast_trait_ref.ref_id); encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref); + let impl_vtables = ty::lookup_impl_vtables(tcx, def_id); + encode_impl_vtables(ebml_w, ecx, &impl_vtables); } encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); ebml_w.end_tag(); @@ -1443,6 +1455,9 @@ fn encode_lang_items(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.start_tag(tag_lang_items); for ecx.tcx.lang_items.each_item |def_id, i| { + let def_id = match def_id { + Some(id) => id, None => { loop } + }; if def_id.crate != local_crate { loop; } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 1edd3c805d0..89b30e46ac0 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -186,7 +186,7 @@ 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 regions = parse_region_substs(st); let self_ty = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)) ); @@ -196,12 +196,28 @@ fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs { st.pos = st.pos + 1u; return ty::substs { - self_r: self_r, + regions: regions, self_ty: self_ty, tps: params }; } +fn parse_region_substs(st: &mut PState) -> ty::RegionSubsts { + match next(st) { + 'e' => ty::ErasedRegions, + 'n' => { + let mut regions = opt_vec::Empty; + while peek(st) != '.' { + let r = parse_region(st); + regions.push(r); + } + assert_eq!(next(st), '.'); + ty::NonerasedRegions(regions) + } + _ => fail!("parse_bound_region: bad input") + } +} + fn parse_bound_region(st: &mut PState) -> ty::bound_region { match next(st) { 's' => ty::br_self, diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index bab13c2b470..a1cb1bf6848 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -120,13 +120,28 @@ fn enc_opt<T>(w: @io::Writer, t: Option<T>, enc_f: &fn(T)) { } fn enc_substs(w: @io::Writer, cx: @ctxt, substs: &ty::substs) { - do enc_opt(w, substs.self_r) |r| { enc_region(w, cx, r) } + enc_region_substs(w, cx, &substs.regions); do enc_opt(w, substs.self_ty) |t| { enc_ty(w, cx, t) } w.write_char('['); for substs.tps.iter().advance |t| { enc_ty(w, cx, *t); } w.write_char(']'); } +fn enc_region_substs(w: @io::Writer, cx: @ctxt, substs: &ty::RegionSubsts) { + match *substs { + ty::ErasedRegions => { + w.write_char('e'); + } + ty::NonerasedRegions(ref regions) => { + w.write_char('n'); + for regions.iter().advance |&r| { + enc_region(w, cx, r); + } + w.write_char('.'); + } + } +} + fn enc_region(w: @io::Writer, cx: @ctxt, r: ty::Region) { match r { ty::re_bound(br) => { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index f3e0779475c..bf39be407c5 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -250,6 +250,8 @@ impl<S:serialize::Encoder> def_id_encoder_helpers for S { trait def_id_decoder_helpers { fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id; + fn read_def_id_noxcx(&mut self, + cdata: @cstore::crate_metadata) -> ast::def_id; } impl<D:serialize::Decoder> def_id_decoder_helpers for D { @@ -257,6 +259,12 @@ impl<D:serialize::Decoder> def_id_decoder_helpers for D { let did: ast::def_id = Decodable::decode(self); did.tr(xcx) } + + fn read_def_id_noxcx(&mut self, + cdata: @cstore::crate_metadata) -> ast::def_id { + let did: ast::def_id = Decodable::decode(self); + decoder::translate_def_id(cdata, did) + } } // ______________________________________________________________________ @@ -582,12 +590,6 @@ impl tr for method_origin { typeck::method_trait(did, m, vstore) => { typeck::method_trait(did.tr(xcx), m, vstore) } - typeck::method_self(did, m) => { - typeck::method_self(did.tr(xcx), m) - } - typeck::method_super(trait_did, m) => { - typeck::method_super(trait_did.tr(xcx), m) - } } } } @@ -595,7 +597,7 @@ impl tr for method_origin { // ______________________________________________________________________ // Encoding and decoding vtable_res -fn encode_vtable_res(ecx: &e::EncodeContext, +pub fn encode_vtable_res(ecx: &e::EncodeContext, ebml_w: &mut writer::Encoder, dr: typeck::vtable_res) { // can't autogenerate this code because automatic code of @@ -603,13 +605,20 @@ fn encode_vtable_res(ecx: &e::EncodeContext, // hand-written encoding routines combine with auto-generated // ones. perhaps we should fix this. 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) - } + encode_vtable_param_res(ecx, ebml_w, *param_tables); } } -fn encode_vtable_origin(ecx: &e::EncodeContext, +pub fn encode_vtable_param_res(ecx: &e::EncodeContext, + ebml_w: &mut writer::Encoder, + param_tables: typeck::vtable_param_res) { + do ebml_w.emit_from_vec(*param_tables) |ebml_w, vtable_origin| { + encode_vtable_origin(ecx, ebml_w, vtable_origin) + } +} + + +pub fn encode_vtable_origin(ecx: &e::EncodeContext, ebml_w: &mut writer::Encoder, vtable_origin: &typeck::vtable_origin) { do ebml_w.emit_enum("vtable_origin") |ebml_w| { @@ -630,40 +639,46 @@ fn encode_vtable_origin(ecx: &e::EncodeContext, typeck::vtable_param(pn, bn) => { do ebml_w.emit_enum_variant("vtable_param", 1u, 2u) |ebml_w| { do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { - ebml_w.emit_uint(pn); + pn.encode(ebml_w); } do ebml_w.emit_enum_variant_arg(1u) |ebml_w| { ebml_w.emit_uint(bn); } } } - 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) - } - } - } } } } -trait vtable_decoder_helpers { - fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) +pub trait vtable_decoder_helpers { + fn read_vtable_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_res; - fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) + fn read_vtable_param_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) + -> typeck::vtable_param_res; + fn read_vtable_origin(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_origin; } impl vtable_decoder_helpers for reader::Decoder { - fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) + fn read_vtable_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_res { @self.read_to_vec(|this| - @this.read_to_vec(|this| - this.read_vtable_origin(xcx))) + this.read_vtable_param_res(tcx, cdata)) } - fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) + fn read_vtable_param_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) + -> typeck::vtable_param_res { + @self.read_to_vec(|this| + this.read_vtable_origin(tcx, cdata)) + } + + fn read_vtable_origin(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_origin { do self.read_enum("vtable_origin") |this| { do this.read_enum_variant(["vtable_static", @@ -674,33 +689,26 @@ impl vtable_decoder_helpers for reader::Decoder { 0 => { typeck::vtable_static( do this.read_enum_variant_arg(0u) |this| { - this.read_def_id(xcx) + this.read_def_id_noxcx(cdata) }, do this.read_enum_variant_arg(1u) |this| { - this.read_tys(xcx) + this.read_tys_noxcx(tcx, cdata) }, do this.read_enum_variant_arg(2u) |this| { - this.read_vtable_res(xcx) + this.read_vtable_res(tcx, cdata) } ) } 1 => { typeck::vtable_param( do this.read_enum_variant_arg(0u) |this| { - this.read_uint() + Decodable::decode(this) }, do this.read_enum_variant_arg(1u) |this| { this.read_uint() } ) } - 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") } @@ -995,9 +1003,35 @@ trait ebml_decoder_decoder_helpers { source: DefIdSource, did: ast::def_id) -> ast::def_id; + + // Versions of the type reading functions that don't need the full + // ExtendedDecodeContext. + fn read_ty_noxcx(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t; + fn read_tys_noxcx(&mut self, + tcx: ty::ctxt, + cdata: @cstore::crate_metadata) -> ~[ty::t]; } impl ebml_decoder_decoder_helpers for reader::Decoder { + fn read_ty_noxcx(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t { + do self.read_opaque |_, doc| { + tydecode::parse_ty_data( + *doc.data, + cdata.cnum, + doc.start, + tcx, + |_, id| decoder::translate_def_id(cdata, id)) + } + } + + fn read_tys_noxcx(&mut self, + tcx: ty::ctxt, + cdata: @cstore::crate_metadata) -> ~[ty::t] { + self.read_to_vec(|this| this.read_ty_noxcx(tcx, cdata) ) + } + fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode @@ -1160,8 +1194,9 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, val_dsr.read_method_map_entry(xcx)); } c::tag_table_vtable_map => { - dcx.maps.vtable_map.insert(id, - val_dsr.read_vtable_res(xcx)); + dcx.maps.vtable_map.insert( + id, + val_dsr.read_vtable_res(xcx.dcx.tcx, xcx.dcx.cdata)); } c::tag_table_adjustments => { let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr); diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 36edb567a50..793cd374718 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -10,7 +10,7 @@ use middle::const_eval::{compare_const_vals, lookup_const_by_id}; -use middle::const_eval::{eval_const_expr, const_val, const_bool}; +use middle::const_eval::{eval_const_expr, const_val, const_bool, const_float}; use middle::pat_util::*; use middle::ty::*; use middle::ty; @@ -102,6 +102,27 @@ pub fn check_arms(cx: &MatchCheckCtxt, arms: &[arm]) { let mut seen = ~[]; for arms.iter().advance |arm| { for arm.pats.iter().advance |pat| { + + // Check that we do not match against a static NaN (#6804) + let pat_matches_nan: &fn(@pat) -> bool = |p| { + match cx.tcx.def_map.find(&p.id) { + Some(&def_static(did, false)) => { + let const_expr = lookup_const_by_id(cx.tcx, did).get(); + match eval_const_expr(cx.tcx, const_expr) { + const_float(f) if f.is_NaN() => true, + _ => false + } + } + _ => false + } + }; + for walk_pat(*pat) |p| { + if pat_matches_nan(p) { + cx.tcx.sess.span_warn(p.span, "unmatchable NaN in pattern, \ + use the is_NaN method in a guard instead"); + } + } + let v = ~[*pat]; match is_useful(cx, &seen, v) { not_useful => { diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index eb9d18c9b24..99aae34911b 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -19,6 +19,7 @@ use util::ppaux::UserString; use syntax::ast::*; use syntax::attr; use syntax::codemap::span; +use syntax::opt_vec; use syntax::print::pprust::expr_to_str; use syntax::{visit, ast_util}; @@ -83,7 +84,7 @@ fn check_struct_safe_for_destructor(cx: Context, let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did); if !struct_tpt.generics.has_type_params() { let struct_ty = ty::mk_struct(cx.tcx, struct_did, ty::substs { - self_r: None, + regions: ty::NonerasedRegions(opt_vec::Empty), self_ty: None, tps: ~[] }); diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 6bc4564bb13..54e7a2fd7e7 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -92,8 +92,8 @@ impl LanguageItems { } } - pub fn each_item(&self, f: &fn(def_id: def_id, i: uint) -> bool) -> bool { - self.items.iter().enumerate().advance(|(i, &item)| f(item.get(), i)) + pub fn each_item(&self, f: &fn(Option<def_id>, uint) -> bool) -> bool { + self.items.iter().enumerate().advance(|(i, &item)| f(item, i)) } pub fn item_name(index: uint) -> &'static str { diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 4bcb40a5fba..aaf0460a4e1 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -79,7 +79,6 @@ pub enum lint { non_camel_case_types, non_uppercase_statics, type_limits, - default_methods, unused_unsafe, managed_heap_memory, @@ -222,13 +221,6 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ default: warn }), - ("default_methods", - LintSpec { - lint: default_methods, - desc: "allow default methods", - default: allow - }), - ("unused_unsafe", LintSpec { lint: unused_unsafe, @@ -690,23 +682,6 @@ fn lint_type_limits() -> visit::vt<@mut Context> { }) } -fn check_item_default_methods(cx: &Context, item: &ast::item) { - match item.node { - ast::item_trait(_, _, ref methods) => { - for methods.iter().advance |method| { - match *method { - ast::required(*) => {} - ast::provided(*) => { - cx.span_lint(default_methods, item.span, - "default methods are experimental"); - } - } - } - } - _ => {} - } -} - fn check_item_ctypes(cx: &Context, it: &ast::item) { fn check_ty(cx: &Context, ty: &ast::Ty) { match ty.node { @@ -852,23 +827,26 @@ fn check_item_non_camel_case_types(cx: &Context, it: &ast::item) { !ident.contains_char('_') } - fn check_case(cx: &Context, ident: ast::ident, span: span) { + fn check_case(cx: &Context, sort: &str, ident: ast::ident, span: span) { if !is_camel_case(cx.tcx, ident) { - cx.span_lint(non_camel_case_types, span, - "type, variant, or trait should have \ - a camel case identifier"); + cx.span_lint( + non_camel_case_types, span, + fmt!("%s `%s` should have a camel case identifier", + sort, cx.tcx.sess.str_of(ident))); } } match it.node { - ast::item_ty(*) | ast::item_struct(*) | + ast::item_ty(*) | ast::item_struct(*) => { + check_case(cx, "type", it.ident, it.span) + } ast::item_trait(*) => { - check_case(cx, it.ident, it.span) + check_case(cx, "trait", it.ident, it.span) } ast::item_enum(ref enum_definition, _) => { - check_case(cx, it.ident, it.span); + check_case(cx, "type", it.ident, it.span); for enum_definition.variants.iter().advance |variant| { - check_case(cx, variant.node.name, variant.span); + check_case(cx, "variant", variant.node.name, variant.span); } } _ => () @@ -1143,7 +1121,6 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::Crate) { check_item_ctypes(cx, it); check_item_non_camel_case_types(cx, it); check_item_non_uppercase_statics(cx, it); - check_item_default_methods(cx, it); check_item_heap(cx, it); cx.process(Item(it)); diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 1ea32b3f404..e768a6d687c 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -15,8 +15,7 @@ use metadata::csearch; use middle::ty::{ty_struct, ty_enum}; use middle::ty; -use middle::typeck::{method_map, method_origin, method_param, method_self}; -use middle::typeck::{method_super}; +use middle::typeck::{method_map, method_origin, method_param}; use middle::typeck::{method_static, method_trait}; use std::util::ignore; @@ -291,9 +290,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, method_num: method_num, _ }) | - method_trait(trait_id, method_num, _) | - method_self(trait_id, method_num) | - method_super(trait_id, method_num) => { + method_trait(trait_id, method_num, _) => { if trait_id.crate == local_crate { match tcx.items.find(&trait_id.node) { Some(&node_item(item, _)) => { diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index d43cea2c733..7b2b130bc68 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -12,6 +12,7 @@ use middle::ty; +use syntax::opt_vec::OptVec; use util::ppaux::Repr; /////////////////////////////////////////////////////////////////////////// @@ -79,6 +80,12 @@ impl<T:Subst> Subst for ~[T] { } } +impl<T:Subst> Subst for OptVec<T> { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> OptVec<T> { + self.map(|t| t.subst(tcx, substs)) + } +} + impl<T:Subst + 'static> Subst for @T { fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @T { match self { @@ -105,13 +112,26 @@ impl Subst for ty::TraitRef { impl Subst for ty::substs { fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::substs { ty::substs { - self_r: self.self_r.subst(tcx, substs), + regions: self.regions.subst(tcx, substs), self_ty: self.self_ty.map(|typ| typ.subst(tcx, substs)), tps: self.tps.map(|typ| typ.subst(tcx, substs)) } } } +impl Subst for ty::RegionSubsts { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::RegionSubsts { + match *self { + ty::ErasedRegions => { + ty::ErasedRegions + } + ty::NonerasedRegions(ref regions) => { + ty::NonerasedRegions(regions.subst(tcx, substs)) + } + } + } +} + impl Subst for ty::BareFnTy { fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::BareFnTy { ty::fold_bare_fn_ty(self, |t| t.subst(tcx, substs)) @@ -158,15 +178,18 @@ impl Subst for ty::Region { // will most likely disappear. match self { &ty::re_bound(ty::br_self) => { - match substs.self_r { - None => { - tcx.sess.bug( - fmt!("ty::Region#subst(): \ - Reference to self region when \ - given substs with no self region: %s", - substs.repr(tcx))); + match substs.regions { + ty::ErasedRegions => ty::re_static, + ty::NonerasedRegions(ref regions) => { + if regions.len() != 1 { + tcx.sess.bug( + fmt!("ty::Region#subst(): \ + Reference to self region when \ + given substs with no self region: %s", + substs.repr(tcx))); + } + *regions.get(0) } - Some(self_r) => self_r } } _ => *self diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 843aa2b749c..648dd033287 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -193,7 +193,7 @@ pub enum Lit { // range) pub enum Opt { lit(Lit), - var(/* disr val */int, @adt::Repr), + var(/* disr val */ uint, @adt::Repr), range(@ast::expr, @ast::expr), vec_len_eq(uint), vec_len_ge(uint, /* slice */uint) @@ -874,7 +874,7 @@ pub struct ExtractedBlock { pub fn extract_variant_args(bcx: @mut Block, repr: &adt::Repr, - disr_val: int, + disr_val: uint, val: ValueRef) -> ExtractedBlock { let _icx = push_ctxt("match::extract_variant_args"); diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index ee53bfdcbda..4a541c17a23 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -64,7 +64,7 @@ use middle::trans::type_::Type; /// Representations. pub enum Repr { /// C-like enums; basically an int. - CEnum(int, int), // discriminant range + CEnum(uint, uint), // discriminant range /** * Single-case variants, and structs/tuples/records. * @@ -89,7 +89,7 @@ pub enum Repr { * is represented such that `None` is a null pointer and `Some` is the * identity function. */ - NullablePointer{ nonnull: Struct, nndiscr: int, ptrfield: uint, + NullablePointer{ nonnull: Struct, nndiscr: uint, ptrfield: uint, nullfields: ~[ty::t] } } @@ -140,7 +140,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr { return Univariant(mk_struct(cx, ftys, packed), dtor) } ty::ty_enum(def_id, ref substs) => { - struct Case { discr: int, tys: ~[ty::t] }; + struct Case { discr: uint, tys: ~[ty::t] }; impl Case { fn is_zerolen(&self, cx: &mut CrateContext) -> bool { mk_struct(cx, self.tys, false).size == 0 @@ -177,7 +177,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr { // Since there's at least one // non-empty body, explicit discriminants should have // been rejected by a checker before this point. - if !cases.iter().enumerate().all(|(i,c)| c.discr == (i as int)) { + if !cases.iter().enumerate().all(|(i,c)| c.discr == i) { cx.sess.bug(fmt!("non-C-like enum %s with specified \ discriminants", ty::item_path_str(cx.tcx, def_id))) @@ -206,7 +206,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr { } // The general case. - let discr = ~[ty::mk_int()]; + let discr = ~[ty::mk_uint()]; return General(cases.map(|c| mk_struct(cx, discr + c.tys, false))) } _ => cx.sess.bug("adt::represent_type called on non-ADT type") @@ -305,9 +305,8 @@ pub fn trans_get_discr(bcx: @mut Block, r: &Repr, scrutinee: ValueRef) -> ValueRef { match *r { CEnum(min, max) => load_discr(bcx, scrutinee, min, max), - Univariant(*) => C_int(bcx.ccx(), 0), - General(ref cases) => load_discr(bcx, scrutinee, 0, - (cases.len() - 1) as int), + Univariant(*) => C_uint(bcx.ccx(), 0), + General(ref cases) => load_discr(bcx, scrutinee, 0, cases.len() - 1), NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => { ZExt(bcx, nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee), Type::enum_discrim(bcx.ccx())) @@ -315,7 +314,7 @@ pub fn trans_get_discr(bcx: @mut Block, r: &Repr, scrutinee: ValueRef) } } -fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: int, ptrfield: uint, +fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: uint, ptrfield: uint, scrutinee: ValueRef) -> ValueRef { let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; let llptr = Load(bcx, GEPi(bcx, scrutinee, [0, ptrfield])); @@ -324,7 +323,7 @@ fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: int, ptrfield: } /// Helper for cases where the discriminant is simply loaded. -fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: int, max: int) +fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: uint, max: uint) -> ValueRef { let ptr = GEPi(bcx, scrutinee, [0, 0]); if max + 1 == min { @@ -348,16 +347,16 @@ fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: int, max: int) * * This should ideally be less tightly tied to `_match`. */ -pub fn trans_case(bcx: @mut Block, r: &Repr, discr: int) -> _match::opt_result { +pub fn trans_case(bcx: @mut Block, r: &Repr, discr: uint) -> _match::opt_result { match *r { CEnum(*) => { - _match::single_result(rslt(bcx, C_int(bcx.ccx(), discr))) + _match::single_result(rslt(bcx, C_uint(bcx.ccx(), discr))) } Univariant(*) => { bcx.ccx().sess.bug("no cases for univariants or structs") } General(*) => { - _match::single_result(rslt(bcx, C_int(bcx.ccx(), discr))) + _match::single_result(rslt(bcx, C_uint(bcx.ccx(), discr))) } NullablePointer{ _ } => { assert!(discr == 0 || discr == 1); @@ -371,11 +370,11 @@ pub fn trans_case(bcx: @mut Block, r: &Repr, discr: int) -> _match::opt_result { * representation. The fields, if any, should then be initialized via * `trans_field_ptr`. */ -pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int) { +pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: uint) { match *r { CEnum(min, max) => { assert!(min <= discr && discr <= max); - Store(bcx, C_int(bcx.ccx(), discr), GEPi(bcx, val, [0, 0])) + Store(bcx, C_uint(bcx.ccx(), discr), GEPi(bcx, val, [0, 0])) } Univariant(ref st, true) => { assert_eq!(discr, 0); @@ -386,7 +385,7 @@ pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int) { assert_eq!(discr, 0); } General(*) => { - Store(bcx, C_int(bcx.ccx(), discr), GEPi(bcx, val, [0, 0])) + Store(bcx, C_uint(bcx.ccx(), discr), GEPi(bcx, val, [0, 0])) } NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => { if discr != nndiscr { @@ -402,14 +401,14 @@ pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int) { * The number of fields in a given case; for use when obtaining this * information from the type or definition is less convenient. */ -pub fn num_args(r: &Repr, discr: int) -> uint { +pub fn num_args(r: &Repr, discr: uint) -> uint { match *r { CEnum(*) => 0, Univariant(ref st, dtor) => { assert_eq!(discr, 0); st.fields.len() - (if dtor { 1 } else { 0 }) } - General(ref cases) => cases[discr as uint].fields.len() - 1, + General(ref cases) => cases[discr].fields.len() - 1, NullablePointer{ nonnull: ref nonnull, nndiscr, nullfields: ref nullfields, _ } => { if discr == nndiscr { nonnull.fields.len() } else { nullfields.len() } } @@ -417,7 +416,7 @@ pub fn num_args(r: &Repr, discr: int) -> uint { } /// Access a field, at a point when the value's case is known. -pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int, +pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: uint, ix: uint) -> ValueRef { // Note: if this ever needs to generate conditionals (e.g., if we // decide to do some kind of cdr-coding-like non-unique repr @@ -431,7 +430,7 @@ pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int, struct_field_ptr(bcx, st, val, ix, false) } General(ref cases) => { - struct_field_ptr(bcx, &cases[discr as uint], val, ix + 1, true) + struct_field_ptr(bcx, &cases[discr], val, ix + 1, true) } NullablePointer{ nonnull: ref nonnull, nullfields: ref nullfields, nndiscr, _ } => { if (discr == nndiscr) { @@ -495,22 +494,22 @@ pub fn trans_drop_flag_ptr(bcx: @mut Block, r: &Repr, val: ValueRef) -> ValueRef * this could be changed in the future to avoid allocating unnecessary * space after values of shorter-than-maximum cases. */ -pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: int, +pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: uint, vals: &[ValueRef]) -> ValueRef { match *r { CEnum(min, max) => { assert_eq!(vals.len(), 0); assert!(min <= discr && discr <= max); - C_int(ccx, discr) + C_uint(ccx, discr) } Univariant(ref st, _dro) => { assert_eq!(discr, 0); C_struct(build_const_struct(ccx, st, vals)) } General(ref cases) => { - let case = &cases[discr as uint]; + let case = &cases[discr]; let max_sz = cases.iter().transform(|x| x.size).max().unwrap(); - let discr_ty = C_int(ccx, discr); + let discr_ty = C_uint(ccx, discr); let contents = build_const_struct(ccx, case, ~[discr_ty] + vals); C_struct(contents + &[padding(max_sz - case.size)]) @@ -582,13 +581,18 @@ fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a } /// Get the discriminant of a constant value. (Not currently used.) pub fn const_get_discrim(ccx: &mut CrateContext, r: &Repr, val: ValueRef) - -> int { + -> uint { match *r { - CEnum(*) => const_to_int(val) as int, + CEnum(*) => const_to_uint(val) as uint, Univariant(*) => 0, - General(*) => const_to_int(const_get_elt(ccx, val, [0])) as int, + General(*) => const_to_uint(const_get_elt(ccx, val, [0])) as uint, NullablePointer{ nndiscr, ptrfield, _ } => { - if is_null(const_struct_field(ccx, val, ptrfield)) { 1 - nndiscr } else { nndiscr } + if is_null(const_struct_field(ccx, val, ptrfield)) { + /* subtraction as uint is ok because nndiscr is either 0 or 1 */ + (1 - nndiscr) as uint + } else { + nndiscr + } } } } @@ -601,7 +605,7 @@ pub fn const_get_discrim(ccx: &mut CrateContext, r: &Repr, val: ValueRef) * raw LLVM-level structs and arrays.) */ pub fn const_get_field(ccx: &mut CrateContext, r: &Repr, val: ValueRef, - _discr: int, ix: uint) -> ValueRef { + _discr: uint, ix: uint) -> ValueRef { match *r { CEnum(*) => ccx.sess.bug("element access in C-like enum const"), Univariant(*) => const_struct_field(ccx, val, ix), diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index d3ae69b23da..50ea6537544 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -67,7 +67,6 @@ 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::uint; @@ -516,7 +515,8 @@ pub fn get_res_dtor(ccx: @mut CrateContext, did }; assert_eq!(did.crate, ast::local_crate); - let tsubsts = ty::substs { self_r: None, self_ty: None, + let tsubsts = ty::substs {regions: ty::ErasedRegions, + self_ty: None, tps: /*bad*/ substs.to_owned() }; let (val, _) = monomorphize::monomorphic_fn(ccx, did, @@ -732,7 +732,7 @@ pub fn iter_structural_ty(cx: @mut Block, av: ValueRef, t: ty::t, for (*variants).iter().advance |variant| { let variant_cx = sub_block(cx, ~"enum-iter-variant-" + - int::to_str(variant.disr_val)); + uint::to_str(variant.disr_val)); let variant_cx = iter_variant(variant_cx, repr, av, *variant, substs.tps, |x,y,z| f(x,y,z)); @@ -1979,7 +1979,7 @@ pub fn trans_enum_variant(ccx: @mut CrateContext, _enum_id: ast::node_id, variant: &ast::variant, args: &[ast::variant_arg], - disr: int, + disr: uint, param_substs: Option<@param_substs>, llfndecl: ValueRef) { let _icx = push_ctxt("trans_enum_variant"); @@ -2028,7 +2028,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>( ccx: @mut CrateContext, ctor_id: ast::node_id, args: &[A], - disr: int, + disr: uint, param_substs: Option<@param_substs>, llfndecl: ValueRef) { @@ -2628,7 +2628,7 @@ pub fn trans_constant(ccx: &mut CrateContext, it: @ast::item) { } }; unsafe { - llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, disr_val)); + llvm::LLVMSetInitializer(discrim_gvar, C_uint(ccx, disr_val)); llvm::LLVMSetGlobalConstant(discrim_gvar, True); } ccx.discrims.insert( diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index d64615e5dc7..db849c78fa7 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -193,30 +193,15 @@ pub fn trans_fn_ref_with_vtables_to_callee( type_params, vtables))} } -fn get_impl_resolutions(bcx: @mut Block, - impl_id: ast::def_id) - -> typeck::vtable_res { - if impl_id.crate == ast::local_crate { - bcx.ccx().maps.vtable_map.get_copy(&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: @mut Block, impl_id: ast::def_id, method: &ty::Method, substs: &ty::substs, impl_vtables: Option<typeck::vtable_res>) - -> typeck::vtable_res { + -> (typeck::vtable_res, typeck::vtable_param_res) { // Get the vtables that the impl implements the trait at - let trait_vtables = get_impl_resolutions(bcx, impl_id); + let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id); // Build up a param_substs that we are going to resolve the // trait_vtables under. @@ -224,11 +209,11 @@ fn resolve_default_method_vtables(bcx: @mut Block, tys: substs.tps.clone(), self_ty: substs.self_ty, vtables: impl_vtables, - self_vtable: None + self_vtables: None }); let trait_vtables_fixed = resolve_vtables_under_param_substs( - bcx.tcx(), param_substs, trait_vtables); + bcx.tcx(), param_substs, impl_res.trait_vtables); // Now we pull any vtables for parameters on the actual method. let num_method_vtables = method.generics.type_param_defs.len(); @@ -241,7 +226,12 @@ fn resolve_default_method_vtables(bcx: @mut Block, None => vec::from_elem(num_method_vtables, @~[]) }; - @(*trait_vtables_fixed + method_vtables) + let param_vtables = @(*trait_vtables_fixed + method_vtables); + + let self_vtables = resolve_param_vtables_under_param_substs( + bcx.tcx(), param_substs, impl_res.self_vtables); + + (param_vtables, self_vtables) } @@ -284,19 +274,14 @@ pub fn trans_fn_ref_with_vtables( // Polytype of the function item (may have type params) let fn_tpt = ty::lookup_item_type(tcx, def_id); - // 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), + let substs = ty::substs { regions: ty::ErasedRegions, 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 (is_default, def_id, substs, self_vtable, vtables) = + let (is_default, def_id, substs, self_vtables, vtables) = match ty::provided_source(tcx, def_id) { None => (false, def_id, substs, None, vtables), Some(source_id) => { @@ -319,20 +304,6 @@ pub fn trans_fn_ref_with_vtables( .expect("could not find trait_ref for impl with \ default methods"); - // 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() - } - }; - - let self_vtable = - typeck::vtable_static(impl_id, receiver_substs, - receiver_vtables); // Compute the first substitution let first_subst = make_substs_for_receiver_types( tcx, impl_id, trait_ref, method); @@ -341,20 +312,22 @@ pub fn trans_fn_ref_with_vtables( let new_substs = first_subst.subst(tcx, &substs); - let vtables = + let (param_vtables, self_vtables) = resolve_default_method_vtables(bcx, impl_id, - method, &new_substs, vtables); + method, &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", + vtables = %s, \ + self_vtable = %s, param_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)); + vtables.repr(tcx), + self_vtables.repr(tcx), param_vtables.repr(tcx)); (true, source_id, - new_substs, Some(self_vtable), Some(vtables)) + new_substs, Some(self_vtables), Some(param_vtables)) } }; @@ -400,7 +373,7 @@ pub fn trans_fn_ref_with_vtables( let (val, must_cast) = monomorphize::monomorphic_fn(ccx, def_id, &substs, - vtables, self_vtable, + vtables, self_vtables, Some(ref_id)); let mut val = val; if must_cast && ref_id != 0 { diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 713939a5d83..690e488d219 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -133,7 +133,7 @@ pub struct param_substs { tys: ~[ty::t], self_ty: Option<ty::t>, vtables: Option<typeck::vtable_res>, - self_vtable: Option<typeck::vtable_origin> + self_vtables: Option<typeck::vtable_param_res> } impl param_substs { @@ -850,6 +850,12 @@ pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint]) } } +pub fn is_const(v: ValueRef) -> bool { + unsafe { + llvm::LLVMIsConstant(v) == True + } +} + pub fn const_to_int(v: ValueRef) -> c_longlong { unsafe { llvm::LLVMConstIntGetSExtValue(v) @@ -1020,15 +1026,26 @@ pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt, vts: typeck::vtable_res) -> typeck::vtable_res { @vts.iter().transform(|ds| - @ds.iter().transform( - |d| resolve_vtable_under_param_substs(tcx, - param_substs, - d)) - .collect::<~[typeck::vtable_origin]>()) - .collect::<~[typeck::vtable_param_res]>() + resolve_param_vtables_under_param_substs(tcx, + param_substs, + *ds)) + .collect() +} + +pub fn resolve_param_vtables_under_param_substs( + tcx: ty::ctxt, + param_substs: Option<@param_substs>, + ds: typeck::vtable_param_res) + -> typeck::vtable_param_res { + @ds.iter().transform( + |d| resolve_vtable_under_param_substs(tcx, + param_substs, + d)) + .collect() } + // Apply the typaram substitutions in the FunctionContext to a vtable. This should // eliminate any vtable_params. pub fn resolve_vtable_in_fn_ctxt(fcx: &FunctionContext, vt: &typeck::vtable_origin) @@ -1068,36 +1085,31 @@ pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt, } } } - typeck::vtable_self(_trait_id) => { - match param_substs { - Some(@param_substs - {self_vtable: Some(ref self_vtable), _}) => { - (*self_vtable).clone() - } - _ => { - tcx.sess.bug(fmt!( - "resolve_vtable_in_fn_ctxt: asked to lookup but \ - no self_vtable in the fn_ctxt!")) - } - } - } } } pub fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, - n_param: uint, + n_param: typeck::param_index, n_bound: uint) -> typeck::vtable_origin { - debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)", + debug!("find_vtable(n_param=%?, n_bound=%u, ps=%s)", n_param, n_bound, ps.repr(tcx)); - ps.vtables.get()[n_param][n_bound].clone() + let param_bounds = match n_param { + typeck::param_self => ps.self_vtables.expect("self vtables missing"), + typeck::param_numbered(n) => { + let tables = ps.vtables + .expect("vtables missing where they are needed"); + tables[n] + } + }; + param_bounds[n_bound].clone() } pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs { substs { - self_r: Some(ty::re_bound(ty::br_self)), + regions: ty::ErasedRegions, self_ty: None, tps: tps } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 15793ea747f..db9e3db2c0f 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -446,7 +446,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef { (expr::cast_enum, expr::cast_float) => { let repr = adt::represent_type(cx, basety); let discr = adt::const_get_discrim(cx, repr, v); - let iv = C_int(cx, discr); + let iv = C_uint(cx, discr); let ety_cast = expr::cast_type_kind(ety); match ety_cast { expr::cast_integral => { diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 2b6c1d82418..8c87766bbbe 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -65,44 +65,36 @@ pub fn trans_if(bcx: @mut Block, let _icx = push_ctxt("trans_if"); - match cond.node { - // `if true` and `if false` can be trans'd more efficiently, - // by dropping branches that are known to be impossible. - ast::expr_lit(@ref l) => match l.node { - ast::lit_bool(true) => { - // if true { .. } [else { .. }] - let then_bcx_in = scope_block(bcx, thn.info(), "if_true_then"); - let then_bcx_out = trans_block(then_bcx_in, thn, dest); - let then_bcx_out = trans_block_cleanups(then_bcx_out, - block_cleanups(then_bcx_in)); - Br(bcx, then_bcx_in.llbb); - return then_bcx_out; + let Result {bcx, val: cond_val} = + expr::trans_to_datum(bcx, cond).to_result(); + + let cond_val = bool_to_i1(bcx, cond_val); + + // Drop branches that are known to be impossible + if is_const(cond_val) && !is_undef(cond_val) { + if const_to_uint(cond_val) == 1 { + // if true { .. } [else { .. }] + return do with_scope(bcx, thn.info(), "if_true_then") |bcx| { + let bcx_out = trans_block(bcx, thn, dest); + trans_block_cleanups(bcx_out, block_cleanups(bcx)) } - ast::lit_bool(false) => { - match els { - // if false { .. } else { .. } - Some(elexpr) => { - let (else_bcx_in, else_bcx_out) = - trans_if_else(bcx, elexpr, dest, "if_false_else"); - Br(bcx, else_bcx_in.llbb); - return else_bcx_out; + } else { + match els { + // if false { .. } else { .. } + Some(elexpr) => { + return do with_scope(bcx, elexpr.info(), "if_false_then") |bcx| { + let bcx_out = trans_if_else(bcx, elexpr, dest); + trans_block_cleanups(bcx_out, block_cleanups(bcx)) } - // if false { .. } - None => return bcx, } + // if false { .. } + None => return bcx, } - _ => {} - }, - _ => {} + } } - let Result {bcx, val: cond_val} = - expr::trans_to_datum(bcx, cond).to_result(); - let then_bcx_in = scope_block(bcx, thn.info(), "then"); - let cond_val = bool_to_i1(bcx, cond_val); - let then_bcx_out = trans_block(then_bcx_in, thn, dest); let then_bcx_out = trans_block_cleanups(then_bcx_out, block_cleanups(then_bcx_in)); @@ -113,7 +105,8 @@ pub fn trans_if(bcx: @mut Block, // 'else' context let (else_bcx_in, next_bcx) = match els { Some(elexpr) => { - let (else_bcx_in, else_bcx_out) = trans_if_else(bcx, elexpr, dest, "else"); + let else_bcx_in = scope_block(bcx, elexpr.info(), "else"); + let else_bcx_out = trans_if_else(else_bcx_in, elexpr, dest); (else_bcx_in, join_blocks(bcx, [then_bcx_out, else_bcx_out])) } _ => { @@ -131,9 +124,8 @@ pub fn trans_if(bcx: @mut Block, return next_bcx; // trans `else [ if { .. } ... | { .. } ]` - fn trans_if_else(bcx: @mut Block, elexpr: @ast::expr, - dest: expr::Dest, scope_name: &str) -> (@mut Block, @mut Block) { - let else_bcx_in = scope_block(bcx, elexpr.info(), scope_name); + fn trans_if_else(else_bcx_in: @mut Block, elexpr: @ast::expr, + dest: expr::Dest) -> @mut Block { let else_bcx_out = match elexpr.node { ast::expr_if(_, _, _) => { let elseif_blk = ast_util::block_from_expr(elexpr); @@ -143,11 +135,9 @@ pub fn trans_if(bcx: @mut Block, trans_block(else_bcx_in, blk, dest) } // would be nice to have a constraint on ifs - _ => bcx.tcx().sess.bug("strange alternative in if") + _ => else_bcx_in.tcx().sess.bug("strange alternative in if") }; - let else_bcx_out = trans_block_cleanups(else_bcx_out, - block_cleanups(else_bcx_in)); - (else_bcx_in, else_bcx_out) + trans_block_cleanups(else_bcx_out, block_cleanups(else_bcx_in)) } } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index f552eded163..c038ca710aa 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1083,7 +1083,7 @@ pub fn trans_local_var(bcx: @mut Block, def: ast::def) -> Datum { pub fn with_field_tys<R>(tcx: ty::ctxt, ty: ty::t, node_id_opt: Option<ast::node_id>, - op: &fn(int, (&[ty::field])) -> R) -> R { + op: &fn(uint, (&[ty::field])) -> R) -> R { match ty::get(ty).sty { ty::ty_struct(did, ref substs) => { op(0, struct_fields(tcx, did, substs)) @@ -1200,7 +1200,7 @@ struct StructBaseInfo { * - `optbase` contains information on the base struct (if any) from * which remaining fields are copied; see comments on `StructBaseInfo`. */ -fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: int, +fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: uint, fields: &[(uint, @ast::expr)], optbase: Option<StructBaseInfo>, dest: Dest) -> @mut Block { diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index a65999ff2aa..9228f20513b 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -147,46 +147,13 @@ pub fn trans_method_callee(bcx: @mut Block, mentry: typeck::method_map_entry) -> Callee { let _icx = push_ctxt("impl::trans_method_callee"); - let tcx = bcx.tcx(); debug!("trans_method_callee(callee_id=%?, this=%s, mentry=%s)", callee_id, bcx.expr_to_str(this), mentry.repr(bcx.tcx())); - // Replace method_self with method_static here. - let mut origin = mentry.origin; - match origin { - 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); - // <impl_id> is the ID of the implementation of - // trait <trait_id> for type <self_ty> - let impl_id = ty::bogus_get_impl_id_from_ty(tcx, trait_id, self_ty); - // Get the supertrait's methods - let supertrait_method_def_ids = ty::trait_method_def_ids(tcx, trait_id); - // Make sure to fail with a readable error message if - // there's some internal error here - if !(method_index < supertrait_method_def_ids.len()) { - tcx.sess.bug("trans_method_callee: supertrait method \ - index is out of bounds"); - } - // Get the method name using the method index in the origin - let method_name = - ty::method(tcx, supertrait_method_def_ids[method_index]).ident; - // Now that we know the impl ID, we can look up the method - // ID from its name - origin = typeck::method_static( - method_with_name(bcx.ccx(), impl_id, method_name)); - } - typeck::method_self(*) | - typeck::method_static(*) | typeck::method_param(*) | - typeck::method_trait(*) => {} - } - - debug!("origin=%?", origin); - - match origin { + match mentry.origin { typeck::method_static(did) => { let callee_fn = callee::trans_fn_ref(bcx, did, callee_id); let mut temp_cleanups = ~[]; @@ -210,7 +177,8 @@ pub fn trans_method_callee(bcx: @mut Block, }) => { match bcx.fcx.param_substs { Some(substs) => { - let vtbl = find_vtable(bcx.tcx(), substs, p, b); + let vtbl = find_vtable(bcx.tcx(), substs, + p, b); trans_monomorphized_callee(bcx, callee_id, this, mentry, trait_id, off, vtbl) } @@ -219,24 +187,6 @@ pub fn trans_method_callee(bcx: @mut Block, } } - 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, - (*vtbl).clone()) - } - _ => { - fail!("trans_method_callee: missing self_vtable") - } - } - } - typeck::method_trait(_, off, store) => { trans_trait_callee(bcx, callee_id, @@ -245,9 +195,6 @@ pub fn trans_method_callee(bcx: @mut Block, store, mentry.explicit_self) } - typeck::method_super(*) => { - fail!("method_super should have been handled above") - } } } @@ -402,9 +349,6 @@ pub fn trans_monomorphized_callee(bcx: @mut 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"); - } }; } @@ -611,7 +555,7 @@ pub fn vtable_id(ccx: @mut CrateContext, tys: (*substs).clone(), vtables: Some(sub_vtables), self_ty: None, - self_vtable: None + self_vtables: None }; monomorphize::make_mono_id( diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 789532abc61..9852e6b09b7 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -41,7 +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>, + self_vtables: Option<typeck::vtable_param_res>, ref_id: Option<ast::node_id>) -> (ValueRef, bool) { @@ -54,7 +54,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, fn_id.repr(ccx.tcx), real_substs.repr(ccx.tcx), vtables.repr(ccx.tcx), - self_vtable.repr(ccx.tcx), + self_vtables.repr(ccx.tcx), ref_id); assert!(real_substs.tps.iter().all(|t| !ty::type_needs_infer(*t))); @@ -72,7 +72,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, tys: real_substs.tps.map(|x| do_normalize(x)), vtables: vtables, self_ty: real_substs.self_ty.map(|x| do_normalize(x)), - self_vtable: self_vtable + self_vtables: self_vtables }; for real_substs.tps.iter().advance |s| { assert!(!ty::type_has_params(*s)); } @@ -371,8 +371,7 @@ pub fn make_mono_id(ccx: @mut CrateContext, Some(vts) => { debug!("make_mono_id vtables=%s substs=%s", vts.repr(ccx.tcx), substs.tys.repr(ccx.tcx)); - let self_vtables = substs.self_vtable.map(|vtbl| @~[(*vtbl).clone()]); - let vts_iter = self_vtables.iter().chain_(vts.iter()); + let vts_iter = substs.self_vtables.iter().chain_(vts.iter()); 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 }) diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 84b001953e0..3d23828979f 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -321,7 +321,7 @@ impl Reflector { 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.disr_val), this.c_uint(v.args.len()), this.c_slice(name)]; do this.bracketed("enum_variant", variant_args) |this| { diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 4e15b4bc229..b743f2e9401 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -17,6 +17,7 @@ use util::ppaux; use middle::trans::type_::Type; use syntax::ast; +use syntax::opt_vec; pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: &ty::t) -> bool { !ty::type_is_immediate(ccx.tcx, *arg_ty) @@ -312,7 +313,8 @@ pub fn llvm_type_name(cx: &CrateContext, a_struct => { "struct" } an_enum => { "enum" } }; - let tstr = ppaux::parameterized(cx.tcx, ty::item_path_str(cx.tcx, did), None, tps); + let tstr = ppaux::parameterized(cx.tcx, ty::item_path_str(cx.tcx, did), + &ty::NonerasedRegions(opt_vec::Empty), tps); if did.crate == 0 { fmt!("%s.%s", name, tstr) } else { diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 4d5d597d382..aa19af01893 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -274,13 +274,12 @@ pub fn mark_for_method_call(cx: &Context, e_id: node_id, callee_id: node_id) { opt_static_did = Some(did); } typeck::method_param(typeck::method_param { - param_num: param, + param_num: typeck::param_numbered(param), _ }) => { cx.uses[param] |= use_tydesc; } - typeck::method_trait(*) | typeck::method_self(*) - | typeck::method_super(*) => (), + _ => (), } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 7eea20175f9..9b3df349f1e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -49,7 +49,7 @@ use syntax::opt_vec; use syntax::abi::AbiSet; use syntax; -pub static INITIAL_DISCRIMINANT_VALUE: int = 0; +pub static INITIAL_DISCRIMINANT_VALUE: uint = 0; // Data types @@ -317,6 +317,9 @@ struct ctxt_ { // some point. Local variable definitions not in this set can be warned // about. used_mut_nodes: @mut HashSet<ast::node_id>, + + // vtable resolution information for impl declarations + impl_vtables: typeck::impl_vtable_map } pub enum tbox_flag { @@ -486,7 +489,15 @@ pub enum bound_region { br_cap_avoid(ast::node_id, @bound_region), } -type opt_region = Option<Region>; +/** + * Represents the values to use when substituting lifetime parameters. + * If the value is `ErasedRegions`, then this subst is occurring during + * trans, and all region parameters will be replaced with `ty::re_static`. */ +#[deriving(Clone, Eq, IterBytes)] +pub enum RegionSubsts { + ErasedRegions, + NonerasedRegions(OptVec<ty::Region>) +} /** * The type substs represents the kinds of things that can be substituted to @@ -507,9 +518,9 @@ type opt_region = Option<Region>; * always substituted away to the implementing type for a trait. */ #[deriving(Clone, Eq, IterBytes)] pub struct substs { - self_r: opt_region, self_ty: Option<ty::t>, - tps: ~[t] + tps: ~[t], + regions: RegionSubsts, } mod primitives { @@ -911,6 +922,7 @@ pub fn mk_ctxt(s: session::Session, impls: @mut HashMap::new(), used_unsafe: @mut HashSet::new(), used_mut_nodes: @mut HashSet::new(), + impl_vtables: @mut HashMap::new(), } } @@ -948,7 +960,14 @@ fn mk_t(cx: ctxt, st: sty) -> t { fn sflags(substs: &substs) -> uint { let mut f = 0u; for substs.tps.iter().advance |tt| { f |= get(*tt).flags; } - for substs.self_r.iter().advance |r| { f |= rflags(*r) } + match substs.regions { + ErasedRegions => {} + NonerasedRegions(ref regions) => { + for regions.iter().advance |r| { + f |= rflags(*r) + } + } + } return f; } match &st { @@ -1286,7 +1305,7 @@ pub fn fold_bare_fn_ty(fty: &BareFnTy, fldop: &fn(t) -> t) -> BareFnTy { fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty { fn fold_substs(substs: &substs, fldop: &fn(t) -> t) -> substs { - substs {self_r: substs.self_r, + substs {regions: substs.regions.clone(), self_ty: substs.self_ty.map(|t| fldop(*t)), tps: substs.tps.map(|t| fldop(*t))} } @@ -1378,8 +1397,15 @@ pub fn fold_regions_and_ty( fldr: &fn(r: Region) -> Region, fldt: &fn(t: t) -> t) -> substs { + let regions = match substs.regions { + ErasedRegions => ErasedRegions, + NonerasedRegions(ref regions) => { + NonerasedRegions(regions.map(|r| fldr(*r))) + } + }; + substs { - self_r: substs.self_r.map(|r| fldr(*r)), + regions: regions, self_ty: substs.self_ty.map(|t| fldt(*t)), tps: substs.tps.map(|t| fldt(*t)) } @@ -1478,8 +1504,13 @@ pub fn subst_tps(cx: ctxt, tps: &[t], self_ty_opt: Option<t>, typ: t) -> t { } pub fn substs_is_noop(substs: &substs) -> bool { + let regions_is_noop = match substs.regions { + ErasedRegions => false, // may be used to canonicalize + NonerasedRegions(ref regions) => regions.is_empty() + }; + substs.tps.len() == 0u && - substs.self_r.is_none() && + regions_is_noop && substs.self_ty.is_none() } @@ -3061,9 +3092,7 @@ pub fn method_call_type_param_defs(tcx: ctxt, typeck::method_param(typeck::method_param { trait_id: trt_id, method_num: n_mth, _}) | - typeck::method_trait(trt_id, n_mth, _) | - typeck::method_self(trt_id, n_mth) | - typeck::method_super(trt_id, n_mth) => { + typeck::method_trait(trt_id, n_mth, _) => { // ...trait methods bounds, in contrast, include only the // method bounds, so we must preprend the tps from the // trait itself. This ought to be harmonized. @@ -3689,7 +3718,7 @@ pub struct VariantInfo { ctor_ty: t, name: ast::ident, id: ast::def_id, - disr_val: int, + disr_val: uint, vis: visibility } @@ -3700,7 +3729,7 @@ impl VariantInfo { /// Does not do any caching of the value in the type context. pub fn from_ast_variant(cx: ctxt, ast_variant: &ast::variant, - discriminant: int) -> VariantInfo { + discriminant: uint) -> VariantInfo { let ctor_ty = node_id_to_type(cx, ast_variant.node.id); @@ -3894,7 +3923,7 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[@VariantInfo] { node: ast::item_enum(ref enum_definition, _), _ }, _) => { - let mut last_discriminant: Option<int> = None; + let mut last_discriminant: Option<uint> = None; @enum_definition.variants.iter().transform(|variant| { let mut discriminant = match last_discriminant { @@ -3904,7 +3933,8 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[@VariantInfo] { match variant.node.disr_expr { Some(e) => match const_eval::eval_const_expr_partial(&cx, e) { - Ok(const_eval::const_int(val)) => discriminant = val as int, + Ok(const_eval::const_int(val)) => discriminant = val as uint, + Ok(const_eval::const_uint(val)) => discriminant = val as uint, Ok(_) => { cx.sess.span_err(e.span, "expected signed integer constant"); } @@ -3955,6 +3985,14 @@ pub fn lookup_item_type(cx: ctxt, || csearch::get_type(cx, did)) } +pub fn lookup_impl_vtables(cx: ctxt, + did: ast::def_id) + -> typeck::impl_res { + lookup_locally_or_in_crate_store( + "impl_vtables", did, cx.impl_vtables, + || csearch::get_impl_vtables(cx, did) ) +} + /// Given the did of a trait, returns its canonical trait ref. pub fn lookup_trait_def(cx: ctxt, did: ast::def_id) -> @ty::TraitDef { match cx.trait_defs.find(&did) { @@ -4227,30 +4265,33 @@ pub fn normalize_ty(cx: ctxt, t: t) -> t { }) } - ty_enum(did, ref r) => - match (*r).self_r { - Some(_) => - // Use re_static since trans doesn't care about regions - mk_enum(cx, did, - substs { - self_r: Some(ty::re_static), - self_ty: None, - tps: (*r).tps.clone() - }), - None => + ty_enum(did, ref r) => { + match (*r).regions { + NonerasedRegions(_) => { + // trans doesn't care about regions + mk_enum(cx, did, substs {regions: ty::ErasedRegions, + self_ty: None, + tps: (*r).tps.clone()}) + } + ErasedRegions => { t - }, + } + } + } - ty_struct(did, ref r) => - match (*r).self_r { - Some(_) => - // Ditto. - mk_struct(cx, did, substs {self_r: Some(ty::re_static), - self_ty: None, - tps: (*r).tps.clone()}), - None => - t - }, + ty_struct(did, ref r) => { + match (*r).regions { + NonerasedRegions(_) => { + // Ditto. + mk_struct(cx, did, substs {regions: ty::ErasedRegions, + self_ty: None, + tps: (*r).tps.clone()}) + } + ErasedRegions => { + t + } + } + } _ => t @@ -4338,9 +4379,9 @@ pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id), // relation on the supertraits from each bounded trait's constraint // list. pub fn each_bound_trait_and_supertraits(tcx: ctxt, - bounds: &ParamBounds, + bounds: &[@TraitRef], f: &fn(@TraitRef) -> bool) -> bool { - for bounds.trait_bounds.iter().advance |&bound_trait_ref| { + for bounds.iter().advance |&bound_trait_ref| { let mut supertrait_set = HashMap::new(); let mut trait_refs = ~[]; let mut i = 0; @@ -4382,38 +4423,14 @@ pub fn count_traits_and_supertraits(tcx: ctxt, type_param_defs: &[TypeParameterDef]) -> uint { let mut total = 0; for type_param_defs.iter().advance |type_param_def| { - for each_bound_trait_and_supertraits(tcx, type_param_def.bounds) |_| { + for each_bound_trait_and_supertraits( + tcx, type_param_def.bounds.trait_bounds) |_| { total += 1; } } return total; } -// Given a trait and a type, returns the impl of that type. -// This is broken, of course, by parametric impls. This used to use -// a table specifically for this mapping, but I removed that table. -// This is only used when calling a supertrait method from a default method, -// and should go away once I fix how that works. -sully -pub fn bogus_get_impl_id_from_ty(tcx: ctxt, - trait_id: def_id, self_ty: t) -> def_id { - match tcx.trait_impls.find(&trait_id) { - Some(ty_to_impl) => { - for ty_to_impl.iter().advance |imp| { - let impl_ty = tcx.tcache.get_copy(&imp.did); - if impl_ty.ty == self_ty { return imp.did; } - } - // try autoderef! - match deref(tcx, self_ty, false) { - Some(some_ty) => - bogus_get_impl_id_from_ty(tcx, trait_id, some_ty.ty), - None => tcx.sess.bug("get_impl_id: no impl of trait for \ - this type") - } - }, - None => tcx.sess.bug("get_impl_id: trait isn't in trait_impls") - } -} - pub fn get_tydesc_ty(tcx: ctxt) -> Result<t, ~str> { do tcx.lang_items.require(TyDescStructLangItem).map |tydesc_lang_item| { tcx.intrinsic_defs.find_copy(tydesc_lang_item) @@ -4434,7 +4451,7 @@ pub fn visitor_object_ty(tcx: ctxt) -> Result<(@TraitRef, t), ~str> { Err(s) => { return Err(s); } }; let substs = substs { - self_r: None, + regions: ty::NonerasedRegions(opt_vec::Empty), self_ty: None, tps: ~[] }; diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 28595e5af51..a506142a971 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -150,26 +150,27 @@ fn ast_path_substs<AC:AstConv,RS:region_scope + Clone + 'static>( // If the type is parameterized by the this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). - let self_r = match (&decl_generics.region_param, &path.rp) { - (&None, &None) => { - None - } - (&None, &Some(_)) => { - tcx.sess.span_err( - path.span, - fmt!("no region bound is allowed on `%s`, \ - which is not declared as containing region pointers", - ty::item_path_str(tcx, def_id))); - None - } - (&Some(_), &None) => { - let res = rscope.anon_region(path.span); - let r = get_region_reporting_err(this.tcx(), path.span, &None, res); - Some(r) - } - (&Some(_), &Some(_)) => { - Some(ast_region_to_region(this, rscope, path.span, &path.rp)) - } + let regions = match (&decl_generics.region_param, &path.rp) { + (&None, &None) => { + opt_vec::Empty + } + (&None, &Some(_)) => { + tcx.sess.span_err( + path.span, + fmt!("no region bound is allowed on `%s`, \ + which is not declared as containing region pointers", + ty::item_path_str(tcx, def_id))); + opt_vec::Empty + } + (&Some(_), &None) => { + let res = rscope.anon_region(path.span); + let r = get_region_reporting_err(this.tcx(), path.span, &None, res); + opt_vec::with(r) + } + (&Some(_), &Some(_)) => { + opt_vec::with( + ast_region_to_region(this, rscope, path.span, &path.rp)) + } }; // Convert the type parameters supplied by the user. @@ -181,7 +182,7 @@ fn ast_path_substs<AC:AstConv,RS:region_scope + Clone + 'static>( } let tps = path.types.map(|a_t| ast_ty_to_ty(this, rscope, a_t)); - substs {self_r:self_r, self_ty:self_ty, tps:tps} + substs {regions:ty::NonerasedRegions(regions), self_ty:self_ty, tps:tps} } pub fn ast_path_to_substs_and_ty<AC:AstConv, diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 8d546366846..a4d93586327 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -90,7 +90,8 @@ use middle::typeck::check::vtable; use middle::typeck::check; use middle::typeck::infer; use middle::typeck::{method_map_entry, method_origin, method_param}; -use middle::typeck::{method_self, method_static, method_trait, method_super}; +use middle::typeck::{method_static, method_trait}; +use middle::typeck::{param_numbered, param_self, param_index}; use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; use util::common::indenter; @@ -328,64 +329,6 @@ impl<'self> LookupContext<'self> { } } - pub fn push_inherent_candidates_from_param(&self, - rcvr_ty: ty::t, - param_ty: param_ty) { - debug!("push_inherent_candidates_from_param(param_ty=%?)", - param_ty); - let _indenter = indenter(); - - let tcx = self.tcx(); - let mut next_bound_idx = 0; // count only trait bounds - let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) { - Some(t) => t, - None => { - tcx.sess.span_bug( - self.expr.span, - fmt!("No param def for %?", param_ty)); - } - }; - - for ty::each_bound_trait_and_supertraits(tcx, type_param_def.bounds) - |bound_trait_ref| - { - let this_bound_idx = next_bound_idx; - next_bound_idx += 1; - - let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); - let pos = { - match trait_methods.iter().position(|m| { - m.explicit_self != ast::sty_static && - m.ident == self.m_name }) - { - Some(pos) => pos, - None => { - debug!("trait doesn't contain method: %?", - bound_trait_ref.def_id); - loop; // check next trait or bound - } - } - }; - let method = trait_methods[pos]; - - let cand = Candidate { - rcvr_ty: rcvr_ty, - rcvr_substs: bound_trait_ref.substs.clone(), - method_ty: method, - origin: method_param( - method_param { - trait_id: bound_trait_ref.def_id, - method_num: pos, - param_num: param_ty.idx, - bound_num: this_bound_idx, - }) - }; - - debug!("pushing inherent candidate for param: %?", cand); - self.inherent_candidates.push(cand); - } - } - pub fn push_inherent_candidates_from_trait(&self, self_ty: ty::t, did: def_id, @@ -438,69 +381,87 @@ impl<'self> LookupContext<'self> { }); } + pub fn push_inherent_candidates_from_param(&self, + rcvr_ty: ty::t, + param_ty: param_ty) { + debug!("push_inherent_candidates_from_param(param_ty=%?)", + param_ty); + let _indenter = indenter(); + + let tcx = self.tcx(); + let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) { + Some(t) => t, + None => { + tcx.sess.span_bug( + self.expr.span, + fmt!("No param def for %?", param_ty)); + } + }; + + self.push_inherent_candidates_from_bounds( + rcvr_ty, type_param_def.bounds.trait_bounds, + param_numbered(param_ty.idx)); + } + + pub fn push_inherent_candidates_from_self(&self, self_ty: ty::t, did: def_id) { - struct MethodInfo { - method_ty: @ty::Method, - trait_def_id: ast::def_id, - index: uint, - trait_ref: @ty::TraitRef - } + let tcx = self.tcx(); + + let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref; + self.push_inherent_candidates_from_bounds( + self_ty, &[trait_ref], param_self); + } + pub fn push_inherent_candidates_from_bounds(&self, + self_ty: ty::t, + bounds: &[@TraitRef], + param: param_index) { let tcx = self.tcx(); - // First, try self methods - let mut method_info: Option<MethodInfo> = None; - let methods = ty::trait_methods(tcx, did); - 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_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).iter().advance |trait_ref| { - let supertrait_methods = - ty::trait_methods(tcx, trait_ref.def_id); - 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_ref: *trait_ref - }); - break; + let mut next_bound_idx = 0; // count only trait bounds + + for ty::each_bound_trait_and_supertraits(tcx, bounds) + |bound_trait_ref| + { + let this_bound_idx = next_bound_idx; + next_bound_idx += 1; + + let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); + let pos = { + match trait_methods.iter().position(|m| { + m.explicit_self != ast::sty_static && + m.ident == self.m_name }) + { + Some(pos) => pos, + None => { + debug!("trait doesn't contain method: %?", + bound_trait_ref.def_id); + loop; // check next trait or bound } - None => () } - } - } - match method_info { - Some(ref info) => { - // We've found a method -- return it - let origin = if did == info.trait_def_id { - method_self(info.trait_def_id, info.index) - } else { - method_super(info.trait_def_id, info.index) - }; - self.inherent_candidates.push(Candidate { - rcvr_ty: self_ty, - rcvr_substs: info.trait_ref.substs.clone(), - method_ty: info.method_ty, - origin: origin - }); - } - _ => return + }; + let method = trait_methods[pos]; + + let cand = Candidate { + rcvr_ty: self_ty, + rcvr_substs: bound_trait_ref.substs.clone(), + method_ty: method, + origin: method_param( + method_param { + trait_id: bound_trait_ref.def_id, + method_num: pos, + param_num: param, + bound_num: this_bound_idx, + }) + }; + + debug!("pushing inherent candidate for param: %?", cand); + self.inherent_candidates.push(cand); } } + pub fn push_inherent_impl_candidates_for_type(&self, did: def_id) { let opt_impl_infos = self.tcx().inherent_impls.find(&did); for opt_impl_infos.iter().advance |impl_infos| { @@ -938,7 +899,7 @@ impl<'self> LookupContext<'self> { // which is equal to the class tps + the method tps. let all_substs = substs { tps: vec::append(candidate.rcvr_substs.tps.clone(), m_substs), - self_r: candidate.rcvr_substs.self_r, + regions: candidate.rcvr_substs.regions.clone(), self_ty: candidate.rcvr_substs.self_ty, }; @@ -1005,14 +966,13 @@ impl<'self> LookupContext<'self> { /*! * * There are some limitations to calling functions through a - * traint instance, because (a) the self type is not known + * trait instance, because (a) the self type is not known * (that's the whole point of a trait instance, after all, to * obscure the self type) and (b) the call must go through a * vtable and hence cannot be monomorphized. */ match candidate.origin { - method_static(*) | method_param(*) | - method_self(*) | method_super(*) => { + method_static(*) | method_param(*) => { return; // not a call to a trait instance } method_trait(*) => {} @@ -1036,10 +996,11 @@ impl<'self> LookupContext<'self> { // No code can call the finalize method explicitly. let bad; match candidate.origin { - method_static(method_id) | method_self(method_id, _) - | method_super(method_id, _) => { + method_static(method_id) => { bad = self.tcx().destructors.contains(&method_id); } + // XXX: does this properly enforce this on everything now + // that self has been merged in? -sully method_param(method_param { trait_id: trait_id, _ }) | method_trait(trait_id, _, _) => { bad = self.tcx().destructor_for_type.contains_key(&trait_id); @@ -1158,8 +1119,7 @@ impl<'self> LookupContext<'self> { method_param(ref mp) => { type_of_trait_method(self.tcx(), mp.trait_id, mp.method_num) } - method_trait(did, idx, _) | method_self(did, idx) | - method_super(did, idx) => { + method_trait(did, idx, _) => { type_of_trait_method(self.tcx(), did, idx) } }; @@ -1180,8 +1140,7 @@ impl<'self> LookupContext<'self> { method_param(ref mp) => { self.report_param_candidate(idx, (*mp).trait_id) } - method_trait(trait_did, _, _) | method_self(trait_did, _) - | method_super(trait_did, _) => { + method_trait(trait_did, _, _) => { self.report_trait_candidate(idx, trait_did) } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index c04e1c2515c..0b80c0cb3c6 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -925,10 +925,15 @@ impl FnCtxt { pub fn region_var_if_parameterized(&self, rp: Option<ty::region_variance>, span: span) - -> Option<ty::Region> { - rp.map( - |_| self.infcx().next_region_var( - infer::BoundRegionInTypeOrImpl(span))) + -> OptVec<ty::Region> { + match rp { + None => opt_vec::Empty, + Some(_) => { + opt_vec::with( + self.infcx().next_region_var( + infer::BoundRegionInTypeOrImpl(span))) + } + } } pub fn type_error_message(&self, @@ -1111,15 +1116,15 @@ pub fn impl_self_ty(vcx: &VtableContext, (ity.generics.type_param_defs.len(), ity.generics.region_param, ity.ty) }; - let self_r = if region_param.is_some() { - Some(vcx.infcx.next_region_var( + let regions = ty::NonerasedRegions(if region_param.is_some() { + opt_vec::with(vcx.infcx.next_region_var( infer::BoundRegionInTypeOrImpl(location_info.span))) } else { - None - }; + opt_vec::Empty + }); let tps = vcx.infcx.next_ty_vars(n_tps); - let substs = substs { self_r: self_r, self_ty: None, tps: tps }; + let substs = substs {regions: regions, self_ty: None, tps: tps}; let substd_ty = ty::subst(tcx, &substs, raw_ty); ty_param_substs_and_ty { substs: substs, ty: substd_ty } @@ -1986,7 +1991,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, bound_self_region(region_parameterized); raw_type = ty::mk_struct(tcx, class_id, substs { - self_r: self_region, + regions: ty::NonerasedRegions(self_region), self_ty: None, tps: ty::ty_params_to_tys( tcx, @@ -2006,11 +2011,11 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } // Generate the struct type. - let self_region = + let regions = fcx.region_var_if_parameterized(region_parameterized, span); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { - self_r: self_region, + regions: ty::NonerasedRegions(regions), self_ty: None, tps: type_parameters }; @@ -2070,11 +2075,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, type_parameter_count = generics.ty_params.len(); - let self_region = - bound_self_region(region_parameterized); + let regions = bound_self_region(region_parameterized); raw_type = ty::mk_enum(tcx, enum_id, substs { - self_r: self_region, + regions: ty::NonerasedRegions(regions), self_ty: None, tps: ty::ty_params_to_tys( tcx, @@ -2094,11 +2098,11 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } // Generate the enum type. - let self_region = + let regions = fcx.region_var_if_parameterized(region_parameterized, span); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { - self_r: self_region, + regions: ty::NonerasedRegions(regions), self_ty: None, tps: type_parameters }; @@ -3139,8 +3143,8 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, let rty = ty::node_id_to_type(ccx.tcx, id); let mut variants: ~[@ty::VariantInfo] = ~[]; - let mut disr_vals: ~[int] = ~[]; - let mut prev_disr_val: Option<int> = None; + let mut disr_vals: ~[uint] = ~[]; + let mut prev_disr_val: Option<uint> = None; for vs.iter().advance |v| { @@ -3155,15 +3159,16 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, Some(e) => { debug!("disr expr, checking %s", pprust::expr_to_str(e, ccx.tcx.sess.intr())); - let declty = ty::mk_int(); let fcx = blank_fn_ctxt(ccx, rty, e.id); + let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id()); check_const_with_ty(fcx, e.span, e, declty); // check_expr (from check_const pass) doesn't guarantee // that the expression is in an form that eval_const_expr can // handle, so we may still get an internal compiler error match const_eval::eval_const_expr_partial(&ccx.tcx, e) { - Ok(const_eval::const_int(val)) => current_disr_val = val as int, + Ok(const_eval::const_int(val)) => current_disr_val = val as uint, + Ok(const_eval::const_uint(val)) => current_disr_val = val as uint, Ok(_) => { ccx.tcx.sess.span_err(e.span, "expected signed integer constant"); } @@ -3309,22 +3314,23 @@ pub fn instantiate_path(fcx: @mut FnCtxt, // determine the region bound, using the value given by the user // (if any) and otherwise using a fresh region variable - let self_r = match pth.rp { - Some(_) => { // user supplied a lifetime parameter... - match tpt.generics.region_param { - None => { // ...but the type is not lifetime parameterized! - fcx.ccx.tcx.sess.span_err - (span, "this item is not region-parameterized"); - None - } - Some(_) => { // ...and the type is lifetime parameterized, ok. - Some(ast_region_to_region(fcx, fcx, span, &pth.rp)) - } + let regions = match pth.rp { + Some(_) => { // user supplied a lifetime parameter... + match tpt.generics.region_param { + None => { // ...but the type is not lifetime parameterized! + fcx.ccx.tcx.sess.span_err + (span, "this item is not region-parameterized"); + opt_vec::Empty + } + Some(_) => { // ...and the type is lifetime parameterized, ok. + opt_vec::with( + ast_region_to_region(fcx, fcx, span, &pth.rp)) + } + } + } + None => { // no lifetime parameter supplied, insert default + fcx.region_var_if_parameterized(tpt.generics.region_param, span) } - } - None => { // no lifetime parameter supplied, insert default - fcx.region_var_if_parameterized(tpt.generics.region_param, span) - } }; // determine values for type parameters, using the values given by @@ -3351,7 +3357,9 @@ pub fn instantiate_path(fcx: @mut FnCtxt, pth.types.map(|aty| fcx.to_ty(aty)) }; - let substs = substs { self_r: self_r, self_ty: None, tps: tps }; + let substs = substs {regions: ty::NonerasedRegions(regions), + self_ty: None, + tps: tps }; fcx.write_ty_substs(node_id, tpt.ty, substs); debug!("<<<"); diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index da09f79d031..5e77ac30f47 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -16,11 +16,11 @@ 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_res}; -use middle::typeck::{vtable_static, vtable_param, vtable_self}; +use middle::typeck::{CrateCtxt, vtable_origin, vtable_res, vtable_param_res}; +use middle::typeck::{vtable_static, vtable_param, impl_res}; +use middle::typeck::{param_numbered, param_self, param_index}; use middle::subst::Subst; use util::common::indenter; -use util::ppaux::tys_to_str; use util::ppaux; use std::hashmap::HashSet; @@ -46,6 +46,16 @@ use syntax::visit; // *fully* resolved. (We could be less restrictive than that, but it // would require much more care, and this seems to work decently in // practice.) +// +// While resolution on a single type requires the type to be fully +// resolved, when resolving a substitution against a list of bounds, +// we do not require all of the types to be resolved in advance. +// Furthermore, we process substitutions in reverse order, which +// allows resolution on later parameters to give information on +// earlier params referenced by the typeclass bounds. +// It may be better to do something more clever, like processing fully +// resolved types first. + /// Location info records the span and ID of the expression or item that is /// responsible for this vtable instantiation. (This may not be an expression @@ -84,42 +94,19 @@ fn lookup_vtables(vcx: &VtableContext, substs.repr(vcx.tcx())); let _i = indenter(); - let tcx = vcx.tcx(); - let mut result = ~[]; - let mut i = 0u; - 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| - { - // ...and here trait_ref is each bound that was declared on A, - // expressed in terms of the type parameters. - - debug!("about to subst: %s, %s", trait_ref.repr(tcx), substs.repr(tcx)); - - // Substitute the values of the type parameters that may - // appear in the bound. - 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) => 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.ty_to_str(*ty))); - } - } - } - result.push(@param_result); - i += 1u; - } + + // We do this backwards for reasons discussed above. + assert_eq!(substs.tps.len(), type_param_defs.len()); + let mut result = + substs.tps.rev_iter() + .zip(type_param_defs.rev_iter()) + .transform(|(ty, def)| + lookup_vtables_for_param(vcx, location_info, Some(substs), + &*def.bounds, *ty, is_early)) + .to_owned_vec(); + result.reverse(); + + assert_eq!(substs.tps.len(), result.len()); debug!("lookup_vtables result(\ location_info=%?, \ type_param_defs=%s, \ @@ -132,25 +119,58 @@ fn lookup_vtables(vcx: &VtableContext, @result } -fn fixup_substs(vcx: &VtableContext, - location_info: &LocationInfo, - id: ast::def_id, - substs: ty::substs, - is_early: bool) - -> Option<ty::substs> { +fn lookup_vtables_for_param(vcx: &VtableContext, + location_info: &LocationInfo, + // None for substs means the identity + substs: Option<&ty::substs>, + type_param_bounds: &ty::ParamBounds, + ty: ty::t, + is_early: bool) -> vtable_param_res { let tcx = vcx.tcx(); - // use a dummy type just to package up the substs that need fixing up - let t = ty::mk_trait(tcx, - id, substs, - ty::RegionTraitStore(ty::re_static), - 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, _, _, _) => (*substs_f).clone(), - _ => fail!("t_f should be a trait") + + // ty is the value supplied for the type parameter A... + let mut param_result = ~[]; + + for ty::each_bound_trait_and_supertraits( + tcx, type_param_bounds.trait_bounds) |trait_ref| + { + // ...and here trait_ref is each bound that was declared on A, + // expressed in terms of the type parameters. + + // Substitute the values of the type parameters that may + // appear in the bound. + let trait_ref = substs.map_default(trait_ref, |substs| { + debug!("about to subst: %s, %s", + trait_ref.repr(tcx), substs.repr(tcx)); + 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) => 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.ty_to_str(ty))); + } } } + + debug!("lookup_vtables_for_param result(\ + location_info=%?, \ + type_param_bounds=%s, \ + ty=%s, \ + result=%s)", + location_info, + type_param_bounds.repr(vcx.tcx()), + ty.repr(vcx.tcx()), + param_result.repr(vcx.tcx())); + + return @param_result; } fn relate_trait_refs(vcx: &VtableContext, @@ -173,10 +193,15 @@ fn relate_trait_refs(vcx: &VtableContext, { result::Ok(()) => {} // Ok. result::Err(ref err) => { + // There is an error, but we need to do some work to make + // the message good. + // Resolve any type vars in the trait refs let r_act_trait_ref = vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(act_trait_ref); let r_exp_trait_ref = vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(exp_trait_ref); + // Only print the message if there aren't any previous type errors + // inside the types. if !ty::trait_ref_contains_error(&r_act_trait_ref) && !ty::trait_ref_contains_error(&r_exp_trait_ref) { @@ -192,8 +217,7 @@ fn relate_trait_refs(vcx: &VtableContext, } } -// Look up the vtable to use when treating an item of type `t` as if it has -// type `trait_ty` +// Look up the vtable implementing the trait `trait_ref` at type `t` fn lookup_vtable(vcx: &VtableContext, location_info: &LocationInfo, ty: ty::t, @@ -216,220 +240,247 @@ fn lookup_vtable(vcx: &VtableContext, // The type has unconstrained type variables in it, so we can't // do early resolution on it. Return some completely bogus vtable // information: we aren't storing it anyways. - return Some(vtable_param(0, 0)); + return Some(vtable_param(param_self, 0)); } }; - match ty::get(ty).sty { + // If the type is self or a param, we look at the trait/supertrait + // bounds to see if they include the trait we are looking for. + let vtable_opt = match ty::get(ty).sty { ty::ty_param(param_ty {idx: n, def_id: did}) => { - let mut n_bound = 0; let type_param_def = tcx.ty_param_defs.get(&did.node); - for ty::each_bound_trait_and_supertraits( - tcx, type_param_def.bounds) |bound_trait_ref| - { - debug!("checking bounds trait %s", bound_trait_ref.repr(vcx.tcx())); - - if bound_trait_ref.def_id == trait_ref.def_id { - relate_trait_refs(vcx, - location_info, - bound_trait_ref, - trait_ref); - let vtable = vtable_param(n, n_bound); - debug!("found param vtable: %?", - vtable); - return Some(vtable); - } - - n_bound += 1; - } + lookup_vtable_from_bounds(vcx, location_info, + type_param_def.bounds.trait_bounds, + param_numbered(n), + trait_ref) } ty::ty_self(trait_id) => { - debug!("trying to find %? vtable for type %?", - trait_ref.def_id, trait_id); + let self_trait_ref = ty::lookup_trait_def(tcx, trait_id).trait_ref; + lookup_vtable_from_bounds(vcx, location_info, + &[self_trait_ref], + param_self, + trait_ref) + } - if trait_id == trait_ref.def_id { - let vtable = vtable_self(trait_id); - debug!("found self vtable: %?", vtable); - return Some(vtable); - } + // Default case just falls through + _ => None + }; + + if vtable_opt.is_some() { return vtable_opt; } + + // If we aren't a self type or param, or it was, but we didn't find it, + // do a search. + return search_for_vtable(vcx, location_info, + ty, trait_ref, is_early) +} + +// Given a list of bounds on a type, search those bounds to see if any +// of them are the vtable we are looking for. +fn lookup_vtable_from_bounds(vcx: &VtableContext, + location_info: &LocationInfo, + bounds: &[@ty::TraitRef], + param: param_index, + trait_ref: @ty::TraitRef) + -> Option<vtable_origin> { + let tcx = vcx.tcx(); + + let mut n_bound = 0; + for ty::each_bound_trait_and_supertraits(tcx, bounds) |bound_trait_ref| { + debug!("checking bounds trait %s", + bound_trait_ref.repr(vcx.tcx())); + + if bound_trait_ref.def_id == trait_ref.def_id { + relate_trait_refs(vcx, + location_info, + bound_trait_ref, + trait_ref); + let vtable = vtable_param(param, n_bound); + debug!("found param vtable: %?", + vtable); + return Some(vtable); } - _ => { - let mut found = ~[]; + n_bound += 1; + } - let mut impls_seen = HashSet::new(); + return None; +} - match tcx.trait_impls.find(&trait_ref.def_id) { - None => { - // Nothing found. Continue. - } - Some(implementations) => { - // implementations is the list of all impls in scope for - // trait_ref. (Usually, there's just one.) - for implementations.iter().advance |im| { - // im is one specific impl of trait_ref. - - // First, ensure we haven't processed this impl yet. - if impls_seen.contains(&im.did) { - loop; - } - impls_seen.insert(im.did); - - // ty::impl_traits gives us the trait im implements, - // if there is one (there's either zero or one). - // - // If foo implements a trait t, and if t is the - // same trait as trait_ref, we need to - // unify it with trait_ref in order to get all - // the ty vars sorted out. - let r = ty::impl_trait_ref(tcx, im.did); - for r.iter().advance |&of_trait_ref| { - if of_trait_ref.def_id != trait_ref.def_id { loop; } - - // At this point, we know that of_trait_ref is - // the same trait as trait_ref, but - // possibly applied to different substs. - // - // Next, we check whether the "for" ty in - // the impl is compatible with the type - // that we're casting to a trait. That is, - // if im is: - // - // impl<T> self_ty<T>: some_trait<T> { ... } - // - // we check whether self_ty<T> is the type - // of the thing that we're trying to cast - // to some_trait. If not, then we try the next - // impl. - // - // FIXME(#5781) this should be mk_eqty not mk_subty - let ty::ty_param_substs_and_ty { - substs: substs, - ty: for_ty - } = impl_self_ty(vcx, location_info, im.did); - match infer::mk_subty(vcx.infcx, - false, - infer::RelateSelfType( - location_info.span), - ty, - for_ty) { - result::Err(_) => loop, - result::Ok(()) => () - } - - // Now, in the previous example, for_ty is - // bound to the type self_ty, and substs - // is bound to [T]. - debug!("The self ty is %s and its substs are %s", - vcx.infcx.ty_to_str(for_ty), - tys_to_str(vcx.tcx(), substs.tps)); - - // Next, we unify trait_ref -- the type - // that we want to cast to -- with of_trait_ref - // -- the trait that im implements. At - // this point, we require that they be - // unifiable with each other -- that's - // what relate_trait_refs does. - // - // For example, in the above example, - // of_trait_ref would be some_trait<T>, so we - // would be unifying trait_ref<U> (for some - // value of U) with some_trait<T>. This - // would fail if T and U weren't - // compatible. - - debug!("(checking vtable) @2 relating trait \ - ty %s to of_trait_ref %s", - 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); - relate_trait_refs( - vcx, location_info, - of_trait_ref, trait_ref); - - // Recall that trait_ref -- the trait type - // we're casting to -- is the trait with - // id trait_ref.def_id applied to the substs - // trait_ref.substs. Now we extract out the - // types themselves from trait_ref.substs. - - // Recall that substs is the impl self - // type's list of substitutions. That is, - // if this is an impl of some trait for - // foo<T, U>, then substs is [T, - // U]. substs might contain type - // variables, so we call fixup_substs to - // resolve them. - - let substs_f = match fixup_substs(vcx, - location_info, - trait_ref.def_id, - substs, - is_early) { - Some(ref substs) => (*substs).clone(), - None => { - assert!(is_early); - // Bail out with a bogus answer - return Some(vtable_param(0, 0)); - } - }; - - debug!("The fixed-up substs are %s - \ - they will be unified with the bounds for \ - the target ty, %s", - tys_to_str(vcx.tcx(), substs_f.tps), - vcx.infcx.trait_ref_to_str(trait_ref)); - - // Next, we unify the fixed-up - // substitutions for the impl self ty with - // the substitutions from the trait type - // that we're trying to cast - // to. connect_trait_tps requires these - // lists of types to unify pairwise. - - let im_generics = - ty::lookup_item_type(tcx, im.did).generics; - connect_trait_tps(vcx, - location_info, - &substs_f, - trait_ref, - im.did); - let subres = lookup_vtables( - vcx, location_info, - *im_generics.type_param_defs, &substs_f, - is_early); - - // Finally, we register that we found a - // matching impl, and record the def ID of - // the impl as well as the resolved list - // of type substitutions for the target - // trait. - found.push(vtable_static(im.did, - substs_f.tps.clone(), - subres)); - } - } - } +fn search_for_vtable(vcx: &VtableContext, + location_info: &LocationInfo, + ty: ty::t, + trait_ref: @ty::TraitRef, + is_early: bool) + -> Option<vtable_origin> +{ + let tcx = vcx.tcx(); + + let mut found = ~[]; + let mut impls_seen = HashSet::new(); + + // XXX: this is a bad way to do this, since we do + // pointless allocations. + let impls = tcx.trait_impls.find(&trait_ref.def_id) + .map_default(@mut ~[], |x| **x); + // impls is the list of all impls in scope for trait_ref. + for impls.iter().advance |im| { + // im is one specific impl of trait_ref. + + // First, ensure we haven't processed this impl yet. + if impls_seen.contains(&im.did) { + loop; + } + impls_seen.insert(im.did); + + // ty::impl_traits gives us the trait im implements. + // + // If foo implements a trait t, and if t is the same trait as + // trait_ref, we need to unify it with trait_ref in order to + // get all the ty vars sorted out. + let r = ty::impl_trait_ref(tcx, im.did); + let of_trait_ref = r.expect("trait_ref missing on trait impl"); + if of_trait_ref.def_id != trait_ref.def_id { loop; } + + // At this point, we know that of_trait_ref is the same trait + // as trait_ref, but possibly applied to different substs. + // + // Next, we check whether the "for" ty in the impl is + // compatible with the type that we're casting to a + // trait. That is, if im is: + // + // impl<T> some_trait<T> for self_ty<T> { ... } + // + // we check whether self_ty<T> is the type of the thing that + // we're trying to cast to some_trait. If not, then we try + // the next impl. + // + // XXX: document a bit more what this means + // + // FIXME(#5781) this should be mk_eqty not mk_subty + let ty::ty_param_substs_and_ty { + substs: substs, + ty: for_ty + } = impl_self_ty(vcx, location_info, im.did); + match infer::mk_subty(vcx.infcx, + false, + infer::RelateSelfType( + location_info.span), + ty, + for_ty) { + result::Err(_) => loop, + result::Ok(()) => () + } + + // Now, in the previous example, for_ty is bound to + // the type self_ty, and substs is bound to [T]. + debug!("The self ty is %s and its substs are %s", + vcx.infcx.ty_to_str(for_ty), + vcx.infcx.tys_to_str(substs.tps)); + + // Next, we unify trait_ref -- the type that we want to cast + // to -- with of_trait_ref -- the trait that im implements. At + // this point, we require that they be unifiable with each + // other -- that's what relate_trait_refs does. + // + // For example, in the above example, of_trait_ref would be + // some_trait<T>, so we would be unifying trait_ref<U> (for + // some value of U) with some_trait<T>. This would fail if T + // and U weren't compatible. + + debug!("(checking vtable) @2 relating trait \ + ty %s to of_trait_ref %s", + 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); + relate_trait_refs(vcx, location_info, of_trait_ref, trait_ref); + + + // Recall that trait_ref -- the trait type we're casting to -- + // is the trait with id trait_ref.def_id applied to the substs + // trait_ref.substs. + + // Resolve any sub bounds. Note that there still may be free + // type variables in substs. This might still be OK: the + // process of looking up bounds might constrain some of them. + let im_generics = + ty::lookup_item_type(tcx, im.did).generics; + let subres = lookup_vtables(vcx, location_info, + *im_generics.type_param_defs, &substs, + is_early); + + + // substs might contain type variables, so we call + // fixup_substs to resolve them. + let substs_f = match fixup_substs(vcx, + location_info, + trait_ref.def_id, + substs, + is_early) { + Some(ref substs) => (*substs).clone(), + None => { + assert!(is_early); + // Bail out with a bogus answer + return Some(vtable_param(param_self, 0)); } + }; + + debug!("The fixed-up substs are %s - \ + they will be unified with the bounds for \ + the target ty, %s", + vcx.infcx.tys_to_str(substs_f.tps), + vcx.infcx.trait_ref_to_str(trait_ref)); + + // Next, we unify the fixed-up substitutions for the impl self + // ty with the substitutions from the trait type that we're + // trying to cast to. connect_trait_tps requires these lists + // of types to unify pairwise. + // I am a little confused about this, since it seems to be + // very similar to the relate_trait_refs we already do, + // but problems crop up if it is removed, so... -sully + connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did); + + // Finally, we register that we found a matching impl, and + // record the def ID of the impl as well as the resolved list + // of type substitutions for the target trait. + found.push(vtable_static(im.did, substs_f.tps.clone(), subres)); + } - match found.len() { - 0 => { /* fallthrough */ } - 1 => return Some(found[0].clone()), - _ => { - if !is_early { - vcx.tcx().sess.span_err( - location_info.span, - "multiple applicable methods in scope"); - } - return Some(found[0].clone()); - } + match found.len() { + 0 => { return None } + 1 => return Some(found[0].clone()), + _ => { + if !is_early { + vcx.tcx().sess.span_err( + location_info.span, + "multiple applicable methods in scope"); } + return Some(found[0].clone()); } } +} - return None; + +fn fixup_substs(vcx: &VtableContext, + location_info: &LocationInfo, + id: ast::def_id, + substs: ty::substs, + is_early: bool) + -> Option<ty::substs> { + let tcx = vcx.tcx(); + // use a dummy type just to package up the substs that need fixing up + let t = ty::mk_trait(tcx, + id, substs, + ty::RegionTraitStore(ty::re_static), + 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, _, _, _) => (*substs_f).clone(), + _ => fail!("t_f should be a trait") + } + } } fn fixup_ty(vcx: &VtableContext, @@ -590,7 +641,7 @@ pub fn early_resolve_expr(ex: @ast::expr, def_id: target_def_id, substs: ty::substs { tps: target_substs.tps.clone(), - self_r: target_substs.self_r, + regions: target_substs.regions.clone(), self_ty: Some(mt.ty) } }; @@ -682,16 +733,39 @@ pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { 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 loc_info = location_info_for_item(impl_item); + // First, check that the impl implements any trait bounds + // on the trait. + let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id); let vtbls = lookup_vtables(&vcx, - &location_info_for_item(impl_item), + &loc_info, *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); + // Now, locate the vtable for the impl itself. The real + // purpose of this is to check for supertrait impls, + // but that falls out of doing this. + let param_bounds = ty::ParamBounds { + builtin_bounds: ty::EmptyBuiltinBounds(), + trait_bounds: ~[trait_ref] + }; + let t = ty::node_id_to_type(ccx.tcx, impl_item.id); + debug!("=== Doing a self lookup now."); + // Right now, we don't have any place to store this. + // We will need to make one so we can use this information + // for compiling default methods that refer to supertraits. + let self_vtable_res = + lookup_vtables_for_param(&vcx, &loc_info, None, + ¶m_bounds, t, false); + + + let res = impl_res { + trait_vtables: vtbls, + self_vtables: self_vtable_res + }; + ccx.tcx.impl_vtables.insert(def_id, res); } } } diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 4d437d83f2a..a7319d4b008 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -20,7 +20,7 @@ use middle::typeck::infer::{force_all, resolve_all, resolve_region}; use middle::typeck::infer::resolve_type; use middle::typeck::infer; use middle::typeck::{vtable_res, vtable_origin}; -use middle::typeck::{vtable_static, vtable_param, vtable_self}; +use middle::typeck::{vtable_static, vtable_param}; use middle::typeck::method_map_entry; use middle::typeck::write_substs_to_tcx; use middle::typeck::write_ty_to_tcx; @@ -109,9 +109,6 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { &vtable_param(n, b) => { vtable_param(n, b) } - &vtable_self(def_id) => { - vtable_self(def_id) - } } } } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 84a2627c87c..4298f043e93 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -45,6 +45,7 @@ use syntax::ast_map; use syntax::ast_util::{def_id_of_def, local_def}; use syntax::codemap::{span, dummy_sp}; use syntax::parse; +use syntax::opt_vec; use syntax::visit::{default_simple_visitor, default_visitor}; use syntax::visit::{mk_simple_visitor, mk_vt, visit_crate, visit_item}; use syntax::visit::{Visitor, SimpleVisitor}; @@ -436,16 +437,20 @@ impl CoherenceChecker { pub fn universally_quantify_polytype(&self, polytype: ty_param_bounds_and_ty) -> UniversalQuantificationResult { - let self_region = - polytype.generics.region_param.map( - |_| self.inference_context.next_region_var( - infer::BoundRegionInCoherence)); + let regions = match polytype.generics.region_param { + None => opt_vec::Empty, + Some(_) => { + opt_vec::with( + 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); let substitutions = substs { - self_r: self_region, + regions: ty::NonerasedRegions(regions), self_ty: None, tps: type_parameters }; @@ -453,13 +458,9 @@ impl CoherenceChecker { &substitutions, polytype.ty); - // Get our type parameters back. - let substs { self_r: _, self_ty: _, tps: type_parameters } = - substitutions; - UniversalQuantificationResult { monotype: monotype, - type_variables: type_parameters, + type_variables: substitutions.tps, type_param_defs: polytype.generics.type_param_defs } } @@ -845,7 +846,7 @@ pub fn make_substs_for_receiver_types(tcx: ty::ctxt, }); return ty::substs { - self_r: trait_ref.substs.self_r, + regions: trait_ref.substs.regions.clone(), self_ty: trait_ref.substs.self_ty, tps: combined_tps }; diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 3db881dac1a..98b4de9d719 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -301,7 +301,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, // Self => D' // D,E,F => E',F',G' let substs = substs { - self_r: None, + regions: ty::NonerasedRegions(opt_vec::Empty), self_ty: Some(self_param), tps: non_shifted_trait_tps + shifted_method_tps }; @@ -622,7 +622,7 @@ pub fn compare_impl_method(tcx: ty::ctxt, let trait_tps = trait_substs.tps.map( |t| replace_bound_self(tcx, *t, dummy_self_r)); let substs = substs { - self_r: Some(dummy_self_r), + regions: ty::NonerasedRegions(opt_vec::with(dummy_self_r)), self_ty: Some(self_ty), tps: vec::append(trait_tps, dummy_tps) }; @@ -1268,6 +1268,8 @@ pub fn mk_item_substs(ccx: &CrateCtxt, i += 1u; t }); - let self_r = rscope::bound_self_region(rp); - (ty_generics, substs {self_r: self_r, self_ty: self_ty, tps: params}) + let regions = rscope::bound_self_region(rp); + (ty_generics, substs {regions: ty::NonerasedRegions(regions), + self_ty: self_ty, + tps: params}) } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 65fbd080561..b1492cac16e 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -197,56 +197,67 @@ pub fn super_substs<C:Combine>( this: &C, generics: &ty::Generics, a: &ty::substs, b: &ty::substs) -> cres<ty::substs> { - fn relate_region_param<C:Combine>( + fn relate_region_params<C:Combine>( this: &C, generics: &ty::Generics, - a: Option<ty::Region>, - b: Option<ty::Region>) - -> cres<Option<ty::Region>> + a: &ty::RegionSubsts, + b: &ty::RegionSubsts) + -> cres<ty::RegionSubsts> { - match (&generics.region_param, &a, &b) { - (&None, &None, &None) => { - Ok(None) - } - (&Some(ty::rv_invariant), &Some(a), &Some(b)) => { - do eq_regions(this, a, b).then { - Ok(Some(a)) - } - } - (&Some(ty::rv_covariant), &Some(a), &Some(b)) => { - do this.regions(a, b).chain |r| { - Ok(Some(r)) + match (a, b) { + (&ty::ErasedRegions, _) | + (_, &ty::ErasedRegions) => { + Ok(ty::ErasedRegions) } - } - (&Some(ty::rv_contravariant), &Some(a), &Some(b)) => { - do this.contraregions(a, b).chain |r| { - Ok(Some(r)) + + (&ty::NonerasedRegions(ref a_rs), + &ty::NonerasedRegions(ref b_rs)) => { + match generics.region_param { + None => { + assert!(a_rs.is_empty()); + assert!(b_rs.is_empty()); + Ok(ty::NonerasedRegions(opt_vec::Empty)) + } + + Some(variance) => { + assert_eq!(a_rs.len(), 1); + assert_eq!(b_rs.len(), 1); + let a_r = *a_rs.get(0); + let b_r = *b_rs.get(0); + + match variance { + ty::rv_invariant => { + do eq_regions(this, a_r, b_r).then { + Ok(ty::NonerasedRegions(opt_vec::with(a_r))) + } + } + + ty::rv_covariant => { + do this.regions(a_r, b_r).chain |r| { + Ok(ty::NonerasedRegions(opt_vec::with(r))) + } + } + + ty::rv_contravariant => { + do this.contraregions(a_r, b_r).chain |r| { + Ok(ty::NonerasedRegions(opt_vec::with(r))) + } + } + } + } + } } - } - (_, _, _) => { - // If these two substitutions are for the same type (and - // they should be), then the type should either - // consistently have a region parameter or not have a - // region parameter, and that should match with the - // polytype. - this.infcx().tcx.sess.bug( - fmt!("substitution a had opt_region %s and \ - b had opt_region %s with variance %?", - a.inf_str(this.infcx()), - b.inf_str(this.infcx()), - generics.region_param)); - } } } do this.tps(a.tps, b.tps).chain |tps| { do this.self_tys(a.self_ty, b.self_ty).chain |self_ty| { - do relate_region_param(this, - generics, - a.self_r, - b.self_r).chain |self_r| { + do relate_region_params(this, + generics, + &a.regions, + &b.regions).chain |regions| { Ok(substs { - self_r: self_r, + regions: regions, self_ty: self_ty, tps: tps.clone() }) diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 1f0fb135762..eb32f4e59f0 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -653,6 +653,11 @@ impl InferCtxt { self.resolve_type_vars_if_possible(t)) } + pub fn tys_to_str(@mut self, ts: &[ty::t]) -> ~str { + let tstrs = ts.map(|t| self.ty_to_str(*t)); + fmt!("(%s)", tstrs.connect(", ")) + } + pub fn trait_ref_to_str(@mut self, t: &ty::TraitRef) -> ~str { let t = self.resolve_type_vars_in_trait_ref_if_possible(t); trait_ref_to_str(self.tcx, &t) diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 81b18e746b2..0ea00e15863 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -75,14 +75,14 @@ pub mod infer; pub mod collect; pub mod coherence; +#[deriving(Clone, Encodable, Decodable, Eq, Ord)] +pub enum param_index { + param_numbered(uint), + param_self +} + #[deriving(Clone, Encodable, Decodable)] pub enum method_origin { - // supertrait method invoked on "self" inside a default method - // first field is supertrait ID; - // second field is method index (relative to the *supertrait* - // method list) - method_super(ast::def_id, uint), - // fully statically resolved method method_static(ast::def_id), @@ -92,9 +92,6 @@ pub enum method_origin { // method invoked on a trait instance method_trait(ast::def_id, uint, ty::TraitStore), - // method invoked on "self" inside a default method - method_self(ast::def_id, uint) - } // details for a method invoked with a receiver whose type is a type parameter @@ -109,7 +106,7 @@ pub struct method_param { // index of the type parameter (from those that are in scope) that is // the type of the receiver - param_num: uint, + param_num: param_index, // index of the bound for this type parameter which specifies the trait bound_num: uint, @@ -153,15 +150,10 @@ pub enum vtable_origin { fn foo<T:quux,baz,bar>(a: T) -- a's vtable would have a vtable_param origin - The first uint is the param number (identifying T in the example), + The first argument is the param index (identifying T in the example), and the second is the bound number (identifying baz) */ - vtable_param(uint, uint), - - /* - Dynamic vtable, comes from self. - */ - vtable_self(ast::def_id) + vtable_param(param_index, uint), } impl Repr for vtable_origin { @@ -178,15 +170,34 @@ impl Repr for vtable_origin { vtable_param(x, y) => { fmt!("vtable_param(%?, %?)", x, y) } - vtable_self(def_id) => { - fmt!("vtable_self(%?)", def_id) - } } } } pub type vtable_map = @mut HashMap<ast::node_id, vtable_res>; + +// Information about the vtable resolutions for for a trait impl. +// Mostly the information is important for implementing default +// methods. +#[deriving(Clone)] +pub struct impl_res { + // resolutions for any bounded params on the trait definition + trait_vtables: vtable_res, + // resolutions for the trait /itself/ (and for supertraits) + self_vtables: vtable_param_res +} + +impl Repr for impl_res { + fn repr(&self, tcx: ty::ctxt) -> ~str { + fmt!("impl_res {trait_vtables=%s, self_vtables=%s}", + self.trait_vtables.repr(tcx), + self.self_vtables.repr(tcx)) + } +} + +pub type impl_vtable_map = @mut HashMap<ast::def_id, impl_res>; + pub struct CrateCtxt { // A mapping from method call sites to traits that have that method. trait_map: resolve::TraitMap, diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index 2f319687f6c..94d30fd9a87 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -260,10 +260,10 @@ impl region_scope for type_rscope { } pub fn bound_self_region(rp: Option<ty::region_variance>) - -> Option<ty::Region> { + -> OptVec<ty::Region> { match rp { - Some(_) => Some(ty::re_bound(ty::br_self)), - None => None + Some(_) => opt_vec::with(ty::re_bound(ty::br_self)), + None => opt_vec::Empty } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 32ac5e72928..a8967e7a878 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -30,6 +30,8 @@ use syntax::codemap::span; use syntax::parse::token; use syntax::print::pprust; use syntax::{ast, ast_util}; +use syntax::opt_vec; +use syntax::opt_vec::OptVec; /// Produces a string suitable for debugging output. pub trait Repr { @@ -451,12 +453,12 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { ty_enum(did, ref substs) | ty_struct(did, ref substs) => { let path = ty::item_path(cx, did); let base = ast_map::path_to_str(path, cx.sess.intr()); - parameterized(cx, base, substs.self_r, substs.tps) + parameterized(cx, base, &substs.regions, substs.tps) } 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); + let ty = parameterized(cx, base, &substs.regions, substs.tps); 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, @@ -475,16 +477,18 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { pub fn parameterized(cx: ctxt, base: &str, - self_r: Option<ty::Region>, + regions: &ty::RegionSubsts, tps: &[ty::t]) -> ~str { let mut strs = ~[]; - match self_r { - None => (), - Some(r) => { - strs.push(region_to_str(cx, "", false, r)) + match *regions { + ty::ErasedRegions => { } + ty::NonerasedRegions(ref regions) => { + for regions.iter().advance |&r| { + strs.push(region_to_str(cx, "", false, r)) + } } - }; + } for tps.iter().advance |t| { strs.push(ty_to_str(cx, *t)) @@ -534,6 +538,15 @@ impl<'self, T:Repr> Repr for &'self [T] { } } +impl<T:Repr> Repr for OptVec<T> { + fn repr(&self, tcx: ctxt) -> ~str { + match *self { + opt_vec::Empty => ~"[]", + opt_vec::Vec(ref v) => repr_vec(tcx, *v) + } + } +} + // This is necessary to handle types like Option<~[T]>, for which // autoderef cannot convert the &[T] handler impl<T:Repr> Repr for ~[T] { @@ -557,13 +570,22 @@ impl Repr for ty::t { impl Repr for ty::substs { fn repr(&self, tcx: ctxt) -> ~str { - fmt!("substs(self_r=%s, self_ty=%s, tps=%s)", - self.self_r.repr(tcx), + fmt!("substs(regions=%s, self_ty=%s, tps=%s)", + self.regions.repr(tcx), self.self_ty.repr(tcx), self.tps.repr(tcx)) } } +impl Repr for ty::RegionSubsts { + fn repr(&self, tcx: ctxt) -> ~str { + match *self { + ty::ErasedRegions => ~"erased", + ty::NonerasedRegions(ref regions) => regions.repr(tcx) + } + } +} + impl Repr for ty::ParamBounds { fn repr(&self, tcx: ctxt) -> ~str { let mut res = ~[]; @@ -715,10 +737,6 @@ impl Repr for typeck::method_map_entry { impl Repr for typeck::method_origin { fn repr(&self, tcx: ctxt) -> ~str { match self { - &typeck::method_super(def_id, n) => { - fmt!("method_super(%s, %?)", - def_id.repr(tcx), n) - } &typeck::method_static(def_id) => { fmt!("method_static(%s)", def_id.repr(tcx)) } @@ -729,9 +747,6 @@ impl Repr for typeck::method_origin { fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n, st.repr(tcx)) } - &typeck::method_self(def_id, n) => { - fmt!("method_self(%s, %?)", def_id.repr(tcx), n) - } } } } @@ -832,10 +847,9 @@ impl UserString for ty::TraitRef { if tcx.sess.verbose() && self.substs.self_ty.is_some() { let mut all_tps = self.substs.tps.clone(); for self.substs.self_ty.iter().advance |&t| { all_tps.push(t); } - parameterized(tcx, base, self.substs.self_r, all_tps) + parameterized(tcx, base, &self.substs.regions, all_tps) } else { - parameterized(tcx, base, self.substs.self_r, - self.substs.tps) + parameterized(tcx, base, &self.substs.regions, self.substs.tps) } } } diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index 13354e61284..0b2519e6fb4 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -10,13 +10,13 @@ //! Managed vectors -use cast::transmute; use clone::Clone; use container::Container; use iterator::IteratorUtil; use option::Option; use sys; use uint; +use unstable::raw::Repr; use vec::{ImmutableVector, OwnedVector}; /// Code for dealing with @-vectors. This is pretty incomplete, and @@ -26,8 +26,8 @@ use vec::{ImmutableVector, OwnedVector}; #[inline] pub fn capacity<T>(v: @[T]) -> uint { unsafe { - let repr: **raw::VecRepr = transmute(&v); - (**repr).unboxed.alloc / sys::size_of::<T>() + let box = v.repr(); + (*box).data.alloc / sys::size_of::<T>() } } @@ -45,10 +45,10 @@ pub fn capacity<T>(v: @[T]) -> uint { */ #[inline] pub fn build_sized<A>(size: uint, builder: &fn(push: &fn(v: A))) -> @[A] { - let mut vec: @[A] = @[]; + let mut vec = @[]; unsafe { raw::reserve(&mut vec, size); } builder(|x| unsafe { raw::push(&mut vec, x) }); - return unsafe { transmute(vec) }; + vec } /** @@ -151,7 +151,7 @@ pub fn to_managed_consume<T>(v: ~[T]) -> @[T] { for v.consume_iter().advance |x| { raw::push(&mut av, x); } - transmute(av) + av } } @@ -195,13 +195,9 @@ pub mod raw { use ptr; use sys; use uint; - use unstable::intrinsics; use unstable::intrinsics::{move_val_init, TyDesc}; - use vec; - use vec::UnboxedVecRepr; - - pub type VecRepr = vec::raw::VecRepr; - pub type SliceRepr = vec::raw::SliceRepr; + use unstable::intrinsics; + use unstable::raw::{Box, Vec}; /** * Sets the length of a vector @@ -211,9 +207,9 @@ pub mod raw { * the vector is actually the specified size. */ #[inline] - pub unsafe fn set_len<T>(v: @[T], new_len: uint) { - let repr: **mut VecRepr = transmute(&v); - (**repr).unboxed.fill = new_len * sys::size_of::<T>(); + pub unsafe fn set_len<T>(v: &mut @[T], new_len: uint) { + let repr: *mut Box<Vec<T>> = cast::transmute_copy(v); + (*repr).data.fill = new_len * sys::size_of::<T>(); } /** @@ -221,9 +217,11 @@ pub mod raw { */ #[inline] pub unsafe fn push<T>(v: &mut @[T], initval: T) { - let repr: **VecRepr = transmute_copy(&v); - let fill = (**repr).unboxed.fill; - if (**repr).unboxed.alloc > fill { + let full = { + let repr: *Box<Vec<T>> = cast::transmute_copy(v); + (*repr).data.alloc > (*repr).data.fill + }; + if full { push_fast(v, initval); } else { push_slow(v, initval); @@ -232,16 +230,15 @@ pub mod raw { #[inline] // really pretty please unsafe fn push_fast<T>(v: &mut @[T], initval: T) { - let repr: **mut VecRepr = ::cast::transmute(v); - let fill = (**repr).unboxed.fill; - (**repr).unboxed.fill += sys::size_of::<T>(); - let p = &((**repr).unboxed.data); - let p = ptr::offset(p, fill) as *mut T; + let repr: *mut Box<Vec<T>> = cast::transmute_copy(v); + let amt = v.len(); + (*repr).data.fill += sys::size_of::<T>(); + let p = ptr::offset(&(*repr).data.data as *T, amt) as *mut T; move_val_init(&mut(*p), initval); } unsafe fn push_slow<T>(v: &mut @[T], initval: T) { - reserve_at_least(&mut *v, v.len() + 1u); + reserve_at_least(v, v.len() + 1u); push_fast(v, initval); } @@ -259,7 +256,7 @@ pub mod raw { pub unsafe fn reserve<T>(v: &mut @[T], n: uint) { // Only make the (slow) call into the runtime if we have to if capacity(*v) < n { - let ptr: *mut *mut VecRepr = transmute(v); + let ptr: *mut *mut Box<Vec<()>> = transmute(v); let ty = intrinsics::get_tydesc::<T>(); // XXX transmute shouldn't be necessary let ty = cast::transmute(ty); @@ -269,16 +266,14 @@ pub mod raw { // Implementation detail. Shouldn't be public #[allow(missing_doc)] - pub fn reserve_raw(ty: *TyDesc, ptr: *mut *mut VecRepr, n: uint) { + pub fn reserve_raw(ty: *TyDesc, ptr: *mut *mut Box<Vec<()>>, n: uint) { unsafe { let size_in_bytes = n * (*ty).size; - if size_in_bytes > (**ptr).unboxed.alloc { - let total_size = size_in_bytes + sys::size_of::<UnboxedVecRepr>(); - // XXX: UnboxedVecRepr has an extra u8 at the end - let total_size = total_size - sys::size_of::<u8>(); - (*ptr) = local_realloc(*ptr as *(), total_size) as *mut VecRepr; - (**ptr).unboxed.alloc = size_in_bytes; + if size_in_bytes > (**ptr).data.alloc { + let total_size = size_in_bytes + sys::size_of::<Vec<()>>(); + (*ptr) = local_realloc(*ptr as *(), total_size) as *mut Box<Vec<()>>; + (**ptr).data.alloc = size_in_bytes; } } diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs index 126650981cd..eeaea6a2cff 100644 --- a/src/libstd/bool.rs +++ b/src/libstd/bool.rs @@ -24,6 +24,7 @@ Implementations of the following traits: * `Ord` * `TotalOrd` * `Eq` +* `Zero` ## Various functions to compare `bool`s @@ -36,14 +37,14 @@ Finally, some inquries into the nature of truth: `is_true` and `is_false`. */ -#[cfg(not(test))] -use cmp::{Eq, Ord, TotalOrd, Ordering}; -#[cfg(not(test))] -use ops::Not; use option::{None, Option, Some}; use from_str::FromStr; use to_str::ToStr; +#[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering}; +#[cfg(not(test))] use ops::Not; +#[cfg(not(test))] use num::Zero; + /** * Negation of a boolean value. * @@ -330,6 +331,12 @@ impl Eq for bool { fn ne(&self, other: &bool) -> bool { (*self) != (*other) } } +#[cfg(not(test))] +impl Zero for bool { + fn zero() -> bool { false } + fn is_zero(&self) -> bool { *self == false } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/libstd/cast.rs b/src/libstd/cast.rs index 86eec80ae6f..ee91d127909 100644 --- a/src/libstd/cast.rs +++ b/src/libstd/cast.rs @@ -133,6 +133,7 @@ pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T { #[cfg(test)] mod tests { use cast::{bump_box_refcount, transmute}; + use unstable::raw; #[test] fn test_transmute_copy() { @@ -156,10 +157,9 @@ mod tests { #[test] fn test_transmute() { - use managed::raw::BoxRepr; unsafe { let x = @100u8; - let x: *BoxRepr = transmute(x); + let x: *raw::Box<u8> = transmute(x); assert!((*x).data == 100); let _x: @int = transmute(x); } diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs index 2ea10b09c8e..ed2b0e16818 100644 --- a/src/libstd/cleanup.rs +++ b/src/libstd/cleanup.rs @@ -12,9 +12,8 @@ use libc::c_void; use ptr::{mut_null}; -use repr::BoxRepr; -use cast::transmute; use unstable::intrinsics::TyDesc; +use unstable::raw; type DropGlue<'self> = &'self fn(**TyDesc, *c_void); @@ -31,27 +30,25 @@ struct AnnihilateStats { } unsafe fn each_live_alloc(read_next_before: bool, - f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) -> bool { + f: &fn(box: *mut raw::Box<()>, uniq: bool) -> bool) -> bool { //! Walks the internal list of allocations use managed; use rt::local_heap; - let box = local_heap::live_allocs(); - let mut box: *mut BoxRepr = transmute(box); + let mut box = local_heap::live_allocs(); while box != mut_null() { - let next_before = transmute((*box).header.next); - let uniq = - (*box).header.ref_count == managed::raw::RC_MANAGED_UNIQUE; + let next_before = (*box).next; + let uniq = (*box).ref_count == managed::RC_MANAGED_UNIQUE; - if !f(box, uniq) { + if !f(box as *mut raw::Box<()>, uniq) { return false; } if read_next_before { box = next_before; } else { - box = transmute((*box).header.next); + box = (*box).next; } } return true; @@ -102,7 +99,7 @@ pub unsafe fn annihilate() { if uniq { stats.n_unique_boxes += 1; } else { - (*box).header.ref_count = managed::raw::RC_IMMORTAL; + (*box).ref_count = managed::RC_IMMORTAL; } } @@ -113,9 +110,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: *TyDesc = transmute((*box).header.type_desc); - let data = transmute(&(*box).data); - ((*tydesc).drop_glue)(data); + let tydesc = (*box).type_desc; + let data = &(*box).data as *(); + ((*tydesc).drop_glue)(data as *i8); } } @@ -128,9 +125,9 @@ pub unsafe fn annihilate() { for each_live_alloc(true) |box, uniq| { if !uniq { stats.n_bytes_freed += - (*((*box).header.type_desc)).size - + sys::size_of::<BoxRepr>(); - local_free(transmute(box)); + (*((*box).type_desc)).size + + sys::size_of::<raw::Box<()>>(); + local_free(box as *i8); } } diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index 8a13cab28c3..7991e1cb56e 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -21,7 +21,6 @@ and `Eq` to overload the `==` and `!=` operators. */ #[allow(missing_doc)]; -#[allow(default_methods)]; // NOTE: Remove when allowed in stage0 /** * Trait for values that can be compared for equality and inequality. @@ -86,6 +85,12 @@ pub trait TotalOrd: TotalEq { fn cmp(&self, other: &Self) -> Ordering; } +impl TotalEq for Ordering { + #[inline] + fn equals(&self, other: &Ordering) -> bool { + *self == *other + } +} impl TotalOrd for Ordering { #[inline] fn cmp(&self, other: &Ordering) -> Ordering { diff --git a/src/libstd/gc.rs b/src/libstd/gc.rs index 911fb5625e5..4feec26a2d9 100644 --- a/src/libstd/gc.rs +++ b/src/libstd/gc.rs @@ -74,14 +74,14 @@ pub mod rustrt { } unsafe fn bump<T, U>(ptr: *T, count: uint) -> *U { - return cast::transmute(ptr::offset(ptr, count)); + return ptr::offset(ptr, count) as *U; } unsafe fn align_to_pointer<T>(ptr: *T) -> *T { let align = sys::min_align_of::<*T>(); - let ptr: uint = cast::transmute(ptr); + let ptr = ptr as uint; let ptr = (ptr + (align - 1)) & -align; - return cast::transmute(ptr); + return ptr as *T; } unsafe fn get_safe_point_count() -> uint { @@ -126,8 +126,8 @@ 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. unsafe fn _walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) -> bool { - let fp_bytes: *u8 = cast::transmute(fp); - let sp_meta: *u32 = cast::transmute(sp.sp_meta); + let fp_bytes = fp as *u8; + let sp_meta = sp.sp_meta as *u32; let num_stack_roots = *sp_meta as uint; let num_reg_roots = *ptr::offset(sp_meta, 1) as uint; @@ -173,9 +173,9 @@ unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) -> bool { // Is fp contained in segment? unsafe fn is_frame_in_segment(fp: *Word, segment: *StackSegment) -> bool { - let begin: Word = cast::transmute(segment); - let end: Word = cast::transmute((*segment).end); - let frame: Word = cast::transmute(fp); + let begin = segment as Word; + let end = (*segment).end as Word; + let frame = fp as Word; return begin <= frame && frame <= end; } diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 0c2a7bb7b40..36645a555bb 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -17,8 +17,6 @@ implementing the `Iterator` trait. */ -#[allow(default_methods)]; // still off by default in stage0 - use cmp; use iter::Times; use num::{Zero, One}; @@ -96,7 +94,7 @@ impl<A, T: DoubleEndedIterator<A>> Iterator<A> for InvertIterator<A, T> { fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } } -impl<A, T: Iterator<A>> DoubleEndedIterator<A> for InvertIterator<A, T> { +impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for InvertIterator<A, T> { #[inline] fn next_back(&mut self) -> Option<A> { self.iter.next() } } @@ -343,6 +341,18 @@ pub trait IteratorUtil<A> { /// ~~~ fn collect<B: FromIterator<A, Self>>(&mut self) -> B; + /// Loops through the entire iterator, collecting all of the elements into + /// a unique vector. This is simply collect() specialized for vectors. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let b: ~[int] = a.iter().transform(|&x| x).to_owned_vec(); + /// assert!(a == b); + /// ~~~ + fn to_owned_vec(&mut self) -> ~[A]; + /// Loops through `n` iterations, returning the `n`th element of the /// iterator. /// @@ -539,6 +549,11 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { FromIterator::from_iterator(self) } + #[inline] + fn to_owned_vec(&mut self) -> ~[A] { + self.collect() + } + /// Return the `n`th item yielded by an iterator. #[inline] fn nth(&mut self, mut n: uint) -> Option<A> { diff --git a/src/libstd/managed.rs b/src/libstd/managed.rs index 2c9fcb2999f..bd4dc69537c 100644 --- a/src/libstd/managed.rs +++ b/src/libstd/managed.rs @@ -14,27 +14,8 @@ use ptr::to_unsafe_ptr; #[cfg(not(test))] use cmp::{Eq, Ord}; -pub mod raw { - use std::unstable::intrinsics::TyDesc; - - pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; - pub static RC_IMMORTAL : uint = 0x77777777; - - #[allow(missing_doc)] - pub struct BoxHeaderRepr { - ref_count: uint, - type_desc: *TyDesc, - prev: *BoxRepr, - next: *BoxRepr, - } - - #[allow(missing_doc)] - pub struct BoxRepr { - header: BoxHeaderRepr, - data: u8 - } - -} +pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; +pub static RC_IMMORTAL : uint = 0x77777777; /// Determine if two shared boxes point to the same object #[inline] diff --git a/src/libstd/option.rs b/src/libstd/option.rs index c4fee908266..eb3f227562a 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -118,13 +118,13 @@ impl<T> Option<T> { } } - /// Returns true if the option equals `none` + /// Returns true if the option equals `None` #[inline] pub fn is_none(&self) -> bool { match *self { None => true, Some(_) => false } } - /// Returns true if the option contains some value + /// Returns true if the option contains a `Some` value #[inline] pub fn is_some(&self) -> bool { !self.is_none() } @@ -158,6 +158,17 @@ impl<T> Option<T> { } } + /// Update an optional value by optionally running its content by mut reference + /// through a function that returns an option. + #[inline] + pub fn chain_mut_ref<'a, U>(&'a mut self, f: &fn(x: &'a mut T) -> Option<U>) + -> Option<U> { + match *self { + Some(ref mut x) => f(x), + None => None + } + } + /// Filters an optional value using given function. #[inline(always)] pub fn filtered(self, f: &fn(t: &T) -> bool) -> Option<T> { @@ -167,19 +178,19 @@ impl<T> Option<T> { } } - /// Maps a `some` value from one type to another by reference + /// Maps a `Some` value from one type to another by reference #[inline] pub fn map<'a, U>(&'a self, f: &fn(&'a T) -> U) -> Option<U> { match *self { Some(ref x) => Some(f(x)), None => None } } - /// Maps a `some` value from one type to another by a mutable reference + /// Maps a `Some` value from one type to another by a mutable reference #[inline] pub fn map_mut<'a, U>(&'a mut self, f: &fn(&'a mut T) -> U) -> Option<U> { match *self { Some(ref mut x) => Some(f(x)), None => None } } - /// Maps a `some` value from one type to another by a mutable reference, + /// Maps a `Some` value from one type to another by a mutable reference, /// or returns a default value. #[inline] pub fn map_mut_default<'a, U>(&'a mut self, def: U, f: &fn(&'a mut T) -> U) -> U { @@ -260,7 +271,7 @@ impl<T> Option<T> { pub fn get_ref<'a>(&'a self) -> &'a T { match *self { Some(ref x) => x, - None => fail!("option::get_ref none") + None => fail!("option::get_ref None") } } @@ -282,7 +293,7 @@ impl<T> Option<T> { pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut T { match *self { Some(ref mut x) => x, - None => fail!("option::get_mut_ref none") + None => fail!("option::get_mut_ref None") } } @@ -306,7 +317,7 @@ impl<T> Option<T> { */ match self { Some(x) => x, - None => fail!("option::unwrap none") + None => fail!("option::unwrap None") } } @@ -320,7 +331,7 @@ impl<T> Option<T> { */ #[inline] pub fn take_unwrap(&mut self) -> T { - if self.is_none() { fail!("option::take_unwrap none") } + if self.is_none() { fail!("option::take_unwrap None") } self.take().unwrap() } @@ -330,7 +341,7 @@ impl<T> Option<T> { * * # Failure * - * Fails if the value equals `none` + * Fails if the value equals `None` */ #[inline] pub fn expect(self, reason: &str) -> T { @@ -358,7 +369,7 @@ impl<T> Option<T> { pub fn get(self) -> T { match self { Some(x) => return x, - None => fail!("option::get none") + None => fail!("option::get None") } } @@ -368,7 +379,7 @@ impl<T> Option<T> { match self { Some(x) => x, None => def } } - /// Applies a function zero or more times until the result is none. + /// Applies a function zero or more times until the result is None. #[inline] pub fn while_some(self, blk: &fn(v: T) -> Option<T>) { let mut opt = self; diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index d49d54ae68f..1d093c4c14b 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -19,7 +19,7 @@ Runtime type reflection use unstable::intrinsics::{Opaque, TyDesc, TyVisitor}; use libc::c_void; use sys; -use vec; +use unstable::raw; /** * Trait for visitor that wishes to reflect on data. To use this, create a @@ -260,7 +260,7 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> { } fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<vec::UnboxedVecRepr>(); + self.align_to::<raw::Vec<()>>(); if ! self.inner.visit_vec(mtbl, inner) { return false; } true } diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index 07fd82e1616..eb4e1918add 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -22,21 +22,17 @@ use container::Container; use io::{Writer, WriterUtil}; use iterator::IteratorUtil; use libc::c_void; -use managed; use ptr; use reflect; use reflect::{MovePtr, align}; use str::StrSlice; use to_str::ToStr; -use vec::raw::{VecRepr, SliceRepr}; -use vec; -use vec::{OwnedVector, UnboxedVecRepr}; +use vec::OwnedVector; use unstable::intrinsics::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc}; +use unstable::raw; #[cfg(test)] use io; -pub use managed::raw::BoxRepr; - /// Helpers trait EscapedCharWriter { @@ -198,11 +194,11 @@ impl ReprVisitor { pub fn write_vec_range(&self, _mtbl: uint, - ptr: *u8, + ptr: *(), len: uint, inner: *TyDesc) -> bool { - let mut p = ptr; + let mut p = ptr as *u8; let (sz, al) = unsafe { ((*inner).size, (*inner).align) }; self.writer.write_char('['); let mut first = true; @@ -225,7 +221,7 @@ impl ReprVisitor { pub fn write_unboxed_vec_repr(&self, mtbl: uint, - v: &UnboxedVecRepr, + v: &raw::Vec<()>, inner: *TyDesc) -> bool { self.write_vec_range(mtbl, ptr::to_unsafe_ptr(&v.data), @@ -289,7 +285,7 @@ impl TyVisitor for ReprVisitor { fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { self.writer.write_char('@'); self.write_mut_qualifier(mtbl); - do self.get::<&managed::raw::BoxRepr> |b| { + do self.get::<&raw::Box<()>> |b| { let p = ptr::to_unsafe_ptr(&b.data) as *c_void; self.visit_ptr_inner(p, inner); } @@ -304,7 +300,7 @@ impl TyVisitor for ReprVisitor { fn visit_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool { self.writer.write_char('~'); - do self.get::<&managed::raw::BoxRepr> |b| { + do self.get::<&raw::Box<()>> |b| { let p = ptr::to_unsafe_ptr(&b.data) as *c_void; self.visit_ptr_inner(p, inner); } @@ -330,35 +326,35 @@ impl TyVisitor for ReprVisitor { fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<vec::UnboxedVecRepr> |b| { + do self.get::<raw::Vec<()>> |b| { self.write_unboxed_vec_repr(mtbl, b, inner); } } fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<&VecRepr> |b| { + do self.get::<&raw::Box<raw::Vec<()>>> |b| { self.writer.write_char('@'); self.write_mut_qualifier(mtbl); - self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner); + self.write_unboxed_vec_repr(mtbl, &b.data, inner); } } fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<&UnboxedVecRepr> |b| { + do self.get::<&raw::Vec<()>> |b| { self.writer.write_char('~'); self.write_unboxed_vec_repr(mtbl, *b, inner); } } fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<&VecRepr> |b| { + do self.get::<&raw::Box<raw::Vec<()>>> |b| { self.writer.write_char('~'); - self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner); + self.write_unboxed_vec_repr(mtbl, &b.data, inner); } } fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<SliceRepr> |s| { + do self.get::<raw::Slice<()>> |s| { self.writer.write_char('&'); self.write_vec_range(mtbl, s.data, s.len, inner); } @@ -366,7 +362,7 @@ impl TyVisitor for ReprVisitor { fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<u8> |b| { + do self.get::<()> |b| { self.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner); } } @@ -547,9 +543,9 @@ impl TyVisitor for ReprVisitor { fn visit_opaque_box(&self) -> bool { self.writer.write_char('@'); - do self.get::<&managed::raw::BoxRepr> |b| { + do self.get::<&raw::Box<()>> |b| { let p = ptr::to_unsafe_ptr(&b.data) as *c_void; - self.visit_ptr_inner(p, b.header.type_desc); + self.visit_ptr_inner(p, b.type_desc); } } diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs index 1a468fcf215..2d489e4dbc3 100644 --- a/src/libstd/rt/borrowck.rs +++ b/src/libstd/rt/borrowck.rs @@ -12,12 +12,12 @@ use cast::transmute; use libc::{c_char, c_void, size_t, STDERR_FILENO}; use io; use io::{Writer, WriterUtil}; -use managed::raw::BoxRepr; use option::{Option, None, Some}; use uint; use str; use str::{OwnedStr, StrSlice}; use sys; +use unstable::raw; use vec::ImmutableVector; #[allow(non_camel_case_types)] @@ -29,7 +29,7 @@ static ALL_BITS: uint = FROZEN_BIT | MUT_BIT; #[deriving(Eq)] struct BorrowRecord { - box: *mut BoxRepr, + box: *mut raw::Box<()>, file: *c_char, line: size_t } @@ -70,7 +70,7 @@ pub unsafe fn clear_task_borrow_list() { let _ = try_take_task_borrow_list(); } -unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { +unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) { debug_borrow("fail_borrowed: ", box, 0, 0, file, line); match try_take_task_borrow_list() { @@ -172,8 +172,8 @@ impl DebugPrints for io::fd_t { #[inline] pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { - let a: *mut BoxRepr = transmute(a); - let old_ref_count = (*a).header.ref_count; + let a = a as *mut raw::Box<()>; + let old_ref_count = (*a).ref_count; let new_ref_count = old_ref_count | FROZEN_BIT; debug_borrow("borrow_as_imm:", a, old_ref_count, new_ref_count, file, line); @@ -182,15 +182,15 @@ pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { fail_borrowed(a, file, line); } - (*a).header.ref_count = new_ref_count; + (*a).ref_count = new_ref_count; old_ref_count } #[inline] pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { - let a: *mut BoxRepr = transmute(a); - let old_ref_count = (*a).header.ref_count; + let a = a as *mut raw::Box<()>; + let old_ref_count = (*a).ref_count; let new_ref_count = old_ref_count | MUT_BIT | FROZEN_BIT; debug_borrow("borrow_as_mut:", a, old_ref_count, new_ref_count, file, line); @@ -199,7 +199,7 @@ pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { fail_borrowed(a, file, line); } - (*a).header.ref_count = new_ref_count; + (*a).ref_count = new_ref_count; old_ref_count } @@ -208,7 +208,7 @@ pub unsafe fn record_borrow(a: *u8, old_ref_count: uint, file: *c_char, line: size_t) { if (old_ref_count & ALL_BITS) == 0 { // was not borrowed before - let a: *mut BoxRepr = transmute(a); + let a = a as *mut raw::Box<()>; debug_borrow("record_borrow:", a, old_ref_count, 0, file, line); do swap_task_borrow_list |borrow_list| { let mut borrow_list = borrow_list; @@ -223,7 +223,7 @@ pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint, if (old_ref_count & ALL_BITS) == 0 { // was not borrowed before, so we should find the record at // the end of the list - let a: *mut BoxRepr = transmute(a); + let a = a as *mut raw::Box<()>; debug_borrow("unrecord_borrow:", a, old_ref_count, 0, file, line); do swap_task_borrow_list |borrow_list| { let mut borrow_list = borrow_list; @@ -246,15 +246,15 @@ pub unsafe fn return_to_mut(a: *u8, orig_ref_count: uint, // Sometimes the box is null, if it is conditionally frozen. // See e.g. #4904. if !a.is_null() { - let a: *mut BoxRepr = transmute(a); - let old_ref_count = (*a).header.ref_count; + let a = a as *mut raw::Box<()>; + let old_ref_count = (*a).ref_count; let new_ref_count = (old_ref_count & !ALL_BITS) | (orig_ref_count & ALL_BITS); debug_borrow("return_to_mut:", a, old_ref_count, new_ref_count, file, line); - (*a).header.ref_count = new_ref_count; + (*a).ref_count = new_ref_count; } } @@ -262,8 +262,8 @@ pub unsafe fn return_to_mut(a: *u8, orig_ref_count: uint, pub unsafe fn check_not_borrowed(a: *u8, file: *c_char, line: size_t) { - let a: *mut BoxRepr = transmute(a); - let ref_count = (*a).header.ref_count; + let a = a as *mut raw::Box<()>; + let ref_count = (*a).ref_count; debug_borrow("check_not_borrowed:", a, ref_count, 0, file, line); if (ref_count & FROZEN_BIT) != 0 { fail_borrowed(a, file, line); diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 54e9cb263db..7488b08da42 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -9,8 +9,8 @@ // except according to those terms. use libc::{c_void, c_char, size_t, uintptr_t, free, malloc, realloc}; -use managed::raw::{BoxHeaderRepr, BoxRepr}; use unstable::intrinsics::TyDesc; +use unstable::raw; use sys::size_of; extern { @@ -20,7 +20,7 @@ extern { #[inline] fn get_box_size(body_size: uint, body_align: uint) -> uint { - let header_size = size_of::<BoxHeaderRepr>(); + let header_size = size_of::<raw::Box<()>>(); // FIXME (#2699): This alignment calculation is suspicious. Is it right? let total_size = align_to(header_size, body_align) + body_size; total_size @@ -82,8 +82,8 @@ pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { 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; + let box = p as *mut raw::Box<()>; + (*box).type_desc = td; box as *c_char } diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index 85917ae3edf..cd8e8549211 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -13,11 +13,11 @@ use libc; use libc::{c_void, uintptr_t, size_t}; use ops::Drop; -use repr::BoxRepr; use rt; use rt::OldTaskContext; use rt::local::Local; use rt::task::Task; +use unstable::raw; type MemoryRegion = c_void; @@ -26,7 +26,7 @@ struct Env { priv opaque: () } struct BoxedRegion { env: *Env, backing_region: *MemoryRegion, - live_allocs: *BoxRepr + live_allocs: *raw::Box<()>, } pub type OpaqueBox = c_void; @@ -103,7 +103,7 @@ pub unsafe fn local_free(ptr: *libc::c_char) { } } -pub fn live_allocs() -> *BoxRepr { +pub fn live_allocs() -> *raw::Box<()> { let region = match rt::context() { OldTaskContext => { unsafe { rust_current_boxed_region() } diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index d8d61806a5b..33cfd69fcd2 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -10,9 +10,9 @@ use either::{Left, Right}; use option::{Option, Some, None}; -use sys; use cast::transmute; use clone::Clone; +use unstable::raw; use super::sleeper_list::SleeperList; use super::work_queue::WorkQueue; @@ -698,7 +698,7 @@ impl SchedHandle { // XXX: Some hacks to put a &fn in Scheduler without borrowck // complaining -type UnsafeTaskReceiver = sys::Closure; +type UnsafeTaskReceiver = raw::Closure; trait ClosureConverter { fn from_fn(&fn(&mut Scheduler, BlockedTask)) -> Self; fn to_fn(self) -> &fn(&mut Scheduler, BlockedTask); diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index d2975148350..8cf864b9222 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -281,7 +281,7 @@ static UNWIND_TOKEN: uintptr_t = 839147; impl Unwinder { pub fn try(&mut self, f: &fn()) { - use sys::Closure; + use unstable::raw::Closure; unsafe { let closure: Closure = transmute(f); diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 636bbc48f8e..c600e7f6c09 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -31,6 +31,7 @@ use ptr; use ptr::RawPtr; use to_str::ToStr; use uint; +use unstable::raw::Repr; use vec; use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector}; @@ -114,9 +115,9 @@ pub fn from_bytes_with_null<'a>(vv: &'a [u8]) -> &'a str { pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { unsafe { assert!(is_utf8(vector)); - let (ptr, len): (*u8, uint) = ::cast::transmute(vector); - let string: &'a str = ::cast::transmute((ptr, len + 1)); - string + let mut s = vector.repr(); + s.len += 1; + cast::transmute(s) } } @@ -142,7 +143,7 @@ impl ToStr for @str { */ pub fn from_byte(b: u8) -> ~str { assert!(b < 128u8); - unsafe { ::cast::transmute(~[b, 0u8]) } + unsafe { cast::transmute(~[b, 0u8]) } } /// Convert a char to a string @@ -217,7 +218,7 @@ impl<'self, S: Str> StrVector for &'self [S] { do s.as_mut_buf |buf, _| { do sep.as_imm_buf |sepbuf, seplen| { let seplen = seplen - 1; - let mut buf = ::cast::transmute_mut_unsafe(buf); + let mut buf = cast::transmute_mut_unsafe(buf); for self.iter().advance |ss| { do ss.as_slice().as_imm_buf |ssbuf, sslen| { let sslen = sslen - 1; @@ -771,10 +772,10 @@ pub mod raw { use cast; use libc; use ptr; - use str::raw; - use str::{is_utf8}; + use str::is_utf8; use vec; use vec::MutableVector; + use unstable::raw::{Slice, String}; /// Create a Rust string from a null-terminated *u8 buffer pub unsafe fn from_buf(buf: *u8) -> ~str { @@ -797,17 +798,17 @@ pub mod raw { v.push(0u8); assert!(is_utf8(v)); - return ::cast::transmute(v); + return cast::transmute(v); } /// Create a Rust string from a null-terminated C string pub unsafe fn from_c_str(c_str: *libc::c_char) -> ~str { - from_buf(::cast::transmute(c_str)) + from_buf(c_str as *u8) } /// Create a Rust string from a `*c_char` buffer of the given length pub unsafe fn from_c_str_len(c_str: *libc::c_char, len: uint) -> ~str { - from_buf_len(::cast::transmute(c_str), len) + from_buf_len(c_str as *u8, len) } /// Converts a vector of bytes to a new owned string. @@ -832,7 +833,7 @@ pub mod raw { } /// Converts a byte to a string. - pub unsafe fn from_byte(u: u8) -> ~str { raw::from_bytes([u]) } + pub unsafe fn from_byte(u: u8) -> ~str { from_bytes([u]) } /// Form a slice from a C string. Unsafe because the caller must ensure the /// C string has the static lifetime, or else the return value may be @@ -845,9 +846,9 @@ pub mod raw { len += 1u; curr = ptr::offset(s, len); } - let v = (s, len + 1); - assert!(is_utf8(::cast::transmute(v))); - ::cast::transmute(v) + let v = Slice { data: s, len: len + 1 }; + assert!(is_utf8(cast::transmute(v))); + cast::transmute(v) } /** @@ -866,8 +867,10 @@ pub mod raw { assert!((begin <= end)); assert!((end <= n)); - let tuple = (ptr::offset(sbuf, begin), end - begin + 1); - ::cast::transmute(tuple) + cast::transmute(Slice { + data: ptr::offset(sbuf, begin), + len: end - begin + 1, + }) } } @@ -909,11 +912,10 @@ pub mod raw { /// Sets the length of the string and adds the null terminator #[inline] pub unsafe fn set_len(v: &mut ~str, new_len: uint) { - let v: **mut vec::UnboxedVecRepr = cast::transmute(v); - let repr: *mut vec::UnboxedVecRepr = *v; + let v: **mut String = cast::transmute(v); + let repr = *v; (*repr).fill = new_len + 1u; - let null = ptr::mut_offset(cast::transmute(&((*repr).data)), - new_len); + let null = ptr::mut_offset(&mut ((*repr).data), new_len); *null = 0u8; } @@ -1595,7 +1597,7 @@ impl<'self> StrSlice<'self> for &'self str { let v = at_vec::from_fn(self.len() + 1, |i| { if i == self.len() { 0 } else { self[i] } }); - unsafe { ::cast::transmute(v) } + unsafe { cast::transmute(v) } } /// Converts to a vector of `u16` encoded as UTF-16. @@ -1750,9 +1752,9 @@ impl<'self> StrSlice<'self> for &'self str { */ fn as_bytes(&self) -> &'self [u8] { unsafe { - let (ptr, len): (*u8, uint) = ::cast::transmute(*self); - let outgoing_tuple: (*u8, uint) = (ptr, len - 1); - ::cast::transmute(outgoing_tuple) + let mut slice = self.repr(); + slice.len -= 1; + cast::transmute(slice) } } @@ -2001,7 +2003,7 @@ impl NullTerminatedStr for ~str { */ #[inline] fn as_bytes_with_null<'a>(&'a self) -> &'a [u8] { - let ptr: &'a ~[u8] = unsafe { ::cast::transmute(self) }; + let ptr: &'a ~[u8] = unsafe { cast::transmute(self) }; let slice: &'a [u8] = *ptr; slice } @@ -2014,7 +2016,7 @@ impl NullTerminatedStr for @str { */ #[inline] fn as_bytes_with_null<'a>(&'a self) -> &'a [u8] { - let ptr: &'a @[u8] = unsafe { ::cast::transmute(self) }; + let ptr: &'a @[u8] = unsafe { cast::transmute(self) }; let slice: &'a [u8] = *ptr; slice } @@ -2058,7 +2060,7 @@ impl OwnedStr for ~str { do self.as_imm_buf |lbuf, _llen| { do rhs.as_imm_buf |rbuf, _rlen| { let dst = ptr::offset(lbuf, llen); - let dst = ::cast::transmute_mut_unsafe(dst); + let dst = cast::transmute_mut_unsafe(dst); ptr::copy_memory(dst, rbuf, rlen); } } @@ -2076,7 +2078,7 @@ impl OwnedStr for ~str { do self.as_imm_buf |lbuf, _llen| { do rhs.as_imm_buf |rbuf, _rlen| { let dst = ptr::offset(lbuf, llen); - let dst = ::cast::transmute_mut_unsafe(dst); + let dst = cast::transmute_mut_unsafe(dst); ptr::copy_memory(dst, rbuf, rlen); } } @@ -2232,7 +2234,7 @@ impl OwnedStr for ~str { /// string, and includes the null terminator. #[inline] fn to_bytes_with_null(self) -> ~[u8] { - unsafe { ::cast::transmute(self) } + unsafe { cast::transmute(self) } } #[inline] diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs index 28cd2345aab..5cf77d901db 100644 --- a/src/libstd/sys.rs +++ b/src/libstd/sys.rs @@ -22,12 +22,6 @@ use str::StrSlice; use str; use unstable::intrinsics; -/// The representation of a Rust closure -pub struct Closure { - code: *(), - env: *(), -} - pub mod rustrt { use libc::{c_char, size_t}; @@ -278,6 +272,7 @@ mod tests { #[test] fn synthesize_closure() { + use unstable::raw::Closure; unsafe { let x = 10; let f: &fn(int) -> int = |y| x + y; diff --git a/src/libstd/task/local_data_priv.rs b/src/libstd/task/local_data_priv.rs index d5f4973e8c7..477981c65e5 100644 --- a/src/libstd/task/local_data_priv.rs +++ b/src/libstd/task/local_data_priv.rs @@ -15,8 +15,8 @@ use libc; use local_data; use prelude::*; use ptr; -use sys; use task::rt; +use unstable::raw; use util; use super::rt::rust_task; @@ -158,7 +158,7 @@ unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap { } unsafe fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void { - let pair: sys::Closure = cast::transmute_copy(&key); + let pair: raw::Closure = cast::transmute_copy(&key); return pair.code as *libc::c_void; } diff --git a/src/libstd/unstable/atomics.rs b/src/libstd/unstable/atomics.rs index b595d3e1a80..712c32d2436 100644 --- a/src/libstd/unstable/atomics.rs +++ b/src/libstd/unstable/atomics.rs @@ -96,7 +96,7 @@ impl AtomicFlag { */ #[inline] pub fn test_and_set(&mut self, order: Ordering) -> bool { - unsafe {atomic_compare_and_swap(&mut self.v, 0, 1, order) > 0} + unsafe { atomic_compare_and_swap(&mut self.v, 0, 1, order) > 0 } } } @@ -121,7 +121,7 @@ impl AtomicBool { pub fn swap(&mut self, val: bool, order: Ordering) -> bool { let val = if val { 1 } else { 0 }; - unsafe { atomic_swap(&mut self.v, val, order) > 0} + unsafe { atomic_swap(&mut self.v, val, order) > 0 } } #[inline] @@ -131,6 +131,38 @@ impl AtomicBool { unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) > 0 } } + + /// Returns the old value + #[inline] + pub fn fetch_and(&mut self, val: bool, order: Ordering) -> bool { + let val = if val { 1 } else { 0 }; + + unsafe { atomic_and(&mut self.v, val, order) > 0 } + } + + /// Returns the old value + #[inline] + pub fn fetch_nand(&mut self, val: bool, order: Ordering) -> bool { + let val = if val { 1 } else { 0 }; + + unsafe { atomic_nand(&mut self.v, val, order) > 0 } + } + + /// Returns the old value + #[inline] + pub fn fetch_or(&mut self, val: bool, order: Ordering) -> bool { + let val = if val { 1 } else { 0 }; + + unsafe { atomic_or(&mut self.v, val, order) > 0 } + } + + /// Returns the old value + #[inline] + pub fn fetch_xor(&mut self, val: bool, order: Ordering) -> bool { + let val = if val { 1 } else { 0 }; + + unsafe { atomic_xor(&mut self.v, val, order) > 0 } + } } impl AtomicInt { @@ -169,6 +201,18 @@ impl AtomicInt { pub fn fetch_sub(&mut self, val: int, order: Ordering) -> int { unsafe { atomic_sub(&mut self.v, val, order) } } + + /// Returns the old value + #[inline] + pub fn fetch_min(&mut self, val: int, order: Ordering) -> int { + unsafe { atomic_min(&mut self.v, val, order) } + } + + /// Returns the old value + #[inline] + pub fn fetch_max(&mut self, val: int, order: Ordering) -> int { + unsafe { atomic_max(&mut self.v, val, order) } + } } impl AtomicUint { @@ -207,6 +251,18 @@ impl AtomicUint { pub fn fetch_sub(&mut self, val: uint, order: Ordering) -> uint { unsafe { atomic_sub(&mut self.v, val, order) } } + + /// Returns the old value + #[inline] + pub fn fetch_min(&mut self, val: uint, order: Ordering) -> uint { + unsafe { atomic_umin(&mut self.v, val, order) } + } + + /// Returns the old value + #[inline] + pub fn fetch_max(&mut self, val: uint, order: Ordering) -> uint { + unsafe { atomic_umax(&mut self.v, val, order) } + } } impl<T> AtomicPtr<T> { @@ -395,6 +451,125 @@ pub unsafe fn atomic_compare_and_swap<T>(dst:&mut T, old:T, new:T, order: Orderi }) } +#[inline] +pub unsafe fn atomic_and<T>(dst: &mut T, val: T, order: Ordering) -> T { + let dst = cast::transmute(dst); + let val = cast::transmute(val); + + cast::transmute(match order { + Acquire => intrinsics::atomic_and_acq(dst, val), + Release => intrinsics::atomic_and_rel(dst, val), + AcqRel => intrinsics::atomic_and_acqrel(dst, val), + Relaxed => intrinsics::atomic_and_relaxed(dst, val), + _ => intrinsics::atomic_and(dst, val) + }) +} + + +#[inline] +pub unsafe fn atomic_nand<T>(dst: &mut T, val: T, order: Ordering) -> T { + let dst = cast::transmute(dst); + let val = cast::transmute(val); + + cast::transmute(match order { + Acquire => intrinsics::atomic_nand_acq(dst, val), + Release => intrinsics::atomic_nand_rel(dst, val), + AcqRel => intrinsics::atomic_nand_acqrel(dst, val), + Relaxed => intrinsics::atomic_nand_relaxed(dst, val), + _ => intrinsics::atomic_nand(dst, val) + }) +} + + +#[inline] +pub unsafe fn atomic_or<T>(dst: &mut T, val: T, order: Ordering) -> T { + let dst = cast::transmute(dst); + let val = cast::transmute(val); + + cast::transmute(match order { + Acquire => intrinsics::atomic_or_acq(dst, val), + Release => intrinsics::atomic_or_rel(dst, val), + AcqRel => intrinsics::atomic_or_acqrel(dst, val), + Relaxed => intrinsics::atomic_or_relaxed(dst, val), + _ => intrinsics::atomic_or(dst, val) + }) +} + + +#[inline] +pub unsafe fn atomic_xor<T>(dst: &mut T, val: T, order: Ordering) -> T { + let dst = cast::transmute(dst); + let val = cast::transmute(val); + + cast::transmute(match order { + Acquire => intrinsics::atomic_xor_acq(dst, val), + Release => intrinsics::atomic_xor_rel(dst, val), + AcqRel => intrinsics::atomic_xor_acqrel(dst, val), + Relaxed => intrinsics::atomic_xor_relaxed(dst, val), + _ => intrinsics::atomic_xor(dst, val) + }) +} + + +#[inline] +pub unsafe fn atomic_max<T>(dst: &mut T, val: T, order: Ordering) -> T { + let dst = cast::transmute(dst); + let val = cast::transmute(val); + + cast::transmute(match order { + Acquire => intrinsics::atomic_max_acq(dst, val), + Release => intrinsics::atomic_max_rel(dst, val), + AcqRel => intrinsics::atomic_max_acqrel(dst, val), + Relaxed => intrinsics::atomic_max_relaxed(dst, val), + _ => intrinsics::atomic_max(dst, val) + }) +} + + +#[inline] +pub unsafe fn atomic_min<T>(dst: &mut T, val: T, order: Ordering) -> T { + let dst = cast::transmute(dst); + let val = cast::transmute(val); + + cast::transmute(match order { + Acquire => intrinsics::atomic_min_acq(dst, val), + Release => intrinsics::atomic_min_rel(dst, val), + AcqRel => intrinsics::atomic_min_acqrel(dst, val), + Relaxed => intrinsics::atomic_min_relaxed(dst, val), + _ => intrinsics::atomic_min(dst, val) + }) +} + +#[inline] +pub unsafe fn atomic_umax<T>(dst: &mut T, val: T, order: Ordering) -> T { + let dst = cast::transmute(dst); + let val = cast::transmute(val); + + cast::transmute(match order { + Acquire => intrinsics::atomic_umax_acq(dst, val), + Release => intrinsics::atomic_umax_rel(dst, val), + AcqRel => intrinsics::atomic_umax_acqrel(dst, val), + Relaxed => intrinsics::atomic_umax_relaxed(dst, val), + _ => intrinsics::atomic_umax(dst, val) + }) +} + + +#[inline] +pub unsafe fn atomic_umin<T>(dst: &mut T, val: T, order: Ordering) -> T { + let dst = cast::transmute(dst); + let val = cast::transmute(val); + + cast::transmute(match order { + Acquire => intrinsics::atomic_umin_acq(dst, val), + Release => intrinsics::atomic_umin_rel(dst, val), + AcqRel => intrinsics::atomic_umin_acqrel(dst, val), + Relaxed => intrinsics::atomic_umin_relaxed(dst, val), + _ => intrinsics::atomic_umin(dst, val) + }) +} + + #[cfg(test)] mod test { use option::*; @@ -448,4 +623,11 @@ mod test { assert!(p.fill(~2, SeqCst).is_none()); // shouldn't fail assert_eq!(p.take(SeqCst), Some(~2)); } + + #[test] + fn bool_and() { + let mut a = AtomicBool::new(true); + assert_eq!(a.fetch_and(false, SeqCst),true); + assert_eq!(a.load(SeqCst),false); + } } diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index d6fd2cbcd1e..0d8cb1e8f74 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -26,6 +26,7 @@ pub mod extfmt; pub mod lang; pub mod sync; pub mod atomics; +pub mod raw; /** diff --git a/src/libstd/unstable/raw.rs b/src/libstd/unstable/raw.rs new file mode 100644 index 00000000000..0e074b53d6b --- /dev/null +++ b/src/libstd/unstable/raw.rs @@ -0,0 +1,61 @@ +// 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 cast; +use unstable::intrinsics::TyDesc; + +/// The representation of a Rust managed box +pub struct Box<T> { + ref_count: uint, + type_desc: *TyDesc, + prev: *Box<T>, + next: *Box<T>, + data: T +} + +/// The representation of a Rust vector +pub struct Vec<T> { + fill: uint, + alloc: uint, + data: T +} + +/// The representation of a Rust string +pub type String = Vec<u8>; + +/// The representation of a Rust slice +pub struct Slice<T> { + data: *T, + len: uint +} + +/// The representation of a Rust closure +pub struct Closure { + code: *(), + env: *(), +} + +/// This trait is meant to map equivalences between raw structs and their +/// corresponding rust values. +pub trait Repr<T> { + /// This function "unwraps" a rust value (without consuming it) into its raw + /// struct representation. This can be used to read/write different values + /// for the struct. This is a safe method because by default it does not + /// give write-access to the struct returned. + fn repr(&self) -> T { unsafe { cast::transmute_copy(self) } } +} + +impl<'self, T> Repr<Slice<T>> for &'self [T] {} +impl<'self> Repr<Slice<u8>> for &'self str {} +impl<T> Repr<*Box<T>> for @T {} +impl<T> Repr<*Box<Vec<T>>> for @[T] {} + +// sure would be nice to have this +// impl<T> Repr<*Vec<T>> for ~[T] {} diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 5f8a2796248..87ac4037e8e 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -12,7 +12,6 @@ #[warn(non_camel_case_types)]; -use cast::transmute; use cast; use clone::Clone; use container::{Container, Mutable}; @@ -32,6 +31,7 @@ use sys::size_of; use uint; use unstable::intrinsics; use unstable::intrinsics::{get_tydesc, contains_managed}; +use unstable::raw::{Box, Repr, Slice, Vec}; use vec; use util; @@ -96,7 +96,7 @@ pub fn with_capacity<T>(capacity: uint) -> ~[T] { vec } else { let alloc = capacity * sys::nonzero_size_of::<T>(); - let ptr = malloc_raw(alloc + sys::size_of::<UnboxedVecRepr>()) as *mut UnboxedVecRepr; + let ptr = malloc_raw(alloc + sys::size_of::<Vec<()>>()) as *mut Vec<()>; (*ptr).alloc = alloc; (*ptr).fill = 0; cast::transmute(ptr) @@ -736,8 +736,10 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { assert!(end <= self.len()); do self.as_imm_buf |p, _len| { unsafe { - transmute((ptr::offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) + cast::transmute(Slice { + data: ptr::offset(p, start), + len: (end - start) * sys::nonzero_size_of::<T>(), + }) } } } @@ -767,8 +769,8 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { unsafe { let p = vec::raw::to_ptr(self); VecIterator{ptr: p, - end: cast::transmute(p as uint + self.len() * - sys::nonzero_size_of::<T>()), + end: (p as uint + self.len() * + sys::nonzero_size_of::<T>()) as *T, lifetime: cast::transmute(p)} } } @@ -947,8 +949,7 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { /// bounds checking. #[inline] unsafe fn unsafe_ref(&self, index: uint) -> *T { - let (ptr, _): (*T, uint) = transmute(*self); - ptr.offset(index) + self.repr().data.offset(index) } /** @@ -1002,11 +1003,8 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { // into `s` and pass them to `f()`, but in fact they are potentially // pointing at *mutable memory*. Use `as_mut_buf` instead! - unsafe { - let v : *(*T,uint) = transmute(self); - let (buf,len) = *v; - f(buf, len / sys::nonzero_size_of::<T>()) - } + let s = self.repr(); + f(s.data, s.len / sys::nonzero_size_of::<T>()) } } @@ -1158,17 +1156,17 @@ impl<T> OwnedVector<T> for ~[T] { unsafe { let td = get_tydesc::<T>(); if contains_managed::<T>() { - let ptr: *mut *mut raw::VecRepr = cast::transmute(self); + let ptr: *mut *mut Box<Vec<()>> = cast::transmute(self); ::at_vec::raw::reserve_raw(td, ptr, n); } else { - let ptr: *mut *mut UnboxedVecRepr = cast::transmute(self); + let ptr: *mut *mut Vec<()> = cast::transmute(self); let alloc = n * sys::nonzero_size_of::<T>(); - let size = alloc + sys::size_of::<UnboxedVecRepr>(); + let size = alloc + sys::size_of::<Vec<()>>(); if alloc / sys::nonzero_size_of::<T>() != n || size < alloc { fail!("vector size is too large: %u", n); } *ptr = realloc_raw(*ptr as *mut c_void, size) - as *mut UnboxedVecRepr; + as *mut Vec<()>; (**ptr).alloc = alloc; } } @@ -1198,10 +1196,10 @@ impl<T> OwnedVector<T> for ~[T] { fn capacity(&self) -> uint { unsafe { if contains_managed::<T>() { - let repr: **raw::VecRepr = transmute(self); - (**repr).unboxed.alloc / sys::nonzero_size_of::<T>() + let repr: **Box<Vec<()>> = cast::transmute(self); + (**repr).data.alloc / sys::nonzero_size_of::<T>() } else { - let repr: **UnboxedVecRepr = transmute(self); + let repr: **Vec<()> = cast::transmute(self); (**repr).alloc / sys::nonzero_size_of::<T>() } } @@ -1212,16 +1210,16 @@ impl<T> OwnedVector<T> for ~[T] { fn push(&mut self, t: T) { unsafe { if contains_managed::<T>() { - let repr: **raw::VecRepr = transmute(&mut *self); - let fill = (**repr).unboxed.fill; - if (**repr).unboxed.alloc <= fill { + let repr: **Box<Vec<()>> = cast::transmute(&mut *self); + let fill = (**repr).data.fill; + if (**repr).data.alloc <= fill { let new_len = self.len() + 1; self.reserve_at_least(new_len); } self.push_fast(t); } else { - let repr: **UnboxedVecRepr = transmute(&mut *self); + let repr: **Vec<()> = cast::transmute(&mut *self); let fill = (**repr).fill; if (**repr).alloc <= fill { let new_len = self.len() + 1; @@ -1237,14 +1235,14 @@ impl<T> OwnedVector<T> for ~[T] { #[inline] // really pretty please unsafe fn push_fast(&mut self, t: T) { if contains_managed::<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 repr: **mut Box<Vec<u8>> = cast::transmute(self); + let fill = (**repr).data.fill; + (**repr).data.fill += sys::nonzero_size_of::<T>(); + let p = to_unsafe_ptr(&((**repr).data.data)); let p = ptr::offset(p, fill) as *mut T; intrinsics::move_val_init(&mut(*p), t); } else { - let repr: **mut UnboxedVecRepr = transmute(self); + let repr: **mut Vec<u8> = cast::transmute(self); let fill = (**repr).fill; (**repr).fill += sys::nonzero_size_of::<T>(); let p = to_unsafe_ptr(&((**repr).data)); @@ -1338,14 +1336,14 @@ impl<T> OwnedVector<T> for ~[T] { { let first_slice = self.slice(0, 1); let last_slice = self.slice(next_ln, ln); - raw::copy_memory(transmute(last_slice), first_slice, 1); + raw::copy_memory(cast::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), + raw::copy_memory(cast::transmute(init_slice), tail_slice, next_ln); } @@ -1689,8 +1687,8 @@ pub trait MutableVector<'self, T> { */ 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); + unsafe fn unsafe_mut_ref(self, index: uint) -> *mut T; + unsafe fn unsafe_set(self, index: uint, val: T); fn as_mut_buf<U>(self, f: &fn(*mut T, uint) -> U) -> U; } @@ -1703,8 +1701,10 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { assert!(end <= self.len()); do self.as_mut_buf |p, _len| { unsafe { - transmute((ptr::mut_offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) + cast::transmute(Slice { + data: ptr::mut_offset(p, start) as *T, + len: (end - start) * sys::nonzero_size_of::<T>() + }) } } } @@ -1723,8 +1723,8 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { unsafe { let p = vec::raw::to_mut_ptr(self); VecMutIterator{ptr: p, - end: cast::transmute(p as uint + self.len() * - sys::nonzero_size_of::<T>()), + end: (p as uint + self.len() * + sys::nonzero_size_of::<T>()) as *mut T, lifetime: cast::transmute(p)} } } @@ -1771,22 +1771,20 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { } #[inline] - unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T { - let pair_ptr: &(*mut T, uint) = transmute(self); - let (ptr, _) = *pair_ptr; - ptr.offset(index) + unsafe fn unsafe_mut_ref(self, index: uint) -> *mut T { + ptr::mut_offset(self.repr().data as *mut T, index) } #[inline] - unsafe fn unsafe_set(&self, index: uint, val: T) { + unsafe fn unsafe_set(self, index: uint, val: T) { *self.unsafe_mut_ref(index) = val; } /// Similar to `as_imm_buf` but passing a `*mut T` #[inline] fn as_mut_buf<U>(self, f: &fn(*mut T, uint) -> U) -> U { - let (buf, len): (*mut T, uint) = unsafe { transmute(self) }; - f(buf, len / sys::nonzero_size_of::<T>()) + let Slice{ data, len } = self.repr(); + f(data as *mut T, len / sys::nonzero_size_of::<T>()) } } @@ -1821,40 +1819,17 @@ pub unsafe fn from_buf<T>(ptr: *T, elts: uint) -> ~[T] { raw::from_buf_raw(ptr, elts) } -/// The internal 'unboxed' representation of a vector -#[allow(missing_doc)] -pub struct UnboxedVecRepr { - fill: uint, - alloc: uint, - data: u8 -} - /// Unsafe operations pub mod raw { - use cast::transmute; + use cast; use clone::Clone; - use managed; use option::Some; use ptr; use sys; use unstable::intrinsics; - use vec::{UnboxedVecRepr, with_capacity, ImmutableVector, MutableVector}; + use vec::{with_capacity, ImmutableVector, MutableVector}; use unstable::intrinsics::contains_managed; - - /// The internal representation of a (boxed) vector - #[allow(missing_doc)] - pub struct VecRepr { - box_header: managed::raw::BoxHeaderRepr, - unboxed: UnboxedVecRepr - } - - /// The internal representation of a slice - pub struct SliceRepr { - /// Pointer to the base of this slice - data: *u8, - /// The length of the slice - len: uint - } + use unstable::raw::{Box, Vec, Slice}; /** * Sets the length of a vector @@ -1866,10 +1841,10 @@ pub mod raw { #[inline] pub unsafe fn set_len<T>(v: &mut ~[T], new_len: uint) { if contains_managed::<T>() { - let repr: **mut VecRepr = transmute(v); - (**repr).unboxed.fill = new_len * sys::nonzero_size_of::<T>(); + let repr: **mut Box<Vec<()>> = cast::transmute(v); + (**repr).data.fill = new_len * sys::nonzero_size_of::<T>(); } else { - let repr: **mut UnboxedVecRepr = transmute(v); + let repr: **mut Vec<()> = cast::transmute(v); (**repr).fill = new_len * sys::nonzero_size_of::<T>(); } } @@ -1885,19 +1860,13 @@ pub mod raw { */ #[inline] pub fn to_ptr<T>(v: &[T]) -> *T { - unsafe { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) - } + v.repr().data } /** see `to_ptr()` */ #[inline] pub fn to_mut_ptr<T>(v: &mut [T]) -> *mut T { - unsafe { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) - } + v.repr().data as *mut T } /** @@ -1908,9 +1877,10 @@ pub mod raw { pub unsafe fn buf_as_slice<T,U>(p: *T, len: uint, f: &fn(v: &[T]) -> U) -> U { - let pair = (p, len * sys::nonzero_size_of::<T>()); - let v : *(&'blk [T]) = transmute(&pair); - f(*v) + f(cast::transmute(Slice { + data: p, + len: len * sys::nonzero_size_of::<T>() + })) } /** @@ -1921,9 +1891,10 @@ pub mod raw { pub unsafe fn mut_buf_as_slice<T,U>(p: *mut T, len: uint, f: &fn(v: &mut [T]) -> U) -> U { - let pair = (p, len * sys::nonzero_size_of::<T>()); - let v : *(&'blk mut [T]) = transmute(&pair); - f(*v) + f(cast::transmute(Slice { + data: p as *T, + len: len * sys::nonzero_size_of::<T>() + })) } /** diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 6ec80140c76..10603751a06 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -9,7 +9,6 @@ // except according to those terms. /*! - * * Defines a type OptVec<T> that can be used in place of ~[T]. * OptVec avoids the need for allocation for empty vectors. * OptVec implements the iterable interface as well as diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index bd57f123cc5..5cdf0ec1acc 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -384,12 +384,10 @@ mod test { span:sp(0,6)}) } - // FIXME (#6416): For some reason, this fails and causes a test failure, even though it's - // marked as `#[should_fail]`. - /*#[should_fail] + #[should_fail] #[test] fn bad_path_expr_1() { string_to_expr(@"::abc::def::return"); - }*/ + } #[test] fn string_to_tts_1 () { let (tts,_ps) = string_to_tts_and_sess(@"fn a (b : int) { b; }"); diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index de97396e453..9d286f1759e 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -33,29 +33,46 @@ pub fn string_to_parser(source_str: @str) -> Parser { p } +fn with_error_checking_parse<T>(s: @str, f: &fn(&mut Parser) -> T) -> T { + let mut p = string_to_parser(s); + let x = f(&mut p); + p.abort_if_errors(); + x +} + pub fn string_to_crate (source_str : @str) -> @ast::Crate { - string_to_parser(source_str).parse_crate_mod() + do with_error_checking_parse(source_str) |p| { + p.parse_crate_mod() + } } // parse a string, return an expr pub fn string_to_expr (source_str : @str) -> @ast::expr { - string_to_parser(source_str).parse_expr() + do with_error_checking_parse(source_str) |p| { + p.parse_expr() + } } // parse a string, return an item pub fn string_to_item (source_str : @str) -> Option<@ast::item> { - string_to_parser(source_str).parse_item(~[]) + do with_error_checking_parse(source_str) |p| { + p.parse_item(~[]) + } } // parse a string, return an item and the ParseSess pub fn string_to_item_and_sess (source_str : @str) -> (Option<@ast::item>,@mut ParseSess) { let (p,ps) = string_to_parser_and_sess(source_str); - (p.parse_item(~[]),ps) + let io = p.parse_item(~[]); + p.abort_if_errors(); + (io,ps) } // parse a string, return a stmt pub fn string_to_stmt(source_str : @str) -> @ast::stmt { - string_to_parser(source_str).parse_stmt(~[]) + do with_error_checking_parse(source_str) |p| { + p.parse_stmt(~[]) + } } // parse a string, return a pat. Uses "irrefutable"... which doesn't diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index a4afb1c0bc5..72979d67eef 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -152,8 +152,6 @@ cleanup_task(cleanup_args *args) { #endif } -extern "C" CDECL void upcall_exchange_free(void *ptr); - // This runs on the Rust stack void task_start_wrapper(spawn_args *a) { diff --git a/src/snapshots.txt b/src/snapshots.txt index a3297ef7f1d..495d58f06f3 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2013-07-25 4cf3072 + macos-i386 f682d6e9ca0d56768bd36a0c05b7e58e12694dff + macos-x86_64 2f4e85c9756ba31a04fa8dd1c999fbaf8e1d3d1a + winnt-i386 6360e61fb5c432ad1511cb28af8e44cc0106f1aa + freebsd-x86_64 5e76c40a64b76e0a065d5b8d51c85dfe38ea833a + linux-i386 46961cef9d4efccf5df23a8389d63cf35d35c1d6 + linux-x86_64 b416ca2644b14403818f0219673f6f8fe189e8b4 + S 2013-07-21 e336cbf macos-i386 d9666dccc1040ebe298a54acb378902a7472ad0f macos-x86_64 808f68916444e3857ef2aab20f8db9db8f4b0b4a diff --git a/src/test/auxiliary/issue_3979_traits.rs b/src/test/auxiliary/issue_3979_traits.rs index 1e56dab1559..eb10553f19c 100644 --- a/src/test/auxiliary/issue_3979_traits.rs +++ b/src/test/auxiliary/issue_3979_traits.rs @@ -14,12 +14,13 @@ #[crate_type = "lib"]; trait Positioned { - fn SetX(&self, int); + fn SetX(&mut self, int); fn X(&self) -> int; } trait Movable: Positioned { - fn translate(&self, dx: int) { - self.SetX(self.X() + dx); + fn translate(&mut self, dx: int) { + let x = self.X() + dx; + self.SetX(x); } } diff --git a/src/test/auxiliary/no_std_crate.rs b/src/test/auxiliary/no_std_crate.rs new file mode 100644 index 00000000000..70f1b76e246 --- /dev/null +++ b/src/test/auxiliary/no_std_crate.rs @@ -0,0 +1,3 @@ +#[no_std]; + +pub fn foo() {} diff --git a/src/test/compile-fail/issue-6804.rs b/src/test/compile-fail/issue-6804.rs new file mode 100644 index 00000000000..0a62e889d09 --- /dev/null +++ b/src/test/compile-fail/issue-6804.rs @@ -0,0 +1,21 @@ +// Matching against NaN should result in a warning + +use std::float::NaN; + +fn main() { + let x = NaN; + match x { + NaN => {}, + _ => {}, + }; + //~^^^ WARNING unmatchable NaN in pattern, use the is_NaN method in a guard instead + match [x, 1.0] { + [NaN, _] => {}, + _ => {}, + }; + //~^^^ WARNING unmatchable NaN in pattern, use the is_NaN method in a guard instead +} + +// At least one error is needed so that compilation fails +#[static_assert] +static b: bool = false; //~ ERROR static assertion failed diff --git a/src/test/compile-fail/lint-default-methods.rs b/src/test/compile-fail/lint-default-methods.rs deleted file mode 100644 index 23befde7559..00000000000 --- a/src/test/compile-fail/lint-default-methods.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[forbid(default_methods)]; - -trait Foo { //~ ERROR default methods are experimental - fn bar(&self) { println("hi"); } -} - -fn main() {} diff --git a/src/test/compile-fail/lint-non-camel-case-types.rs b/src/test/compile-fail/lint-non-camel-case-types.rs index 27c9ca64a93..2cabdfe5bb0 100644 --- a/src/test/compile-fail/lint-non-camel-case-types.rs +++ b/src/test/compile-fail/lint-non-camel-case-types.rs @@ -10,25 +10,25 @@ #[forbid(non_camel_case_types)]; -struct foo { //~ ERROR type, variant, or trait should have a camel case identifier +struct foo { //~ ERROR type `foo` should have a camel case identifier bar: int, } -enum foo2 { //~ ERROR type, variant, or trait should have a camel case identifier +enum foo2 { //~ ERROR type `foo2` should have a camel case identifier Bar } -struct foo3 { //~ ERROR type, variant, or trait should have a camel case identifier +struct foo3 { //~ ERROR type `foo3` should have a camel case identifier bar: int } -type foo4 = int; //~ ERROR type, variant, or trait should have a camel case identifier +type foo4 = int; //~ ERROR type `foo4` should have a camel case identifier enum Foo5 { - bar //~ ERROR type, variant, or trait should have a camel case identifier + bar //~ ERROR variant `bar` should have a camel case identifier } -trait foo6 { //~ ERROR type, variant, or trait should have a camel case identifier +trait foo6 { //~ ERROR trait `foo6` should have a camel case identifier } fn main() { } diff --git a/src/test/run-pass/default-method-supertrait-vtable.rs b/src/test/run-pass/default-method-supertrait-vtable.rs new file mode 100644 index 00000000000..90a2b914021 --- /dev/null +++ b/src/test/run-pass/default-method-supertrait-vtable.rs @@ -0,0 +1,36 @@ +// 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 we can call a function bounded over a supertrait from +// a default method + +fn require_y<T: Y>(x: T) -> int { x.y() } + +trait Y { + fn y(self) -> int; +} + + +trait Z: Y { + fn x(self) -> int { + require_y(self) + } +} + +impl Y for int { + fn y(self) -> int { self } +} + +impl Z for int; + +fn main() { + assert_eq!(12.x(), 12); +} diff --git a/src/test/run-pass/deriving-zero.rs b/src/test/run-pass/deriving-zero.rs index 2ee57624112..f2c5a7e94ef 100644 --- a/src/test/run-pass/deriving-zero.rs +++ b/src/test/run-pass/deriving-zero.rs @@ -33,6 +33,7 @@ struct Lots { g: (f32, char), h: ~[util::NonCopyable], i: @mut (int, int), + j: bool, } fn main() { diff --git a/src/test/run-pass/enum-discr.rs b/src/test/run-pass/enum-discr.rs new file mode 100644 index 00000000000..5a14f0050e8 --- /dev/null +++ b/src/test/run-pass/enum-discr.rs @@ -0,0 +1,20 @@ +enum Animal { + Cat = 0u, + Dog = 1u, + Horse = 2u, + Snake = 3u +} + +enum Hero { + Batman = -1, + Superman = -2, + Ironman = -3, + Spiderman = -4 +} + +fn main() { + let pet: Animal = Snake; + let hero: Hero = Superman; + assert!(pet as uint == 3); + assert!(hero as int == -2); +} diff --git a/src/test/run-pass/issue-3168.rs b/src/test/run-pass/issue-3168.rs index fbe66708e47..609849bffb4 100644 --- a/src/test/run-pass/issue-3168.rs +++ b/src/test/run-pass/issue-3168.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-fast +// xfail-win32 #7999 use std::comm; use std::task; diff --git a/src/test/run-pass/issue-3176.rs b/src/test/run-pass/issue-3176.rs index 96648a2706b..df242ee3d30 100644 --- a/src/test/run-pass/issue-3176.rs +++ b/src/test/run-pass/issue-3176.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-fast +// xfail-win32 #7999 use std::comm::{Select2, Selectable}; use std::comm; diff --git a/src/test/run-pass/issue-3979-2.rs b/src/test/run-pass/issue-3979-2.rs index 9a8b90db185..39e9f5dcd2d 100644 --- a/src/test/run-pass/issue-3979-2.rs +++ b/src/test/run-pass/issue-3979-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - trait A { fn a_method(&self); } diff --git a/src/test/run-pass/issue-3979-generics.rs b/src/test/run-pass/issue-3979-generics.rs index 2a1ded96827..867301121da 100644 --- a/src/test/run-pass/issue-3979-generics.rs +++ b/src/test/run-pass/issue-3979-generics.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test FIXME #5946 trait Positioned<S> { fn SetX(&mut self, S); fn X(&self) -> S; } -trait Movable<S, T>: Positioned<T> { - fn translate(&self, dx: T) { - self.SetX(self.X() + dx); +trait Movable<S: Add<S, S>>: Positioned<S> { + fn translate(&mut self, dx: S) { + let x = self.X() + dx; + self.SetX(x); } } @@ -31,10 +31,10 @@ impl Positioned<int> for Point { } } -impl Movable<int, int> for Point; +impl Movable<int> for Point; pub fn main() { - let p = Point{ x: 1, y: 2}; + let mut p = Point{ x: 1, y: 2}; p.translate(3); assert_eq!(p.X(), 4); } diff --git a/src/test/run-pass/issue-3979-xcrate.rs b/src/test/run-pass/issue-3979-xcrate.rs index 4bde414c4ac..caf6d202316 100644 --- a/src/test/run-pass/issue-3979-xcrate.rs +++ b/src/test/run-pass/issue-3979-xcrate.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test // tjc: ??? +// xfail-fast // aux-build:issue_3979_traits.rs extern mod issue_3979_traits; use issue_3979_traits::*; diff --git a/src/test/run-pass/issue-3979.rs b/src/test/run-pass/issue-3979.rs index fe10dd5af53..2e53fb5d3f9 100644 --- a/src/test/run-pass/issue-3979.rs +++ b/src/test/run-pass/issue-3979.rs @@ -1,5 +1,3 @@ -// xfail-test -// Reason: ICE with explicit self // Copyright 2012 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/issue-7712.rs b/src/test/run-pass/issue-7712.rs index d4faae415d2..41c4af86bac 100644 --- a/src/test/run-pass/issue-7712.rs +++ b/src/test/run-pass/issue-7712.rs @@ -10,8 +10,6 @@ // compile-flags:-Z debug-info -#[allow(default_methods)]; - pub trait TraitWithDefaultMethod { pub fn method(self) { () @@ -24,4 +22,4 @@ impl TraitWithDefaultMethod for MyStruct { } fn main() { MyStruct.method(); -} \ No newline at end of file +} diff --git a/src/test/compile-fail/issue-2467.rs b/src/test/run-pass/no-std-xcrate.rs index 3149db8a03f..104e33b7488 100644 --- a/src/test/compile-fail/issue-2467.rs +++ b/src/test/run-pass/no-std-xcrate.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,9 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum test { thing = 3u } //~ ERROR mismatched types -//~^ ERROR expected signed integer constant +// xfail-fast +// aux-build:no_std_crate.rs + +// This tests that crates which link to std can also be linked to crates with +// #[no_std] that have no lang items. + +extern mod no_std_crate; + fn main() { - error!(thing as int); - assert_eq!(thing as int, 3); + no_std_crate::foo(); } diff --git a/src/test/run-pass/no-std-xcrate2.rs b/src/test/run-pass/no-std-xcrate2.rs new file mode 100644 index 00000000000..e393eb3a5c9 --- /dev/null +++ b/src/test/run-pass/no-std-xcrate2.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-test: this has weird linking problems on linux, and it probably needs a +// solution along the lines of disabling segmented stacks and/or the +// stack checks. +// aux-build:no_std_crate.rs + +// This tests that libraries built with #[no_std] can be linked to crates with +// #[no_std] and actually run. + +#[no_std]; + +extern mod no_std_crate; + +// This is an unfortunate thing to have to do on linux :( +#[cfg(target_os = "linux")] +#[doc(hidden)] +pub mod linkhack { + #[link_args="-lrustrt -lrt"] + extern {} +} + +#[start] +fn main(_: int, _: **u8, _: *u8) -> int { + no_std_crate::foo(); + 0 +} diff --git a/src/test/run-pass/pipe-sleep.rs b/src/test/run-pass/pipe-sleep.rs index 549c7332440..4475a16a63b 100644 --- a/src/test/run-pass/pipe-sleep.rs +++ b/src/test/run-pass/pipe-sleep.rs @@ -11,6 +11,7 @@ // except according to those terms. // xfail-test needs sleep +// xfail-win32 #7999 extern mod extra; diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index 21d13c722e7..e91537bec3b 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -14,8 +14,8 @@ use std::int; use std::libc::c_void; use std::ptr; use std::sys; -use std::vec::UnboxedVecRepr; use std::unstable::intrinsics::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Opaque}; +use std::unstable::raw::Vec; #[doc = "High-level interfaces to `std::unstable::intrinsics::visit_ty` reflection system."] @@ -247,7 +247,7 @@ impl<V:TyVisitor + movable_ptr> TyVisitor for ptr_visit_adaptor<V> { } fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<UnboxedVecRepr>(); + self.align_to::<Vec<()>>(); // FIXME (#3732): Inner really has to move its own pointers on this one. // or else possibly we could have some weird interface wherein we // read-off a word from inner's pointers, but the read-word has to diff --git a/src/test/run-pass/supertrait-default-generics.rs b/src/test/run-pass/supertrait-default-generics.rs new file mode 100644 index 00000000000..ae7e18d532b --- /dev/null +++ b/src/test/run-pass/supertrait-default-generics.rs @@ -0,0 +1,42 @@ +// 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. + +// There is some other borrowck bug, so we make the stuff not mut. + +trait Positioned<S> { + fn SetX(&mut self, S); + fn X(&self) -> S; +} + +trait Movable<S: Add<S, S>>: Positioned<S> { + fn translate(&mut self, dx: S) { + let x = self.X() + dx; + self.SetX(x); + } +} + +struct Point<S> { x: S, y: S } + +impl<S: Clone> Positioned<S> for Point<S> { + fn SetX(&mut self, x: S) { + self.x = x; + } + fn X(&self) -> S { + self.x.clone() + } +} + +impl<S: Clone + Add<S, S>> Movable<S> for Point<S>; + +pub fn main() { + let mut p = Point{ x: 1, y: 2}; + p.translate(3); + assert_eq!(p.X(), 4); +} diff --git a/src/test/compile-fail/tag-variant-disr-type-mismatch.rs b/src/test/run-pass/tag-variant-disr-type-mismatch.rs index 518a12fb2eb..514f868db54 100644 --- a/src/test/compile-fail/tag-variant-disr-type-mismatch.rs +++ b/src/test/run-pass/tag-variant-disr-type-mismatch.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//error-pattern: mismatched types - enum color { red = 1u, blue = 2, 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 41b971d64d0..d4a95ea607c 100644 --- a/src/test/run-pass/unit-like-struct-drop-run.rs +++ b/src/test/run-pass/unit-like-struct-drop-run.rs @@ -10,6 +10,7 @@ // Make sure the destructor is run for unit-like structs. // xfail-fast +// xfail-win32 #7999 use std::task; |
