]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #42394 - ollie27:rustdoc_deref_box, r=QuietMisdreavus
authorbors <bors@rust-lang.org>
Tue, 6 Jun 2017 06:18:17 +0000 (06:18 +0000)
committerbors <bors@rust-lang.org>
Tue, 6 Jun 2017 06:18:17 +0000 (06:18 +0000)
rustdoc: Hide `self: Box<Self>` in list of deref methods

These methods can never be called through deref so there is no point including them. For example you can't call [`into_boxed_bytes`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.into_boxed_bytes) or [`into_string`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.into_string) on `String`.

285 files changed:
.gitignore
.travis.yml
RELEASES.md
src/Cargo.lock
src/bootstrap/Cargo.toml
src/bootstrap/bin/rustc.rs
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/step.rs
src/bootstrap/util.rs
src/build_helper/lib.rs
src/ci/docker/run.sh
src/ci/init_repo.sh
src/ci/run.sh
src/ci/shared.sh
src/doc/book
src/doc/nomicon
src/doc/reference
src/doc/unstable-book/src/SUMMARY.md
src/doc/unstable-book/src/library-features/slice-rotate.md [new file with mode: 0644]
src/liballoc_jemalloc/Cargo.toml
src/liballoc_system/lib.rs
src/libcollections/benches/lib.rs
src/libcollections/benches/slice.rs
src/libcollections/borrow.rs
src/libcollections/lib.rs
src/libcollections/slice.rs
src/libcollections/tests/binary_heap.rs
src/libcollections/tests/lib.rs
src/libcollections/tests/slice.rs
src/libcollections/tests/vec.rs
src/libcollections/tests/vec_deque.rs
src/libcompiler_builtins/Cargo.toml
src/libcore/intrinsics.rs
src/libcore/iter/mod.rs
src/libcore/iter/range.rs
src/libcore/slice/mod.rs
src/libcore/slice/rotate.rs [new file with mode: 0644]
src/libcore/tests/iter.rs
src/libcore/tests/lib.rs
src/libcore/tests/slice.rs
src/libflate/Cargo.toml
src/librustc/cfg/construct.rs
src/librustc/dep_graph/README.md
src/librustc/dep_graph/dep_node.rs
src/librustc/dep_graph/safe.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/definitions.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/ich/fingerprint.rs
src/librustc/ich/hcx.rs
src/librustc/ich/impls_hir.rs
src/librustc/ich/impls_ty.rs
src/librustc/infer/at.rs [new file with mode: 0644]
src/librustc/infer/combine.rs
src/librustc/infer/mod.rs
src/librustc/infer/sub.rs
src/librustc/lib.rs
src/librustc/middle/cstore.rs
src/librustc/middle/dead.rs
src/librustc/middle/effect.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/intrinsicck.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/reachable.rs
src/librustc/middle/region.rs
src/librustc/traits/coherence.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/fulfill.rs
src/librustc/traits/mod.rs
src/librustc/traits/project.rs
src/librustc/traits/select.rs
src/librustc/traits/specialize/mod.rs
src/librustc/traits/specialize/specialization_graph.rs
src/librustc/traits/structural_impls.rs
src/librustc/traits/trans/mod.rs
src/librustc/traits/util.rs
src/librustc/ty/adjustment.rs
src/librustc/ty/context.rs
src/librustc/ty/fold.rs
src/librustc/ty/layout.rs
src/librustc/ty/maps.rs
src/librustc/ty/mod.rs
src/librustc/ty/structural_impls.rs
src/librustc/ty/sty.rs
src/librustc/ty/subst.rs
src/librustc/ty/trait_def.rs
src/librustc/ty/util.rs
src/librustc/ty/wf.rs
src/librustc/util/ppaux.rs
src/librustc_borrowck/borrowck/check_loans.rs
src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
src/librustc_borrowck/borrowck/gather_loans/mod.rs
src/librustc_borrowck/borrowck/gather_loans/move_error.rs
src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_borrowck/borrowck/move_data.rs
src/librustc_const_eval/check_match.rs
src/librustc_const_eval/diagnostics.rs
src/librustc_const_eval/eval.rs
src/librustc_const_eval/pattern.rs
src/librustc_driver/test.rs
src/librustc_errors/diagnostic.rs
src/librustc_errors/emitter.rs
src/librustc_errors/lib.rs
src/librustc_incremental/calculate_svh/mod.rs
src/librustc_incremental/persist/data.rs
src/librustc_incremental/persist/directory.rs [deleted file]
src/librustc_incremental/persist/dirty_clean.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/mod.rs
src/librustc_incremental/persist/save.rs
src/librustc_lint/builtin.rs
src/librustc_lint/types.rs
src/librustc_lint/unused.rs
src/librustc_llvm/Cargo.toml
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/decoder.rs
src/librustc_mir/build/expr/as_constant.rs
src/librustc_mir/build/expr/as_temp.rs
src/librustc_mir/build/expr/into.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/hair/cx/block.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/hair/mod.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/type_check.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_mir/util/pretty.rs
src/librustc_passes/consts.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_save_analysis/lib.rs
src/librustc_trans/Cargo.toml
src/librustc_trans/back/link.rs
src/librustc_trans/back/msvc/arch.rs [deleted file]
src/librustc_trans/back/msvc/mod.rs [deleted file]
src/librustc_trans/back/msvc/registry.rs [deleted file]
src/librustc_trans/base.rs
src/librustc_trans/context.rs
src/librustc_trans/glue.rs
src/librustc_trans/intrinsic.rs
src/librustc_trans/lib.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/autoderef.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/cast.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/dropck.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/op.rs
src/librustc_typeck/check/regionck.rs
src/librustc_typeck/check/upvar.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/coherence/builtin.rs
src/librustc_typeck/coherence/inherent_impls_overlap.rs
src/librustc_typeck/lib.rs
src/librustdoc/Cargo.toml
src/librustdoc/clean/mod.rs
src/librustdoc/html/format.rs
src/libstd/Cargo.toml
src/libstd/io/error.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sys/redox/syscall/data.rs
src/libstd/sys/unix/process/magenta.rs
src/libstd/thread/mod.rs
src/libsyntax/codemap.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/parser.rs
src/test/codegen/fastcall-inreg.rs
src/test/codegen/prefetch.rs [new file with mode: 0644]
src/test/compile-fail/E0297.rs
src/test/compile-fail/E0603.rs [new file with mode: 0644]
src/test/compile-fail/auxiliary/no_method_suggested_traits.rs [deleted file]
src/test/compile-fail/bogus-tag.rs
src/test/compile-fail/feature-gate-decl_macro.rs
src/test/compile-fail/for-loop-has-unit-body.rs [new file with mode: 0644]
src/test/compile-fail/issue-21659-show-relevant-trait-impls-3.rs [deleted file]
src/test/compile-fail/issue-26548.rs [deleted file]
src/test/compile-fail/issue-28344.rs
src/test/compile-fail/issue-30123.rs
src/test/compile-fail/issue-36082.rs
src/test/compile-fail/issue-39559.rs
src/test/compile-fail/issue-3973.rs
src/test/compile-fail/issue-7950.rs
src/test/compile-fail/lexical-scopes.rs
src/test/compile-fail/method-call-err-msg.rs
src/test/compile-fail/method-suggestion-no-duplication.rs [deleted file]
src/test/compile-fail/no-method-suggested-traits.rs [deleted file]
src/test/compile-fail/trait-item-privacy.rs
src/test/compile-fail/unspecified-self-in-trait-ref.rs
src/test/compile-fail/unused-macro-rules.rs [new file with mode: 0644]
src/test/compile-fail/unused-macro.rs
src/test/parse-fail/removed-syntax-extern-const.rs
src/test/parse-fail/underscore-suffix-for-string.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs [deleted file]
src/test/run-pass-fulldeps/auxiliary/lint_plugin_test.rs [deleted file]
src/test/run-pass-fulldeps/deprecated-derive.rs [deleted file]
src/test/run-pass-fulldeps/lint-group-plugin.rs [deleted file]
src/test/run-pass-fulldeps/lint-plugin-cmdline-allow.rs [deleted file]
src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs [deleted file]
src/test/run-pass-fulldeps/lint-plugin.rs [deleted file]
src/test/run-pass/deprecated-macro_escape-inner.rs [deleted file]
src/test/run-pass/deprecated-macro_escape.rs [deleted file]
src/test/run-pass/deriving-meta-empty-trait-list.rs [deleted file]
src/test/run-pass/enum-size-variance.rs [deleted file]
src/test/run-pass/for-loop-has-unit-body.rs [new file with mode: 0644]
src/test/run-pass/i128-ffi.rs
src/test/run-pass/issue-19100.rs [deleted file]
src/test/run-pass/path-lookahead.rs [deleted file]
src/test/run-pass/test-should-panic-attr.rs [deleted file]
src/test/ui-fulldeps/auxiliary/lint_group_plugin_test.rs [new file with mode: 0644]
src/test/ui-fulldeps/auxiliary/lint_plugin_test.rs [new file with mode: 0644]
src/test/ui-fulldeps/deprecated-derive.rs [new file with mode: 0644]
src/test/ui-fulldeps/deprecated-derive.stderr [new file with mode: 0644]
src/test/ui-fulldeps/lint-group-plugin.rs [new file with mode: 0644]
src/test/ui-fulldeps/lint-group-plugin.stderr [new file with mode: 0644]
src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs [new file with mode: 0644]
src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr [new file with mode: 0644]
src/test/ui-fulldeps/lint-plugin-cmdline-load.rs [new file with mode: 0644]
src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr [new file with mode: 0644]
src/test/ui-fulldeps/lint-plugin.rs [new file with mode: 0644]
src/test/ui-fulldeps/lint-plugin.stderr [new file with mode: 0644]
src/test/ui/deprecated-macro_escape-inner.rs [new file with mode: 0644]
src/test/ui/deprecated-macro_escape-inner.stderr [new file with mode: 0644]
src/test/ui/deprecated-macro_escape.rs [new file with mode: 0644]
src/test/ui/deprecated-macro_escape.stderr [new file with mode: 0644]
src/test/ui/deriving-meta-empty-trait-list.rs [new file with mode: 0644]
src/test/ui/deriving-meta-empty-trait-list.stderr [new file with mode: 0644]
src/test/ui/enum-size-variance.rs [new file with mode: 0644]
src/test/ui/enum-size-variance.stderr [new file with mode: 0644]
src/test/ui/impl-trait/auxiliary/no_method_suggested_traits.rs [new file with mode: 0644]
src/test/ui/impl-trait/equality.stderr
src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.rs [new file with mode: 0644]
src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.stderr [new file with mode: 0644]
src/test/ui/impl-trait/method-suggestion-no-duplication.rs [new file with mode: 0644]
src/test/ui/impl-trait/method-suggestion-no-duplication.stderr [new file with mode: 0644]
src/test/ui/impl-trait/no-method-suggested-traits.rs [new file with mode: 0644]
src/test/ui/impl-trait/no-method-suggested-traits.stderr [new file with mode: 0644]
src/test/ui/impl-trait/trait_type.rs [new file with mode: 0644]
src/test/ui/impl-trait/trait_type.stderr [new file with mode: 0644]
src/test/ui/issue-19100.rs [new file with mode: 0644]
src/test/ui/issue-19100.stderr [new file with mode: 0644]
src/test/ui/issue-26548.rs [new file with mode: 0644]
src/test/ui/issue-26548.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/binops.stderr
src/test/ui/path-lookahead.rs [new file with mode: 0644]
src/test/ui/path-lookahead.stderr [new file with mode: 0644]
src/test/ui/resolve/privacy-struct-ctor.stderr
src/test/ui/span/coerce-suggestions.rs
src/test/ui/span/coerce-suggestions.stderr
src/test/ui/span/issue-7575.stderr
src/test/ui/span/multiline-span-simple.stderr
src/test/ui/test-should-panic-attr.rs [new file with mode: 0644]
src/test/ui/test-should-panic-attr.stderr [new file with mode: 0644]
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/rust-installer
src/tools/tidy/src/features.rs
src/tools/tidy/src/main.rs

index d82e279e012d8d22b452832a46a014436151c9b1..ff839c34df1a7d323301568c4629f43eb84afd59 100644 (file)
@@ -101,3 +101,4 @@ version.ml
 version.texi
 .cargo
 !src/vendor/**
+/src/target/
index 190cb3380a18c633870f6c4d0f7baf677bf3d09a..40fecb3ee5ea490c34c9944ad111a34e679fe94c 100644 (file)
@@ -1,4 +1,4 @@
-language: minimal
+language: generic
 sudo: required
 dist: trusty
 services:
@@ -33,7 +33,7 @@ matrix:
     - env: IMAGE=dist-powerpc64le-linux DEPLOY=1
     - env: IMAGE=dist-s390x-linux DEPLOY=1
     - env: IMAGE=dist-x86_64-freebsd DEPLOY=1
-    - env: IMAGE=dist-x86_64-linux DEPLOY=1
+    - env: IMAGE=dist-x86_64-linux DEPLOY=1 ALLOW_TRY=1
     - env: IMAGE=dist-x86_64-musl DEPLOY=1
     - env: IMAGE=dist-x86_64-netbsd DEPLOY=1
     - env: IMAGE=emscripten
@@ -152,20 +152,35 @@ before_script:
       echo "#### Disk usage before running script:";
       df -h;
       du . | sort -nr | head -n100
-
-script:
+  # If we are building a pull request, do the build if $ALLOW_PR == 1
+  # Otherwise, do the build if we are on the auto branch, or the try branch and $ALLOW_TRY == 1
   - >
-      if [ "$ALLOW_PR" = "" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then
-          echo skipping, not a full build
+      if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then
+          if [[ "$ALLOW_PR" == "1" ]]; then
+              SKIP_BUILD=false;
+          else
+              SKIP_BUILD=true;
+          fi
+      elif [[ "$TRAVIS_BRANCH" == "auto" || ( "$ALLOW_TRY" == "1" && "$TRAVIS_BRANCH" == "try" ) ]]; then
+          SKIP_BUILD=false;
+      else
+          SKIP_BUILD=true;
+      fi
+
+      if [[ "$SKIP_BUILD" == true ]]; then
+          export RUN_SCRIPT="echo 'skipping, not a full build'";
       else
-          stamp src/ci/init_repo.sh . "$HOME/rustsrc" &&
+          RUN_SCRIPT="stamp src/ci/init_repo.sh . $HOME/rustsrc";
           if [ "$TRAVIS_OS_NAME" = "osx" ]; then
-              stamp src/ci/run.sh;
+              export RUN_SCRIPT="$RUN_SCRIPT && stamp src/ci/run.sh";
           else
-              stamp src/ci/docker/run.sh $IMAGE;
+              export RUN_SCRIPT="$RUN_SCRIPT && stamp src/ci/docker/run.sh $IMAGE";
           fi
       fi
 
+script:
+  - sh -x -c "$RUN_SCRIPT"
+
 after_success:
   - >
       echo "#### Build successful; Disk usage after running script:";
@@ -238,6 +253,20 @@ deploy:
       branch: auto
       condition: $DEPLOY = 1
 
+  - provider: s3
+    bucket: rust-lang-ci
+    skip_cleanup: true
+    local_dir: deploy
+    upload_dir: rustc-builds-try
+    acl: public_read
+    region: us-east-1
+    access_key_id: AKIAIPQVNYF2T3DTYIWQ
+    secret_access_key:
+      secure: "FBqDqOTeIPMu6v/WYPf4CFSlh9rLRZGKVtpLa5KkyuOhXRTrnEzBduEtS8/FMIxdQImvurhSvxWvqRybMOi4qoVfjMqqpHAI7uBbidbrvAcJoHNsx6BgUNVCIoH6a0UsAjTUtm6/YPIpzbHoLZXPL0GrHPMk6Mu04qVSmcYNWn4="
+    on:
+      branch: try
+      condition: $DEPLOY = 1 && $ALLOW_TRY = 1
+
   # this is the same as the above deployment provider except that it uploads to
   # a slightly different directory and has a different trigger
   - provider: s3
index 8f641792add66cf519096bf6db50f13aacbc266b..d397ec556851fff8167070a19bc6be9a895b4559 100644 (file)
@@ -1,3 +1,153 @@
+Version 1.18.0 (2017-06-08)
+===========================
+
+Language
+--------
+
+- [Stabilize pub(restricted)][40556] `pub` can now accept a module path to
+  make the item visible to just that module tree. Also accepts the keyword
+  `crate` to make something public to the whole crate but not users of the
+  library. Example: `pub(crate) mod utils;`. [RFC 1422].
+- [Stabilize `#![windows_subsystem]` attribute][40870] conservative exposure of the
+  `/SUBSYSTEM` linker flag on Windows platforms. [RFC 1665].
+- [Refactor of trait object type parsing][40043] Now `ty` in macros can accept
+  types like `Write + Send`, trailing `+` are now supported in trait objects,
+  and better error reporting for trait objects starting with `?Sized`.
+- [0e+10 is now a valid floating point literal][40589]
+- [Now warns if you bind a lifetime parameter to 'static][40734]
+- [Tuples, Enum variant fields, and structs with no `repr` attribute or with
+  `#[repr(Rust)]` are reordered to minimize padding and produce a smaller
+  representation in some cases.][40377]
+
+Compiler
+--------
+
+- [rustc can now emit mir with `--emit mir`][39891]
+- [Improved LLVM IR for trivial functions][40367]
+- [Added explanation for E0090(Wrong number of lifetimes are supplied)][40723]
+- [rustc compilation is now 15%-20% faster][41469] Thanks to optimisation
+  opportunities found through profiling
+- [Improved backtrace formatting when panicking][38165]
+
+Libraries
+---------
+
+- [Specialized `Vec::from_iter` being passed `vec::IntoIter`][40731] if the
+  iterator hasn't been advanced the original `Vec` is reassembled with no actual
+  iteration or reallocation.
+- [Simplified HashMap Bucket interface][40561] provides performance
+  improvements for iterating and cloning.
+- [Specialize Vec::from_elem to use calloc][40409]
+- [Fixed Race condition in fs::create_dir_all][39799]
+- [No longer caching stdio on Windows][40516]
+- [Optimized insertion sort in slice][40807] insertion sort in some cases
+  2.50%~ faster and in one case now 12.50% faster.
+- [Optimized `AtomicBool::fetch_nand`][41143]
+
+Stabilized APIs
+---------------
+
+- [`Child::try_wait`]
+- [`HashMap::retain`]
+- [`HashSet::retain`]
+- [`PeekMut::pop`]
+- [`TcpStream::peek`]
+- [`UdpSocket::peek`]
+- [`UdpSocket::peek_from`]
+
+Cargo
+-----
+
+- [Added partial Pijul support][cargo/3842] Pijul is a version control system in Rust.
+  You can now create new cargo projects with Pijul using `cargo new --vcs pijul`
+- [Now always emits build script warnings for crates that fail to build][cargo/3847]
+- [Added Android build support][cargo/3885]
+- [Added `--bins` and `--tests` flags][cargo/3901] now you can build all programs
+  of a certain type, for example `cargo build --bins` will build all
+  binaries.
+- [Added support for haiku][cargo/3952]
+
+Misc
+----
+
+- [rustdoc can now use pulldown-cmark with the `--enable-commonmark` flag][40338]
+- [Added rust-winbg script for better debugging on Windows][39983]
+- [Rust now uses the official cross compiler for NetBSD][40612]
+- [rustdoc now accepts `#` at the start of files][40828]
+- [Fixed jemalloc support for musl][41168]
+
+Compatibility Notes
+-------------------
+
+- [Changes to how the `0` flag works in format!][40241] Padding zeroes are now
+  always placed after the sign if it exists and before the digits. With the `#`
+  flag the zeroes are placed after the prefix and before the digits.
+- [Due to the struct field optimisation][40377], using `transmute` on structs
+  that have no `repr` attribute or `#[repr(Rust)]` will no longer work. This has
+  always been undefined behavior, but is now more likely to break in practice.
+- [The refactor of trait object type parsing][40043] fixed a bug where `+` was
+  receiving the wrong priority parsing things like `&for<'a> Tr<'a> + Send` as
+  `&(for<'a> Tr<'a> + Send)` instead of `(&for<'a> Tr<'a>) + Send`
+- [Overlapping inherent `impl`s are now a hard error][40728]
+- [`PartialOrd` and `Ord` must agree on the ordering.][41270]
+- [`rustc main.rs -o out --emit=asm,llvm-ir`][41085] Now will output
+  `out.asm` and `out.ll` instead of only one of the filetypes.
+- [ calling a function that returns `Self` will no longer work][41805] when
+  the size of `Self` cannot be statically determined.
+- [rustc now builds with a "pthreads" flavour of MinGW for Windows GNU][40805]
+  this has caused a few regressions namely:
+
+  - Changed the link order of local static/dynamic libraries (respecting the
+    order on given rather than having the compiler reorder).
+  - Changed how MinGW is linked, native code linked to dynamic libraries
+    may require manually linking to the gcc support library (for the native
+    code itself)
+
+[38165]: https://github.com/rust-lang/rust/pull/38165
+[39799]: https://github.com/rust-lang/rust/pull/39799
+[39891]: https://github.com/rust-lang/rust/pull/39891
+[39983]: https://github.com/rust-lang/rust/pull/39983
+[40043]: https://github.com/rust-lang/rust/pull/40043
+[40241]: https://github.com/rust-lang/rust/pull/40241
+[40338]: https://github.com/rust-lang/rust/pull/40338
+[40367]: https://github.com/rust-lang/rust/pull/40367
+[40377]: https://github.com/rust-lang/rust/pull/40377
+[40409]: https://github.com/rust-lang/rust/pull/40409
+[40516]: https://github.com/rust-lang/rust/pull/40516
+[40556]: https://github.com/rust-lang/rust/pull/40556
+[40561]: https://github.com/rust-lang/rust/pull/40561
+[40589]: https://github.com/rust-lang/rust/pull/40589
+[40612]: https://github.com/rust-lang/rust/pull/40612
+[40723]: https://github.com/rust-lang/rust/pull/40723
+[40728]: https://github.com/rust-lang/rust/pull/40728
+[40731]: https://github.com/rust-lang/rust/pull/40731
+[40734]: https://github.com/rust-lang/rust/pull/40734
+[40805]: https://github.com/rust-lang/rust/pull/40805
+[40807]: https://github.com/rust-lang/rust/pull/40807
+[40828]: https://github.com/rust-lang/rust/pull/40828
+[40870]: https://github.com/rust-lang/rust/pull/40870
+[41085]: https://github.com/rust-lang/rust/pull/41085
+[41143]: https://github.com/rust-lang/rust/pull/41143
+[41168]: https://github.com/rust-lang/rust/pull/41168
+[41270]: https://github.com/rust-lang/rust/issues/41270
+[41469]: https://github.com/rust-lang/rust/pull/41469
+[41805]: https://github.com/rust-lang/rust/issues/41805
+[RFC 1422]: https://github.com/rust-lang/rfcs/blob/master/text/1422-pub-restricted.md
+[RFC 1665]: https://github.com/rust-lang/rfcs/blob/master/text/1665-windows-subsystem.md
+[`Child::try_wait`]: https://doc.rust-lang.org/std/process/struct.Child.html#method.try_wait
+[`HashMap::retain`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.retain
+[`HashSet::retain`]: https://doc.rust-lang.org/std/collections/struct.HashSet.html#method.retain
+[`PeekMut::pop`]: https://doc.rust-lang.org/std/collections/binary_heap/struct.PeekMut.html#method.pop
+[`TcpStream::peek`]: https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.peek
+[`UdpSocket::peek_from`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.peek_from
+[`UdpSocket::peek`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.peek
+[cargo/3842]: https://github.com/rust-lang/cargo/pull/3842
+[cargo/3847]: https://github.com/rust-lang/cargo/pull/3847
+[cargo/3885]: https://github.com/rust-lang/cargo/pull/3885
+[cargo/3901]: https://github.com/rust-lang/cargo/pull/3901
+[cargo/3952]: https://github.com/rust-lang/cargo/pull/3952
+
+
 Version 1.17.0 (2017-04-27)
 ===========================
 
index d55dd919bdf28cf9446672dc69b69bd9205990ef..cc2da1a02dc9fe66c4be7eba1b6b90c5573ff454 100644 (file)
@@ -44,7 +44,7 @@ version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
  "core 0.0.0",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.0.0",
 ]
 
@@ -84,7 +84,7 @@ name = "backtrace-sys"
 version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -110,7 +110,7 @@ dependencies = [
  "build_helper 0.1.0",
  "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -178,7 +178,7 @@ dependencies = [
  "serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -202,7 +202,7 @@ dependencies = [
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -239,7 +239,7 @@ name = "cmake"
 version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -257,7 +257,7 @@ version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
  "core 0.0.0",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -308,7 +308,7 @@ name = "curl-sys"
 version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -411,7 +411,7 @@ name = "flate"
 version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -444,7 +444,7 @@ dependencies = [
 
 [[package]]
 name = "gcc"
-version = "0.3.46"
+version = "0.3.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -540,7 +540,7 @@ dependencies = [
  "flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "xz2 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -605,7 +605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "curl-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -630,7 +630,7 @@ name = "libz-sys"
 version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -650,7 +650,7 @@ version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -697,7 +697,7 @@ name = "miniz-sys"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -830,7 +830,7 @@ name = "openssl-sys"
 version = "0.9.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1248,7 +1248,7 @@ name = "rustc_llvm"
 version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_bitflags 0.0.0",
 ]
 
@@ -1375,6 +1375,7 @@ name = "rustc_trans"
 version = "0.0.0"
 dependencies = [
  "flate 0.0.0",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
@@ -1425,7 +1426,7 @@ dependencies = [
  "arena 0.0.0",
  "build_helper 0.1.0",
  "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
@@ -1577,7 +1578,7 @@ dependencies = [
  "collections 0.0.0",
  "compiler_builtins 0.0.0",
  "core 0.0.0",
- "gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.0.0",
  "panic_abort 0.0.0",
  "panic_unwind 0.0.0",
@@ -1744,7 +1745,7 @@ dependencies = [
 
 [[package]]
 name = "tar"
-version = "0.4.12"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2042,7 +2043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
 "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d"
 "checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf"
-"checksum gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "181e3cebba1d663bd92eb90e2da787e10597e027eb00de8d742b260a7850948f"
+"checksum gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)" = "5f837c392f2ea61cb1576eac188653df828c861b7137d74ea4a5caa89621f9e6"
 "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
 "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
 "checksum git2 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9de9df4358c17e448a778d90cd0272e1dab5eae30244502333fa2001c4e24357"
@@ -2128,7 +2129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047"
 "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde"
 "checksum syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e0e4dbae163dd98989464c23dd503161b338790640e11537686f2ef0f25c791"
-"checksum tar 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ab0ef9ead2fe0aa9e18475a96a207bfd5143f4124779ef7429503a8665416ce8"
+"checksum tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "281285b717926caa919ad905ef89c63d75805c7d89437fb873100925a53f2b1b"
 "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
 "checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989"
 "checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a"
index cc560e0172e3a3fa63a6e92e2bc873b028d49633..8842dce0257dd064f53544446176d4f1cf54e1e8 100644 (file)
@@ -36,5 +36,5 @@ num_cpus = "1.0"
 toml = "0.1"
 getopts = "0.2"
 rustc-serialize = "0.3"
-gcc = "0.3.46"
+gcc = "0.3.50"
 libc = "0.2"
index e11f7bd089f6c78ea8149981d0ea114816f6b3cc..d048645d4d5303fe60283178a4dff7aaed559482 100644 (file)
@@ -232,12 +232,6 @@ fn main() {
             if let Some(rpath) = rpath {
                 cmd.arg("-C").arg(format!("link-args={}", rpath));
             }
-
-            if let Ok(s) = env::var("RUSTFLAGS") {
-                for flag in s.split_whitespace() {
-                    cmd.arg(flag);
-                }
-            }
         }
 
         if target.contains("pc-windows-msvc") {
index d24bb074cd374d13bb50ad7cc8ce670f090e65c6..5483b6a914b29a3bdd9fde93c02f99e57a03e437 100644 (file)
@@ -58,6 +58,28 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+fn try_run(build: &Build, cmd: &mut Command) {
+    if build.flags.cmd.no_fail_fast() {
+        if !build.try_run(cmd) {
+            let failures = build.delayed_failures.get();
+            build.delayed_failures.set(failures + 1);
+        }
+    } else {
+        build.run(cmd);
+    }
+}
+
+fn try_run_quiet(build: &Build, cmd: &mut Command) {
+    if build.flags.cmd.no_fail_fast() {
+        if !build.try_run_quiet(cmd) {
+            let failures = build.delayed_failures.get();
+            build.delayed_failures.set(failures + 1);
+        }
+    } else {
+        build.run_quiet(cmd);
+    }
+}
+
 /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
 ///
 /// This tool in `src/tools` will verify the validity of all our links in the
@@ -67,8 +89,8 @@ pub fn linkcheck(build: &Build, host: &str) {
     let compiler = Compiler::new(0, host);
 
     let _time = util::timeit();
-    build.run(build.tool_cmd(&compiler, "linkchecker")
-                   .arg(build.out.join(host).join("doc")));
+    try_run(build, build.tool_cmd(&compiler, "linkchecker")
+                        .arg(build.out.join(host).join("doc")));
 }
 
 /// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler.
@@ -87,10 +109,10 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) {
     let _time = util::timeit();
     let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest"));
     build.prepare_tool_cmd(compiler, &mut cmd);
-    build.run(cmd.arg(&build.cargo)
-                 .arg(&out_dir)
-                 .env("RUSTC", build.compiler_path(compiler))
-                 .env("RUSTDOC", build.rustdoc(compiler)))
+    try_run(build, cmd.arg(&build.cargo)
+                      .arg(&out_dir)
+                      .env("RUSTC", build.compiler_path(compiler))
+                      .env("RUSTDOC", build.rustdoc(compiler)));
 }
 
 /// Runs `cargo test` for `cargo` packaged with Rust.
@@ -107,6 +129,9 @@ pub fn cargo(build: &Build, stage: u32, host: &str) {
 
     let mut cargo = build.cargo(compiler, Mode::Tool, host, "test");
     cargo.arg("--manifest-path").arg(build.src.join("src/tools/cargo/Cargo.toml"));
+    if build.flags.cmd.no_fail_fast() {
+        cargo.arg("--no-fail-fast");
+    }
 
     // Don't build tests dynamically, just a pain to work with
     cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
@@ -115,7 +140,7 @@ pub fn cargo(build: &Build, stage: u32, host: &str) {
     // available.
     cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
 
-    build.run(cargo.env("PATH", newpath));
+    try_run(build, cargo.env("PATH", newpath));
 }
 
 /// Runs the `tidy` tool as compiled in `stage` by the `host` compiler.
@@ -124,6 +149,7 @@ pub fn cargo(build: &Build, stage: u32, host: &str) {
 /// otherwise just implements a few lint-like checks that are specific to the
 /// compiler itself.
 pub fn tidy(build: &Build, host: &str) {
+    let _folder = build.fold_output(|| "tidy");
     println!("tidy check ({})", host);
     let compiler = Compiler::new(0, host);
     let mut cmd = build.tool_cmd(&compiler, "tidy");
@@ -131,7 +157,10 @@ pub fn tidy(build: &Build, host: &str) {
     if !build.config.vendor {
         cmd.arg("--no-vendor");
     }
-    build.run(&mut cmd);
+    if build.config.quiet_tests {
+        cmd.arg("--quiet");
+    }
+    try_run(build, &mut cmd);
 }
 
 fn testdir(build: &Build, host: &str) -> PathBuf {
@@ -148,6 +177,7 @@ pub fn compiletest(build: &Build,
                    target: &str,
                    mode: &str,
                    suite: &str) {
+    let _folder = build.fold_output(|| format!("test_{}", suite));
     println!("Check compiletest suite={} mode={} ({} -> {})",
              suite, mode, compiler.host, target);
     let mut cmd = Command::new(build.tool(&Compiler::new(0, compiler.host),
@@ -278,8 +308,10 @@ pub fn compiletest(build: &Build,
         cmd.arg("--android-cross-path").arg("");
     }
 
+    build.ci_env.force_coloring_in_ci(&mut cmd);
+
     let _time = util::timeit();
-    build.run(&mut cmd);
+    try_run(build, &mut cmd);
 }
 
 /// Run `rustdoc --test` for all documentation in `src/doc`.
@@ -292,6 +324,7 @@ pub fn docs(build: &Build, compiler: &Compiler) {
     // tests for all files that end in `*.md`
     let mut stack = vec![build.src.join("src/doc")];
     let _time = util::timeit();
+    let _folder = build.fold_output(|| "test_docs");
 
     while let Some(p) = stack.pop() {
         if p.is_dir() {
@@ -325,6 +358,7 @@ pub fn docs(build: &Build, compiler: &Compiler) {
 /// generate a markdown file from the error indexes of the code base which is
 /// then passed to `rustdoc --test`.
 pub fn error_index(build: &Build, compiler: &Compiler) {
+    let _folder = build.fold_output(|| "test_error_index");
     println!("Testing error-index stage{}", compiler.stage);
 
     let dir = testdir(build, compiler.host);
@@ -349,13 +383,14 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
     cmd.arg(markdown);
     cmd.env("RUSTC_BOOTSTRAP", "1");
 
-    let mut test_args = build.flags.cmd.test_args().join(" ");
-    if build.config.quiet_tests {
-        test_args.push_str(" --quiet");
-    }
+    let test_args = build.flags.cmd.test_args().join(" ");
     cmd.arg("--test-args").arg(test_args);
 
-    build.run(&mut cmd);
+    if build.config.quiet_tests {
+        try_run_quiet(build, &mut cmd);
+    } else {
+        try_run(build, &mut cmd);
+    }
 }
 
 /// Run all unit tests plus documentation tests for an entire crate DAG defined
@@ -384,6 +419,9 @@ pub fn krate(build: &Build,
         }
         _ => panic!("can only test libraries"),
     };
+    let _folder = build.fold_output(|| {
+        format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, name)
+    });
     println!("{} {} stage{} ({} -> {})", test_kind, name, compiler.stage,
              compiler.host, target);
 
@@ -406,6 +444,9 @@ pub fn krate(build: &Build,
     cargo.arg("--manifest-path")
          .arg(build.src.join(path).join("Cargo.toml"))
          .arg("--features").arg(features);
+    if test_kind.subcommand() == "test" && build.flags.cmd.no_fail_fast() {
+        cargo.arg("--no-fail-fast");
+    }
 
     match krate {
         Some(krate) => {
@@ -465,7 +506,7 @@ pub fn krate(build: &Build,
         krate_remote(build, &compiler, target, mode);
     } else {
         cargo.args(&build.flags.cmd.test_args());
-        build.run(&mut cargo);
+        try_run(build, &mut cargo);
     }
 }
 
@@ -486,7 +527,7 @@ fn krate_emscripten(build: &Build,
         if build.config.quiet_tests {
             cmd.arg("--quiet");
         }
-        build.run(&mut cmd);
+        try_run(build, &mut cmd);
     }
 }
 
@@ -508,7 +549,7 @@ fn krate_remote(build: &Build,
             cmd.arg("--quiet");
         }
         cmd.args(&build.flags.cmd.test_args());
-        build.run(&mut cmd);
+        try_run(build, &mut cmd);
     }
 }
 
@@ -624,6 +665,9 @@ pub fn bootstrap(build: &Build) {
        .current_dir(build.src.join("src/bootstrap"))
        .env("CARGO_TARGET_DIR", build.out.join("bootstrap"))
        .env("RUSTC", &build.rustc);
+    if build.flags.cmd.no_fail_fast() {
+        cmd.arg("--no-fail-fast");
+    }
     cmd.arg("--").args(&build.flags.cmd.test_args());
-    build.run(&mut cmd);
+    try_run(build, &mut cmd);
 }
index 114948f0cf278dd240cb39ebf53322812e2ea7ba..9946c93913fe7292fd502c6d2e726831a6af3e5c 100644 (file)
@@ -41,6 +41,7 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) {
     let libdir = build.sysroot_libdir(compiler, target);
     t!(fs::create_dir_all(&libdir));
 
+    let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
     println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
              compiler.host, target);
 
@@ -192,6 +193,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st
 /// the build using the `compiler` targeting the `target` architecture. The
 /// artifacts created will also be linked into the sysroot directory.
 pub fn test(build: &Build, target: &str, compiler: &Compiler) {
+    let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
     println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
              compiler.host, target);
     let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
@@ -228,6 +230,7 @@ pub fn test_link(build: &Build,
 /// the `compiler` targeting the `target` architecture. The artifacts
 /// created will also be linked into the sysroot directory.
 pub fn rustc(build: &Build, target: &str, compiler: &Compiler) {
+    let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
     println!("Building stage{} compiler artifacts ({} -> {})",
              compiler.stage, compiler.host, target);
 
@@ -435,6 +438,7 @@ pub fn maybe_clean_tools(build: &Build, stage: u32, target: &str, mode: Mode) {
 /// This will build the specified tool with the specified `host` compiler in
 /// `stage` into the normal cargo output directory.
 pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) {
+    let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
     println!("Building stage{} tool {} ({})", stage, tool, target);
 
     let compiler = Compiler::new(stage, &build.config.build);
index fe4e18ab622cde83e701d96014314189a8775849..f100baa5d2ca7181be6fc4f93847ef5a8439b97b 100644 (file)
@@ -61,6 +61,7 @@ pub enum Subcommand {
     Test {
         paths: Vec<PathBuf>,
         test_args: Vec<String>,
+        no_fail_fast: bool,
     },
     Bench {
         paths: Vec<PathBuf>,
@@ -141,7 +142,10 @@ pub fn parse(args: &[String]) -> Flags {
 
         // Some subcommands get extra options
         match subcommand.as_str() {
-            "test"  => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
+            "test"  => {
+                opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
+                opts.optmulti("", "test-args", "extra arguments", "ARGS");
+            },
             "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
             _ => { },
         };
@@ -263,6 +267,7 @@ pub fn parse(args: &[String]) -> Flags {
                 Subcommand::Test {
                     paths: paths,
                     test_args: matches.opt_strs("test-args"),
+                    no_fail_fast: matches.opt_present("no-fail-fast"),
                 }
             }
             "bench" => {
@@ -342,6 +347,13 @@ pub fn test_args(&self) -> Vec<&str> {
             _ => Vec::new(),
         }
     }
+
+    pub fn no_fail_fast(&self) -> bool {
+        match *self {
+            Subcommand::Test { no_fail_fast, .. } => no_fail_fast,
+            _ => false,
+        }
+    }
 }
 
 fn split(s: Vec<String>) -> Vec<String> {
index 665b9ee49c02d5597ed3261be23f344007c7da65..2fe6a2a3ae89fdd34eb33923581a8c03344117fa 100644 (file)
@@ -79,6 +79,7 @@
 #[cfg(unix)]
 extern crate libc;
 
+use std::cell::Cell;
 use std::cmp;
 use std::collections::HashMap;
 use std::env;
@@ -88,9 +89,9 @@
 use std::path::{PathBuf, Path};
 use std::process::Command;
 
-use build_helper::{run_silent, run_suppressed, output, mtime};
+use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime};
 
-use util::{exe, libdir, add_lib_path};
+use util::{exe, libdir, add_lib_path, OutputFolder, CiEnv};
 
 mod cc;
 mod channel;
@@ -179,6 +180,8 @@ pub struct Build {
     crates: HashMap<String, Crate>,
     is_sudo: bool,
     src_is_git: bool,
+    ci_env: CiEnv,
+    delayed_failures: Cell<usize>,
 }
 
 #[derive(Debug)]
@@ -272,6 +275,8 @@ pub fn new(flags: Flags, config: Config) -> Build {
             lldb_python_dir: None,
             is_sudo: is_sudo,
             src_is_git: src_is_git,
+            ci_env: CiEnv::current(),
+            delayed_failures: Cell::new(0),
         }
     }
 
@@ -507,6 +512,9 @@ fn cargo(&self,
         if self.config.vendor || self.is_sudo {
             cargo.arg("--frozen");
         }
+
+        self.ci_env.force_coloring_in_ci(&mut cargo);
+
         return cargo
     }
 
@@ -779,6 +787,22 @@ fn run_quiet(&self, cmd: &mut Command) {
         run_suppressed(cmd)
     }
 
+    /// Runs a command, printing out nice contextual information if it fails.
+    /// Exits if the command failed to execute at all, otherwise returns its
+    /// `status.success()`.
+    fn try_run(&self, cmd: &mut Command) -> bool {
+        self.verbose(&format!("running: {:?}", cmd));
+        try_run_silent(cmd)
+    }
+
+    /// Runs a command, printing out nice contextual information if it fails.
+    /// Exits if the command failed to execute at all, otherwise returns its
+    /// `status.success()`.
+    fn try_run_quiet(&self, cmd: &mut Command) -> bool {
+        self.verbose(&format!("running: {:?}", cmd));
+        try_run_suppressed(cmd)
+    }
+
     /// Prints a message if this build is configured in verbose mode.
     fn verbose(&self, msg: &str) {
         if self.flags.verbose() || self.config.verbose() {
@@ -1011,6 +1035,19 @@ fn unstable_features(&self) -> bool {
             "nightly" | _ => true,
         }
     }
+
+    /// Fold the output of the commands after this method into a group. The fold
+    /// ends when the returned object is dropped. Folding can only be used in
+    /// the Travis CI environment.
+    pub fn fold_output<D, F>(&self, name: F) -> Option<OutputFolder>
+        where D: Into<String>, F: FnOnce() -> D
+    {
+        if self.ci_env == CiEnv::Travis {
+            Some(OutputFolder::new(name().into()))
+        } else {
+            None
+        }
+    }
 }
 
 impl<'a> Compiler<'a> {
index 6cb1d1fc4bf05b47c14c968bd56f16e7da135faf..6b9a6347d227299e80ff193b3eb36c5aed48697f 100644 (file)
@@ -63,6 +63,7 @@ pub fn llvm(build: &Build, target: &str) {
         drop(fs::remove_dir_all(&out_dir));
     }
 
+    let _folder = build.fold_output(|| "llvm");
     println!("Building LLVM for {}", target);
     let _time = util::timeit();
     t!(fs::create_dir_all(&out_dir));
@@ -183,7 +184,7 @@ pub fn llvm(build: &Build, target: &str) {
     configure_compilers(&mut cfg);
 
     if env::var_os("SCCACHE_ERROR_LOG").is_some() {
-        cfg.env("RUST_LOG", "sccache=info");
+        cfg.env("RUST_LOG", "sccache=warn");
     }
 
     // FIXME: we don't actually need to build all LLVM tools and all LLVM
@@ -218,6 +219,7 @@ pub fn test_helpers(build: &Build, target: &str) {
         return
     }
 
+    let _folder = build.fold_output(|| "build_test_helpers");
     println!("Building test helpers");
     t!(fs::create_dir_all(&dst));
     let mut cfg = gcc::Config::new();
index 16029a8a0cccd49c68fb55bf675fd6ac6a818f2b..9e8b08a23b7e96fb0991ffa28a396d880a985529 100644 (file)
@@ -28,6 +28,7 @@
 
 use std::collections::{BTreeMap, HashSet, HashMap};
 use std::mem;
+use std::process;
 
 use check::{self, TestKind};
 use compile;
@@ -1174,8 +1175,8 @@ fn plan(&self) -> Vec<Step<'a>> {
         let (kind, paths) = match self.build.flags.cmd {
             Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
             Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
-            Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]),
-            Subcommand::Bench { ref paths, test_args: _ } => (Kind::Bench, &paths[..]),
+            Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
+            Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
             Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
             Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
             Subcommand::Clean => panic!(),
@@ -1268,6 +1269,13 @@ fn run(&self, steps: &[Step<'a>]) {
             self.build.verbose(&format!("executing step {:?}", step));
             (self.rules[step.name].run)(step);
         }
+
+        // Check for postponed failures from `test --no-fail-fast`.
+        let failures = self.build.delayed_failures.get();
+        if failures > 0 {
+            println!("\n{} command(s) did not execute successfully.\n", failures);
+            process::exit(1);
+        }
     }
 
     /// From the top level targets `steps` generate a topological ordering of
index e01c06b10fcd63097de8a14f8b5e2b0f525bccb3..61bd85e76c59882b9967746f8bbba3a76ec9382e 100644 (file)
 use std::env;
 use std::ffi::OsString;
 use std::fs;
-use std::io;
+use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 use std::process::Command;
-use std::time::Instant;
+use std::time::{SystemTime, Instant};
 
 use filetime::{self, FileTime};
 
@@ -324,3 +324,102 @@ fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
         }
     }
 }
+
+/// An RAII structure that indicates all output until this instance is dropped
+/// is part of the same group.
+///
+/// On Travis CI, these output will be folded by default, together with the
+/// elapsed time in this block. This reduces noise from unnecessary logs,
+/// allowing developers to quickly identify the error.
+///
+/// Travis CI supports folding by printing `travis_fold:start:<name>` and
+/// `travis_fold:end:<name>` around the block. Time elapsed is recognized
+/// similarly with `travis_time:[start|end]:<name>`. These are undocumented, but
+/// can easily be deduced from source code of the [Travis build commands].
+///
+/// [Travis build commands]:
+/// https://github.com/travis-ci/travis-build/blob/f603c0089/lib/travis/build/templates/header.sh
+pub struct OutputFolder {
+    name: String,
+    start_time: SystemTime, // we need SystemTime to get the UNIX timestamp.
+}
+
+impl OutputFolder {
+    /// Creates a new output folder with the given group name.
+    pub fn new(name: String) -> OutputFolder {
+        // "\r" moves the cursor to the beginning of the line, and "\x1b[0K" is
+        // the ANSI escape code to clear from the cursor to end of line.
+        // Travis seems to have trouble when _not_ using "\r\x1b[0K", that will
+        // randomly put lines to the top of the webpage.
+        print!("travis_fold:start:{0}\r\x1b[0Ktravis_time:start:{0}\r\x1b[0K", name);
+        OutputFolder {
+            name,
+            start_time: SystemTime::now(),
+        }
+    }
+}
+
+impl Drop for OutputFolder {
+    fn drop(&mut self) {
+        use std::time::*;
+        use std::u64;
+
+        fn to_nanos(duration: Result<Duration, SystemTimeError>) -> u64 {
+            match duration {
+                Ok(d) => d.as_secs() * 1_000_000_000 + d.subsec_nanos() as u64,
+                Err(_) => u64::MAX,
+            }
+        }
+
+        let end_time = SystemTime::now();
+        let duration = end_time.duration_since(self.start_time);
+        let start = self.start_time.duration_since(UNIX_EPOCH);
+        let finish = end_time.duration_since(UNIX_EPOCH);
+        println!(
+            "travis_fold:end:{0}\r\x1b[0K\n\
+                travis_time:end:{0}:start={1},finish={2},duration={3}\r\x1b[0K",
+            self.name,
+            to_nanos(start),
+            to_nanos(finish),
+            to_nanos(duration)
+        );
+        io::stdout().flush().unwrap();
+    }
+}
+
+/// The CI environment rustbuild is running in. This mainly affects how the logs
+/// are printed.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum CiEnv {
+    /// Not a CI environment.
+    None,
+    /// The Travis CI environment, for Linux (including Docker) and macOS builds.
+    Travis,
+    /// The AppVeyor environment, for Windows builds.
+    AppVeyor,
+}
+
+impl CiEnv {
+    /// Obtains the current CI environment.
+    pub fn current() -> CiEnv {
+        if env::var("TRAVIS").ok().map_or(false, |e| &*e == "true") {
+            CiEnv::Travis
+        } else if env::var("APPVEYOR").ok().map_or(false, |e| &*e == "True") {
+            CiEnv::AppVeyor
+        } else {
+            CiEnv::None
+        }
+    }
+
+    /// If in a CI environment, forces the command to run with colors.
+    pub fn force_coloring_in_ci(self, cmd: &mut Command) {
+        if self != CiEnv::None {
+            // Due to use of stamp/docker, the output stream of rustbuild is not
+            // a TTY in CI, so coloring is by-default turned off.
+            // The explicit `TERM=xterm` environment is needed for
+            // `--color always` to actually work. This env var was lost when
+            // compiling through the Makefile. Very strange.
+            cmd.env("TERM", "xterm").args(&["--color", "always"]);
+        }
+    }
+}
\ No newline at end of file
index da00b970da977e950bacdf275403c0a57e0e6ad7..ea6a822e360a49dde2ac0aedac04f7562e9a85d4 100644 (file)
@@ -42,35 +42,49 @@ pub fn run(cmd: &mut Command) {
 }
 
 pub fn run_silent(cmd: &mut Command) {
+    if !try_run_silent(cmd) {
+        std::process::exit(1);
+    }
+}
+
+pub fn try_run_silent(cmd: &mut Command) -> bool {
     let status = match cmd.status() {
         Ok(status) => status,
         Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                 cmd, e)),
     };
     if !status.success() {
-        fail(&format!("command did not execute successfully: {:?}\n\
-                       expected success, got: {}",
-                      cmd,
-                      status));
+        println!("\n\ncommand did not execute successfully: {:?}\n\
+                  expected success, got: {}\n\n",
+                 cmd,
+                 status);
     }
+    status.success()
 }
 
 pub fn run_suppressed(cmd: &mut Command) {
+    if !try_run_suppressed(cmd) {
+        std::process::exit(1);
+    }
+}
+
+pub fn try_run_suppressed(cmd: &mut Command) -> bool {
     let output = match cmd.output() {
         Ok(status) => status,
         Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                 cmd, e)),
     };
     if !output.status.success() {
-        fail(&format!("command did not execute successfully: {:?}\n\
-                       expected success, got: {}\n\n\
-                       stdout ----\n{}\n\
-                       stderr ----\n{}\n",
-                      cmd,
-                      output.status,
-                      String::from_utf8_lossy(&output.stdout),
-                      String::from_utf8_lossy(&output.stderr)));
+        println!("\n\ncommand did not execute successfully: {:?}\n\
+                  expected success, got: {}\n\n\
+                  stdout ----\n{}\n\
+                  stderr ----\n{}\n\n",
+                 cmd,
+                 output.status,
+                 String::from_utf8_lossy(&output.stdout),
+                 String::from_utf8_lossy(&output.stderr));
     }
+    output.status.success()
 }
 
 pub fn gnu_target(target: &str) -> String {
index bb9a860574dd2f175245cd6e8e97fc911d8787c7..4f34a7214cbc6763c6ac308b95fb7865378dd8c0 100755 (executable)
@@ -21,6 +21,9 @@ root_dir="`dirname $src_dir`"
 
 source "$ci_dir/shared.sh"
 
+travis_fold start build_docker
+travis_time_start
+
 if [ -f "$docker_dir/$image/Dockerfile" ]; then
     retry docker \
       build \
@@ -44,6 +47,9 @@ else
     exit 1
 fi
 
+travis_fold end build_docker
+travis_time_finish
+
 objdir=$root_dir/obj
 
 mkdir -p $HOME/.cargo
@@ -72,6 +78,8 @@ exec docker \
   --env DEPLOY=$DEPLOY \
   --env DEPLOY_ALT=$DEPLOY_ALT \
   --env LOCAL_USER_ID=`id -u` \
+  --env TRAVIS=${TRAVIS-false} \
+  --env TRAVIS_BRANCH \
   --volume "$HOME/.cargo:/cargo" \
   --volume "$HOME/rustsrc:$HOME/rustsrc" \
   --privileged \
index 0a17bd3b5710f6430a2817704b7bbfdc51f95dfd..282da009eac35c3f3e29c88b1e4e70c7c2ae1214 100755 (executable)
@@ -13,11 +13,11 @@ set -o errexit
 set -o pipefail
 set -o nounset
 
-set -o xtrace
-
 ci_dir=$(cd $(dirname $0) && pwd)
 . "$ci_dir/shared.sh"
 
+travis_fold start init_repo
+
 REPO_DIR="$1"
 CACHE_DIR="$2"
 
@@ -38,6 +38,7 @@ fi
 
 # Wipe the cache if it's not valid, or mark it as invalid while we update it
 if [ ! -f "$cache_valid_file" ]; then
+    echo "Invalid cache, wiping ($cache_valid_file missing)"
     rm -rf "$CACHE_DIR"
     mkdir "$CACHE_DIR"
 else
@@ -54,10 +55,14 @@ else
         rm -rf "$CACHE_DIR"
         mkdir "$CACHE_DIR"
     else
+        echo "Valid cache ($cache_valid_file exists)"
         rm "$cache_valid_file"
     fi
 fi
 
+travis_fold start update_cache
+travis_time_start
+
 # Update the cache (a pristine copy of the rust source master)
 if [ ! -d "$cache_src_dir/.git" ]; then
     retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \
@@ -69,8 +74,15 @@ retry sh -c "cd $cache_src_dir && \
     git submodule deinit -f . && git submodule sync && git submodule update --init"
 
 # Cache was updated without errors, mark it as valid
+echo "Refreshed cache (touch $cache_valid_file)"
 touch "$cache_valid_file"
 
+travis_fold end update_cache
+travis_time_finish
+
+travis_fold start update_submodules
+travis_time_start
+
 # Update the submodules of the repo we're in, using the pristine repo as
 # a cache for any object files
 # No, `git submodule foreach` won't work:
@@ -94,3 +106,8 @@ for module in $modules; do
     retry sh -c "git submodule deinit -f $module && \
         git submodule update --init --reference $cache_src_dir/$module $module"
 done
+
+travis_fold end update_submodules
+travis_time_finish
+
+travis_fold end init_repo
index c6510120b47ae7ec3fb500d71df5db6ba5dc52ff..549e804603c07b90f14bc223d3605e64559c1c45 100755 (executable)
@@ -23,6 +23,10 @@ fi
 ci_dir=`cd $(dirname $0) && pwd`
 source "$ci_dir/shared.sh"
 
+if [ "$TRAVIS" == "true" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then
+    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests"
+fi
+
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps"
@@ -58,8 +62,17 @@ else
   fi
 fi
 
+travis_fold start configure
+travis_time_start
 $SRC/configure $RUST_CONFIGURE_ARGS
+travis_fold end configure
+travis_time_finish
+
+travis_fold start make-prepare
+travis_time_start
 retry make prepare
+travis_fold end make-prepare
+travis_time_finish
 
 if [ "$TRAVIS_OS_NAME" = "osx" ]; then
     ncpus=$(sysctl -n hw.ncpu)
@@ -67,12 +80,21 @@ else
     ncpus=$(grep processor /proc/cpuinfo | wc -l)
 fi
 
-set -x
-
 if [ ! -z "$SCRIPT" ]; then
   sh -x -c "$SCRIPT"
 else
-  make -j $ncpus tidy
-  make -j $ncpus
-  make $RUST_CHECK_TARGET -j $ncpus
+  do_make() {
+    travis_fold start "make-$1"
+    travis_time_start
+    echo "make -j $ncpus $1"
+    make -j $ncpus "$1"
+    local retval=$?
+    travis_fold end "make-$1"
+    travis_time_finish
+    return $retval
+  }
+
+  do_make tidy
+  do_make all
+  do_make "$RUST_CHECK_TARGET"
 fi
index f2e13fc73ae4778930fcd635a8c85f21a9e91d7a..4a08683e3ee86511f505d16a88f00b39d3a2fe5d 100644 (file)
@@ -30,3 +30,37 @@ function retry {
     }
   done
 }
+
+if ! declare -F travis_fold; then
+  if [ "${TRAVIS-false}" = 'true' ]; then
+    # This is a trimmed down copy of
+    # https://github.com/travis-ci/travis-build/blob/master/lib/travis/build/templates/header.sh
+    travis_fold() {
+      echo -en "travis_fold:$1:$2\r\033[0K"
+    }
+    travis_time_start() {
+      travis_timer_id=$(printf %08x $(( RANDOM * RANDOM )))
+      travis_start_time=$(travis_nanoseconds)
+      echo -en "travis_time:start:$travis_timer_id\r\033[0K"
+    }
+    travis_time_finish() {
+      travis_end_time=$(travis_nanoseconds)
+      local duration=$(($travis_end_time-$travis_start_time))
+      local msg="travis_time:end:$travis_timer_id"
+      echo -en "\n$msg:start=$travis_start_time,finish=$travis_end_time,duration=$duration\r\033[0K"
+    }
+    if [ $(uname) = 'Darwin' ]; then
+      travis_nanoseconds() {
+        date -u '+%s000000000'
+      }
+    else
+      travis_nanoseconds() {
+        date -u '+%s%N'
+      }
+    fi
+  else
+    travis_fold() { return 0; }
+    travis_time_start() { return 0; }
+    travis_time_finish() { return 0; }
+  fi
+fi
index 97422981c53a00f7c3d6584d363443117f179fff..f746084b099060f55ac5e7d8050797593fcedd6e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 97422981c53a00f7c3d6584d363443117f179fff
+Subproject commit f746084b099060f55ac5e7d8050797593fcedd6e
index 6fa139b1630a9bb95dcd60cfc90aff9c19e54580..c0e8c56d76bdf6bd16c64338f81c04d48c60f117 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 6fa139b1630a9bb95dcd60cfc90aff9c19e54580
+Subproject commit c0e8c56d76bdf6bd16c64338f81c04d48c60f117
index f7a108dfa9e90b07821700c55d01f08a9adf005c..876582e9d0fbdc9cecb03133c28db96e9ff8c844 160000 (submodule)
@@ -1 +1 @@
-Subproject commit f7a108dfa9e90b07821700c55d01f08a9adf005c
+Subproject commit 876582e9d0fbdc9cecb03133c28db96e9ff8c844
index 28bbcf734f8173de25288f84048483e1c41df57c..2b3ef338fad5860605a9b04b64a9e607e242136b 100644 (file)
     - [sip_hash_13](library-features/sip-hash-13.md)
     - [slice_concat_ext](library-features/slice-concat-ext.md)
     - [slice_get_slice](library-features/slice-get-slice.md)
+    - [slice_rotate](library-features/slice-rotate.md)
     - [slice_rsplit](library-features/slice-rsplit.md)
     - [sort_internals](library-features/sort-internals.md)
     - [sort_unstable](library-features/sort-unstable.md)
diff --git a/src/doc/unstable-book/src/library-features/slice-rotate.md b/src/doc/unstable-book/src/library-features/slice-rotate.md
new file mode 100644 (file)
index 0000000..77fd598
--- /dev/null
@@ -0,0 +1,7 @@
+# `slice_rotate`
+
+The tracking issue for this feature is: [#41891]
+
+[#41891]: https://github.com/rust-lang/rust/issues/41891
+
+------------------------
index 01393be9949ae2f9cdc5a2c7b4e5a8b3e6a1a3cb..49e5baad74dda4322d93ee395ba63a3999fa3f00 100644 (file)
@@ -17,7 +17,7 @@ libc = { path = "../rustc/libc_shim" }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
 
 [features]
 debug = []
index 6d47c2ff28fbf77ad565d1eeea92c622f03dd9f4..1f36bc4fbcea73043049bdfb013378c22b3041b6 100644 (file)
@@ -171,6 +171,8 @@ pub fn usable_size(size: usize, _align: usize) -> usize {
 #[cfg(windows)]
 #[allow(bad_style)]
 mod imp {
+    use core::cmp::min;
+    use core::ptr::copy_nonoverlapping;
     use MIN_ALIGN;
 
     type LPVOID = *mut u8;
@@ -225,19 +227,16 @@ pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
         allocate_with_flags(size, align, HEAP_ZERO_MEMORY)
     }
 
-    pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
+    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
         if align <= MIN_ALIGN {
             HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
         } else {
-            let header = get_header(ptr);
-            let new = HeapReAlloc(GetProcessHeap(),
-                                  0,
-                                  header.0 as LPVOID,
-                                  (size + align) as SIZE_T) as *mut u8;
-            if new.is_null() {
-                return new;
+            let new = allocate(size, align);
+            if !new.is_null() {
+                copy_nonoverlapping(ptr, new, min(size, old_size));
+                deallocate(ptr, old_size, align);
             }
-            align_ptr(new, align)
+            new
         }
     }
 
@@ -246,15 +245,19 @@ pub unsafe fn reallocate_inplace(ptr: *mut u8,
                                      size: usize,
                                      align: usize)
                                      -> usize {
-        if align <= MIN_ALIGN {
-            let new = HeapReAlloc(GetProcessHeap(),
-                                  HEAP_REALLOC_IN_PLACE_ONLY,
-                                  ptr as LPVOID,
-                                  size as SIZE_T) as *mut u8;
-            if new.is_null() { old_size } else { size }
+        let new = if align <= MIN_ALIGN {
+            HeapReAlloc(GetProcessHeap(),
+                        HEAP_REALLOC_IN_PLACE_ONLY,
+                        ptr as LPVOID,
+                        size as SIZE_T) as *mut u8
         } else {
-            old_size
-        }
+            let header = get_header(ptr);
+            HeapReAlloc(GetProcessHeap(),
+                        HEAP_REALLOC_IN_PLACE_ONLY,
+                        header.0 as LPVOID,
+                        size + align as SIZE_T) as *mut u8
+        };
+        if new.is_null() { old_size } else { size }
     }
 
     pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
index 9f356e4b57912af410b56fcb4f4b7903a4c27c88..958020d0b0e0c33e3b70b803f187fc204c0f84bb 100644 (file)
@@ -13,6 +13,7 @@
 #![feature(i128_type)]
 #![feature(rand)]
 #![feature(repr_simd)]
+#![feature(slice_rotate)]
 #![feature(sort_unstable)]
 #![feature(test)]
 
index 0079f2d01036cf76d5fa956a75ce7acdb0ec127f..aa5a438b35e62341e5611755f233b1b12c7c830e 100644 (file)
@@ -195,6 +195,11 @@ fn gen_random(len: usize) -> Vec<u64> {
     rng.gen_iter::<u64>().take(len).collect()
 }
 
+fn gen_random_bytes(len: usize) -> Vec<u8> {
+    let mut rng = thread_rng();
+    rng.gen_iter::<u8>().take(len).collect()
+}
+
 fn gen_mostly_ascending(len: usize) -> Vec<u64> {
     let mut rng = thread_rng();
     let mut v = gen_ascending(len);
@@ -315,3 +320,39 @@ fn $name(b: &mut Bencher) {
 reverse!(reverse_u128, u128, |x| x as u128);
 #[repr(simd)] struct F64x4(f64, f64, f64, f64);
 reverse!(reverse_simd_f64x4, F64x4, |x| { let x = x as f64; F64x4(x,x,x,x) });
+
+macro_rules! rotate {
+    ($name:ident, $gen:expr, $len:expr, $mid:expr) => {
+        #[bench]
+        fn $name(b: &mut Bencher) {
+            let size = mem::size_of_val(&$gen(1)[0]);
+            let mut v = $gen($len * 8 / size);
+            b.iter(|| black_box(&mut v).rotate(($mid*8+size-1)/size));
+            b.bytes = (v.len() * size) as u64;
+        }
+    }
+}
+
+rotate!(rotate_tiny_by1, gen_random, 16, 1);
+rotate!(rotate_tiny_half, gen_random, 16, 16/2);
+rotate!(rotate_tiny_half_plus_one, gen_random, 16, 16/2+1);
+
+rotate!(rotate_medium_by1, gen_random, 9158, 1);
+rotate!(rotate_medium_by727_u64, gen_random, 9158, 727);
+rotate!(rotate_medium_by727_bytes, gen_random_bytes, 9158, 727);
+rotate!(rotate_medium_by727_strings, gen_strings, 9158, 727);
+rotate!(rotate_medium_half, gen_random, 9158, 9158/2);
+rotate!(rotate_medium_half_plus_one, gen_random, 9158, 9158/2+1);
+
+// Intended to use more RAM than the machine has cache
+rotate!(rotate_huge_by1, gen_random, 5*1024*1024, 1);
+rotate!(rotate_huge_by9199_u64, gen_random, 5*1024*1024, 9199);
+rotate!(rotate_huge_by9199_bytes, gen_random_bytes, 5*1024*1024, 9199);
+rotate!(rotate_huge_by9199_strings, gen_strings, 5*1024*1024, 9199);
+rotate!(rotate_huge_by9199_big, gen_big_random, 5*1024*1024, 9199);
+rotate!(rotate_huge_by1234577_u64, gen_random, 5*1024*1024, 1234577);
+rotate!(rotate_huge_by1234577_bytes, gen_random_bytes, 5*1024*1024, 1234577);
+rotate!(rotate_huge_by1234577_strings, gen_strings, 5*1024*1024, 1234577);
+rotate!(rotate_huge_by1234577_big, gen_big_random, 5*1024*1024, 1234577);
+rotate!(rotate_huge_half, gen_random, 5*1024*1024, 5*1024*1024/2);
+rotate!(rotate_huge_half_plus_one, gen_random, 5*1024*1024, 5*1024*1024/2+1);
index 0de52b6696fcf02febb16085c5eb2860edbb52c1..a662e4b1f4f931de28292c8ed094f559e4d0b031 100644 (file)
@@ -191,13 +191,16 @@ impl<'a, B: ?Sized> Cow<'a, B>
     /// # Examples
     ///
     /// ```
+    /// use std::ascii::AsciiExt;
     /// use std::borrow::Cow;
     ///
-    /// let mut cow: Cow<[_]> = Cow::Owned(vec![1, 2, 3]);
+    /// let mut cow = Cow::Borrowed("foo");
+    /// cow.to_mut().make_ascii_uppercase();
     ///
-    /// let hello = cow.to_mut();
-    ///
-    /// assert_eq!(hello, &[1, 2, 3]);
+    /// assert_eq!(
+    ///   cow,
+    ///   Cow::Owned(String::from("FOO")) as Cow<str>
+    /// );
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
@@ -219,14 +222,33 @@ pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
     ///
     /// # Examples
     ///
+    /// Calling `into_owned` on a `Cow::Borrowed` clones the underlying data
+    /// and becomes a `Cow::Owned`:
+    ///
     /// ```
     /// use std::borrow::Cow;
     ///
-    /// let cow: Cow<[_]> = Cow::Owned(vec![1, 2, 3]);
+    /// let s = "Hello world!";
+    /// let cow = Cow::Borrowed(s);
+    ///
+    /// assert_eq!(
+    ///   cow.into_owned(),
+    ///   Cow::Owned(String::from(s))
+    /// );
+    /// ```
+    ///
+    /// Calling `into_owned` on a `Cow::Owned` is a no-op:
+    ///
+    /// ```
+    /// use std::borrow::Cow;
     ///
-    /// let hello = cow.into_owned();
+    /// let s = "Hello world!";
+    /// let cow: Cow<str> = Cow::Owned(String::from(s));
     ///
-    /// assert_eq!(vec![1, 2, 3], hello);
+    /// assert_eq!(
+    ///   cow.into_owned(),
+    ///   Cow::Owned(String::from(s))
+    /// );
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_owned(self) -> <B as ToOwned>::Owned {
index 72ff6575ca13725bc230059c04b0a6645119ae9e..34626326c221ce533c452920960f12f1604dec5d 100644 (file)
@@ -55,6 +55,7 @@
 #![feature(shared)]
 #![feature(slice_get_slice)]
 #![feature(slice_patterns)]
+#![cfg_attr(not(test), feature(slice_rotate))]
 #![feature(slice_rsplit)]
 #![cfg_attr(not(test), feature(sort_unstable))]
 #![feature(specialization)]
index 233ff8a51545dd12b9ca826f14c1806634d71259..97d6687c79b5749aaa3d69e5d0d64a373cb0f133 100644 (file)
@@ -1347,6 +1347,61 @@ pub fn sort_unstable_by_key<B, F>(&mut self, f: F)
         core_slice::SliceExt::sort_unstable_by_key(self, f);
     }
 
+    /// Permutes the slice in-place such that `self[mid..]` moves to the
+    /// beginning of the slice while `self[..mid]` moves to the end of the
+    /// slice.  Equivalently, rotates the slice `mid` places to the left
+    /// or `k = self.len() - mid` places to the right.
+    ///
+    /// This is a "k-rotation", a permutation in which item `i` moves to
+    /// position `i + k`, modulo the length of the slice.  See _Elements
+    /// of Programming_ [§10.4][eop].
+    ///
+    /// Rotation by `mid` and rotation by `k` are inverse operations.
+    ///
+    /// [eop]: https://books.google.com/books?id=CO9ULZGINlsC&pg=PA178&q=k-rotation
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if `mid` is greater than the length of the
+    /// slice.  (Note that `mid == self.len()` does _not_ panic; it's a nop
+    /// rotation with `k == 0`, the inverse of a rotation with `mid == 0`.)
+    ///
+    /// # Complexity
+    ///
+    /// Takes linear (in `self.len()`) time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_rotate)]
+    ///
+    /// let mut a = [1, 2, 3, 4, 5, 6, 7];
+    /// let mid = 2;
+    /// a.rotate(mid);
+    /// assert_eq!(&a, &[3, 4, 5, 6, 7, 1, 2]);
+    /// let k = a.len() - mid;
+    /// a.rotate(k);
+    /// assert_eq!(&a, &[1, 2, 3, 4, 5, 6, 7]);
+    ///
+    /// use std::ops::Range;
+    /// fn slide<T>(slice: &mut [T], range: Range<usize>, to: usize) {
+    ///     if to < range.start {
+    ///         slice[to..range.end].rotate(range.start-to);
+    ///     } else if to > range.end {
+    ///         slice[range.start..to].rotate(range.end-range.start);
+    ///     }
+    /// }
+    /// let mut v: Vec<_> = (0..10).collect();
+    /// slide(&mut v, 1..4, 7);
+    /// assert_eq!(&v, &[0, 4, 5, 6, 1, 2, 3, 7, 8, 9]);
+    /// slide(&mut v, 6..8, 1);
+    /// assert_eq!(&v, &[0, 3, 7, 4, 5, 6, 1, 2, 8, 9]);
+    /// ```
+    #[unstable(feature = "slice_rotate", issue = "41891")]
+    pub fn rotate(&mut self, mid: usize) {
+        core_slice::SliceExt::rotate(self, mid);
+    }
+
     /// Copies the elements from `src` into `self`.
     ///
     /// The length of `src` must be the same as `self`.
@@ -1460,6 +1515,7 @@ pub trait SliceConcatExt<T: ?Sized> {
     ///
     /// ```
     /// assert_eq!(["hello", "world"].concat(), "helloworld");
+    /// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn concat(&self) -> Self::Output;
@@ -1471,6 +1527,7 @@ pub trait SliceConcatExt<T: ?Sized> {
     ///
     /// ```
     /// assert_eq!(["hello", "world"].join(" "), "hello world");
+    /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
     /// ```
     #[stable(feature = "rename_connect_to_join", since = "1.3.0")]
     fn join(&self, sep: &T) -> Self::Output;
index af18cddaddb013050ce91c6c98e32e06c6ba2ebe..06d585f8ea82f699e64a181921554f237083ff21 100644 (file)
@@ -134,22 +134,22 @@ fn test_push() {
 fn test_push_unique() {
     let mut heap = BinaryHeap::<Box<_>>::from(vec![box 2, box 4, box 9]);
     assert_eq!(heap.len(), 3);
-    assert!(*heap.peek().unwrap() == box 9);
+    assert!(**heap.peek().unwrap() == 9);
     heap.push(box 11);
     assert_eq!(heap.len(), 4);
-    assert!(*heap.peek().unwrap() == box 11);
+    assert!(**heap.peek().unwrap() == 11);
     heap.push(box 5);
     assert_eq!(heap.len(), 5);
-    assert!(*heap.peek().unwrap() == box 11);
+    assert!(**heap.peek().unwrap() == 11);
     heap.push(box 27);
     assert_eq!(heap.len(), 6);
-    assert!(*heap.peek().unwrap() == box 27);
+    assert!(**heap.peek().unwrap() == 27);
     heap.push(box 3);
     assert_eq!(heap.len(), 7);
-    assert!(*heap.peek().unwrap() == box 27);
+    assert!(**heap.peek().unwrap() == 27);
     heap.push(box 103);
     assert_eq!(heap.len(), 8);
-    assert!(*heap.peek().unwrap() == box 103);
+    assert!(**heap.peek().unwrap() == 103);
 }
 
 fn check_to_vec(mut data: Vec<i32>) {
index cda8c6d59987efc42e652802aaa7f82e1f9ceee7..5f5217b73c2596ee2ff6de6e23c643cab30be58f 100644 (file)
 
 #![deny(warnings)]
 
+#![feature(attr_literals)]
 #![feature(box_syntax)]
 #![feature(inclusive_range_syntax)]
 #![feature(collection_placement)]
 #![feature(collections)]
 #![feature(const_fn)]
 #![feature(exact_size_is_empty)]
+#![feature(iterator_step_by)]
 #![feature(pattern)]
 #![feature(placement_in_syntax)]
 #![feature(rand)]
+#![feature(repr_align)]
+#![feature(slice_rotate)]
 #![feature(splice)]
-#![feature(step_by)]
 #![feature(str_escape)]
 #![feature(test)]
 #![feature(unboxed_closures)]
index 1708f98b7ee47c2ab40ff0807fec183e09de2eea..7fa65a2144e9b47d1f3f093c04fa980bc6bf5596 100644 (file)
@@ -466,6 +466,41 @@ fn test_sort_stability() {
     }
 }
 
+#[test]
+fn test_rotate() {
+    let expected: Vec<_> = (0..13).collect();
+    let mut v = Vec::new();
+
+    // no-ops
+    v.clone_from(&expected);
+    v.rotate(0);
+    assert_eq!(v, expected);
+    v.rotate(expected.len());
+    assert_eq!(v, expected);
+    let mut zst_array = [(), (), ()];
+    zst_array.rotate(2);
+
+    // happy path
+    v = (5..13).chain(0..5).collect();
+    v.rotate(8);
+    assert_eq!(v, expected);
+
+    let expected: Vec<_> = (0..1000).collect();
+
+    // small rotations in large slice, uses ptr::copy
+    v = (2..1000).chain(0..2).collect();
+    v.rotate(998);
+    assert_eq!(v, expected);
+    v = (998..1000).chain(0..998).collect();
+    v.rotate(2);
+    assert_eq!(v, expected);
+
+    // non-small prime rotation, has a few rounds of swapping
+    v = (389..1000).chain(0..389).collect();
+    v.rotate(1000-389);
+    assert_eq!(v, expected);
+}
+
 #[test]
 fn test_concat() {
     let v: [Vec<i32>; 0] = [];
index 29f18274962fe04e6c3a517370c401d610f711ca..fdf453b39cf5d9144c21cf9c4091af7c41c44312 100644 (file)
@@ -781,3 +781,18 @@ fn from_into_inner() {
     assert_eq!(vec, [2, 3]);
     assert!(ptr != vec.as_ptr());
 }
+
+#[test]
+fn overaligned_allocations() {
+    #[repr(align(256))]
+    struct Foo(usize);
+    let mut v = vec![Foo(273)];
+    for i in 0..0x1000 {
+        v.reserve_exact(i);
+        assert!(v[0].0 == 273);
+        assert!(v.as_ptr() as usize & 0xff == 0);
+        v.shrink_to_fit();
+        assert!(v[0].0 == 273);
+        assert!(v.as_ptr() as usize & 0xff == 0);
+    }
+}
index f2935c05d4f7a90ac3112b0481fdac7057562652..a992351653d7b996e2f2100c57f5c8c1c4ee82a1 100644 (file)
@@ -510,7 +510,8 @@ fn test_from_iter() {
     let u: Vec<_> = deq.iter().cloned().collect();
     assert_eq!(u, v);
 
-    let seq = (0..).step_by(2).take(256);
+    // FIXME #27741: Remove `.skip(0)` when Range::step_by is fully removed
+    let seq = (0..).skip(0).step_by(2).take(256);
     let deq: VecDeque<_> = seq.collect();
     for (i, &x) in deq.iter().enumerate() {
         assert_eq!(2 * i, x);
index 3f844b3f09e3a28648d4c3b76b30e3a9cb1f3c59..2c9cee5e7a0937cf3644a712095f375b212fa8dd 100644 (file)
@@ -16,4 +16,4 @@ core = { path = "../libcore" }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
index 9f1870e56d38af2d504c0fbfc64913163078a58a..3566bbdebc2b6b1a2b2d31d18fed33827cb00936 100644 (file)
     pub fn atomic_umax_rel<T>(dst: *mut T, src: T) -> T;
     pub fn atomic_umax_acqrel<T>(dst: *mut T, src: T) -> T;
     pub fn atomic_umax_relaxed<T>(dst: *mut T, src: T) -> T;
+
+    /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
+    /// if supported; otherwise, it is a noop.
+    /// Prefetches have no effect on the behavior of the program but can change its performance
+    /// characteristics.
+    ///
+    /// The `locality` argument must be a constant integer and is a temporal locality specifier
+    /// ranging from (0) - no locality, to (3) - extremely local keep in cache
+    #[cfg(not(stage0))]
+    pub fn prefetch_read_data<T>(data: *const T, locality: i32);
+    /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
+    /// if supported; otherwise, it is a noop.
+    /// Prefetches have no effect on the behavior of the program but can change its performance
+    /// characteristics.
+    ///
+    /// The `locality` argument must be a constant integer and is a temporal locality specifier
+    /// ranging from (0) - no locality, to (3) - extremely local keep in cache
+    #[cfg(not(stage0))]
+    pub fn prefetch_write_data<T>(data: *const T, locality: i32);
+    /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
+    /// if supported; otherwise, it is a noop.
+    /// Prefetches have no effect on the behavior of the program but can change its performance
+    /// characteristics.
+    ///
+    /// The `locality` argument must be a constant integer and is a temporal locality specifier
+    /// ranging from (0) - no locality, to (3) - extremely local keep in cache
+    #[cfg(not(stage0))]
+    pub fn prefetch_read_instruction<T>(data: *const T, locality: i32);
+    /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
+    /// if supported; otherwise, it is a noop.
+    /// Prefetches have no effect on the behavior of the program but can change its performance
+    /// characteristics.
+    ///
+    /// The `locality` argument must be a constant integer and is a temporal locality specifier
+    /// ranging from (0) - no locality, to (3) - extremely local keep in cache
+    #[cfg(not(stage0))]
+    pub fn prefetch_write_instruction<T>(data: *const T, locality: i32);
 }
 
+// Empty bootstrap implementations for stage0 compilation
+#[cfg(stage0)]
+pub fn prefetch_read_data<T>(_data: *const T, _locality: i32) { /* EMPTY */ }
+#[cfg(stage0)]
+pub fn prefetch_write_data<T>(_data: *const T, _locality: i32) { /* EMPTY */ }
+#[cfg(stage0)]
+pub fn prefetch_read_instruction<T>(_data: *const T, _locality: i32) { /* EMPTY */ }
+#[cfg(stage0)]
+pub fn prefetch_write_instruction<T>(_data: *const T, _locality: i32) { /* EMPTY */ }
+
 extern "rust-intrinsic" {
 
     pub fn atomic_fence();
index 07aed65f7a05709b9725529e27b977c1b91e3aef..ee81151348772e2456e597b7bacb918904d28648 100644 (file)
 //! {
 //!     let result = match IntoIterator::into_iter(values) {
 //!         mut iter => loop {
-//!             match iter.next() {
-//!                 Some(x) => { println!("{}", x); },
+//!             let x = match iter.next() {
+//!                 Some(val) => val,
 //!                 None => break,
-//!             }
+//!             };
+//!             let () = { println!("{}", x); };
 //!         },
 //!     };
 //!     result
 pub use self::range::Step;
 #[unstable(feature = "step_by", reason = "recent addition",
            issue = "27741")]
+#[rustc_deprecated(since = "1.19.0",
+                   reason = "replaced by `iter::StepBy`")]
+#[allow(deprecated)]
 pub use self::range::StepBy as DeprecatedStepBy;
 
 #[stable(feature = "rust1", since = "1.0.0")]
index c0313333ea9ee41d604afcbc133968fc6606e3b6..9aea4477fb7fc604027231739c7045074b1aebeb 100644 (file)
@@ -252,6 +252,9 @@ fn steps_between_by_one(start: &Self, end: &Self) -> Option<usize> {
 #[derive(Clone, Debug)]
 #[unstable(feature = "step_by", reason = "recent addition",
            issue = "27741")]
+#[rustc_deprecated(since = "1.19.0",
+                   reason = "replaced by `iter::StepBy`")]
+#[allow(deprecated)]
 pub struct StepBy<A, R> {
     step_by: A,
     range: R,
@@ -272,6 +275,9 @@ impl<A: Step> ops::RangeFrom<A> {
     /// ```
     #[unstable(feature = "step_by", reason = "recent addition",
                issue = "27741")]
+    #[rustc_deprecated(since = "1.19.0",
+                       reason = "replaced by `Iterator::step_by`")]
+    #[allow(deprecated)]
     pub fn step_by(self, by: A) -> StepBy<A, Self> {
         StepBy {
             step_by: by,
@@ -297,6 +303,9 @@ impl<A: Step> ops::Range<A> {
     /// ```
     #[unstable(feature = "step_by", reason = "recent addition",
                issue = "27741")]
+    #[rustc_deprecated(since = "1.19.0",
+                       reason = "replaced by `Iterator::step_by`")]
+    #[allow(deprecated)]
     pub fn step_by(self, by: A) -> StepBy<A, Self> {
         StepBy {
             step_by: by,
@@ -321,6 +330,9 @@ impl<A: Step> ops::RangeInclusive<A> {
     /// ```
     #[unstable(feature = "step_by", reason = "recent addition",
                issue = "27741")]
+    #[rustc_deprecated(since = "1.19.0",
+                       reason = "replaced by `Iterator::step_by`")]
+    #[allow(deprecated)]
     pub fn step_by(self, by: A) -> StepBy<A, Self> {
         StepBy {
             step_by: by,
@@ -331,6 +343,7 @@ pub fn step_by(self, by: A) -> StepBy<A, Self> {
 
 #[unstable(feature = "step_by", reason = "recent addition",
            issue = "27741")]
+#[allow(deprecated)]
 impl<A> Iterator for StepBy<A, ops::RangeFrom<A>> where
     A: Clone,
     for<'a> &'a A: Add<&'a A, Output = A>
@@ -351,11 +364,13 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 }
 
 #[unstable(feature = "fused", issue = "35602")]
+#[allow(deprecated)]
 impl<A> FusedIterator for StepBy<A, ops::RangeFrom<A>>
     where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> {}
 
 #[unstable(feature = "step_by", reason = "recent addition",
            issue = "27741")]
+#[allow(deprecated)]
 impl<A: Step + Clone> Iterator for StepBy<A, ops::Range<A>> {
     type Item = A;
 
@@ -393,11 +408,13 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 }
 
 #[unstable(feature = "fused", issue = "35602")]
+#[allow(deprecated)]
 impl<A: Step + Clone> FusedIterator for StepBy<A, ops::Range<A>> {}
 
 #[unstable(feature = "inclusive_range",
            reason = "recently added, follows RFC",
            issue = "28237")]
+#[allow(deprecated)]
 impl<A: Step + Clone> Iterator for StepBy<A, ops::RangeInclusive<A>> {
     type Item = A;
 
@@ -437,6 +454,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 }
 
 #[unstable(feature = "fused", issue = "35602")]
+#[allow(deprecated)]
 impl<A: Step + Clone> FusedIterator for StepBy<A, ops::RangeInclusive<A>> {}
 
 macro_rules! range_exact_iter_impl {
index cef3682fd94d74859a69f0207b2796555520154a..b13e19c0306947e2c893d77adc066d838dc83950 100644 (file)
@@ -51,6 +51,7 @@
 use marker::{Copy, Send, Sync, Sized, self};
 use iter_private::TrustedRandomAccess;
 
+mod rotate;
 mod sort;
 
 #[repr(C)]
@@ -202,6 +203,9 @@ unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
     #[stable(feature = "core", since = "1.6.0")]
     fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
 
+    #[unstable(feature = "slice_rotate", issue = "41891")]
+    fn rotate(&mut self, mid: usize);
+
     #[stable(feature = "clone_from_slice", since = "1.7.0")]
     fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone;
 
@@ -635,6 +639,16 @@ fn binary_search<Q: ?Sized>(&self, x: &Q) -> Result<usize, usize>
         self.binary_search_by(|p| p.borrow().cmp(x))
     }
 
+    fn rotate(&mut self, mid: usize) {
+        assert!(mid <= self.len());
+        let k = self.len() - mid;
+
+        unsafe {
+            let p = self.as_mut_ptr();
+            rotate::ptr_rotate(mid, p.offset(mid as isize), k);
+        }
+    }
+
     #[inline]
     fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
         assert!(self.len() == src.len(),
diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs
new file mode 100644 (file)
index 0000000..3b9ae56
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cmp;
+use mem;
+use ptr;
+
+/// Rotation is much faster if it has access to a little bit of memory. This
+/// union provides a RawVec-like interface, but to a fixed-size stack buffer.
+#[allow(unions_with_drop_fields)]
+union RawArray<T> {
+    /// Ensure this is appropriately aligned for T, and is big
+    /// enough for two elements even if T is enormous.
+    typed: [T; 2],
+    /// For normally-sized types, especially things like u8, having more
+    /// than 2 in the buffer is necessary for usefulness, so pad it out
+    /// enough to be helpful, but not so big as to risk overflow.
+    _extra: [usize; 32],
+}
+
+impl<T> RawArray<T> {
+    fn new() -> Self {
+        unsafe { mem::uninitialized() }
+    }
+    fn ptr(&self) -> *mut T {
+        unsafe { &self.typed as *const T as *mut T }
+    }
+    fn cap() -> usize {
+        if mem::size_of::<T>() == 0 {
+            usize::max_value()
+        } else {
+            mem::size_of::<Self>() / mem::size_of::<T>()
+        }
+    }
+}
+
+/// Rotates the range `[mid-left, mid+right)` such that the element at `mid`
+/// becomes the first element.  Equivalently, rotates the range `left`
+/// elements to the left or `right` elements to the right.
+///
+/// # Safety
+///
+/// The specified range must be valid for reading and writing.
+/// The type `T` must have non-zero size.
+///
+/// # Algorithm
+///
+/// For longer rotations, swap the left-most `delta = min(left, right)`
+/// elements with the right-most `delta` elements.  LLVM vectorizes this,
+/// which is profitable as we only reach this step for a "large enough"
+/// rotation.  Doing this puts `delta` elements on the larger side into the
+/// correct position, leaving a smaller rotate problem.  Demonstration:
+///
+/// ```text
+/// [ 6 7 8 9 10 11 12 13 . 1 2 3 4 5 ]
+/// 1 2 3 4 5 [ 11 12 13 . 6 7 8 9 10 ]
+/// 1 2 3 4 5 [ 8 9 10 . 6 7 ] 11 12 13
+/// 1 2 3 4 5 6 7 [ 10 . 8 9 ] 11 12 13
+/// 1 2 3 4 5 6 7 [ 9 . 8 ] 10 11 12 13
+/// 1 2 3 4 5 6 7 8 [ . ] 9 10 11 12 13
+/// ```
+///
+/// Once the rotation is small enough, copy some elements into a stack
+/// buffer, `memmove` the others, and move the ones back from the buffer.
+pub unsafe fn ptr_rotate<T>(mut left: usize, mid: *mut T, mut right: usize) {
+    loop {
+        let delta = cmp::min(left, right);
+        if delta <= RawArray::<T>::cap() {
+            break;
+        }
+
+        ptr_swap_n(
+            mid.offset(-(left as isize)),
+            mid.offset((right-delta) as isize),
+            delta);
+
+        if left <= right {
+            right -= delta;
+        } else {
+            left -= delta;
+        }
+    }
+
+    let rawarray = RawArray::new();
+    let buf = rawarray.ptr();
+
+    let dim = mid.offset(-(left as isize)).offset(right as isize);
+    if left <= right {
+        ptr::copy_nonoverlapping(mid.offset(-(left as isize)), buf, left);
+        ptr::copy(mid, mid.offset(-(left as isize)), right);
+        ptr::copy_nonoverlapping(buf, dim, left);
+    }
+    else {
+        ptr::copy_nonoverlapping(mid, buf, right);
+        ptr::copy(mid.offset(-(left as isize)), dim, left);
+        ptr::copy_nonoverlapping(buf, mid.offset(-(left as isize)), right);
+    }
+}
+
+unsafe fn ptr_swap_n<T>(a: *mut T, b: *mut T, n: usize) {
+    for i in 0..n {
+        // These are nonoverlapping, so use mem::swap instead of ptr::swap
+        mem::swap(&mut *a.offset(i as isize), &mut *b.offset(i as isize));
+    }
+}
index 44d5936c63edd5c6d6e0b256a4401dc3e50a3824..4f9951cd1539931c06dfad7d0e0fb64fb9f51a53 100644 (file)
 use core::{i8, i16, isize};
 use core::usize;
 
+// FIXME #27741: This is here to simplify calling Iterator::step_by. Remove
+// once Range::step_by is completely gone (not just deprecated).
+trait IterEx: Sized {
+    fn iter_step_by(self, n: usize) -> StepBy<Self>;
+}
+impl<I:Iterator> IterEx for I {
+    fn iter_step_by(self, n: usize) -> StepBy<Self> { self.step_by(n) }
+}
+
 #[test]
 fn test_lt() {
     let empty: [isize; 0] = [];
@@ -67,7 +76,7 @@ fn test_multi_iter() {
 
 #[test]
 fn test_counter_from_iter() {
-    let it = (0..).step_by(5).take(10);
+    let it = (0..).iter_step_by(5).take(10);
     let xs: Vec<isize> = FromIterator::from_iter(it);
     assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
 }
@@ -85,7 +94,7 @@ fn test_iterator_chain() {
     }
     assert_eq!(i, expected.len());
 
-    let ys = (30..).step_by(10).take(4);
+    let ys = (30..).iter_step_by(10).take(4);
     let it = xs.iter().cloned().chain(ys);
     let mut i = 0;
     for x in it {
@@ -147,15 +156,13 @@ fn test_iterator_chain_find() {
 #[test]
 fn test_iterator_step_by() {
     // Identity
-    // Replace with (0..).step_by(1) after Range::step_by gets removed
-    let mut it = Iterator::step_by((0..), 1).take(3);
+    let mut it = (0..).iter_step_by(1).take(3);
     assert_eq!(it.next(), Some(0));
     assert_eq!(it.next(), Some(1));
     assert_eq!(it.next(), Some(2));
     assert_eq!(it.next(), None);
 
-    // Replace with (0..).step_by(3) after Range::step_by gets removed
-    let mut it = Iterator::step_by((0..), 3).take(4);
+    let mut it = (0..).iter_step_by(3).take(4);
     assert_eq!(it.next(), Some(0));
     assert_eq!(it.next(), Some(3));
     assert_eq!(it.next(), Some(6));
@@ -166,8 +173,7 @@ fn test_iterator_step_by() {
 #[test]
 #[should_panic]
 fn test_iterator_step_by_zero() {
-    // Replace with (0..).step_by(0) after Range::step_by gets removed
-    let mut it = Iterator::step_by((0..), 0);
+    let mut it = (0..).iter_step_by(0);
     it.next();
 }
 
@@ -246,7 +252,7 @@ fn test(self) -> bool { true }
 
 #[test]
 fn test_filter_map() {
-    let it = (0..).step_by(1).take(10)
+    let it = (0..).iter_step_by(1).take(10)
         .filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None });
     assert_eq!(it.collect::<Vec<usize>>(), [0*0, 2*2, 4*4, 6*6, 8*8]);
 }
@@ -648,7 +654,7 @@ fn add(old: &mut isize, new: &usize) -> Option<f64> {
 fn test_iterator_flat_map() {
     let xs = [0, 3, 6];
     let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
-    let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3));
+    let it = xs.iter().flat_map(|&x| (x..).iter_step_by(1).take(3));
     let mut i = 0;
     for x in it {
         assert_eq!(x, ys[i]);
@@ -674,13 +680,13 @@ fn test_inspect() {
 #[test]
 fn test_cycle() {
     let cycle_len = 3;
-    let it = (0..).step_by(1).take(cycle_len).cycle();
+    let it = (0..).iter_step_by(1).take(cycle_len).cycle();
     assert_eq!(it.size_hint(), (usize::MAX, None));
     for (i, x) in it.take(100).enumerate() {
         assert_eq!(i % cycle_len, x);
     }
 
-    let mut it = (0..).step_by(1).take(0).cycle();
+    let mut it = (0..).iter_step_by(1).take(0).cycle();
     assert_eq!(it.size_hint(), (0, Some(0)));
     assert_eq!(it.next(), None);
 }
@@ -759,7 +765,7 @@ fn test_iterator_min() {
 
 #[test]
 fn test_iterator_size_hint() {
-    let c = (0..).step_by(1);
+    let c = (0..).iter_step_by(1);
     let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
     let v2 = &[10, 11, 12];
     let vi = v.iter();
@@ -1081,6 +1087,8 @@ fn test_range() {
 
 #[test]
 fn test_range_step() {
+    #![allow(deprecated)]
+
     assert_eq!((0..20).step_by(5).collect::<Vec<isize>>(), [0, 5, 10, 15]);
     assert_eq!((20..0).step_by(-5).collect::<Vec<isize>>(), [20, 15, 10, 5]);
     assert_eq!((20..0).step_by(-6).collect::<Vec<isize>>(), [20, 14, 8, 2]);
index e9f62dfbaed76c140bd866b11d5babea9c205884..505e51fa80b333b651eb10c089b1378272620dc0 100644 (file)
@@ -30,6 +30,7 @@
 #![feature(raw)]
 #![feature(sip_hash_13)]
 #![feature(slice_patterns)]
+#![feature(slice_rotate)]
 #![feature(sort_internals)]
 #![feature(sort_unstable)]
 #![feature(specialization)]
index 15047204e50d609699e5df8bcee730d9aa37ee6c..e5d6b53b570628b688e8e623a0b6052f5dab1f0d 100644 (file)
@@ -238,6 +238,22 @@ fn test_find_rfind() {
     assert_eq!(v.iter().rfind(|&&x| x <= 3), Some(&3));
 }
 
+#[test]
+fn test_rotate() {
+    const N: usize = 600;
+    let a: &mut [_] = &mut [0; N];
+    for i in 0..N {
+        a[i] = i;
+    }
+
+    a.rotate(42);
+    let k = N - 42;
+
+    for i in 0..N {
+        assert_eq!(a[(i+k)%N], i);
+    }
+}
+
 #[test]
 fn sort_unstable() {
     let mut v = [0; 600];
index 5423da9c81c02880c991871943c00b6442751fe6..e5c611460f73897ee3986277a60f9f8dd43974e5 100644 (file)
@@ -11,4 +11,4 @@ crate-type = ["dylib"]
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
index c1c195852f9492bddfe2406446ce1a4b78698b22..85b1858c875bc0eae8b513d285daac10e6d9fab1 100644 (file)
@@ -355,11 +355,11 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
             }
 
             hir::ExprIndex(ref l, ref r) |
-            hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr.id) => {
+            hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr) => {
                 self.call(expr, pred, &l, Some(&**r).into_iter())
             }
 
-            hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr.id) => {
+            hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr) => {
                 self.call(expr, pred, &e, None::<hir::Expr>.iter())
             }
 
@@ -412,16 +412,10 @@ fn call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
             pred: CFGIndex,
             func_or_rcvr: &hir::Expr,
             args: I) -> CFGIndex {
-        let method_call = ty::MethodCall::expr(call_expr.id);
-        let fn_ty = match self.tables.method_map.get(&method_call) {
-            Some(method) => method.ty,
-            None => self.tables.expr_ty_adjusted(func_or_rcvr),
-        };
-
         let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
         let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
         // FIXME(canndrew): This is_never should probably be an is_uninhabited.
-        if fn_ty.fn_ret().0.is_never() {
+        if self.tables.expr_ty(call_expr).is_never() {
             self.add_unreachable_node()
         } else {
             ret
index daed41f04700d95afb4d145db71344329495b5f8..72715cf6bc74d6e65a49ee5812f5bbcc760e9c5f 100644 (file)
@@ -254,7 +254,7 @@ and `...` are whatever edges the `/* compute value */` closure creates.
 In particular, using the memoize helper is much better than writing
 the obvious code yourself:
 
-```
+```rust
 if let Some(result) = map.get(key) {
     return result;
 }
index 38ad473e4042fc015fdf2881acb4c74612c87178..85a02953a91042a163270fd5ec7ee59ecf8ac00f 100644 (file)
@@ -27,35 +27,35 @@ pub enum DepNode<D: Clone + Debug> {
     // During compilation, it is always `DefId`, but when serializing
     // it is mapped to `DefPath`.
 
-    // Represents the `Krate` as a whole (the `hir::Krate` value) (as
-    // distinct from the krate module). This is basically a hash of
-    // the entire krate, so if you read from `Krate` (e.g., by calling
-    // `tcx.hir.krate()`), we will have to assume that any change
-    // means that you need to be recompiled. This is because the
-    // `Krate` value gives you access to all other items. To avoid
-    // this fate, do not call `tcx.hir.krate()`; instead, prefer
-    // wrappers like `tcx.visit_all_items_in_krate()`.  If there is no
-    // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
-    // access to the krate, but you must remember to add suitable
-    // edges yourself for the individual items that you read.
+    /// Represents the `Krate` as a whole (the `hir::Krate` value) (as
+    /// distinct from the krate module). This is basically a hash of
+    /// the entire krate, so if you read from `Krate` (e.g., by calling
+    /// `tcx.hir.krate()`), we will have to assume that any change
+    /// means that you need to be recompiled. This is because the
+    /// `Krate` value gives you access to all other items. To avoid
+    /// this fate, do not call `tcx.hir.krate()`; instead, prefer
+    /// wrappers like `tcx.visit_all_items_in_krate()`.  If there is no
+    /// suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
+    /// access to the krate, but you must remember to add suitable
+    /// edges yourself for the individual items that you read.
     Krate,
 
-    // Represents the HIR node with the given node-id
+    /// Represents the HIR node with the given node-id
     Hir(D),
 
-    // Represents the body of a function or method. The def-id is that of the
-    // function/method.
+    /// Represents the body of a function or method. The def-id is that of the
+    /// function/method.
     HirBody(D),
 
-    // Represents the metadata for a given HIR node, typically found
-    // in an extern crate.
+    /// Represents the metadata for a given HIR node, typically found
+    /// in an extern crate.
     MetaData(D),
 
-    // Represents some piece of metadata global to its crate.
+    /// Represents some piece of metadata global to its crate.
     GlobalMetaData(D, GlobalMetaDataKind),
 
-    // Represents some artifact that we save to disk. Note that these
-    // do not have a def-id as part of their identifier.
+    /// Represents some artifact that we save to disk. Note that these
+    /// do not have a def-id as part of their identifier.
     WorkProduct(Arc<WorkProductId>),
 
     // Represents different phases in the compiler.
@@ -112,14 +112,15 @@ pub enum DepNode<D: Clone + Debug> {
     IsSized(D),
     IsFreeze(D),
     NeedsDrop(D),
+    Layout(D),
 
-    // The set of impls for a given trait. Ultimately, it would be
-    // nice to get more fine-grained here (e.g., to include a
-    // simplified type), but we can't do that until we restructure the
-    // HIR to distinguish the *header* of an impl from its body.  This
-    // is because changes to the header may change the self-type of
-    // the impl and hence would require us to be more conservative
-    // than changes in the impl body.
+    /// The set of impls for a given trait. Ultimately, it would be
+    /// nice to get more fine-grained here (e.g., to include a
+    /// simplified type), but we can't do that until we restructure the
+    /// HIR to distinguish the *header* of an impl from its body.  This
+    /// is because changes to the header may change the self-type of
+    /// the impl and hence would require us to be more conservative
+    /// than changes in the impl body.
     TraitImpls(D),
 
     AllLocalTraitImpls,
@@ -132,35 +133,35 @@ pub enum DepNode<D: Clone + Debug> {
     TraitItems(D),
     ReprHints(D),
 
-    // Trait selection cache is a little funny. Given a trait
-    // reference like `Foo: SomeTrait<Bar>`, there could be
-    // arbitrarily many def-ids to map on in there (e.g., `Foo`,
-    // `SomeTrait`, `Bar`). We could have a vector of them, but it
-    // requires heap-allocation, and trait sel in general can be a
-    // surprisingly hot path. So instead we pick two def-ids: the
-    // trait def-id, and the first def-id in the input types. If there
-    // is no def-id in the input types, then we use the trait def-id
-    // again. So for example:
-    //
-    // - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
-    // - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
-    // - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
-    // - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }`
-    // - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }`
-    // - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
-    // - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
-    // - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
-    // - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
-    //
-    // You can see that we map many trait refs to the same
-    // trait-select node.  This is not a problem, it just means
-    // imprecision in our dep-graph tracking.  The important thing is
-    // that for any given trait-ref, we always map to the **same**
-    // trait-select node.
+    /// Trait selection cache is a little funny. Given a trait
+    /// reference like `Foo: SomeTrait<Bar>`, there could be
+    /// arbitrarily many def-ids to map on in there (e.g., `Foo`,
+    /// `SomeTrait`, `Bar`). We could have a vector of them, but it
+    /// requires heap-allocation, and trait sel in general can be a
+    /// surprisingly hot path. So instead we pick two def-ids: the
+    /// trait def-id, and the first def-id in the input types. If there
+    /// is no def-id in the input types, then we use the trait def-id
+    /// again. So for example:
+    ///
+    /// - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
+    /// - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
+    /// - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
+    /// - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }`
+    /// - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }`
+    /// - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
+    /// - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
+    /// - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
+    /// - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
+    ///
+    /// You can see that we map many trait refs to the same
+    /// trait-select node.  This is not a problem, it just means
+    /// imprecision in our dep-graph tracking.  The important thing is
+    /// that for any given trait-ref, we always map to the **same**
+    /// trait-select node.
     TraitSelect { trait_def_id: D, input_def_id: D },
 
-    // For proj. cache, we just keep a list of all def-ids, since it is
-    // not a hotspot.
+    /// For proj. cache, we just keep a list of all def-ids, since it is
+    /// not a hotspot.
     ProjectionCache { def_ids: Vec<D> },
 
     ParamEnv(D),
@@ -241,6 +242,7 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
             IsSized(ref d) => op(d).map(IsSized),
             IsFreeze(ref d) => op(d).map(IsFreeze),
             NeedsDrop(ref d) => op(d).map(NeedsDrop),
+            Layout(ref d) => op(d).map(Layout),
             Hir(ref d) => op(d).map(Hir),
             HirBody(ref d) => op(d).map(HirBody),
             MetaData(ref d) => op(d).map(MetaData),
index 59dce6f6bb0975a83f35090a27ac576ef1fccc60..bf224f89f0ddb41539b1b3b08b3733d7deb73dc8 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! The `DepGraphSafe` trait
+
 use hir::BodyId;
 use hir::def_id::DefId;
 use syntax::ast::NodeId;
index df82fee80f23c4cb437a82dc6a3ab31b2010a1fb..4c436fb640f01797f22a08ea489f9c6fdcc04402 100644 (file)
@@ -891,6 +891,7 @@ fn lower_local(&mut self, l: &Local) -> P<hir::Local> {
             init: l.init.as_ref().map(|e| P(self.lower_expr(e))),
             span: l.span,
             attrs: l.attrs.clone(),
+            source: hir::LocalSource::Normal,
         })
     }
 
@@ -2167,10 +2168,11 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 //     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
                 //       mut iter => {
                 //         [opt_ident]: loop {
-                //           match ::std::iter::Iterator::next(&mut iter) {
-                //             ::std::option::Option::Some(<pat>) => <body>,
+                //           let <pat> = match ::std::iter::Iterator::next(&mut iter) {
+                //             ::std::option::Option::Some(val) => val,
                 //             ::std::option::Option::None => break
-                //           }
+                //           };
+                //           SemiExpr(<body>);
                 //         }
                 //       }
                 //     };
@@ -2182,15 +2184,13 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
 
                 let iter = self.str_to_ident("iter");
 
-                // `::std::option::Option::Some(<pat>) => <body>`
+                // `::std::option::Option::Some(val) => val`
                 let pat_arm = {
-                    let body_block = self.with_loop_scope(e.id,
-                                                          |this| this.lower_block(body, false));
-                    let body_expr = P(self.expr_block(body_block, ThinVec::new()));
-                    let pat = self.lower_pat(pat);
-                    let some_pat = self.pat_some(e.span, pat);
-
-                    self.arm(hir_vec![some_pat], body_expr)
+                    let val_ident = self.str_to_ident("val");
+                    let val_pat = self.pat_ident(e.span, val_ident);
+                    let val_expr = P(self.expr_ident(e.span, val_ident, val_pat.id));
+                    let some_pat = self.pat_some(e.span, val_pat);
+                    self.arm(hir_vec![some_pat], val_expr)
                 };
 
                 // `::std::option::Option::None => break`
@@ -2221,8 +2221,20 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                                 ThinVec::new()))
                 };
 
+                let pat = self.lower_pat(pat);
+                let pat_let = self.stmt_let_pat(e.span,
+                    match_expr,
+                    pat,
+                    hir::LocalSource::ForLoopDesugar);
+
+                let body_block = self.with_loop_scope(e.id,
+                                                        |this| this.lower_block(body, false));
+                let body_expr = P(self.expr_block(body_block, ThinVec::new()));
+                let body_stmt = respan(e.span, hir::StmtExpr(body_expr, self.next_id()));
+
+                let loop_block = P(self.block_all(e.span, hir_vec![pat_let, body_stmt], None));
+
                 // `[opt_ident]: loop { ... }`
-                let loop_block = P(self.block_expr(match_expr));
                 let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
                                               hir::LoopSource::ForLoop);
                 let loop_expr = P(hir::Expr {
@@ -2585,14 +2597,12 @@ fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec<Attribute>) -> h
         }
     }
 
-    fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P<hir::Expr>)
-                -> (hir::Stmt, NodeId) {
-        let pat = if mutbl {
-            self.pat_ident_binding_mode(sp, ident, hir::BindByValue(hir::MutMutable))
-        } else {
-            self.pat_ident(sp, ident)
-        };
-        let pat_id = pat.id;
+    fn stmt_let_pat(&mut self,
+                    sp: Span,
+                    ex: P<hir::Expr>,
+                    pat: P<hir::Pat>,
+                    source: hir::LocalSource)
+                    -> hir::Stmt {
         let local = P(hir::Local {
             pat: pat,
             ty: None,
@@ -2600,9 +2610,21 @@ fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P<hir::Expr>)
             id: self.next_id(),
             span: sp,
             attrs: ThinVec::new(),
+            source,
         });
         let decl = respan(sp, hir::DeclLocal(local));
-        (respan(sp, hir::StmtDecl(P(decl), self.next_id())), pat_id)
+        respan(sp, hir::StmtDecl(P(decl), self.next_id()))
+    }
+
+    fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P<hir::Expr>)
+                -> (hir::Stmt, NodeId) {
+        let pat = if mutbl {
+            self.pat_ident_binding_mode(sp, ident, hir::BindByValue(hir::MutMutable))
+        } else {
+            self.pat_ident(sp, ident)
+        };
+        let pat_id = pat.id;
+        (self.stmt_let_pat(sp, ex, pat, hir::LocalSource::Normal), pat_id)
     }
 
     fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block {
index c86b140fbc61462d6723c5a61dbb140351c7b631..ced0f351c9eed630f65f4ddc01f84ceab9ed3999 100644 (file)
@@ -36,7 +36,7 @@
 pub struct DefPathTable {
     index_to_key: [Vec<DefKey>; 2],
     key_to_index: FxHashMap<DefKey, DefIndex>,
-    def_path_hashes: [Vec<Fingerprint>; 2],
+    def_path_hashes: [Vec<DefPathHash>; 2],
 }
 
 // Unfortunately we have to provide a manual impl of Clone because of the
@@ -57,7 +57,7 @@ impl DefPathTable {
 
     fn allocate(&mut self,
                 key: DefKey,
-                def_path_hash: Fingerprint,
+                def_path_hash: DefPathHash,
                 address_space: DefIndexAddressSpace)
                 -> DefIndex {
         let index = {
@@ -81,7 +81,7 @@ pub fn def_key(&self, index: DefIndex) -> DefKey {
     }
 
     #[inline(always)]
-    pub fn def_path_hash(&self, index: DefIndex) -> Fingerprint {
+    pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
         self.def_path_hashes[index.address_space().index()]
                             [index.as_array_index()]
     }
@@ -126,6 +126,30 @@ pub fn retrace_path(&self,
 
         Some(index)
     }
+
+    pub fn add_def_path_hashes_to(&self,
+                                  cnum: CrateNum,
+                                  out: &mut FxHashMap<DefPathHash, DefId>) {
+        for address_space in &[DefIndexAddressSpace::Low, DefIndexAddressSpace::High] {
+            let start_index = address_space.start();
+            out.extend(
+                (&self.def_path_hashes[address_space.index()])
+                    .iter()
+                    .enumerate()
+                    .map(|(index, &hash)| {
+                        let def_id = DefId {
+                            krate: cnum,
+                            index: DefIndex::new(index + start_index),
+                        };
+                        (hash, def_id)
+                    })
+            );
+        }
+    }
+
+    pub fn size(&self) -> usize {
+        self.key_to_index.len()
+    }
 }
 
 
@@ -148,8 +172,8 @@ fn decode<D: Decoder>(d: &mut D) -> Result<DefPathTable, D::Error> {
         let index_to_key_lo: Vec<DefKey> = Decodable::decode(d)?;
         let index_to_key_hi: Vec<DefKey> = Decodable::decode(d)?;
 
-        let def_path_hashes_lo: Vec<Fingerprint> = Decodable::decode(d)?;
-        let def_path_hashes_hi: Vec<Fingerprint> = Decodable::decode(d)?;
+        let def_path_hashes_lo: Vec<DefPathHash> = Decodable::decode(d)?;
+        let def_path_hashes_hi: Vec<DefPathHash> = Decodable::decode(d)?;
 
         let index_to_key = [index_to_key_lo, index_to_key_hi];
         let def_path_hashes = [def_path_hashes_lo, def_path_hashes_hi];
@@ -216,7 +240,7 @@ pub struct DefKey {
 }
 
 impl DefKey {
-    fn compute_stable_hash(&self, parent_hash: Fingerprint) -> Fingerprint {
+    fn compute_stable_hash(&self, parent_hash: DefPathHash) -> DefPathHash {
         let mut hasher = StableHasher::new();
 
         // We hash a 0u8 here to disambiguate between regular DefPath hashes,
@@ -224,17 +248,17 @@ fn compute_stable_hash(&self, parent_hash: Fingerprint) -> Fingerprint {
         0u8.hash(&mut hasher);
         parent_hash.hash(&mut hasher);
         self.disambiguated_data.hash(&mut hasher);
-        hasher.finish()
+        DefPathHash(hasher.finish())
     }
 
-    fn root_parent_stable_hash(crate_name: &str, crate_disambiguator: &str) -> Fingerprint {
+    fn root_parent_stable_hash(crate_name: &str, crate_disambiguator: &str) -> DefPathHash {
         let mut hasher = StableHasher::new();
         // Disambiguate this from a regular DefPath hash,
         // see compute_stable_hash() above.
         1u8.hash(&mut hasher);
         crate_name.hash(&mut hasher);
         crate_disambiguator.hash(&mut hasher);
-        hasher.finish()
+        DefPathHash(hasher.finish())
     }
 }
 
@@ -296,7 +320,9 @@ pub fn to_string(&self, tcx: TyCtxt) -> String {
 
         s.push_str(&tcx.original_crate_name(self.krate).as_str());
         s.push_str("/");
-        s.push_str(&tcx.crate_disambiguator(self.krate).as_str());
+        // Don't print the whole crate disambiguator. That's just annoying in
+        // debug output.
+        s.push_str(&tcx.crate_disambiguator(self.krate).as_str()[..7]);
 
         for component in &self.data {
             write!(s,
@@ -372,6 +398,12 @@ pub enum DefPathData {
     Typeof,
 }
 
+#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug,
+         RustcEncodable, RustcDecodable)]
+pub struct DefPathHash(pub Fingerprint);
+
+impl_stable_hash_for!(tuple_struct DefPathHash { fingerprint });
+
 impl Definitions {
     /// Create new empty definition map.
     pub fn new() -> Definitions {
@@ -404,7 +436,7 @@ pub fn def_key(&self, index: DefIndex) -> DefKey {
     }
 
     #[inline(always)]
-    pub fn def_path_hash(&self, index: DefIndex) -> Fingerprint {
+    pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
         self.table.def_path_hash(index)
     }
 
index 09e9d7c5b2f7d81cd8355e0bfc1254cec19e4721..176760c255c00f50c742dbdf1c7cf0c5246e056d 100644 (file)
@@ -13,7 +13,7 @@
 use self::collector::NodeCollector;
 pub use self::def_collector::{DefCollector, MacroInvocationData};
 pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
-                            DisambiguatedDefPathData};
+                            DisambiguatedDefPathData, DefPathHash};
 
 use dep_graph::{DepGraph, DepNode};
 
index 500e95a8a778ee46d99b7342eff8c77268fa0464..3f2977cc503df5558d615a3afbf371d571193360 100644 (file)
@@ -872,6 +872,7 @@ pub struct Local {
     pub id: NodeId,
     pub span: Span,
     pub attrs: ThinVec<Attribute>,
+    pub source: LocalSource,
 }
 
 pub type Decl = Spanned<Decl_>;
@@ -1080,6 +1081,15 @@ pub enum QPath {
     TypeRelative(P<Ty>, P<PathSegment>)
 }
 
+/// Hints at the original code for a let statement
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum LocalSource {
+    /// A `match _ { .. }`
+    Normal,
+    /// A desugared `for _ in _ { .. }` loop
+    ForLoopDesugar,
+}
+
 /// Hints at the original code for a `match _ { .. }`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum MatchSource {
index a947f6aeff709af0ebc9ec71a47658cc2988e084..8308c756c0532f1ecaddea56bc018e671a857ff2 100644 (file)
@@ -8,12 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
 use rustc_data_structures::stable_hasher;
 use std::mem;
 use std::slice;
 
-#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)]
+#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, RustcEncodable, RustcDecodable)]
 pub struct Fingerprint(u64, u64);
 
 impl Fingerprint {
@@ -37,23 +36,6 @@ pub fn to_hex(&self) -> String {
     }
 }
 
-impl Encodable for Fingerprint {
-    #[inline]
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u64(self.0.to_le())?;
-        s.emit_u64(self.1.to_le())
-    }
-}
-
-impl Decodable for Fingerprint {
-    #[inline]
-    fn decode<D: Decoder>(d: &mut D) -> Result<Fingerprint, D::Error> {
-        let _0 = u64::from_le(d.read_u64()?);
-        let _1 = u64::from_le(d.read_u64()?);
-        Ok(Fingerprint(_0, _1))
-    }
-}
-
 impl ::std::fmt::Display for Fingerprint {
     fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
         write!(formatter, "{:x}-{:x}", self.0, self.1)
index f8dddc42e48ccf8d1c2d2e044f38711f83b83546..a835548894182493fed5f506a4f53fbea9ba8e29 100644 (file)
@@ -10,6 +10,7 @@
 
 use hir;
 use hir::def_id::DefId;
+use hir::map::DefPathHash;
 use ich::{self, CachingCodemapView};
 use session::config::DebugInfoLevel::NoDebugInfo;
 use ty;
@@ -115,7 +116,7 @@ pub fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> {
     }
 
     #[inline]
-    pub fn def_path_hash(&mut self, def_id: DefId) -> ich::Fingerprint {
+    pub fn def_path_hash(&mut self, def_id: DefId) -> DefPathHash {
         self.tcx.def_path_hash(def_id)
     }
 
index dbe91e2725deffec2a377df2602646edbb886d79..c582cac67e22b508e43dd5dd6e4c542da0a32518 100644 (file)
@@ -490,7 +490,8 @@ fn hash_stable<W: StableHasherResult>(&self,
     init,
     id,
     span,
-    attrs
+    attrs,
+    source
 });
 
 impl_stable_hash_for_spanned!(hir::Decl_);
@@ -640,6 +641,11 @@ fn hash_stable<W: StableHasherResult>(&self,
     ExprRepeat(val, times)
 });
 
+impl_stable_hash_for!(enum hir::LocalSource {
+    Normal,
+    ForLoopDesugar
+});
+
 impl_stable_hash_for!(enum hir::LoopSource {
     Loop,
     WhileLet,
index b43c516f317f2e746889631ceae4516bd4eb5760..a362dc31ff180e27031f6b5c6a9c3bf8f732bee0 100644 (file)
@@ -19,8 +19,6 @@
 use syntax_pos::symbol::InternedString;
 use ty;
 
-impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs });
-
 impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for &'tcx ty::Slice<T>
     where T: HashStable<StableHashingContext<'a, 'tcx>> {
     fn hash_stable<W: StableHasherResult>(&self,
@@ -101,19 +99,20 @@ fn hash_stable<W: StableHasherResult>(&self,
             ty::adjustment::Adjust::ReifyFnPointer |
             ty::adjustment::Adjust::UnsafeFnPointer |
             ty::adjustment::Adjust::ClosureFnPointer |
-            ty::adjustment::Adjust::MutToConstPointer => {}
-            ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => {
-                autoderefs.hash_stable(hcx, hasher);
+            ty::adjustment::Adjust::MutToConstPointer |
+            ty::adjustment::Adjust::Unsize => {}
+            ty::adjustment::Adjust::Deref(ref overloaded) => {
+                overloaded.hash_stable(hcx, hasher);
+            }
+            ty::adjustment::Adjust::Borrow(ref autoref) => {
                 autoref.hash_stable(hcx, hasher);
-                unsize.hash_stable(hcx, hasher);
             }
         }
     }
 }
 
 impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
-impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef });
-impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs });
+impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl });
 impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
 impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
 
@@ -601,11 +600,10 @@ fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a, 'tcx>,
                                           hasher: &mut StableHasher<W>) {
         let ty::TypeckTables {
-            ref type_relative_path_defs,
+            ref type_dependent_defs,
             ref node_types,
-            ref item_substs,
+            ref node_substs,
             ref adjustments,
-            ref method_map,
             ref upvar_capture_map,
             ref closure_tys,
             ref closure_kinds,
@@ -622,21 +620,10 @@ fn hash_stable<W: StableHasherResult>(&self,
         } = *self;
 
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-            ich::hash_stable_nodemap(hcx, hasher, type_relative_path_defs);
+            ich::hash_stable_nodemap(hcx, hasher, type_dependent_defs);
             ich::hash_stable_nodemap(hcx, hasher, node_types);
-            ich::hash_stable_nodemap(hcx, hasher, item_substs);
+            ich::hash_stable_nodemap(hcx, hasher, node_substs);
             ich::hash_stable_nodemap(hcx, hasher, adjustments);
-
-            ich::hash_stable_hashmap(hcx, hasher, method_map, |hcx, method_call| {
-                let ty::MethodCall {
-                    expr_id,
-                    autoderef
-                } = *method_call;
-
-                let def_id = hcx.tcx().hir.local_def_id(expr_id);
-                (hcx.def_path_hash(def_id), autoderef)
-            });
-
             ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| {
                 let ty::UpvarId {
                     var_id,
diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs
new file mode 100644 (file)
index 0000000..756e0b5
--- /dev/null
@@ -0,0 +1,310 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A nice interface for working with the infcx.  The basic idea is to
+//! do `infcx.at(cause, param_env)`, which sets the "cause" of the
+//! operation as well as the surrounding parameter environment.  Then
+//! you can do something like `.sub(a, b)` or `.eq(a, b)` to create a
+//! subtype or equality relationship respectively. The first argument
+//! is always the "expected" output from the POV of diagnostics.
+//!
+//! Examples:
+//!
+//!     infcx.at(cause, param_env).sub(a, b)
+//!     // requires that `a <: b`, with `a` considered the "expected" type
+//!
+//!     infcx.at(cause, param_env).sup(a, b)
+//!     // requires that `b <: a`, with `a` considered the "expected" type
+//!
+//!     infcx.at(cause, param_env).eq(a, b)
+//!     // requires that `a == b`, with `a` considered the "expected" type
+//!
+//! For finer-grained control, you can also do use `trace`:
+//!
+//!     infcx.at(...).trace(a, b).sub(&c, &d)
+//!
+//! This will set `a` and `b` as the "root" values for
+//! error-reporting, but actually operate on `c` and `d`. This is
+//! sometimes useful when the types of `c` and `d` are not traceable
+//! things. (That system should probably be refactored.)
+
+use super::*;
+
+use ty::relate::{Relate, TypeRelation};
+
+pub struct At<'a, 'gcx: 'tcx, 'tcx: 'a> {
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    cause: &'a ObligationCause<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+}
+
+pub struct Trace<'a, 'gcx: 'tcx, 'tcx: 'a> {
+    at: At<'a, 'gcx, 'tcx>,
+    a_is_expected: bool,
+    trace: TypeTrace<'tcx>,
+}
+
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+    pub fn at(&'a self,
+              cause: &'a ObligationCause<'tcx>,
+              param_env: ty::ParamEnv<'tcx>)
+              -> At<'a, 'gcx, 'tcx>
+    {
+        At { infcx: self, cause, param_env }
+    }
+}
+
+pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
+    fn to_trace(cause: &ObligationCause<'tcx>,
+                a_is_expected: bool,
+                a: Self,
+                b: Self)
+                -> TypeTrace<'tcx>;
+}
+
+impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> {
+    /// Hacky routine for equating two impl headers in coherence.
+    pub fn eq_impl_headers(self,
+                           expected: &ty::ImplHeader<'tcx>,
+                           actual: &ty::ImplHeader<'tcx>)
+                           -> InferResult<'tcx, ()>
+    {
+        debug!("eq_impl_header({:?} = {:?})", expected, actual);
+        match (expected.trait_ref, actual.trait_ref) {
+            (Some(a_ref), Some(b_ref)) =>
+                self.eq(a_ref, b_ref),
+            (None, None) =>
+                self.eq(expected.self_ty, actual.self_ty),
+            _ =>
+                bug!("mk_eq_impl_headers given mismatched impl kinds"),
+        }
+    }
+
+    /// Make `a <: b` where `a` may or may not be expected
+    pub fn sub_exp<T>(self,
+                      a_is_expected: bool,
+                      a: T,
+                      b: T)
+                      -> InferResult<'tcx, ()>
+        where T: ToTrace<'tcx>
+    {
+        self.trace_exp(a_is_expected, a, b).sub(&a, &b)
+    }
+
+    /// Make `actual <: expected`. For example, if type-checking a
+    /// call like `foo(x)`, where `foo: fn(i32)`, you might have
+    /// `sup(i32, x)`, since the "expected" type is the type that
+    /// appears in the signature.
+    pub fn sup<T>(self,
+                  expected: T,
+                  actual: T)
+                  -> InferResult<'tcx, ()>
+        where T: ToTrace<'tcx>
+    {
+        self.sub_exp(false, actual, expected)
+    }
+
+    /// Make `expected <: actual`
+    pub fn sub<T>(self,
+                  expected: T,
+                  actual: T)
+                  -> InferResult<'tcx, ()>
+        where T: ToTrace<'tcx>
+    {
+        self.sub_exp(true, expected, actual)
+    }
+
+    /// Make `expected <: actual`
+    pub fn eq_exp<T>(self,
+                     a_is_expected: bool,
+                     a: T,
+                     b: T)
+                     -> InferResult<'tcx, ()>
+        where T: ToTrace<'tcx>
+    {
+        self.trace_exp(a_is_expected, a, b).eq(&a, &b)
+    }
+
+    /// Make `expected <: actual`
+    pub fn eq<T>(self,
+                 expected: T,
+                 actual: T)
+                 -> InferResult<'tcx, ()>
+        where T: ToTrace<'tcx>
+    {
+        self.trace(expected, actual).eq(&expected, &actual)
+    }
+
+    /// Compute the least-upper-bound, or mutual supertype, of two
+    /// values. The order of the arguments doesn't matter, but since
+    /// this can result in an error (e.g., if asked to compute LUB of
+    /// u32 and i32), it is meaningful to call one of them the
+    /// "expected type".
+    pub fn lub<T>(self,
+                  expected: T,
+                  actual: T)
+                  -> InferResult<'tcx, T>
+        where T: ToTrace<'tcx>
+    {
+        self.trace(expected, actual).lub(&expected, &actual)
+    }
+
+    /// Compute the greatest-lower-bound, or mutual subtype, of two
+    /// values. As with `lub` order doesn't matter, except for error
+    /// cases.
+    pub fn glb<T>(self,
+                  expected: T,
+                  actual: T)
+                  -> InferResult<'tcx, T>
+        where T: ToTrace<'tcx>
+    {
+        self.trace(expected, actual).glb(&expected, &actual)
+    }
+
+    /// Sets the "trace" values that will be used for
+    /// error-repporting, but doesn't actually perform any operation
+    /// yet (this is useful when you want to set the trace using
+    /// distinct values from those you wish to operate upon).
+    pub fn trace<T>(self,
+                    expected: T,
+                    actual: T)
+                    -> Trace<'a, 'gcx, 'tcx>
+        where T: ToTrace<'tcx>
+    {
+        self.trace_exp(true, expected, actual)
+    }
+
+    /// Like `trace`, but the expected value is determined by the
+    /// boolean argument (if true, then the first argument `a` is the
+    /// "expected" value).
+    pub fn trace_exp<T>(self,
+                        a_is_expected: bool,
+                        a: T,
+                        b: T)
+                        -> Trace<'a, 'gcx, 'tcx>
+        where T: ToTrace<'tcx>
+    {
+        let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
+        Trace { at: self, trace: trace, a_is_expected }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> {
+    /// Make `a <: b` where `a` may or may not be expected (if
+    /// `a_is_expected` is true, then `a` is expected).
+    /// Make `expected <: actual`
+    pub fn sub<T>(self,
+                  a: &T,
+                  b: &T)
+                  -> InferResult<'tcx, ()>
+        where T: Relate<'tcx>
+    {
+        debug!("sub({:?} <: {:?})", a, b);
+        let Trace { at, trace, a_is_expected } = self;
+        at.infcx.commit_if_ok(|_| {
+            let mut fields = at.infcx.combine_fields(trace, at.param_env);
+            fields.sub(a_is_expected)
+                  .relate(a, b)
+                  .map(move |_| InferOk { value: (), obligations: fields.obligations })
+        })
+    }
+
+    /// Make `a == b`; the expectation is set by the call to
+    /// `trace()`.
+    pub fn eq<T>(self,
+                 a: &T,
+                 b: &T)
+                 -> InferResult<'tcx, ()>
+        where T: Relate<'tcx>
+    {
+        debug!("eq({:?} == {:?})", a, b);
+        let Trace { at, trace, a_is_expected } = self;
+        at.infcx.commit_if_ok(|_| {
+            let mut fields = at.infcx.combine_fields(trace, at.param_env);
+            fields.equate(a_is_expected)
+                  .relate(a, b)
+                  .map(move |_| InferOk { value: (), obligations: fields.obligations })
+        })
+    }
+
+    pub fn lub<T>(self,
+                  a: &T,
+                  b: &T)
+                  -> InferResult<'tcx, T>
+        where T: Relate<'tcx>
+    {
+        debug!("lub({:?} \\/ {:?})", a, b);
+        let Trace { at, trace, a_is_expected } = self;
+        at.infcx.commit_if_ok(|_| {
+            let mut fields = at.infcx.combine_fields(trace, at.param_env);
+            fields.lub(a_is_expected)
+                  .relate(a, b)
+                  .map(move |t| InferOk { value: t, obligations: fields.obligations })
+        })
+    }
+
+    pub fn glb<T>(self,
+                  a: &T,
+                  b: &T)
+                  -> InferResult<'tcx, T>
+        where T: Relate<'tcx>
+    {
+        debug!("glb({:?} /\\ {:?})", a, b);
+        let Trace { at, trace, a_is_expected } = self;
+        at.infcx.commit_if_ok(|_| {
+            let mut fields = at.infcx.combine_fields(trace, at.param_env);
+            fields.glb(a_is_expected)
+                  .relate(a, b)
+                  .map(move |t| InferOk { value: t, obligations: fields.obligations })
+        })
+    }
+}
+
+impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>,
+                a_is_expected: bool,
+                a: Self,
+                b: Self)
+                -> TypeTrace<'tcx>
+    {
+        TypeTrace {
+            cause: cause.clone(),
+            values: Types(ExpectedFound::new(a_is_expected, a, b))
+        }
+    }
+}
+
+impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>,
+                a_is_expected: bool,
+                a: Self,
+                b: Self)
+                -> TypeTrace<'tcx>
+    {
+        TypeTrace {
+            cause: cause.clone(),
+            values: TraitRefs(ExpectedFound::new(a_is_expected, a, b))
+        }
+    }
+}
+
+impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>,
+                a_is_expected: bool,
+                a: Self,
+                b: Self)
+                -> TypeTrace<'tcx>
+    {
+        TypeTrace {
+            cause: cause.clone(),
+            values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b))
+        }
+    }
+}
index aabb6aff55140c4138efecfa741db1245b2e0e4b..14920b8b668ec56fb0f26141dec9a5c3707e05e4 100644 (file)
@@ -55,6 +55,7 @@ pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
     pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>,
     pub trace: TypeTrace<'tcx>,
     pub cause: Option<ty::relate::Cause>,
+    pub param_env: ty::ParamEnv<'tcx>,
     pub obligations: PredicateObligations<'tcx>,
 }
 
@@ -215,6 +216,7 @@ pub fn instantiate(&mut self,
 
         if needs_wf {
             self.obligations.push(Obligation::new(self.trace.cause.clone(),
+                                                  self.param_env,
                                                   ty::Predicate::WellFormed(b_ty)));
         }
 
index a6dbbee79a48c83dfa6ab3651e4259f97d03eafc..f5869b8a20fab7881529092b132d00fbf5a5d26a 100644 (file)
@@ -31,7 +31,7 @@
 use ty::{self, Ty, TyCtxt};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use ty::relate::{Relate, RelateResult, TypeRelation};
+use ty::relate::RelateResult;
 use traits::{self, ObligationCause, PredicateObligations, Reveal};
 use rustc_data_structures::unify::{self, UnificationTable};
 use std::cell::{Cell, RefCell, Ref, RefMut};
@@ -49,6 +49,7 @@
 use self::type_variable::TypeVariableOrigin;
 use self::unify_key::ToType;
 
+pub mod at;
 mod combine;
 mod equate;
 pub mod error_reporting;
@@ -161,8 +162,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // For region variables.
     region_vars: RegionVarBindings<'a, 'gcx, 'tcx>,
 
-    pub param_env: ty::ParamEnv<'gcx>,
-
     /// Caches the results of trait selection. This cache is used
     /// for things that have to do with the parameters in scope.
     pub selection_cache: traits::SelectionCache<'tcx>,
@@ -174,11 +173,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // avoid reporting the same error twice.
     pub reported_trait_errors: RefCell<FxHashSet<traits::TraitErrorKey<'tcx>>>,
 
-    // Sadly, the behavior of projection varies a bit depending on the
-    // stage of compilation. The specifics are given in the
-    // documentation for `Reveal`.
-    projection_mode: Reveal,
-
     // When an error occurs, we want to avoid reporting "derived"
     // errors that are due to this original failure. Normally, we
     // handle this with the `err_count_on_creation` count, which
@@ -405,55 +399,39 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 pub trait InferEnv<'a, 'tcx> {
     fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
                 -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>,
-                    Option<ty::ParamEnv<'tcx>>);
+                    Option<ty::TypeckTables<'tcx>>);
 }
 
 impl<'a, 'tcx> InferEnv<'a, 'tcx> for () {
     fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
                 -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>,
-                    Option<ty::ParamEnv<'tcx>>) {
-        (None, None, None)
-    }
-}
-
-impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::ParamEnv<'tcx> {
-    fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-                -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>,
-                    Option<ty::ParamEnv<'tcx>>) {
-        (None, None, Some(self))
+                    Option<ty::TypeckTables<'tcx>>) {
+        (None, None)
     }
 }
 
-impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) {
+impl<'a, 'tcx> InferEnv<'a, 'tcx> for &'a ty::TypeckTables<'tcx> {
     fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
                 -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>,
-                    Option<ty::ParamEnv<'tcx>>) {
-        (Some(self.0), None, Some(self.1))
+                    Option<ty::TypeckTables<'tcx>>) {
+        (Some(self), None)
     }
 }
 
-impl<'a, 'tcx> InferEnv<'a, 'tcx> for (ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) {
+impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::TypeckTables<'tcx> {
     fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
                 -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>,
-                    Option<ty::ParamEnv<'tcx>>) {
-        (None, Some(self.0), Some(self.1))
+                    Option<ty::TypeckTables<'tcx>>) {
+        (None, Some(self))
     }
 }
 
 impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId {
     fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
                 -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>,
-                    Option<ty::ParamEnv<'tcx>>) {
+                    Option<ty::TypeckTables<'tcx>>) {
         let def_id = tcx.hir.body_owner_def_id(self);
-        (Some(tcx.typeck_tables_of(def_id)),
-         None,
-         Some(tcx.param_env(def_id)))
+        (Some(tcx.typeck_tables_of(def_id)), None)
     }
 }
 
@@ -465,23 +443,16 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     arena: DroplessArena,
     fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
     tables: Option<&'a ty::TypeckTables<'gcx>>,
-    param_env: Option<ty::ParamEnv<'gcx>>,
-    projection_mode: Reveal,
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
-    pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self,
-                                             env: E,
-                                             projection_mode: Reveal)
-                                             -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
-        let (tables, fresh_tables, param_env) = env.to_parts(self);
+    pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self, env: E) -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
+        let (tables, fresh_tables) = env.to_parts(self);
         InferCtxtBuilder {
             global_tcx: self,
             arena: DroplessArena::new(),
             fresh_tables: fresh_tables.map(RefCell::new),
             tables: tables,
-            param_env: param_env,
-            projection_mode: projection_mode,
         }
     }
 
@@ -490,7 +461,7 @@ pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self,
     /// If any inference functionality is used, ICEs will occur.
     pub fn borrowck_fake_infer_ctxt(self, body: hir::BodyId)
                                     -> InferCtxt<'a, 'gcx, 'gcx> {
-        let (tables, _, param_env) = body.to_parts(self);
+        let (tables, _) = body.to_parts(self);
         InferCtxt {
             tcx: self,
             tables: InferTables::Interned(tables.unwrap()),
@@ -498,12 +469,10 @@ pub fn borrowck_fake_infer_ctxt(self, body: hir::BodyId)
             int_unification_table: RefCell::new(UnificationTable::new()),
             float_unification_table: RefCell::new(UnificationTable::new()),
             region_vars: RegionVarBindings::new(self),
-            param_env: param_env.unwrap(),
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
             projection_cache: RefCell::new(traits::ProjectionCache::new()),
             reported_trait_errors: RefCell::new(FxHashSet()),
-            projection_mode: Reveal::UserFacing,
             tainted_by_errors_flag: Cell::new(false),
             err_count_on_creation: self.sess.err_count(),
             in_snapshot: Cell::new(false),
@@ -520,13 +489,10 @@ pub fn enter<F, R>(&'tcx mut self, f: F) -> R
             ref arena,
             ref fresh_tables,
             tables,
-            ref mut param_env,
-            projection_mode,
         } = *self;
         let tables = tables.map(InferTables::Interned).unwrap_or_else(|| {
             fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress)
         });
-        let param_env = param_env.take().unwrap_or_else(|| ty::ParamEnv::empty());
         global_tcx.enter_local(arena, |tcx| f(InferCtxt {
             tcx: tcx,
             tables: tables,
@@ -535,11 +501,9 @@ pub fn enter<F, R>(&'tcx mut self, f: F) -> R
             int_unification_table: RefCell::new(UnificationTable::new()),
             float_unification_table: RefCell::new(UnificationTable::new()),
             region_vars: RegionVarBindings::new(tcx),
-            param_env: param_env,
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
             reported_trait_errors: RefCell::new(FxHashSet()),
-            projection_mode: projection_mode,
             tainted_by_errors_flag: Cell::new(false),
             err_count_on_creation: tcx.sess.err_count(),
             in_snapshot: Cell::new(false),
@@ -564,19 +528,23 @@ pub fn unit(self) -> InferOk<'tcx, ()> {
 }
 
 #[must_use = "once you start a snapshot, you should always consume it"]
-pub struct CombinedSnapshot {
+pub struct CombinedSnapshot<'a, 'tcx:'a> {
     projection_cache_snapshot: traits::ProjectionCacheSnapshot,
     type_snapshot: type_variable::Snapshot,
     int_snapshot: unify::Snapshot<ty::IntVid>,
     float_snapshot: unify::Snapshot<ty::FloatVid>,
     region_vars_snapshot: RegionSnapshot,
     was_in_snapshot: bool,
+    _in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>,
 }
 
 /// Helper trait for shortening the lifetimes inside a
 /// value for post-type-checking normalization.
 pub trait TransNormalize<'gcx>: TypeFoldable<'gcx> {
-    fn trans_normalize<'a, 'tcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self;
+    fn trans_normalize<'a, 'tcx>(&self,
+                                 infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                 param_env: ty::ParamEnv<'tcx>)
+                                 -> Self;
 }
 
 macro_rules! items { ($($item:item)+) => ($($item)+) }
@@ -584,9 +552,10 @@ macro_rules! impl_trans_normalize {
     ($lt_gcx:tt, $($ty:ty),+) => {
         items!($(impl<$lt_gcx> TransNormalize<$lt_gcx> for $ty {
             fn trans_normalize<'a, 'tcx>(&self,
-                                         infcx: &InferCtxt<'a, $lt_gcx, 'tcx>)
+                                         infcx: &InferCtxt<'a, $lt_gcx, 'tcx>,
+                                         param_env: ty::ParamEnv<'tcx>)
                                          -> Self {
-                infcx.normalize_projections_in(self)
+                infcx.normalize_projections_in(param_env, self)
             }
         })+);
     }
@@ -603,13 +572,16 @@ fn trans_normalize<'a, 'tcx>(&self,
 );
 
 impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {
-    fn trans_normalize<'a, 'tcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self {
+    fn trans_normalize<'a, 'tcx>(&self,
+                                 infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                 param_env: ty::ParamEnv<'tcx>)
+                                 -> Self {
         match *self {
-            LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.trans_normalize(infcx) },
+            LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.trans_normalize(infcx, param_env) },
             LvalueTy::Downcast { adt_def, substs, variant_index } => {
                 LvalueTy::Downcast {
                     adt_def: adt_def,
-                    substs: substs.trans_normalize(infcx),
+                    substs: substs.trans_normalize(infcx, param_env),
                     variant_index: variant_index
                 }
             }
@@ -631,22 +603,30 @@ pub fn erase_late_bound_regions_and_normalize<T>(self, value: &ty::Binder<T>)
         self.normalize_associated_type(&value)
     }
 
+    /// Fully normalizes any associated types in `value`, using an
+    /// empty environment and `Reveal::All` mode (therefore, suitable
+    /// only for monomorphized code during trans, basically).
     pub fn normalize_associated_type<T>(self, value: &T) -> T
         where T: TransNormalize<'tcx>
     {
         debug!("normalize_associated_type(t={:?})", value);
 
+        let param_env = ty::ParamEnv::empty(Reveal::All);
         let value = self.erase_regions(value);
 
         if !value.has_projection_types() {
             return value;
         }
 
-        self.infer_ctxt((), Reveal::All).enter(|infcx| {
-            value.trans_normalize(&infcx)
+        self.infer_ctxt(()).enter(|infcx| {
+            value.trans_normalize(&infcx, param_env)
         })
     }
 
+    /// Does a best-effort to normalize any associated types in
+    /// `value`; this includes revealing specializable types, so this
+    /// should be not be used during type-checking, but only during
+    /// optimization and code generation.
     pub fn normalize_associated_type_in_env<T>(
         self, value: &T, env: ty::ParamEnv<'tcx>
     ) -> T
@@ -660,20 +640,20 @@ pub fn normalize_associated_type_in_env<T>(
             return value;
         }
 
-        self.infer_ctxt(env, Reveal::All).enter(|infcx| {
-            value.trans_normalize(&infcx)
+        self.infer_ctxt(()).enter(|infcx| {
+            value.trans_normalize(&infcx, env.reveal_all())
        })
     }
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    fn normalize_projections_in<T>(&self, value: &T) -> T::Lifted
+    fn normalize_projections_in<T>(&self, param_env: ty::ParamEnv<'tcx>, value: &T) -> T::Lifted
         where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
     {
         let mut selcx = traits::SelectionContext::new(self);
         let cause = traits::ObligationCause::dummy();
         let traits::Normalized { value: result, obligations } =
-            traits::normalize(&mut selcx, cause, value);
+            traits::normalize(&mut selcx, param_env, cause, value);
 
         debug!("normalize_projections_in: result={:?} obligations={:?}",
                 result, obligations);
@@ -727,10 +707,6 @@ pub fn drain_fulfillment_cx_or_panic<T>(&self,
         }
     }
 
-    pub fn projection_mode(&self) -> Reveal {
-        self.projection_mode
-    }
-
     pub fn is_in_snapshot(&self) -> bool {
         self.in_snapshot.get()
     }
@@ -816,52 +792,17 @@ pub fn unsolved_variables(&self) -> Vec<ty::Ty<'tcx>> {
         return variables;
     }
 
-    fn combine_fields(&'a self, trace: TypeTrace<'tcx>)
+    fn combine_fields(&'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>)
                       -> CombineFields<'a, 'gcx, 'tcx> {
         CombineFields {
             infcx: self,
             trace: trace,
             cause: None,
+            param_env,
             obligations: PredicateObligations::new(),
         }
     }
 
-    pub fn equate<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-        -> InferResult<'tcx, T>
-        where T: Relate<'tcx>
-    {
-        let mut fields = self.combine_fields(trace);
-        let result = fields.equate(a_is_expected).relate(a, b);
-        result.map(move |t| InferOk { value: t, obligations: fields.obligations })
-    }
-
-    pub fn sub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-        -> InferResult<'tcx, T>
-        where T: Relate<'tcx>
-    {
-        let mut fields = self.combine_fields(trace);
-        let result = fields.sub(a_is_expected).relate(a, b);
-        result.map(move |t| InferOk { value: t, obligations: fields.obligations })
-    }
-
-    pub fn lub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-        -> InferResult<'tcx, T>
-        where T: Relate<'tcx>
-    {
-        let mut fields = self.combine_fields(trace);
-        let result = fields.lub(a_is_expected).relate(a, b);
-        result.map(move |t| InferOk { value: t, obligations: fields.obligations })
-    }
-
-    pub fn glb<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-        -> InferResult<'tcx, T>
-        where T: Relate<'tcx>
-    {
-        let mut fields = self.combine_fields(trace);
-        let result = fields.glb(a_is_expected).relate(a, b);
-        result.map(move |t| InferOk { value: t, obligations: fields.obligations })
-    }
-
     // Clear the "currently in a snapshot" flag, invoke the closure,
     // then restore the flag to its original value. This flag is a
     // debugging measure designed to detect cases where we start a
@@ -888,7 +829,7 @@ pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R
         result
     }
 
-    fn start_snapshot(&self) -> CombinedSnapshot {
+    fn start_snapshot<'b>(&'b self) -> CombinedSnapshot<'b, 'tcx> {
         debug!("start_snapshot()");
 
         let in_snapshot = self.in_snapshot.get();
@@ -901,6 +842,12 @@ fn start_snapshot(&self) -> CombinedSnapshot {
             float_snapshot: self.float_unification_table.borrow_mut().snapshot(),
             region_vars_snapshot: self.region_vars.start_snapshot(),
             was_in_snapshot: in_snapshot,
+            // Borrow tables "in progress" (i.e. during typeck)
+            // to ban writes from within a snapshot to them.
+            _in_progress_tables: match self.tables {
+                InferTables::InProgress(ref tables) => tables.try_borrow().ok(),
+                _ => None
+            }
         }
     }
 
@@ -911,7 +858,8 @@ fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot) {
                                int_snapshot,
                                float_snapshot,
                                region_vars_snapshot,
-                               was_in_snapshot } = snapshot;
+                               was_in_snapshot,
+                               _in_progress_tables } = snapshot;
 
         self.in_snapshot.set(was_in_snapshot);
 
@@ -938,7 +886,8 @@ fn commit_from(&self, snapshot: CombinedSnapshot) {
                                int_snapshot,
                                float_snapshot,
                                region_vars_snapshot,
-                               was_in_snapshot } = snapshot;
+                               was_in_snapshot,
+                               _in_progress_tables } = snapshot;
 
         self.in_snapshot.set(was_in_snapshot);
 
@@ -1013,94 +962,35 @@ pub fn add_given(&self,
         self.region_vars.add_given(sub, sup);
     }
 
-    pub fn sub_types(&self,
-                     a_is_expected: bool,
-                     cause: &ObligationCause<'tcx>,
-                     a: Ty<'tcx>,
-                     b: Ty<'tcx>)
-        -> InferResult<'tcx, ()>
-    {
-        debug!("sub_types({:?} <: {:?})", a, b);
-        self.commit_if_ok(|_| {
-            let trace = TypeTrace::types(cause, a_is_expected, a, b);
-            self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
-        })
-    }
-
-    pub fn can_sub_types(&self,
-                         a: Ty<'tcx>,
-                         b: Ty<'tcx>)
-                         -> UnitResult<'tcx>
+    pub fn can_sub<T>(&self,
+                      param_env: ty::ParamEnv<'tcx>,
+                      a: T,
+                      b: T)
+                      -> UnitResult<'tcx>
+        where T: at::ToTrace<'tcx>
     {
+        let origin = &ObligationCause::dummy();
         self.probe(|_| {
-            let origin = &ObligationCause::dummy();
-            let trace = TypeTrace::types(origin, true, a, b);
-            self.sub(true, trace, &a, &b).map(|InferOk { obligations: _, .. }| {
+            self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| {
                 // Ignore obligations, since we are unrolling
                 // everything anyway.
             })
         })
     }
 
-    pub fn eq_types(&self,
-                    a_is_expected: bool,
-                    cause: &ObligationCause<'tcx>,
-                    a: Ty<'tcx>,
-                    b: Ty<'tcx>)
-        -> InferResult<'tcx, ()>
-    {
-        self.commit_if_ok(|_| {
-            let trace = TypeTrace::types(cause, a_is_expected, a, b);
-            self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
-        })
-    }
-
-    pub fn eq_trait_refs(&self,
-                          a_is_expected: bool,
-                          cause: &ObligationCause<'tcx>,
-                          a: ty::TraitRef<'tcx>,
-                          b: ty::TraitRef<'tcx>)
-        -> InferResult<'tcx, ()>
-    {
-        debug!("eq_trait_refs({:?} = {:?})", a, b);
-        self.commit_if_ok(|_| {
-            let trace = TypeTrace {
-                cause: cause.clone(),
-                values: TraitRefs(ExpectedFound::new(a_is_expected, a, b))
-            };
-            self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
-        })
-    }
-
-    pub fn eq_impl_headers(&self,
-                           a_is_expected: bool,
-                           cause: &ObligationCause<'tcx>,
-                           a: &ty::ImplHeader<'tcx>,
-                           b: &ty::ImplHeader<'tcx>)
-                           -> InferResult<'tcx, ()>
-    {
-        debug!("eq_impl_header({:?} = {:?})", a, b);
-        match (a.trait_ref, b.trait_ref) {
-            (Some(a_ref), Some(b_ref)) => self.eq_trait_refs(a_is_expected, cause, a_ref, b_ref),
-            (None, None) => self.eq_types(a_is_expected, cause, a.self_ty, b.self_ty),
-            _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
-        }
-    }
-
-    pub fn sub_poly_trait_refs(&self,
-                               a_is_expected: bool,
-                               cause: ObligationCause<'tcx>,
-                               a: ty::PolyTraitRef<'tcx>,
-                               b: ty::PolyTraitRef<'tcx>)
-        -> InferResult<'tcx, ()>
+    pub fn can_eq<T>(&self,
+                      param_env: ty::ParamEnv<'tcx>,
+                      a: T,
+                      b: T)
+                      -> UnitResult<'tcx>
+        where T: at::ToTrace<'tcx>
     {
-        debug!("sub_poly_trait_refs({:?} <: {:?})", a, b);
-        self.commit_if_ok(|_| {
-            let trace = TypeTrace {
-                cause: cause,
-                values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b))
-            };
-            self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
+        let origin = &ObligationCause::dummy();
+        self.probe(|_| {
+            self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| {
+                // Ignore obligations, since we are unrolling
+                // everything anyway.
+            })
         })
     }
 
@@ -1114,6 +1004,7 @@ pub fn sub_regions(&self,
 
     pub fn equality_predicate(&self,
                               cause: &ObligationCause<'tcx>,
+                              param_env: ty::ParamEnv<'tcx>,
                               predicate: &ty::PolyEquatePredicate<'tcx>)
         -> InferResult<'tcx, ()>
     {
@@ -1121,7 +1012,7 @@ pub fn equality_predicate(&self,
             let (ty::EquatePredicate(a, b), skol_map) =
                 self.skolemize_late_bound_regions(predicate, snapshot);
             let cause_span = cause.span;
-            let eqty_ok = self.eq_types(false, cause, a, b)?;
+            let eqty_ok = self.at(cause, param_env).eq(b, a)?;
             self.leak_check(false, cause_span, &skol_map, snapshot)?;
             self.pop_skolemized(skol_map, snapshot);
             Ok(eqty_ok.unit())
@@ -1130,6 +1021,7 @@ pub fn equality_predicate(&self,
 
     pub fn subtype_predicate(&self,
                              cause: &ObligationCause<'tcx>,
+                             param_env: ty::ParamEnv<'tcx>,
                              predicate: &ty::PolySubtypePredicate<'tcx>)
         -> Option<InferResult<'tcx, ()>>
     {
@@ -1158,7 +1050,7 @@ pub fn subtype_predicate(&self,
                 self.skolemize_late_bound_regions(predicate, snapshot);
 
             let cause_span = cause.span;
-            let ok = self.sub_types(a_is_expected, cause, a, b)?;
+            let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
             self.leak_check(false, cause_span, &skol_map, snapshot)?;
             self.pop_skolemized(skol_map, snapshot);
             Ok(ok.unit())
@@ -1560,6 +1452,7 @@ pub fn replace_late_bound_regions_with_fresh_var<T>(
     /// details.
     pub fn match_poly_projection_predicate(&self,
                                            cause: ObligationCause<'tcx>,
+                                           param_env: ty::ParamEnv<'tcx>,
                                            match_a: ty::PolyProjectionPredicate<'tcx>,
                                            match_b: ty::TraitRef<'tcx>)
                                            -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>>
@@ -1572,7 +1465,7 @@ pub fn match_poly_projection_predicate(&self,
         };
 
         let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty));
-        let mut combine = self.combine_fields(trace);
+        let mut combine = self.combine_fields(trace, param_env);
         let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?;
         Ok(InferOk { value: result, obligations: combine.obligations })
     }
@@ -1591,27 +1484,6 @@ pub fn verify_generic_bound(&self,
         self.region_vars.verify_generic_bound(origin, kind, a, bound);
     }
 
-    pub fn can_equate<T>(&self, a: &T, b: &T) -> UnitResult<'tcx>
-        where T: Relate<'tcx> + fmt::Debug
-    {
-        debug!("can_equate({:?}, {:?})", a, b);
-        self.probe(|_| {
-            // Gin up a dummy trace, since this won't be committed
-            // anyhow. We should make this typetrace stuff more
-            // generic so we don't have to do anything quite this
-            // terrible.
-            let trace = TypeTrace::dummy(self.tcx);
-            self.equate(true, trace, a, b).map(|InferOk { obligations: _, .. }| {
-                // We can intentionally ignore obligations here, since
-                // this is part of a simple test for general
-                // "equatability". However, it's not entirely clear
-                // that we *ought* to be, perhaps a better thing would
-                // be to use a mini-fulfillment context or something
-                // like that.
-            })
-        })
-    }
-
     pub fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
         let ty = self.node_type(id);
         self.resolve_type_vars_or_error(&ty)
@@ -1622,9 +1494,13 @@ pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
         self.resolve_type_vars_or_error(&ty)
     }
 
-    pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
+    pub fn type_moves_by_default(&self,
+                                 param_env: ty::ParamEnv<'tcx>,
+                                 ty: Ty<'tcx>,
+                                 span: Span)
+                                 -> bool {
         let ty = self.resolve_type_vars_if_possible(&ty);
-        if let Some(ty) = self.tcx.lift_to_global(&ty) {
+        if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) {
             // Even if the type may have no inference variables, during
             // type-checking closure types are in local tables only.
             let local_closures = match self.tables {
@@ -1632,7 +1508,7 @@ pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
                 _ => false
             };
             if !local_closures {
-                return ty.moves_by_default(self.tcx.global_tcx(), self.param_env(), span);
+                return ty.moves_by_default(self.tcx.global_tcx(), param_env, span);
             }
         }
 
@@ -1642,40 +1518,13 @@ pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
         // rightly refuses to work with inference variables, but
         // moves_by_default has a cache, which we want to use in other
         // cases.
-        !traits::type_known_to_meet_bound(self, ty, copy_def_id, span)
-    }
-
-    pub fn node_method_ty(&self, method_call: ty::MethodCall)
-                          -> Option<Ty<'tcx>> {
-        self.tables
-            .borrow()
-            .method_map
-            .get(&method_call)
-            .map(|method| method.ty)
-            .map(|ty| self.resolve_type_vars_if_possible(&ty))
-    }
-
-    pub fn node_method_id(&self, method_call: ty::MethodCall)
-                          -> Option<DefId> {
-        self.tables
-            .borrow()
-            .method_map
-            .get(&method_call)
-            .map(|method| method.def_id)
-    }
-
-    pub fn is_method_call(&self, id: ast::NodeId) -> bool {
-        self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id))
+        !traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
     }
 
     pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
         self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
     }
 
-    pub fn param_env(&self) -> ty::ParamEnv<'gcx> {
-        self.param_env
-    }
-
     pub fn closure_kind(&self,
                         def_id: DefId)
                         -> Option<ty::ClosureKind>
index 487195fdfae9f833bff88a645ab6691bbab8c6de..405699968135243e5cb4ab974837fe07150e817f 100644 (file)
@@ -96,6 +96,7 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 self.fields.obligations.push(
                     Obligation::new(
                         self.fields.trace.cause.clone(),
+                        self.fields.param_env,
                         ty::Predicate::Subtype(
                             ty::Binder(ty::SubtypePredicate {
                                 a_is_expected: self.a_is_expected,
index 2a877aca53b7cb618d7b4bed10b97c50df360317..2216103636fb6c7821bfbb8b0fda714b129d02be 100644 (file)
@@ -47,7 +47,7 @@
 #![cfg_attr(stage0, feature(staged_api))]
 #![cfg_attr(stage0, feature(loop_break_value))]
 
-#![recursion_limit="192"]
+#![recursion_limit="256"]
 
 extern crate arena;
 extern crate core;
index 6597db9e19bd9e2d49cf0b4c2d39bb1148f70145..71b066c6688b583e0b26c9121e9c384cba600c4c 100644 (file)
@@ -26,7 +26,8 @@
 use dep_graph::DepNode;
 use hir::def_id::{CrateNum, DefId, DefIndex};
 use hir::map as hir_map;
-use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData};
+use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData,
+                            DefPathTable};
 use hir::svh::Svh;
 use ich;
 use middle::lang_items;
@@ -281,7 +282,8 @@ fn retrace_path(&self,
                     -> Option<DefId>;
     fn def_key(&self, def: DefId) -> DefKey;
     fn def_path(&self, def: DefId) -> hir_map::DefPath;
-    fn def_path_hash(&self, def: DefId) -> ich::Fingerprint;
+    fn def_path_hash(&self, def: DefId) -> hir_map::DefPathHash;
+    fn def_path_table(&self, cnum: CrateNum) -> Rc<DefPathTable>;
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>;
     fn item_children(&self, did: DefId) -> Vec<def::Export>;
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
@@ -412,8 +414,11 @@ fn def_key(&self, def: DefId) -> DefKey { bug!("def_key") }
     fn def_path(&self, def: DefId) -> hir_map::DefPath {
         bug!("relative_def_path")
     }
-    fn def_path_hash(&self, def: DefId) -> ich::Fingerprint {
-        bug!("wa")
+    fn def_path_hash(&self, def: DefId) -> hir_map::DefPathHash {
+        bug!("def_path_hash")
+    }
+    fn def_path_table(&self, cnum: CrateNum) -> Rc<DefPathTable> {
+        bug!("def_path_table")
     }
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { bug!("struct_field_names") }
     fn item_children(&self, did: DefId) -> Vec<def::Export> { bug!("item_children") }
index 84ead6506c85c16d9b54da4eb58a35a4b7ba0481..6077b7863e2c3d034a59f8548df12fb21e9d8208 100644 (file)
@@ -95,9 +95,7 @@ fn handle_definition(&mut self, def: Def) {
     }
 
     fn lookup_and_handle_method(&mut self, id: ast::NodeId) {
-        let method_call = ty::MethodCall::expr(id);
-        let method = self.tables.method_map[&method_call];
-        self.check_def_id(method.def_id);
+        self.check_def_id(self.tables.type_dependent_defs[&id].def_id());
     }
 
     fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
index 2261f296454ef75470a7f648ff1e6c665cc644ab..74e1225f3948b92e9ab52e93f016ba48271a3d9e 100644 (file)
@@ -13,7 +13,6 @@
 use self::RootUnsafeContext::*;
 
 use ty::{self, Ty, TyCtxt};
-use ty::MethodCall;
 use lint;
 
 use syntax::ast;
@@ -174,8 +173,8 @@ fn visit_block(&mut self, block: &'tcx hir::Block) {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         match expr.node {
             hir::ExprMethodCall(..) => {
-                let method_call = MethodCall::expr(expr.id);
-                let base_type = self.tables.method_map[&method_call].ty;
+                let def_id = self.tables.type_dependent_defs[&expr.id].def_id();
+                let base_type = self.tcx.type_of(def_id);
                 debug!("effect: method call case, base type is {:?}",
                         base_type);
                 if type_is_unsafe_function(base_type) {
index 99b140f690a4848cda6ee003634a45f7cb321ed9..0b2652c748816c5355eb236a0def7b72c1884746 100644 (file)
@@ -242,6 +242,7 @@ fn from_method_id(tcx: TyCtxt, method_id: DefId) -> OverloadedCallType {
 pub struct ExprUseVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>,
     delegate: &'a mut Delegate<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
 }
 
 // If the TYPER results in an error, it's because the type check
@@ -263,33 +264,31 @@ macro_rules! return_if_err {
     )
 }
 
-/// Whether the elements of an overloaded operation are passed by value or by reference
-enum PassArgs {
-    ByValue,
-    ByRef,
-}
-
 impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
                region_maps: &'a RegionMaps,
-               infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
+               infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+               param_env: ty::ParamEnv<'tcx>)
                -> Self
     {
         ExprUseVisitor::with_options(delegate,
                                      infcx,
+                                     param_env,
                                      region_maps,
                                      mc::MemCategorizationOptions::default())
     }
 
     pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
                         infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+                        param_env: ty::ParamEnv<'tcx>,
                         region_maps: &'a RegionMaps,
                         options: mc::MemCategorizationOptions)
                -> Self
     {
         ExprUseVisitor {
             mc: mc::MemCategorizationContext::with_options(infcx, region_maps, options),
-            delegate: delegate
+            delegate,
+            param_env,
         }
     }
 
@@ -304,7 +303,6 @@ pub fn consume_body(&mut self, body: &hir::Body) {
                 arg.id,
                 arg.pat.span,
                 fn_body_scope_r, // Args live only as long as the fn body.
-                fn_body_scope_r,
                 arg_ty);
 
             self.walk_irrefutable_pat(arg_cmt, &arg.pat);
@@ -324,7 +322,7 @@ fn delegate_consume(&mut self,
         debug!("delegate_consume(consume_id={}, cmt={:?})",
                consume_id, cmt);
 
-        let mode = copy_or_move(self.mc.infcx, &cmt, DirectRefMove);
+        let mode = copy_or_move(self.mc.infcx, self.param_env, &cmt, DirectRefMove);
         self.delegate.consume(consume_id, consume_span, cmt, mode);
     }
 
@@ -382,9 +380,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
             }
 
             hir::ExprUnary(hir::UnDeref, ref base) => {      // *base
-                if !self.walk_overloaded_operator(expr, &base, Vec::new(), PassArgs::ByRef) {
-                    self.select_from_expr(&base);
-                }
+                self.select_from_expr(&base);
             }
 
             hir::ExprField(ref base, _) => {         // base.f
@@ -396,13 +392,8 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
             }
 
             hir::ExprIndex(ref lhs, ref rhs) => {       // lhs[rhs]
-                if !self.walk_overloaded_operator(expr,
-                                                  &lhs,
-                                                  vec![&rhs],
-                                                  PassArgs::ByValue) {
-                    self.select_from_expr(&lhs);
-                    self.consume_expr(&rhs);
-                }
+                self.select_from_expr(&lhs);
+                self.consume_expr(&rhs);
             }
 
             hir::ExprCall(ref callee, ref args) => {    // callee(args)
@@ -485,29 +476,13 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
                 self.walk_block(&blk);
             }
 
-            hir::ExprUnary(op, ref lhs) => {
-                let pass_args = if op.is_by_value() {
-                    PassArgs::ByValue
-                } else {
-                    PassArgs::ByRef
-                };
-
-                if !self.walk_overloaded_operator(expr, &lhs, Vec::new(), pass_args) {
-                    self.consume_expr(&lhs);
-                }
+            hir::ExprUnary(_, ref lhs) => {
+                self.consume_expr(&lhs);
             }
 
-            hir::ExprBinary(op, ref lhs, ref rhs) => {
-                let pass_args = if op.node.is_by_value() {
-                    PassArgs::ByValue
-                } else {
-                    PassArgs::ByRef
-                };
-
-                if !self.walk_overloaded_operator(expr, &lhs, vec![&rhs], pass_args) {
-                    self.consume_expr(&lhs);
-                    self.consume_expr(&rhs);
-                }
+            hir::ExprBinary(_, ref lhs, ref rhs) => {
+                self.consume_expr(&lhs);
+                self.consume_expr(&rhs);
             }
 
             hir::ExprBlock(ref blk) => {
@@ -529,14 +504,13 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
                 self.consume_expr(&base);
             }
 
-            hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-                // NB All our assignment operations take the RHS by value
-                assert!(op.node.is_by_value());
-
-                if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) {
+            hir::ExprAssignOp(_, ref lhs, ref rhs) => {
+                if self.mc.infcx.tables.borrow().is_method_call(expr) {
+                    self.consume_expr(lhs);
+                } else {
                     self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead);
-                    self.consume_expr(&rhs);
                 }
+                self.consume_expr(&rhs);
             }
 
             hir::ExprRepeat(ref base, _) => {
@@ -563,19 +537,8 @@ fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) {
             }
             ty::TyError => { }
             _ => {
-                let overloaded_call_type =
-                    match self.mc.infcx.node_method_id(ty::MethodCall::expr(call.id)) {
-                        Some(method_id) => {
-                            OverloadedCallType::from_method_id(self.tcx(), method_id)
-                        }
-                        None => {
-                            span_bug!(
-                                callee.span,
-                                "unexpected callee type {}",
-                                callee_ty)
-                        }
-                    };
-                match overloaded_call_type {
+                let def_id = self.mc.infcx.tables.borrow().type_dependent_defs[&call.id].def_id();
+                match OverloadedCallType::from_method_id(self.tcx(), def_id) {
                     FnMutOverloadedCall => {
                         let call_scope_r = self.tcx().node_scope_region(call.id);
                         self.borrow_expr(callee,
@@ -715,102 +678,55 @@ fn contains_field_named(field: &ty::FieldDef,
     // consumed or borrowed as part of the automatic adjustment
     // process.
     fn walk_adjustment(&mut self, expr: &hir::Expr) {
-        let infcx = self.mc.infcx;
         //NOTE(@jroesch): mixed RefCell borrow causes crash
-        let adj = infcx.tables.borrow().adjustments.get(&expr.id).map(|x| x.clone());
-        if let Some(adjustment) = adj {
+        let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec();
+        let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr));
+        for adjustment in adjustments {
+            debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
             match adjustment.kind {
                 adjustment::Adjust::NeverToAny |
                 adjustment::Adjust::ReifyFnPointer |
                 adjustment::Adjust::UnsafeFnPointer |
                 adjustment::Adjust::ClosureFnPointer |
-                adjustment::Adjust::MutToConstPointer => {
+                adjustment::Adjust::MutToConstPointer |
+                adjustment::Adjust::Unsize => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
-                    debug!("walk_adjustment: trivial adjustment");
-                    let cmt_unadjusted =
-                        return_if_err!(self.mc.cat_expr_unadjusted(expr));
-                    self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
+                    self.delegate_consume(expr.id, expr.span, cmt.clone());
                 }
-                adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => {
-                    debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
 
-                    self.walk_autoderefs(expr, autoderefs);
-
-                    let cmt_derefd =
-                        return_if_err!(self.mc.cat_expr_autoderefd(expr, autoderefs));
-
-                    let cmt_refd =
-                        self.walk_autoref(expr, cmt_derefd, autoref);
-
-                    if unsize {
-                        // Unsizing consumes the thin pointer and produces a fat one.
-                        self.delegate_consume(expr.id, expr.span, cmt_refd);
-                    }
+                adjustment::Adjust::Deref(None) => {}
+
+                // Autoderefs for overloaded Deref calls in fact reference
+                // their receiver. That is, if we have `(*x)` where `x`
+                // is of type `Rc<T>`, then this in fact is equivalent to
+                // `x.deref()`. Since `deref()` is declared with `&self`,
+                // this is an autoref of `x`.
+                adjustment::Adjust::Deref(Some(ref deref)) => {
+                    let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
+                    self.delegate.borrow(expr.id, expr.span, cmt.clone(),
+                                         deref.region, bk, AutoRef);
                 }
-            }
-        }
-    }
 
-    /// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have
-    /// `(*x)` where `x` is of type `Rc<T>`, then this in fact is equivalent to `x.deref()`. Since
-    /// `deref()` is declared with `&self`, this is an autoref of `x`.
-    fn walk_autoderefs(&mut self,
-                       expr: &hir::Expr,
-                       autoderefs: usize) {
-        debug!("walk_autoderefs expr={:?} autoderefs={}", expr, autoderefs);
-
-        for i in 0..autoderefs {
-            let deref_id = ty::MethodCall::autoderef(expr.id, i as u32);
-            if let Some(method_ty) = self.mc.infcx.node_method_ty(deref_id) {
-                let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i));
-
-                // the method call infrastructure should have
-                // replaced all late-bound regions with variables:
-                let self_ty = method_ty.fn_sig().input(0);
-                let self_ty = self.tcx().no_late_bound_regions(&self_ty).unwrap();
-
-                let (m, r) = match self_ty.sty {
-                    ty::TyRef(r, ref m) => (m.mutbl, r),
-                    _ => span_bug!(expr.span,
-                                   "bad overloaded deref type {:?}",
-                                   method_ty)
-                };
-                let bk = ty::BorrowKind::from_mutbl(m);
-                self.delegate.borrow(expr.id, expr.span, cmt,
-                                     r, bk, AutoRef);
+                adjustment::Adjust::Borrow(ref autoref) => {
+                    self.walk_autoref(expr, cmt.clone(), autoref);
+                }
             }
+            cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment));
         }
     }
 
-    /// Walks the autoref `opt_autoref` applied to the autoderef'd
-    /// `expr`. `cmt_derefd` is the mem-categorized form of `expr`
-    /// after all relevant autoderefs have occurred. Because AutoRefs
-    /// can be recursive, this function is recursive: it first walks
-    /// deeply all the way down the autoref chain, and then processes
-    /// the autorefs on the way out. At each point, it returns the
-    /// `cmt` for the rvalue that will be produced by introduced an
-    /// autoref.
+    /// Walks the autoref `autoref` applied to the autoderef'd
+    /// `expr`. `cmt_base` is the mem-categorized form of `expr`
+    /// after all relevant autoderefs have occurred.
     fn walk_autoref(&mut self,
                     expr: &hir::Expr,
                     cmt_base: mc::cmt<'tcx>,
-                    opt_autoref: Option<adjustment::AutoBorrow<'tcx>>)
-                    -> mc::cmt<'tcx>
-    {
-        debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
+                    autoref: &adjustment::AutoBorrow<'tcx>) {
+        debug!("walk_autoref(expr.id={} cmt_base={:?} autoref={:?})",
                expr.id,
                cmt_base,
-               opt_autoref);
-
-        let cmt_base_ty = cmt_base.ty;
-
-        let autoref = match opt_autoref {
-            Some(ref autoref) => autoref,
-            None => {
-                // No AutoRef.
-                return cmt_base;
-            }
-        };
+               autoref);
 
         match *autoref {
             adjustment::AutoBorrow::Ref(r, m) => {
@@ -840,58 +756,6 @@ fn walk_autoref(&mut self,
                                      AutoUnsafe);
             }
         }
-
-        // Construct the categorization for the result of the autoref.
-        // This is always an rvalue, since we are producing a new
-        // (temporary) indirection.
-
-        let adj_ty = cmt_base_ty.adjust_for_autoref(self.tcx(), opt_autoref);
-
-        self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty)
-    }
-
-
-    // When this returns true, it means that the expression *is* a
-    // method-call (i.e. via the operator-overload).  This true result
-    // also implies that walk_overloaded_operator already took care of
-    // recursively processing the input arguments, and thus the caller
-    // should not do so.
-    fn walk_overloaded_operator(&mut self,
-                                expr: &hir::Expr,
-                                receiver: &hir::Expr,
-                                rhs: Vec<&hir::Expr>,
-                                pass_args: PassArgs)
-                                -> bool
-    {
-        if !self.mc.infcx.is_method_call(expr.id) {
-            return false;
-        }
-
-        match pass_args {
-            PassArgs::ByValue => {
-                self.consume_expr(receiver);
-                for &arg in &rhs {
-                    self.consume_expr(arg);
-                }
-
-                return true;
-            },
-            PassArgs::ByRef => {},
-        }
-
-        self.walk_expr(receiver);
-
-        // Arguments (but not receivers) to overloaded operator
-        // methods are implicitly autoref'd which sadly does not use
-        // adjustments, so we must hardcode the borrow here.
-
-        let r = self.tcx().node_scope_region(expr.id);
-        let bk = ty::ImmBorrow;
-
-        for &arg in &rhs {
-            self.borrow_expr(arg, r, bk, OverloadedOperator);
-        }
-        return true;
     }
 
     fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode {
@@ -937,7 +801,7 @@ fn determine_pat_move_mode(&mut self,
                 PatKind::Binding(hir::BindByRef(..), ..) =>
                     mode.lub(BorrowingMatch),
                 PatKind::Binding(hir::BindByValue(..), ..) => {
-                    match copy_or_move(self.mc.infcx, &cmt_pat, PatBindingMove) {
+                    match copy_or_move(self.mc.infcx, self.param_env, &cmt_pat, PatBindingMove) {
                         Copy => mode.lub(CopyingMatch),
                         Move(..) => mode.lub(MovingMatch),
                     }
@@ -953,10 +817,9 @@ fn determine_pat_move_mode(&mut self,
     fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) {
         debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat);
 
-        let tcx = &self.tcx();
-        let mc = &self.mc;
+        let tcx = self.tcx();
         let infcx = self.mc.infcx;
-        let delegate = &mut self.delegate;
+        let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self;
         return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
             if let PatKind::Binding(bmode, def_id, ..) = pat.node {
                 debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
@@ -980,7 +843,7 @@ fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: Mat
                         }
                     }
                     hir::BindByValue(..) => {
-                        let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove);
+                        let mode = copy_or_move(infcx, param_env, &cmt_pat, PatBindingMove);
                         debug!("walk_pat binding consuming pat");
                         delegate.consume_pat(pat, cmt_pat, mode);
                     }
@@ -1039,7 +902,10 @@ fn walk_captures(&mut self, closure_expr: &hir::Expr, fn_decl_span: Span) {
                                                                    freevar.def));
                 match upvar_capture {
                     ty::UpvarCapture::ByValue => {
-                        let mode = copy_or_move(self.mc.infcx, &cmt_var, CaptureMove);
+                        let mode = copy_or_move(self.mc.infcx,
+                                                self.param_env,
+                                                &cmt_var,
+                                                CaptureMove);
                         self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
                     }
                     ty::UpvarCapture::ByRef(upvar_borrow) => {
@@ -1069,11 +935,12 @@ fn cat_captured_var(&mut self,
 }
 
 fn copy_or_move<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                param_env: ty::ParamEnv<'tcx>,
                                 cmt: &mc::cmt<'tcx>,
                                 move_reason: MoveReason)
                                 -> ConsumeMode
 {
-    if infcx.type_moves_by_default(cmt.ty, cmt.span) {
+    if infcx.type_moves_by_default(param_env, cmt.ty, cmt.span) {
         Move(move_reason)
     } else {
         Copy
index a759a9061f8428874475d8a2f61be1e8426d6057..57815b7f0b690b68cc85a0b3aaffb28cdec53fce 100644 (file)
@@ -10,8 +10,6 @@
 
 use hir::def::Def;
 use hir::def_id::DefId;
-use infer::InferCtxt;
-use traits::Reveal;
 use ty::{self, Ty, TyCtxt};
 use ty::layout::{LayoutError, Pointer, SizeSkeleton};
 
@@ -31,8 +29,10 @@ struct ItemVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>
 }
 
-struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>
+struct ExprVisitor<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    tables: &'tcx ty::TypeckTables<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
 }
 
 /// If the type is `Option<T>`, it will return `T`, otherwise
@@ -64,18 +64,18 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     ty
 }
 
-impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx> ExprVisitor<'a, 'tcx> {
     fn def_id_is_transmute(&self, def_id: DefId) -> bool {
-        let intrinsic = match self.infcx.tcx.type_of(def_id).sty {
+        let intrinsic = match self.tcx.type_of(def_id).sty {
             ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic,
             _ => return false
         };
-        intrinsic && self.infcx.tcx.item_name(def_id) == "transmute"
+        intrinsic && self.tcx.item_name(def_id) == "transmute"
     }
 
-    fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>) {
-        let sk_from = SizeSkeleton::compute(from, self.infcx);
-        let sk_to = SizeSkeleton::compute(to, self.infcx);
+    fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
+        let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env);
+        let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env);
 
         // Check for same size using the skeletons.
         if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
@@ -85,11 +85,11 @@ fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>) {
 
             // Special-case transmutting from `typeof(function)` and
             // `Option<typeof(function)>` to present a clearer error.
-            let from = unpack_option_like(self.infcx.tcx.global_tcx(), from);
+            let from = unpack_option_like(self.tcx.global_tcx(), from);
             match (&from.sty, sk_to) {
                 (&ty::TyFnDef(..), SizeSkeleton::Known(size_to))
-                        if size_to == Pointer.size(self.infcx) => {
-                    struct_span_err!(self.infcx.tcx.sess, span, E0591,
+                        if size_to == Pointer.size(self.tcx) => {
+                    struct_span_err!(self.tcx.sess, span, E0591,
                                      "`{}` is zero-sized and can't be transmuted to `{}`",
                                      from, to)
                         .span_note(span, "cast with `as` to a pointer instead")
@@ -101,7 +101,7 @@ fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>) {
         }
 
         // Try to display a sensible error with as much information as possible.
-        let skeleton_string = |ty: Ty<'gcx>, sk| {
+        let skeleton_string = |ty: Ty<'tcx>, sk| {
             match sk {
                 Ok(SizeSkeleton::Known(size)) => {
                     format!("{} bits", size.bits())
@@ -120,7 +120,7 @@ fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>) {
             }
         };
 
-        struct_span_err!(self.infcx.tcx.sess, span, E0512,
+        struct_span_err!(self.tcx.sess, span, E0512,
                   "transmute called with differently sized types: \
                    {} ({}) to {} ({})",
                   from, skeleton_string(from, sk_from),
@@ -139,32 +139,30 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
+        let owner_def_id = self.tcx.hir.body_owner_def_id(body_id);
         let body = self.tcx.hir.body(body_id);
-        self.tcx.infer_ctxt(body_id, Reveal::All).enter(|infcx| {
-            let mut visitor = ExprVisitor {
-                infcx: &infcx
-            };
-            visitor.visit_body(body);
-        });
+        let param_env = self.tcx.param_env(owner_def_id);
+        let tables = self.tcx.typeck_tables_of(owner_def_id);
+        ExprVisitor { tcx: self.tcx, param_env, tables }.visit_body(body);
         self.visit_body(body);
     }
 }
 
-impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
+impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         NestedVisitorMap::None
     }
 
-    fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         let def = if let hir::ExprPath(ref qpath) = expr.node {
-            self.infcx.tables.borrow().qpath_def(qpath, expr.id)
+            self.tables.qpath_def(qpath, expr.id)
         } else {
             Def::Err
         };
         match def {
             Def::Fn(did) if self.def_id_is_transmute(did) => {
-                let typ = self.infcx.tables.borrow().node_id_to_type(expr.id);
-                let typ = self.infcx.tcx.lift_to_global(&typ).unwrap();
+                let typ = self.tables.node_id_to_type(expr.id);
+                let typ = self.tcx.lift_to_global(&typ).unwrap();
                 match typ.sty {
                     ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => {
                         let from = sig.inputs().skip_binder()[0];
index ecd350d12736897799a3a78d6cfbbf01274db79a..c6a42be6135ccbfb8995eb37cd8509bf0ef2491f 100644 (file)
@@ -1045,7 +1045,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
 
           hir::ExprAssignOp(_, ref l, ref r) => {
             // an overloaded assign op is like a method call
-            if self.tables.is_method_call(expr.id) {
+            if self.tables.is_method_call(expr) {
                 let succ = self.propagate_through_expr(&l, succ);
                 self.propagate_through_expr(&r, succ)
             } else {
@@ -1072,9 +1072,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
 
           hir::ExprCall(ref f, ref args) => {
             // FIXME(canndrew): This is_never should really be an is_uninhabited
-            let diverges = !self.tables.is_method_call(expr.id) &&
-                self.tables.expr_ty_adjusted(&f).fn_ret().0.is_never();
-            let succ = if diverges {
+            let succ = if self.tables.expr_ty(expr).is_never() {
                 self.s.exit_ln
             } else {
                 succ
@@ -1084,10 +1082,8 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
           }
 
           hir::ExprMethodCall(.., ref args) => {
-            let method_call = ty::MethodCall::expr(expr.id);
-            let method_ty = self.tables.method_map[&method_call].ty;
             // FIXME(canndrew): This is_never should really be an is_uninhabited
-            let succ = if method_ty.fn_ret().0.is_never() {
+            let succ = if self.tables.expr_ty(expr).is_never() {
                 self.s.exit_ln
             } else {
                 succ
@@ -1370,7 +1366,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
       }
 
       hir::ExprAssignOp(_, ref l, _) => {
-        if !this.tables.is_method_call(expr.id) {
+        if !this.tables.is_method_call(expr) {
             this.check_lvalue(&l);
         }
 
index d0adf51d79e68675a59672003c9c96b4d31a54f6..c114aa1d7a883b9e27ba523200f1c07df94779f7 100644 (file)
@@ -63,7 +63,6 @@
 pub use self::PointerKind::*;
 pub use self::InteriorKind::*;
 pub use self::FieldName::*;
-pub use self::ElementKind::*;
 pub use self::MutabilityCategory::*;
 pub use self::AliasableReason::*;
 pub use self::Note::*;
 
 #[derive(Clone, PartialEq)]
 pub enum Categorization<'tcx> {
-    // temporary val, argument is its scope
-    Rvalue(ty::Region<'tcx>, ty::Region<'tcx>),
+    Rvalue(ty::Region<'tcx>),              // temporary val, argument is its scope
     StaticItem,
     Upvar(Upvar),                          // upvar referenced by closure env
     Local(ast::NodeId),                    // local variable
-    Deref(cmt<'tcx>, usize, PointerKind<'tcx>),  // deref of a ptr
+    Deref(cmt<'tcx>, PointerKind<'tcx>),   // deref of a ptr
     Interior(cmt<'tcx>, InteriorKind),     // something interior: field, tuple, etc
     Downcast(cmt<'tcx>, DefId),            // selects a particular enum variant (*1)
 
@@ -129,7 +127,7 @@ pub enum PointerKind<'tcx> {
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub enum InteriorKind {
     InteriorField(FieldName),
-    InteriorElement(InteriorOffsetKind, ElementKind),
+    InteriorElement(InteriorOffsetKind),
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
@@ -144,12 +142,6 @@ pub enum InteriorOffsetKind {
     Pattern,          // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }`
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub enum ElementKind {
-    VecElement,
-    OtherElement,
-}
-
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub enum MutabilityCategory {
     McImmutable, // Immutable.
@@ -229,8 +221,8 @@ fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tc
 
     pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
         match self.cat {
-            Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) |
-            Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => {
+            Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) |
+            Categorization::Deref(ref base_cmt, Implicit(ty::ImmBorrow, _)) => {
                 // try to figure out where the immutable reference came from
                 match base_cmt.cat {
                     Categorization::Local(node_id) =>
@@ -255,13 +247,13 @@ pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
             }
             Categorization::Rvalue(..) |
             Categorization::Upvar(..) |
-            Categorization::Deref(.., UnsafePtr(..)) => {
+            Categorization::Deref(_, UnsafePtr(..)) => {
                 // This should not be reachable up to inference limitations.
                 None
             }
             Categorization::Interior(ref base_cmt, _) |
             Categorization::Downcast(ref base_cmt, _) |
-            Categorization::Deref(ref base_cmt, _, _) => {
+            Categorization::Deref(ref base_cmt, _) => {
                 base_cmt.immutability_blame()
             }
             Categorization::StaticItem => {
@@ -473,53 +465,64 @@ fn pat_ty(&self, pat: &hir::Pat) -> McResult<Ty<'tcx>> {
     }
 
     pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
-        match self.infcx.tables.borrow().adjustments.get(&expr.id) {
-            None => {
-                // No adjustments.
-                self.cat_expr_unadjusted(expr)
-            }
-
-            Some(adjustment) => {
-                match adjustment.kind {
-                    adjustment::Adjust::DerefRef {
-                        autoderefs,
-                        autoref: None,
-                        unsize: false
-                    } => {
-                        // Equivalent to *expr or something similar.
-                        self.cat_expr_autoderefd(expr, autoderefs)
-                    }
-
-                    adjustment::Adjust::NeverToAny |
-                    adjustment::Adjust::ReifyFnPointer |
-                    adjustment::Adjust::UnsafeFnPointer |
-                    adjustment::Adjust::ClosureFnPointer |
-                    adjustment::Adjust::MutToConstPointer |
-                    adjustment::Adjust::DerefRef {..} => {
-                        debug!("cat_expr({:?}): {:?}",
-                               adjustment,
-                               expr);
-                        // Result is an rvalue.
-                        let expr_ty = self.expr_ty_adjusted(expr)?;
-                        Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
-                    }
+        // This recursion helper avoids going through *too many*
+        // adjustments, since *only* non-overloaded deref recurses.
+        fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>,
+                                  expr: &hir::Expr,
+                                  adjustments: &[adjustment::Adjustment<'tcx>])
+                                   -> McResult<cmt<'tcx>> {
+            match adjustments.split_last() {
+                None => mc.cat_expr_unadjusted(expr),
+                Some((adjustment, previous)) => {
+                    mc.cat_expr_adjusted_with(expr, || helper(mc, expr, previous), adjustment)
                 }
             }
         }
+
+        helper(self, expr, self.infcx.tables.borrow().expr_adjustments(expr))
+    }
+
+    pub fn cat_expr_adjusted(&self, expr: &hir::Expr,
+                             previous: cmt<'tcx>,
+                             adjustment: &adjustment::Adjustment<'tcx>)
+                             -> McResult<cmt<'tcx>> {
+        self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
     }
 
-    pub fn cat_expr_autoderefd(&self,
-                               expr: &hir::Expr,
-                               autoderefs: usize)
-                               -> McResult<cmt<'tcx>> {
-        let mut cmt = self.cat_expr_unadjusted(expr)?;
-        debug!("cat_expr_autoderefd: autoderefs={}, cmt={:?}",
-               autoderefs,
-               cmt);
-        for deref in 1..autoderefs + 1 {
-            cmt = self.cat_deref(expr, cmt, deref)?;
+    fn cat_expr_adjusted_with<F>(&self, expr: &hir::Expr,
+                                 previous: F,
+                                 adjustment: &adjustment::Adjustment<'tcx>)
+                                 -> McResult<cmt<'tcx>>
+        where F: FnOnce() -> McResult<cmt<'tcx>>
+    {
+        debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
+        let target = self.infcx.resolve_type_vars_if_possible(&adjustment.target);
+        match adjustment.kind {
+            adjustment::Adjust::Deref(overloaded) => {
+                // Equivalent to *expr or something similar.
+                let base = if let Some(deref) = overloaded {
+                    let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut {
+                        ty: target,
+                        mutbl: deref.mutbl,
+                    });
+                    self.cat_rvalue_node(expr.id, expr.span, ref_ty)
+                } else {
+                    previous()?
+                };
+                self.cat_deref(expr, base, false)
+            }
+
+            adjustment::Adjust::NeverToAny |
+            adjustment::Adjust::ReifyFnPointer |
+            adjustment::Adjust::UnsafeFnPointer |
+            adjustment::Adjust::ClosureFnPointer |
+            adjustment::Adjust::MutToConstPointer |
+            adjustment::Adjust::Borrow(_) |
+            adjustment::Adjust::Unsize => {
+                // Result is an rvalue.
+                Ok(self.cat_rvalue_node(expr.id, expr.span, target))
+            }
         }
-        return Ok(cmt);
     }
 
     pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
@@ -528,8 +531,12 @@ pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
         let expr_ty = self.expr_ty(expr)?;
         match expr.node {
           hir::ExprUnary(hir::UnDeref, ref e_base) => {
-            let base_cmt = self.cat_expr(&e_base)?;
-            self.cat_deref(expr, base_cmt, 0)
+            if self.infcx.tables.borrow().is_method_call(expr) {
+                self.cat_overloaded_lvalue(expr, e_base, false)
+            } else {
+                let base_cmt = self.cat_expr(&e_base)?;
+                self.cat_deref(expr, base_cmt, false)
+            }
           }
 
           hir::ExprField(ref base, f_name) => {
@@ -547,33 +554,16 @@ pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
           }
 
           hir::ExprIndex(ref base, _) => {
-            let method_call = ty::MethodCall::expr(expr.id());
-            match self.infcx.node_method_ty(method_call) {
-                Some(method_ty) => {
-                    // If this is an index implemented by a method call, then it
-                    // will include an implicit deref of the result.
-                    let ret_ty = self.overloaded_method_return_ty(method_ty);
-
-                    // The index method always returns an `&T`, so
-                    // dereference it to find the result type.
-                    let elem_ty = match ret_ty.sty {
-                        ty::TyRef(_, mt) => mt.ty,
-                        _ => {
-                            debug!("cat_expr_unadjusted: return type of overloaded index is {:?}?",
-                                   ret_ty);
-                            return Err(());
-                        }
-                    };
-
-                    // The call to index() returns a `&T` value, which
-                    // is an rvalue. That is what we will be
-                    // dereferencing.
-                    let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty);
-                    Ok(self.cat_deref_common(expr, base_cmt, 1, elem_ty, true))
-                }
-                None => {
-                    self.cat_index(expr, self.cat_expr(&base)?, InteriorOffsetKind::Index)
-                }
+            if self.infcx.tables.borrow().is_method_call(expr) {
+                // If this is an index implemented by a method call, then it
+                // will include an implicit deref of the result.
+                // The call to index() returns a `&T` value, which
+                // is an rvalue. That is what we will be
+                // dereferencing.
+                self.cat_overloaded_lvalue(expr, base, true)
+            } else {
+                let base_cmt = self.cat_expr(&base)?;
+                self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index)
             }
           }
 
@@ -763,7 +753,7 @@ fn cat_upvar(&self,
                 cmt_ {
                     id: id,
                     span: span,
-                    cat: Categorization::Deref(Rc::new(cmt_result), 0, ptr),
+                    cat: Categorization::Deref(Rc::new(cmt_result), ptr),
                     mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind),
                     ty: var_ty,
                     note: NoteUpvarRef(upvar_id)
@@ -823,7 +813,7 @@ fn env_deref(&self,
         let ret = cmt_ {
             id: id,
             span: span,
-            cat: Categorization::Deref(Rc::new(cmt_result), 0, env_ptr),
+            cat: Categorization::Deref(Rc::new(cmt_result), env_ptr),
             mutbl: deref_mutbl,
             ty: var_ty,
             note: NoteClosureEnv(upvar_id)
@@ -836,18 +826,13 @@ fn env_deref(&self,
 
     /// Returns the lifetime of a temporary created by expr with id `id`.
     /// This could be `'static` if `id` is part of a constant expression.
-    pub fn temporary_scope(&self, id: ast::NodeId) -> (ty::Region<'tcx>, ty::Region<'tcx>)
+    pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region<'tcx>
     {
-        let (scope, old_scope) =
-            self.region_maps.old_and_new_temporary_scope(id);
-        (self.tcx().mk_region(match scope {
-            Some(scope) => ty::ReScope(scope),
-            None => ty::ReStatic
-        }),
-         self.tcx().mk_region(match old_scope {
+        let scope = self.region_maps.temporary_scope(id);
+        self.tcx().mk_region(match scope {
             Some(scope) => ty::ReScope(scope),
             None => ty::ReStatic
-        }))
+        })
     }
 
     pub fn cat_rvalue_node(&self,
@@ -867,13 +852,12 @@ pub fn cat_rvalue_node(&self,
         // Compute maximum lifetime of this rvalue. This is 'static if
         // we can promote to a constant, otherwise equal to enclosing temp
         // lifetime.
-        let (re, old_re) = if promotable {
-            (self.tcx().types.re_static,
-             self.tcx().types.re_static)
+        let re = if promotable {
+            self.tcx().types.re_static
         } else {
             self.temporary_scope(id)
         };
-        let ret = self.cat_rvalue(id, span, re, old_re, expr_ty);
+        let ret = self.cat_rvalue(id, span, re, expr_ty);
         debug!("cat_rvalue_node ret {:?}", ret);
         ret
     }
@@ -882,12 +866,11 @@ pub fn cat_rvalue(&self,
                       cmt_id: ast::NodeId,
                       span: Span,
                       temp_scope: ty::Region<'tcx>,
-                      old_temp_scope: ty::Region<'tcx>,
                       expr_ty: Ty<'tcx>) -> cmt<'tcx> {
         let ret = Rc::new(cmt_ {
             id:cmt_id,
             span:span,
-            cat:Categorization::Rvalue(temp_scope, old_temp_scope),
+            cat:Categorization::Rvalue(temp_scope),
             mutbl:McDeclared,
             ty:expr_ty,
             note: NoteNone
@@ -932,51 +915,51 @@ pub fn cat_tup_field<N:ast_node>(&self,
         ret
     }
 
-    fn cat_deref<N:ast_node>(&self,
-                             node: &N,
-                             base_cmt: cmt<'tcx>,
-                             deref_cnt: usize)
+    fn cat_overloaded_lvalue(&self,
+                             expr: &hir::Expr,
+                             base: &hir::Expr,
+                             implicit: bool)
                              -> McResult<cmt<'tcx>> {
-        let method_call = ty::MethodCall {
-            expr_id: node.id(),
-            autoderef: deref_cnt as u32
-        };
-        let method_ty = self.infcx.node_method_ty(method_call);
+        debug!("cat_overloaded_lvalue: implicit={}", implicit);
 
-        debug!("cat_deref: method_call={:?} method_ty={:?}",
-               method_call, method_ty.map(|ty| ty));
+        // Reconstruct the output assuming it's a reference with the
+        // same region and mutability as the receiver. This holds for
+        // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
+        let lvalue_ty = self.expr_ty(expr)?;
+        let base_ty = self.expr_ty_adjusted(base)?;
 
-        let base_cmt = match method_ty {
-            Some(method_ty) => {
-                let ref_ty =
-                    self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
-                self.cat_rvalue_node(node.id(), node.span(), ref_ty)
+        let (region, mutbl) = match base_ty.sty {
+            ty::TyRef(region, mt) => (region, mt.mutbl),
+            _ => {
+                span_bug!(expr.span, "cat_overloaded_lvalue: base is not a reference")
             }
-            None => base_cmt
         };
+        let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut {
+            ty: lvalue_ty,
+            mutbl,
+        });
+
+        let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty);
+        self.cat_deref(expr, base_cmt, implicit)
+    }
+
+    pub fn cat_deref<N:ast_node>(&self,
+                                 node: &N,
+                                 base_cmt: cmt<'tcx>,
+                                 implicit: bool)
+                                 -> McResult<cmt<'tcx>> {
+        debug!("cat_deref: base_cmt={:?}", base_cmt);
+
         let base_cmt_ty = base_cmt.ty;
-        match base_cmt_ty.builtin_deref(true, ty::NoPreference) {
-            Some(mt) => {
-                let ret = self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, false);
-                debug!("cat_deref ret {:?}", ret);
-                Ok(ret)
-            }
+        let deref_ty = match base_cmt_ty.builtin_deref(true, ty::NoPreference) {
+            Some(mt) => mt.ty,
             None => {
                 debug!("Explicit deref of non-derefable type: {:?}",
                        base_cmt_ty);
                 return Err(());
             }
-        }
-    }
+        };
 
-    fn cat_deref_common<N:ast_node>(&self,
-                                    node: &N,
-                                    base_cmt: cmt<'tcx>,
-                                    deref_cnt: usize,
-                                    deref_ty: Ty<'tcx>,
-                                    implicit: bool)
-                                    -> cmt<'tcx>
-    {
         let ptr = match base_cmt.ty.sty {
             ty::TyAdt(def, ..) if def.is_box() => Unique,
             ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl),
@@ -984,26 +967,27 @@ fn cat_deref_common<N:ast_node>(&self,
                 let bk = ty::BorrowKind::from_mutbl(mt.mutbl);
                 if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) }
             }
-            ref ty => bug!("unexpected type in cat_deref_common: {:?}", ty)
+            ref ty => bug!("unexpected type in cat_deref: {:?}", ty)
         };
         let ret = Rc::new(cmt_ {
             id: node.id(),
             span: node.span(),
             // For unique ptrs, we inherit mutability from the owning reference.
             mutbl: MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
-            cat: Categorization::Deref(base_cmt, deref_cnt, ptr),
+            cat: Categorization::Deref(base_cmt, ptr),
             ty: deref_ty,
             note: NoteNone
         });
-        debug!("cat_deref_common ret {:?}", ret);
-        ret
+        debug!("cat_deref ret {:?}", ret);
+        Ok(ret)
     }
 
-    pub fn cat_index<N:ast_node>(&self,
-                                 elt: &N,
-                                 mut base_cmt: cmt<'tcx>,
-                                 context: InteriorOffsetKind)
-                                 -> McResult<cmt<'tcx>> {
+    fn cat_index<N:ast_node>(&self,
+                             elt: &N,
+                             base_cmt: cmt<'tcx>,
+                             element_ty: Ty<'tcx>,
+                             context: InteriorOffsetKind)
+                             -> McResult<cmt<'tcx>> {
         //! Creates a cmt for an indexing operation (`[]`).
         //!
         //! One subtle aspect of indexing that may not be
@@ -1021,31 +1005,9 @@ pub fn cat_index<N:ast_node>(&self,
         //! - `elt`: the AST node being indexed
         //! - `base_cmt`: the cmt of `elt`
 
-        let method_call = ty::MethodCall::expr(elt.id());
-        let method_ty = self.infcx.node_method_ty(method_call);
-
-        let (element_ty, element_kind) = match method_ty {
-            Some(method_ty) => {
-                let ref_ty = self.overloaded_method_return_ty(method_ty);
-                base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
-
-                (ref_ty.builtin_deref(false, ty::NoPreference).unwrap().ty,
-                 ElementKind::OtherElement)
-            }
-            None => {
-                match base_cmt.ty.builtin_index() {
-                    Some(ty) => (ty, ElementKind::VecElement),
-                    None => {
-                        debug!("Explicit index of non-indexable type {:?}", base_cmt);
-                        return Err(());
-                    }
-                }
-            }
-        };
-
-        let interior_elem = InteriorElement(context, element_kind);
+        let interior_elem = InteriorElement(context);
         let ret =
-            self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem);
+            self.cat_imm_interior(elt, base_cmt, element_ty, interior_elem);
         debug!("cat_index ret {:?}", ret);
         return Ok(ret);
     }
@@ -1235,13 +1197,20 @@ fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResul
             // box p1, &p1, &mut p1.  we can ignore the mutability of
             // PatKind::Ref since that information is already contained
             // in the type.
-            let subcmt = self.cat_deref(pat, cmt, 0)?;
+            let subcmt = self.cat_deref(pat, cmt, false)?;
             self.cat_pattern_(subcmt, &subpat, op)?;
           }
 
           PatKind::Slice(ref before, ref slice, ref after) => {
+            let element_ty = match cmt.ty.builtin_index() {
+                Some(ty) => ty,
+                None => {
+                    debug!("Explicit index of non-indexable type {:?}", cmt);
+                    return Err(());
+                }
+            };
             let context = InteriorOffsetKind::Pattern;
-            let elt_cmt = self.cat_index(pat, cmt, context)?;
+            let elt_cmt = self.cat_index(pat, cmt, element_ty, context)?;
             for before_pat in before {
                 self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
             }
@@ -1261,19 +1230,6 @@ fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResul
 
         Ok(())
     }
-
-    fn overloaded_method_return_ty(&self,
-                                   method_ty: Ty<'tcx>)
-                                   -> Ty<'tcx>
-    {
-        // When we process an overloaded `*` or `[]` etc, we often
-        // need to extract the return type of the method. These method
-        // types are generated by method resolution and always have
-        // all late-bound regions fully instantiated, so we just want
-        // to skip past the binder.
-        self.tcx().no_late_bound_regions(&method_ty.fn_ret())
-           .unwrap()
-    }
 }
 
 #[derive(Clone, Debug)]
@@ -1300,15 +1256,15 @@ pub fn guarantor(&self) -> cmt<'tcx> {
             Categorization::Rvalue(..) |
             Categorization::StaticItem |
             Categorization::Local(..) |
-            Categorization::Deref(.., UnsafePtr(..)) |
-            Categorization::Deref(.., BorrowedPtr(..)) |
-            Categorization::Deref(.., Implicit(..)) |
+            Categorization::Deref(_, UnsafePtr(..)) |
+            Categorization::Deref(_, BorrowedPtr(..)) |
+            Categorization::Deref(_, Implicit(..)) |
             Categorization::Upvar(..) => {
                 Rc::new((*self).clone())
             }
             Categorization::Downcast(ref b, _) |
             Categorization::Interior(ref b, _) |
-            Categorization::Deref(ref b, _, Unique) => {
+            Categorization::Deref(ref b, Unique) => {
                 b.guarantor()
             }
         }
@@ -1321,11 +1277,11 @@ pub fn freely_aliasable(&self) -> Aliasability {
         // aliased and eventually recused.
 
         match self.cat {
-            Categorization::Deref(ref b, _, BorrowedPtr(ty::MutBorrow, _)) |
-            Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) |
-            Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
-            Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
-            Categorization::Deref(ref b, _, Unique) |
+            Categorization::Deref(ref b, BorrowedPtr(ty::MutBorrow, _)) |
+            Categorization::Deref(ref b, Implicit(ty::MutBorrow, _)) |
+            Categorization::Deref(ref b, BorrowedPtr(ty::UniqueImmBorrow, _)) |
+            Categorization::Deref(ref b, Implicit(ty::UniqueImmBorrow, _)) |
+            Categorization::Deref(ref b, Unique) |
             Categorization::Downcast(ref b, _) |
             Categorization::Interior(ref b, _) => {
                 // Aliasability depends on base cmt
@@ -1335,7 +1291,7 @@ pub fn freely_aliasable(&self) -> Aliasability {
             Categorization::Rvalue(..) |
             Categorization::Local(..) |
             Categorization::Upvar(..) |
-            Categorization::Deref(.., UnsafePtr(..)) => { // yes, it's aliasable, but...
+            Categorization::Deref(_, UnsafePtr(..)) => { // yes, it's aliasable, but...
                 NonAliasable
             }
 
@@ -1347,8 +1303,8 @@ pub fn freely_aliasable(&self) -> Aliasability {
                 }
             }
 
-            Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
-            Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => {
+            Categorization::Deref(_, BorrowedPtr(ty::ImmBorrow, _)) |
+            Categorization::Deref(_, Implicit(ty::ImmBorrow, _)) => {
                 FreelyAliasable(AliasableBorrowed)
             }
         }
@@ -1360,9 +1316,9 @@ pub fn upvar(&self) -> Option<cmt<'tcx>> {
         match self.note {
             NoteClosureEnv(..) | NoteUpvarRef(..) => {
                 Some(match self.cat {
-                    Categorization::Deref(ref inner, ..) => {
+                    Categorization::Deref(ref inner, _) => {
                         match inner.cat {
-                            Categorization::Deref(ref inner, ..) => inner.clone(),
+                            Categorization::Deref(ref inner, _) => inner.clone(),
                             Categorization::Upvar(..) => inner.clone(),
                             _ => bug!()
                         }
@@ -1390,7 +1346,7 @@ pub fn descriptive_string(&self, tcx: TyCtxt) -> String {
                     "local variable".to_string()
                 }
             }
-            Categorization::Deref(.., pk) => {
+            Categorization::Deref(_, pk) => {
                 let upvar = self.upvar();
                 match upvar.as_ref().map(|i| &i.cat) {
                     Some(&Categorization::Upvar(ref var)) => {
@@ -1421,16 +1377,10 @@ pub fn descriptive_string(&self, tcx: TyCtxt) -> String {
             Categorization::Interior(_, InteriorField(PositionalField(_))) => {
                 "anonymous field".to_string()
             }
-            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index,
-                                                        VecElement)) |
-            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index,
-                                                        OtherElement)) => {
+            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index)) => {
                 "indexed content".to_string()
             }
-            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern,
-                                                        VecElement)) |
-            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern,
-                                                        OtherElement)) => {
+            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern)) => {
                 "pattern-bound indexed content".to_string()
             }
             Categorization::Upvar(ref var) => {
@@ -1457,9 +1407,7 @@ impl<'tcx> fmt::Debug for Categorization<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             Categorization::StaticItem => write!(f, "static"),
-            Categorization::Rvalue(r, or) => {
-                write!(f, "rvalue({:?}, {:?})", r, or)
-            }
+            Categorization::Rvalue(r) => { write!(f, "rvalue({:?})", r) }
             Categorization::Local(id) => {
                let name = ty::tls::with(|tcx| tcx.local_var_name_str(id));
                write!(f, "local({})", name)
@@ -1467,8 +1415,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             Categorization::Upvar(upvar) => {
                 write!(f, "upvar({:?})", upvar)
             }
-            Categorization::Deref(ref cmt, derefs, ptr) => {
-                write!(f, "{:?}-{:?}{}->", cmt.cat, ptr, derefs)
+            Categorization::Deref(ref cmt, ptr) => {
+                write!(f, "{:?}-{:?}->", cmt.cat, ptr)
             }
             Categorization::Interior(ref cmt, interior) => {
                 write!(f, "{:?}.{:?}", cmt.cat, interior)
index 939d7364d9e06bcedb839db9af70948b6342a8b8..c2f69147e3a563c64e0c87794debfdf7d1ff20b6 100644 (file)
@@ -110,9 +110,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
                 Some(self.tables.qpath_def(qpath, expr.id))
             }
             hir::ExprMethodCall(..) => {
-                let method_call = ty::MethodCall::expr(expr.id);
-                let def_id = self.tables.method_map[&method_call].def_id;
-                Some(Def::Method(def_id))
+                Some(self.tables.type_dependent_defs[&expr.id])
             }
             _ => None
         };
index 2d632e3feb5457de6b463f62e84160cb362f19ce..6455d7ecf85ae83d640bae0525ec2660ee76a0db 100644 (file)
@@ -223,13 +223,6 @@ pub struct RegionMaps {
     /// block (see `terminating_scopes`).
     rvalue_scopes: NodeMap<CodeExtent>,
 
-    /// Records the value of rvalue scopes before they were shrunk by
-    /// #36082, for error reporting.
-    ///
-    /// FIXME: this should be temporary. Remove this by 1.18.0 or
-    /// so.
-    shrunk_rvalue_scopes: NodeMap<CodeExtent>,
-
     /// Encodes the hierarchy of fn bodies. Every fn body (including
     /// closures) forms its own distinct region hierarchy, rooted in
     /// the block that is the fn body. This map points from the id of
@@ -301,7 +294,6 @@ pub fn new() -> Self {
             destruction_scopes: FxHashMap(),
             var_map: NodeMap(),
             rvalue_scopes: NodeMap(),
-            shrunk_rvalue_scopes: NodeMap(),
             fn_tree: NodeMap(),
         }
     }
@@ -370,12 +362,6 @@ fn record_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent) {
         self.rvalue_scopes.insert(var, lifetime);
     }
 
-    fn record_shrunk_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent) {
-        debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
-        assert!(var != lifetime.node_id());
-        self.shrunk_rvalue_scopes.insert(var, lifetime);
-    }
-
     pub fn opt_encl_scope(&self, id: CodeExtent) -> Option<CodeExtent> {
         //! Returns the narrowest scope that encloses `id`, if any.
         self.scope_map.get(&id).cloned()
@@ -395,32 +381,6 @@ pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent {
         }
     }
 
-    pub fn temporary_scope2(&self, expr_id: ast::NodeId)
-                            -> (Option<CodeExtent>, bool) {
-        let temporary_scope = self.temporary_scope(expr_id);
-        let was_shrunk = match self.shrunk_rvalue_scopes.get(&expr_id) {
-            Some(&s) => {
-                info!("temporary_scope2({:?}, scope={:?}, shrunk={:?})",
-                      expr_id, temporary_scope, s);
-                temporary_scope != Some(s)
-            }
-            _ => false
-        };
-        info!("temporary_scope2({:?}) - was_shrunk={:?}", expr_id, was_shrunk);
-        (temporary_scope, was_shrunk)
-    }
-
-    pub fn old_and_new_temporary_scope(&self, expr_id: ast::NodeId)
-                                       -> (Option<CodeExtent>,
-                                           Option<CodeExtent>)
-    {
-        let temporary_scope = self.temporary_scope(expr_id);
-        (temporary_scope,
-         self.shrunk_rvalue_scopes
-             .get(&expr_id).cloned()
-             .or(temporary_scope))
-    }
-
     pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option<CodeExtent> {
         //! Returns the scope when temp created by expr_id will be cleaned up
 
@@ -896,10 +856,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
     // Rule A. `let (ref x, ref y) = (foo().x, 44)`. The rvalue `(22, 44)`
     // would have an extended lifetime, but not `foo()`.
     //
-    // Rule B. `let x: &[...] = [foo().x]`. The rvalue `[foo().x]`
-    // would have an extended lifetime, but not `foo()`.
-    //
-    // Rule C. `let x = &foo().x`. The rvalue ``foo()` would have extended
+    // Rule B. `let x = &foo().x`. The rvalue ``foo()` would have extended
     // lifetime.
     //
     // In some cases, multiple rules may apply (though not to the same
@@ -916,13 +873,8 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
     if let Some(ref expr) = local.init {
         record_rvalue_scope_if_borrow_expr(visitor, &expr, blk_scope);
 
-        let is_borrow =
-            if let Some(ref ty) = local.ty { is_borrowed_ty(&ty) } else { false };
-
         if is_binding_pat(&local.pat) {
-            record_rvalue_scope(visitor, &expr, blk_scope, false);
-        } else if is_borrow {
-            record_rvalue_scope(visitor, &expr, blk_scope, true);
+            record_rvalue_scope(visitor, &expr, blk_scope);
         }
     }
 
@@ -963,14 +915,6 @@ fn is_binding_pat(pat: &hir::Pat) -> bool {
         }
     }
 
-    /// True if `ty` is a borrowed pointer type like `&int` or `&[...]`.
-    fn is_borrowed_ty(ty: &hir::Ty) -> bool {
-        match ty.node {
-            hir::TyRptr(..) => true,
-            _ => false
-        }
-    }
-
     /// If `expr` matches the `E&` grammar, then records an extended rvalue scope as appropriate:
     ///
     ///     E& = & ET
@@ -989,7 +933,7 @@ fn record_rvalue_scope_if_borrow_expr<'a, 'tcx>(
         match expr.node {
             hir::ExprAddrOf(_, ref subexpr) => {
                 record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
-                record_rvalue_scope(visitor, &subexpr, blk_id, false);
+                record_rvalue_scope(visitor, &subexpr, blk_id);
             }
             hir::ExprStruct(_, ref fields, _) => {
                 for field in fields {
@@ -1034,8 +978,7 @@ fn record_rvalue_scope_if_borrow_expr<'a, 'tcx>(
     /// Note: ET is intended to match "rvalues or lvalues based on rvalues".
     fn record_rvalue_scope<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
                                      expr: &hir::Expr,
-                                     blk_scope: CodeExtent,
-                                     is_shrunk: bool) {
+                                     blk_scope: CodeExtent) {
         let mut expr = expr;
         loop {
             // Note: give all the expressions matching `ET` with the
@@ -1043,12 +986,7 @@ fn record_rvalue_scope<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>
             // because in trans if we must compile e.g. `*rvalue()`
             // into a temporary, we request the temporary scope of the
             // outer expression.
-            if is_shrunk {
-                // this changed because of #36082
-                visitor.region_maps.record_shrunk_rvalue_scope(expr.id, blk_scope);
-            } else {
-                visitor.region_maps.record_rvalue_scope(expr.id, blk_scope);
-            }
+            visitor.region_maps.record_rvalue_scope(expr.id, blk_scope);
 
             match expr.node {
                 hir::ExprAddrOf(_, ref subexpr) |
index a943ef30e534bf57bec8449dd28ce4650160a820..54fe3a42b6179050550ecd71b3899ec80d1652dc 100644 (file)
 
 //! See `README.md` for high-level documentation
 
-use super::{SelectionContext, Obligation, ObligationCause};
-
 use hir::def_id::{DefId, LOCAL_CRATE};
+use syntax_pos::DUMMY_SP;
+use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause, Reveal};
 use ty::{self, Ty, TyCtxt};
+use ty::subst::Subst;
 
 use infer::{InferCtxt, InferOk};
 
@@ -37,6 +38,28 @@ pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
     overlap(selcx, impl1_def_id, impl2_def_id)
 }
 
+fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
+                                       param_env: ty::ParamEnv<'tcx>,
+                                       impl_def_id: DefId)
+                                       -> ty::ImplHeader<'tcx>
+{
+    let tcx = selcx.tcx();
+    let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id);
+
+    let header = ty::ImplHeader {
+        impl_def_id: impl_def_id,
+        self_ty: tcx.type_of(impl_def_id),
+        trait_ref: tcx.impl_trait_ref(impl_def_id),
+        predicates: tcx.predicates_of(impl_def_id).predicates
+    }.subst(tcx, impl_substs);
+
+    let Normalized { value: mut header, obligations } =
+        traits::normalize(selcx, param_env, ObligationCause::dummy(), &header);
+
+    header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
+    header
+}
+
 /// Can both impl `a` and impl `b` be satisfied by a common type (including
 /// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls.
 fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
@@ -48,18 +71,22 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
            a_def_id,
            b_def_id);
 
-    let a_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, a_def_id);
-    let b_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, b_def_id);
+    // For the purposes of this check, we don't bring any skolemized
+    // types into scope; instead, we replace the generic types with
+    // fresh type variables, and hence we do our evaluations in an
+    // empty environment.
+    let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
+
+    let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id);
+    let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id);
 
     debug!("overlap: a_impl_header={:?}", a_impl_header);
     debug!("overlap: b_impl_header={:?}", b_impl_header);
 
     // Do `a` and `b` unify? If not, no overlap.
-    let obligations = match selcx.infcx().eq_impl_headers(true,
-                                        &ObligationCause::dummy(),
-                                        &a_impl_header,
-                                        &b_impl_header) {
-        Ok(InferOk { obligations, .. }) => {
+    let obligations = match selcx.infcx().at(&ObligationCause::dummy(), param_env)
+                                         .eq_impl_headers(&a_impl_header, &b_impl_header) {
+        Ok(InferOk { obligations, value: () }) => {
             obligations
         }
         Err(_) => return None
@@ -75,6 +102,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
                      .chain(&b_impl_header.predicates)
                      .map(|p| infcx.resolve_type_vars_if_possible(p))
                      .map(|p| Obligation { cause: ObligationCause::dummy(),
+                                           param_env: param_env,
                                            recursion_depth: 0,
                                            predicate: p })
                      .chain(obligations)
index 3c7761c6cd3bcf338373f2a5c278e5af96666048..049d5e488c946f0e0d3312c25083f2a33ebb5d5e 100644 (file)
@@ -179,14 +179,13 @@ fn report_projection_error(&self,
                     data);
                 let normalized = super::normalize_projection_type(
                     &mut selcx,
+                    obligation.param_env,
                     data.projection_ty,
                     obligation.cause.clone(),
                     0
                 );
-                if let Err(error) = self.eq_types(
-                    false, &obligation.cause,
-                    data.ty, normalized.value
-                ) {
+                if let Err(error) = self.at(&obligation.cause, obligation.param_env)
+                                        .eq(normalized.value, data.ty) {
                     values = Some(infer::ValuePairs::Types(ExpectedFound {
                         expected: normalized.value,
                         found: data.ty,
@@ -251,7 +250,7 @@ fn impl_similar_to(&self,
                        -> Option<DefId>
     {
         let tcx = self.tcx;
-
+        let param_env = obligation.param_env;
         let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
         let trait_self_ty = trait_ref.self_ty();
 
@@ -268,7 +267,7 @@ fn impl_similar_to(&self,
 
                 let impl_self_ty = impl_trait_ref.self_ty();
 
-                if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) {
+                if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
                     self_match_impls.push(def_id);
 
                     if trait_ref.substs.types().skip(1)
@@ -578,7 +577,7 @@ pub fn report_selection_error(&self,
 
                         // Try to report a help message
                         if !trait_ref.has_infer_types() &&
-                            self.predicate_can_apply(trait_ref) {
+                            self.predicate_can_apply(obligation.param_env, trait_ref) {
                             // If a where-clause may be useful, remind the
                             // user that they can add it.
                             //
@@ -607,7 +606,8 @@ pub fn report_selection_error(&self,
                     ty::Predicate::Equate(ref predicate) => {
                         let predicate = self.resolve_type_vars_if_possible(predicate);
                         let err = self.equality_predicate(&obligation.cause,
-                                                            &predicate).err().unwrap();
+                                                          obligation.param_env,
+                                                          &predicate).err().unwrap();
                         struct_span_err!(self.tcx.sess, span, E0278,
                             "the requirement `{}` is not satisfied (`{}`)",
                             predicate, err)
@@ -936,7 +936,10 @@ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
 
     /// Returns whether the trait predicate may apply for *some* assignment
     /// to the type parameters.
-    fn predicate_can_apply(&self, pred: ty::PolyTraitRef<'tcx>) -> bool {
+    fn predicate_can_apply(&self,
+                           param_env: ty::ParamEnv<'tcx>,
+                           pred: ty::PolyTraitRef<'tcx>)
+                           -> bool {
         struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
             infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
             var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>
@@ -967,12 +970,14 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
 
             let cleaned_pred = super::project::normalize(
                 &mut selcx,
+                param_env,
                 ObligationCause::dummy(),
                 &cleaned_pred
             ).value;
 
             let obligation = Obligation::new(
                 ObligationCause::dummy(),
+                param_env,
                 cleaned_pred.to_predicate()
             );
 
index e8baaa7ffb26d01a59f705e28d7bc2ece9df2707..c2fe04534375f1c6500c119499fbb16b791f4fce 100644 (file)
@@ -113,6 +113,7 @@ pub fn new() -> FulfillmentContext<'tcx> {
     /// `projection_ty` again.
     pub fn normalize_projection_type(&mut self,
                                      infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                     param_env: ty::ParamEnv<'tcx>,
                                      projection_ty: ty::ProjectionTy<'tcx>,
                                      cause: ObligationCause<'tcx>)
                                      -> Ty<'tcx>
@@ -125,7 +126,11 @@ pub fn normalize_projection_type(&mut self,
         // FIXME(#20304) -- cache
 
         let mut selcx = SelectionContext::new(infcx);
-        let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0);
+        let normalized = project::normalize_projection_type(&mut selcx,
+                                                            param_env,
+                                                            projection_ty,
+                                                            cause,
+                                                            0);
 
         for obligation in normalized.obligations {
             self.register_predicate_obligation(infcx, obligation);
@@ -136,8 +141,12 @@ pub fn normalize_projection_type(&mut self,
         normalized.value
     }
 
+    /// Requires that `ty` must implement the trait with `def_id` in
+    /// the given environment. This trait must not have any type
+    /// parameters (except for `Self`).
     pub fn register_bound(&mut self,
                           infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                          param_env: ty::ParamEnv<'tcx>,
                           ty: Ty<'tcx>,
                           def_id: DefId,
                           cause: ObligationCause<'tcx>)
@@ -149,6 +158,7 @@ pub fn register_bound(&mut self,
         self.register_predicate_obligation(infcx, Obligation {
             cause: cause,
             recursion_depth: 0,
+            param_env,
             predicate: trait_ref.to_predicate()
         });
     }
@@ -410,7 +420,9 @@ fn process_predicate<'a, 'gcx, 'tcx>(
         }
 
         ty::Predicate::Equate(ref binder) => {
-            match selcx.infcx().equality_predicate(&obligation.cause, binder) {
+            match selcx.infcx().equality_predicate(&obligation.cause,
+                                                   obligation.param_env,
+                                                   binder) {
                 Ok(InferOk { obligations, value: () }) => {
                     Ok(Some(obligations))
                 },
@@ -498,7 +510,9 @@ fn process_predicate<'a, 'gcx, 'tcx>(
         }
 
         ty::Predicate::WellFormed(ty) => {
-            match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id,
+            match ty::wf::obligations(selcx.infcx(),
+                                      obligation.param_env,
+                                      obligation.cause.body_id,
                                       ty, obligation.cause.span) {
                 None => {
                     pending_obligation.stalled_on = vec![ty];
@@ -509,7 +523,9 @@ fn process_predicate<'a, 'gcx, 'tcx>(
         }
 
         ty::Predicate::Subtype(ref subtype) => {
-            match selcx.infcx().subtype_predicate(&obligation.cause, subtype) {
+            match selcx.infcx().subtype_predicate(&obligation.cause,
+                                                  obligation.param_env,
+                                                  subtype) {
                 None => {
                     // none means that both are unresolved
                     pending_obligation.stalled_on = vec![subtype.skip_binder().a,
index e358f39bd9a3a1356fb2130b3ea15cb1b382bcb9..c51974e6e670021a3f390f3739c1516b4538f148 100644 (file)
@@ -68,6 +68,7 @@
 #[derive(Clone, PartialEq, Eq)]
 pub struct Obligation<'tcx, T> {
     pub cause: ObligationCause<'tcx>,
+    pub param_env: ty::ParamEnv<'tcx>,
     pub recursion_depth: usize,
     pub predicate: T,
 }
@@ -359,10 +360,11 @@ pub struct VtableFnPointerData<'tcx, N> {
 
 /// Creates predicate obligations from the generic bounds.
 pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
+                                     param_env: ty::ParamEnv<'tcx>,
                                      generic_bounds: &ty::InstantiatedPredicates<'tcx>)
                                      -> PredicateObligations<'tcx>
 {
-    util::predicates_for_generics(cause, 0, generic_bounds)
+    util::predicates_for_generics(cause, 0, param_env, generic_bounds)
 }
 
 /// Determines whether the type `ty` is known to meet `bound` and
@@ -371,6 +373,7 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
 /// conservative towards *no impl*, which is the opposite of the
 /// `evaluate` methods).
 pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                                param_env: ty::ParamEnv<'tcx>,
                                                 ty: Ty<'tcx>,
                                                 def_id: DefId,
                                                 span: Span)
@@ -385,6 +388,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
         substs: infcx.tcx.mk_substs_trait(ty, &[]),
     };
     let obligation = Obligation {
+        param_env,
         cause: ObligationCause::misc(span, ast::DUMMY_NODE_ID),
         recursion_depth: 0,
         predicate: trait_ref.to_predicate(),
@@ -408,7 +412,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
         // anyhow).
         let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
 
-        fulfill_cx.register_bound(infcx, ty, def_id, cause);
+        fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
 
         // Note: we only assume something is `Copy` if we can
         // *definitively* show that it implements `Copy`. Otherwise,
@@ -477,24 +481,27 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
            predicates);
 
-    let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates));
+    let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
+                                           unnormalized_env.reveal);
 
-    tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| {
+    tcx.infer_ctxt(()).enter(|infcx| {
         let predicates = match fully_normalize(
-                &infcx, cause,
-                // You would really want to pass infcx.param_env.caller_bounds here,
-                // but that is an interned slice, and fully_normalize takes &T and returns T, so
-                // without further refactoring, a slice can't be used. Luckily, we still have the
-                // predicate vector from which we created the ParamEnv in infcx, so we
-                // can pass that instead. It's roundabout and a bit brittle, but this code path
-                // ought to be refactored anyway, and until then it saves us from having to copy.
-                &predicates,
+            &infcx,
+            cause,
+            elaborated_env,
+            // You would really want to pass infcx.param_env.caller_bounds here,
+            // but that is an interned slice, and fully_normalize takes &T and returns T, so
+            // without further refactoring, a slice can't be used. Luckily, we still have the
+            // predicate vector from which we created the ParamEnv in infcx, so we
+            // can pass that instead. It's roundabout and a bit brittle, but this code path
+            // ought to be refactored anyway, and until then it saves us from having to copy.
+            &predicates,
         ) {
             Ok(predicates) => predicates,
             Err(errors) => {
                 infcx.report_fulfillment_errors(&errors);
                 // An unnormalized env is better than nothing.
-                return infcx.param_env;
+                return elaborated_env;
             }
         };
 
@@ -516,24 +523,25 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 // all things considered.
                 tcx.sess.span_err(span, &fixup_err.to_string());
                 // An unnormalized env is better than nothing.
-                return infcx.param_env;
+                return elaborated_env;
             }
         };
 
         let predicates = match tcx.lift_to_global(&predicates) {
             Some(predicates) => predicates,
-            None => return infcx.param_env
+            None => return elaborated_env,
         };
 
         debug!("normalize_param_env_or_error: resolved predicates={:?}",
-            predicates);
+               predicates);
 
-        ty::ParamEnv::new(tcx.intern_predicates(&predicates))
+        ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal)
     })
 }
 
 pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                           cause: ObligationCause<'tcx>,
+                                          param_env: ty::ParamEnv<'tcx>,
                                           value: &T)
                                           -> Result<T, Vec<FulfillmentError<'tcx>>>
     where T : TypeFoldable<'tcx>
@@ -557,7 +565,7 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     let mut fulfill_cx = FulfillmentContext::new();
 
     let Normalized { value: normalized_value, obligations } =
-        project::normalize(selcx, cause, value);
+        project::normalize(selcx, param_env, cause, value);
     debug!("fully_normalize: normalized_value={:?} obligations={:?}",
            normalized_value,
            obligations);
@@ -579,10 +587,10 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     Ok(resolved_value)
 }
 
-/// Normalizes the predicates and checks whether they hold.  If this
-/// returns false, then either normalize encountered an error or one
-/// of the predicates did not hold. Used when creating vtables to
-/// check for unsatisfiable methods.
+/// Normalizes the predicates and checks whether they hold in an empty
+/// environment. If this returns false, then either normalize
+/// encountered an error or one of the predicates did not hold. Used
+/// when creating vtables to check for unsatisfiable methods.
 pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                predicates: Vec<ty::Predicate<'tcx>>)
                                                -> bool
@@ -590,17 +598,18 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("normalize_and_test_predicates(predicates={:?})",
            predicates);
 
-    tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
+    tcx.infer_ctxt(()).enter(|infcx| {
+        let param_env = ty::ParamEnv::empty(Reveal::All);
         let mut selcx = SelectionContext::new(&infcx);
         let mut fulfill_cx = FulfillmentContext::new();
         let cause = ObligationCause::dummy();
         let Normalized { value: predicates, obligations } =
-            normalize(&mut selcx, cause.clone(), &predicates);
+            normalize(&mut selcx, param_env, cause.clone(), &predicates);
         for obligation in obligations {
             fulfill_cx.register_predicate_obligation(&infcx, obligation);
         }
         for predicate in predicates {
-            let obligation = Obligation::new(cause.clone(), predicate);
+            let obligation = Obligation::new(cause.clone(), param_env, predicate);
             fulfill_cx.register_predicate_obligation(&infcx, obligation);
         }
 
@@ -662,30 +671,33 @@ pub fn get_vtable_methods<'a, 'tcx>(
 
 impl<'tcx,O> Obligation<'tcx,O> {
     pub fn new(cause: ObligationCause<'tcx>,
-               trait_ref: O)
+               param_env: ty::ParamEnv<'tcx>,
+               predicate: O)
                -> Obligation<'tcx, O>
     {
-        Obligation { cause: cause,
-                     recursion_depth: 0,
-                     predicate: trait_ref }
+        Obligation { cause, param_env, recursion_depth: 0, predicate }
     }
 
     fn with_depth(cause: ObligationCause<'tcx>,
                   recursion_depth: usize,
-                  trait_ref: O)
+                  param_env: ty::ParamEnv<'tcx>,
+                  predicate: O)
                   -> Obligation<'tcx, O>
     {
-        Obligation { cause: cause,
-                     recursion_depth: recursion_depth,
-                     predicate: trait_ref }
+        Obligation { cause, param_env, recursion_depth, predicate }
     }
 
-    pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> {
-        Obligation::new(ObligationCause::misc(span, body_id), trait_ref)
+    pub fn misc(span: Span,
+                body_id: ast::NodeId,
+                param_env: ty::ParamEnv<'tcx>,
+                trait_ref: O)
+                -> Obligation<'tcx, O> {
+        Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref)
     }
 
     pub fn with<P>(&self, value: P) -> Obligation<'tcx,P> {
         Obligation { cause: self.cause.clone(),
+                     param_env: self.param_env,
                      recursion_depth: self.recursion_depth,
                      predicate: value }
     }
index f5672ffbdc53498dc5eec9c959db753569d254ce..787452121d375c841f51665ea8b23706ded59789 100644 (file)
@@ -36,7 +36,7 @@
 
 /// Depending on the stage of compilation, we want projection to be
 /// more or less conservative.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub enum Reveal {
     /// At type-checking time, we refuse to project any associated
     /// type that is marked `default`. Non-`default` ("final") types
@@ -168,7 +168,8 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
 
     let Normalized { value: normalized_ty, mut obligations } =
         match opt_normalize_projection_type(selcx,
-                                            obligation.predicate.projection_ty.clone(),
+                                            obligation.param_env,
+                                            obligation.predicate.projection_ty,
                                             obligation.cause.clone(),
                                             obligation.recursion_depth) {
             Some(n) => n,
@@ -180,7 +181,8 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
            obligations);
 
     let infcx = selcx.infcx();
-    match infcx.eq_types(true, &obligation.cause, normalized_ty, obligation.predicate.ty) {
+    match infcx.at(&obligation.cause, obligation.param_env)
+               .eq(normalized_ty, obligation.predicate.ty) {
         Ok(InferOk { obligations: inferred_obligations, value: () }) => {
             obligations.extend(inferred_obligations);
             Ok(Some(obligations))
@@ -194,17 +196,19 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
 /// combines the normalized result and any additional obligations that
 /// were incurred as result.
 pub fn normalize<'a, 'b, 'gcx, 'tcx, T>(selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
+                                        param_env: ty::ParamEnv<'tcx>,
                                         cause: ObligationCause<'tcx>,
                                         value: &T)
                                         -> Normalized<'tcx, T>
     where T : TypeFoldable<'tcx>
 {
-    normalize_with_depth(selcx, cause, 0, value)
+    normalize_with_depth(selcx, param_env, cause, 0, value)
 }
 
 /// As `normalize`, but with a custom depth.
 pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>(
     selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize,
     value: &T)
@@ -213,7 +217,7 @@ pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>(
     where T : TypeFoldable<'tcx>
 {
     debug!("normalize_with_depth(depth={}, value={:?})", depth, value);
-    let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
+    let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, depth);
     let result = normalizer.fold(value);
     debug!("normalize_with_depth: depth={} result={:?} with {} obligations",
            depth, result, normalizer.obligations.len());
@@ -227,6 +231,7 @@ pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>(
 
 struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
     selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     cause: ObligationCause<'tcx>,
     obligations: Vec<PredicateObligation<'tcx>>,
     depth: usize,
@@ -234,12 +239,14 @@ struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
 
 impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
     fn new(selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
+           param_env: ty::ParamEnv<'tcx>,
            cause: ObligationCause<'tcx>,
            depth: usize)
            -> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx>
     {
         AssociatedTypeNormalizer {
             selcx: selcx,
+            param_env: param_env,
             cause: cause,
             obligations: vec![],
             depth: depth,
@@ -278,12 +285,14 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         match ty.sty {
             ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*)
                 // Only normalize `impl Trait` after type-checking, usually in trans.
-                if self.selcx.projection_mode() == Reveal::All {
-                    let generic_ty = self.tcx().type_of(def_id);
-                    let concrete_ty = generic_ty.subst(self.tcx(), substs);
-                    self.fold_ty(concrete_ty)
-                } else {
-                    ty
+                match self.param_env.reveal {
+                    Reveal::UserFacing => ty,
+
+                    Reveal::All => {
+                        let generic_ty = self.tcx().type_of(def_id);
+                        let concrete_ty = generic_ty.subst(self.tcx(), substs);
+                        self.fold_ty(concrete_ty)
+                    }
                 }
             }
 
@@ -303,6 +312,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
 
                 let Normalized { value: normalized_ty, obligations } =
                     normalize_projection_type(self.selcx,
+                                              self.param_env,
                                               data.clone(),
                                               self.cause.clone(),
                                               self.depth);
@@ -342,12 +352,13 @@ pub fn with<U>(self, value: U) -> Normalized<'tcx,U> {
 /// obligation `<T as Trait>::Item == $X` for later.
 pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
     selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     projection_ty: ty::ProjectionTy<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize)
     -> NormalizedTy<'tcx>
 {
-    opt_normalize_projection_type(selcx, projection_ty.clone(), cause.clone(), depth)
+    opt_normalize_projection_type(selcx, param_env, projection_ty.clone(), cause.clone(), depth)
         .unwrap_or_else(move || {
             // if we bottom out in ambiguity, create a type variable
             // and a deferred predicate to resolve this when more type
@@ -364,7 +375,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                 ty: ty_var
             });
             let obligation = Obligation::with_depth(
-                cause, depth + 1, projection.to_predicate());
+                cause, depth + 1, param_env, projection.to_predicate());
             Normalized {
                 value: ty_var,
                 obligations: vec![obligation]
@@ -378,6 +389,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
 /// which indicates that there are unbound type variables.
 fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
     selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     projection_ty: ty::ProjectionTy<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize)
@@ -447,6 +459,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             let recursion_limit = selcx.tcx().sess.recursion_limit.get();
             let obligation = Obligation::with_depth(cause.clone(),
                                                     recursion_limit,
+                                                    param_env,
                                                     projection_ty);
             selcx.infcx().report_overflow_error(&obligation, false);
         }
@@ -462,11 +475,11 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
         Err(ProjectionCacheEntry::Error) => {
             debug!("opt_normalize_projection_type: \
                     found error");
-            return Some(normalize_to_error(selcx, projection_ty, cause, depth));
+            return Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth));
         }
     }
 
-    let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone());
+    let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
     match project_type(selcx, &obligation) {
         Ok(ProjectedTy::Progress(Progress { ty: projected_ty,
                                             mut obligations,
@@ -487,7 +500,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                    cacheable);
 
             let result = if projected_ty.has_projection_types() {
-                let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth+1);
+                let mut normalizer = AssociatedTypeNormalizer::new(selcx,
+                                                                   param_env,
+                                                                   cause,
+                                                                   depth+1);
                 let normalized_ty = normalizer.fold(&projected_ty);
 
                 debug!("opt_normalize_projection_type: \
@@ -538,7 +554,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
 
             infcx.projection_cache.borrow_mut()
                                   .error(projection_ty);
-            Some(normalize_to_error(selcx, projection_ty, cause, depth))
+            Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth))
         }
     }
 }
@@ -563,6 +579,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
 /// because it contains `[type error]`. Yuck! (See issue #29857 for
 /// one case where this arose.)
 fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
+                                      param_env: ty::ParamEnv<'tcx>,
                                       projection_ty: ty::ProjectionTy<'tcx>,
                                       cause: ObligationCause<'tcx>,
                                       depth: usize)
@@ -571,6 +588,7 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc
     let trait_ref = projection_ty.trait_ref.to_poly_trait_ref();
     let trait_obligation = Obligation { cause: cause,
                                         recursion_depth: depth,
+                                        param_env,
                                         predicate: trait_ref.to_predicate() };
     let tcx = selcx.infcx().tcx;
     let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i|
@@ -744,13 +762,12 @@ fn assemble_candidates_from_param_env<'cx, 'gcx, 'tcx>(
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
 {
     debug!("assemble_candidates_from_param_env(..)");
-    let env_predicates = selcx.param_env().caller_bounds.iter().cloned();
     assemble_candidates_from_predicates(selcx,
                                         obligation,
                                         obligation_trait_ref,
                                         candidate_set,
                                         ProjectionTyCandidate::ParamEnv,
-                                        env_predicates);
+                                        obligation.param_env.caller_bounds.iter().cloned());
 }
 
 /// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
@@ -805,7 +822,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
     ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
     env_predicates: I)
-    where I: Iterator<Item=ty::Predicate<'tcx>>
+    where I: IntoIterator<Item=ty::Predicate<'tcx>>
 {
     debug!("assemble_candidates_from_predicates(obligation={:?})",
            obligation);
@@ -823,15 +840,13 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
                         data.to_poly_trait_ref();
                     let obligation_poly_trait_ref =
                         obligation_trait_ref.to_poly_trait_ref();
-                    infcx.sub_poly_trait_refs(false,
-                                              obligation.cause.clone(),
-                                              data_poly_trait_ref,
-                                              obligation_poly_trait_ref)
-                        .map(|InferOk { obligations: _, value: () }| {
-                            // FIXME(#32730) -- do we need to take obligations
-                            // into account in any way? At the moment, no.
-                        })
-                        .is_ok()
+                    infcx.at(&obligation.cause, obligation.param_env)
+                         .sup(obligation_poly_trait_ref, data_poly_trait_ref)
+                         .map(|InferOk { obligations: _, value: () }| {
+                             // FIXME(#32730) -- do we need to take obligations
+                             // into account in any way? At the moment, no.
+                         })
+                         .is_ok()
                 });
 
                 debug!("assemble_candidates_from_predicates: candidate={:?} \
@@ -934,7 +949,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                 // get a result which isn't correct for all monomorphizations.
                 let new_candidate = if !is_default {
                     Some(ProjectionTyCandidate::Select)
-                } else if selcx.projection_mode() == Reveal::All {
+                } else if obligation.param_env.reveal == Reveal::All {
                     assert!(!poly_trait_ref.needs_infer());
                     if !poly_trait_ref.needs_subst() {
                         Some(ProjectionTyCandidate::Select)
@@ -1092,10 +1107,9 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
             let data_poly_trait_ref = data.to_poly_trait_ref();
             let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
             selcx.infcx().probe(|_| {
-                selcx.infcx().sub_poly_trait_refs(false,
-                                                  obligation.cause.clone(),
-                                                  data_poly_trait_ref,
-                                                  obligation_poly_trait_ref).is_ok()
+                selcx.infcx().at(&obligation.cause, obligation.param_env)
+                             .sup(obligation_poly_trait_ref, data_poly_trait_ref)
+                             .is_ok()
             })
         });
 
@@ -1141,6 +1155,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
         value: closure_type,
         obligations
     } = normalize_with_depth(selcx,
+                             obligation.param_env,
                              obligation.cause.clone(),
                              obligation.recursion_depth+1,
                              &closure_type);
@@ -1201,8 +1216,9 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
 {
     let infcx = selcx.infcx();
     let cause = obligation.cause.clone();
+    let param_env = obligation.param_env;
     let trait_ref = obligation.predicate.trait_ref;
-    match infcx.match_poly_projection_predicate(cause, poly_projection, trait_ref) {
+    match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) {
         Ok(InferOk { value: ty_match, obligations }) => {
             Progress {
                 ty: ty_match.value,
@@ -1231,6 +1247,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
     let VtableImplData { substs, nested, impl_def_id } = impl_vtable;
 
     let tcx = selcx.tcx();
+    let param_env = obligation.param_env;
     let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name(tcx));
 
     let ty = if !assoc_ty.item.defaultness.has_value() {
@@ -1245,7 +1262,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
     } else {
         tcx.type_of(assoc_ty.item.def_id)
     };
-    let substs = translate_substs(selcx.infcx(), impl_def_id, substs, assoc_ty.node);
+    let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node);
     Progress {
         ty: ty.subst(tcx, substs),
         obligations: nested,
index 7366ed45f31bd514f96279377cbd36433dfe1e26..998201ad8d9ffd685b56dc98d4c91b7e9ed3e295 100644 (file)
@@ -21,7 +21,6 @@
 use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
 use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
 use super::{ObjectCastObligation, Obligation};
-use super::Reveal;
 use super::TraitNotObjectSafe;
 use super::Selection;
 use super::SelectionResult;
@@ -315,18 +314,10 @@ pub fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
-    pub fn param_env(&self) -> ty::ParamEnv<'gcx> {
-        self.infcx.param_env()
-    }
-
     pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> {
         self.infcx
     }
 
-    pub fn projection_mode(&self) -> Reveal {
-        self.infcx.projection_mode()
-    }
-
     /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
     /// context's self.
     fn in_snapshot<R, F>(&mut self, f: F) -> R
@@ -540,7 +531,7 @@ fn evaluate_predicate_recursively<'o>(&mut self,
 
             ty::Predicate::Equate(ref p) => {
                 // does this code ever run?
-                match self.infcx.equality_predicate(&obligation.cause, p) {
+                match self.infcx.equality_predicate(&obligation.cause, obligation.param_env, p) {
                     Ok(InferOk { obligations, .. }) => {
                         self.inferred_obligations.extend(obligations);
                         EvaluatedToOk
@@ -551,7 +542,7 @@ fn evaluate_predicate_recursively<'o>(&mut self,
 
             ty::Predicate::Subtype(ref p) => {
                 // does this code ever run?
-                match self.infcx.subtype_predicate(&obligation.cause, p) {
+                match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
                     Some(Ok(InferOk { obligations, .. })) => {
                         self.inferred_obligations.extend(obligations);
                         EvaluatedToOk
@@ -562,7 +553,9 @@ fn evaluate_predicate_recursively<'o>(&mut self,
             }
 
             ty::Predicate::WellFormed(ty) => {
-                match ty::wf::obligations(self.infcx, obligation.cause.body_id,
+                match ty::wf::obligations(self.infcx,
+                                          obligation.param_env,
+                                          obligation.cause.body_id,
                                           ty, obligation.cause.span) {
                     Some(obligations) =>
                         self.evaluate_predicates_recursively(previous_stack, obligations.iter()),
@@ -628,7 +621,7 @@ fn evaluate_obligation_recursively<'o>(&mut self,
 
         let stack = self.push_stack(previous_stack, obligation);
         let fresh_trait_ref = stack.fresh_trait_ref;
-        if let Some(result) = self.check_evaluation_cache(fresh_trait_ref) {
+        if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
             debug!("CACHE HIT: EVAL({:?})={:?}",
                    fresh_trait_ref,
                    result);
@@ -640,7 +633,7 @@ fn evaluate_obligation_recursively<'o>(&mut self,
         debug!("CACHE MISS: EVAL({:?})={:?}",
                fresh_trait_ref,
                result);
-        self.insert_evaluation_cache(fresh_trait_ref, result);
+        self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, result);
 
         result
     }
@@ -751,10 +744,12 @@ fn evaluate_candidate<'o>(&mut self,
         result
     }
 
-    fn check_evaluation_cache(&self, trait_ref: ty::PolyTraitRef<'tcx>)
+    fn check_evaluation_cache(&self,
+                              param_env: ty::ParamEnv<'tcx>,
+                              trait_ref: ty::PolyTraitRef<'tcx>)
                               -> Option<EvaluationResult>
     {
-        if self.can_use_global_caches() {
+        if self.can_use_global_caches(param_env) {
             let cache = self.tcx().evaluation_cache.hashmap.borrow();
             if let Some(cached) = cache.get(&trait_ref) {
                 return Some(cached.clone());
@@ -764,6 +759,7 @@ fn check_evaluation_cache(&self, trait_ref: ty::PolyTraitRef<'tcx>)
     }
 
     fn insert_evaluation_cache(&mut self,
+                               param_env: ty::ParamEnv<'tcx>,
                                trait_ref: ty::PolyTraitRef<'tcx>,
                                result: EvaluationResult)
     {
@@ -778,7 +774,7 @@ fn insert_evaluation_cache(&mut self,
             return;
         }
 
-        if self.can_use_global_caches() {
+        if self.can_use_global_caches(param_env) {
             let mut cache = self.tcx().evaluation_cache.hashmap.borrow_mut();
             if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) {
                 cache.insert(trait_ref, result);
@@ -819,7 +815,8 @@ fn candidate_from_obligation<'o>(&mut self,
                stack);
         assert!(!stack.obligation.predicate.has_escaping_regions());
 
-        if let Some(c) = self.check_candidate_cache(&cache_fresh_trait_pred) {
+        if let Some(c) = self.check_candidate_cache(stack.obligation.param_env,
+                                                    &cache_fresh_trait_pred) {
             debug!("CACHE HIT: SELECT({:?})={:?}",
                    cache_fresh_trait_pred,
                    c);
@@ -832,7 +829,9 @@ fn candidate_from_obligation<'o>(&mut self,
         if self.should_update_candidate_cache(&cache_fresh_trait_pred, &candidate) {
             debug!("CACHE MISS: SELECT({:?})={:?}",
                    cache_fresh_trait_pred, candidate);
-            self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone());
+            self.insert_candidate_cache(stack.obligation.param_env,
+                                        cache_fresh_trait_pred,
+                                        candidate.clone());
         }
 
         candidate
@@ -995,7 +994,7 @@ fn is_knowable<'o>(&mut self,
     /// Returns true if the global caches can be used.
     /// Do note that if the type itself is not in the
     /// global tcx, the local caches will be used.
-    fn can_use_global_caches(&self) -> bool {
+    fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
         // If there are any where-clauses in scope, then we always use
         // a cache local to this particular scope. Otherwise, we
         // switch to a global cache. We used to try and draw
@@ -1003,7 +1002,7 @@ fn can_use_global_caches(&self) -> bool {
         // annoying and weird bugs like #22019 and #18290. This simple
         // rule seems to be pretty clearly safe and also still retains
         // a very high hit rate (~95% when compiling rustc).
-        if !self.param_env().caller_bounds.is_empty() {
+        if !param_env.caller_bounds.is_empty() {
             return false;
         }
 
@@ -1023,11 +1022,12 @@ fn can_use_global_caches(&self) -> bool {
     }
 
     fn check_candidate_cache(&mut self,
+                             param_env: ty::ParamEnv<'tcx>,
                              cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>)
                              -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>>
     {
         let trait_ref = &cache_fresh_trait_pred.0.trait_ref;
-        if self.can_use_global_caches() {
+        if self.can_use_global_caches(param_env) {
             let cache = self.tcx().selection_cache.hashmap.borrow();
             if let Some(cached) = cache.get(&trait_ref) {
                 return Some(cached.clone());
@@ -1037,11 +1037,12 @@ fn check_candidate_cache(&mut self,
     }
 
     fn insert_candidate_cache(&mut self,
+                              param_env: ty::ParamEnv<'tcx>,
                               cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
                               candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>)
     {
         let trait_ref = cache_fresh_trait_pred.0.trait_ref;
-        if self.can_use_global_caches() {
+        if self.can_use_global_caches(param_env) {
             let mut cache = self.tcx().selection_cache.hashmap.borrow_mut();
             if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) {
                 if let Some(candidate) = self.tcx().lift_to_global(&candidate) {
@@ -1099,6 +1100,7 @@ fn assemble_candidates<'o>(&mut self,
     {
         let TraitObligationStack { obligation, .. } = *stack;
         let ref obligation = Obligation {
+            param_env: obligation.param_env,
             cause: obligation.cause.clone(),
             recursion_depth: obligation.recursion_depth,
             predicate: self.infcx().resolve_type_vars_if_possible(&obligation.predicate)
@@ -1269,11 +1271,8 @@ fn match_projection(&mut self,
                         -> bool
     {
         assert!(!skol_trait_ref.has_escaping_regions());
-        let cause = obligation.cause.clone();
-        match self.infcx.sub_poly_trait_refs(false,
-                                             cause,
-                                             trait_bound.clone(),
-                                             ty::Binder(skol_trait_ref.clone())) {
+        match self.infcx.at(&obligation.cause, obligation.param_env)
+                        .sup(ty::Binder(skol_trait_ref), trait_bound) {
             Ok(InferOk { obligations, .. }) => {
                 self.inferred_obligations.extend(obligations);
             }
@@ -1296,9 +1295,9 @@ fn assemble_candidates_from_caller_bounds<'o>(&mut self,
                stack.obligation);
 
         let all_bounds =
-            self.param_env().caller_bounds
-                            .iter()
-                            .filter_map(|o| o.to_opt_poly_trait_ref());
+            stack.obligation.param_env.caller_bounds
+                                      .iter()
+                                      .filter_map(|o| o.to_opt_poly_trait_ref());
 
         // micro-optimization: filter out predicates relating to different
         // traits.
@@ -1953,6 +1952,7 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
     }
 
     fn collect_predicates_for_types(&mut self,
+                                    param_env: ty::ParamEnv<'tcx>,
                                     cause: ObligationCause<'tcx>,
                                     recursion_depth: usize,
                                     trait_def_id: DefId,
@@ -1981,16 +1981,17 @@ fn collect_predicates_for_types(&mut self,
                     this.infcx().skolemize_late_bound_regions(&ty, snapshot);
                 let Normalized { value: normalized_ty, mut obligations } =
                     project::normalize_with_depth(this,
+                                                  param_env,
                                                   cause.clone(),
                                                   recursion_depth,
                                                   &skol_ty);
                 let skol_obligation =
-                    this.tcx().predicate_for_trait_def(
-                                                  cause.clone(),
-                                                  trait_def_id,
-                                                  recursion_depth,
-                                                  normalized_ty,
-                                                  &[]);
+                    this.tcx().predicate_for_trait_def(param_env,
+                                                       cause.clone(),
+                                                       trait_def_id,
+                                                       recursion_depth,
+                                                       normalized_ty,
+                                                       &[]);
                 obligations.push(skol_obligation);
                 this.infcx().plug_leaks(skol_map, snapshot, obligations)
             })
@@ -2131,7 +2132,8 @@ fn confirm_builtin_candidate(&mut self,
             };
 
             let cause = obligation.derived_cause(BuiltinDerivedObligation);
-            self.collect_predicates_for_types(cause,
+            self.collect_predicates_for_types(obligation.param_env,
+                                              cause,
                                               obligation.recursion_depth+1,
                                               trait_def,
                                               nested)
@@ -2175,6 +2177,7 @@ fn vtable_default_impl(&mut self,
 
         let cause = obligation.derived_cause(BuiltinDerivedObligation);
         let mut obligations = self.collect_predicates_for_types(
+            obligation.param_env,
             cause,
             obligation.recursion_depth+1,
             trait_def_id,
@@ -2187,6 +2190,7 @@ fn vtable_default_impl(&mut self,
             let cause = obligation.derived_cause(ImplDerivedObligation);
             this.impl_or_trait_obligations(cause,
                                            obligation.recursion_depth + 1,
+                                           obligation.param_env,
                                            trait_def_id,
                                            &trait_ref.substs,
                                            skol_map,
@@ -2220,9 +2224,13 @@ fn confirm_impl_candidate(&mut self,
                                   snapshot);
             debug!("confirm_impl_candidate substs={:?}", substs);
             let cause = obligation.derived_cause(ImplDerivedObligation);
-            this.vtable_impl(impl_def_id, substs, cause,
+            this.vtable_impl(impl_def_id,
+                             substs,
+                             cause,
                              obligation.recursion_depth + 1,
-                             skol_map, snapshot)
+                             obligation.param_env,
+                             skol_map,
+                             snapshot)
         })
     }
 
@@ -2231,6 +2239,7 @@ fn vtable_impl(&mut self,
                    mut substs: Normalized<'tcx, &'tcx Substs<'tcx>>,
                    cause: ObligationCause<'tcx>,
                    recursion_depth: usize,
+                   param_env: ty::ParamEnv<'tcx>,
                    skol_map: infer::SkolemizationMap<'tcx>,
                    snapshot: &infer::CombinedSnapshot)
                    -> VtableImplData<'tcx, PredicateObligation<'tcx>>
@@ -2244,6 +2253,7 @@ fn vtable_impl(&mut self,
         let mut impl_obligations =
             self.impl_or_trait_obligations(cause,
                                            recursion_depth,
+                                           param_env,
                                            impl_def_id,
                                            &substs.value,
                                            skol_map,
@@ -2345,6 +2355,7 @@ fn confirm_fn_pointer_candidate(&mut self, obligation: &TraitObligation<'tcx>)
             .map_bound(|(trait_ref, _)| trait_ref);
 
         self.confirm_poly_trait_refs(obligation.cause.clone(),
+                                     obligation.param_env,
                                      obligation.predicate.to_poly_trait_ref(),
                                      trait_ref)?;
         Ok(VtableFnPointerData { fn_ty: self_ty, nested: vec![] })
@@ -2374,12 +2385,14 @@ fn confirm_closure_candidate(&mut self,
                obligations);
 
         self.confirm_poly_trait_refs(obligation.cause.clone(),
+                                     obligation.param_env,
                                      obligation.predicate.to_poly_trait_ref(),
                                      trait_ref)?;
 
         obligations.push(Obligation::new(
-                obligation.cause.clone(),
-                ty::Predicate::ClosureKind(closure_def_id, kind)));
+            obligation.cause.clone(),
+            obligation.param_env,
+            ty::Predicate::ClosureKind(closure_def_id, kind)));
 
         Ok(VtableClosureData {
             closure_def_id: closure_def_id,
@@ -2415,15 +2428,15 @@ fn confirm_closure_candidate(&mut self,
     /// report an error to the user.
     fn confirm_poly_trait_refs(&mut self,
                                obligation_cause: ObligationCause<'tcx>,
+                               obligation_param_env: ty::ParamEnv<'tcx>,
                                obligation_trait_ref: ty::PolyTraitRef<'tcx>,
                                expected_trait_ref: ty::PolyTraitRef<'tcx>)
                                -> Result<(), SelectionError<'tcx>>
     {
         let obligation_trait_ref = obligation_trait_ref.clone();
-        self.infcx.sub_poly_trait_refs(false,
-                                       obligation_cause.clone(),
-                                       expected_trait_ref.clone(),
-                                       obligation_trait_ref.clone())
+        self.infcx
+            .at(&obligation_cause, obligation_param_env)
+            .sup(obligation_trait_ref, expected_trait_ref)
             .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
             .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
     }
@@ -2458,8 +2471,9 @@ fn confirm_builtin_unsize_candidate(&mut self,
                 let new_trait = tcx.mk_dynamic(
                     ty::Binder(tcx.mk_existential_predicates(iter)), r_b);
                 let InferOk { obligations, .. } =
-                    self.infcx.eq_types(false, &obligation.cause, new_trait, target)
-                    .map_err(|_| Unimplemented)?;
+                    self.infcx.at(&obligation.cause, obligation.param_env)
+                              .eq(target, new_trait)
+                              .map_err(|_| Unimplemented)?;
                 self.inferred_obligations.extend(obligations);
 
                 // Register one obligation for 'a: 'b.
@@ -2469,6 +2483,7 @@ fn confirm_builtin_unsize_candidate(&mut self,
                 let outlives = ty::OutlivesPredicate(r_a, r_b);
                 nested.push(Obligation::with_depth(cause,
                                                    obligation.recursion_depth + 1,
+                                                   obligation.param_env,
                                                    ty::Binder(outlives).to_predicate()));
             }
 
@@ -2488,6 +2503,7 @@ fn confirm_builtin_unsize_candidate(&mut self,
                 let mut push = |predicate| {
                     nested.push(Obligation::with_depth(cause.clone(),
                                                        obligation.recursion_depth + 1,
+                                                       obligation.param_env,
                                                        predicate));
                 };
 
@@ -2517,8 +2533,9 @@ fn confirm_builtin_unsize_candidate(&mut self,
             // [T; n] -> [T].
             (&ty::TyArray(a, _), &ty::TySlice(b)) => {
                 let InferOk { obligations, .. } =
-                    self.infcx.eq_types(false, &obligation.cause, a, b)
-                    .map_err(|_| Unimplemented)?;
+                    self.infcx.at(&obligation.cause, obligation.param_env)
+                              .eq(b, a)
+                              .map_err(|_| Unimplemented)?;
                 self.inferred_obligations.extend(obligations);
             }
 
@@ -2580,12 +2597,14 @@ fn confirm_builtin_unsize_candidate(&mut self,
                 });
                 let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
                 let InferOk { obligations, .. } =
-                    self.infcx.eq_types(false, &obligation.cause, new_struct, target)
-                    .map_err(|_| Unimplemented)?;
+                    self.infcx.at(&obligation.cause, obligation.param_env)
+                              .eq(target, new_struct)
+                              .map_err(|_| Unimplemented)?;
                 self.inferred_obligations.extend(obligations);
 
                 // Construct the nested Field<T>: Unsize<Field<U>> predicate.
                 nested.push(tcx.predicate_for_trait_def(
+                    obligation.param_env,
                     obligation.cause.clone(),
                     obligation.predicate.def_id(),
                     obligation.recursion_depth + 1,
@@ -2655,6 +2674,7 @@ fn match_impl(&mut self,
 
         let impl_trait_ref =
             project::normalize_with_depth(self,
+                                          obligation.param_env,
                                           obligation.cause.clone(),
                                           obligation.recursion_depth + 1,
                                           &impl_trait_ref);
@@ -2667,14 +2687,12 @@ fn match_impl(&mut self,
                skol_obligation_trait_ref);
 
         let InferOk { obligations, .. } =
-            self.infcx.eq_trait_refs(false,
-                                     &obligation.cause,
-                                     impl_trait_ref.value.clone(),
-                                     skol_obligation_trait_ref)
-            .map_err(|e| {
-                debug!("match_impl: failed eq_trait_refs due to `{}`", e);
-                ()
-            })?;
+            self.infcx.at(&obligation.cause, obligation.param_env)
+                      .eq(skol_obligation_trait_ref, impl_trait_ref.value)
+                      .map_err(|e| {
+                          debug!("match_impl: failed eq_trait_refs due to `{}`", e);
+                          ()
+                      })?;
         self.inferred_obligations.extend(obligations);
 
         if let Err(e) = self.infcx.leak_check(false,
@@ -2740,12 +2758,10 @@ fn match_poly_trait_ref(&mut self,
                obligation,
                poly_trait_ref);
 
-        self.infcx.sub_poly_trait_refs(false,
-                                       obligation.cause.clone(),
-                                       poly_trait_ref,
-                                       obligation.predicate.to_poly_trait_ref())
-            .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
-            .map_err(|_| ())
+        self.infcx.at(&obligation.cause, obligation.param_env)
+                  .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
+                  .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
+                  .map_err(|_| ())
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -2809,6 +2825,7 @@ fn closure_trait_ref(&mut self,
         // A closure signature can contain associated types which
         // must be normalized.
         normalize_with_depth(self,
+                             obligation.param_env,
                              obligation.cause.clone(),
                              obligation.recursion_depth+1,
                              &trait_ref)
@@ -2821,6 +2838,7 @@ fn closure_trait_ref(&mut self,
     fn impl_or_trait_obligations(&mut self,
                                  cause: ObligationCause<'tcx>,
                                  recursion_depth: usize,
+                                 param_env: ty::ParamEnv<'tcx>,
                                  def_id: DefId, // of impl or trait
                                  substs: &Substs<'tcx>, // for impl or trait
                                  skol_map: infer::SkolemizationMap<'tcx>,
@@ -2847,12 +2865,13 @@ fn impl_or_trait_obligations(&mut self,
         let predicates = tcx.predicates_of(def_id);
         assert_eq!(predicates.parent, None);
         let predicates = predicates.predicates.iter().flat_map(|predicate| {
-            let predicate = normalize_with_depth(self, cause.clone(), recursion_depth,
+            let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth,
                                                  &predicate.subst(tcx, substs));
             predicate.obligations.into_iter().chain(
                 Some(Obligation {
                     cause: cause.clone(),
                     recursion_depth: recursion_depth,
+                    param_env,
                     predicate: predicate.value
                 }))
         }).collect();
index e0f28e3b49e919832a56b8bc738e0b2f6d983fe2..689f06a359730056625988161a583642fe1eef36 100644 (file)
@@ -41,6 +41,7 @@ pub struct OverlapError {
 /// Given a subst for the requested impl, translate it to a subst
 /// appropriate for the actual item definition (whether it be in that impl,
 /// a parent impl, or the trait).
+///
 /// When we have selected one impl, but are actually using item definitions from
 /// a parent impl providing a default, we need a way to translate between the
 /// type parameters of the two impls. Here the `source_impl` is the one we've
@@ -73,6 +74,7 @@ pub struct OverlapError {
 /// *fulfillment* to relate the two impls, requiring that all projections are
 /// resolved.
 pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                        param_env: ty::ParamEnv<'tcx>,
                                         source_impl: DefId,
                                         source_substs: &'tcx Substs<'tcx>,
                                         target_node: specialization_graph::Node)
@@ -91,10 +93,11 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                 return source_substs;
             }
 
-            fulfill_implication(infcx, source_trait_ref, target_impl).unwrap_or_else(|_| {
-                bug!("When translating substitutions for specialization, the expected \
-                      specializaiton failed to hold")
-            })
+            fulfill_implication(infcx, param_env, source_trait_ref, target_impl)
+                .unwrap_or_else(|_| {
+                    bug!("When translating substitutions for specialization, the expected \
+                          specializaiton failed to hold")
+                })
         }
         specialization_graph::Node::Trait(..) => source_trait_ref.substs,
     };
@@ -122,9 +125,10 @@ pub fn find_associated_item<'a, 'tcx>(
     let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id);
     match ancestors.defs(tcx, item.name, item.kind).next() {
         Some(node_item) => {
-            let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
+            let substs = tcx.infer_ctxt(()).enter(|infcx| {
+                let param_env = ty::ParamEnv::empty(Reveal::All);
                 let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
-                let substs = translate_substs(&infcx, impl_data.impl_def_id,
+                let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id,
                                               substs, node_item.node);
                 let substs = infcx.tcx.erase_regions(&substs);
                 tcx.lift(&substs).unwrap_or_else(|| {
@@ -184,11 +188,14 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
 
     // Create a infcx, taking the predicates of impl1 as assumptions:
-    let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| {
+    let result = tcx.infer_ctxt(()).enter(|infcx| {
         // Normalize the trait reference. The WF rules ought to ensure
         // that this always succeeds.
         let impl1_trait_ref =
-            match traits::fully_normalize(&infcx, ObligationCause::dummy(), &impl1_trait_ref) {
+            match traits::fully_normalize(&infcx,
+                                          ObligationCause::dummy(),
+                                          penv,
+                                          &impl1_trait_ref) {
                 Ok(impl1_trait_ref) => impl1_trait_ref,
                 Err(err) => {
                     bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
@@ -196,7 +203,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             };
 
         // Attempt to prove that impl2 applies, given all of the above.
-        fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
+        fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
     });
 
     tcx.specializes_cache.borrow_mut().insert(impl1_def_id, impl2_def_id, result);
@@ -209,20 +216,20 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// `source_trait_ref` and those whose identity is determined via a where
 /// clause in the impl.
 fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                       param_env: ty::ParamEnv<'tcx>,
                                        source_trait_ref: ty::TraitRef<'tcx>,
                                        target_impl: DefId)
                                        -> Result<&'tcx Substs<'tcx>, ()> {
     let selcx = &mut SelectionContext::new(&infcx);
     let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
     let (target_trait_ref, mut obligations) = impl_trait_ref_and_oblig(selcx,
-                                                                   target_impl,
-                                                                   target_substs);
+                                                                       param_env,
+                                                                       target_impl,
+                                                                       target_substs);
 
     // do the impls unify? If not, no specialization.
-    match infcx.eq_trait_refs(true,
-                              &ObligationCause::dummy(),
-                              source_trait_ref,
-                              target_trait_ref) {
+    match infcx.at(&ObligationCause::dummy(), param_env)
+               .eq(source_trait_ref, target_trait_ref) {
         Ok(InferOk { obligations: o, .. }) => {
             obligations.extend(o);
         }
@@ -250,7 +257,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                        source_trait_ref,
                        target_trait_ref,
                        errors,
-                       infcx.param_env.caller_bounds);
+                       param_env.caller_bounds);
                 Err(())
             }
 
index 87c98a0ef0ed6daf16839d7a96f712dd99bde1f4..702c5035a18b721e9708f6fa1ab81afde4b18f09 100644 (file)
@@ -11,7 +11,7 @@
 use super::{OverlapError, specializes};
 
 use hir::def_id::DefId;
-use traits::{self, Reveal};
+use traits;
 use ty::{self, TyCtxt, TypeFoldable};
 use ty::fast_reject::{self, SimplifiedType};
 use std::rc::Rc;
@@ -109,7 +109,7 @@ fn insert(&mut self,
             let possible_sibling = *slot;
 
             let tcx = tcx.global_tcx();
-            let (le, ge) = tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+            let (le, ge) = tcx.infer_ctxt(()).enter(|infcx| {
                 let overlap = traits::overlapping_impls(&infcx,
                                                         possible_sibling,
                                                         impl_def_id);
index 9d0b1035ade497076f6c76cb116da4dbc36317d3..4abb0cb549db45add7ce5f917660a282bc030f72 100644 (file)
@@ -341,6 +341,7 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
             cause: self.cause.clone(),
             recursion_depth: self.recursion_depth,
             predicate: self.predicate.fold_with(folder),
+            param_env: self.param_env.fold_with(folder),
         }
     }
 
index e38306aed2a91b9e7a0ffeac8bbe57bf32547ef1..7ad2ef90f0d49fc2eb8f7eb5654695d8d9c821ef 100644 (file)
@@ -46,12 +46,14 @@ pub fn trans_fulfill_obligation(self,
 
             // Do the initial selection for the obligation. This yields the
             // shallow result we are looking for -- that is, what specific impl.
-            self.infer_ctxt((), Reveal::All).enter(|infcx| {
+            self.infer_ctxt(()).enter(|infcx| {
                 let mut selcx = SelectionContext::new(&infcx);
 
+                let param_env = ty::ParamEnv::empty(Reveal::All);
                 let obligation_cause = ObligationCause::misc(span,
                                                              ast::DUMMY_NODE_ID);
                 let obligation = Obligation::new(obligation_cause,
+                                                 param_env,
                                                  trait_ref.to_poly_trait_predicate());
 
                 let selection = match selcx.select(&obligation) {
index 3f5cf7eca53077bd48c8900e3093d33b3b9799b2..c385927811cf7532aac7bcad629670ab58c19340 100644 (file)
@@ -358,6 +358,7 @@ fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
 /// returning the resulting trait ref and all obligations that arise.
 /// The obligations are closed under normalization.
 pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
+                                                param_env: ty::ParamEnv<'tcx>,
                                                 impl_def_id: DefId,
                                                 impl_substs: &Substs<'tcx>)
                                                 -> (ty::TraitRef<'tcx>,
@@ -368,14 +369,14 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a,
     let impl_trait_ref =
         impl_trait_ref.subst(selcx.tcx(), impl_substs);
     let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } =
-        super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref);
+        super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref);
 
     let predicates = selcx.tcx().predicates_of(impl_def_id);
     let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
     let Normalized { value: predicates, obligations: normalization_obligations2 } =
-        super::normalize(selcx, ObligationCause::dummy(), &predicates);
+        super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates);
     let impl_obligations =
-        predicates_for_generics(ObligationCause::dummy(), 0, &predicates);
+        predicates_for_generics(ObligationCause::dummy(), 0, param_env, &predicates);
 
     let impl_obligations: Vec<_> =
         impl_obligations.into_iter()
@@ -389,6 +390,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a,
 /// See `super::obligations_for_generics`
 pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
                                      recursion_depth: usize,
+                                     param_env: ty::ParamEnv<'tcx>,
                                      generic_bounds: &ty::InstantiatedPredicates<'tcx>)
                                      -> Vec<PredicateObligation<'tcx>>
 {
@@ -398,18 +400,21 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
     generic_bounds.predicates.iter().map(|predicate| {
         Obligation { cause: cause.clone(),
                      recursion_depth: recursion_depth,
+                     param_env: param_env,
                      predicate: predicate.clone() }
     }).collect()
 }
 
 pub fn predicate_for_trait_ref<'tcx>(
     cause: ObligationCause<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     recursion_depth: usize)
     -> PredicateObligation<'tcx>
 {
     Obligation {
         cause: cause,
+        param_env: param_env,
         recursion_depth: recursion_depth,
         predicate: trait_ref.to_predicate(),
     }
@@ -417,18 +422,19 @@ pub fn predicate_for_trait_ref<'tcx>(
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn predicate_for_trait_def(self,
-        cause: ObligationCause<'tcx>,
-        trait_def_id: DefId,
-        recursion_depth: usize,
-        param_ty: Ty<'tcx>,
-        ty_params: &[Ty<'tcx>])
+                                   param_env: ty::ParamEnv<'tcx>,
+                                   cause: ObligationCause<'tcx>,
+                                   trait_def_id: DefId,
+                                   recursion_depth: usize,
+                                   param_ty: Ty<'tcx>,
+                                   ty_params: &[Ty<'tcx>])
         -> PredicateObligation<'tcx>
     {
         let trait_ref = ty::TraitRef {
             def_id: trait_def_id,
             substs: self.mk_substs_trait(param_ty, ty_params)
         };
-        predicate_for_trait_ref(cause, trait_ref, recursion_depth)
+        predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
     }
 
     /// Cast a trait reference into a reference to one of its super
index 385591e10f744c9052d3cfa8b37a178cd6c3a7b7..62d137475f90e9797b10bbc0e17611f84584d541 100644 (file)
@@ -8,21 +8,59 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ty::{self, Ty, TyCtxt, TypeAndMut};
-use ty::LvaluePreference::{NoPreference};
-
-use syntax::ast;
-use syntax_pos::Span;
-
 use hir;
+use hir::def_id::DefId;
+use ty::{self, Ty, TyCtxt};
+use ty::subst::Substs;
+
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
+/// Represents coercing a value to a different type of value.
+///
+/// We transform values by following a number of `Adjust` steps in order.
+/// See the documentation on variants of `Adjust` for more details.
+///
+/// Here are some common scenarios:
+///
+/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
+/// Here the pointer will be dereferenced N times (where a dereference can
+/// happen to raw or borrowed pointers or any smart pointer which implements
+/// Deref, including Box<_>). The types of dereferences is given by
+/// `autoderefs`.  It can then be auto-referenced zero or one times, indicated
+/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
+/// `false`.
+///
+/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
+/// with a thin pointer, deref a number of times, unsize the underlying data,
+/// then autoref. The 'unsize' phase may change a fixed length array to a
+/// dynamically sized one, a concrete object to a trait object, or statically
+/// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
+/// represented by:
+///
+/// ```
+/// Deref(None) -> [i32; 4],
+/// Borrow(AutoBorrow::Ref) -> &[i32; 4],
+/// Unsize -> &[i32],
+/// ```
+///
+/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
+/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
+/// The autoderef and -ref are the same as in the above example, but the type
+/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
+/// the underlying conversions from `[i32; 4]` to `[i32]`.
+///
+/// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case.  In
+/// that case, we have the pointer we need coming in, so there are no
+/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
+/// At some point, of course, `Box` should move out of the compiler, in which
+/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
+/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
+#[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct Adjustment<'tcx> {
     pub kind: Adjust<'tcx>,
-    pub target: Ty<'tcx>
+    pub target: Ty<'tcx>,
 }
 
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub enum Adjust<'tcx> {
     /// Go from ! to any type.
     NeverToAny,
@@ -39,94 +77,45 @@ pub enum Adjust<'tcx> {
     /// Go from a mut raw pointer to a const raw pointer.
     MutToConstPointer,
 
-    /// Represents coercing a pointer to a different kind of pointer - where 'kind'
-    /// here means either or both of raw vs borrowed vs unique and fat vs thin.
-    ///
-    /// We transform pointers by following the following steps in order:
-    /// 1. Deref the pointer `self.autoderefs` times (may be 0).
-    /// 2. If `autoref` is `Some(_)`, then take the address and produce either a
-    ///    `&` or `*` pointer.
-    /// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
-    ///    which will do things like convert thin pointers to fat
-    ///    pointers, or convert structs containing thin pointers to
-    ///    structs containing fat pointers, or convert between fat
-    ///    pointers.  We don't store the details of how the transform is
-    ///    done (in fact, we don't know that, because it might depend on
-    ///    the precise type parameters). We just store the target
-    ///    type. Trans figures out what has to be done at monomorphization
-    ///    time based on the precise source/target type at hand.
-    ///
-    /// To make that more concrete, here are some common scenarios:
-    ///
-    /// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
-    /// Here the pointer will be dereferenced N times (where a dereference can
-    /// happen to raw or borrowed pointers or any smart pointer which implements
-    /// Deref, including Box<_>). The number of dereferences is given by
-    /// `autoderefs`.  It can then be auto-referenced zero or one times, indicated
-    /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
-    /// None.
-    ///
-    /// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
-    /// with a thin pointer, deref a number of times, unsize the underlying data,
-    /// then autoref. The 'unsize' phase may change a fixed length array to a
-    /// dynamically sized one, a concrete object to a trait object, or statically
-    /// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
-    /// represented by:
-    ///
-    /// ```
-    /// Adjust::DerefRef {
-    ///     autoderefs: 1,          // &[i32; 4] -> [i32; 4]
-    ///     autoref: Some(AutoBorrow::Ref), // [i32] -> &[i32]
-    ///     unsize: Some([i32]),    // [i32; 4] -> [i32]
-    /// }
-    /// ```
-    ///
-    /// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
-    /// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
-    /// The autoderef and -ref are the same as in the above example, but the type
-    /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
-    /// the underlying conversions from `[i32; 4]` to `[i32]`.
-    ///
-    /// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case.  In
-    /// that case, we have the pointer we need coming in, so there are no
-    /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
-    /// At some point, of course, `Box` should move out of the compiler, in which
-    /// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
-    /// Box<[i32]> is represented by:
-    ///
-    /// ```
-    /// Adjust::DerefRef {
-    ///     autoderefs: 0,
-    ///     autoref: None,
-    ///     unsize: Some(Box<[i32]>),
-    /// }
-    /// ```
-    DerefRef {
-        /// Step 1. Apply a number of dereferences, producing an lvalue.
-        autoderefs: usize,
-
-        /// Step 2. Optionally produce a pointer/reference from the value.
-        autoref: Option<AutoBorrow<'tcx>>,
-
-        /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
-        /// `&[T]`. Note that the source could be a thin or fat pointer.
-        unsize: bool,
-    }
+    /// Dereference once, producing an lvalue.
+    Deref(Option<OverloadedDeref<'tcx>>),
+
+    /// Take the address and produce either a `&` or `*` pointer.
+    Borrow(AutoBorrow<'tcx>),
+
+    /// Unsize a pointer/reference value, e.g. `&[T; n]` to
+    /// `&[T]`. Note that the source could be a thin or fat pointer.
+    /// This will do things like convert thin pointers to fat
+    /// pointers, or convert structs containing thin pointers to
+    /// structs containing fat pointers, or convert between fat
+    /// pointers.  We don't store the details of how the transform is
+    /// done (in fact, we don't know that, because it might depend on
+    /// the precise type parameters). We just store the target
+    /// type. Trans figures out what has to be done at monomorphization
+    /// time based on the precise source/target type at hand.
+    Unsize,
 }
 
-impl<'tcx> Adjustment<'tcx> {
-    pub fn is_identity(&self) -> bool {
-        match self.kind {
-            Adjust::NeverToAny => self.target.is_never(),
-
-            Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true,
+/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
+/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
+/// The target type is `U` in both cases, with the region and mutability
+/// being those shared by both the receiver and the returned reference.
+#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
+pub struct OverloadedDeref<'tcx> {
+    pub region: ty::Region<'tcx>,
+    pub mutbl: hir::Mutability,
+}
 
-            Adjust::ReifyFnPointer |
-            Adjust::UnsafeFnPointer |
-            Adjust::ClosureFnPointer |
-            Adjust::MutToConstPointer |
-            Adjust::DerefRef {..} => false,
-        }
+impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> {
+    pub fn method_call(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, source: Ty<'tcx>)
+                       -> (DefId, &'tcx Substs<'tcx>) {
+        let trait_def_id = match self.mutbl {
+            hir::MutImmutable => tcx.lang_items.deref_trait(),
+            hir::MutMutable => tcx.lang_items.deref_mut_trait()
+        };
+        let method_def_id = tcx.associated_items(trait_def_id.unwrap())
+            .find(|m| m.kind == ty::AssociatedKind::Method).unwrap().def_id;
+        (method_def_id, tcx.mk_substs_trait(source, &[]))
     }
 }
 
@@ -159,48 +148,3 @@ pub enum CustomCoerceUnsized {
     /// Records the index of the field being coerced.
     Struct(usize)
 }
-
-impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
-    pub fn adjust_for_autoderef<F>(&'tcx self,
-                                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                   expr_id: ast::NodeId,
-                                   expr_span: Span,
-                                   autoderef: u32, // how many autoderefs so far?
-                                   mut method_type: F)
-                                   -> Ty<'tcx> where
-        F: FnMut(ty::MethodCall) -> Option<Ty<'tcx>>,
-    {
-        let method_call = ty::MethodCall::autoderef(expr_id, autoderef);
-        let mut adjusted_ty = self;
-        if let Some(method_ty) = method_type(method_call) {
-            // Method calls always have all late-bound regions
-            // fully instantiated.
-            adjusted_ty = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
-        }
-        match adjusted_ty.builtin_deref(true, NoPreference) {
-            Some(mt) => mt.ty,
-            None => {
-                span_bug!(
-                    expr_span,
-                    "the {}th autoderef for {} failed: {}",
-                    autoderef,
-                    expr_id,
-                    adjusted_ty);
-            }
-        }
-    }
-
-    pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                              autoref: Option<AutoBorrow<'tcx>>)
-                              -> Ty<'tcx> {
-        match autoref {
-            None => self,
-            Some(AutoBorrow::Ref(r, m)) => {
-                tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m })
-            }
-            Some(AutoBorrow::RawPtr(m)) => {
-                tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m })
-            }
-        }
-    }
-}
index 8c801c6fa2b977b31f17f2357f66be8418914141..2bbb71610ad0cc583213647a0b794c83f85acb19 100644 (file)
@@ -18,7 +18,7 @@
 use hir::def::{Def, ExportMap};
 use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use hir::map as hir_map;
-use hir::map::DisambiguatedDefPathData;
+use hir::map::{DisambiguatedDefPathData, DefPathHash};
 use middle::free_region::FreeRegionMap;
 use middle::lang_items;
 use middle::resolve_lifetime;
@@ -206,8 +206,9 @@ pub struct CommonTypes<'tcx> {
 
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct TypeckTables<'tcx> {
-    /// Resolved definitions for `<T>::X` associated paths.
-    pub type_relative_path_defs: NodeMap<Def>,
+    /// Resolved definitions for `<T>::X` associated paths and
+    /// method calls, including those of overloaded operators.
+    pub type_dependent_defs: NodeMap<Def>,
 
     /// Stores the types for various nodes in the AST.  Note that this table
     /// is not guaranteed to be populated until after typeck.  See
@@ -218,11 +219,9 @@ pub struct TypeckTables<'tcx> {
     /// of this node.  This only applies to nodes that refer to entities
     /// parameterized by type parameters, such as generic fns, types, or
     /// other items.
-    pub item_substs: NodeMap<ty::ItemSubsts<'tcx>>,
+    pub node_substs: NodeMap<&'tcx Substs<'tcx>>,
 
-    pub adjustments: NodeMap<ty::adjustment::Adjustment<'tcx>>,
-
-    pub method_map: ty::MethodMap<'tcx>,
+    pub adjustments: NodeMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
 
     /// Borrows
     pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
@@ -271,11 +270,10 @@ pub struct TypeckTables<'tcx> {
 impl<'tcx> TypeckTables<'tcx> {
     pub fn empty() -> TypeckTables<'tcx> {
         TypeckTables {
-            type_relative_path_defs: NodeMap(),
+            type_dependent_defs: NodeMap(),
             node_types: FxHashMap(),
-            item_substs: NodeMap(),
+            node_substs: NodeMap(),
             adjustments: NodeMap(),
-            method_map: FxHashMap(),
             upvar_capture_map: FxHashMap(),
             closure_tys: NodeMap(),
             closure_kinds: NodeMap(),
@@ -294,7 +292,7 @@ pub fn qpath_def(&self, qpath: &hir::QPath, id: NodeId) -> Def {
         match *qpath {
             hir::QPath::Resolved(_, ref path) => path.def,
             hir::QPath::TypeRelative(..) => {
-                self.type_relative_path_defs.get(&id).cloned().unwrap_or(Def::Err)
+                self.type_dependent_defs.get(&id).cloned().unwrap_or(Def::Err)
             }
         }
     }
@@ -313,8 +311,8 @@ pub fn node_id_to_type_opt(&self, id: NodeId) -> Option<Ty<'tcx>> {
         self.node_types.get(&id).cloned()
     }
 
-    pub fn node_id_item_substs(&self, id: NodeId) -> Option<&'tcx Substs<'tcx>> {
-        self.item_substs.get(&id).map(|ts| ts.substs)
+    pub fn node_substs(&self, id: NodeId) -> &'tcx Substs<'tcx> {
+        self.node_substs.get(&id).cloned().unwrap_or(Substs::empty())
     }
 
     // Returns the type of a pattern as a monotype. Like @expr_ty, this function
@@ -345,24 +343,37 @@ pub fn expr_ty_opt(&self, expr: &hir::Expr) -> Option<Ty<'tcx>> {
         self.node_id_to_type_opt(expr.id)
     }
 
+    pub fn expr_adjustments(&self, expr: &hir::Expr)
+                            -> &[ty::adjustment::Adjustment<'tcx>] {
+        self.adjustments.get(&expr.id).map_or(&[], |a| &a[..])
+    }
+
     /// Returns the type of `expr`, considering any `Adjustment`
     /// entry recorded for that expression.
     pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> {
-        self.adjustments.get(&expr.id)
+        self.expr_adjustments(expr)
+            .last()
             .map_or_else(|| self.expr_ty(expr), |adj| adj.target)
     }
 
     pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option<Ty<'tcx>> {
-        self.adjustments.get(&expr.id)
-            .map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
+        self.expr_adjustments(expr)
+            .last()
+            .map(|adj| adj.target)
+            .or_else(|| self.expr_ty_opt(expr))
     }
 
-    pub fn is_method_call(&self, expr_id: NodeId) -> bool {
-        self.method_map.contains_key(&ty::MethodCall::expr(expr_id))
-    }
+    pub fn is_method_call(&self, expr: &hir::Expr) -> bool {
+        // Only paths and method calls/overloaded operators have
+        // entries in type_dependent_defs, ignore the former here.
+        if let hir::ExprPath(_) = expr.node {
+            return false;
+        }
 
-    pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool {
-        self.method_map.contains_key(&ty::MethodCall::autoderef(expr_id, autoderefs))
+        match self.type_dependent_defs.get(&expr.id) {
+            Some(&Def::Method(_)) => true,
+            _ => false
+        }
     }
 
     pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
@@ -450,6 +461,10 @@ pub struct GlobalCtxt<'tcx> {
 
     pub hir: hir_map::Map<'tcx>,
 
+    /// A map from DefPathHash -> DefId. Includes DefIds from the local crate
+    /// as well as all upstream crates. Only populated in incremental mode.
+    pub def_path_hash_to_def_id: Option<FxHashMap<DefPathHash, DefId>>,
+
     pub maps: maps::Maps<'tcx>,
 
     pub mir_passes: Rc<Passes>,
@@ -508,9 +523,6 @@ pub struct GlobalCtxt<'tcx> {
     /// Data layout specification for the current target.
     pub data_layout: TargetDataLayout,
 
-    /// Cache for layouts computed from types.
-    pub layout_cache: RefCell<FxHashMap<Ty<'tcx>, &'tcx Layout>>,
-
     /// Used to prevent layout from recursing too deeply.
     pub layout_depth: Cell<usize>,
 
@@ -678,6 +690,40 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
         let max_cnum = s.cstore.crates().iter().map(|c| c.as_usize()).max().unwrap_or(0);
         let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1);
         providers[LOCAL_CRATE] = local_providers;
+
+        let def_path_hash_to_def_id = if s.opts.build_dep_graph() {
+            let upstream_def_path_tables: Vec<(CrateNum, Rc<_>)> = s
+                .cstore
+                .crates()
+                .iter()
+                .map(|&cnum| (cnum, s.cstore.def_path_table(cnum)))
+                .collect();
+
+            let def_path_tables = || {
+                upstream_def_path_tables
+                    .iter()
+                    .map(|&(cnum, ref rc)| (cnum, &**rc))
+                    .chain(iter::once((LOCAL_CRATE, hir.definitions().def_path_table())))
+            };
+
+            // Precompute the capacity of the hashmap so we don't have to
+            // re-allocate when populating it.
+            let capacity = def_path_tables().map(|(_, t)| t.size()).sum::<usize>();
+
+            let mut map: FxHashMap<_, _> = FxHashMap::with_capacity_and_hasher(
+                capacity,
+                ::std::default::Default::default()
+            );
+
+            for (cnum, def_path_table) in def_path_tables() {
+                def_path_table.add_def_path_hashes_to(cnum, &mut map);
+            }
+
+            Some(map)
+        } else {
+            None
+        };
+
         tls::enter_global(GlobalCtxt {
             sess: s,
             trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()),
@@ -691,6 +737,7 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             export_map: resolutions.export_map,
             fulfilled_predicates: RefCell::new(fulfilled_predicates),
             hir: hir,
+            def_path_hash_to_def_id: def_path_hash_to_def_id,
             maps: maps::Maps::new(providers),
             mir_passes,
             freevars: RefCell::new(resolutions.freevars),
@@ -707,7 +754,6 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             rvalue_promotable_to_static: RefCell::new(NodeMap()),
             crate_name: Symbol::intern(crate_name),
             data_layout: data_layout,
-            layout_cache: RefCell::new(FxHashMap()),
             layout_interner: RefCell::new(FxHashSet()),
             layout_depth: Cell::new(0),
             derive_macros: RefCell::new(NodeMap()),
@@ -754,6 +800,18 @@ pub trait Lift<'tcx> {
     fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted>;
 }
 
+impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
+    type Lifted = ty::ParamEnv<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<ty::ParamEnv<'tcx>> {
+        self.caller_bounds.lift_to_tcx(tcx).and_then(|caller_bounds| {
+            Some(ty::ParamEnv {
+                reveal: self.reveal,
+                caller_bounds,
+            })
+        })
+    }
+}
+
 impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
     type Lifted = Ty<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
@@ -840,6 +898,25 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Predicate<'a>> {
+    type Lifted = &'tcx Slice<Predicate<'tcx>>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
+        -> Option<&'tcx Slice<Predicate<'tcx>>> {
+        if self.is_empty() {
+            return Some(Slice::empty());
+        }
+        if tcx.interners.arena.in_arena(*self as *const _) {
+            return Some(unsafe { mem::transmute(*self) });
+        }
+        // Also try in the global tcx if we're not that.
+        if !tcx.is_global() {
+            self.lift_to_tcx(tcx.global_tcx())
+        } else {
+            None
+        }
+    }
+}
+
 pub mod tls {
     use super::{CtxtInterners, GlobalCtxt, TyCtxt};
 
index c17a54f4f69bbb98717992d487c0d0c8a1e7afba..bb13031a2b7c4ac0580771dc4c1acd5a326b5ff1 100644 (file)
@@ -39,8 +39,6 @@
 //! These methods return true to indicate that the visitor has found what it is looking for
 //! and does not need to visit anything else.
 
-use ty::subst::Substs;
-use ty::adjustment;
 use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
 
 use std::fmt;
@@ -138,34 +136,9 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         t.super_fold_with(self)
     }
 
-    fn fold_mt(&mut self, t: &ty::TypeAndMut<'tcx>) -> ty::TypeAndMut<'tcx> {
-        t.super_fold_with(self)
-    }
-
-    fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> {
-        imp.super_fold_with(self)
-    }
-
-    fn fold_substs(&mut self,
-                   substs: &'tcx Substs<'tcx>)
-                   -> &'tcx Substs<'tcx> {
-        substs.super_fold_with(self)
-    }
-
-    fn fold_fn_sig(&mut self,
-                   sig: &ty::FnSig<'tcx>)
-                   -> ty::FnSig<'tcx> {
-        sig.super_fold_with(self)
-    }
-
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         r.super_fold_with(self)
     }
-
-    fn fold_autoref(&mut self, ar: &adjustment::AutoBorrow<'tcx>)
-                    -> adjustment::AutoBorrow<'tcx> {
-        ar.super_fold_with(self)
-    }
 }
 
 pub trait TypeVisitor<'tcx> : Sized {
index 1a8c74ff1f94323db427711be1617d01c1100a48..12af56d5c3dfa5ee862b0732b58959fae4a868d2 100644 (file)
 pub use self::Layout::*;
 pub use self::Primitive::*;
 
-use infer::InferCtxt;
-use session::Session;
-use traits;
+use session::{self, DataTypeKind, Session};
 use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags};
 
-use syntax::ast::{FloatTy, IntTy, UintTy};
+use syntax::ast::{self, FloatTy, IntTy, UintTy};
 use syntax::attr;
 use syntax_pos::DUMMY_SP;
 
@@ -212,6 +210,12 @@ fn data_layout(&self) -> &TargetDataLayout {
     }
 }
 
+impl<'a, 'tcx> HasDataLayout for TyCtxt<'a, 'tcx, 'tcx> {
+    fn data_layout(&self) -> &TargetDataLayout {
+        &self.data_layout
+    }
+}
+
 /// Endianness of the target, which must match cfg(target-endian).
 #[derive(Copy, Clone)]
 pub enum Endian {
@@ -457,8 +461,12 @@ pub fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer {
     /// signed discriminant range and #[repr] attribute.
     /// N.B.: u64 values above i64::MAX will be treated as signed, but
     /// that shouldn't affect anything, other than maybe debuginfo.
-    fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64)
-                      -> (Integer, bool) {
+    fn repr_discr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            ty: Ty<'tcx>,
+                            repr: &ReprOptions,
+                            min: i64,
+                            max: i64)
+                            -> (Integer, bool) {
         // Theoretically, negative values could be larger in unsigned representation
         // than the unsigned representation of the signed minimum. However, if there
         // are any negative values, the only valid unsigned representation is u64
@@ -583,10 +591,13 @@ enum StructKind {
     EnumVariant,
 }
 
-impl<'a, 'gcx, 'tcx> Struct {
-    fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
-                  repr: &ReprOptions, kind: StructKind,
-                  scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
+impl<'a, 'tcx> Struct {
+    fn new(dl: &TargetDataLayout,
+           fields: &Vec<&'a Layout>,
+           repr: &ReprOptions,
+           kind: StructKind,
+           scapegoat: Ty<'tcx>)
+           -> Result<Struct, LayoutError<'tcx>> {
         if repr.packed() && repr.align > 0 {
             bug!("Struct cannot be packed and aligned");
         }
@@ -723,8 +734,8 @@ pub fn stride(&self) -> Size {
 
     /// Determine whether a structure would be zero-sized, given its fields.
     fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
-                              -> Result<bool, LayoutError<'gcx>>
-    where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
+                              -> Result<bool, LayoutError<'tcx>>
+    where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
         for field in fields {
             let field = field?;
             if field.is_unsized() || field.size(dl).bytes() > 0 {
@@ -764,11 +775,11 @@ pub fn field_index_by_increasing_offset<'b>(&'b self) -> impl iter::Iterator<Ite
     /// The tuple is `(path, source_path)`,
     /// where `path` is in memory order and `source_path` in source order.
     // FIXME(eddyb) track value ranges and traverse already optimized enums.
-    fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                               ty: Ty<'gcx>)
-                               -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> {
-        let tcx = infcx.tcx.global_tcx();
-        match (ty.layout(infcx)?, &ty.sty) {
+    fn non_zero_field_in_type(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                              param_env: ty::ParamEnv<'tcx>,
+                              ty: Ty<'tcx>)
+                              -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>> {
+        match (ty.layout(tcx, param_env)?, &ty.sty) {
             (&Scalar { non_zero: true, .. }, _) |
             (&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))),
             (&FatPointer { non_zero: true, .. }, _) => {
@@ -779,7 +790,7 @@ fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
             (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => {
                 let fields = &def.struct_variant().fields;
                 assert_eq!(fields.len(), 1);
-                match *fields[0].ty(tcx, substs).layout(infcx)? {
+                match *fields[0].ty(tcx, substs).layout(tcx, param_env)? {
                     // FIXME(eddyb) also allow floating-point types here.
                     Scalar { value: Int(_), non_zero: false } |
                     Scalar { value: Pointer, non_zero: false } => {
@@ -796,37 +807,49 @@ fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
             // Perhaps one of the fields of this struct is non-zero
             // let's recurse and find out
             (&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => {
-                Struct::non_zero_field_paths(infcx, def.struct_variant().fields
-                                                      .iter().map(|field| {
-                    field.ty(tcx, substs)
-                }),
-                Some(&variant.memory_index[..]))
+                Struct::non_zero_field_paths(
+                    tcx,
+                    param_env,
+                    def.struct_variant().fields.iter().map(|field| {
+                        field.ty(tcx, substs)
+                    }),
+                    Some(&variant.memory_index[..]))
             }
 
             // Perhaps one of the upvars of this closure is non-zero
             (&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => {
                 let upvar_tys = substs.upvar_tys(def, tcx);
-                Struct::non_zero_field_paths(infcx, upvar_tys,
+                Struct::non_zero_field_paths(
+                    tcx,
+                    param_env,
+                    upvar_tys,
                     Some(&variant.memory_index[..]))
             }
             // Can we use one of the fields in this tuple?
             (&Univariant { ref variant, .. }, &ty::TyTuple(tys, _)) => {
-                Struct::non_zero_field_paths(infcx, tys.iter().cloned(),
+                Struct::non_zero_field_paths(
+                    tcx,
+                    param_env,
+                    tys.iter().cloned(),
                     Some(&variant.memory_index[..]))
             }
 
             // Is this a fixed-size array of something non-zero
             // with at least one element?
             (_, &ty::TyArray(ety, d)) if d > 0 => {
-                Struct::non_zero_field_paths(infcx, Some(ety).into_iter(), None)
+                Struct::non_zero_field_paths(
+                    tcx,
+                    param_env,
+                    Some(ety).into_iter(),
+                    None)
             }
 
             (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
-                let normalized = infcx.normalize_projections(ty);
+                let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
                 if ty == normalized {
                     return Ok(None);
                 }
-                return Struct::non_zero_field_in_type(infcx, normalized);
+                return Struct::non_zero_field_in_type(tcx, param_env, normalized);
             }
 
             // Anything else is not a non-zero type.
@@ -838,13 +861,15 @@ fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     /// the given set of fields and recursing through aggregates.
     /// Returns Some((path, source_path)) on success.
     /// `path` is translated to memory order. `source_path` is not.
-    fn non_zero_field_paths<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                  fields: I,
-                                  permutation: Option<&[u32]>)
-                                  -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>>
-    where I: Iterator<Item=Ty<'gcx>> {
+    fn non_zero_field_paths<I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                               param_env: ty::ParamEnv<'tcx>,
+                               fields: I,
+                               permutation: Option<&[u32]>)
+                               -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>>
+    where I: Iterator<Item=Ty<'tcx>> {
         for (i, ty) in fields.enumerate() {
-            if let Some((mut path, mut source_path)) = Struct::non_zero_field_in_type(infcx, ty)? {
+            let r = Struct::non_zero_field_in_type(tcx, param_env, ty)?;
+            if let Some((mut path, mut source_path)) = r {
                 source_path.push(i as u32);
                 let index = if let Some(p) = permutation {
                     p[i] as usize
@@ -881,7 +906,7 @@ pub struct Union {
     pub packed: bool,
 }
 
-impl<'a, 'gcx, 'tcx> Union {
+impl<'a, 'tcx> Union {
     fn new(dl: &TargetDataLayout, packed: bool) -> Union {
         let align = if packed { dl.i8_align } else { dl.aggregate_align };
         Union {
@@ -895,9 +920,9 @@ fn new(dl: &TargetDataLayout, packed: bool) -> Union {
     /// Extend the Struct with more fields.
     fn extend<I>(&mut self, dl: &TargetDataLayout,
                  fields: I,
-                 scapegoat: Ty<'gcx>)
-                 -> Result<(), LayoutError<'gcx>>
-    where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
+                 scapegoat: Ty<'tcx>)
+                 -> Result<(), LayoutError<'tcx>>
+    where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
         for (index, field) in fields.enumerate() {
             let field = field?;
             if field.is_unsized() {
@@ -1067,19 +1092,19 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl<'a, 'gcx, 'tcx> Layout {
-    pub fn compute_uncached(ty: Ty<'gcx>,
-                            infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-                            -> Result<&'gcx Layout, LayoutError<'gcx>> {
-        let tcx = infcx.tcx.global_tcx();
+impl<'a, 'tcx> Layout {
+    pub fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            param_env: ty::ParamEnv<'tcx>,
+                            ty: Ty<'tcx>)
+                            -> Result<&'tcx Layout, LayoutError<'tcx>> {
         let success = |layout| Ok(tcx.intern_layout(layout));
         let dl = &tcx.data_layout;
         assert!(!ty.has_infer_types());
 
-        let ptr_layout = |pointee: Ty<'gcx>| {
+        let ptr_layout = |pointee: Ty<'tcx>| {
             let non_zero = !ty.is_unsafe_ptr();
-            let pointee = infcx.normalize_projections(pointee);
-            if pointee.is_sized(tcx, infcx.param_env, DUMMY_SP) {
+            let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
+            if pointee.is_sized(tcx, param_env, DUMMY_SP) {
                 Ok(Scalar { value: Pointer, non_zero: non_zero })
             } else {
                 let unsized_part = tcx.struct_tail(pointee);
@@ -1132,7 +1157,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
 
             // Arrays and slices.
             ty::TyArray(element, count) => {
-                let element = element.layout(infcx)?;
+                let element = element.layout(tcx, param_env)?;
                 let element_size = element.size(dl);
                 // FIXME(eddyb) Don't use host `usize` for array lengths.
                 let usize_count: usize = count;
@@ -1149,7 +1174,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 }
             }
             ty::TySlice(element) => {
-                let element = element.layout(infcx)?;
+                let element = element.layout(tcx, param_env)?;
                 Array {
                     sized: false,
                     align: element.align(dl),
@@ -1187,7 +1212,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
             ty::TyClosure(def_id, ref substs) => {
                 let tys = substs.upvar_tys(def_id, tcx);
                 let st = Struct::new(dl,
-                    &tys.map(|ty| ty.layout(infcx))
+                    &tys.map(|ty| ty.layout(tcx, param_env))
                       .collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(),
                     StructKind::AlwaysSizedUnivariant, ty)?;
@@ -1198,7 +1223,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 // FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
                 // See the univariant case below to learn how.
                 let st = Struct::new(dl,
-                    &tys.iter().map(|ty| ty.layout(infcx))
+                    &tys.iter().map(|ty| ty.layout(tcx, param_env))
                       .collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?;
                 Univariant { variant: st, non_zero: false }
@@ -1207,7 +1232,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
             // SIMD vector types.
             ty::TyAdt(def, ..) if def.repr.simd() => {
                 let element = ty.simd_type(tcx);
-                match *element.layout(infcx)? {
+                match *element.layout(tcx, param_env)? {
                     Scalar { value, .. } => {
                         return success(Vector {
                             element: value,
@@ -1278,7 +1303,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     };
 
                     let fields = def.variants[0].fields.iter().map(|field| {
-                        field.ty(tcx, substs).layout(infcx)
+                        field.ty(tcx, substs).layout(tcx, param_env)
                     }).collect::<Result<Vec<_>, _>>()?;
                     let layout = if def.is_union() {
                         let mut un = Union::new(dl, def.repr.packed());
@@ -1312,20 +1337,21 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     // Nullable pointer optimization
                     for discr in 0..2 {
                         let other_fields = variants[1 - discr].iter().map(|ty| {
-                            ty.layout(infcx)
+                            ty.layout(tcx, param_env)
                         });
                         if !Struct::would_be_zero_sized(dl, other_fields)? {
                             continue;
                         }
-                        let paths = Struct::non_zero_field_paths(infcx,
-                            variants[discr].iter().cloned(),
-                            None)?;
+                        let paths = Struct::non_zero_field_paths(tcx,
+                                                                 param_env,
+                                                                 variants[discr].iter().cloned(),
+                                                                 None)?;
                         let (mut path, mut path_source) = if let Some(p) = paths { p }
                           else { continue };
 
                         // FIXME(eddyb) should take advantage of a newtype.
                         if path == &[0] && variants[discr].len() == 1 {
-                            let value = match *variants[discr][0].layout(infcx)? {
+                            let value = match *variants[discr][0].layout(tcx, param_env)? {
                                 Scalar { value, .. } => value,
                                 CEnum { discr, .. } => Int(discr),
                                 _ => bug!("Layout::compute: `{}`'s non-zero \
@@ -1339,7 +1365,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                         }
 
                         let st = Struct::new(dl,
-                            &variants[discr].iter().map(|ty| ty.layout(infcx))
+                            &variants[discr].iter().map(|ty| ty.layout(tcx, param_env))
                               .collect::<Result<Vec<_>, _>>()?,
                             &def.repr, StructKind::AlwaysSizedUnivariant, ty)?;
 
@@ -1377,7 +1403,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 let discr = Scalar { value: Int(min_ity), non_zero: false };
                 let mut variants = variants.into_iter().map(|fields| {
                     let mut fields = fields.into_iter().map(|field| {
-                        field.layout(infcx)
+                        field.layout(tcx, param_env)
                     }).collect::<Result<Vec<_>, _>>()?;
                     fields.insert(0, &discr);
                     let st = Struct::new(dl,
@@ -1470,11 +1496,11 @@ pub fn compute_uncached(ty: Ty<'gcx>,
 
             // Types with no meaningful known layout.
             ty::TyProjection(_) | ty::TyAnon(..) => {
-                let normalized = infcx.normalize_projections(ty);
+                let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
                 if ty == normalized {
                     return Err(LayoutError::Unknown(ty));
                 }
-                return normalized.layout(infcx);
+                return normalized.layout(tcx, param_env);
             }
             ty::TyParam(_) => {
                 return Err(LayoutError::Unknown(ty));
@@ -1664,6 +1690,225 @@ pub fn field_offset<C: HasDataLayout>(&self,
             }
         }
     }
+
+    /// This is invoked by the `layout_raw` query to record the final
+    /// layout of each type.
+    #[inline]
+    pub fn record_layout_for_printing(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                      ty: Ty<'tcx>,
+                                      param_env: ty::ParamEnv<'tcx>,
+                                      layout: &Layout) {
+        // If we are running with `-Zprint-type-sizes`, record layouts for
+        // dumping later. Ignore layouts that are done with non-empty
+        // environments or non-monomorphic layouts, as the user only wants
+        // to see the stuff resulting from the final trans session.
+        if
+            !tcx.sess.opts.debugging_opts.print_type_sizes ||
+            ty.has_param_types() ||
+            ty.has_self_ty() ||
+            !param_env.caller_bounds.is_empty()
+        {
+            return;
+        }
+
+        Self::record_layout_for_printing_outlined(tcx, ty, param_env, layout)
+    }
+
+    fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                           ty: Ty<'tcx>,
+                                           param_env: ty::ParamEnv<'tcx>,
+                                           layout: &Layout) {
+        // (delay format until we actually need it)
+        let record = |kind, opt_discr_size, variants| {
+            let type_desc = format!("{:?}", ty);
+            let overall_size = layout.size(tcx);
+            let align = layout.align(tcx);
+            tcx.sess.code_stats.borrow_mut().record_type_size(kind,
+                                                              type_desc,
+                                                              align,
+                                                              overall_size,
+                                                              opt_discr_size,
+                                                              variants);
+        };
+
+        let (adt_def, substs) = match ty.sty {
+            ty::TyAdt(ref adt_def, substs) => {
+                debug!("print-type-size t: `{:?}` process adt", ty);
+                (adt_def, substs)
+            }
+
+            ty::TyClosure(..) => {
+                debug!("print-type-size t: `{:?}` record closure", ty);
+                record(DataTypeKind::Closure, None, vec![]);
+                return;
+            }
+
+            _ => {
+                debug!("print-type-size t: `{:?}` skip non-nominal", ty);
+                return;
+            }
+        };
+
+        let adt_kind = adt_def.adt_kind();
+
+        let build_field_info = |(field_name, field_ty): (ast::Name, Ty<'tcx>), offset: &Size| {
+            let layout = field_ty.layout(tcx, param_env);
+            match layout {
+                Err(_) => bug!("no layout found for field {} type: `{:?}`", field_name, field_ty),
+                Ok(field_layout) => {
+                    session::FieldInfo {
+                        name: field_name.to_string(),
+                        offset: offset.bytes(),
+                        size: field_layout.size(tcx).bytes(),
+                        align: field_layout.align(tcx).abi(),
+                    }
+                }
+            }
+        };
+
+        let build_primitive_info = |name: ast::Name, value: &Primitive| {
+            session::VariantInfo {
+                name: Some(name.to_string()),
+                kind: session::SizeKind::Exact,
+                align: value.align(tcx).abi(),
+                size: value.size(tcx).bytes(),
+                fields: vec![],
+            }
+        };
+
+        enum Fields<'a> {
+            WithDiscrim(&'a Struct),
+            NoDiscrim(&'a Struct),
+        }
+
+        let build_variant_info = |n: Option<ast::Name>,
+                                  flds: &[(ast::Name, Ty<'tcx>)],
+                                  layout: Fields| {
+            let (s, field_offsets) = match layout {
+                Fields::WithDiscrim(s) => (s, &s.offsets[1..]),
+                Fields::NoDiscrim(s) => (s, &s.offsets[0..]),
+            };
+            let field_info: Vec<_> =
+                flds.iter()
+                    .zip(field_offsets.iter())
+                    .map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset))
+                    .collect();
+
+            session::VariantInfo {
+                name: n.map(|n|n.to_string()),
+                kind: if s.sized {
+                    session::SizeKind::Exact
+                } else {
+                    session::SizeKind::Min
+                },
+                align: s.align.abi(),
+                size: s.min_size.bytes(),
+                fields: field_info,
+            }
+        };
+
+        match *layout {
+            Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
+                                                   nndiscr,
+                                                   discrfield: _,
+                                                   discrfield_source: _ } => {
+                debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
+                       ty, nndiscr, variant_layout);
+                let variant_def = &adt_def.variants[nndiscr as usize];
+                let fields: Vec<_> =
+                    variant_def.fields.iter()
+                                      .map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
+                                      .collect();
+                record(adt_kind.into(),
+                       None,
+                       vec![build_variant_info(Some(variant_def.name),
+                                               &fields,
+                                               Fields::NoDiscrim(variant_layout))]);
+            }
+            Layout::RawNullablePointer { nndiscr, value } => {
+                debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}",
+                       ty, nndiscr, value);
+                let variant_def = &adt_def.variants[nndiscr as usize];
+                record(adt_kind.into(), None,
+                       vec![build_primitive_info(variant_def.name, &value)]);
+            }
+            Layout::Univariant { variant: ref variant_layout, non_zero: _ } => {
+                let variant_names = || {
+                    adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
+                };
+                debug!("print-type-size t: `{:?}` adt univariant {:?} variants: {:?}",
+                       ty, variant_layout, variant_names());
+                assert!(adt_def.variants.len() <= 1,
+                        "univariant with variants {:?}", variant_names());
+                if adt_def.variants.len() == 1 {
+                    let variant_def = &adt_def.variants[0];
+                    let fields: Vec<_> =
+                        variant_def.fields.iter()
+                                          .map(|f| (f.name, f.ty(tcx, substs)))
+                                          .collect();
+                    record(adt_kind.into(),
+                           None,
+                           vec![build_variant_info(Some(variant_def.name),
+                                                   &fields,
+                                                   Fields::NoDiscrim(variant_layout))]);
+                } else {
+                    // (This case arises for *empty* enums; so give it
+                    // zero variants.)
+                    record(adt_kind.into(), None, vec![]);
+                }
+            }
+
+            Layout::General { ref variants, discr, .. } => {
+                debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}",
+                       ty, adt_def.variants.len(), variants.len(), variants);
+                let variant_infos: Vec<_> =
+                    adt_def.variants.iter()
+                                    .zip(variants.iter())
+                                    .map(|(variant_def, variant_layout)| {
+                                        let fields: Vec<_> =
+                                            variant_def.fields
+                                                       .iter()
+                                                       .map(|f| (f.name, f.ty(tcx, substs)))
+                                                       .collect();
+                                        build_variant_info(Some(variant_def.name),
+                                                           &fields,
+                                                           Fields::WithDiscrim(variant_layout))
+                                    })
+                                    .collect();
+                record(adt_kind.into(), Some(discr.size()), variant_infos);
+            }
+
+            Layout::UntaggedUnion { ref variants } => {
+                debug!("print-type-size t: `{:?}` adt union variants {:?}",
+                       ty, variants);
+                // layout does not currently store info about each
+                // variant...
+                record(adt_kind.into(), None, Vec::new());
+            }
+
+            Layout::CEnum { discr, .. } => {
+                debug!("print-type-size t: `{:?}` adt c-like enum", ty);
+                let variant_infos: Vec<_> =
+                    adt_def.variants.iter()
+                                    .map(|variant_def| {
+                                        build_primitive_info(variant_def.name,
+                                                             &Primitive::Int(discr))
+                                    })
+                                    .collect();
+                record(adt_kind.into(), Some(discr.size()), variant_infos);
+            }
+
+            // other cases provide little interesting (i.e. adjustable
+            // via representation tweaks) size info beyond total size.
+            Layout::Scalar { .. } |
+            Layout::Vector { .. } |
+            Layout::Array { .. } |
+            Layout::FatPointer { .. } => {
+                debug!("print-type-size t: `{:?}` adt other", ty);
+                record(adt_kind.into(), None, Vec::new())
+            }
+        }
+    }
 }
 
 /// Type size "skeleton", i.e. the only information determining a type's size.
@@ -1686,21 +1931,22 @@ pub enum SizeSkeleton<'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
-    pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-                   -> Result<SizeSkeleton<'gcx>, LayoutError<'gcx>> {
-        let tcx = infcx.tcx.global_tcx();
+impl<'a, 'tcx> SizeSkeleton<'tcx> {
+    pub fn compute(ty: Ty<'tcx>,
+                   tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                   param_env: ty::ParamEnv<'tcx>)
+                   -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
         assert!(!ty.has_infer_types());
 
         // First try computing a static layout.
-        let err = match ty.layout(infcx) {
+        let err = match ty.layout(tcx, param_env) {
             Ok(layout) => {
                 return Ok(SizeSkeleton::Known(layout.size(tcx)));
             }
             Err(err) => err
         };
 
-        let ptr_skeleton = |pointee: Ty<'gcx>| {
+        let ptr_skeleton = |pointee: Ty<'tcx>| {
             let non_zero = !ty.is_unsafe_ptr();
             let tail = tcx.struct_tail(pointee);
             match tail.sty {
@@ -1737,7 +1983,7 @@ pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
                 // Get a zero-sized variant or a pointer newtype.
                 let zero_or_ptr_variant = |i: usize| {
                     let fields = def.variants[i].fields.iter().map(|field| {
-                        SizeSkeleton::compute(field.ty(tcx, substs), infcx)
+                        SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env)
                     });
                     let mut ptr = None;
                     for field in fields {
@@ -1788,11 +2034,11 @@ pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
             }
 
             ty::TyProjection(_) | ty::TyAnon(..) => {
-                let normalized = infcx.normalize_projections(ty);
+                let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
                 if ty == normalized {
                     Err(err)
                 } else {
-                    SizeSkeleton::compute(normalized, infcx)
+                    SizeSkeleton::compute(normalized, tcx, param_env)
                 }
             }
 
@@ -1826,71 +2072,53 @@ fn deref(&self) -> &Layout {
     }
 }
 
-pub trait HasTyCtxt<'tcx>: HasDataLayout {
+pub trait LayoutTyper<'tcx>: HasDataLayout {
+    type TyLayout;
+
     fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
+    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
 }
 
-impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> {
-    fn data_layout(&self) -> &TargetDataLayout {
-        &self.data_layout
-    }
+/// Combines a tcx with the parameter environment so that you can
+/// compute layout operations.
+#[derive(Copy, Clone)]
+pub struct LayoutCx<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
-        self.global_tcx()
+impl<'a, 'tcx> LayoutCx<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+        LayoutCx { tcx, param_env }
     }
 }
 
-impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx> HasDataLayout for LayoutCx<'a, 'tcx> {
     fn data_layout(&self) -> &TargetDataLayout {
         &self.tcx.data_layout
     }
 }
 
-impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
-        self.tcx.global_tcx()
-    }
-}
-
-pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> {
-    type TyLayout;
-
-    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
-    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
-}
+impl<'a, 'tcx> LayoutTyper<'tcx> for LayoutCx<'a, 'tcx> {
+    type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
 
-impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
-    type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>;
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+        self.tcx
+    }
 
-    fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
         let ty = self.normalize_projections(ty);
 
         Ok(TyLayout {
             ty: ty,
-            layout: ty.layout(self)?,
+            layout: ty.layout(self.tcx, self.param_env)?,
             variant_index: None
         })
     }
 
-    fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> {
-        if !ty.has_projection_types() {
-            return ty;
-        }
-
-        let mut selcx = traits::SelectionContext::new(self);
-        let cause = traits::ObligationCause::dummy();
-        let traits::Normalized { value: result, obligations } =
-            traits::normalize(&mut selcx, cause, &ty);
-
-        let mut fulfill_cx = traits::FulfillmentContext::new();
-
-        for obligation in obligations {
-            fulfill_cx.register_predicate_obligation(self, obligation);
-        }
-
-        self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
+    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.tcx.normalize_associated_type_in_env(&ty, self.param_env)
     }
 }
 
@@ -1943,7 +2171,7 @@ pub fn field_count(&self) -> usize {
         }
     }
 
-    pub fn field_type<C: HasTyCtxt<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
+    pub fn field_type<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
         let tcx = cx.tcx();
 
         let ptr_field_type = |pointee: Ty<'tcx>| {
@@ -2014,7 +2242,10 @@ pub fn field_type<C: HasTyCtxt<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
         }
     }
 
-    pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout {
+    pub fn field<C: LayoutTyper<'tcx>>(&self,
+                                       cx: C,
+                                       i: usize)
+                                       -> C::TyLayout {
         cx.layout_of(cx.normalize_projections(self.field_type(cx, i)))
     }
 }
index cfb9e648d3b7eb1dd4c0d18c649080decd35403d..b5adcc8ed757d108435d8523d53af5ec62da60aa 100644 (file)
@@ -20,6 +20,7 @@
 use session::CompileResult;
 use traits::specialization_graph;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
+use ty::layout::{Layout, LayoutError};
 use ty::item_path;
 use ty::steal::Steal;
 use ty::subst::Substs;
@@ -293,6 +294,12 @@ fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
     }
 }
 
+impl<'tcx> QueryDescription for queries::layout_raw<'tcx> {
+    fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
+        format!("computing layout of `{}`", env.value)
+    }
+}
+
 impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> {
     fn describe(tcx: TyCtxt, def_id: DefId) -> String {
         format!("computing the supertraits of `{}`",
@@ -906,6 +913,12 @@ fn default() -> Self {
     [] specialization_graph_of: SpecializationGraph(DefId) -> Rc<specialization_graph::Graph>,
     [] is_object_safe: ObjectSafety(DefId) -> bool,
 
+    // Get the ParameterEnvironment for a given item; this environment
+    // will be in "user-facing" mode, meaning that it is suitabe for
+    // type-checking etc, and it does not normalize specializable
+    // associated types. This is almost always what you want,
+    // unless you are doing MIR optimizations, in which case you
+    // might want to use `reveal_all()` method to change modes.
     [] param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>,
 
     // Trait selection queries. These are best used by invoking `ty.moves_by_default()`,
@@ -914,6 +927,8 @@ fn default() -> Self {
     [] is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
     [] is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
     [] needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
+    [] layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+                                  -> Result<&'tcx Layout, LayoutError<'tcx>>,
 }
 
 fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@@ -981,3 +996,9 @@ fn needs_drop_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<De
         .unwrap_or(DefId::local(CRATE_DEF_INDEX));
     DepNode::NeedsDrop(def_id)
 }
+
+fn layout_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> {
+    let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
+        .unwrap_or(DefId::local(CRATE_DEF_INDEX));
+    DepNode::Layout(def_id)
+}
index 22fcc61953b2b4a838e66c0bec702ef743a7b3f2..653021119aab7d7d86fcd8505e051b608a3fa6a8 100644 (file)
@@ -19,7 +19,7 @@
 use hir::{map as hir_map, FreevarMap, TraitMap};
 use hir::def::{Def, CtorKind, ExportMap};
 use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
-use ich::{self, StableHashingContext};
+use ich::StableHashingContext;
 use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::privacy::AccessLevels;
@@ -158,29 +158,6 @@ pub struct ImplHeader<'tcx> {
     pub predicates: Vec<Predicate<'tcx>>,
 }
 
-impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> {
-    pub fn with_fresh_ty_vars(selcx: &mut traits::SelectionContext<'a, 'gcx, 'tcx>,
-                              impl_def_id: DefId)
-                              -> ImplHeader<'tcx>
-    {
-        let tcx = selcx.tcx();
-        let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id);
-
-        let header = ImplHeader {
-            impl_def_id: impl_def_id,
-            self_ty: tcx.type_of(impl_def_id),
-            trait_ref: tcx.impl_trait_ref(impl_def_id),
-            predicates: tcx.predicates_of(impl_def_id).predicates
-        }.subst(tcx, impl_substs);
-
-        let traits::Normalized { value: mut header, obligations } =
-            traits::normalize(selcx, traits::ObligationCause::dummy(), &header);
-
-        header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
-        header
-    }
-}
-
 #[derive(Copy, Clone, Debug)]
 pub struct AssociatedItem {
     pub def_id: DefId,
@@ -221,6 +198,22 @@ pub fn relevant_for_never<'tcx>(&self) -> bool {
             AssociatedKind::Method => !self.method_has_self_argument,
         }
     }
+
+    pub fn signature<'a, 'tcx>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) -> String {
+        match self.kind {
+            ty::AssociatedKind::Method => {
+                // We skip the binder here because the binder would deanonymize all
+                // late-bound regions, and we don't want method signatures to show up
+                // `as for<'r> fn(&'r MyType)`.  Pretty-printing handles late-bound
+                // regions just fine, showing `fn(&MyType)`.
+                format!("{}", tcx.type_of(self.def_id).fn_sig().skip_binder())
+            }
+            ty::AssociatedKind::Type => format!("type {};", self.name.to_string()),
+            ty::AssociatedKind::Const => {
+                format!("const {}: {:?};", self.name.to_string(), tcx.type_of(self.def_id))
+            }
+        }
+    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable)]
@@ -390,52 +383,6 @@ pub fn xform(self, v: ty::Variance) -> ty::Variance {
     }
 }
 
-#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)]
-pub struct MethodCallee<'tcx> {
-    /// Impl method ID, for inherent methods, or trait method ID, otherwise.
-    pub def_id: DefId,
-    pub ty: Ty<'tcx>,
-    pub substs: &'tcx Substs<'tcx>
-}
-
-/// With method calls, we store some extra information in
-/// side tables (i.e method_map). We use
-/// MethodCall as a key to index into these tables instead of
-/// just directly using the expression's NodeId. The reason
-/// for this being that we may apply adjustments (coercions)
-/// with the resulting expression also needing to use the
-/// side tables. The problem with this is that we don't
-/// assign a separate NodeId to this new expression
-/// and so it would clash with the base expression if both
-/// needed to add to the side tables. Thus to disambiguate
-/// we also keep track of whether there's an adjustment in
-/// our key.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct MethodCall {
-    pub expr_id: NodeId,
-    pub autoderef: u32
-}
-
-impl MethodCall {
-    pub fn expr(id: NodeId) -> MethodCall {
-        MethodCall {
-            expr_id: id,
-            autoderef: 0
-        }
-    }
-
-    pub fn autoderef(expr_id: NodeId, autoderef: u32) -> MethodCall {
-        MethodCall {
-            expr_id: expr_id,
-            autoderef: 1 + autoderef
-        }
-    }
-}
-
-// maps from an expression id that corresponds to a method call to the details
-// of the method to be invoked
-pub type MethodMap<'tcx> = FxHashMap<MethodCall, MethodCallee<'tcx>>;
-
 // Contains information needed to resolve types and (in the future) look up
 // the types of AST nodes.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
@@ -1237,6 +1184,11 @@ pub struct ParamEnv<'tcx> {
     /// the set of bounds on the in-scope type parameters, translated
     /// into Obligations, and elaborated and normalized.
     pub caller_bounds: &'tcx Slice<ty::Predicate<'tcx>>,
+
+    /// Typically, this is `Reveal::UserFacing`, but during trans we
+    /// want `Reveal::All` -- note that this is always paired with an
+    /// empty environment. To get that, use `ParamEnv::reveal()`.
+    pub reveal: traits::Reveal,
 }
 
 impl<'tcx> ParamEnv<'tcx> {
@@ -1264,7 +1216,7 @@ pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
             }
         } else {
             ParamEnvAnd {
-                param_env: ParamEnv::empty(),
+                param_env: ParamEnv::empty(self.reveal),
                 value: value,
             }
         }
@@ -1843,13 +1795,6 @@ pub fn ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx>
     }
 }
 
-/// Records the substitutions used to translate the polytype for an
-/// item into the monotype of an item reference.
-#[derive(Clone, RustcEncodable, RustcDecodable)]
-pub struct ItemSubsts<'tcx> {
-    pub substs: &'tcx Substs<'tcx>,
-}
-
 #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub enum ClosureKind {
     // Warning: Ordering is significant here! The ordering is chosen
@@ -1927,12 +1872,6 @@ pub fn maybe_walk<F>(&'tcx self, mut f: F)
     }
 }
 
-impl<'tcx> ItemSubsts<'tcx> {
-    pub fn is_noop(&self) -> bool {
-        self.substs.is_noop()
-    }
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum LvaluePreference {
     PreferMutLvalue,
@@ -2244,7 +2183,7 @@ pub fn def_path(self, id: DefId) -> hir_map::DefPath {
     }
 
     #[inline]
-    pub fn def_path_hash(self, def_id: DefId) -> ich::Fingerprint {
+    pub fn def_path_hash(self, def_id: DefId) -> hir_map::DefPathHash {
         if def_id.is_local() {
             self.hir.definitions().def_path_hash(def_id.index)
         } else {
@@ -2526,8 +2465,8 @@ fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option
 
 /// See `ParamEnv` struct def'n for details.
 fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   def_id: DefId)
-                                   -> ParamEnv<'tcx> {
+                       def_id: DefId)
+                       -> ParamEnv<'tcx> {
     // Compute the bounds on Self and the type parameters.
 
     let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx);
@@ -2545,7 +2484,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // are any errors at that point, so after type checking you can be
     // sure that this will succeed without errors anyway.
 
-    let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates));
+    let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
+                                             traits::Reveal::UserFacing);
 
     let body_id = tcx.hir.as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| {
         tcx.hir.maybe_body_owned_by(id).map_or(id, |body| body.node_id)
index c3ca679153759c2a23f4d63b267c8f94e9ee2bd0..1e2689243903e3a7c2f81f186d78ea4b2f09f0d9 100644 (file)
@@ -217,12 +217,50 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for ty::ItemSubsts<'a> {
-    type Lifted = ty::ItemSubsts<'tcx>;
+impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> {
+    type Lifted = ty::adjustment::Adjustment<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.substs).map(|substs| {
-            ty::ItemSubsts {
-                substs: substs
+        tcx.lift(&self.kind).and_then(|kind| {
+            tcx.lift(&self.target).map(|target| {
+                ty::adjustment::Adjustment { kind, target }
+            })
+        })
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
+    type Lifted = ty::adjustment::Adjust<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        match *self {
+            ty::adjustment::Adjust::NeverToAny =>
+                Some(ty::adjustment::Adjust::NeverToAny),
+            ty::adjustment::Adjust::ReifyFnPointer =>
+                Some(ty::adjustment::Adjust::ReifyFnPointer),
+            ty::adjustment::Adjust::UnsafeFnPointer =>
+                Some(ty::adjustment::Adjust::UnsafeFnPointer),
+            ty::adjustment::Adjust::ClosureFnPointer =>
+                Some(ty::adjustment::Adjust::ClosureFnPointer),
+            ty::adjustment::Adjust::MutToConstPointer =>
+                Some(ty::adjustment::Adjust::MutToConstPointer),
+            ty::adjustment::Adjust::Unsize =>
+                Some(ty::adjustment::Adjust::Unsize),
+            ty::adjustment::Adjust::Deref(ref overloaded) => {
+                tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref)
+            }
+            ty::adjustment::Adjust::Borrow(ref autoref) => {
+                tcx.lift(autoref).map(ty::adjustment::Adjust::Borrow)
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
+    type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.region).map(|region| {
+            ty::adjustment::OverloadedDeref {
+                region,
+                mutbl: self.mutbl,
             }
         })
     }
@@ -428,6 +466,20 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        ty::ParamEnv {
+            reveal: self.reveal,
+            caller_bounds: self.caller_bounds.fold_with(folder),
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        let &ty::ParamEnv { reveal: _, ref caller_bounds } = self;
+        caller_bounds.super_visit_with(visitor)
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         let v = self.iter().map(|p| p.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
@@ -540,10 +592,6 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
         ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl }
     }
 
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_mt(self)
-    }
-
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         self.ty.visit_with(visitor)
     }
@@ -560,10 +608,6 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
         }
     }
 
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_fn_sig(self)
-    }
-
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         self.inputs().iter().any(|i| i.visit_with(visitor)) ||
         self.output().visit_with(visitor)
@@ -610,10 +654,6 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
         }
     }
 
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_impl_header(self)
-    }
-
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         self.self_ty.visit_with(visitor) ||
             self.trait_ref.map(|r| r.visit_with(visitor)).unwrap_or(false) ||
@@ -651,15 +691,66 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjustment<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::ItemSubsts {
-            substs: self.substs.fold_with(folder),
+        ty::adjustment::Adjustment {
+            kind: self.kind.fold_with(folder),
+            target: self.target.fold_with(folder),
         }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.substs.visit_with(visitor)
+        self.kind.visit_with(visitor) ||
+        self.target.visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            ty::adjustment::Adjust::NeverToAny |
+            ty::adjustment::Adjust::ReifyFnPointer |
+            ty::adjustment::Adjust::UnsafeFnPointer |
+            ty::adjustment::Adjust::ClosureFnPointer |
+            ty::adjustment::Adjust::MutToConstPointer |
+            ty::adjustment::Adjust::Unsize => self.clone(),
+            ty::adjustment::Adjust::Deref(ref overloaded) => {
+                ty::adjustment::Adjust::Deref(overloaded.fold_with(folder))
+            }
+            ty::adjustment::Adjust::Borrow(ref autoref) => {
+                ty::adjustment::Adjust::Borrow(autoref.fold_with(folder))
+            }
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            ty::adjustment::Adjust::NeverToAny |
+            ty::adjustment::Adjust::ReifyFnPointer |
+            ty::adjustment::Adjust::UnsafeFnPointer |
+            ty::adjustment::Adjust::ClosureFnPointer |
+            ty::adjustment::Adjust::MutToConstPointer |
+            ty::adjustment::Adjust::Unsize => false,
+            ty::adjustment::Adjust::Deref(ref overloaded) => {
+                overloaded.visit_with(visitor)
+            }
+            ty::adjustment::Adjust::Borrow(ref autoref) => {
+                autoref.visit_with(visitor)
+            }
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        ty::adjustment::OverloadedDeref {
+            region: self.region.fold_with(folder),
+            mutbl: self.mutbl,
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.region.visit_with(visitor)
     }
 }
 
@@ -673,10 +764,6 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
         }
     }
 
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_autoref(self)
-    }
-
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match *self {
             ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor),
@@ -698,6 +785,17 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::Predicate<'tcx>> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        let v = self.iter().map(|p| p.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
+        folder.tcx().intern_predicates(&v)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.iter().any(|p| p.visit_with(visitor))
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
index bbb399434d6ae219c5aa25e068c6e52015110752..6923a6d21d63f1dec1cc499cffd9154338189b66 100644 (file)
@@ -11,6 +11,7 @@
 //! This module contains TypeVariants and its major components
 
 use hir::def_id::DefId;
+use hir::map::DefPathHash;
 
 use middle::region;
 use ty::subst::Substs;
@@ -29,7 +30,6 @@
 use serialize;
 
 use hir;
-use ich;
 
 use self::InferTy::*;
 use self::TypeVariants::*;
@@ -141,8 +141,6 @@ pub enum TypeVariants<'tcx> {
     TyFnDef(DefId, &'tcx Substs<'tcx>, PolyFnSig<'tcx>),
 
     /// A pointer to a function.  Written as `fn() -> i32`.
-    /// FIXME: This is currently also used to represent the callee of a method;
-    /// see ty::MethodCallee etc.
     TyFnPtr(PolyFnSig<'tcx>),
 
     /// A trait, defined with `trait`.
@@ -875,7 +873,7 @@ pub fn item_name(&self) -> Name {
         self.item_name // safe to skip the binder to access a name
     }
 
-    pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (ich::Fingerprint, InternedString) {
+    pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (DefPathHash, InternedString) {
         // We want something here that is stable across crate boundaries.
         // The DefId isn't but the `deterministic_hash` of the corresponding
         // DefPath is.
@@ -910,7 +908,7 @@ pub fn item_name(&self) -> Name {
         self.skip_binder().item_name()
     }
 
-    pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (ich::Fingerprint, InternedString) {
+    pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (DefPathHash, InternedString) {
         self.skip_binder().sort_key(tcx)
     }
 
@@ -1338,15 +1336,6 @@ pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
         }
     }
 
-    /// Type accessors for substructures of types
-    pub fn fn_args(&self) -> ty::Binder<&'tcx [Ty<'tcx>]> {
-        self.fn_sig().inputs()
-    }
-
-    pub fn fn_ret(&self) -> Binder<Ty<'tcx>> {
-        self.fn_sig().output()
-    }
-
     pub fn is_fn(&self) -> bool {
         match self.sty {
             TyFnDef(..) | TyFnPtr(_) => true,
index e23003bf772f2d284b33ad59ca63db7d16ddcd9d..d0d61323392c732c983c288867e814a2219efaa4 100644 (file)
@@ -320,10 +320,6 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
         }
     }
 
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_substs(self)
-    }
-
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         self.iter().any(|t| t.visit_with(visitor))
     }
index 86774136bd6cbc0c07741dd3c83b22b4a8ee8395..ef6bce8a3d9d101bf7809fc1edd51909b25878f5 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use hir::def_id::DefId;
-use ich::Fingerprint;
+use hir::map::DefPathHash;
 use traits::specialization_graph;
 use ty::fast_reject;
 use ty::fold::TypeFoldable;
@@ -33,7 +33,7 @@ pub struct TraitDef {
 
     /// The ICH of this trait's DefPath, cached here so it doesn't have to be
     /// recomputed all the time.
-    pub def_path_hash: Fingerprint,
+    pub def_path_hash: DefPathHash,
 }
 
 // We don't store the list of impls in a flat list because each cached list of
@@ -95,7 +95,7 @@ pub fn new(def_id: DefId,
                unsafety: hir::Unsafety,
                paren_sugar: bool,
                has_default_impl: bool,
-               def_path_hash: Fingerprint)
+               def_path_hash: DefPathHash)
                -> TraitDef {
         TraitDef {
             def_id,
index ce0f1ed5bb86c884c6dc33cc9efc768eb7bc9ae1..ec4ca54d6f5eddedb7c9f3ca1299d2bb269b7be5 100644 (file)
@@ -12,7 +12,6 @@
 
 use hir::def_id::{DefId, LOCAL_CRATE};
 use hir::map::DefPathData;
-use infer::InferCtxt;
 use ich::{StableHashingContext, NodeIdHashingMode};
 use traits::{self, Reveal};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -150,20 +149,33 @@ pub enum Representability {
 impl<'tcx> ty::ParamEnv<'tcx> {
     /// Construct a trait environment suitable for contexts where
     /// there are no where clauses in scope.
-    pub fn empty() -> Self {
-        Self::new(ty::Slice::empty())
+    pub fn empty(reveal: Reveal) -> Self {
+        Self::new(ty::Slice::empty(), reveal)
     }
 
     /// Construct a trait environment with the given set of predicates.
-    pub fn new(caller_bounds: &'tcx ty::Slice<ty::Predicate<'tcx>>) -> Self {
-        ty::ParamEnv { caller_bounds }
+    pub fn new(caller_bounds: &'tcx ty::Slice<ty::Predicate<'tcx>>,
+               reveal: Reveal)
+               -> Self {
+        ty::ParamEnv { caller_bounds, reveal }
     }
 
-    pub fn can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    /// Returns a new parameter environment with the same clauses, but
+    /// which "reveals" the true results of projections in all cases
+    /// (even for associated types that are specializable).  This is
+    /// the desired behavior during trans and certain other special
+    /// contexts; normally though we want to use `Reveal::UserFacing`,
+    /// which is the default.
+    pub fn reveal_all(self) -> Self {
+        ty::ParamEnv { reveal: Reveal::All, ..self }
+    }
+
+    pub fn can_type_implement_copy<'a>(self,
+                                       tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        self_type: Ty<'tcx>, span: Span)
-                                       -> Result<(), CopyImplementationError> {
+                                       -> Result<(), CopyImplementationError<'tcx>> {
         // FIXME: (@jroesch) float this code up
-        tcx.infer_ctxt(self.clone(), Reveal::UserFacing).enter(|infcx| {
+        tcx.infer_ctxt(()).enter(|infcx| {
             let (adt, substs) = match self_type.sty {
                 ty::TyAdt(adt, substs) => (adt, substs),
                 _ => return Err(CopyImplementationError::NotAnAdt),
@@ -171,8 +183,8 @@ pub fn can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             let field_implements_copy = |field: &ty::FieldDef| {
                 let cause = traits::ObligationCause::dummy();
-                match traits::fully_normalize(&infcx, cause, &field.ty(tcx, substs)) {
-                    Ok(ty) => !infcx.type_moves_by_default(ty, span),
+                match traits::fully_normalize(&infcx, cause, self, &field.ty(tcx, substs)) {
+                    Ok(ty) => !infcx.type_moves_by_default(self, ty, span),
                     Err(..) => false,
                 }
             };
@@ -779,32 +791,27 @@ pub fn needs_drop(&'tcx self,
         tcx.needs_drop_raw(param_env.and(self))
     }
 
+    /// Computes the layout of a type. Note that this implicitly
+    /// executes in "reveal all" mode.
     #[inline]
-    pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>)
+    pub fn layout<'lcx>(&'tcx self,
+                        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        param_env: ty::ParamEnv<'tcx>)
                         -> Result<&'tcx Layout, LayoutError<'tcx>> {
-        let tcx = infcx.tcx.global_tcx();
-        let can_cache = !self.has_param_types() && !self.has_self_ty();
-        if can_cache {
-            if let Some(&cached) = tcx.layout_cache.borrow().get(&self) {
-                return Ok(cached);
-            }
+        let ty = tcx.erase_regions(&self);
+        let layout = tcx.layout_raw(param_env.reveal_all().and(ty));
+
+        // NB: This recording is normally disabled; when enabled, it
+        // can however trigger recursive invocations of `layout()`.
+        // Therefore, we execute it *after* the main query has
+        // completed, to avoid problems around recursive structures
+        // and the like. (Admitedly, I wasn't able to reproduce a problem
+        // here, but it seems like the right thing to do. -nmatsakis)
+        if let Ok(l) = layout {
+            Layout::record_layout_for_printing(tcx, ty, param_env, l);
         }
 
-        let rec_limit = tcx.sess.recursion_limit.get();
-        let depth = tcx.layout_depth.get();
-        if depth > rec_limit {
-            tcx.sess.fatal(
-                &format!("overflow representing the type `{}`", self));
-        }
-
-        tcx.layout_depth.set(depth+1);
-        let layout = Layout::compute_uncached(self, infcx);
-        tcx.layout_depth.set(depth);
-        let layout = layout?;
-        if can_cache {
-            tcx.layout_cache.borrow_mut().insert(self, layout);
-        }
-        Ok(layout)
+        layout
     }
 
 
@@ -970,8 +977,12 @@ fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let (param_env, ty) = query.into_parts();
     let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem);
-    tcx.infer_ctxt(param_env, Reveal::UserFacing)
-       .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP))
+    tcx.infer_ctxt(())
+       .enter(|infcx| traits::type_known_to_meet_bound(&infcx,
+                                                       param_env,
+                                                       ty,
+                                                       trait_def_id,
+                                                       DUMMY_SP))
 }
 
 fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -980,8 +991,12 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let (param_env, ty) = query.into_parts();
     let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem);
-    tcx.infer_ctxt(param_env, Reveal::UserFacing)
-       .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP))
+    tcx.infer_ctxt(())
+       .enter(|infcx| traits::type_known_to_meet_bound(&infcx,
+                                                       param_env,
+                                                       ty,
+                                                       trait_def_id,
+                                                       DUMMY_SP))
 }
 
 fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -990,8 +1005,12 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let (param_env, ty) = query.into_parts();
     let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem);
-    tcx.infer_ctxt(param_env, Reveal::UserFacing)
-       .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP))
+    tcx.infer_ctxt(())
+       .enter(|infcx| traits::type_known_to_meet_bound(&infcx,
+                                                       param_env,
+                                                       ty,
+                                                       trait_def_id,
+                                                       DUMMY_SP))
 }
 
 fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -1062,6 +1081,25 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
+fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+                        -> Result<&'tcx Layout, LayoutError<'tcx>>
+{
+    let (param_env, ty) = query.into_parts();
+
+    let rec_limit = tcx.sess.recursion_limit.get();
+    let depth = tcx.layout_depth.get();
+    if depth > rec_limit {
+        tcx.sess.fatal(
+            &format!("overflow representing the type `{}`", ty));
+    }
+
+    tcx.layout_depth.set(depth+1);
+    let layout = Layout::compute_uncached(tcx, param_env, ty);
+    tcx.layout_depth.set(depth);
+
+    layout
+}
 
 pub fn provide(providers: &mut ty::maps::Providers) {
     *providers = ty::maps::Providers {
@@ -1069,6 +1107,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         is_sized_raw,
         is_freeze_raw,
         needs_drop_raw,
+        layout_raw,
         ..*providers
     };
 }
index d0cbbaf2c10bf391b803f0a7ff6b4cbdd74c6c54..aa2c9802e54737bff9bf52eb372ee1740f704129 100644 (file)
 /// make any progress at all. This is to prevent "livelock" where we
 /// say "$0 is WF if $0 is WF".
 pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                   param_env: ty::ParamEnv<'tcx>,
                                    body_id: ast::NodeId,
                                    ty: Ty<'tcx>,
                                    span: Span)
                                    -> Option<Vec<traits::PredicateObligation<'tcx>>>
 {
     let mut wf = WfPredicates { infcx: infcx,
+                                param_env: param_env,
                                 body_id: body_id,
                                 span: span,
                                 out: vec![] };
@@ -50,23 +52,25 @@ pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 /// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
 /// if `Bar: Eq`.
 pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                         param_env: ty::ParamEnv<'tcx>,
                                          body_id: ast::NodeId,
                                          trait_ref: &ty::TraitRef<'tcx>,
                                          span: Span)
                                          -> Vec<traits::PredicateObligation<'tcx>>
 {
-    let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] };
+    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
     wf.compute_trait_ref(trait_ref);
     wf.normalize()
 }
 
 pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                             param_env: ty::ParamEnv<'tcx>,
                                              body_id: ast::NodeId,
                                              predicate: &ty::Predicate<'tcx>,
                                              span: Span)
                                              -> Vec<traits::PredicateObligation<'tcx>>
 {
-    let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] };
+    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
 
     // (*) ok to skip binders, because wf code is prepared for it
     match *predicate {
@@ -126,6 +130,7 @@ pub enum ImpliedBound<'tcx> {
 /// the `ImpliedBound` type for more details.
 pub fn implied_bounds<'a, 'gcx, 'tcx>(
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     body_id: ast::NodeId,
     ty: Ty<'tcx>,
     span: Span)
@@ -148,7 +153,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>(
         // than the ultimate set. (Note: normally there won't be
         // unresolved inference variables here anyway, but there might be
         // during typeck under some circumstances.)
-        let obligations = obligations(infcx, body_id, ty, span).unwrap_or(vec![]);
+        let obligations = obligations(infcx, param_env, body_id, ty, span).unwrap_or(vec![]);
 
         // From the full set of obligations, just filter down to the
         // region relationships.
@@ -231,6 +236,7 @@ fn implied_bounds_from_components<'tcx>(sub_region: ty::Region<'tcx>,
 
 struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     body_id: ast::NodeId,
     span: Span,
     out: Vec<traits::PredicateObligation<'tcx>>,
@@ -244,11 +250,12 @@ fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::Obligati
     fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> {
         let cause = self.cause(traits::MiscObligation);
         let infcx = &mut self.infcx;
+        let param_env = self.param_env;
         self.out.iter()
                 .inspect(|pred| assert!(!pred.has_escaping_regions()))
                 .flat_map(|pred| {
                     let mut selcx = traits::SelectionContext::new(infcx);
-                    let pred = traits::normalize(&mut selcx, cause.clone(), pred);
+                    let pred = traits::normalize(&mut selcx, param_env, cause.clone(), pred);
                     once(pred.value).chain(pred.obligations)
                 })
                 .collect()
@@ -261,10 +268,12 @@ fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
         self.out.extend(obligations);
 
         let cause = self.cause(traits::MiscObligation);
+        let param_env = self.param_env;
         self.out.extend(
             trait_ref.substs.types()
                             .filter(|ty| !ty.has_escaping_regions())
                             .map(|ty| traits::Obligation::new(cause.clone(),
+                                                              param_env,
                                                               ty::Predicate::WellFormed(ty))));
     }
 
@@ -280,7 +289,7 @@ fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
         if !data.has_escaping_regions() {
             let predicate = data.trait_ref.to_predicate();
             let cause = self.cause(traits::ProjectionWf(data));
-            self.out.push(traits::Obligation::new(cause, predicate));
+            self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
         }
     }
 
@@ -291,7 +300,7 @@ fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<
                 def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
                 substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
             };
-            self.out.push(traits::Obligation::new(cause, trait_ref.to_predicate()));
+            self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate()));
         }
     }
 
@@ -301,6 +310,7 @@ fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<
     /// in which case we are not able to simplify at all.
     fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
         let mut subtys = ty0.walk();
+        let param_env = self.param_env;
         while let Some(ty) = subtys.next() {
             match ty.sty {
                 ty::TyBool |
@@ -350,6 +360,7 @@ fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
                         self.out.push(
                             traits::Obligation::new(
                                 cause,
+                                param_env,
                                 ty::Predicate::TypeOutlives(
                                     ty::Binder(
                                         ty::OutlivesPredicate(mt.ty, r)))));
@@ -389,12 +400,12 @@ fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
                     // checking those
 
                     let cause = self.cause(traits::MiscObligation);
-
                     let component_traits =
                         data.auto_traits().chain(data.principal().map(|p| p.def_id()));
                     self.out.extend(
                         component_traits.map(|did| traits::Obligation::new(
                             cause.clone(),
+                            param_env,
                             ty::Predicate::ObjectSafe(did)
                         ))
                     );
@@ -422,7 +433,9 @@ fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
 
                         let cause = self.cause(traits::MiscObligation);
                         self.out.push( // ...not the type we started from, so we made progress.
-                            traits::Obligation::new(cause, ty::Predicate::WellFormed(ty)));
+                            traits::Obligation::new(cause,
+                                                    self.param_env,
+                                                    ty::Predicate::WellFormed(ty)));
                     } else {
                         // Yes, resolved, proceed with the
                         // result. Should never return false because
@@ -448,7 +461,9 @@ fn nominal_obligations(&mut self,
         let cause = self.cause(traits::ItemObligation(def_id));
         predicates.predicates
                   .into_iter()
-                  .map(|pred| traits::Obligation::new(cause.clone(), pred))
+                  .map(|pred| traits::Obligation::new(cause.clone(),
+                                                      self.param_env,
+                                                      pred))
                   .filter(|pred| !pred.has_escaping_regions())
                   .collect()
     }
@@ -497,7 +512,9 @@ fn from_object_ty(&mut self, ty: Ty<'tcx>,
             for implicit_bound in implicit_bounds {
                 let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
                 let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound));
-                self.out.push(traits::Obligation::new(cause, outlives.to_predicate()));
+                self.out.push(traits::Obligation::new(cause,
+                                                      self.param_env,
+                                                      outlives.to_predicate()));
             }
         }
     }
index 5a1b7393db312562395f68c1ae1d793950c8b4af..15fbeb5108fdb26654da9de941aaba81eef71b33 100644 (file)
@@ -363,12 +363,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ItemSubsts<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ItemSubsts({:?})", self.substs)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         // when printing out the debug representation, we don't need
index 722ec6424fecec3dc9c0393b1df4989b022e16f2..122a37ee32aeab1b9c3ed0db03770170ac498a5e 100644 (file)
@@ -90,7 +90,7 @@ struct CheckLoanCtxt<'a, 'tcx: 'a> {
     dfcx_loans: &'a LoanDataFlow<'a, 'tcx>,
     move_data: &'a move_data::FlowedMoveData<'a, 'tcx>,
     all_loans: &'a [Loan<'tcx>],
-    param_env: &'a ty::ParamEnv<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
@@ -191,15 +191,17 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                      body: &hir::Body) {
     debug!("check_loans(body id={})", body.value.id);
 
+    let def_id = bccx.tcx.hir.body_owner_def_id(body.id());
     let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body.id());
+    let param_env = bccx.tcx.param_env(def_id);
     let mut clcx = CheckLoanCtxt {
         bccx: bccx,
         dfcx_loans: dfcx_loans,
         move_data: move_data,
         all_loans: all_loans,
-        param_env: &infcx.param_env
+        param_env,
     };
-    euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx).consume_body(body);
+    euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx, param_env).consume_body(body);
 }
 
 #[derive(PartialEq)]
@@ -805,7 +807,7 @@ fn check_if_assigned_path_is_moved(&self,
                 self.check_if_assigned_path_is_moved(id, span,
                                                      use_kind, lp_base);
             }
-            LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) |
+            LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) |
             LpExtend(ref lp_base, _, LpDeref(_)) => {
                 // assigning to `P[i]` requires `P` is initialized
                 // assigning to `(*P)` requires `P` is initialized
index f193588dd7d6c605e77849de7abd94b2c249d2e2..3d98c2a23dc674317b619c96c502830c16a9b624 100644 (file)
@@ -222,9 +222,9 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                                cmt: &mc::cmt<'tcx>)
                                                -> Option<mc::cmt<'tcx>> {
     match cmt.cat {
-        Categorization::Deref(.., mc::BorrowedPtr(..)) |
-        Categorization::Deref(.., mc::Implicit(..)) |
-        Categorization::Deref(.., mc::UnsafePtr(..)) |
+        Categorization::Deref(_, mc::BorrowedPtr(..)) |
+        Categorization::Deref(_, mc::Implicit(..)) |
+        Categorization::Deref(_, mc::UnsafePtr(..)) |
         Categorization::StaticItem => {
             Some(cmt.clone())
         }
@@ -237,7 +237,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 
         Categorization::Downcast(ref b, _) |
         Categorization::Interior(ref b, mc::InteriorField(_)) |
-        Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
+        Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern)) => {
             match b.ty.sty {
                 ty::TyAdt(def, _) => {
                     if def.has_dtor(bccx.tcx) {
@@ -253,12 +253,12 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             }
         }
 
-        Categorization::Interior(_, mc::InteriorElement(Kind::Index, _)) => {
+        Categorization::Interior(_, mc::InteriorElement(Kind::Index)) => {
             // Forbid move of arr[i] for arr: [T; 3]; see RFC 533.
             Some(cmt.clone())
         }
 
-        Categorization::Deref(ref b, _, mc::Unique) => {
+        Categorization::Deref(ref b, mc::Unique) => {
             check_and_get_illegal_move_origin(bccx, b)
         }
     }
index 5fc5682a60b456c38ba9f22e5745839b3e3cd6b5..89c60da396913cf36986f0be7be303cdbd13703f 100644 (file)
@@ -72,11 +72,11 @@ fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option<ast::NodeId>) -> R {
 
         match cmt.cat {
             Categorization::Rvalue(..) |
-            Categorization::Local(..) |                         // L-Local
+            Categorization::Local(..) |                     // L-Local
             Categorization::Upvar(..) |
-            Categorization::Deref(.., mc::BorrowedPtr(..)) |  // L-Deref-Borrowed
-            Categorization::Deref(.., mc::Implicit(..)) |
-            Categorization::Deref(.., mc::UnsafePtr(..)) => {
+            Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed
+            Categorization::Deref(_, mc::Implicit(..)) |
+            Categorization::Deref(_, mc::UnsafePtr(..)) => {
                 self.check_scope(self.scope(cmt))
             }
 
@@ -85,8 +85,8 @@ fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option<ast::NodeId>) -> R {
             }
 
             Categorization::Downcast(ref base, _) |
-            Categorization::Deref(ref base, _, mc::Unique) |     // L-Deref-Send
-            Categorization::Interior(ref base, _) => {             // L-Field
+            Categorization::Deref(ref base, mc::Unique) |   // L-Deref-Send
+            Categorization::Interior(ref base, _) => {      // L-Field
                 self.check(base, discr_scope)
             }
         }
@@ -108,7 +108,7 @@ fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> {
         //! rooting etc, and presuming `cmt` is not mutated.
 
         match cmt.cat {
-            Categorization::Rvalue(temp_scope, _) => {
+            Categorization::Rvalue(temp_scope) => {
                 temp_scope
             }
             Categorization::Upvar(..) => {
@@ -119,15 +119,15 @@ fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> {
                     self.bccx.region_maps.var_scope(local_id)))
             }
             Categorization::StaticItem |
-            Categorization::Deref(.., mc::UnsafePtr(..)) => {
+            Categorization::Deref(_, mc::UnsafePtr(..)) => {
                 self.bccx.tcx.types.re_static
             }
-            Categorization::Deref(.., mc::BorrowedPtr(_, r)) |
-            Categorization::Deref(.., mc::Implicit(_, r)) => {
+            Categorization::Deref(_, mc::BorrowedPtr(_, r)) |
+            Categorization::Deref(_, mc::Implicit(_, r)) => {
                 r
             }
             Categorization::Downcast(ref cmt, _) |
-            Categorization::Deref(ref cmt, _, mc::Unique) |
+            Categorization::Deref(ref cmt, mc::Unique) |
             Categorization::Interior(ref cmt, _) => {
                 self.scope(cmt)
             }
index 4cfee36359cd7576522dc4a871cbf339741b5d24..85a09969ac81c68cd950cd15ac9de31566b3bd11 100644 (file)
 
 pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                     body: hir::BodyId)
-                                    -> (Vec<Loan<'tcx>>,
-                                        move_data::MoveData<'tcx>) {
+                                    -> (Vec<Loan<'tcx>>, move_data::MoveData<'tcx>) {
+    let def_id = bccx.tcx.hir.body_owner_def_id(body);
     let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body);
+    let param_env = bccx.tcx.param_env(def_id);
     let mut glcx = GatherLoanCtxt {
         bccx: bccx,
         infcx: &infcx,
@@ -51,7 +52,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     };
 
     let body = glcx.bccx.tcx.hir.body(body);
-    euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx).consume_body(body);
+    euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx, param_env).consume_body(body);
 
     glcx.report_potential_errors();
     let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
index 1ee6d565d0d7debd0718f06e5382d62f7b3cc776..cceb4a7b3cc2180a1d41e9354d4298ac78c85445 100644 (file)
@@ -138,9 +138,9 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                        move_from: mc::cmt<'tcx>)
                                        -> DiagnosticBuilder<'a> {
     match move_from.cat {
-        Categorization::Deref(.., mc::BorrowedPtr(..)) |
-        Categorization::Deref(.., mc::Implicit(..)) |
-        Categorization::Deref(.., mc::UnsafePtr(..)) |
+        Categorization::Deref(_, mc::BorrowedPtr(..)) |
+        Categorization::Deref(_, mc::Implicit(..)) |
+        Categorization::Deref(_, mc::UnsafePtr(..)) |
         Categorization::StaticItem => {
             let mut err = struct_span_err!(bccx, move_from.span, E0507,
                              "cannot move out of {}",
@@ -152,7 +152,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             err
         }
 
-        Categorization::Interior(ref b, mc::InteriorElement(ik, _)) => {
+        Categorization::Interior(ref b, mc::InteriorElement(ik)) => {
             match (&b.ty.sty, ik) {
                 (&ty::TySlice(..), _) |
                 (_, Kind::Index) => {
index 7f90a8b19d4a1250794f360233134db585111fb5..b7965f81b8826e3e0a8b28d2cafb2d04699179fc 100644 (file)
@@ -133,7 +133,7 @@ fn restrict(&self,
                 RestrictionResult::Safe
             }
 
-            Categorization::Deref(cmt_base, _, pk) => {
+            Categorization::Deref(cmt_base, pk) => {
                 match pk {
                     mc::Unique => {
                         // R-Deref-Send-Pointer
index 9b084acc1938fd39eedea5e390239e564171fb1f..c72bdd04011161166f6abe81f84cd68af64bb8d9 100644 (file)
@@ -284,7 +284,7 @@ fn to_type(&self) -> ty::Ty<'tcx> { self.ty }
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub enum InteriorKind {
     InteriorField(mc::FieldName),
-    InteriorElement(mc::ElementKind),
+    InteriorElement,
 }
 
 trait ToInteriorKind { fn cleaned(self) -> InteriorKind; }
@@ -292,7 +292,7 @@ impl ToInteriorKind for mc::InteriorKind {
     fn cleaned(self) -> InteriorKind {
         match self {
             mc::InteriorField(name) => InteriorField(name),
-            mc::InteriorElement(_, elem_kind) => InteriorElement(elem_kind),
+            mc::InteriorElement(_) => InteriorElement,
         }
     }
 }
@@ -426,7 +426,7 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option<Rc<LoanPath<'tcx>>> {
             Some(new_lp(LpUpvar(id)))
         }
 
-        Categorization::Deref(ref cmt_base, _, pk) => {
+        Categorization::Deref(ref cmt_base, pk) => {
             opt_loan_path(cmt_base).map(|lp| {
                 new_lp(LpExtend(lp, cmt.mutbl, LpDeref(pk)))
             })
@@ -526,7 +526,7 @@ pub fn report_use_of_moved_value(&self,
                                      lp: &LoanPath<'tcx>,
                                      the_move: &move_data::Move,
                                      moved_lp: &LoanPath<'tcx>,
-                                     _param_env: &ty::ParamEnv<'tcx>) {
+                                     _param_env: ty::ParamEnv<'tcx>) {
         let (verb, verb_participle) = match use_kind {
             MovedInUse => ("use", "used"),
             MovedInCapture => ("capture", "captured"),
@@ -1125,17 +1125,6 @@ fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx
                 if let Some(_) = statement_scope_span(self.tcx, super_scope) {
                     db.note("consider using a `let` binding to increase its lifetime");
                 }
-
-
-
-                match err.cmt.cat {
-                    mc::Categorization::Rvalue(r, or) if r != or => {
-                        db.note("\
-before rustc 1.16, this temporary lived longer - see issue #39283 \
-(https://github.com/rust-lang/rust/issues/39283)");
-                    }
-                    _ => {}
-                }
             }
 
             err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
@@ -1232,7 +1221,7 @@ pub fn append_loan_path_to_string(&self,
                 }
             }
 
-            LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) => {
+            LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => {
                 self.append_autoderefd_loan_path_to_string(&lp_base, out);
                 out.push_str("[..]");
             }
@@ -1318,7 +1307,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             InteriorField(mc::NamedField(fld)) => write!(f, "{}", fld),
             InteriorField(mc::PositionalField(i)) => write!(f, "#{}", i),
-            InteriorElement(..) => write!(f, "[]"),
+            InteriorElement => write!(f, "[]"),
         }
     }
 }
index 1b364596a23f7fd518de0871ebb808afa4778592..0a31905c7928af79c050177a1653ee84d1bb135b 100644 (file)
@@ -191,7 +191,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
         LpVar(_) | LpUpvar(_) => {
             true
         }
-        LpExtend(.., LpInterior(_, InteriorKind::InteriorElement(..))) => {
+        LpExtend(.., LpInterior(_, InteriorKind::InteriorElement)) => {
             // Paths involving element accesses a[i] do not refer to a unique
             // location, as there is no accurate tracking of the indices.
             //
index b35b0865991659d29b461f44f441bc2991ab9d2d..7c3076fda4fe1f31d7b51fda097a5a68b51e244e 100644 (file)
@@ -20,7 +20,6 @@
 use rustc::middle::mem_categorization::{cmt};
 use rustc::middle::region::RegionMaps;
 use rustc::session::Session;
-use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::lint;
 use rustc_errors::{Diagnostic, Level, DiagnosticBuilder};
@@ -92,7 +91,10 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
     fn visit_local(&mut self, loc: &'tcx hir::Local) {
         intravisit::walk_local(self, loc);
 
-        self.check_irrefutable(&loc.pat, false);
+        self.check_irrefutable(&loc.pat, match loc.source {
+            hir::LocalSource::Normal => "local binding",
+            hir::LocalSource::ForLoopDesugar => "`for` loop binding",
+        });
 
         // Check legality of move bindings and `@` patterns.
         self.check_patterns(false, slice::ref_slice(&loc.pat));
@@ -102,7 +104,7 @@ fn visit_body(&mut self, body: &'tcx hir::Body) {
         intravisit::walk_body(self, body);
 
         for arg in &body.arguments {
-            self.check_irrefutable(&arg.pat, true);
+            self.check_irrefutable(&arg.pat, "function argument");
             self.check_patterns(false, slice::ref_slice(&arg.pat));
         }
     }
@@ -211,7 +213,7 @@ fn check_match(
                 .map(|pat| vec![pat.0])
                 .collect();
             let scrut_ty = self.tables.node_id_to_type(scrut.id);
-            check_exhaustive(cx, scrut_ty, scrut.span, &matrix, source);
+            check_exhaustive(cx, scrut_ty, scrut.span, &matrix);
         })
     }
 
@@ -224,13 +226,7 @@ fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool {
         }
     }
 
-    fn check_irrefutable(&self, pat: &Pat, is_fn_arg: bool) {
-        let origin = if is_fn_arg {
-            "function argument"
-        } else {
-            "local binding"
-        };
-
+    fn check_irrefutable(&self, pat: &Pat, origin: &str) {
         let module = self.tcx.hir.get_module_parent(pat.id);
         MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
             let mut patcx = PatternContext::new(self.tcx, self.tables);
@@ -396,8 +392,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
 fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                               scrut_ty: Ty<'tcx>,
                               sp: Span,
-                              matrix: &Matrix<'a, 'tcx>,
-                              source: hir::MatchSource) {
+                              matrix: &Matrix<'a, 'tcx>) {
     let wild_pattern = Pattern {
         ty: scrut_ty,
         span: DUMMY_SP,
@@ -410,52 +405,32 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
             } else {
                 pats.iter().map(|w| w.single_pattern()).collect()
             };
-            match source {
-                hir::MatchSource::ForLoopDesugar => {
-                    // `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
-                    let witness = match *witnesses[0].kind {
-                        PatternKind::Variant { ref subpatterns, .. } => match &subpatterns[..] {
-                            &[ref pat] => &pat.pattern,
-                            _ => bug!(),
-                        },
-                        _ => bug!(),
-                    };
-                    let pattern_string = witness.to_string();
-                    struct_span_err!(cx.tcx.sess, sp, E0297,
-                        "refutable pattern in `for` loop binding: \
-                                `{}` not covered",
-                                pattern_string)
-                        .span_label(sp, format!("pattern `{}` not covered", pattern_string))
-                        .emit();
+
+            const LIMIT: usize = 3;
+            let joined_patterns = match witnesses.len() {
+                0 => bug!(),
+                1 => format!("`{}`", witnesses[0]),
+                2...LIMIT => {
+                    let (tail, head) = witnesses.split_last().unwrap();
+                    let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
+                    format!("`{}` and `{}`", head.join("`, `"), tail)
                 },
                 _ => {
-                    const LIMIT: usize = 3;
-                    let joined_patterns = match witnesses.len() {
-                        0 => bug!(),
-                        1 => format!("`{}`", witnesses[0]),
-                        2...LIMIT => {
-                            let (tail, head) = witnesses.split_last().unwrap();
-                            let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
-                            format!("`{}` and `{}`", head.join("`, `"), tail)
-                        },
-                        _ => {
-                            let (head, tail) = witnesses.split_at(LIMIT);
-                            let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
-                            format!("`{}` and {} more", head.join("`, `"), tail.len())
-                        }
-                    };
-
-                    let label_text = match witnesses.len() {
-                        1 => format!("pattern {} not covered", joined_patterns),
-                        _ => format!("patterns {} not covered", joined_patterns)
-                    };
-                    create_e0004(cx.tcx.sess, sp,
-                                 format!("non-exhaustive patterns: {} not covered",
-                                         joined_patterns))
-                        .span_label(sp, label_text)
-                        .emit();
-                },
-            }
+                    let (head, tail) = witnesses.split_at(LIMIT);
+                    let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
+                    format!("`{}` and {} more", head.join("`, `"), tail.len())
+                }
+            };
+
+            let label_text = match witnesses.len() {
+                1 => format!("pattern {} not covered", joined_patterns),
+                _ => format!("patterns {} not covered", joined_patterns)
+            };
+            create_e0004(cx.tcx.sess, sp,
+                            format!("non-exhaustive patterns: {} not covered",
+                                    joined_patterns))
+                .span_label(sp, label_text)
+                .emit();
         }
         NotUseful => {
             // This is good, wildcard pattern isn't reachable
@@ -518,11 +493,11 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
 ///
 /// FIXME: this should be done by borrowck.
 fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
-    cx.tcx.infer_ctxt((cx.tables, cx.param_env), Reveal::UserFacing).enter(|infcx| {
+    cx.tcx.infer_ctxt(cx.tables).enter(|infcx| {
         let mut checker = MutationChecker {
             cx: cx,
         };
-        ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx).walk_expr(guard);
+        ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx, cx.param_env).walk_expr(guard);
     });
 }
 
index 04fc3e68c8ccd9033f3fd0226cfc10e6fe4967b0..4fc7ef8035eb54d777351cb8cc2745957a5a1f69 100644 (file)
@@ -452,12 +452,14 @@ enum Method { GET, POST }
 
 
 E0297: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
 Patterns used to bind names must be irrefutable. That is, they must guarantee
 that a name will be extracted in all cases. Instead of pattern matching the
 loop variable, consider using a `match` or `if let` inside the loop body. For
 instance:
 
-```compile_fail,E0297
+```compile_fail,E0005
 let xs : Vec<Option<i32>> = vec![Some(1), None];
 
 // This fails because `None` is not covered.
index e79f23aee11456e2fd3f3ce35f7e72a95f45d1ca..3d07ffc2bc77aefda074e589a1267e478de2b3c7 100644 (file)
@@ -286,8 +286,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         }
       }
       hir::ExprPath(ref qpath) => {
-        let substs = cx.tables.node_id_item_substs(e.id)
-            .unwrap_or_else(|| tcx.intern_substs(&[]));
+        let substs = cx.tables.node_substs(e.id);
 
         // Avoid applying substitutions if they're empty, that'd ICE.
         let substs = if cx.substs.is_empty() {
@@ -484,9 +483,11 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
 
-    tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+    tcx.infer_ctxt(()).enter(|infcx| {
+        let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
+                                                 param_env,
                                                  trait_ref.to_poly_trait_predicate());
         let selection = match selcx.select(&obligation) {
             Ok(Some(vtable)) => vtable,
index a2e0bb80d23ddf40b78d24ab9eb12b6ed18ae715..d175920e8a6baf895abb18522c26e55295cf5954 100644 (file)
@@ -584,8 +584,7 @@ fn lower_path(&mut self,
         let kind = match def {
             Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                 let tcx = self.tcx.global_tcx();
-                let substs = self.tables.node_id_item_substs(id)
-                    .unwrap_or_else(|| tcx.intern_substs(&[]));
+                let substs = self.tables.node_substs(id);
                 match eval::lookup_const_by_id(tcx, def_id, substs) {
                     Some((def_id, _substs)) => {
                         // Enter the inlined constant's tables temporarily.
index 1d236a96bf62ed97c313cfad34909734a9def2aa..2b74d0a812b4a90f8fcf11558054e3e88c5a8cee 100644 (file)
@@ -46,6 +46,7 @@
 struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>,
     region_maps: &'a mut RegionMaps,
+    param_env: ty::ParamEnv<'tcx>,
 }
 
 struct RH<'a> {
@@ -153,9 +154,13 @@ fn test_env<F>(source_string: &str,
                              index,
                              "test_crate",
                              |tcx| {
-        tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+        tcx.infer_ctxt(()).enter(|infcx| {
             let mut region_maps = RegionMaps::new();
-            body(Env { infcx: &infcx, region_maps: &mut region_maps });
+            body(Env {
+                infcx: &infcx,
+                region_maps: &mut region_maps,
+                param_env: ty::ParamEnv::empty(Reveal::UserFacing),
+            });
             let free_regions = FreeRegionMap::new();
             let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
             infcx.resolve_regions_and_report_errors(def_id, &region_maps, &free_regions);
@@ -250,14 +255,14 @@ fn search(this: &Env, it: &hir::Item, idx: usize, names: &[String]) -> Option<as
     }
 
     pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
-        match self.infcx.sub_types(true, &ObligationCause::dummy(), a, b) {
+        match self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(a, b) {
             Ok(_) => true,
             Err(ref e) => panic!("Encountered error: {}", e),
         }
     }
 
     pub fn is_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
-        self.infcx.can_sub_types(a, b).is_ok()
+        self.infcx.can_sub(self.param_env, a, b).is_ok()
     }
 
     pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
@@ -354,30 +359,23 @@ pub fn t_rptr_empty(&self) -> Ty<'tcx> {
                                   self.tcx().types.isize)
     }
 
-    pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> {
-        infer::TypeTrace::dummy(self.tcx())
-    }
-
-    pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
-        let trace = self.dummy_type_trace();
-        self.infcx.sub(true, trace, &t1, &t2)
+    pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, ()> {
+        self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(t1, t2)
     }
 
     pub fn lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
-        let trace = self.dummy_type_trace();
-        self.infcx.lub(true, trace, &t1, &t2)
+        self.infcx.at(&ObligationCause::dummy(), self.param_env).lub(t1, t2)
     }
 
     pub fn glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
-        let trace = self.dummy_type_trace();
-        self.infcx.glb(true, trace, &t1, &t2)
+        self.infcx.at(&ObligationCause::dummy(), self.param_env).glb(t1, t2)
     }
 
     /// Checks that `t1 <: t2` is true (this may register additional
     /// region checks).
     pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
         match self.sub(t1, t2) {
-            Ok(InferOk { obligations, .. }) => {
+            Ok(InferOk { obligations, value: () }) => {
                 // None of these tests should require nested obligations:
                 assert!(obligations.is_empty());
             }
index 861880aa265ec140a1072f8b25a12bc211c827e6..7a64cdeee65c74028cea750a7073f5d3b0348a06 100644 (file)
@@ -157,6 +157,14 @@ pub fn note_expected_found_extra(&mut self,
         self
     }
 
+    pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
+        self.highlighted_note(vec![
+            (format!("`{}` from trait: `", name), Style::NoStyle),
+            (signature, Style::Highlight),
+            ("`".to_string(), Style::NoStyle)]);
+        self
+    }
+
     pub fn note(&mut self, msg: &str) -> &mut Self {
         self.sub(Level::Note, msg, MultiSpan::new(), None);
         self
index a9645f9ab7bb2305398a4ff23535cc93ee3d73c7..f820ea4c5e17827e9da683548844bd845d8009ec 100644 (file)
@@ -705,11 +705,9 @@ fn fix_multispan_in_std_macros(&mut self, span: &mut MultiSpan) -> bool {
                 if *sp == DUMMY_SP {
                     continue;
                 }
-                if cm.span_to_filename(sp.clone()).contains("macros>") {
-                    let v = sp.macro_backtrace();
-                    if let Some(use_site) = v.last() {
-                        before_after.push((sp.clone(), use_site.call_site.clone()));
-                    }
+                let call_sp = cm.call_span_if_macro(*sp);
+                if call_sp != *sp {
+                    before_after.push((sp.clone(), call_sp));
                 }
                 for trace in sp.macro_backtrace().iter().rev() {
                     // Only show macro locations that are local
index d1aaaf4ba7b378c7e8dd0f2f9e78cf5b15a525b8..8d5e9e776ed23ec05d8e7e6f77b27dcc7b9a6961 100644 (file)
@@ -102,6 +102,7 @@ pub trait CodeMapper {
     fn span_to_string(&self, sp: Span) -> String;
     fn span_to_filename(&self, sp: Span) -> FileName;
     fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
+    fn call_span_if_macro(&self, sp: Span) -> Span;
 }
 
 impl CodeSuggestion {
index f5727aa0a5ecc4be364e23c0fbcbfe27571c45dc..be4d610a89559e5484ef35fd037590f4b04be30a 100644 (file)
@@ -32,6 +32,7 @@
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::map::DefPathHash;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::ich::{Fingerprint, StableHashingContext};
 use rustc::ty::TyCtxt;
@@ -218,7 +219,7 @@ fn compute_and_store_ich_for_trait_impls(&mut self, krate: &'tcx hir::Crate)
     {
         let tcx = self.hcx.tcx();
 
-        let mut impls: Vec<(Fingerprint, Fingerprint)> = krate
+        let mut impls: Vec<(DefPathHash, Fingerprint)> = krate
             .trait_impls
             .iter()
             .map(|(&trait_id, impls)| {
index b016ff34bc5c604be24c0b0d4c1557d34bf2a573..682a7051a1e95e45883d5827cee3e27b94e1bace 100644 (file)
 
 use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId};
 use rustc::hir::def_id::DefIndex;
+use rustc::hir::map::DefPathHash;
 use rustc::ich::Fingerprint;
 use rustc::middle::cstore::EncodedMetadataHash;
 use std::sync::Arc;
 use rustc_data_structures::fx::FxHashMap;
-
-use super::directory::DefPathIndex;
+use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
 /// Data for use when recompiling the **current crate**.
 #[derive(Debug, RustcEncodable, RustcDecodable)]
 pub struct SerializedDepGraph {
-    pub edges: Vec<SerializedEdgeSet>,
+    /// The set of all DepNodes in the graph
+    pub nodes: IndexVec<DepNodeIndex, DepNode<DefPathHash>>,
+    /// For each DepNode, stores the list of edges originating from that
+    /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
+    /// which holds the actual DepNodeIndices of the target nodes.
+    pub edge_list_indices: Vec<(u32, u32)>,
+    /// A flattened list of all edge targets in the graph. Edge sources are
+    /// implicit in edge_list_indices.
+    pub edge_list_data: Vec<DepNodeIndex>,
 
     /// These are output nodes that have no incoming edges. We track
     /// these separately so that when we reload all edges, we don't
     /// lose track of these nodes.
-    pub bootstrap_outputs: Vec<DepNode<DefPathIndex>>,
+    pub bootstrap_outputs: Vec<DepNode<DefPathHash>>,
 
     /// These are hashes of two things:
     /// - the HIR nodes in this crate
@@ -51,18 +59,36 @@ pub struct SerializedDepGraph {
     pub hashes: Vec<SerializedHash>,
 }
 
-/// Represents a set of "reduced" dependency edge. We group the
-/// outgoing edges from a single source together.
-#[derive(Debug, RustcEncodable, RustcDecodable)]
-pub struct SerializedEdgeSet {
-    pub source: DepNode<DefPathIndex>,
-    pub targets: Vec<DepNode<DefPathIndex>>
+/// The index of a DepNode in the SerializedDepGraph::nodes array.
+#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug,
+         RustcEncodable, RustcDecodable)]
+pub struct DepNodeIndex(pub u32);
+
+impl DepNodeIndex {
+    #[inline]
+    pub fn new(idx: usize) -> DepNodeIndex {
+        assert!(idx <= ::std::u32::MAX as usize);
+        DepNodeIndex(idx as u32)
+    }
+}
+
+impl Idx for DepNodeIndex {
+    #[inline]
+    fn new(idx: usize) -> Self {
+        assert!(idx <= ::std::u32::MAX as usize);
+        DepNodeIndex(idx as u32)
+    }
+
+    #[inline]
+    fn index(self) -> usize {
+        self.0 as usize
+    }
 }
 
 #[derive(Debug, RustcEncodable, RustcDecodable)]
 pub struct SerializedHash {
     /// def-id of thing being hashed
-    pub dep_node: DepNode<DefPathIndex>,
+    pub dep_node: DepNode<DefPathHash>,
 
     /// the hash as of previous compilation, computed by code in
     /// `hash` module
@@ -115,5 +141,5 @@ pub struct SerializedMetadataHashes {
     /// is only populated if -Z query-dep-graph is specified. It will be
     /// empty otherwise. Importing crates are perfectly happy with just having
     /// the DefIndex.
-    pub index_map: FxHashMap<DefIndex, DefPathIndex>
+    pub index_map: FxHashMap<DefIndex, DefPathHash>
 }
diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs
deleted file mode 100644 (file)
index b9b8602..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Code to convert a DefId into a DefPath (when serializing) and then
-//! back again (when deserializing). Note that the new DefId
-//! necessarily will not be the same as the old (and of course the
-//! item might even be removed in the meantime).
-
-use rustc::dep_graph::DepNode;
-use rustc::hir::map::DefPath;
-use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
-use rustc::ty::TyCtxt;
-use rustc::util::nodemap::DefIdMap;
-use std::fmt::{self, Debug};
-use std::iter::once;
-use std::collections::HashMap;
-
-/// Index into the DefIdDirectory
-#[derive(Copy, Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq,
-         RustcEncodable, RustcDecodable)]
-pub struct DefPathIndex {
-    index: u32
-}
-
-#[derive(RustcEncodable, RustcDecodable)]
-pub struct DefIdDirectory {
-    // N.B. don't use Removable here because these def-ids are loaded
-    // directly without remapping, so loading them should not fail.
-    paths: Vec<DefPath>,
-
-    // For each crate, saves the crate-name/disambiguator so that
-    // later we can match crate-numbers up again.
-    krates: Vec<CrateInfo>,
-}
-
-#[derive(Debug, RustcEncodable, RustcDecodable)]
-pub struct CrateInfo {
-    krate: CrateNum,
-    name: String,
-    disambiguator: String,
-}
-
-impl DefIdDirectory {
-    pub fn new(krates: Vec<CrateInfo>) -> DefIdDirectory {
-        DefIdDirectory { paths: vec![], krates: krates }
-    }
-
-    fn max_current_crate(&self, tcx: TyCtxt) -> CrateNum {
-        tcx.sess.cstore.crates()
-                       .into_iter()
-                       .max()
-                       .unwrap_or(LOCAL_CRATE)
-    }
-
-    /// Returns a string form for `index`; useful for debugging
-    pub fn def_path_string(&self, tcx: TyCtxt, index: DefPathIndex) -> String {
-        let path = &self.paths[index.index as usize];
-        if self.krate_still_valid(tcx, self.max_current_crate(tcx), path.krate) {
-            path.to_string(tcx)
-        } else {
-            format!("<crate {} changed>", path.krate)
-        }
-    }
-
-    pub fn krate_still_valid(&self,
-                             tcx: TyCtxt,
-                             max_current_crate: CrateNum,
-                             krate: CrateNum) -> bool {
-        // Check that the crate-number still matches. For now, if it
-        // doesn't, just return None. We could do better, such as
-        // finding the new number.
-
-        if krate > max_current_crate {
-            false
-        } else {
-            let old_info = &self.krates[krate.as_usize()];
-            assert_eq!(old_info.krate, krate);
-            let old_name: &str = &old_info.name;
-            let old_disambiguator: &str = &old_info.disambiguator;
-            let new_name: &str = &tcx.crate_name(krate).as_str();
-            let new_disambiguator: &str = &tcx.crate_disambiguator(krate).as_str();
-            old_name == new_name && old_disambiguator == new_disambiguator
-        }
-    }
-
-    pub fn retrace(&self, tcx: TyCtxt) -> RetracedDefIdDirectory {
-
-        fn make_key(name: &str, disambiguator: &str) -> String {
-            format!("{}/{}", name, disambiguator)
-        }
-
-        let new_krates: HashMap<_, _> =
-            once(LOCAL_CRATE)
-            .chain(tcx.sess.cstore.crates())
-            .map(|krate| (make_key(&tcx.crate_name(krate).as_str(),
-                                   &tcx.crate_disambiguator(krate).as_str()), krate))
-            .collect();
-
-        let ids = self.paths.iter()
-                            .map(|path| {
-                                let old_krate_id = path.krate.as_usize();
-                                assert!(old_krate_id < self.krates.len());
-                                let old_crate_info = &self.krates[old_krate_id];
-                                let old_crate_key = make_key(&old_crate_info.name,
-                                                         &old_crate_info.disambiguator);
-                                if let Some(&new_crate_key) = new_krates.get(&old_crate_key) {
-                                    tcx.retrace_path(new_crate_key, &path.data)
-                                } else {
-                                    debug!("crate {:?} no longer exists", old_crate_key);
-                                    None
-                                }
-                            })
-                            .collect();
-        RetracedDefIdDirectory { ids: ids }
-    }
-}
-
-#[derive(Debug, RustcEncodable, RustcDecodable)]
-pub struct RetracedDefIdDirectory {
-    ids: Vec<Option<DefId>>
-}
-
-impl RetracedDefIdDirectory {
-    pub fn def_id(&self, index: DefPathIndex) -> Option<DefId> {
-        self.ids[index.index as usize]
-    }
-
-    pub fn map(&self, node: &DepNode<DefPathIndex>) -> Option<DepNode<DefId>> {
-        node.map_def(|&index| self.def_id(index))
-    }
-}
-
-pub struct DefIdDirectoryBuilder<'a,'tcx:'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    hash: DefIdMap<DefPathIndex>,
-    directory: DefIdDirectory,
-}
-
-impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> DefIdDirectoryBuilder<'a, 'tcx> {
-        let mut krates: Vec<_> =
-            once(LOCAL_CRATE)
-            .chain(tcx.sess.cstore.crates())
-            .map(|krate| {
-                CrateInfo {
-                    krate: krate,
-                    name: tcx.crate_name(krate).to_string(),
-                    disambiguator: tcx.crate_disambiguator(krate).to_string()
-                }
-            })
-            .collect();
-
-        // the result of crates() is not in order, so sort list of
-        // crates so that we can just index it later
-        krates.sort_by_key(|k| k.krate);
-
-        DefIdDirectoryBuilder {
-            tcx: tcx,
-            hash: DefIdMap(),
-            directory: DefIdDirectory::new(krates),
-        }
-    }
-
-    pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
-        self.tcx
-    }
-
-    pub fn add(&mut self, def_id: DefId) -> DefPathIndex {
-        debug!("DefIdDirectoryBuilder: def_id={:?}", def_id);
-        let tcx = self.tcx;
-        let paths = &mut self.directory.paths;
-        self.hash.entry(def_id)
-                 .or_insert_with(|| {
-                     let def_path = tcx.def_path(def_id);
-                     let index = paths.len() as u32;
-                     paths.push(def_path);
-                     DefPathIndex { index: index }
-                 })
-                 .clone()
-    }
-
-    pub fn map(&mut self, node: &DepNode<DefId>) -> DepNode<DefPathIndex> {
-        node.map_def(|&def_id| Some(self.add(def_id))).unwrap()
-    }
-
-    pub fn directory(&self) -> &DefIdDirectory {
-        &self.directory
-    }
-}
-
-impl Debug for DefIdDirectory {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-        fmt.debug_list()
-           .entries(self.paths.iter().enumerate())
-           .finish()
-    }
-}
index 5facfe36efdb93c8b452b186e50b15526f23e1e3..3a428bd7b8f7d273819fb2c8e3481d01a3798337 100644 (file)
@@ -40,7 +40,6 @@
 //! previous revision to compare things to.
 //!
 
-use super::directory::RetracedDefIdDirectory;
 use super::load::DirtyNodes;
 use rustc::dep_graph::{DepGraphQuery, DepNode};
 use rustc::hir;
 const CFG: &'static str = "cfg";
 
 pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                               dirty_inputs: &DirtyNodes,
-                                               retraced: &RetracedDefIdDirectory) {
+                                               dirty_inputs: &DirtyNodes) {
     // can't add `#[rustc_dirty]` etc without opting in to this feature
     if !tcx.sess.features.borrow().rustc_attrs {
         return;
     }
 
     let _ignore = tcx.dep_graph.in_ignore();
+    let def_path_hash_to_def_id = tcx.def_path_hash_to_def_id.as_ref().unwrap();
     let dirty_inputs: FxHashSet<DepNode<DefId>> =
         dirty_inputs.keys()
-                    .filter_map(|d| retraced.map(d))
+                    .filter_map(|dep_node| {
+                        dep_node.map_def(|def_path_hash| {
+                            def_path_hash_to_def_id.get(def_path_hash).cloned()
+                        })
+                    })
                     .collect();
+
     let query = tcx.dep_graph.query();
     debug!("query-nodes: {:?}", query.nodes());
     let krate = tcx.hir.krate();
index 7fad600d1054294ff769cec9341d5172fa28bf6f..b30a1f4d3254fbfbd157850460895bc5f918a866 100644 (file)
@@ -12,6 +12,7 @@
 
 use rustc::dep_graph::{DepNode, WorkProductId};
 use rustc::hir::def_id::DefId;
+use rustc::hir::map::DefPathHash;
 use rustc::hir::svh::Svh;
 use rustc::ich::Fingerprint;
 use rustc::session::Session;
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 use rustc_serialize::Decodable as RustcDecodable;
 use rustc_serialize::opaque::Decoder;
+use std::default::Default;
 use std::path::{Path};
 use std::sync::Arc;
 
 use IncrementalHashesMap;
 use super::data::*;
-use super::directory::*;
 use super::dirty_clean;
 use super::hash::*;
 use super::fs::*;
@@ -33,7 +34,7 @@
 
 // The key is a dirty node. The value is **some** base-input that we
 // can blame it on.
-pub type DirtyNodes = FxHashMap<DepNode<DefPathIndex>, DepNode<DefPathIndex>>;
+pub type DirtyNodes = FxHashMap<DepNode<DefPathHash>, DepNode<DefPathHash>>;
 
 /// If we are in incremental mode, and a previous dep-graph exists,
 /// then load up those nodes/edges that are still valid into the
@@ -118,6 +119,16 @@ fn load_data(sess: &Session, path: &Path) -> Option<Vec<u8>> {
     None
 }
 
+/// Try to convert a DepNode from the old dep-graph into a DepNode in the
+/// current graph by mapping the DefPathHash to a valid DefId. This will fail
+/// if the DefPathHash refers to something that has been removed (because
+/// there is no DefId for that thing anymore).
+fn retrace(tcx: TyCtxt, dep_node: &DepNode<DefPathHash>) -> Option<DepNode<DefId>> {
+    dep_node.map_def(|def_path_hash| {
+        tcx.def_path_hash_to_def_id.as_ref().unwrap().get(def_path_hash).cloned()
+    })
+}
+
 /// Decode the dep graph and load the edges/nodes that are still clean
 /// into `tcx.dep_graph`.
 pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -149,16 +160,25 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         return Ok(());
     }
 
-    let directory = DefIdDirectory::decode(&mut dep_graph_decoder)?;
     let serialized_dep_graph = SerializedDepGraph::decode(&mut dep_graph_decoder)?;
 
-    let edge_map: FxHashMap<_, _> = serialized_dep_graph.edges
-                                                        .into_iter()
-                                                        .map(|s| (s.source, s.targets))
-                                                        .collect();
+    let edge_map: FxHashMap<DepNode<DefPathHash>, Vec<DepNode<DefPathHash>>> = {
+        let capacity = serialized_dep_graph.edge_list_data.len();
+        let mut edge_map = FxHashMap::with_capacity_and_hasher(capacity, Default::default());
+
+        for (node_index, source) in serialized_dep_graph.nodes.iter().enumerate() {
+            let (start, end) = serialized_dep_graph.edge_list_indices[node_index];
+            let targets =
+                (&serialized_dep_graph.edge_list_data[start as usize .. end as usize])
+                .into_iter()
+                .map(|&node_index| serialized_dep_graph.nodes[node_index].clone())
+                .collect();
+
+            edge_map.insert(source.clone(), targets);
+        }
 
-    // Retrace the paths in the directory to find their current location (if any).
-    let retraced = directory.retrace(tcx);
+        edge_map
+    };
 
     // Compute the set of nodes from the old graph where some input
     // has changed or been removed. These are "raw" source nodes,
@@ -169,8 +189,7 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // the current compilation).
     let dirty_raw_nodes = initial_dirty_nodes(tcx,
                                               incremental_hashes_map,
-                                              &serialized_dep_graph.hashes,
-                                              &retraced);
+                                              &serialized_dep_graph.hashes);
     let dirty_raw_nodes = transitive_dirty_nodes(&edge_map, dirty_raw_nodes);
 
     // Recreate the edges in the graph that are still clean.
@@ -179,7 +198,7 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut extra_edges = vec![];
     for (source, targets) in &edge_map {
         for target in targets {
-            process_edges(tcx, source, target, &edge_map, &directory, &retraced, &dirty_raw_nodes,
+            process_edges(tcx, source, target, &edge_map, &dirty_raw_nodes,
                           &mut clean_work_products, &mut dirty_work_products, &mut extra_edges);
         }
     }
@@ -187,7 +206,7 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // Recreate bootstrap outputs, which are outputs that have no incoming edges (and hence cannot
     // be dirty).
     for bootstrap_output in &serialized_dep_graph.bootstrap_outputs {
-        if let Some(n) = retraced.map(bootstrap_output) {
+        if let Some(n) = retrace(tcx, bootstrap_output) {
             if let DepNode::WorkProduct(ref wp) = n {
                 clean_work_products.insert(wp.clone());
             }
@@ -214,7 +233,7 @@ fn create_node((): (), (): ()) {
     // the edge from `Hir(X)` to `Bar` (or, if `Bar` itself cannot be
     // recreated, to the targets of `Bar`).
     while let Some((source, target)) = extra_edges.pop() {
-        process_edges(tcx, source, target, &edge_map, &directory, &retraced, &dirty_raw_nodes,
+        process_edges(tcx, source, target, &edge_map, &dirty_raw_nodes,
                       &mut clean_work_products, &mut dirty_work_products, &mut extra_edges);
     }
 
@@ -222,10 +241,9 @@ fn create_node((): (), (): ()) {
     // dirty.
     reconcile_work_products(tcx, work_products, &clean_work_products);
 
-    dirty_clean::check_dirty_clean_annotations(tcx, &dirty_raw_nodes, &retraced);
+    dirty_clean::check_dirty_clean_annotations(tcx, &dirty_raw_nodes);
 
     load_prev_metadata_hashes(tcx,
-                              &retraced,
                               &mut *incremental_hashes_map.prev_metadata_hashes.borrow_mut());
     Ok(())
 }
@@ -234,8 +252,7 @@ fn create_node((): (), (): ()) {
 /// a bit vector where the index is the DefPathIndex.
 fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  incremental_hashes_map: &IncrementalHashesMap,
-                                 serialized_hashes: &[SerializedHash],
-                                 retraced: &RetracedDefIdDirectory)
+                                 serialized_hashes: &[SerializedHash])
                                  -> DirtyNodes {
     let mut hcx = HashContext::new(tcx, incremental_hashes_map);
     let mut dirty_nodes = FxHashMap();
@@ -249,7 +266,7 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     };
 
     for hash in serialized_hashes {
-        if let Some(dep_node) = retraced.map(&hash.dep_node) {
+        if let Some(dep_node) = retrace(tcx, &hash.dep_node) {
             if let Some(current_hash) = hcx.hash(&dep_node) {
                 if current_hash == hash.hash {
                     debug!("initial_dirty_nodes: {:?} is clean (hash={:?})",
@@ -282,11 +299,11 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     dirty_nodes
 }
 
-fn transitive_dirty_nodes(edge_map: &FxHashMap<DepNode<DefPathIndex>, Vec<DepNode<DefPathIndex>>>,
+fn transitive_dirty_nodes(edge_map: &FxHashMap<DepNode<DefPathHash>, Vec<DepNode<DefPathHash>>>,
                           mut dirty_nodes: DirtyNodes)
                           -> DirtyNodes
 {
-    let mut stack: Vec<(DepNode<DefPathIndex>, DepNode<DefPathIndex>)> = vec![];
+    let mut stack: Vec<(DepNode<DefPathHash>, DepNode<DefPathHash>)> = vec![];
     stack.extend(dirty_nodes.iter().map(|(s, b)| (s.clone(), b.clone())));
     while let Some((source, blame)) = stack.pop() {
         // we know the source is dirty (because of the node `blame`)...
@@ -348,7 +365,6 @@ fn delete_dirty_work_product(tcx: TyCtxt,
 }
 
 fn load_prev_metadata_hashes(tcx: TyCtxt,
-                             retraced: &RetracedDefIdDirectory,
                              output: &mut FxHashMap<DefId, Fingerprint>) {
     if !tcx.sess.opts.debugging_opts.query_dep_graph {
         return
@@ -388,9 +404,11 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
     debug!("load_prev_metadata_hashes() - Mapping DefIds");
 
     assert_eq!(serialized_hashes.index_map.len(), serialized_hashes.entry_hashes.len());
+    let def_path_hash_to_def_id = tcx.def_path_hash_to_def_id.as_ref().unwrap();
+
     for serialized_hash in serialized_hashes.entry_hashes {
-        let def_path_index = serialized_hashes.index_map[&serialized_hash.def_index];
-        if let Some(def_id) = retraced.def_id(def_path_index) {
+        let def_path_hash = serialized_hashes.index_map[&serialized_hash.def_index];
+        if let Some(&def_id) = def_path_hash_to_def_id.get(&def_path_hash) {
             let old = output.insert(def_id, serialized_hash.hash);
             assert!(old.is_none(), "already have hash for {:?}", def_id);
         }
@@ -402,15 +420,13 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
 
 fn process_edges<'a, 'tcx, 'edges>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    source: &'edges DepNode<DefPathIndex>,
-    target: &'edges DepNode<DefPathIndex>,
-    edges: &'edges FxHashMap<DepNode<DefPathIndex>, Vec<DepNode<DefPathIndex>>>,
-    directory: &DefIdDirectory,
-    retraced: &RetracedDefIdDirectory,
+    source: &'edges DepNode<DefPathHash>,
+    target: &'edges DepNode<DefPathHash>,
+    edges: &'edges FxHashMap<DepNode<DefPathHash>, Vec<DepNode<DefPathHash>>>,
     dirty_raw_nodes: &DirtyNodes,
     clean_work_products: &mut FxHashSet<Arc<WorkProductId>>,
     dirty_work_products: &mut FxHashSet<Arc<WorkProductId>>,
-    extra_edges: &mut Vec<(&'edges DepNode<DefPathIndex>, &'edges DepNode<DefPathIndex>)>)
+    extra_edges: &mut Vec<(&'edges DepNode<DefPathHash>, &'edges DepNode<DefPathHash>)>)
 {
     // If the target is dirty, skip the edge. If this is an edge
     // that targets a work-product, we can print the blame
@@ -419,14 +435,21 @@ fn process_edges<'a, 'tcx, 'edges>(
         if let DepNode::WorkProduct(ref wp) = *target {
             if tcx.sess.opts.debugging_opts.incremental_info {
                 if dirty_work_products.insert(wp.clone()) {
-                    // It'd be nice to pretty-print these paths better than just
-                    // using the `Debug` impls, but wev.
+                    // Try to reconstruct the human-readable version of the
+                    // DepNode. This cannot be done for things that where
+                    // removed.
+                    let readable_blame = if let Some(dep_node) = retrace(tcx, blame) {
+                        dep_node.map_def(|&def_id| Some(tcx.def_path(def_id).to_string(tcx)))
+                                .unwrap()
+                    } else {
+                        blame.map_def(|def_path_hash| Some(format!("{:?}", def_path_hash)))
+                             .unwrap()
+                    };
+
                     println!("incremental: module {:?} is dirty because {:?} \
                               changed or was removed",
                              wp,
-                             blame.map_def(|&index| {
-                                 Some(directory.def_path_string(tcx, index))
-                             }).unwrap());
+                             readable_blame);
                 }
             }
         }
@@ -439,8 +462,8 @@ fn process_edges<'a, 'tcx, 'edges>(
     // Retrace the source -> target edges to def-ids and then create
     // an edge in the graph. Retracing may yield none if some of the
     // data happens to have been removed.
-    if let Some(source_node) = retraced.map(source) {
-        if let Some(target_node) = retraced.map(target) {
+    if let Some(source_node) = retrace(tcx, source) {
+        if let Some(target_node) = retrace(tcx, target) {
             let _task = tcx.dep_graph.in_task(target_node);
             tcx.dep_graph.read(source_node);
             if let DepNode::WorkProduct(ref wp) = *target {
index 3ae8fcdfb51a1bd41bf6ea7a5a5c51ace06bdfec..c03a0ab4ba2c181d0c19267b2f9b65948bc0d48c 100644 (file)
@@ -13,7 +13,6 @@
 //! various HIR nodes.
 
 mod data;
-mod directory;
 mod dirty_clean;
 mod fs;
 mod hash;
index 06e49e9d37c8464c82061bd4fb46198b5b8551ba..6d717d6f409d5706f4b3d90928d32e1061de95a1 100644 (file)
 use rustc::dep_graph::DepNode;
 use rustc::hir::def_id::DefId;
 use rustc::hir::svh::Svh;
+use rustc::hir::map::DefPathHash;
 use rustc::ich::Fingerprint;
 use rustc::middle::cstore::EncodedMetadataHashes;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::graph;
+use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_serialize::Encodable as RustcEncodable;
 use rustc_serialize::opaque::Encoder;
 use std::io::{self, Cursor, Write};
@@ -24,7 +27,6 @@
 
 use IncrementalHashesMap;
 use super::data::*;
-use super::directory::*;
 use super::hash::*;
 use super::preds::*;
 use super::fs::*;
@@ -43,7 +45,6 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         return;
     }
 
-    let mut builder = DefIdDirectoryBuilder::new(tcx);
     let query = tcx.dep_graph.query();
 
     if tcx.sess.opts.debugging_opts.incremental_info {
@@ -65,14 +66,13 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 |e| encode_metadata_hashes(tcx,
                                            svh,
                                            metadata_hashes,
-                                           &mut builder,
                                            &mut current_metadata_hashes,
                                            e));
     }
 
     save_in(sess,
             dep_graph_path(sess),
-            |e| encode_dep_graph(&preds, &mut builder, e));
+            |e| encode_dep_graph(tcx, &preds, e));
 
     let prev_metadata_hashes = incremental_hashes_map.prev_metadata_hashes.borrow();
     dirty_clean::check_dirty_clean_metadata(tcx,
@@ -167,73 +167,84 @@ fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
     }
 }
 
-pub fn encode_dep_graph(preds: &Predecessors,
-                        builder: &mut DefIdDirectoryBuilder,
+pub fn encode_dep_graph(tcx: TyCtxt,
+                        preds: &Predecessors,
                         encoder: &mut Encoder)
                         -> io::Result<()> {
     // First encode the commandline arguments hash
-    let tcx = builder.tcx();
     tcx.sess.opts.dep_tracking_hash().encode(encoder)?;
 
-    // Create a flat list of (Input, WorkProduct) edges for
-    // serialization.
-    let mut edges = FxHashMap();
-    for edge in preds.reduced_graph.all_edges() {
-        let source = *preds.reduced_graph.node_data(edge.source());
-        let target = *preds.reduced_graph.node_data(edge.target());
-        match *target {
-            DepNode::MetaData(ref def_id) => {
-                // Metadata *targets* are always local metadata nodes. We have
-                // already handled those in `encode_metadata_hashes`.
-                assert!(def_id.is_local());
-                continue;
-            }
-            _ => (),
-        }
-        debug!("serialize edge: {:?} -> {:?}", source, target);
-        let source = builder.map(source);
-        let target = builder.map(target);
-        edges.entry(source).or_insert(vec![]).push(target);
-    }
+    let to_hash_based_node = |dep_node: &DepNode<DefId>| {
+        dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id))).unwrap()
+    };
 
-    if tcx.sess.opts.debugging_opts.incremental_dump_hash {
-        for (dep_node, hash) in &preds.hashes {
-            println!("HIR hash for {:?} is {}", dep_node, hash);
+    // NB: We rely on this Vec being indexable by reduced_graph's NodeIndex.
+    let nodes: IndexVec<DepNodeIndex, DepNode<DefPathHash>> = preds
+        .reduced_graph
+        .all_nodes()
+        .iter()
+        .map(|node| to_hash_based_node(node.data))
+        .collect();
+
+    let mut edge_list_indices = Vec::with_capacity(nodes.len());
+    let mut edge_list_data = Vec::with_capacity(preds.reduced_graph.len_edges());
+
+    for node_index in 0 .. nodes.len() {
+        let start = edge_list_data.len() as u32;
+
+        for target in preds.reduced_graph.successor_nodes(graph::NodeIndex(node_index)) {
+            edge_list_data.push(DepNodeIndex::new(target.node_id()));
         }
+
+        let end = edge_list_data.len() as u32;
+        debug_assert_eq!(node_index, edge_list_indices.len());
+        edge_list_indices.push((start, end));
     }
 
-    // Create the serialized dep-graph.
-    let bootstrap_outputs = preds.bootstrap_outputs.iter()
-                                                   .map(|n| builder.map(n))
-                                                   .collect();
-    let edges = edges.into_iter()
-                     .map(|(k, v)| SerializedEdgeSet { source: k, targets: v })
-                     .collect();
+    // Let's make we had no overflow there.
+    assert!(edge_list_data.len() <= ::std::u32::MAX as usize);
+    // Check that we have a consistent number of edges.
+    assert_eq!(edge_list_data.len(), preds.reduced_graph.len_edges());
+
+    let bootstrap_outputs = preds
+        .bootstrap_outputs
+        .iter()
+        .map(|n| to_hash_based_node(n))
+        .collect();
+
+    let hashes = preds
+        .hashes
+        .iter()
+        .map(|(&dep_node, &hash)| {
+            SerializedHash {
+                dep_node: to_hash_based_node(dep_node),
+                hash: hash,
+            }
+        })
+        .collect();
+
     let graph = SerializedDepGraph {
+        nodes,
+        edge_list_indices,
+        edge_list_data,
         bootstrap_outputs,
-        edges,
-        hashes: preds.hashes
-            .iter()
-            .map(|(&dep_node, &hash)| {
-                SerializedHash {
-                    dep_node: builder.map(dep_node),
-                    hash: hash,
-                }
-            })
-            .collect(),
+        hashes,
     };
 
+    // Encode the graph data.
+    graph.encode(encoder)?;
+
     if tcx.sess.opts.debugging_opts.incremental_info {
-        println!("incremental: {} nodes in reduced dep-graph", preds.reduced_graph.len_nodes());
-        println!("incremental: {} edges in serialized dep-graph", graph.edges.len());
+        println!("incremental: {} nodes in reduced dep-graph", graph.nodes.len());
+        println!("incremental: {} edges in serialized dep-graph", graph.edge_list_data.len());
         println!("incremental: {} hashes in serialized dep-graph", graph.hashes.len());
     }
 
-    debug!("graph = {:#?}", graph);
-
-    // Encode the directory and then the graph data.
-    builder.directory().encode(encoder)?;
-    graph.encode(encoder)?;
+    if tcx.sess.opts.debugging_opts.incremental_dump_hash {
+        for (dep_node, hash) in &preds.hashes {
+            println!("ICH for {:?} is {}", dep_node, hash);
+        }
+    }
 
     Ok(())
 }
@@ -241,7 +252,6 @@ pub fn encode_dep_graph(preds: &Predecessors,
 pub fn encode_metadata_hashes(tcx: TyCtxt,
                               svh: Svh,
                               metadata_hashes: &EncodedMetadataHashes,
-                              builder: &mut DefIdDirectoryBuilder,
                               current_metadata_hashes: &mut FxHashMap<DefId, Fingerprint>,
                               encoder: &mut Encoder)
                               -> io::Result<()> {
@@ -256,8 +266,8 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
             let def_id = DefId::local(serialized_hash.def_index);
 
             // Store entry in the index_map
-            let def_path_index = builder.add(def_id);
-            serialized_hashes.index_map.insert(def_id.index, def_path_index);
+            let def_path_hash = tcx.def_path_hash(def_id);
+            serialized_hashes.index_map.insert(def_id.index, def_path_hash);
 
             // Record hash in current_metadata_hashes
             current_metadata_hashes.insert(def_id, serialized_hash.hash);
index f1d014692a4b8d43e7cc5a4eb2046099eb66ebf0..3a4729e64548a732d74aa73f5be1d9c138ea598c 100644 (file)
@@ -488,7 +488,7 @@ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
         if def.has_dtor(cx.tcx) {
             return;
         }
-        let param_env = ty::ParamEnv::empty();
+        let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
         if !ty.moves_by_default(cx.tcx, param_env, item.span) {
             return;
         }
@@ -881,30 +881,37 @@ fn expr_refers_to_this_method(cx: &LateContext,
                                       -> bool {
             use rustc::ty::adjustment::*;
 
-            // Check for method calls and overloaded operators.
-            let opt_m = cx.tables.method_map.get(&ty::MethodCall::expr(id)).cloned();
-            if let Some(m) = opt_m {
-                if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) {
-                    return true;
-                }
-            }
+            // Ignore non-expressions.
+            let expr = if let hir_map::NodeExpr(e) = cx.tcx.hir.get(id) {
+                e
+            } else {
+                return false;
+            };
 
             // Check for overloaded autoderef method calls.
-            let opt_adj = cx.tables.adjustments.get(&id).cloned();
-            if let Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) = opt_adj {
-                for i in 0..autoderefs {
-                    let method_call = ty::MethodCall::autoderef(id, i as u32);
-                    if let Some(m) = cx.tables.method_map.get(&method_call).cloned() {
-                        if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) {
-                            return true;
-                        }
+            let mut source = cx.tables.expr_ty(expr);
+            for adjustment in cx.tables.expr_adjustments(expr) {
+                if let Adjust::Deref(Some(deref)) = adjustment.kind {
+                    let (def_id, substs) = deref.method_call(cx.tcx, source);
+                    if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) {
+                        return true;
                     }
                 }
+                source = adjustment.target;
+            }
+
+            // Check for method calls and overloaded operators.
+            if cx.tables.is_method_call(expr) {
+                let def_id = cx.tables.type_dependent_defs[&id].def_id();
+                let substs = cx.tables.node_substs(id);
+                if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) {
+                    return true;
+                }
             }
 
             // Check for calls to methods via explicit paths (e.g. `T::method()`).
-            match cx.tcx.hir.get(id) {
-                hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
+            match expr.node {
+                hir::ExprCall(ref callee, _) => {
                     let def = if let hir::ExprPath(ref qpath) = callee.node {
                         cx.tables.qpath_def(qpath, callee.id)
                     } else {
@@ -912,8 +919,7 @@ fn expr_refers_to_this_method(cx: &LateContext,
                     };
                     match def {
                         Def::Method(def_id) => {
-                            let substs = cx.tables.node_id_item_substs(callee.id)
-                                .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
+                            let substs = cx.tables.node_substs(callee.id);
                             method_call_refers_to_method(
                                 cx.tcx, method, def_id, substs, id)
                         }
@@ -945,12 +951,13 @@ fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs);
                     let trait_ref = ty::Binder(trait_ref);
                     let span = tcx.hir.span(expr_id);
+                    let param_env = tcx.param_env(method.def_id);
                     let obligation =
                         traits::Obligation::new(traits::ObligationCause::misc(span, expr_id),
+                                                param_env,
                                                 trait_ref.to_poly_trait_predicate());
 
-                    let param_env = tcx.param_env(method.def_id);
-                    tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
+                    tcx.infer_ctxt(()).enter(|infcx| {
                         let mut selcx = traits::SelectionContext::new(&infcx);
                         match selcx.select(&obligation) {
                             // The method comes from a `T: Trait` bound.
index c2181c9764c6cdfe97ab27138216502ef3fbb543..3019165bfbf9a9343b424a861e485d8b481f6ad7 100644 (file)
@@ -14,7 +14,6 @@
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, AdtKind, Ty, TyCtxt};
 use rustc::ty::layout::{Layout, Primitive};
-use rustc::traits::Reveal;
 use middle::const_val::ConstVal;
 use rustc_const_eval::ConstContext;
 use util::nodemap::FxHashSet;
@@ -724,12 +723,12 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
             if gens.ty_params.is_empty() {
                 // sizes only make sense for non-generic types
-                let t = cx.tcx.type_of(cx.tcx.hir.local_def_id(it.id));
-                let layout = cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
-                    let ty = cx.tcx.erase_regions(&t);
-                    ty.layout(&infcx).unwrap_or_else(|e| {
-                        bug!("failed to get layout for `{}`: {}", t, e)
-                    })
+                let item_def_id = cx.tcx.hir.local_def_id(it.id);
+                let t = cx.tcx.type_of(item_def_id);
+                let param_env = cx.tcx.param_env(item_def_id).reveal_all();
+                let ty = cx.tcx.erase_regions(&t);
+                let layout = ty.layout(cx.tcx, param_env).unwrap_or_else(|e| {
+                    bug!("failed to get layout for `{}`: {}", t, e)
                 });
 
                 if let Layout::General { ref variants, ref size, discr, .. } = *layout {
index 93ff609a280ae1d4b0d24431dcadef941b32b6a2..0c82679c307d3ad0c2cdd665689cd53cd90388a1 100644 (file)
@@ -468,21 +468,13 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
             _ => return,
         }
 
-        if let Some(adjustment) = cx.tables.adjustments.get(&e.id) {
-            if let adjustment::Adjust::DerefRef { autoref, .. } = adjustment.kind {
-                match autoref {
-                    Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => {
-                        cx.span_lint(UNUSED_ALLOCATION,
-                                     e.span,
-                                     "unnecessary allocation, use & instead");
-                    }
-                    Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => {
-                        cx.span_lint(UNUSED_ALLOCATION,
-                                     e.span,
-                                     "unnecessary allocation, use &mut instead");
-                    }
-                    _ => (),
-                }
+        for adj in cx.tables.expr_adjustments(e) {
+            if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
+                let msg = match m {
+                    hir::MutImmutable => "unnecessary allocation, use & instead",
+                    hir::MutMutable => "unnecessary allocation, use &mut instead"
+                };
+                cx.span_lint(UNUSED_ALLOCATION, e.span, msg);
             }
         }
     }
index f97daa22ff6624c26487dfe8b9a5e1d1a1c43fb0..f2eea014dd3020244ec026004bd96dc780ff69b1 100644 (file)
@@ -17,4 +17,4 @@ rustc_bitflags = { path = "../librustc_bitflags" }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
index ec6947b4a486c31ebcaa1444fc827d2115c72f04..51f152991fdaf54974792026ea147e32c382a6fa 100644 (file)
@@ -326,7 +326,7 @@ fn register_crate(&mut self,
         let mut cmeta = cstore::CrateMetadata {
             name: name,
             extern_crate: Cell::new(None),
-            def_path_table: def_path_table,
+            def_path_table: Rc::new(def_path_table),
             exported_symbols: exported_symbols,
             trait_impls: trait_impls,
             proc_macros: crate_root.macro_derive_registrar.map(|_| {
index 64fccb0314e97d67743a613a58406568dbcde43f..5066b927c11526214029b6f3667c5cedb3a67c53 100644 (file)
@@ -76,7 +76,7 @@ pub struct CrateMetadata {
     /// hashmap, which gives the reverse mapping.  This allows us to
     /// quickly retrace a `DefPath`, which is needed for incremental
     /// compilation support.
-    pub def_path_table: DefPathTable,
+    pub def_path_table: Rc<DefPathTable>,
 
     pub exported_symbols: Tracked<FxHashSet<DefIndex>>,
 
index b3503713c904ea3acff385cb4337ac0aba044357..dcc55846b53d8421f334dabb3afc039d76fccfb2 100644 (file)
@@ -17,7 +17,6 @@
                             ExternCrate, NativeLibrary, MetadataLoader, LinkMeta,
                             LinkagePreference, LoadedMacro, EncodedMetadata};
 use rustc::hir::def;
-use rustc::ich;
 use rustc::middle::lang_items;
 use rustc::session::Session;
 use rustc::ty::{self, TyCtxt};
@@ -25,7 +24,8 @@
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 
 use rustc::dep_graph::{DepNode, GlobalMetaDataKind};
-use rustc::hir::map::{DefKey, DefPath, DisambiguatedDefPathData};
+use rustc::hir::map::{DefKey, DefPath, DisambiguatedDefPathData, DefPathHash};
+use rustc::hir::map::definitions::DefPathTable;
 use rustc::util::nodemap::{NodeSet, DefIdMap};
 use rustc_back::PanicStrategy;
 
@@ -334,10 +334,14 @@ fn def_path(&self, def: DefId) -> DefPath {
         self.get_crate_data(def.krate).def_path(def.index)
     }
 
-    fn def_path_hash(&self, def: DefId) -> ich::Fingerprint {
+    fn def_path_hash(&self, def: DefId) -> DefPathHash {
         self.get_crate_data(def.krate).def_path_hash(def.index)
     }
 
+    fn def_path_table(&self, cnum: CrateNum) -> Rc<DefPathTable> {
+        self.get_crate_data(cnum).def_path_table.clone()
+    }
+
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>
     {
         self.dep_graph.read(DepNode::MetaData(def));
index 1db5821f31878e9ca1bf954e17ae9e69ff642a8f..91470f238ecb12ec00656681a53a7f3878fc22ce 100644 (file)
@@ -14,9 +14,8 @@
 use schema::*;
 
 use rustc::dep_graph::{DepGraph, DepNode, GlobalMetaDataKind};
-use rustc::hir::map::{DefKey, DefPath, DefPathData};
+use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc::hir;
-use rustc::ich;
 
 use rustc::middle::cstore::LinkagePreference;
 use rustc::hir::def::{self, Def, CtorKind};
@@ -1109,7 +1108,7 @@ pub fn def_path(&self, id: DefIndex) -> DefPath {
     }
 
     #[inline]
-    pub fn def_path_hash(&self, index: DefIndex) -> ich::Fingerprint {
+    pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
         self.def_path_table.def_path_hash(index)
     }
 
index 7caf8a778d409d6b0a9a0417ade5c7d5d14d0f29..6d15f0a2e5d7f28b366f9f845b45829e29575de3 100644 (file)
@@ -26,7 +26,7 @@ pub fn as_constant<M>(&mut self, expr: M) -> Constant<'tcx>
 
     fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> {
         let this = self;
-        let Expr { ty, temp_lifetime: _, temp_lifetime_was_shrunk: _, span, kind }
+        let Expr { ty, temp_lifetime: _, span, kind }
             = expr;
         match kind {
             ExprKind::Scope { extent: _, value } =>
index ab27a1a9c24bc2a92c5bfea8e22d56348cd37b77..17d74571ce4828128ef1d4798fda7b8439543198 100644 (file)
@@ -50,13 +50,6 @@ fn expr_as_temp(&mut self,
         let temp = this.temp(expr_ty.clone(), expr_span);
         let source_info = this.source_info(expr_span);
 
-        if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) {
-            this.hir.tcx().sess.span_warn(
-                expr_span,
-                "this temporary used to live longer - see issue #39283 \
-(https://github.com/rust-lang/rust/issues/39283)");
-        }
-
         if !expr_ty.is_never() && temp_lifetime.is_some() {
             this.cfg.push(block, Statement {
                 source_info: source_info,
index 5982d3bdc81a49191e8e1771261ac7df5d9912c0..d456bc3ded3907b03224c66c0436c848f2df1eff 100644 (file)
@@ -201,13 +201,8 @@ pub fn into_expr(&mut self,
                 exit_block.unit()
             }
             ExprKind::Call { ty, fun, args } => {
-                let diverges = match ty.sty {
-                    ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
-                        // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                        f.output().skip_binder().is_never()
-                    }
-                    _ => false
-                };
+                // FIXME(canndrew): This is_never should probably be an is_uninhabited
+                let diverges = expr.ty.is_never();
                 let intrinsic = match ty.sty {
                     ty::TyFnDef(def_id, _, ref f) if
                         f.abi() == Abi::RustIntrinsic ||
index 407b08d2831497b3456a2fdf0a7f9795c2f9d348..08a5cb37e5788a4b545fac5048e77444c0349e7c 100644 (file)
@@ -18,7 +18,6 @@
 use rustc::mir::*;
 use rustc::mir::transform::MirSource;
 use rustc::mir::visit::MutVisitor;
-use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
 use rustc::util::nodemap::NodeMap;
@@ -84,7 +83,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
     };
 
     let src = MirSource::from_node(tcx, id);
-    tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
+    tcx.infer_ctxt(body_id).enter(|infcx| {
         let cx = Cx::new(&infcx, src);
         let mut mir = if cx.tables().tainted_by_errors {
             build::construct_error(cx, body_id)
@@ -172,8 +171,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let span = tcx.hir.span(ctor_id);
     if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
-        let pe = tcx.param_env(tcx.hir.local_def_id(ctor_id));
-        tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
+        tcx.infer_ctxt(()).enter(|infcx| {
             let (mut mir, src) =
                 shim::build_adt_ctor(&infcx, ctor_id, fields, span);
 
index 920da30611633d64d66bd5ef18f3003f18d04adf..47c50b78f3acca6f531340bc6814ae6a6562b797 100644 (file)
@@ -82,11 +82,10 @@ pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                    block: &'tcx hir::Block)
                                    -> ExprRef<'tcx> {
     let block_ty = cx.tables().node_id_to_type(block.id);
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(block.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(block.id);
     let expr = Expr {
         ty: block_ty,
         temp_lifetime: temp_lifetime,
-        temp_lifetime_was_shrunk: was_shrunk,
         span: block.span,
         kind: ExprKind::Block { body: block },
     };
index b180d982e86b669c9be4c517efa98d2a7503e454..8cfeecdafb51a39349a829975ba8baf8089ef5f2 100644 (file)
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::ty::cast::CastKind as TyCastKind;
+use rustc::ty::subst::Subst;
 use rustc::hir;
-use syntax::ptr::P;
 
 impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
     type Output = Expr<'tcx>;
 
     fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
-        let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(self.id);
+        let temp_lifetime = cx.region_maps.temporary_scope(self.id);
         let expr_extent = CodeExtent::Misc(self.id);
 
         debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
 
         let mut expr = make_mirror_unadjusted(cx, self);
-        let adj = cx.tables().adjustments.get(&self.id).cloned();
-
-        debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
-               expr,
-               adj);
 
         // Now apply adjustments, if any.
-        match adj.map(|adj| (adj.kind, adj.target)) {
-            None => {}
-            Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => {
-                expr = Expr {
-                    temp_lifetime: temp_lifetime,
-                    temp_lifetime_was_shrunk: was_shrunk,
-                    ty: adjusted_ty,
-                    span: self.span,
-                    kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
-                };
-            }
-            Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => {
-                expr = Expr {
-                    temp_lifetime: temp_lifetime,
-                    temp_lifetime_was_shrunk: was_shrunk,
-                    ty: adjusted_ty,
-                    span: self.span,
-                    kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
-                };
-            }
-            Some((ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => {
-                expr = Expr {
-                    temp_lifetime: temp_lifetime,
-                    temp_lifetime_was_shrunk: was_shrunk,
-                    ty: adjusted_ty,
-                    span: self.span,
-                    kind: ExprKind::ClosureFnPointer { source: expr.to_ref() },
-                };
-            }
-            Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
-                expr = Expr {
-                    temp_lifetime: temp_lifetime,
-                    temp_lifetime_was_shrunk: was_shrunk,
-                    ty: adjusted_ty,
-                    span: self.span,
-                    kind: ExprKind::NeverToAny { source: expr.to_ref() },
-                };
-            }
-            Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => {
-                expr = Expr {
-                    temp_lifetime: temp_lifetime,
-                    temp_lifetime_was_shrunk: was_shrunk,
-                    ty: adjusted_ty,
-                    span: self.span,
-                    kind: ExprKind::Cast { source: expr.to_ref() },
-                };
-            }
-            Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize },
-                  adjusted_ty)) => {
-                for i in 0..autoderefs {
-                    let i = i as u32;
-                    let adjusted_ty =
-                        expr.ty.adjust_for_autoderef(cx.tcx, self.id, self.span, i, |mc| {
-                            cx.tables().method_map.get(&mc).map(|m| m.ty)
-                        });
-                    debug!("make_mirror: autoderef #{}, adjusted_ty={:?}",
-                           i,
-                           adjusted_ty);
-                    let method_key = ty::MethodCall::autoderef(self.id, i);
-                    let meth_ty = cx.tables().method_map.get(&method_key).map(|m| m.ty);
-                    let kind = if let Some(meth_ty) = meth_ty {
-                        debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
-
-                        let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
-                        let (region, mutbl) = match ref_ty {
-                            Some(&ty::TyS { sty: ty::TyRef(region, mt), .. }) => (region, mt.mutbl),
-                            _ => span_bug!(expr.span, "autoderef returned bad type"),
-                        };
-
-                        expr = Expr {
-                            temp_lifetime: temp_lifetime,
-                            temp_lifetime_was_shrunk: was_shrunk,
-                            ty: cx.tcx.mk_ref(region,
-                                              ty::TypeAndMut {
-                                                  ty: expr.ty,
-                                                  mutbl: mutbl,
-                                              }),
-                            span: expr.span,
-                            kind: ExprKind::Borrow {
-                                region: region,
-                                borrow_kind: to_borrow_kind(mutbl),
-                                arg: expr.to_ref(),
-                            },
-                        };
-
-                        overloaded_lvalue(cx,
-                                          self,
-                                          method_key,
-                                          PassArgs::ByRef,
-                                          expr.to_ref(),
-                                          vec![])
-                    } else {
-                        debug!("make_mirror: built-in autoderef");
-                        ExprKind::Deref { arg: expr.to_ref() }
-                    };
-                    expr = Expr {
-                        temp_lifetime: temp_lifetime,
-                        temp_lifetime_was_shrunk: was_shrunk,
-                        ty: adjusted_ty,
-                        span: self.span,
-                        kind: kind,
-                    };
-                }
-
-                if let Some(autoref) = autoref {
-                    let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
-                    match autoref {
-                        ty::adjustment::AutoBorrow::Ref(r, m) => {
-                            expr = Expr {
-                                temp_lifetime: temp_lifetime,
-                                temp_lifetime_was_shrunk: was_shrunk,
-                                ty: adjusted_ty,
-                                span: self.span,
-                                kind: ExprKind::Borrow {
-                                    region: r,
-                                    borrow_kind: to_borrow_kind(m),
-                                    arg: expr.to_ref(),
-                                },
-                            };
-                        }
-                        ty::adjustment::AutoBorrow::RawPtr(m) => {
-                            // Convert this to a suitable `&foo` and
-                            // then an unsafe coercion. Limit the region to be just this
-                            // expression.
-                            let region = ty::ReScope(expr_extent);
-                            let region = cx.tcx.mk_region(region);
-                            expr = Expr {
-                                temp_lifetime: temp_lifetime,
-                                temp_lifetime_was_shrunk: was_shrunk,
-                                ty: cx.tcx.mk_ref(region,
-                                                  ty::TypeAndMut {
-                                                      ty: expr.ty,
-                                                      mutbl: m,
-                                                  }),
-                                span: self.span,
-                                kind: ExprKind::Borrow {
-                                    region: region,
-                                    borrow_kind: to_borrow_kind(m),
-                                    arg: expr.to_ref(),
-                                },
-                            };
-                            expr = Expr {
-                                temp_lifetime: temp_lifetime,
-                                temp_lifetime_was_shrunk: was_shrunk,
-                                ty: adjusted_ty,
-                                span: self.span,
-                                kind: ExprKind::Cast { source: expr.to_ref() },
-                            };
-                        }
-                    }
-                }
-
-                if unsize {
-                    expr = Expr {
-                        temp_lifetime: temp_lifetime,
-                        temp_lifetime_was_shrunk: was_shrunk,
-                        ty: adjusted_ty,
-                        span: self.span,
-                        kind: ExprKind::Unsize { source: expr.to_ref() },
-                    };
-                }
-            }
+        for adjustment in cx.tables().expr_adjustments(self) {
+            debug!("make_mirror: expr={:?} applying adjustment={:?}",
+                   expr,
+                   adjustment);
+            expr = apply_adjustment(cx, self, expr, adjustment);
         }
 
         // Next, wrap this up in the expr's scope.
         expr = Expr {
             temp_lifetime: temp_lifetime,
-            temp_lifetime_was_shrunk: was_shrunk,
             ty: expr.ty,
             span: self.span,
             kind: ExprKind::Scope {
@@ -218,7 +56,6 @@ fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
         if let Some(extent) = cx.region_maps.opt_destruction_extent(self.id) {
             expr = Expr {
                 temp_lifetime: temp_lifetime,
-                temp_lifetime_was_shrunk: was_shrunk,
                 ty: expr.ty,
                 span: self.span,
                 kind: ExprKind::Scope {
@@ -233,17 +70,104 @@ fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
     }
 }
 
+fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                                    hir_expr: &'tcx hir::Expr,
+                                    mut expr: Expr<'tcx>,
+                                    adjustment: &Adjustment<'tcx>)
+                                    -> Expr<'tcx> {
+    let Expr { temp_lifetime, span, .. } = expr;
+    let kind = match adjustment.kind {
+        Adjust::ReifyFnPointer => {
+            ExprKind::ReifyFnPointer { source: expr.to_ref() }
+        }
+        Adjust::UnsafeFnPointer => {
+            ExprKind::UnsafeFnPointer { source: expr.to_ref() }
+        }
+        Adjust::ClosureFnPointer => {
+            ExprKind::ClosureFnPointer { source: expr.to_ref() }
+        }
+        Adjust::NeverToAny => {
+            ExprKind::NeverToAny { source: expr.to_ref() }
+        }
+        Adjust::MutToConstPointer => {
+            ExprKind::Cast { source: expr.to_ref() }
+        }
+        Adjust::Deref(None) => {
+            ExprKind::Deref { arg: expr.to_ref() }
+        }
+        Adjust::Deref(Some(deref)) => {
+            let call = deref.method_call(cx.tcx, expr.ty);
+
+            expr = Expr {
+                temp_lifetime,
+                ty: cx.tcx.mk_ref(deref.region,
+                                  ty::TypeAndMut {
+                                    ty: expr.ty,
+                                    mutbl: deref.mutbl,
+                                  }),
+                span,
+                kind: ExprKind::Borrow {
+                    region: deref.region,
+                    borrow_kind: to_borrow_kind(deref.mutbl),
+                    arg: expr.to_ref(),
+                },
+            };
+
+            overloaded_lvalue(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()])
+        }
+        Adjust::Borrow(AutoBorrow::Ref(r, m)) => {
+            ExprKind::Borrow {
+                region: r,
+                borrow_kind: to_borrow_kind(m),
+                arg: expr.to_ref(),
+            }
+        }
+        Adjust::Borrow(AutoBorrow::RawPtr(m)) => {
+            // Convert this to a suitable `&foo` and
+            // then an unsafe coercion. Limit the region to be just this
+            // expression.
+            let region = ty::ReScope(CodeExtent::Misc(hir_expr.id));
+            let region = cx.tcx.mk_region(region);
+            expr = Expr {
+                temp_lifetime,
+                ty: cx.tcx.mk_ref(region,
+                                  ty::TypeAndMut {
+                                    ty: expr.ty,
+                                    mutbl: m,
+                                  }),
+                span,
+                kind: ExprKind::Borrow {
+                    region: region,
+                    borrow_kind: to_borrow_kind(m),
+                    arg: expr.to_ref(),
+                },
+            };
+            ExprKind::Cast { source: expr.to_ref() }
+        }
+        Adjust::Unsize => {
+            ExprKind::Unsize { source: expr.to_ref() }
+        }
+    };
+
+    Expr {
+        temp_lifetime,
+        ty: adjustment.target,
+        span,
+        kind,
+    }
+}
+
 fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                           expr: &'tcx hir::Expr)
                                           -> Expr<'tcx> {
     let expr_ty = cx.tables().expr_ty(expr);
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(expr.id);
 
     let kind = match expr.node {
         // Here comes the interesting stuff:
         hir::ExprMethodCall(.., ref args) => {
             // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
-            let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
+            let expr = method_callee(cx, expr, None);
             let args = args.iter()
                 .map(|e| e.to_ref())
                 .collect();
@@ -255,7 +179,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprCall(ref fun, ref args) => {
-            if cx.tables().is_method_call(expr.id) {
+            if cx.tables().is_method_call(expr) {
                 // The callee is something implementing Fn, FnMut, or FnOnce.
                 // Find the actual method implementation being called and
                 // build the appropriate UFCS call expression with the
@@ -263,20 +187,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
                 // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
 
-                let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
-
-                let sig = method.ty.fn_sig();
-
-                let sig = cx.tcx
-                    .no_late_bound_regions(&sig)
-                    .unwrap_or_else(|| span_bug!(expr.span, "method call has late-bound regions"));
-
-                assert_eq!(sig.inputs().len(), 2);
+                let method = method_callee(cx, expr, None);
 
+                let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e));
                 let tupled_args = Expr {
-                    ty: sig.inputs()[1],
+                    ty: cx.tcx.mk_tup(arg_tys, false),
                     temp_lifetime: temp_lifetime,
-                    temp_lifetime_was_shrunk: was_shrunk,
                     span: expr.span,
                     kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() },
                 };
@@ -302,8 +218,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     None
                 };
                 if let Some((adt_def, index)) = adt_data {
-                    let substs = cx.tables().node_id_item_substs(fun.id)
-                        .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
+                    let substs = cx.tables().node_substs(fun.id);
                     let field_refs = args.iter()
                         .enumerate()
                         .map(|(idx, e)| {
@@ -352,18 +267,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            if cx.tables().is_method_call(expr.id) {
-                let pass_args = if op.node.is_by_value() {
-                    PassArgs::ByValue
-                } else {
-                    PassArgs::ByRef
-                };
-                overloaded_operator(cx,
-                                    expr,
-                                    ty::MethodCall::expr(expr.id),
-                                    pass_args,
-                                    lhs.to_ref(),
-                                    vec![rhs])
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
             } else {
                 ExprKind::AssignOp {
                     op: bin_op(op.node),
@@ -376,18 +281,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) },
 
         hir::ExprBinary(op, ref lhs, ref rhs) => {
-            if cx.tables().is_method_call(expr.id) {
-                let pass_args = if op.node.is_by_value() {
-                    PassArgs::ByValue
-                } else {
-                    PassArgs::ByRef
-                };
-                overloaded_operator(cx,
-                                    expr,
-                                    ty::MethodCall::expr(expr.id),
-                                    pass_args,
-                                    lhs.to_ref(),
-                                    vec![rhs])
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
             } else {
                 // FIXME overflow
                 match (op.node, cx.constness) {
@@ -436,13 +331,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprIndex(ref lhs, ref index) => {
-            if cx.tables().is_method_call(expr.id) {
-                overloaded_lvalue(cx,
-                                  expr,
-                                  ty::MethodCall::expr(expr.id),
-                                  PassArgs::ByValue,
-                                  lhs.to_ref(),
-                                  vec![index])
+            if cx.tables().is_method_call(expr) {
+                overloaded_lvalue(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()])
             } else {
                 ExprKind::Index {
                     lhs: lhs.to_ref(),
@@ -452,26 +342,16 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
-            if cx.tables().is_method_call(expr.id) {
-                overloaded_lvalue(cx,
-                                  expr,
-                                  ty::MethodCall::expr(expr.id),
-                                  PassArgs::ByValue,
-                                  arg.to_ref(),
-                                  vec![])
+            if cx.tables().is_method_call(expr) {
+                overloaded_lvalue(cx, expr, expr_ty, None, vec![arg.to_ref()])
             } else {
                 ExprKind::Deref { arg: arg.to_ref() }
             }
         }
 
         hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
-            if cx.tables().is_method_call(expr.id) {
-                overloaded_operator(cx,
-                                    expr,
-                                    ty::MethodCall::expr(expr.id),
-                                    PassArgs::ByValue,
-                                    arg.to_ref(),
-                                    vec![])
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![arg.to_ref()])
             } else {
                 ExprKind::Unary {
                     op: UnOp::Not,
@@ -481,13 +361,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
-            if cx.tables().is_method_call(expr.id) {
-                overloaded_operator(cx,
-                                    expr,
-                                    ty::MethodCall::expr(expr.id),
-                                    PassArgs::ByValue,
-                                    arg.to_ref(),
-                                    vec![])
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![arg.to_ref()])
             } else {
                 // FIXME runtime-overflow
                 if let hir::ExprLit(_) = arg.node {
@@ -694,7 +569,6 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
     Expr {
         temp_lifetime: temp_lifetime,
-        temp_lifetime_was_shrunk: was_shrunk,
         ty: expr_ty,
         span: expr.span,
         kind: kind,
@@ -703,18 +577,20 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
 fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                  expr: &hir::Expr,
-                                 method_call: ty::MethodCall)
+                                 custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>)
                                  -> Expr<'tcx> {
-    let callee = cx.tables().method_map[&method_call];
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(expr.id);
+    let (def_id, substs) = custom_callee.unwrap_or_else(|| {
+        (cx.tables().type_dependent_defs[&expr.id].def_id(),
+         cx.tables().node_substs(expr.id))
+    });
     Expr {
         temp_lifetime: temp_lifetime,
-        temp_lifetime_was_shrunk: was_shrunk,
-        ty: callee.ty,
+        ty: cx.tcx.type_of(def_id).subst(cx.tcx, substs),
         span: expr.span,
         kind: ExprKind::Literal {
             literal: Literal::Value {
-                value: ConstVal::Function(callee.def_id, callee.substs),
+                value: ConstVal::Function(def_id, substs),
             },
         },
     }
@@ -739,8 +615,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                      expr: &'tcx hir::Expr,
                                      def: Def)
                                      -> ExprKind<'tcx> {
-    let substs = cx.tables().node_id_item_substs(expr.id)
-        .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
+    let substs = cx.tables().node_substs(expr.id);
     match def {
         // A regular function, constructor function or a constant.
         Def::Fn(def_id) |
@@ -790,7 +665,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                expr: &'tcx hir::Expr,
                                def: Def)
                                -> ExprKind<'tcx> {
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(expr.id);
 
     match def {
         Def::Local(def_id) => {
@@ -829,13 +704,11 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     Expr {
                         ty: closure_ty,
                         temp_lifetime: temp_lifetime,
-                        temp_lifetime_was_shrunk: was_shrunk,
                         span: expr.span,
                         kind: ExprKind::Deref {
                             arg: Expr {
                                 ty: ref_closure_ty,
                                 temp_lifetime: temp_lifetime,
-                                temp_lifetime_was_shrunk: was_shrunk,
                                 span: expr.span,
                                 kind: ExprKind::SelfRef,
                             }
@@ -852,13 +725,11 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     Expr {
                         ty: closure_ty,
                         temp_lifetime: temp_lifetime,
-                        temp_lifetime_was_shrunk: was_shrunk,
                         span: expr.span,
                         kind: ExprKind::Deref {
                             arg: Expr {
                                 ty: ref_closure_ty,
                                 temp_lifetime: temp_lifetime,
-                                temp_lifetime_was_shrunk: was_shrunk,
                                 span: expr.span,
                                 kind: ExprKind::SelfRef,
                             }.to_ref(),
@@ -869,7 +740,6 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     Expr {
                         ty: closure_ty,
                         temp_lifetime: temp_lifetime,
-                        temp_lifetime_was_shrunk: was_shrunk,
                         span: expr.span,
                         kind: ExprKind::SelfRef,
                     }
@@ -900,7 +770,6 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     ExprKind::Deref {
                         arg: Expr {
                             temp_lifetime: temp_lifetime,
-                            temp_lifetime_was_shrunk: was_shrunk,
                             ty: cx.tcx.mk_ref(borrow.region,
                                               ty::TypeAndMut {
                                                   ty: var_ty,
@@ -941,90 +810,58 @@ fn bin_op(op: hir::BinOp_) -> BinOp {
     }
 }
 
-enum PassArgs {
-    ByValue,
-    ByRef,
-}
-
 fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                        expr: &'tcx hir::Expr,
-                                       method_call: ty::MethodCall,
-                                       pass_args: PassArgs,
-                                       receiver: ExprRef<'tcx>,
-                                       args: Vec<&'tcx P<hir::Expr>>)
+                                       args: Vec<ExprRef<'tcx>>)
                                        -> ExprKind<'tcx> {
-    // the receiver has all the adjustments that are needed, so we can
-    // just push a reference to it
-    let mut argrefs = vec![receiver];
-
-    // the arguments, unfortunately, do not, so if this is a ByRef
-    // operator, we have to gin up the autorefs (but by value is easy)
-    match pass_args {
-        PassArgs::ByValue => argrefs.extend(args.iter().map(|arg| arg.to_ref())),
-
-        PassArgs::ByRef => {
-            let region = cx.tcx.node_scope_region(expr.id);
-            let (temp_lifetime, was_shrunk) =
-                cx.region_maps.temporary_scope2(expr.id);
-            argrefs.extend(args.iter()
-                .map(|arg| {
-                    let arg_ty = cx.tables().expr_ty_adjusted(arg);
-                    let adjusted_ty = cx.tcx.mk_ref(region,
-                                                    ty::TypeAndMut {
-                                                        ty: arg_ty,
-                                                        mutbl: hir::MutImmutable,
-                                                    });
-                    Expr {
-                        temp_lifetime: temp_lifetime,
-                        temp_lifetime_was_shrunk: was_shrunk,
-                        ty: adjusted_ty,
-                        span: expr.span,
-                        kind: ExprKind::Borrow {
-                            region: region,
-                            borrow_kind: BorrowKind::Shared,
-                            arg: arg.to_ref(),
-                        },
-                    }
-                    .to_ref()
-                }))
-        }
-    }
-
-    // now create the call itself
-    let fun = method_callee(cx, expr, method_call);
+    let fun = method_callee(cx, expr, None);
     ExprKind::Call {
         ty: fun.ty,
         fun: fun.to_ref(),
-        args: argrefs,
+        args,
     }
 }
 
 fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                      expr: &'tcx hir::Expr,
-                                     method_call: ty::MethodCall,
-                                     pass_args: PassArgs,
-                                     receiver: ExprRef<'tcx>,
-                                     args: Vec<&'tcx P<hir::Expr>>)
+                                     lvalue_ty: Ty<'tcx>,
+                                     custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
+                                     args: Vec<ExprRef<'tcx>>)
                                      -> ExprKind<'tcx> {
     // For an overloaded *x or x[y] expression of type T, the method
     // call returns an &T and we must add the deref so that the types
     // line up (this is because `*x` and `x[y]` represent lvalues):
 
-    // to find the type &T of the content returned by the method;
-    let ref_ty = cx.tables().method_map[&method_call].ty.fn_ret();
-    let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap();
-    // callees always have all late-bound regions fully instantiated,
+    let recv_ty = match args[0] {
+        ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e),
+        ExprRef::Mirror(ref e) => e.ty
+    };
+
+    // Reconstruct the output assuming it's a reference with the
+    // same region and mutability as the receiver. This holds for
+    // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
+    let (region, mt) = match recv_ty.sty {
+        ty::TyRef(region, mt) => (region, mt),
+        _ => span_bug!(expr.span, "overloaded_lvalue: receiver is not a reference"),
+    };
+    let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut {
+        ty: lvalue_ty,
+        mutbl: mt.mutbl,
+    });
 
     // construct the complete expression `foo()` for the overloaded call,
     // which will yield the &T type
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
-    let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args);
+    let temp_lifetime = cx.region_maps.temporary_scope(expr.id);
+    let fun = method_callee(cx, expr, custom_callee);
     let ref_expr = Expr {
         temp_lifetime: temp_lifetime,
-        temp_lifetime_was_shrunk: was_shrunk,
         ty: ref_ty,
         span: expr.span,
-        kind: ref_kind,
+        kind: ExprKind::Call {
+            ty: fun.ty,
+            fun: fun.to_ref(),
+            args,
+        },
     };
 
     // construct and return a deref wrapper `*foo()`
@@ -1042,11 +879,10 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         closure_expr_id: closure_expr.id,
     };
     let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap();
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(closure_expr.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.id);
     let var_ty = cx.tables().node_id_to_type(id_var);
     let captured_var = Expr {
         temp_lifetime: temp_lifetime,
-        temp_lifetime_was_shrunk: was_shrunk,
         ty: var_ty,
         span: closure_expr.span,
         kind: convert_var(cx, closure_expr, freevar.def),
@@ -1061,7 +897,6 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             };
             Expr {
                 temp_lifetime: temp_lifetime,
-                temp_lifetime_was_shrunk: was_shrunk,
                 ty: freevar_ty,
                 span: closure_expr.span,
                 kind: ExprKind::Borrow {
index 581a403fb6dee848861860711fca541722b9fa5b..5b7b52a72b0ab4c625c19b24d863def31b7c2b73 100644 (file)
@@ -35,6 +35,7 @@
 pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    pub param_env: ty::ParamEnv<'tcx>,
     pub region_maps: Rc<RegionMaps>,
 
     /// This is `Constness::Const` if we are compiling a `static`,
@@ -64,6 +65,7 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, src: MirSource) -> Cx<'a, 'gcx,
         let src_id = src.item_id();
         let src_def_id = tcx.hir.local_def_id(src_id);
 
+        let param_env = tcx.param_env(src_def_id);
         let region_maps = tcx.region_maps(src_def_id);
 
         let attrs = tcx.hir.attrs(src_id);
@@ -80,7 +82,7 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, src: MirSource) -> Cx<'a, 'gcx,
         // Constants and const fn's always need overflow checks.
         check_overflow |= constness == hir::Constness::Const;
 
-        Cx { tcx, infcx, region_maps, constness, src, check_overflow }
+        Cx { tcx, infcx, param_env, region_maps, constness, src, check_overflow }
     }
 }
 
@@ -169,12 +171,12 @@ pub fn all_fields(&mut self, adt_def: &ty::AdtDef, variant_index: usize) -> Vec<
     }
 
     pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
-        let ty = self.tcx.lift_to_global(&ty).unwrap_or_else(|| {
-            bug!("MIR: Cx::needs_drop({}) got \
+        let (ty, param_env) = self.tcx.lift_to_global(&(ty, self.param_env)).unwrap_or_else(|| {
+            bug!("MIR: Cx::needs_drop({:?}, {:?}) got \
                   type with inference types/regions",
-                 ty);
+                 ty, self.param_env);
         });
-        ty.needs_drop(self.tcx.global_tcx(), self.infcx.param_env)
+        ty.needs_drop(self.tcx.global_tcx(), param_env)
     }
 
     pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
index 1af9d722599e6e7663e035aa47659a31969d8415..044096699b1a4226a8755cc452c873fa8f9bdb07 100644 (file)
@@ -99,9 +99,6 @@ pub struct Expr<'tcx> {
     /// temporary; should be None only if in a constant context
     pub temp_lifetime: Option<CodeExtent>,
 
-    /// whether this temp lifetime was shrunk by #36082.
-    pub temp_lifetime_was_shrunk: bool,
-
     /// span of the expression in the source
     pub span: Span,
 
index edb2f44d18e35423afe37ec1bebed8a9bca2f5d8..0ac35a5fdd4722bd625317bfba4afe3e03643731 100644 (file)
@@ -18,7 +18,6 @@
 use rustc::mir::*;
 use rustc::mir::transform::{MirPass, MirSource};
 use rustc::mir::visit::*;
-use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::{Subst,Substs};
 
@@ -545,12 +544,11 @@ fn make_call_args(&self, args: Vec<Operand<'tcx>>,
     }
 }
 
-fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>,
+fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          param_env: ty::ParamEnv<'tcx>,
                           ty: Ty<'tcx>) -> Option<u64> {
-    tcx.infer_ctxt(param_env, traits::Reveal::All).enter(|infcx| {
-        ty.layout(&infcx).ok().map(|layout| {
-            layout.size(&tcx.data_layout).bytes()
-        })
+    ty.layout(tcx, param_env).ok().map(|layout| {
+        layout.size(&tcx.data_layout).bytes()
     })
 }
 
index 3b1c54f68e49b878889ba43261671bbb115d0641..ef88e813a50c60bf54691ab28010fe720bbb7f20 100644 (file)
@@ -998,10 +998,13 @@ fn run_pass<'a, 'tcx>(&self,
         // Statics must be Sync.
         if mode == Mode::Static {
             let ty = mir.return_ty;
-            tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+            tcx.infer_ctxt(()).enter(|infcx| {
+                let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
                 let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
                 let mut fulfillment_cx = traits::FulfillmentContext::new();
-                fulfillment_cx.register_bound(&infcx, ty,
+                fulfillment_cx.register_bound(&infcx,
+                                              param_env,
+                                              ty,
                                               tcx.require_lang_item(lang_items::SyncTraitLangItem),
                                               cause);
                 if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
index 8258627748f3008df8b7f567fce5345c6604a966..da8e3b5a42ba9e5dac82cb9e4ae59ac16be42e7b 100644 (file)
@@ -12,7 +12,7 @@
 #![allow(unreachable_code)]
 
 use rustc::infer::{self, InferCtxt, InferOk};
-use rustc::traits::{self, Reveal};
+use rustc::traits;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, Ty, TyCtxt, TypeVariants};
 use rustc::middle::const_val::ConstVal;
@@ -320,6 +320,7 @@ fn field_ty(&mut self,
 
 pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    param_env: ty::ParamEnv<'gcx>,
     fulfillment_cx: traits::FulfillmentContext<'tcx>,
     last_span: Span,
     body_id: ast::NodeId,
@@ -327,12 +328,16 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 }
 
 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
-    fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, body_id: ast::NodeId) -> Self {
+    fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+           body_id: ast::NodeId,
+           param_env: ty::ParamEnv<'gcx>)
+           -> Self {
         TypeChecker {
             infcx: infcx,
             fulfillment_cx: traits::FulfillmentContext::new(),
             last_span: DUMMY_SP,
-            body_id: body_id,
+            body_id,
+            param_env,
             reported_errors: FxHashSet(),
         }
     }
@@ -348,18 +353,20 @@ pub fn register_infer_ok_obligations<T>(&mut self, infer_ok: InferOk<'tcx, T>) -
         infer_ok.value
     }
 
-    fn sub_types(&mut self, sup: Ty<'tcx>, sub: Ty<'tcx>)
+    fn sub_types(&mut self, sub: Ty<'tcx>, sup: Ty<'tcx>)
                  -> infer::UnitResult<'tcx>
     {
-        self.infcx.sub_types(false, &self.misc(self.last_span), sup, sub)
-            .map(|ok| self.register_infer_ok_obligations(ok))
+        self.infcx.at(&self.misc(self.last_span), self.param_env)
+                  .sup(sup, sub)
+                  .map(|ok| self.register_infer_ok_obligations(ok))
     }
 
     fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
                 -> infer::UnitResult<'tcx>
     {
-        self.infcx.eq_types(false, &self.misc(span), a, b)
-            .map(|ok| self.register_infer_ok_obligations(ok))
+        self.infcx.at(&self.misc(span), self.param_env)
+                  .eq(b, a)
+                  .map(|ok| self.register_infer_ok_obligations(ok))
     }
 
     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
@@ -665,7 +672,7 @@ fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<
 
         let span = local_decl.source_info.span;
         let ty = local_decl.ty;
-        if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) {
+        if !ty.is_sized(self.tcx().global_tcx(), self.param_env, span) {
             // in current MIR construction, all non-control-flow rvalue
             // expressions evaluate through `as_temp` or `into` a return
             // slot or local, so to find all unsized rvalues it is enough
@@ -706,7 +713,7 @@ fn normalize<T>(&mut self, value: &T) -> T
         let mut selcx = traits::SelectionContext::new(self.infcx);
         let cause = traits::ObligationCause::misc(self.last_span, ast::CRATE_NODE_ID);
         let traits::Normalized { value, obligations } =
-            traits::normalize(&mut selcx, cause, value);
+            traits::normalize(&mut selcx, self.param_env, cause, value);
 
         debug!("normalize: value={:?} obligations={:?}",
                value,
@@ -752,8 +759,8 @@ fn run_pass<'a, 'tcx>(&self,
             return;
         }
         let param_env = tcx.param_env(def_id);
-        tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
-            let mut checker = TypeChecker::new(&infcx, item_id);
+        tcx.infer_ctxt(()).enter(|infcx| {
+            let mut checker = TypeChecker::new(&infcx, item_id, param_env);
             {
                 let mut verifier = TypeVerifier::new(&mut checker, mir);
                 verifier.visit_mir(mir);
index 50ebe366387330901ab6fc96db53c8f70fc58577..da7e218439cf0bfe21bef73e70fe8e81faee7f81 100644 (file)
@@ -673,7 +673,7 @@ fn drop_loop_pair(&mut self, ety: Ty<'tcx>, ptr_based: bool) -> BasicBlock {
         debug!("drop_loop_pair({:?}, {:?})", ety, ptr_based);
         let tcx = self.tcx();
         let iter_ty = if ptr_based {
-            tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::MutMutable })
+            tcx.mk_mut_ptr(ety)
         } else {
             tcx.types.usize
         };
@@ -708,15 +708,20 @@ fn drop_loop_pair(&mut self, ety: Ty<'tcx>, ptr_based: bool) -> BasicBlock {
         let mut drop_block_stmts = vec![];
         drop_block_stmts.push(self.assign(&length, Rvalue::Len(self.lvalue.clone())));
         if ptr_based {
-            // cur = &LV[0];
-            // end = &LV[len];
-            drop_block_stmts.push(self.assign(&cur, Rvalue::Ref(
-                tcx.types.re_erased, BorrowKind::Mut,
-                self.lvalue.clone().index(zero.clone())
+            let tmp_ty = tcx.mk_mut_ptr(self.lvalue_ty(self.lvalue));
+            let tmp = Lvalue::Local(self.new_temp(tmp_ty));
+            // tmp = &LV;
+            // cur = tmp as *mut T;
+            // end = Offset(cur, len);
+            drop_block_stmts.push(self.assign(&tmp, Rvalue::Ref(
+                tcx.types.re_erased, BorrowKind::Mut, self.lvalue.clone()
             )));
-            drop_block_stmts.push(self.assign(&length_or_end, Rvalue::Ref(
-                tcx.types.re_erased, BorrowKind::Mut,
-                self.lvalue.clone().index(Operand::Consume(length.clone()))
+            drop_block_stmts.push(self.assign(&cur, Rvalue::Cast(
+                CastKind::Misc, Operand::Consume(tmp.clone()), iter_ty
+            )));
+            drop_block_stmts.push(self.assign(&length_or_end,
+                Rvalue::BinaryOp(BinOp::Offset,
+                     Operand::Consume(cur.clone()), Operand::Consume(length.clone())
             )));
         } else {
             // index = 0 (length already pushed)
index eaba573dcd2e582d21dfdc056e87ba601d820e94..22a8c4378d4c34236ba39a05045c8d5f08f8147e 100644 (file)
@@ -111,6 +111,7 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let p = Path::new(file_dir);
         file_path.push(p);
     };
+    let _ = fs::create_dir_all(&file_path);
     let file_name = format!("rustc.node{}{}{}.{}.{}.mir",
                             source.item_id(), promotion_id, pass_num, pass_name, disambiguator);
     file_path.push(&file_name);
index 698850f0e9e7fa6e20908930f6b3d3b5a23040d0..65a9334bbae19512dbf8892ee2df3da9673274a7 100644 (file)
@@ -138,11 +138,11 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) {
             self.check_const_eval(&body.value);
         }
 
-        let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
-            let param_env = infcx.param_env.clone();
+        let outer_penv = self.tcx.infer_ctxt(body_id).enter(|infcx| {
+            let param_env = self.tcx.param_env(item_def_id);
             let outer_penv = mem::replace(&mut self.param_env, param_env);
             let region_maps = &self.tcx.region_maps(item_def_id);
-            euv::ExprUseVisitor::new(self, region_maps, &infcx).consume_body(body);
+            euv::ExprUseVisitor::new(self, region_maps, &infcx, param_env).consume_body(body);
             outer_penv
         });
 
@@ -280,11 +280,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
         _ => {}
     }
 
-    let method_call = ty::MethodCall::expr(e.id);
     match e.node {
         hir::ExprUnary(..) |
         hir::ExprBinary(..) |
-        hir::ExprIndex(..) if v.tables.method_map.contains_key(&method_call) => {
+        hir::ExprIndex(..) if v.tables.is_method_call(e) => {
             v.promotable = false;
         }
         hir::ExprBox(_) => {
@@ -381,9 +380,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             }
         }
         hir::ExprMethodCall(..) => {
-            let method = v.tables.method_map[&method_call];
-            match v.tcx.associated_item(method.def_id).container {
-                ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty),
+            let def_id = v.tables.type_dependent_defs[&e.id].def_id();
+            match v.tcx.associated_item(def_id).container {
+                ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty),
                 ty::TraitContainer(_) => v.promotable = false
             }
         }
@@ -442,18 +441,21 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
 fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
     use rustc::ty::adjustment::*;
 
-    match v.tables.adjustments.get(&e.id).map(|adj| adj.kind) {
-        None |
-        Some(Adjust::NeverToAny) |
-        Some(Adjust::ReifyFnPointer) |
-        Some(Adjust::UnsafeFnPointer) |
-        Some(Adjust::ClosureFnPointer) |
-        Some(Adjust::MutToConstPointer) => {}
-
-        Some(Adjust::DerefRef { autoderefs, .. }) => {
-            if (0..autoderefs as u32)
-                .any(|autoderef| v.tables.is_overloaded_autoderef(e.id, autoderef)) {
-                v.promotable = false;
+    for adjustment in v.tables.expr_adjustments(e) {
+        match adjustment.kind {
+            Adjust::NeverToAny |
+            Adjust::ReifyFnPointer |
+            Adjust::UnsafeFnPointer |
+            Adjust::ClosureFnPointer |
+            Adjust::MutToConstPointer |
+            Adjust::Borrow(_) |
+            Adjust::Unsize => {}
+
+            Adjust::Deref(ref overloaded) => {
+                if overloaded.is_some() {
+                    v.promotable = false;
+                    break;
+                }
             }
         }
     }
@@ -466,7 +468,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         in_fn: false,
         promotable: false,
         mut_rvalue_borrows: NodeSet(),
-        param_env: ty::ParamEnv::empty(),
+        param_env: ty::ParamEnv::empty(Reveal::UserFacing),
     }.as_deep_visitor());
     tcx.sess.abort_if_errors();
 }
@@ -512,7 +514,7 @@ fn borrow(&mut self,
                 Categorization::StaticItem => {
                     break;
                 }
-                Categorization::Deref(ref cmt, ..) |
+                Categorization::Deref(ref cmt, _) |
                 Categorization::Downcast(ref cmt, _) |
                 Categorization::Interior(ref cmt, _) => {
                     cur = cmt;
index fa6ea9dba43c2e7e3d38308f8f32d608be5b7811..1a5cf89f96998f1dad5005cd16ada36b7ad4e6e5 100644 (file)
@@ -1578,6 +1578,35 @@ fn print_on_failure(state: &State) {
 ```
 "##,
 
+E0603: r##"
+A private item was used outside its scope.
+
+Erroneous code example:
+
+```compile_fail,E0603
+mod SomeModule {
+    const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we
+                                            // can't use it outside of the
+                                            // `SomeModule` module.
+}
+
+println!("const value: {}", SomeModule::PRIVATE); // error: constant `CONSTANT`
+                                                  //        is private
+```
+
+In order to fix this error, you need to make the item public by using the `pub`
+keyword. Example:
+
+```
+mod SomeModule {
+    pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the
+                                                // `pub` keyword.
+}
+
+println!("const value: {}", SomeModule::PRIVATE); // ok!
+```
+"##,
+
 }
 
 register_diagnostics! {
index a40c191f7bd29f72aa25b8f77445440062ebc53d..b77d5a2f71f9ed0a2e3b16ab94bd5277d4870e8a 100644 (file)
@@ -1204,7 +1204,7 @@ pub struct Resolver<'a> {
     pub found_unresolved_macro: bool,
 
     // List of crate local macros that we need to warn about as being unused.
-    // Right now this only includes macro_rules! macros.
+    // Right now this only includes macro_rules! macros, and macros 2.0.
     unused_macros: FxHashSet<DefId>,
 
     // Maps the `Mark` of an expansion to its containing module or block.
@@ -3428,7 +3428,7 @@ fn report_errors(&mut self) {
 
         for &PrivacyError(span, name, binding) in &self.privacy_errors {
             if !reported_spans.insert(span) { continue }
-            self.session.span_err(span, &format!("{} `{}` is private", binding.descr(), name));
+            span_err!(self.session, span, E0603, "{} `{}` is private", binding.descr(), name);
         }
     }
 
index 9a37df762327979cca096ffeb6a45b50a9753f08..a950a9a23e47ca92c5663f91aece10849cfd8d48 100644 (file)
@@ -316,6 +316,7 @@ fn check_unused_macros(&self) {
         for did in self.unused_macros.iter() {
             let id_span = match *self.macro_map[did] {
                 SyntaxExtension::NormalTT(_, isp, _) => isp,
+                SyntaxExtension::DeclMacro(.., osp) => osp,
                 _ => None,
             };
             if let Some((id, span)) = id_span {
@@ -735,6 +736,9 @@ pub fn define_macro(&mut self,
             let module = self.current_module;
             let def = Def::Macro(def_id, MacroKind::Bang);
             let vis = self.resolve_visibility(&item.vis);
+            if vis != ty::Visibility::Public {
+                self.unused_macros.insert(def_id);
+            }
             self.define(module, ident, MacroNS, (def, vis, item.span, expansion));
         }
     }
index fa74e4d6ffcccfae3d5539c3363a37b4d2e82d77..b74d3982d61c5739eca252d6dd7728bec0e20563 100644 (file)
@@ -564,8 +564,7 @@ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
                 }
             }
             ast::ExprKind::MethodCall(..) => {
-                let method_call = ty::MethodCall::expr(expr.id);
-                let method_id = self.tables.method_map[&method_call].def_id;
+                let method_id = self.tables.type_dependent_defs[&expr.id].def_id();
                 let (def_id, decl_id) = match self.tcx.associated_item(method_id).container {
                     ty::ImplContainer(_) => (Some(method_id), None),
                     ty::TraitContainer(_) => (None, Some(method_id)),
index 4ccc85257f3c990ba313df23fa87a9de43476721..7355b399360a30485c08670cb4b88d0b3edb3352 100644 (file)
@@ -25,3 +25,6 @@ rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
 serialize = { path = "../libserialize" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
+
+[target."cfg(windows)".dependencies]
+gcc = "0.3.50"
index e40267238801cb791e63a600821b493aa769e84b..ee92a4b4a2dfeaf170998eabe3dd56fb523de8b1 100644 (file)
@@ -12,7 +12,6 @@
 use super::linker::Linker;
 use super::rpath::RPathConfig;
 use super::rpath;
-use super::msvc;
 use metadata::METADATA_FILENAME;
 use rustc::session::config::{self, NoDebugInfo, OutputFilenames, Input, OutputType};
 use rustc::session::filesearch;
@@ -142,20 +141,41 @@ pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap) -> LinkMet
     return r;
 }
 
-// The third parameter is for an extra path to add to PATH for MSVC
-// cross linkers for host toolchain DLL dependencies
-pub fn get_linker(sess: &Session) -> (String, Command, Option<PathBuf>) {
+// The third parameter is for an env vars, used to set up the path for MSVC
+// to find its DLLs
+pub fn get_linker(sess: &Session) -> (String, Command, Vec<(OsString, OsString)>) {
     if let Some(ref linker) = sess.opts.cg.linker {
-        (linker.clone(), Command::new(linker), None)
+        (linker.clone(), Command::new(linker), vec![])
     } else if sess.target.target.options.is_like_msvc {
-        let (cmd, host) = msvc::link_exe_cmd(sess);
-        ("link.exe".to_string(), cmd, host)
+        let (cmd, envs) = msvc_link_exe_cmd(sess);
+        ("link.exe".to_string(), cmd, envs)
     } else {
         (sess.target.target.options.linker.clone(),
-         Command::new(&sess.target.target.options.linker), None)
+         Command::new(&sess.target.target.options.linker), vec![])
     }
 }
 
+#[cfg(windows)]
+pub fn msvc_link_exe_cmd(sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
+    use gcc::windows_registry;
+
+    let target = &sess.opts.target_triple;
+    let tool = windows_registry::find_tool(target, "link.exe");
+
+    if let Some(tool) = tool {
+        let envs = tool.env().to_vec();
+        (tool.to_command(), envs)
+    } else {
+        debug!("Failed to locate linker.");
+        (Command::new("link.exe"), vec![])
+    }
+}
+
+#[cfg(not(windows))]
+pub fn msvc_link_exe_cmd(_sess: &Session) -> (Command, Vec<(OsString, OsString)>) {
+    (Command::new("link.exe"), vec![])
+}
+
 pub fn get_ar_prog(sess: &Session) -> String {
     sess.opts.cg.ar.clone().unwrap_or_else(|| {
         sess.target.target.options.ar.clone()
@@ -706,8 +726,9 @@ fn link_natively(sess: &Session,
     let flavor = sess.linker_flavor();
 
     // The invocations of cc share some flags across platforms
-    let (pname, mut cmd, extra) = get_linker(sess);
-    cmd.env("PATH", command_path(sess, extra));
+    let (pname, mut cmd, envs) = get_linker(sess);
+    // This will set PATH on MSVC
+    cmd.envs(envs);
 
     let root = sess.target_filesearch(PathKind::Native).get_lib_path();
     if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
diff --git a/src/librustc_trans/back/msvc/arch.rs b/src/librustc_trans/back/msvc/arch.rs
deleted file mode 100644 (file)
index c10312a..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(non_camel_case_types, non_snake_case)]
-
-use libc::c_void;
-use std::mem;
-
-type DWORD = u32;
-type WORD = u16;
-type LPVOID = *mut c_void;
-type DWORD_PTR = usize;
-
-const PROCESSOR_ARCHITECTURE_INTEL: WORD = 0;
-const PROCESSOR_ARCHITECTURE_AMD64: WORD = 9;
-
-#[repr(C)]
-struct SYSTEM_INFO {
-    wProcessorArchitecture: WORD,
-    _wReserved: WORD,
-    _dwPageSize: DWORD,
-    _lpMinimumApplicationAddress: LPVOID,
-    _lpMaximumApplicationAddress: LPVOID,
-    _dwActiveProcessorMask: DWORD_PTR,
-    _dwNumberOfProcessors: DWORD,
-    _dwProcessorType: DWORD,
-    _dwAllocationGranularity: DWORD,
-    _wProcessorLevel: WORD,
-    _wProcessorRevision: WORD,
-}
-
-extern "system" {
-    fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
-}
-
-pub enum Arch {
-    X86,
-    Amd64,
-}
-
-pub fn host_arch() -> Option<Arch> {
-    let mut info = unsafe { mem::zeroed() };
-    unsafe { GetNativeSystemInfo(&mut info) };
-    match info.wProcessorArchitecture {
-        PROCESSOR_ARCHITECTURE_INTEL => Some(Arch::X86),
-        PROCESSOR_ARCHITECTURE_AMD64 => Some(Arch::Amd64),
-        _ => None,
-    }
-}
diff --git a/src/librustc_trans/back/msvc/mod.rs b/src/librustc_trans/back/msvc/mod.rs
deleted file mode 100644 (file)
index 9764888..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-// Copyright 2015 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.
-
-//! MSVC-specific logic for linkers and such.
-//!
-//! This module contains a cross-platform interface but has a blank unix
-//! implementation. The Windows implementation builds on top of Windows native
-//! libraries (reading registry keys), so it otherwise wouldn't link on unix.
-//!
-//! Note that we don't have much special logic for finding the system linker on
-//! any other platforms, so it may seem a little odd to single out MSVC to have
-//! a good deal of code just to find the linker. Unlike Unix systems, however,
-//! the MSVC linker is not in the system PATH by default. It also additionally
-//! needs a few environment variables or command line flags to be able to link
-//! against system libraries.
-//!
-//! In order to have a nice smooth experience on Windows, the logic in this file
-//! is here to find the MSVC linker and set it up in the default configuration
-//! one would need to set up anyway. This means that the Rust compiler can be
-//! run not only in the developer shells of MSVC but also the standard cmd.exe
-//! shell or MSYS shells.
-//!
-//! As a high-level note, all logic in this module for looking up various
-//! paths/files is based on Microsoft's logic in their vcvars bat files, but
-//! comments can also be found below leading through the various code paths.
-
-// A simple macro to make this option mess easier to read
-#[cfg(windows)]
-macro_rules! otry {
-    ($expr:expr) => (match $expr {
-        Some(val) => val,
-        None => return None,
-    })
-}
-
-#[cfg(windows)]
-mod registry;
-#[cfg(windows)]
-mod arch;
-
-#[cfg(windows)]
-mod platform {
-    use std::env;
-    use std::ffi::OsString;
-    use std::fs;
-    use std::path::{Path, PathBuf};
-    use std::process::Command;
-    use rustc::session::Session;
-    use super::arch::{host_arch, Arch};
-    use super::registry::LOCAL_MACHINE;
-
-    // First we need to figure out whether the environment is already correctly
-    // configured by vcvars. We do this by looking at the environment variable
-    // `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
-    // otherwise. If it is defined, then we find `link.exe` in `PATH and trust
-    // that everything else is configured correctly.
-    //
-    // If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where
-    // it claimed it should be), then we resort to finding everything
-    // ourselves. First we find where the latest version of MSVC is installed
-    // and what version it is. Then based on the version we find the
-    // appropriate SDKs.
-    //
-    // If despite our best efforts we are still unable to find MSVC then we
-    // just blindly call `link.exe` and hope for the best.
-    //
-    // This code only supports VC 11 through 15. For versions older than that
-    // the user will need to manually execute the appropriate vcvars bat file
-    // and it should hopefully work.
-    //
-    // The second member of the tuple we return is the directory for the host
-    // linker toolchain, which is necessary when using the cross linkers.
-    pub fn link_exe_cmd(sess: &Session) -> (Command, Option<PathBuf>) {
-        let arch = &sess.target.target.arch;
-        env::var_os("VCINSTALLDIR").and_then(|_| {
-            debug!("Detected that vcvars was already run.");
-            let path = otry!(env::var_os("PATH"));
-            // Mingw has its own link which is not the link we want so we
-            // look for `cl.exe` too as a precaution.
-            env::split_paths(&path).find(|path| {
-                path.join("cl.exe").is_file()
-                    && path.join("link.exe").is_file()
-            }).map(|path| {
-                (Command::new(path.join("link.exe")), None)
-            })
-        }).or_else(|| {
-            None.or_else(|| {
-                find_msvc_latest(arch, "15.0")
-            }).or_else(|| {
-                find_msvc_latest(arch, "14.0")
-            }).or_else(|| {
-                find_msvc_12(arch)
-            }).or_else(|| {
-                find_msvc_11(arch)
-            }).map(|(cmd, path)| (cmd, Some(path)))
-        }).unwrap_or_else(|| {
-            debug!("Failed to locate linker.");
-            (Command::new("link.exe"), None)
-        })
-    }
-
-    // For MSVC 14 or newer we need to find the Universal CRT as well as either
-    // the Windows 10 SDK or Windows 8.1 SDK.
-    fn find_msvc_latest(arch: &str, ver: &str) -> Option<(Command, PathBuf)> {
-        let vcdir = otry!(get_vc_dir(ver));
-        let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
-        let sub = otry!(lib_subdir(arch));
-        let ucrt = otry!(get_ucrt_dir());
-        debug!("Found Universal CRT {:?}", ucrt);
-        add_lib(&mut cmd, &ucrt.join("ucrt").join(sub));
-        if let Some(dir) = get_sdk10_dir() {
-            debug!("Found Win10 SDK {:?}", dir);
-            add_lib(&mut cmd, &dir.join("um").join(sub));
-        } else if let Some(dir) = get_sdk81_dir() {
-            debug!("Found Win8.1 SDK {:?}", dir);
-            add_lib(&mut cmd, &dir.join("um").join(sub));
-        } else {
-            return None
-        }
-        Some((cmd, host))
-    }
-
-    // For MSVC 12 we need to find the Windows 8.1 SDK.
-    fn find_msvc_12(arch: &str) -> Option<(Command, PathBuf)> {
-        let vcdir = otry!(get_vc_dir("12.0"));
-        let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
-        let sub = otry!(lib_subdir(arch));
-        let sdk81 = otry!(get_sdk81_dir());
-        debug!("Found Win8.1 SDK {:?}", sdk81);
-        add_lib(&mut cmd, &sdk81.join("um").join(sub));
-        Some((cmd, host))
-    }
-
-    // For MSVC 11 we need to find the Windows 8 SDK.
-    fn find_msvc_11(arch: &str) -> Option<(Command, PathBuf)> {
-        let vcdir = otry!(get_vc_dir("11.0"));
-        let (mut cmd, host) = otry!(get_linker(&vcdir, arch));
-        let sub = otry!(lib_subdir(arch));
-        let sdk8 = otry!(get_sdk8_dir());
-        debug!("Found Win8 SDK {:?}", sdk8);
-        add_lib(&mut cmd, &sdk8.join("um").join(sub));
-        Some((cmd, host))
-    }
-
-    // A convenience function to append library paths.
-    fn add_lib(cmd: &mut Command, lib: &Path) {
-        let mut arg: OsString = "/LIBPATH:".into();
-        arg.push(lib);
-        cmd.arg(arg);
-    }
-
-    // Given a possible MSVC installation directory, we look for the linker and
-    // then add the MSVC library path.
-    fn get_linker(path: &Path, arch: &str) -> Option<(Command, PathBuf)> {
-        debug!("Looking for linker in {:?}", path);
-        bin_subdir(arch).into_iter().map(|(sub, host)| {
-            (path.join("bin").join(sub).join("link.exe"),
-             path.join("bin").join(host))
-        }).filter(|&(ref path, _)| {
-            path.is_file()
-        }).map(|(path, host)| {
-            (Command::new(path), host)
-        }).filter_map(|(mut cmd, host)| {
-            let sub = otry!(vc_lib_subdir(arch));
-            add_lib(&mut cmd, &path.join("lib").join(sub));
-            Some((cmd, host))
-        }).next()
-    }
-
-    // To find MSVC we look in a specific registry key for the version we are
-    // trying to find.
-    fn get_vc_dir(ver: &str) -> Option<PathBuf> {
-        let key = otry!(LOCAL_MACHINE
-            .open(r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7".as_ref()).ok());
-        let path = otry!(key.query_str(ver).ok());
-        Some(path.into())
-    }
-
-    // To find the Universal CRT we look in a specific registry key for where
-    // all the Universal CRTs are located and then sort them asciibetically to
-    // find the newest version. While this sort of sorting isn't ideal,  it is
-    // what vcvars does so that's good enough for us.
-    fn get_ucrt_dir() -> Option<PathBuf> {
-        let key = otry!(LOCAL_MACHINE
-            .open(r"SOFTWARE\Microsoft\Windows Kits\Installed Roots".as_ref()).ok());
-        let root = otry!(key.query_str("KitsRoot10").ok());
-        let readdir = otry!(fs::read_dir(Path::new(&root).join("lib")).ok());
-        readdir.filter_map(|dir| {
-            dir.ok()
-        }).map(|dir| {
-            dir.path()
-        }).filter(|dir| {
-            dir.components().last().and_then(|c| {
-                c.as_os_str().to_str()
-            }).map(|c| {
-                c.starts_with("10.") && dir.join("ucrt").is_dir()
-            }).unwrap_or(false)
-        }).max()
-    }
-
-    // Vcvars finds the correct version of the Windows 10 SDK by looking
-    // for the include `um\Windows.h` because sometimes a given version will
-    // only have UCRT bits without the rest of the SDK. Since we only care about
-    // libraries and not includes, we instead look for `um\x64\kernel32.lib`.
-    // Since the 32-bit and 64-bit libraries are always installed together we
-    // only need to bother checking x64, making this code a tiny bit simpler.
-    // Like we do for the Universal CRT, we sort the possibilities
-    // asciibetically to find the newest one as that is what vcvars does.
-    fn get_sdk10_dir() -> Option<PathBuf> {
-        let key = otry!(LOCAL_MACHINE
-            .open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0".as_ref()).ok());
-        let root = otry!(key.query_str("InstallationFolder").ok());
-        let readdir = otry!(fs::read_dir(Path::new(&root).join("lib")).ok());
-        let mut dirs: Vec<_> = readdir.filter_map(|dir| dir.ok())
-            .map(|dir| dir.path()).collect();
-        dirs.sort();
-        dirs.into_iter().rev().filter(|dir| {
-            dir.join("um").join("x64").join("kernel32.lib").is_file()
-        }).next()
-    }
-
-    // Interestingly there are several subdirectories, `win7` `win8` and
-    // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same
-    // applies to us. Note that if we were targetting kernel mode drivers
-    // instead of user mode applications, we would care.
-    fn get_sdk81_dir() -> Option<PathBuf> {
-        let key = otry!(LOCAL_MACHINE
-            .open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1".as_ref()).ok());
-        let root = otry!(key.query_str("InstallationFolder").ok());
-        Some(Path::new(&root).join("lib").join("winv6.3"))
-    }
-
-    fn get_sdk8_dir() -> Option<PathBuf> {
-        let key = otry!(LOCAL_MACHINE
-            .open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0".as_ref()).ok());
-        let root = otry!(key.query_str("InstallationFolder").ok());
-        Some(Path::new(&root).join("lib").join("win8"))
-    }
-
-    // When choosing the linker toolchain to use, we have to choose the one
-    // which matches the host architecture. Otherwise we end up in situations
-    // where someone on 32-bit Windows is trying to cross compile to 64-bit and
-    // it tries to invoke the native 64-bit linker which won't work.
-    //
-    // For the return value of this function, the first member of the tuple is
-    // the folder of the linker we will be invoking, while the second member
-    // is the folder of the host toolchain for that linker which is essential
-    // when using a cross linker. We return a Vec since on x64 there are often
-    // two linkers that can target the architecture we desire. The 64-bit host
-    // linker is preferred, and hence first, due to 64-bit allowing it more
-    // address space to work with and potentially being faster.
-    //
-    // FIXME - Figure out what happens when the host architecture is arm.
-    fn bin_subdir(arch: &str) -> Vec<(&'static str, &'static str)> {
-        match (arch, host_arch()) {
-            ("x86", Some(Arch::X86)) => vec![("", "")],
-            ("x86", Some(Arch::Amd64)) => vec![("amd64_x86", "amd64"), ("", "")],
-            ("x86_64", Some(Arch::X86)) => vec![("x86_amd64", "")],
-            ("x86_64", Some(Arch::Amd64)) => vec![("amd64", "amd64"), ("x86_amd64", "")],
-            ("arm", Some(Arch::X86)) => vec![("x86_arm", "")],
-            ("arm", Some(Arch::Amd64)) => vec![("amd64_arm", "amd64"), ("x86_arm", "")],
-            _ => vec![],
-        }
-    }
-
-    fn lib_subdir(arch: &str) -> Option<&'static str> {
-        match arch {
-            "x86" => Some("x86"),
-            "x86_64" => Some("x64"),
-            "arm" => Some("arm"),
-            _ => None,
-        }
-    }
-
-    // MSVC's x86 libraries are not in a subfolder
-    fn vc_lib_subdir(arch: &str) -> Option<&'static str> {
-        match arch {
-            "x86" => Some(""),
-            "x86_64" => Some("amd64"),
-            "arm" => Some("arm"),
-            _ => None,
-        }
-    }
-}
-
-// If we're not on Windows, then there's no registry to search through and MSVC
-// wouldn't be able to run, so we just call `link.exe` and hope for the best.
-#[cfg(not(windows))]
-mod platform {
-    use std::path::PathBuf;
-    use std::process::Command;
-    use rustc::session::Session;
-    pub fn link_exe_cmd(_sess: &Session) -> (Command, Option<PathBuf>) {
-        (Command::new("link.exe"), None)
-    }
-}
-
-pub use self::platform::*;
diff --git a/src/librustc_trans/back/msvc/registry.rs b/src/librustc_trans/back/msvc/registry.rs
deleted file mode 100644 (file)
index 8242f53..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::io;
-use std::ffi::{OsString, OsStr};
-use std::os::windows::prelude::*;
-use std::ptr;
-use libc::c_long;
-
-pub type DWORD = u32;
-type LPCWSTR = *const u16;
-type LONG = c_long;
-type LPDWORD = *mut DWORD;
-type LPBYTE = *mut u8;
-
-
-const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
-const KEY_WOW64_32KEY: REGSAM = 0x0200;
-const KEY_READ: REGSAM = (STANDARD_RIGTS_READ | KEY_QUERY_VALUE |
-                          KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & !SYNCHRONIZE;
-const STANDARD_RIGTS_READ: REGSAM = READ_CONTROL;
-const READ_CONTROL: REGSAM = 0x00020000;
-const KEY_QUERY_VALUE: REGSAM = 0x0001;
-const KEY_ENUMERATE_SUB_KEYS: REGSAM = 0x0008;
-const KEY_NOTIFY: REGSAM = 0x0010;
-const SYNCHRONIZE: REGSAM = 0x00100000;
-const REG_SZ: DWORD = 1;
-const ERROR_SUCCESS: i32 = 0;
-
-pub enum __HKEY__ {}
-pub type HKEY = *mut __HKEY__;
-pub type PHKEY = *mut HKEY;
-pub type REGSAM = DWORD;
-
-#[link(name = "advapi32")]
-extern "system" {
-    fn RegOpenKeyExW(hKey: HKEY,
-                     lpSubKey: LPCWSTR,
-                     ulOptions: DWORD,
-                     samDesired: REGSAM,
-                     phkResult: PHKEY) -> LONG;
-    fn RegQueryValueExW(hKey: HKEY,
-                        lpValueName: LPCWSTR,
-                        lpReserved: LPDWORD,
-                        lpType: LPDWORD,
-                        lpData: LPBYTE,
-                        lpcbData: LPDWORD) -> LONG;
-    fn RegCloseKey(hKey: HKEY) -> LONG;
-}
-
-pub struct RegistryKey(Repr);
-
-struct OwnedKey(HKEY);
-
-enum Repr {
-    Const(HKEY),
-    Owned(OwnedKey),
-}
-
-unsafe impl Sync for RegistryKey {}
-unsafe impl Send for RegistryKey {}
-
-pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
-
-impl RegistryKey {
-    fn raw(&self) -> HKEY {
-        match self.0 {
-            Repr::Const(val) => val,
-            Repr::Owned(ref val) => val.0,
-        }
-    }
-
-    pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
-        let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
-        let mut ret = ptr::null_mut();
-        let err = unsafe {
-            RegOpenKeyExW(self.raw(), key.as_ptr(), 0,
-                          KEY_READ | KEY_WOW64_32KEY, &mut ret)
-        };
-        if err == ERROR_SUCCESS {
-            Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
-        } else {
-            Err(io::Error::from_raw_os_error(err as i32))
-        }
-    }
-
-    pub fn query_str(&self, name: &str) -> io::Result<OsString> {
-        let name: &OsStr = name.as_ref();
-        let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
-        let mut len = 0;
-        let mut kind = 0;
-        unsafe {
-            let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(),
-                                       &mut kind, ptr::null_mut(), &mut len);
-            if err != ERROR_SUCCESS {
-                return Err(io::Error::from_raw_os_error(err as i32))
-            }
-            if kind != REG_SZ {
-                return Err(io::Error::new(io::ErrorKind::Other,
-                                          "registry key wasn't a string"))
-            }
-
-            // The length here is the length in bytes, but we're using wide
-            // characters so we need to be sure to halve it for the capacity
-            // passed in.
-            let mut v = Vec::with_capacity(len as usize / 2);
-            let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(),
-                                       ptr::null_mut(), v.as_mut_ptr() as *mut _,
-                                       &mut len);
-            if err != ERROR_SUCCESS {
-                return Err(io::Error::from_raw_os_error(err as i32))
-            }
-            v.set_len(len as usize / 2);
-
-            // Some registry keys may have a terminating nul character, but
-            // we're not interested in that, so chop it off if it's there.
-            if v[v.len() - 1] == 0 {
-                v.pop();
-            }
-            Ok(OsString::from_wide(&v))
-        }
-    }
-}
-
-impl Drop for OwnedKey {
-    fn drop(&mut self) {
-        unsafe { RegCloseKey(self.0); }
-    }
-}
index 1b3f0ba7ce5b6f61c7430d92a882cfb7cc7fa9f7..88c30cd86659920184abaa67789e2f1a9283669e 100644 (file)
@@ -44,7 +44,7 @@
 use rustc::hir::map as hir_map;
 use rustc::util::common::time;
 use rustc::session::config::{self, NoDebugInfo};
-use rustc::session::{self, DataTypeKind, Session};
+use rustc::session::Session;
 use rustc_incremental::IncrementalHashesMap;
 use abi;
 use mir::lvalue::LvalueRef;
@@ -80,7 +80,6 @@
 use syntax_pos::Span;
 use syntax::attr;
 use rustc::hir;
-use rustc::ty::layout::{self, Layout};
 use syntax::ast;
 
 use mir::lvalue::Alignment;
@@ -1287,10 +1286,6 @@ fn module_translation<'a, 'tcx>(
                             &exported_symbols);
     });
 
-    if tcx.sess.opts.debugging_opts.print_type_sizes {
-        gather_type_sizes(tcx);
-    }
-
     if sess.target.target.options.is_like_msvc &&
        sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
         create_imps(sess, &llvm_modules);
@@ -1322,193 +1317,6 @@ fn module_translation<'a, 'tcx>(
     }
 }
 
-fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let layout_cache = tcx.layout_cache.borrow();
-    for (ty, layout) in layout_cache.iter() {
-
-        // (delay format until we actually need it)
-        let record = |kind, opt_discr_size, variants| {
-            let type_desc = format!("{:?}", ty);
-            let overall_size = layout.size(tcx);
-            let align = layout.align(tcx);
-            tcx.sess.code_stats.borrow_mut().record_type_size(kind,
-                                                              type_desc,
-                                                              align,
-                                                              overall_size,
-                                                              opt_discr_size,
-                                                              variants);
-        };
-
-        let (adt_def, substs) = match ty.sty {
-            ty::TyAdt(ref adt_def, substs) => {
-                debug!("print-type-size t: `{:?}` process adt", ty);
-                (adt_def, substs)
-            }
-
-            ty::TyClosure(..) => {
-                debug!("print-type-size t: `{:?}` record closure", ty);
-                record(DataTypeKind::Closure, None, vec![]);
-                continue;
-            }
-
-            _ => {
-                debug!("print-type-size t: `{:?}` skip non-nominal", ty);
-                continue;
-            }
-        };
-
-        let adt_kind = adt_def.adt_kind();
-
-        let build_field_info = |(field_name, field_ty): (ast::Name, Ty), offset: &layout::Size| {
-            match layout_cache.get(&field_ty) {
-                None => bug!("no layout found for field {} type: `{:?}`", field_name, field_ty),
-                Some(field_layout) => {
-                    session::FieldInfo {
-                        name: field_name.to_string(),
-                        offset: offset.bytes(),
-                        size: field_layout.size(tcx).bytes(),
-                        align: field_layout.align(tcx).abi(),
-                    }
-                }
-            }
-        };
-
-        let build_primitive_info = |name: ast::Name, value: &layout::Primitive| {
-            session::VariantInfo {
-                name: Some(name.to_string()),
-                kind: session::SizeKind::Exact,
-                align: value.align(tcx).abi(),
-                size: value.size(tcx).bytes(),
-                fields: vec![],
-            }
-        };
-
-        enum Fields<'a> {
-            WithDiscrim(&'a layout::Struct),
-            NoDiscrim(&'a layout::Struct),
-        }
-
-        let build_variant_info = |n: Option<ast::Name>, flds: &[(ast::Name, Ty)], layout: Fields| {
-            let (s, field_offsets) = match layout {
-                Fields::WithDiscrim(s) => (s, &s.offsets[1..]),
-                Fields::NoDiscrim(s) => (s, &s.offsets[0..]),
-            };
-            let field_info: Vec<_> = flds.iter()
-                .zip(field_offsets.iter())
-                .map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset))
-                .collect();
-
-            session::VariantInfo {
-                name: n.map(|n|n.to_string()),
-                kind: if s.sized {
-                    session::SizeKind::Exact
-                } else {
-                    session::SizeKind::Min
-                },
-                align: s.align.abi(),
-                size: s.min_size.bytes(),
-                fields: field_info,
-            }
-        };
-
-        match **layout {
-            Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
-                                                   nndiscr,
-                                                   discrfield: _,
-                                                   discrfield_source: _ } => {
-                debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
-                       ty, nndiscr, variant_layout);
-                let variant_def = &adt_def.variants[nndiscr as usize];
-                let fields: Vec<_> = variant_def.fields.iter()
-                    .map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
-                    .collect();
-                record(adt_kind.into(),
-                       None,
-                       vec![build_variant_info(Some(variant_def.name),
-                                               &fields,
-                                               Fields::NoDiscrim(variant_layout))]);
-            }
-            Layout::RawNullablePointer { nndiscr, value } => {
-                debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}",
-                       ty, nndiscr, value);
-                let variant_def = &adt_def.variants[nndiscr as usize];
-                record(adt_kind.into(), None,
-                       vec![build_primitive_info(variant_def.name, &value)]);
-            }
-            Layout::Univariant { variant: ref variant_layout, non_zero: _ } => {
-                let variant_names = || {
-                    adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
-                };
-                debug!("print-type-size t: `{:?}` adt univariant {:?} variants: {:?}",
-                       ty, variant_layout, variant_names());
-                assert!(adt_def.variants.len() <= 1,
-                        "univariant with variants {:?}", variant_names());
-                if adt_def.variants.len() == 1 {
-                    let variant_def = &adt_def.variants[0];
-                    let fields: Vec<_> = variant_def.fields.iter()
-                        .map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
-                        .collect();
-                    record(adt_kind.into(),
-                           None,
-                           vec![build_variant_info(Some(variant_def.name),
-                                                   &fields,
-                                                   Fields::NoDiscrim(variant_layout))]);
-                } else {
-                    // (This case arises for *empty* enums; so give it
-                    // zero variants.)
-                    record(adt_kind.into(), None, vec![]);
-                }
-            }
-
-            Layout::General { ref variants, discr, .. } => {
-                debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}",
-                       ty, adt_def.variants.len(), variants.len(), variants);
-                let variant_infos: Vec<_> = adt_def.variants.iter()
-                    .zip(variants.iter())
-                    .map(|(variant_def, variant_layout)| {
-                        let fields: Vec<_> = variant_def.fields.iter()
-                            .map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
-                            .collect();
-                        build_variant_info(Some(variant_def.name),
-                                           &fields,
-                                           Fields::WithDiscrim(variant_layout))
-                    })
-                    .collect();
-                record(adt_kind.into(), Some(discr.size()), variant_infos);
-            }
-
-            Layout::UntaggedUnion { ref variants } => {
-                debug!("print-type-size t: `{:?}` adt union variants {:?}",
-                       ty, variants);
-                // layout does not currently store info about each
-                // variant...
-                record(adt_kind.into(), None, Vec::new());
-            }
-
-            Layout::CEnum { discr, .. } => {
-                debug!("print-type-size t: `{:?}` adt c-like enum", ty);
-                let variant_infos: Vec<_> = adt_def.variants.iter()
-                    .map(|variant_def| {
-                        build_primitive_info(variant_def.name,
-                                             &layout::Primitive::Int(discr))
-                    })
-                    .collect();
-                record(adt_kind.into(), Some(discr.size()), variant_infos);
-            }
-
-            // other cases provide little interesting (i.e. adjustable
-            // via representation tweaks) size info beyond total size.
-            Layout::Scalar { .. } |
-            Layout::Vector { .. } |
-            Layout::Array { .. } |
-            Layout::FatPointer { .. } => {
-                debug!("print-type-size t: `{:?}` adt other", ty);
-                record(adt_kind.into(), None, Vec::new())
-            }
-        }
-    }
-}
-
 #[inline(never)] // give this a place in the profiler
 fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I)
     where I: Iterator<Item=&'a TransItem<'tcx>>
index c3b16c2d07d0733ddc43b0c403ab7dc426a38455..6266452419ed9b035a32ab66603f8e5a118c2ccd 100644 (file)
 use partitioning::CodegenUnit;
 use type_::Type;
 use rustc_data_structures::base_n;
-use rustc::ty::subst::Substs;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::{LayoutTyper, TyLayout};
 use rustc::session::config::{self, NoDebugInfo};
 use rustc::session::Session;
+use rustc::ty::subst::Substs;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout};
 use rustc::util::nodemap::{NodeSet, DefIdMap, FxHashMap};
 
 use std::ffi::{CStr, CString};
@@ -320,15 +320,15 @@ pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
     }
 
     pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
-        ty.needs_drop(self.tcx, ty::ParamEnv::empty())
+        ty.needs_drop(self.tcx, ty::ParamEnv::empty(traits::Reveal::All))
     }
 
     pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_sized(self.tcx, ty::ParamEnv::empty(), DUMMY_SP)
+        ty.is_sized(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
     }
 
     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_freeze(self.tcx, ty::ParamEnv::empty(), DUMMY_SP)
+        ty.is_freeze(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
     }
 
     pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet {
@@ -709,41 +709,27 @@ fn data_layout(&self) -> &ty::layout::TargetDataLayout {
     }
 }
 
-impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
-        self.tcx
-    }
-}
-
 impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> {
     fn data_layout(&self) -> &ty::layout::TargetDataLayout {
         &self.shared.tcx.data_layout
     }
 }
 
-impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CrateContext<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
-        self.shared.tcx
-    }
-}
-
 impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
     type TyLayout = TyLayout<'tcx>;
 
-    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
-        if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) {
-            return TyLayout { ty: ty, layout: layout, variant_index: None };
-        }
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+        self.tcx
+    }
 
-        self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
-            infcx.layout_of(ty).unwrap_or_else(|e| {
-                match e {
-                    ty::layout::LayoutError::SizeOverflow(_) =>
-                        self.sess().fatal(&e.to_string()),
-                    _ => bug!("failed to get layout for `{}`: {}", ty, e)
-                }
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+        let param_env = ty::ParamEnv::empty(traits::Reveal::All);
+        LayoutCx::new(self.tcx, param_env)
+            .layout_of(ty)
+            .unwrap_or_else(|e| match e {
+                LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()),
+                _ => bug!("failed to get layout for `{}`: {}", ty, e)
             })
-        })
     }
 
     fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
@@ -754,6 +740,10 @@ fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
 impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
     type TyLayout = TyLayout<'tcx>;
 
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+        self.shared.tcx
+    }
+
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
         self.shared.layout_of(ty)
     }
@@ -942,6 +932,7 @@ macro_rules! mk_struct {
     ifn!("llvm.x86.seh.recoverfp", fn(i8p, i8p) -> i8p);
 
     ifn!("llvm.assume", fn(i1) -> void);
+    ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void);
 
     if ccx.sess().opts.debuginfo != NoDebugInfo {
         ifn!("llvm.dbg.declare", fn(Type::metadata(ccx), Type::metadata(ccx)) -> void);
index fa400b54d2708ed98b4d2e7f0d7df0bc54617ec9..367f0398fa838848a1a1902a5a2131f4d6f8f868 100644 (file)
@@ -46,15 +46,13 @@ pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>
         ty::TyAdt(def, _) if def.is_box() => {
             let typ = t.boxed_ty();
             if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) {
-                scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
-                    let layout = t.layout(&infcx).unwrap();
-                    if layout.size(scx).bytes() == 0 {
-                        // `Box<ZeroSizeType>` does not allocate.
-                        false
-                    } else {
-                        true
-                    }
-                })
+                let layout = t.layout(scx.tcx(), ty::ParamEnv::empty(traits::Reveal::All)).unwrap();
+                if layout.size(scx).bytes() == 0 {
+                    // `Box<ZeroSizeType>` does not allocate.
+                    false
+                } else {
+                    true
+                }
             } else {
                 true
             }
index 54e20f590c6718350bd22c1b4326402202f4cc63..f2e6aa3ef00b1b038fcc709c1619923574ade2d8 100644 (file)
@@ -255,7 +255,18 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             }
             C_nil(ccx)
         },
-
+        "prefetch_read_data" | "prefetch_write_data" |
+        "prefetch_read_instruction" | "prefetch_write_instruction" => {
+            let expect = ccx.get_intrinsic(&("llvm.prefetch"));
+            let (rw, cache_type) = match name {
+                "prefetch_read_data" => (0, 1),
+                "prefetch_write_data" => (1, 1),
+                "prefetch_read_instruction" => (0, 0),
+                "prefetch_write_instruction" => (1, 0),
+                _ => bug!()
+            };
+            bcx.call(expect, &[llargs[0], C_i32(ccx, rw), llargs[1], C_i32(ccx, cache_type)], None)
+        },
         "ctlz" | "cttz" | "ctpop" | "bswap" |
         "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
         "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
index c111a3983e7ea272e0b7c0c9957e2d906776f775..71fb2e5fb202a232302192bd475e4d68096a6b7b 100644 (file)
@@ -35,6 +35,7 @@
 #![feature(slice_patterns)]
 #![feature(unicode)]
 #![feature(conservative_impl_trait)]
+#![feature(command_envs)]
 
 #![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
 #![cfg_attr(stage0, feature(rustc_private))]
@@ -62,6 +63,8 @@
 extern crate syntax_pos;
 extern crate rustc_errors as errors;
 extern crate serialize;
+#[cfg(windows)]
+extern crate gcc; // Used to locate MSVC, not gcc :)
 
 pub use base::trans_crate;
 pub use back::symbol_names::provide;
@@ -77,8 +80,7 @@ pub mod back {
     pub(crate) mod symbol_export;
     pub(crate) mod symbol_names;
     pub mod write;
-    mod msvc;
-    mod rpath;
+    pub mod rpath;
 }
 
 mod diagnostics;
index bbe34f37950dc6b7b9238092cf87891785b01654..33f0b0282d173b878953ffe5dc2bf09aa840b453 100644 (file)
@@ -619,7 +619,8 @@ fn check_pat_tuple_struct(&self,
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
         // Replace constructor type with constructed type for tuple struct patterns.
-        let pat_ty = tcx.no_late_bound_regions(&pat_ty.fn_ret()).expect("expected fn type");
+        let pat_ty = pat_ty.fn_sig().output();
+        let pat_ty = tcx.no_late_bound_regions(&pat_ty).expect("expected fn type");
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
index 7d3a63263edbf9aad7d6f652a47b246fd4330b7d..6aac9dc42ee02bda67e747fb6738600259fc4116 100644 (file)
 use astconv::AstConv;
 
 use super::{FnCtxt, LvalueOp};
+use super::method::MethodCallee;
 
-use check::coercion::AsCoercionSite;
 use rustc::infer::InferOk;
 use rustc::traits;
 use rustc::ty::{self, Ty, TraitRef};
 use rustc::ty::{ToPredicate, TypeFoldable};
-use rustc::ty::{MethodCall, MethodCallee};
 use rustc::ty::{LvaluePreference, NoPreference};
-use rustc::hir;
+use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
 
 use syntax_pos::Span;
 use syntax::symbol::Symbol;
 
+use std::iter;
+
 #[derive(Copy, Clone, Debug)]
 enum AutoderefKind {
     Builtin,
@@ -117,13 +118,16 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
 
         let mut selcx = traits::SelectionContext::new(self.fcx);
-        let obligation = traits::Obligation::new(cause.clone(), trait_ref.to_predicate());
+        let obligation = traits::Obligation::new(cause.clone(),
+                                                 self.fcx.param_env,
+                                                 trait_ref.to_predicate());
         if !selcx.evaluate_obligation(&obligation) {
             debug!("overloaded_deref_ty: cannot match obligation");
             return None;
         }
 
         let normalized = traits::normalize_projection_type(&mut selcx,
+                                                           self.fcx.param_env,
                                                            ty::ProjectionTy::from_ref_and_name(
                                                                tcx,
                                                                trait_ref,
@@ -150,52 +154,59 @@ pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
         self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
     }
 
-    pub fn finalize(self, pref: LvaluePreference, expr: &hir::Expr) {
-        let fcx = self.fcx;
-        fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, &[expr]));
+    pub fn step_count(&self) -> usize {
+        self.steps.len()
+    }
+
+    /// Returns the adjustment steps.
+    pub fn adjust_steps(&self, pref: LvaluePreference)
+                        -> Vec<Adjustment<'tcx>> {
+        self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref))
     }
 
-    pub fn finalize_as_infer_ok<E>(self, pref: LvaluePreference, exprs: &[E])
-                                   -> InferOk<'tcx, ()>
-        where E: AsCoercionSite
-    {
-        let Autoderef { fcx, span, mut obligations, steps, .. } = self;
-        let methods: Vec<_> = steps
-            .iter()
-            .map(|&(ty, kind)| {
-                if let AutoderefKind::Overloaded = kind {
-                    fcx.try_overloaded_deref(span, None, ty, pref)
-                        .map(|InferOk { value, obligations: o }| {
-                            obligations.extend(o);
-                            value
-                        })
-                } else {
-                    None
-                }
-            })
-            .collect();
-
-        debug!("finalize({:?}) - {:?},{:?}",
-               pref,
-               methods,
-               obligations);
-
-        for expr in exprs {
-            let expr = expr.as_coercion_site();
-            debug!("finalize - finalizing #{} - {:?}", expr.id, expr);
-            for (n, method) in methods.iter().enumerate() {
-                if let &Some(method) = method {
-                    let method_call = MethodCall::autoderef(expr.id, n as u32);
-                    fcx.tables.borrow_mut().method_map.insert(method_call, method);
-                }
+    pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference)
+                                    -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
+        let mut obligations = vec![];
+        let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty)
+            .chain(iter::once(self.cur_ty));
+        let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| {
+            if let AutoderefKind::Overloaded = kind {
+                self.fcx.try_overloaded_deref(self.span, source, pref)
+                    .and_then(|InferOk { value: method, obligations: o }| {
+                        obligations.extend(o);
+                        if let ty::TyRef(region, mt) = method.sig.output().sty {
+                            Some(OverloadedDeref {
+                                region,
+                                mutbl: mt.mutbl,
+                            })
+                        } else {
+                            None
+                        }
+                    })
+            } else {
+                None
             }
-        }
+        }).zip(targets).map(|(autoderef, target)| {
+            Adjustment {
+                kind: Adjust::Deref(autoderef),
+                target
+            }
+        }).collect();
 
         InferOk {
-            value: (),
-            obligations
+            obligations,
+            value: steps
         }
     }
+
+    pub fn finalize(self) {
+        let fcx = self.fcx;
+        fcx.register_predicates(self.into_obligations());
+    }
+
+    pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
+        self.obligations
+    }
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
@@ -212,14 +223,9 @@ pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx,
 
     pub fn try_overloaded_deref(&self,
                                 span: Span,
-                                base_expr: Option<&hir::Expr>,
                                 base_ty: Ty<'tcx>,
                                 pref: LvaluePreference)
                                 -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        let rcvr = base_expr.map(|base_expr| super::AdjustedRcvr {
-            rcvr_expr: base_expr, autoderefs: 0, unsize: false
-        });
-
-        self.try_overloaded_lvalue_op(span, rcvr, base_ty, &[], pref, LvalueOp::Deref)
+        self.try_overloaded_lvalue_op(span, base_ty, &[], pref, LvalueOp::Deref)
     }
 }
index dde5f598a68329ec77a3e91c858fdcfb46575085..d5ee66a2f0a07e0fa5ee8f0c80cb6769a6d9c9fc 100644 (file)
@@ -8,13 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag};
+use super::{Expectation, FnCtxt, TupleArgumentsFlag};
+use super::autoderef::Autoderef;
+use super::method::MethodCallee;
 
 use hir::def::Def;
 use hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::{infer, traits};
 use rustc::ty::{self, TyCtxt, LvaluePreference, Ty};
 use rustc::ty::subst::Subst;
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use syntax::abi;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
@@ -33,9 +36,9 @@ pub fn check_legal_trait_for_method_call(tcx: TyCtxt, span: Span, trait_id: DefI
 }
 
 enum CallStep<'tcx> {
-    Builtin,
+    Builtin(Ty<'tcx>),
     DeferredClosure(ty::FnSig<'tcx>),
-    Overloaded(ty::MethodCallee<'tcx>),
+    Overloaded(MethodCallee<'tcx>),
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
@@ -49,13 +52,11 @@ pub fn check_call(&self,
         let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
 
         let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
-        let result = autoderef.by_ref()
-            .flat_map(|(adj_ty, idx)| {
-                self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
-            })
-            .next();
-        let callee_ty = autoderef.unambiguous_final_ty();
-        autoderef.finalize(LvaluePreference::NoPreference, callee_expr);
+        let mut result = None;
+        while result.is_none() && autoderef.next().is_some() {
+            result = self.try_overloaded_call_step(call_expr, callee_expr, &autoderef);
+        }
+        autoderef.finalize();
 
         let output = match result {
             None => {
@@ -63,7 +64,7 @@ pub fn check_call(&self,
                 self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected)
             }
 
-            Some(CallStep::Builtin) => {
+            Some(CallStep::Builtin(callee_ty)) => {
                 self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected)
             }
 
@@ -72,11 +73,7 @@ pub fn check_call(&self,
             }
 
             Some(CallStep::Overloaded(method_callee)) => {
-                self.confirm_overloaded_call(call_expr,
-                                             callee_expr,
-                                             arg_exprs,
-                                             expected,
-                                             method_callee)
+                self.confirm_overloaded_call(call_expr, arg_exprs, expected, method_callee)
             }
         };
 
@@ -89,19 +86,19 @@ pub fn check_call(&self,
     fn try_overloaded_call_step(&self,
                                 call_expr: &'gcx hir::Expr,
                                 callee_expr: &'gcx hir::Expr,
-                                adjusted_ty: Ty<'tcx>,
-                                autoderefs: usize)
+                                autoderef: &Autoderef<'a, 'gcx, 'tcx>)
                                 -> Option<CallStep<'tcx>> {
-        debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
+        let adjusted_ty = autoderef.unambiguous_final_ty();
+        debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
                call_expr,
-               adjusted_ty,
-               autoderefs);
+               adjusted_ty);
 
         // If the callee is a bare function or a closure, then we're all set.
-        match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty {
+        match adjusted_ty.sty {
             ty::TyFnDef(..) | ty::TyFnPtr(_) => {
-                self.apply_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty);
-                return Some(CallStep::Builtin);
+                let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
+                self.apply_adjustments(callee_expr, adjustments);
+                return Some(CallStep::Builtin(adjusted_ty));
             }
 
             ty::TyClosure(def_id, substs) => {
@@ -116,15 +113,15 @@ fn try_overloaded_call_step(&self,
                                                                    infer::FnCall,
                                                                    &closure_ty)
                         .0;
-                    self.record_deferred_call_resolution(def_id,
-                                                         Box::new(CallResolution {
-                                                             call_expr: call_expr,
-                                                             callee_expr: callee_expr,
-                                                             adjusted_ty: adjusted_ty,
-                                                             autoderefs: autoderefs,
-                                                             fn_sig: fn_sig.clone(),
-                                                             closure_def_id: def_id,
-                                                         }));
+                    let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
+                    self.record_deferred_call_resolution(def_id, DeferredCallResolution {
+                        call_expr,
+                        callee_expr,
+                        adjusted_ty,
+                        adjustments,
+                        fn_sig,
+                        closure_def_id: def_id,
+                    });
                     return Some(CallStep::DeferredClosure(fn_sig));
                 }
             }
@@ -137,47 +134,54 @@ fn try_overloaded_call_step(&self,
             // over the top. The simplest fix by far is to just ignore
             // this case and deref again, so we wind up with
             // `FnMut::call_mut(&mut *x, ())`.
-            ty::TyRef(..) if autoderefs == 0 => {
+            ty::TyRef(..) if autoderef.step_count() == 0 => {
                 return None;
             }
 
             _ => {}
         }
 
-        self.try_overloaded_call_traits(call_expr, callee_expr, adjusted_ty, autoderefs)
-            .map(|method_callee| CallStep::Overloaded(method_callee))
+        self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| {
+            let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
+            adjustments.extend(autoref);
+            self.apply_adjustments(callee_expr, adjustments);
+            CallStep::Overloaded(method)
+        })
     }
 
     fn try_overloaded_call_traits(&self,
                                   call_expr: &hir::Expr,
-                                  callee_expr: &hir::Expr,
-                                  adjusted_ty: Ty<'tcx>,
-                                  autoderefs: usize)
-                                  -> Option<ty::MethodCallee<'tcx>> {
+                                  adjusted_ty: Ty<'tcx>)
+                                  -> Option<(Option<Adjustment<'tcx>>,
+                                             MethodCallee<'tcx>)> {
         // Try the options that are least restrictive on the caller first.
-        for &(opt_trait_def_id, method_name) in
-            &[(self.tcx.lang_items.fn_trait(), Symbol::intern("call")),
-              (self.tcx.lang_items.fn_mut_trait(), Symbol::intern("call_mut")),
-              (self.tcx.lang_items.fn_once_trait(), Symbol::intern("call_once"))] {
+        for &(opt_trait_def_id, method_name, borrow) in
+            &[(self.tcx.lang_items.fn_trait(), Symbol::intern("call"), true),
+              (self.tcx.lang_items.fn_mut_trait(), Symbol::intern("call_mut"), true),
+              (self.tcx.lang_items.fn_once_trait(), Symbol::intern("call_once"), false)] {
             let trait_def_id = match opt_trait_def_id {
                 Some(def_id) => def_id,
                 None => continue,
             };
 
-            match self.lookup_method_in_trait_adjusted(call_expr.span,
-                                                       Some(super::AdjustedRcvr {
-                                                           rcvr_expr: callee_expr,
-                                                           autoderefs,
-                                                           unsize: false
-                                                       }),
-                                                       method_name,
-                                                       trait_def_id,
-                                                       adjusted_ty,
-                                                       None) {
+            match self.lookup_method_in_trait(call_expr.span,
+                                              method_name,
+                                              trait_def_id,
+                                              adjusted_ty,
+                                              None) {
                 None => continue,
                 Some(ok) => {
-                    let method_callee = self.register_infer_ok_obligations(ok);
-                    return Some(method_callee);
+                    let method = self.register_infer_ok_obligations(ok);
+                    let mut autoref = None;
+                    if borrow {
+                        if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
+                            autoref = Some(Adjustment {
+                                kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
+                                target: method.sig.inputs()[0]
+                            });
+                        }
+                    }
+                    return Some((autoref, method));
                 }
             }
         }
@@ -301,42 +305,33 @@ fn confirm_deferred_closure_call(&self,
 
     fn confirm_overloaded_call(&self,
                                call_expr: &hir::Expr,
-                               callee_expr: &'gcx hir::Expr,
                                arg_exprs: &'gcx [hir::Expr],
                                expected: Expectation<'tcx>,
-                               method_callee: ty::MethodCallee<'tcx>)
+                               method_callee: MethodCallee<'tcx>)
                                -> Ty<'tcx> {
         let output_type = self.check_method_argument_types(call_expr.span,
-                                                           method_callee.ty,
-                                                           callee_expr,
+                                                           Ok(method_callee),
                                                            arg_exprs,
                                                            TupleArgumentsFlag::TupleArguments,
                                                            expected);
 
-        self.write_overloaded_call_method_map(call_expr, method_callee);
+        self.write_method_call(call_expr.id, method_callee);
         output_type
     }
-
-    fn write_overloaded_call_method_map(&self,
-                                        call_expr: &hir::Expr,
-                                        method_callee: ty::MethodCallee<'tcx>) {
-        let method_call = ty::MethodCall::expr(call_expr.id);
-        self.tables.borrow_mut().method_map.insert(method_call, method_callee);
-    }
 }
 
 #[derive(Debug)]
-struct CallResolution<'gcx: 'tcx, 'tcx> {
+pub struct DeferredCallResolution<'gcx: 'tcx, 'tcx> {
     call_expr: &'gcx hir::Expr,
     callee_expr: &'gcx hir::Expr,
     adjusted_ty: Ty<'tcx>,
-    autoderefs: usize,
+    adjustments: Vec<Adjustment<'tcx>>,
     fn_sig: ty::FnSig<'tcx>,
     closure_def_id: DefId,
 }
 
-impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tcx> {
-    fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
+impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
+    pub fn resolve(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
         debug!("DeferredCallResolution::resolve() {:?}", self);
 
         // we should not be invoked until the closure kind has been
@@ -345,10 +340,8 @@ fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
 
         // We may now know enough to figure out fn vs fnmut etc.
         match fcx.try_overloaded_call_traits(self.call_expr,
-                                             self.callee_expr,
-                                             self.adjusted_ty,
-                                             self.autoderefs) {
-            Some(method_callee) => {
+                                             self.adjusted_ty) {
+            Some((autoref, method_callee)) => {
                 // One problem is that when we get here, we are going
                 // to have a newly instantiated function signature
                 // from the call trait. This has to be reconciled with
@@ -357,9 +350,7 @@ fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
                 // can't because of the annoying need for a TypeTrace.
                 // (This always bites me, should find a way to
                 // refactor it.)
-                let method_sig = fcx.tcx
-                    .no_late_bound_regions(&method_callee.ty.fn_sig())
-                    .unwrap();
+                let method_sig = method_callee.sig;
 
                 debug!("attempt_resolution: method_callee={:?}", method_callee);
 
@@ -370,7 +361,11 @@ fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
 
                 fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output());
 
-                fcx.write_overloaded_call_method_map(self.call_expr, method_callee);
+                let mut adjustments = self.adjustments;
+                adjustments.extend(autoref);
+                fcx.apply_adjustments(self.callee_expr, adjustments);
+
+                fcx.write_method_call(self.call_expr.id, method_callee);
             }
             None => {
                 span_bug!(self.call_expr.span,
index 72ce7d3b5ed711abe4cb6539cd5380fb19108af9..91aeade65aa4c2b57a5ffd1f7d263845c769cc69 100644 (file)
@@ -555,6 +555,6 @@ fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn type_is_known_to_be_sized(&self, ty: Ty<'tcx>, span: Span) -> bool {
         let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem);
-        traits::type_known_to_meet_bound(self, ty, lang_item, span)
+        traits::type_known_to_meet_bound(self, self.param_env, ty, lang_item, span)
     }
 }
index c2e8269aafef94091e5b2c437c6bb78cc3879713..f041db43e16d757c1e80bddceea92e1cba623fbb 100644 (file)
@@ -81,9 +81,11 @@ fn check_closure(&self,
 
         let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig);
         let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
-                                                            body.value.id, &fn_sig);
+                                                            body.value.id,
+                                                            self.param_env,
+                                                            &fn_sig);
 
-        check_fn(self, fn_sig, decl, expr.id, body);
+        check_fn(self, self.param_env, fn_sig, decl, expr.id, body);
 
         // Tuple up the arguments and insert the resulting function type into
         // the `closures` table.
index 883a0a9d88a1c083d94170415aaff3aa0004ce8a..30ac7b4bfb9be8d14a4c069e48c6b81184598324 100644 (file)
@@ -64,7 +64,7 @@
 
 use rustc::hir;
 use rustc::hir::def_id::DefId;
-use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace};
+use rustc::infer::{Coercion, InferResult, InferOk};
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
@@ -95,7 +95,7 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>;
+type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
 
 fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
                        to_mutbl: hir::Mutability)
@@ -108,23 +108,18 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
     }
 }
 
-fn identity<'tcx>() -> Adjust<'tcx> {
-    Adjust::DerefRef {
-        autoderefs: 0,
-        autoref: None,
-        unsize: false,
-    }
+fn identity(_: Ty) -> Vec<Adjustment> { vec![] }
+
+fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
+    move |target| vec![Adjustment { kind, target }]
 }
 
-fn success<'tcx>(kind: Adjust<'tcx>,
+fn success<'tcx>(adj: Vec<Adjustment<'tcx>>,
                  target: Ty<'tcx>,
                  obligations: traits::PredicateObligations<'tcx>)
                  -> CoerceResult<'tcx> {
     Ok(InferOk {
-        value: Adjustment {
-            kind,
-            target
-        },
+        value: (adj, target),
         obligations
     })
 }
@@ -140,36 +135,34 @@ fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self {
 
     fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
         self.commit_if_ok(|_| {
-            let trace = TypeTrace::types(&self.cause, false, a, b);
             if self.use_lub {
-                self.lub(false, trace, &a, &b)
+                self.at(&self.cause, self.fcx.param_env)
+                    .lub(b, a)
             } else {
-                self.sub(false, trace, &a, &b)
+                self.at(&self.cause, self.fcx.param_env)
+                    .sup(b, a)
+                    .map(|InferOk { value: (), obligations }| InferOk { value: a, obligations })
             }
         })
     }
 
     /// Unify two types (using sub or lub) and produce a specific coercion.
-    fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, kind: Adjust<'tcx>)
-                 -> CoerceResult<'tcx> {
+    fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F)
+                    -> CoerceResult<'tcx>
+        where F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>
+    {
         self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| {
-            success(kind, ty, obligations)
+            success(f(ty), ty, obligations)
         })
     }
 
-    fn coerce<E>(&self,
-                 exprs: &[E],
-                 a: Ty<'tcx>,
-                 b: Ty<'tcx>)
-                 -> CoerceResult<'tcx>
-        where E: AsCoercionSite
-    {
+    fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
         let a = self.shallow_resolve(a);
         debug!("Coerce.tys({:?} => {:?})", a, b);
 
         // Just ignore error types.
         if a.references_error() || b.references_error() {
-            return success(identity(), b, vec![]);
+            return success(vec![], b, vec![]);
         }
 
         if a.is_never() {
@@ -186,9 +179,9 @@ fn coerce<E>(&self,
                 // already resolved in some way.
                 let diverging_ty = self.next_diverging_ty_var(
                     TypeVariableOrigin::AdjustmentType(self.cause.span));
-                self.unify_and(&b, &diverging_ty, Adjust::NeverToAny)
+                self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
             } else {
-                success(Adjust::NeverToAny, b, vec![])
+                success(simple(Adjust::NeverToAny)(b), b, vec![])
             };
         }
 
@@ -210,7 +203,7 @@ fn coerce<E>(&self,
             }
 
             ty::TyRef(r_b, mt_b) => {
-                return self.coerce_borrowed_pointer(exprs, a, b, r_b, mt_b);
+                return self.coerce_borrowed_pointer(a, b, r_b, mt_b);
             }
 
             _ => {}
@@ -237,7 +230,7 @@ fn coerce<E>(&self,
             }
             _ => {
                 // Otherwise, just use unification rules.
-                self.unify_and(a, b, identity())
+                self.unify_and(a, b, identity)
             }
         }
     }
@@ -245,15 +238,12 @@ fn coerce<E>(&self,
     /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
     /// To match `A` with `B`, autoderef will be performed,
     /// calling `deref`/`deref_mut` where necessary.
-    fn coerce_borrowed_pointer<E>(&self,
-                                  exprs: &[E],
-                                  a: Ty<'tcx>,
-                                  b: Ty<'tcx>,
-                                  r_b: ty::Region<'tcx>,
-                                  mt_b: TypeAndMut<'tcx>)
-                                  -> CoerceResult<'tcx>
-        where E: AsCoercionSite
-    {
+    fn coerce_borrowed_pointer(&self,
+                               a: Ty<'tcx>,
+                               b: Ty<'tcx>,
+                               r_b: ty::Region<'tcx>,
+                               mt_b: TypeAndMut<'tcx>)
+                               -> CoerceResult<'tcx> {
 
         debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
 
@@ -268,7 +258,7 @@ fn coerce_borrowed_pointer<E>(&self,
                 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
                 (r_a, mt_a)
             }
-            _ => return self.unify_and(a, b, identity()),
+            _ => return self.unify_and(a, b, identity),
         };
 
         let span = self.cause.span;
@@ -375,7 +365,7 @@ fn coerce_borrowed_pointer<E>(&self,
                                               });
             match self.unify(derefd_ty_a, b) {
                 Ok(ok) => {
-                    found = Some((ok, autoderefs));
+                    found = Some(ok);
                     break;
                 }
                 Err(err) => {
@@ -391,7 +381,7 @@ fn coerce_borrowed_pointer<E>(&self,
         // (e.g., in example above, the failure from relating `Vec<T>`
         // to the target type), since that should be the least
         // confusing.
-        let (InferOk { value: ty, mut obligations }, autoderefs) = match found {
+        let InferOk { value: ty, mut obligations } = match found {
             Some(d) => d,
             None => {
                 let err = first_error.expect("coerce_borrowed_pointer had no error");
@@ -400,7 +390,7 @@ fn coerce_borrowed_pointer<E>(&self,
             }
         };
 
-        if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 {
+        if ty == a && mt_a.mutbl == hir::MutImmutable && autoderef.step_count() == 1 {
             // As a special case, if we would produce `&'a *x`, that's
             // a total no-op. We end up with the type `&'a T` just as
             // we started with.  In that case, just skip it
@@ -413,29 +403,31 @@ fn coerce_borrowed_pointer<E>(&self,
             // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
             // which is a borrow.
             assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U
-            return success(identity(), ty, obligations);
+            return success(vec![], ty, obligations);
         }
 
+        let pref = LvaluePreference::from_mutbl(mt_b.mutbl);
+        let InferOk { value: mut adjustments, obligations: o }
+            = autoderef.adjust_steps_as_infer_ok(pref);
+        obligations.extend(o);
+        obligations.extend(autoderef.into_obligations());
+
         // Now apply the autoref. We have to extract the region out of
         // the final ref type we got.
         let r_borrow = match ty.sty {
             ty::TyRef(r_borrow, _) => r_borrow,
             _ => span_bug!(span, "expected a ref type, got {:?}", ty),
         };
-        let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl));
-        debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}",
-               ty,
-               autoderefs,
-               autoref);
+        adjustments.push(Adjustment {
+            kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)),
+            target: ty
+        });
 
-        let pref = LvaluePreference::from_mutbl(mt_b.mutbl);
-        obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs).obligations);
+        debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}",
+               ty,
+               adjustments);
 
-        success(Adjust::DerefRef {
-            autoderefs: autoderefs,
-            autoref: autoref,
-            unsize: false,
-        }, ty, obligations)
+        success(adjustments, ty, obligations)
     }
 
 
@@ -460,27 +452,40 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
         // that, at which point we will need extra checks on the target here.
 
         // Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
-        let (source, reborrow) = match (&source.sty, &target.sty) {
+        let reborrow = match (&source.sty, &target.sty) {
             (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
                 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
 
                 let coercion = Coercion(self.cause.span);
                 let r_borrow = self.next_region_var(coercion);
-                (mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)))
+                Some((Adjustment {
+                    kind: Adjust::Deref(None),
+                    target: mt_a.ty
+                }, Adjustment {
+                    kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)),
+                    target:  self.tcx.mk_ref(r_borrow, ty::TypeAndMut {
+                        mutbl: mt_b.mutbl,
+                        ty: mt_a.ty
+                    })
+                }))
             }
             (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
                 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
-                (mt_a.ty, Some(AutoBorrow::RawPtr(mt_b.mutbl)))
-            }
-            _ => (source, None),
-        };
-        let coerce_source = source.adjust_for_autoref(self.tcx, reborrow);
 
-        let adjust = Adjust::DerefRef {
-            autoderefs: if reborrow.is_some() { 1 } else { 0 },
-            autoref: reborrow,
-            unsize: true,
+                Some((Adjustment {
+                    kind: Adjust::Deref(None),
+                    target: mt_a.ty
+                }, Adjustment {
+                    kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b.mutbl)),
+                    target:  self.tcx.mk_ptr(ty::TypeAndMut {
+                        mutbl: mt_b.mutbl,
+                        ty: mt_a.ty
+                    })
+                }))
+            }
+            _ => None,
         };
+        let coerce_source = reborrow.as_ref().map_or(source, |&(_, ref r)| r.target);
 
         // Setup either a subtyping or a LUB relationship between
         // the `CoerceUnsized` target type and the expected type.
@@ -488,7 +493,18 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
         // for the former and let type inference do the rest.
         let origin = TypeVariableOrigin::MiscVariable(self.cause.span);
         let coerce_target = self.next_ty_var(origin);
-        let mut coercion = self.unify_and(coerce_target, target, adjust)?;
+        let mut coercion = self.unify_and(coerce_target, target, |target| {
+            let unsize = Adjustment {
+                kind: Adjust::Unsize,
+                target
+            };
+            match reborrow {
+                None => vec![unsize],
+                Some((ref deref, ref autoref)) => {
+                    vec![deref.clone(), autoref.clone(), unsize]
+                }
+            }
+        })?;
 
         let mut selcx = traits::SelectionContext::new(self);
 
@@ -497,9 +513,12 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
 
         // Create an obligation for `Source: CoerceUnsized<Target>`.
         let cause = ObligationCause::misc(self.cause.span, self.body_id);
-        queue.push_back(self.tcx
-            .predicate_for_trait_def(cause, coerce_unsized_did, 0,
-                                     coerce_source, &[coerce_target]));
+        queue.push_back(self.tcx.predicate_for_trait_def(self.fcx.param_env,
+                                                         cause,
+                                                         coerce_unsized_did,
+                                                         0,
+                                                         coerce_source,
+                                                         &[coerce_target]));
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -541,13 +560,16 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
         Ok(coercion)
     }
 
-    fn coerce_from_safe_fn(&self,
-                           a: Ty<'tcx>,
-                           fn_ty_a: ty::PolyFnSig<'tcx>,
-                           b: Ty<'tcx>,
-                           to_unsafe: Adjust<'tcx>,
-                           normal: Adjust<'tcx>)
-                           -> CoerceResult<'tcx> {
+    fn coerce_from_safe_fn<F, G>(&self,
+                                 a: Ty<'tcx>,
+                                 fn_ty_a: ty::PolyFnSig<'tcx>,
+                                 b: Ty<'tcx>,
+                                 to_unsafe: F,
+                                 normal: G)
+                                 -> CoerceResult<'tcx>
+        where F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
+              G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>
+    {
         if let ty::TyFnPtr(fn_ty_b) = b.sty {
             match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) {
                 (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
@@ -573,7 +595,7 @@ fn coerce_from_fn_pointer(&self,
         debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
 
         self.coerce_from_safe_fn(a, fn_ty_a, b,
-            Adjust::UnsafeFnPointer, identity())
+            simple(Adjust::UnsafeFnPointer), identity)
     }
 
     fn coerce_from_fn_item(&self,
@@ -592,9 +614,9 @@ fn coerce_from_fn_item(&self,
             ty::TyFnPtr(_) => {
                 let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
                 self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b,
-                    Adjust::ReifyFnPointer, Adjust::ReifyFnPointer)
+                    simple(Adjust::ReifyFnPointer), simple(Adjust::ReifyFnPointer))
             }
-            _ => self.unify_and(a, b, identity()),
+            _ => self.unify_and(a, b, identity),
         }
     }
 
@@ -636,9 +658,9 @@ fn coerce_closure_to_fn(&self,
                 let pointer_ty = self.tcx.mk_fn_ptr(converted_sig);
                 debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})",
                        a, b, pointer_ty);
-                self.unify_and(pointer_ty, b, Adjust::ClosureFnPointer)
+                self.unify_and(pointer_ty, b, simple(Adjust::ClosureFnPointer))
             }
-            _ => self.unify_and(a, b, identity()),
+            _ => self.unify_and(a, b, identity),
         }
     }
 
@@ -653,7 +675,7 @@ fn coerce_unsafe_ptr(&self,
             ty::TyRef(_, mt) => (true, mt),
             ty::TyRawPtr(mt) => (false, mt),
             _ => {
-                return self.unify_and(a, b, identity());
+                return self.unify_and(a, b, identity);
             }
         };
 
@@ -666,17 +688,21 @@ fn coerce_unsafe_ptr(&self,
         // Although references and unsafe ptrs have the same
         // representation, we still register an Adjust::DerefRef so that
         // regionck knows that the region for `a` must be valid here.
-        self.unify_and(a_unsafe, b, if is_ref {
-            Adjust::DerefRef {
-                autoderefs: 1,
-                autoref: Some(AutoBorrow::RawPtr(mutbl_b)),
-                unsize: false,
-            }
+        if is_ref {
+            self.unify_and(a_unsafe, b, |target| {
+                vec![Adjustment {
+                    kind: Adjust::Deref(None),
+                    target: mt_a.ty
+                }, Adjustment {
+                    kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)),
+                    target
+                }]
+            })
         } else if mt_a.mutbl != mutbl_b {
-            Adjust::MutToConstPointer
+            self.unify_and(a_unsafe, b, simple(Adjust::MutToConstPointer))
         } else {
-            identity()
-        })
+            self.unify_and(a_unsafe, b, identity)
+        }
     }
 }
 
@@ -703,14 +729,10 @@ pub fn try_coerce(&self,
 
         let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
         let coerce = Coerce::new(self, cause);
-        let ok = self.commit_if_ok(|_| coerce.coerce(&[expr], source, target))?;
-
-        let adjustment = self.register_infer_ok_obligations(ok);
-        self.apply_adjustment(expr.id, adjustment);
+        let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
 
-        // We should now have added sufficient adjustments etc to
-        // ensure that the type of expression, post-adjustment, is
-        // a subtype of target.
+        let (adjustments, _) = self.register_infer_ok_obligations(ok);
+        self.apply_adjustments(expr, adjustments);
         Ok(target)
     }
 
@@ -721,7 +743,7 @@ pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
 
         let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
         let coerce = Coerce::new(self, cause);
-        self.probe(|_| coerce.coerce::<hir::Expr>(&[], source, target)).is_ok()
+        self.probe(|_| coerce.coerce(source, target)).is_ok()
     }
 
     /// Given some expressions, their known unified type and another expression,
@@ -751,20 +773,22 @@ fn try_find_coercion_lub<E>(&self,
             return Ok(prev_ty);
         }
 
-        let trace = TypeTrace::types(cause, true, prev_ty, new_ty);
-
         // Special-case that coercion alone cannot handle:
         // Two function item types of differing IDs or Substs.
         match (&prev_ty.sty, &new_ty.sty) {
             (&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
                 // The signature must always match.
-                let fty = self.lub(true, trace.clone(), &a_fty, &b_fty)
+                let fty = self.at(cause, self.param_env)
+                              .trace(prev_ty, new_ty)
+                              .lub(&a_fty, &b_fty)
                               .map(|ok| self.register_infer_ok_obligations(ok))?;
 
                 if a_def_id == b_def_id {
                     // Same function, maybe the parameters match.
                     let substs = self.commit_if_ok(|_| {
-                        self.lub(true, trace.clone(), &a_substs, &b_substs)
+                        self.at(cause, self.param_env)
+                            .trace(prev_ty, new_ty)
+                            .lub(&a_substs, &b_substs)
                             .map(|ok| self.register_infer_ok_obligations(ok))
                     });
 
@@ -779,10 +803,10 @@ fn try_find_coercion_lub<E>(&self,
                 for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) {
                     // The only adjustment that can produce an fn item is
                     // `NeverToAny`, so this should always be valid.
-                    self.apply_adjustment(expr.id, Adjustment {
+                    self.apply_adjustments(expr, vec![Adjustment {
                         kind: Adjust::ReifyFnPointer,
                         target: fn_ptr
-                    });
+                    }]);
                 }
                 return Ok(fn_ptr);
             }
@@ -796,12 +820,12 @@ fn try_find_coercion_lub<E>(&self,
         // but only if the new expression has no coercion already applied to it.
         let mut first_error = None;
         if !self.tables.borrow().adjustments.contains_key(&new.id) {
-            let result = self.commit_if_ok(|_| coerce.coerce(&[new], new_ty, prev_ty));
+            let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty));
             match result {
                 Ok(ok) => {
-                    let adjustment = self.register_infer_ok_obligations(ok);
-                    self.apply_adjustment(new.id, adjustment);
-                    return Ok(adjustment.target);
+                    let (adjustments, target) = self.register_infer_ok_obligations(ok);
+                    self.apply_adjustments(new, adjustments);
+                    return Ok(target);
                 }
                 Err(e) => first_error = Some(e),
             }
@@ -812,54 +836,54 @@ fn try_find_coercion_lub<E>(&self,
         // previous expressions, other than noop reborrows (ignoring lifetimes).
         for expr in exprs {
             let expr = expr.as_coercion_site();
-            let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| adj.kind) {
-                Some(Adjust::DerefRef {
-                    autoderefs: 1,
-                    autoref: Some(AutoBorrow::Ref(_, mutbl_adj)),
-                    unsize: false
-                }) => {
+            let noop = match self.tables.borrow().expr_adjustments(expr) {
+                &[
+                    Adjustment { kind: Adjust::Deref(_), .. },
+                    Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. }
+                ] => {
                     match self.node_ty(expr.id).sty {
                         ty::TyRef(_, mt_orig) => {
                             // Reborrow that we can safely ignore, because
-                            // the next adjustment can only be a DerefRef
+                            // the next adjustment can only be a Deref
                             // which will be merged into it.
                             mutbl_adj == mt_orig.mutbl
                         }
                         _ => false,
                     }
                 }
-                Some(Adjust::NeverToAny) => true,
-                Some(_) => false,
-                None => true,
+                &[Adjustment { kind: Adjust::NeverToAny, .. }] | &[] => true,
+                _ => false,
             };
 
             if !noop {
                 return self.commit_if_ok(|_| {
-                    self.lub(true, trace.clone(), &prev_ty, &new_ty)
+                    self.at(cause, self.param_env)
+                        .lub(prev_ty, new_ty)
                         .map(|ok| self.register_infer_ok_obligations(ok))
                 });
             }
         }
 
-        match self.commit_if_ok(|_| coerce.coerce(&exprs, prev_ty, new_ty)) {
+        match self.commit_if_ok(|_| coerce.coerce(prev_ty, new_ty)) {
             Err(_) => {
                 // Avoid giving strange errors on failed attempts.
                 if let Some(e) = first_error {
                     Err(e)
                 } else {
                     self.commit_if_ok(|_| {
-                        self.lub(true, trace, &prev_ty, &new_ty)
+                        self.at(cause, self.param_env)
+                            .lub(prev_ty, new_ty)
                             .map(|ok| self.register_infer_ok_obligations(ok))
                     })
                 }
             }
             Ok(ok) => {
-                let adjustment = self.register_infer_ok_obligations(ok);
+                let (adjustments, target) = self.register_infer_ok_obligations(ok);
                 for expr in exprs {
                     let expr = expr.as_coercion_site();
-                    self.apply_adjustment(expr.id, adjustment);
+                    self.apply_adjustments(expr, adjustments.clone());
                 }
-                Ok(adjustment.target)
+                Ok(target)
             }
         }
     }
@@ -1091,7 +1115,8 @@ fn coerce_inner<'a>(&mut self,
             // Another example is `break` with no argument expression.
             assert!(expression_ty.is_nil());
             assert!(expression_ty.is_nil(), "if let hack without unit type");
-            fcx.eq_types(label_expression_as_expected, cause, expression_ty, self.merged_ty())
+            fcx.at(cause, fcx.param_env)
+               .eq_exp(label_expression_as_expected, expression_ty, self.merged_ty())
                .map(|infer_ok| {
                    fcx.register_infer_ok_obligations(infer_ok);
                    expression_ty
index 3121f4948504eb71dffda0b45a99680996788d11..8b76431fd2e6519f0b2a48db04a96f1d81556cb5 100644 (file)
@@ -212,18 +212,19 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // The key step here is to update the caller_bounds's predicates to be
     // the new hybrid bounds we computed.
     let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id);
-    let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates));
+    let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates),
+                                      Reveal::UserFacing);
     let param_env = traits::normalize_param_env_or_error(tcx,
                                                          impl_m.def_id,
                                                          param_env,
                                                          normalize_cause.clone());
 
-    tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
+    tcx.infer_ctxt(()).enter(|infcx| {
         let inh = Inherited::new(infcx, impl_m.def_id);
         let infcx = &inh.infcx;
 
         debug!("compare_impl_method: caller_bounds={:?}",
-               infcx.param_env.caller_bounds);
+               param_env.caller_bounds);
 
         let mut selcx = traits::SelectionContext::new(&infcx);
 
@@ -233,10 +234,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                        &ty::Binder(impl_m_own_bounds.predicates));
         for predicate in impl_m_own_bounds {
             let traits::Normalized { value: predicate, obligations } =
-                traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
+                traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate);
 
             inh.register_predicates(obligations);
-            inh.register_predicate(traits::Obligation::new(cause.clone(), predicate));
+            inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
         }
 
         // We now need to check that the signature of the impl method is
@@ -269,6 +270,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let impl_sig =
             inh.normalize_associated_types_in(impl_m_span,
                                               impl_m_node_id,
+                                              param_env,
                                               &impl_sig);
         let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig));
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
@@ -281,12 +283,14 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let trait_sig =
             inh.normalize_associated_types_in(impl_m_span,
                                               impl_m_node_id,
+                                              param_env,
                                               &trait_sig);
         let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig));
 
         debug!("compare_impl_method: trait_fty={:?}", trait_fty);
 
-        let sub_result = infcx.sub_types(false, &cause, impl_fty, trait_fty)
+        let sub_result = infcx.at(&cause, param_env)
+                              .sup(trait_fty, impl_fty)
                               .map(|InferOk { obligations, .. }| {
                                   inh.register_predicates(obligations);
                               });
@@ -297,6 +301,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                    trait_fty);
 
             let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx,
+                                                                                    param_env,
                                                                                     &terr,
                                                                                     &cause,
                                                                                     impl_m,
@@ -344,11 +349,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // pass around temporarily.
             let region_maps = RegionMaps::new();
             let mut free_regions = FreeRegionMap::new();
-            free_regions.relate_free_regions_from_predicates(
-                &infcx.param_env.caller_bounds);
+            free_regions.relate_free_regions_from_predicates(&param_env.caller_bounds);
             infcx.resolve_regions_and_report_errors(impl_m.def_id, &region_maps, &free_regions);
         } else {
-            let fcx = FnCtxt::new(&inh, impl_m_node_id);
+            let fcx = FnCtxt::new(&inh, param_env, impl_m_node_id);
             fcx.regionck_item(impl_m_node_id, impl_m_span, &[]);
         }
 
@@ -399,6 +403,7 @@ trait declaration",
 }
 
 fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
+                                                     param_env: ty::ParamEnv<'tcx>,
                                                      terr: &TypeError,
                                                      cause: &ObligationCause<'tcx>,
                                                      impl_m: &ty::AssociatedItem,
@@ -456,21 +461,23 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                 impl_iter.zip(trait_iter)
                          .zip(impl_m_iter)
                          .zip(trait_m_iter)
-                         .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
-                             match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) {
+                         .filter_map(|(((&impl_arg_ty, &trait_arg_ty), impl_arg), trait_arg)| {
+                             match infcx.at(&cause, param_env).sub(trait_arg_ty, impl_arg_ty) {
                                  Ok(_) => None,
                                  Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
                              }
                          })
                          .next()
                          .unwrap_or_else(|| {
-                             if infcx.sub_types(false, &cause, impl_sig.output(),
-                                                trait_sig.output())
-                                     .is_err() {
-                                         (impl_m_output.span(), Some(trait_m_output.span()))
-                                     } else {
-                                         (cause.span, tcx.hir.span_if_local(trait_m.def_id))
-                                     }
+                             if
+                                 infcx.at(&cause, param_env)
+                                      .sup(trait_sig.output(), impl_sig.output())
+                                      .is_err()
+                             {
+                                 (impl_m_output.span(), Some(trait_m_output.span()))
+                             } else {
+                                 (cause.span, tcx.hir.span_if_local(trait_m.def_id))
+                             }
                          })
             } else {
                 (cause.span, tcx.hir.span_if_local(trait_m.def_id))
@@ -543,6 +550,9 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            format!("expected `{}` in impl", self_descr));
             if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
                 err.span_label(span, format!("`{}` used in trait", self_descr));
+            } else {
+                err.note_trait_signature(trait_m.name.to_string(),
+                                         trait_m.signature(&tcx));
             }
             err.emit();
             return Err(ErrorReported);
@@ -690,6 +700,9 @@ trait `{}` has {}",
                                     } else {
                                         format!("{} parameter", trait_number_args)
                                     }));
+        } else {
+            err.note_trait_signature(trait_m.name.to_string(),
+                                     trait_m.signature(&tcx));
         }
         err.span_label(impl_span,
                        format!("expected {}, found {}",
@@ -713,7 +726,8 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     impl_trait_ref: ty::TraitRef<'tcx>) {
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
-    tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+    tcx.infer_ctxt(()).enter(|infcx| {
+        let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
         let inh = Inherited::new(infcx, impl_c.def_id);
         let infcx = &inh.infcx;
 
@@ -736,18 +750,21 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // There is no "body" here, so just pass dummy id.
         let impl_ty = inh.normalize_associated_types_in(impl_c_span,
                                                         impl_c_node_id,
+                                                        param_env,
                                                         &impl_ty);
 
         debug!("compare_const_impl: impl_ty={:?}", impl_ty);
 
         let trait_ty = inh.normalize_associated_types_in(impl_c_span,
                                                          impl_c_node_id,
+                                                         param_env,
                                                          &trait_ty);
 
         debug!("compare_const_impl: trait_ty={:?}", trait_ty);
 
-        let err = infcx.sub_types(false, &cause, impl_ty, trait_ty)
-            .map(|ok| inh.register_infer_ok_obligations(ok));
+        let err = infcx.at(&cause, param_env)
+                       .sup(trait_ty, impl_ty)
+                       .map(|ok| inh.register_infer_ok_obligations(ok));
 
         if let Err(terr) = err {
             debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
@@ -794,7 +811,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             return;
         }
 
-        let fcx = FnCtxt::new(&inh, impl_c_node_id);
+        let fcx = FnCtxt::new(&inh, param_env, impl_c_node_id);
         fcx.regionck_item(impl_c_node_id, impl_c_span, &[]);
     });
 }
index d92dafe6904590e57f5ae09bc3861df60fe9a1be..9ed50dd1e4d4042f4a45e030c3bfbf6a00219a78 100644 (file)
@@ -18,7 +18,7 @@
 use rustc::hir;
 use rustc::hir::def::Def;
 use rustc::ty::{self, Ty, AssociatedItem};
-use errors::DiagnosticBuilder;
+use errors::{DiagnosticBuilder, CodeMapper};
 
 use super::method::probe;
 
@@ -26,8 +26,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     // Requires that the two types unify, and prints an error message if
     // they don't.
     pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
-        let cause = self.misc(sp);
-        match self.sub_types(false, &cause, actual, expected) {
+        let cause = &self.misc(sp);
+        match self.at(cause, self.param_env).sup(expected, actual) {
             Ok(InferOk { obligations, value: () }) => {
                 self.register_predicates(obligations);
             },
@@ -54,7 +54,7 @@ pub fn demand_eqtype_with_origin(&self,
                                      cause: &ObligationCause<'tcx>,
                                      expected: Ty<'tcx>,
                                      actual: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
-        match self.eq_types(false, cause, actual, expected) {
+        match self.at(cause, self.param_env).eq(expected, actual) {
             Ok(InferOk { obligations, value: () }) => {
                 self.register_predicates(obligations);
                 None
@@ -187,7 +187,9 @@ fn check_ref(&self,
                                                        checked_ty),
                 };
                 if self.can_coerce(ref_ty, expected) {
-                    if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
+                    // Use the callsite's span if this is a macro call. #41858
+                    let sp = self.sess().codemap().call_span_if_macro(expr.span);
+                    if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(sp) {
                         return Some(format!("try with `{}{}`",
                                             match mutability.mutbl {
                                                 hir::Mutability::MutMutable => "&mut ",
index 3ed0da05dc2c2f800e8916017a22e047de4e2069..bff9289de505585b3279e0475c4fb328d06f7f8e 100644 (file)
@@ -16,7 +16,7 @@
 use rustc::middle::region::{self, RegionMaps};
 use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::traits::{self, ObligationCause, Reveal};
+use rustc::traits::{self, ObligationCause};
 use util::common::ErrorReported;
 use util::nodemap::FxHashSet;
 
@@ -79,8 +79,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
 
     // check that the impl type can be made to match the trait type.
 
-    let impl_param_env = tcx.param_env(self_type_did);
-    tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|ref infcx| {
+    tcx.infer_ctxt(()).enter(|ref infcx| {
+        let impl_param_env = tcx.param_env(self_type_did);
         let tcx = infcx.tcx;
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
@@ -92,7 +92,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
         let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
 
         let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);
-        match infcx.eq_types(true, cause, named_type, fresh_impl_self_ty) {
+        match infcx.at(cause, impl_param_env).eq(named_type, fresh_impl_self_ty) {
             Ok(InferOk { obligations, .. }) => {
                 fulfillment_cx.register_predicate_obligations(infcx, obligations);
             }
index 60067e6a6ec0238e9c8da62e73ec9f60ed71e31c..daf202cd7973150c7895a375e59f2bd47a6a8213 100644 (file)
@@ -133,6 +133,14 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                   ],
                tcx.mk_nil())
             }
+            "prefetch_read_data" | "prefetch_write_data" |
+            "prefetch_read_instruction" | "prefetch_write_instruction" => {
+                (1, vec![tcx.mk_ptr(ty::TypeAndMut {
+                          ty: param(0),
+                          mutbl: hir::MutImmutable
+                         }), tcx.types.i32],
+                    tcx.mk_nil())
+            }
             "drop_in_place" => {
                 (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_nil())
             }
index a9e82a0601feeafe8784bba5458cb49e51271399..c8815f3df5aa25ecda4a4772b287a9b1eec84c21 100644 (file)
@@ -8,14 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::probe;
+use super::{probe, MethodCallee};
 
 use check::{FnCtxt, LvalueOp, callee};
 use hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref};
 use rustc::ty::fold::TypeFoldable;
 use rustc::infer::{self, InferOk};
 use syntax_pos::Span;
@@ -45,7 +45,7 @@ pub fn confirm_method(&self,
                           unadjusted_self_ty: Ty<'tcx>,
                           pick: probe::Pick<'tcx>,
                           supplied_method_types: Vec<Ty<'tcx>>)
-                          -> ty::MethodCallee<'tcx> {
+                          -> MethodCallee<'tcx> {
         debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
                unadjusted_self_ty,
                pick,
@@ -74,7 +74,7 @@ fn confirm(&mut self,
                unadjusted_self_ty: Ty<'tcx>,
                pick: probe::Pick<'tcx>,
                supplied_method_types: Vec<Ty<'tcx>>)
-               -> ty::MethodCallee<'tcx> {
+               -> MethodCallee<'tcx> {
         // Adjust the self expression the user provided and obtain the adjusted type.
         let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
 
@@ -88,19 +88,20 @@ fn confirm(&mut self,
         debug!("all_substs={:?}", all_substs);
 
         // Create the final signature for the method, replacing late-bound regions.
-        let (method_ty, method_predicates) = self.instantiate_method_sig(&pick, all_substs);
+        let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs);
 
         // Unify the (adjusted) self type with what the method expects.
-        self.unify_receivers(self_ty, method_ty.fn_sig().input(0).skip_binder());
+        self.unify_receivers(self_ty, method_sig.inputs()[0]);
 
         // Add any trait/regions obligations specified on the method's type parameters.
+        let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig));
         self.add_obligations(method_ty, all_substs, &method_predicates);
 
         // Create the final `MethodCallee`.
-        let callee = ty::MethodCallee {
+        let callee = MethodCallee {
             def_id: pick.item.def_id,
-            ty: method_ty,
             substs: all_substs,
+            sig: method_sig,
         };
 
         if let Some(hir::MutMutable) = pick.autoref {
@@ -117,40 +118,49 @@ fn adjust_self_ty(&mut self,
                       unadjusted_self_ty: Ty<'tcx>,
                       pick: &probe::Pick<'tcx>)
                       -> Ty<'tcx> {
-        let autoref = if let Some(mutbl) = pick.autoref {
+        // Commit the autoderefs by calling `autoderef` again, but this
+        // time writing the results into the various tables.
+        let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
+        let (_, n) = autoderef.nth(pick.autoderefs).unwrap();
+        assert_eq!(n, pick.autoderefs);
+
+        let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
+
+        let mut target = autoderef.unambiguous_final_ty();
+
+        if let Some(mutbl) = pick.autoref {
             let region = self.next_region_var(infer::Autoref(self.span));
-            Some(AutoBorrow::Ref(region, mutbl))
+            target = self.tcx.mk_ref(region, ty::TypeAndMut {
+                mutbl,
+                ty: target
+            });
+            adjustments.push(Adjustment {
+                kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+                target
+            });
+
+            if let Some(unsize_target) = pick.unsize {
+                target = self.tcx.mk_ref(region, ty::TypeAndMut {
+                    mutbl,
+                    ty: unsize_target
+                });
+                adjustments.push(Adjustment {
+                    kind: Adjust::Unsize,
+                    target
+                });
+            }
         } else {
             // No unsizing should be performed without autoref (at
             // least during method dispach). This is because we
             // currently only unsize `[T;N]` to `[T]`, and naturally
             // that must occur being a reference.
             assert!(pick.unsize.is_none());
-            None
-        };
-
-
-        // Commit the autoderefs by calling `autoderef` again, but this
-        // time writing the results into the various tables.
-        let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
-        let (autoderefd_ty, n) = autoderef.nth(pick.autoderefs).unwrap();
-        assert_eq!(n, pick.autoderefs);
-
-        autoderef.unambiguous_final_ty();
-        autoderef.finalize(LvaluePreference::NoPreference, self.self_expr);
+        }
 
-        let target = pick.unsize.unwrap_or(autoderefd_ty);
-        let target = target.adjust_for_autoref(self.tcx, autoref);
+        autoderef.finalize();
 
-        // Write out the final adjustment.
-        self.apply_adjustment(self.self_expr.id, Adjustment {
-            kind: Adjust::DerefRef {
-                autoderefs: pick.autoderefs,
-                autoref: autoref,
-                unsize: pick.unsize.is_some(),
-            },
-            target: target
-        });
+        // Write out the final adjustments.
+        self.apply_adjustments(self.self_expr, adjustments);
 
         target
     }
@@ -330,7 +340,7 @@ fn instantiate_method_substs(&mut self,
     }
 
     fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
-        match self.sub_types(false, &self.misc(self.span), self_ty, method_self_ty) {
+        match self.at(&self.misc(self.span), self.param_env).sup(method_self_ty, self_ty) {
             Ok(InferOk { obligations, value: () }) => {
                 self.register_predicates(obligations);
             }
@@ -349,7 +359,7 @@ fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
     fn instantiate_method_sig(&mut self,
                               pick: &probe::Pick<'tcx>,
                               all_substs: &'tcx Substs<'tcx>)
-                              -> (Ty<'tcx>, ty::InstantiatedPredicates<'tcx>) {
+                              -> (ty::FnSig<'tcx>, ty::InstantiatedPredicates<'tcx>) {
         debug!("instantiate_method_sig(pick={:?}, all_substs={:?})",
                pick,
                all_substs);
@@ -380,8 +390,7 @@ fn instantiate_method_sig(&mut self,
         let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
         debug!("type scheme substituted, method_sig={:?}", method_sig);
 
-        (self.tcx.mk_fn_def(def_id, all_substs, ty::Binder(method_sig)),
-         method_predicates)
+        (method_sig, method_predicates)
     }
 
     fn add_obligations(&mut self,
@@ -436,19 +445,23 @@ fn convert_lvalue_derefs_to_mutable(&self) {
             // Fix up the autoderefs. Autorefs can only occur immediately preceding
             // overloaded lvalue ops, and will be fixed by them in order to get
             // the correct region.
-            let autoderefs = match self.tables.borrow().adjustments.get(&expr.id) {
-                Some(&Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => autoderefs,
-                Some(_) | None => 0
-            };
-
-            if autoderefs > 0 {
-                let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
-                autoderef.nth(autoderefs).unwrap_or_else(|| {
-                    span_bug!(expr.span,
-                              "expr was deref-able {} times but now isn't?",
-                              autoderefs);
-                });
-                autoderef.finalize(PreferMutLvalue, expr);
+            let mut source = self.node_ty(expr.id);
+            if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) {
+                let pref = LvaluePreference::PreferMutLvalue;
+                for adjustment in adjustments {
+                    if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
+                        if let Some(ok) = self.try_overloaded_deref(expr.span, source, pref) {
+                            let method = self.register_infer_ok_obligations(ok);
+                            if let ty::TyRef(region, mt) = method.sig.output().sty {
+                                *deref = OverloadedDeref {
+                                    region,
+                                    mutbl: mt.mutbl
+                                };
+                            }
+                        }
+                    }
+                    source = adjustment.target;
+                }
             }
 
             match expr.node {
@@ -474,13 +487,12 @@ fn convert_lvalue_op_to_mutable(&self,
     {
         debug!("convert_lvalue_op_to_mutable({:?}, {:?}, {:?}, {:?})",
                op, expr, base_expr, arg_tys);
-        let method_call = ty::MethodCall::expr(expr.id);
-        if !self.tables.borrow().method_map.contains_key(&method_call) {
+        if !self.tables.borrow().is_method_call(expr) {
             debug!("convert_lvalue_op_to_mutable - builtin, nothing to do");
             return
         }
 
-        let base_ty = self.tables.borrow().adjustments.get(&base_expr.id)
+        let base_ty = self.tables.borrow().expr_adjustments(base_expr).last()
             .map_or_else(|| self.node_ty(expr.id), |adj| adj.target);
         let base_ty = self.resolve_type_vars_if_possible(&base_ty);
 
@@ -490,34 +502,44 @@ fn convert_lvalue_op_to_mutable(&self,
             .ty;
 
         let method = self.try_overloaded_lvalue_op(
-            expr.span, None, base_ty, arg_tys, PreferMutLvalue, op);
-        let ok = match method {
-            Some(method) => method,
+            expr.span, base_ty, arg_tys, PreferMutLvalue, op);
+        let method = match method {
+            Some(ok) => self.register_infer_ok_obligations(ok),
             None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed")
         };
-        let method = self.register_infer_ok_obligations(ok);
         debug!("convert_lvalue_op_to_mutable: method={:?}", method);
-        self.tables.borrow_mut().method_map.insert(method_call, method);
+        self.write_method_call(expr.id, method);
+
+        let (region, mutbl) = if let ty::TyRef(r, mt) = method.sig.inputs()[0].sty {
+            (r, mt.mutbl)
+        } else {
+            span_bug!(expr.span, "input to lvalue op is not a ref?");
+        };
 
         // Convert the autoref in the base expr to mutable with the correct
         // region and mutability.
-        if let Some(&mut Adjustment {
-            ref mut target, kind: Adjust::DerefRef {
-                autoref: Some(AutoBorrow::Ref(ref mut r, ref mut mutbl)), ..
+        let base_expr_ty = self.node_ty(base_expr.id);
+        if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) {
+            let mut source = base_expr_ty;
+            for adjustment in &mut adjustments[..] {
+                if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
+                    debug!("convert_lvalue_op_to_mutable: converting autoref {:?}", adjustment);
+                    adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
+                    adjustment.target = self.tcx.mk_ref(region, ty::TypeAndMut {
+                        ty: source,
+                        mutbl
+                    });
+                }
+                source = adjustment.target;
             }
-        }) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) {
-            debug!("convert_lvalue_op_to_mutable: converting autoref of {:?}", target);
-
-            // extract method return type, which will be &mut T;
-            // all LB regions should have been instantiated during method lookup
-            let method_sig = self.tcx.no_late_bound_regions(&method.ty.fn_sig()).unwrap();
 
-            *target = method_sig.inputs()[0];
-            if let ty::TyRef(r_, mt) = target.sty {
-                *r = r_;
-                *mutbl = mt.mutbl;
-            } else {
-                span_bug!(expr.span, "input to lvalue op is not a ref?");
+            // If we have an autoref followed by unsizing at the end, fix the unsize target.
+            match adjustments[..] {
+                [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
+                 Adjustment { kind: Adjust::Unsize, ref mut target }] => {
+                    *target = method.sig.inputs()[0];
+                }
+                _ => {}
             }
         }
     }
index 43bf702935ac31e3d232821aa85bf28c150c99bb..73c1215f275fbd8612ba0dbdab7ce4b47cc7be49 100644 (file)
 
 //! Method lookup: the secret sauce of Rust. See `README.md`.
 
-use check::{FnCtxt, AdjustedRcvr};
+use check::FnCtxt;
 use hir::def::Def;
 use hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::ty::subst::Subst;
 use rustc::infer::{self, InferOk};
 
 
 use self::probe::IsSuggestion;
 
+#[derive(Clone, Copy, Debug)]
+pub struct MethodCallee<'tcx> {
+    /// Impl method ID, for inherent methods, or trait method ID, otherwise.
+    pub def_id: DefId,
+    pub substs: &'tcx Substs<'tcx>,
+
+    /// Instantiated method signature, i.e. it has been
+    /// substituted, normalized, and has had late-bound
+    /// lifetimes replaced with inference variables.
+    pub sig: ty::FnSig<'tcx>,
+}
+
 pub enum MethodError<'tcx> {
     // Did not find an applicable method, but we did find various near-misses that may work.
     NoMatch(NoMatchData<'tcx>),
@@ -125,7 +136,7 @@ pub fn lookup_method(&self,
                          supplied_method_types: Vec<ty::Ty<'tcx>>,
                          call_expr: &'gcx hir::Expr,
                          self_expr: &'gcx hir::Expr)
-                         -> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>> {
+                         -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
         debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
                method_name,
                self_ty,
@@ -153,29 +164,25 @@ pub fn lookup_method(&self,
                                supplied_method_types))
     }
 
-    /// `lookup_in_trait_adjusted` is used for overloaded operators.
+    /// `lookup_method_in_trait` is used for overloaded operators.
     /// It does a very narrow slice of what the normal probe/confirm path does.
     /// In particular, it doesn't really do any probing: it simply constructs
     /// an obligation for aparticular trait with the given self-type and checks
     /// whether that trait is implemented.
     ///
     /// FIXME(#18741) -- It seems likely that we can consolidate some of this
-    /// code with the other method-lookup code. In particular, autoderef on
-    /// index is basically identical to autoderef with normal probes, except
-    /// that the test also looks for built-in indexing. Also, the second half of
-    /// this method is basically the same as confirmation.
-    pub fn lookup_method_in_trait_adjusted(&self,
-                                           span: Span,
-                                           self_info: Option<AdjustedRcvr>,
-                                           m_name: ast::Name,
-                                           trait_def_id: DefId,
-                                           self_ty: ty::Ty<'tcx>,
-                                           opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
-                                           -> Option<InferOk<'tcx, ty::MethodCallee<'tcx>>> {
-        debug!("lookup_in_trait_adjusted(self_ty={:?}, self_info={:?}, \
+    /// code with the other method-lookup code. In particular, the second half
+    /// of this method is basically the same as confirmation.
+    pub fn lookup_method_in_trait(&self,
+                                  span: Span,
+                                  m_name: ast::Name,
+                                  trait_def_id: DefId,
+                                  self_ty: ty::Ty<'tcx>,
+                                  opt_input_types: Option<&[ty::Ty<'tcx>]>)
+                                  -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        debug!("lookup_in_trait_adjusted(self_ty={:?}, \
                 m_name={}, trait_def_id={:?})",
                self_ty,
-               self_info,
                m_name,
                trait_def_id);
 
@@ -198,7 +205,10 @@ pub fn lookup_method_in_trait_adjusted(&self,
         // Construct an obligation
         let poly_trait_ref = trait_ref.to_poly_trait_ref();
         let obligation =
-            traits::Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate());
+            traits::Obligation::misc(span,
+                                     self.body_id,
+                                     self.param_env,
+                                     poly_trait_ref.to_predicate());
 
         // Now we want to know if this can be matched
         let mut selcx = traits::SelectionContext::new(self);
@@ -225,8 +235,7 @@ pub fn lookup_method_in_trait_adjusted(&self,
         // NB: Instantiate late-bound regions first so that
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
-        let original_method_ty = tcx.type_of(def_id);
-        let fn_sig = original_method_ty.fn_sig();
+        let fn_sig = tcx.type_of(def_id).fn_sig();
         let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
                                                                     infer::FnCall,
                                                                     &fn_sig).0;
@@ -237,12 +246,6 @@ pub fn lookup_method_in_trait_adjusted(&self,
                 value
             }
         };
-        let transformed_self_ty = fn_sig.inputs()[0];
-        let method_ty = tcx.mk_fn_def(def_id, substs, ty::Binder(fn_sig));
-
-        debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
-               method_ty,
-               obligation);
 
         // Register obligations for the parameters.  This will include the
         // `Self` parameter, which in turn has a bound of the main trait,
@@ -262,46 +265,23 @@ pub fn lookup_method_in_trait_adjusted(&self,
         assert!(!bounds.has_escaping_regions());
 
         let cause = traits::ObligationCause::misc(span, self.body_id);
-        obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds));
+        obligations.extend(traits::predicates_for_generics(cause.clone(),
+                                                           self.param_env,
+                                                           &bounds));
 
         // Also add an obligation for the method type being well-formed.
-        obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty)));
-
-        // Insert any adjustments needed (always an autoref of some mutability).
-        if let Some(AdjustedRcvr { rcvr_expr, autoderefs, unsize }) = self_info {
-            debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
-                    (self-id={}, autoderefs={}, unsize={}, fty={:?})",
-                    rcvr_expr.id, autoderefs, unsize, original_method_ty);
-
-            let original_sig = original_method_ty.fn_sig();
-            let autoref = match (&original_sig.input(0).skip_binder().sty,
-                                 &transformed_self_ty.sty) {
-                (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => {
-                    // Trait method is fn(&self) or fn(&mut self), need an
-                    // autoref. Pull the region etc out of the type of first argument.
-                    Some(AutoBorrow::Ref(region, mutbl))
-                }
-                _ => {
-                    // Trait method is fn(self), no transformation needed.
-                    assert!(!unsize);
-                    None
-                }
-            };
-
-            self.apply_adjustment(rcvr_expr.id, Adjustment {
-                kind: Adjust::DerefRef {
-                    autoderefs: autoderefs,
-                    autoref: autoref,
-                    unsize: unsize
-                },
-                target: transformed_self_ty
-            });
-        }
+        let method_ty = tcx.mk_fn_ptr(ty::Binder(fn_sig));
+        debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
+               method_ty,
+               obligation);
+        obligations.push(traits::Obligation::new(cause,
+                                                 self.param_env,
+                                                 ty::Predicate::WellFormed(method_ty)));
 
-        let callee = ty::MethodCallee {
+        let callee = MethodCallee {
             def_id: def_id,
-            ty: method_ty,
             substs: trait_ref.substs,
+            sig: fn_sig,
         };
 
         debug!("callee = {:?}", callee);
index 1a1a9361a89f9929cec3266baa18ceb59676ee12..2518a1739f73e69a85cdee096002de109a09fd01 100644 (file)
@@ -540,7 +540,7 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
             let cause = traits::ObligationCause::misc(self.span, self.body_id);
             let mut selcx = &mut traits::SelectionContext::new(self.fcx);
             let traits::Normalized { value: xform_self_ty, obligations } =
-                traits::normalize(selcx, cause, &xform_self_ty);
+                traits::normalize(selcx, self.param_env, cause, &xform_self_ty);
             debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
                    xform_self_ty);
 
@@ -679,7 +679,7 @@ pub fn matches_return_type(&self, method: &ty::AssociatedItem,
                     let output = fty.output().subst(self.tcx, substs);
                     let (output, _) = self.replace_late_bound_regions_with_fresh_var(
                         self.span, infer::FnCall, &output);
-                    self.can_sub_types(output, expected).is_ok()
+                    self.can_sub(self.param_env, output, expected).is_ok()
                 })
             }
             _ => false,
@@ -751,7 +751,7 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
             let cause = traits::ObligationCause::misc(self.span, self.body_id);
             let mut selcx = &mut traits::SelectionContext::new(self.fcx);
             let traits::Normalized { value: xform_self_ty, obligations } =
-                traits::normalize(selcx, cause, &xform_self_ty);
+                traits::normalize(selcx, self.param_env, cause, &xform_self_ty);
 
             debug!("xform_self_ty={:?}", xform_self_ty);
 
@@ -885,7 +885,7 @@ fn assemble_projection_candidates(&mut self,
                        substs,
                        bound);
 
-                if self.can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
+                if self.can_eq(self.param_env, step.self_ty, bound.self_ty()).is_ok() {
                     let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs);
 
                     debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}",
@@ -1143,10 +1143,8 @@ fn consider_probe(&self,
 
         self.probe(|_| {
             // First check that the self type can be related.
-            let sub_obligations = match self.sub_types(false,
-                                                       &ObligationCause::dummy(),
-                                                       self_ty,
-                                                       probe.xform_self_ty) {
+            let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env)
+                                            .sup(probe.xform_self_ty, self_ty) {
                 Ok(InferOk { obligations, value: () }) => obligations,
                 Err(_) => {
                     debug!("--> cannot relate self-types");
@@ -1182,10 +1180,12 @@ fn consider_probe(&self,
             let impl_bounds = self.tcx.predicates_of(impl_def_id);
             let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
             let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
-                traits::normalize(selcx, cause.clone(), &impl_bounds);
+                traits::normalize(selcx, self.param_env, cause.clone(), &impl_bounds);
 
             // Convert the bounds into obligations.
-            let obligations = traits::predicates_for_generics(cause.clone(), &impl_bounds);
+            let obligations = traits::predicates_for_generics(cause.clone(),
+                                                              self.param_env,
+                                                              &impl_bounds);
             debug!("impl_obligations={:?}", obligations);
 
             // Evaluate those obligations to see if they might possibly hold.
index 594f1813a5ab4bcda290edf1ec001b257007204f..f8dd5774793a3f70c8df5d204cf8f1dc42f68794 100644 (file)
@@ -57,7 +57,10 @@ fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool {
                         let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
                         let poly_trait_ref = trait_ref.to_poly_trait_ref();
                         let obligation =
-                            Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate());
+                            Obligation::misc(span,
+                                             self.body_id,
+                                             self.param_env,
+                                             poly_trait_ref.to_predicate());
                         SelectionContext::new(self).evaluate_obligation(&obligation)
                     })
                 })
@@ -173,7 +176,18 @@ pub fn report_method_error(&self,
                                      if mode == Mode::MethodCall {
                                          "method"
                                      } else {
-                                         "associated item"
+                                         match item_name.as_str().chars().next() {
+                                             Some(name) => {
+                                                 if name.is_lowercase() {
+                                                     "function or associated item"
+                                                 } else {
+                                                     "associated item"
+                                                 }
+                                             },
+                                             None => {
+                                                 ""
+                                             },
+                                         }
                                      },
                                      item_name,
                                      self.ty_to_string(actual))
@@ -228,7 +242,7 @@ pub fn report_method_error(&self,
                     macro_rules! report_function {
                         ($span:expr, $name:expr) => {
                             err.note(&format!("{} is a function, perhaps you wish to call it",
-                                         $name));
+                                              $name));
                         }
                     }
 
@@ -315,9 +329,9 @@ fn suggest_traits_to_import(&self,
             let mut candidates = valid_out_of_scope_traits;
             candidates.sort();
             candidates.dedup();
-            let msg = format!("items from traits can only be used if the trait is in scope; the \
-                               following {traits_are} implemented but not in scope, perhaps add \
-                               a `use` for {one_of_them}:",
+            err.help("items from traits can only be used if the trait is in scope");
+            let mut msg = format!("the following {traits_are} implemented but not in scope, \
+                                   perhaps add a `use` for {one_of_them}:",
                               traits_are = if candidates.len() == 1 {
                                   "trait is"
                               } else {
@@ -329,17 +343,17 @@ fn suggest_traits_to_import(&self,
                                   "one of them"
                               });
 
-            err.help(&msg[..]);
-
             let limit = if candidates.len() == 5 { 5 } else { 4 };
             for (i, trait_did) in candidates.iter().take(limit).enumerate() {
-                err.help(&format!("candidate #{}: `use {};`",
-                                  i + 1,
-                                  self.tcx.item_path_str(*trait_did)));
+                msg.push_str(&format!("\ncandidate #{}: `use {};`",
+                                      i + 1,
+                                      self.tcx.item_path_str(*trait_did)));
             }
             if candidates.len() > limit {
-                err.note(&format!("and {} others", candidates.len() - limit));
+                msg.push_str(&format!("\nand {} others", candidates.len() - limit));
             }
+            err.note(&msg[..]);
+
             return;
         }
 
@@ -369,28 +383,27 @@ fn suggest_traits_to_import(&self,
             // FIXME #21673 this help message could be tuned to the case
             // of a type parameter: suggest adding a trait bound rather
             // than implementing.
-            let msg = format!("items from traits can only be used if the trait is implemented \
-                               and in scope; the following {traits_define} an item `{name}`, \
-                               perhaps you need to implement {one_of_them}:",
-                              traits_define = if candidates.len() == 1 {
-                                  "trait defines"
-                              } else {
-                                  "traits define"
-                              },
-                              one_of_them = if candidates.len() == 1 {
-                                  "it"
-                              } else {
-                                  "one of them"
-                              },
-                              name = item_name);
-
-            err.help(&msg[..]);
+            err.help("items from traits can only be used if the trait is implemented and in scope");
+            let mut msg = format!("the following {traits_define} an item `{name}`, \
+                                   perhaps you need to implement {one_of_them}:",
+                                  traits_define = if candidates.len() == 1 {
+                                      "trait defines"
+                                  } else {
+                                      "traits define"
+                                  },
+                                  one_of_them = if candidates.len() == 1 {
+                                      "it"
+                                  } else {
+                                      "one of them"
+                                  },
+                                  name = item_name);
 
             for (i, trait_info) in candidates.iter().enumerate() {
-                err.help(&format!("candidate #{}: `{}`",
-                                  i + 1,
-                                  self.tcx.item_path_str(trait_info.def_id)));
+                msg.push_str(&format!("\ncandidate #{}: `{}`",
+                                      i + 1,
+                                      self.tcx.item_path_str(trait_info.def_id)));
             }
+            err.note(&msg[..]);
         }
     }
 
index 3a6fd51693e73539bbc5d085a4727e2a292bd9d2..c3bce8048796b761da8a3284d8ca2f20fa6278d0 100644 (file)
@@ -52,7 +52,7 @@
 
 While type checking a function, the intermediate types for the
 expressions, blocks, and so forth contained within the function are
-stored in `fcx.node_types` and `fcx.item_substs`.  These types
+stored in `fcx.node_types` and `fcx.node_substs`.  These types
 may contain unresolved type variables.  After type checking is
 complete, the functions in the writeback module are used to take the
 types from this table, resolve them, and then write them into their
 */
 
 pub use self::Expectation::*;
+use self::autoderef::Autoderef;
+use self::callee::DeferredCallResolution;
 use self::coercion::{CoerceMany, DynamicCoerceMany};
 pub use self::compare_method::{compare_impl_method, compare_const_impl};
+use self::method::MethodCallee;
 use self::TupleArgumentsFlag::*;
 
 use astconv::AstConv;
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region::CodeExtent;
 use rustc::ty::subst::{Kind, Subst, Substs};
-use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal};
+use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
 use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
 use rustc::ty::{self, Ty, TyCtxt, Visibility};
-use rustc::ty::{MethodCall, MethodCallee};
 use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
 use rustc::ty::maps::Providers;
@@ -168,7 +170,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // decision. We keep these deferred resolutions grouped by the
     // def-id of the closure, so that once we decide, we can easily go
     // back and process them.
-    deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'gcx, 'tcx>>>>,
+    deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolution<'gcx, 'tcx>>>>,
 
     deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
 
@@ -194,12 +196,6 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-trait DeferredCallResolution<'gcx, 'tcx> {
-    fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>);
-}
-
-type DeferredCallResolutionHandler<'gcx, 'tcx> = Box<DeferredCallResolution<'gcx, 'tcx>+'tcx>;
-
 /// When type-checking an expression, we propagate downward
 /// whatever type hint we are able in the form of an `Expectation`.
 #[derive(Copy, Clone, Debug)]
@@ -375,13 +371,6 @@ pub enum LvalueOp {
     Index
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct AdjustedRcvr<'a> {
-    pub rcvr_expr: &'a hir::Expr,
-    pub autoderefs: usize,
-    pub unsize: bool
-}
-
 /// Tracks whether executing a node may exit normally (versus
 /// return/break/panic, which "diverge", leaving dead code in their
 /// wake). Tracked semi-automatically (through type variables marked
@@ -461,6 +450,14 @@ fn find_breakable(&mut self, target_id: ast::NodeId) -> &mut BreakableCtxt<'gcx,
 pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     body_id: ast::NodeId,
 
+    /// The parameter environment used for proving trait obligations
+    /// in this function. This can change when we descend into
+    /// closures (as they bring new things into scope), hence it is
+    /// not part of `Inherited` (as of the time of this writing,
+    /// closures do not yet change the environment, but they will
+    /// eventually).
+    param_env: ty::ParamEnv<'tcx>,
+
     // Number of errors that had been reported when we started
     // checking this function. On exit, if we find that *more* errors
     // have been reported, we will skip regionck and other work that
@@ -539,9 +536,8 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
     pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, def_id: DefId)
                  -> InheritedBuilder<'a, 'gcx, 'tcx> {
         let tables = ty::TypeckTables::empty();
-        let param_env = tcx.param_env(def_id);
         InheritedBuilder {
-            infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing),
+            infcx: tcx.infer_ctxt(tables),
             def_id,
         }
     }
@@ -601,16 +597,18 @@ fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
     fn normalize_associated_types_in<T>(&self,
                                         span: Span,
                                         body_id: ast::NodeId,
+                                        param_env: ty::ParamEnv<'tcx>,
                                         value: &T) -> T
         where T : TypeFoldable<'tcx>
     {
-        let ok = self.normalize_associated_types_in_as_infer_ok(span, body_id, value);
+        let ok = self.normalize_associated_types_in_as_infer_ok(span, body_id, param_env, value);
         self.register_infer_ok_obligations(ok)
     }
 
     fn normalize_associated_types_in_as_infer_ok<T>(&self,
                                                     span: Span,
                                                     body_id: ast::NodeId,
+                                                    param_env: ty::ParamEnv<'tcx>,
                                                     value: &T)
                                                     -> InferOk<'tcx, T>
         where T : TypeFoldable<'tcx>
@@ -619,7 +617,7 @@ fn normalize_associated_types_in_as_infer_ok<T>(&self,
         let mut selcx = traits::SelectionContext::new(self);
         let cause = ObligationCause::misc(span, body_id);
         let traits::Normalized { value, obligations } =
-            traits::normalize(&mut selcx, cause, value);
+            traits::normalize(&mut selcx, param_env, cause, value);
         debug!("normalize_associated_types_in: result={:?} predicates={:?}",
             value,
             obligations);
@@ -808,6 +806,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let body = tcx.hir.body(body_id);
 
     Inherited::build(tcx, def_id).enter(|inh| {
+        let param_env = tcx.param_env(def_id);
         let fcx = if let Some(decl) = fn_decl {
             let fn_sig = tcx.type_of(def_id).fn_sig();
 
@@ -817,11 +816,14 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             let fn_sig =
                 inh.liberate_late_bound_regions(def_id, &fn_sig);
             let fn_sig =
-                inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
+                inh.normalize_associated_types_in(body.value.span,
+                                                  body_id.node_id,
+                                                  param_env,
+                                                  &fn_sig);
 
-            check_fn(&inh, fn_sig, decl, id, body)
+            check_fn(&inh, param_env, fn_sig, decl, id, body)
         } else {
-            let fcx = FnCtxt::new(&inh, body.value.id);
+            let fcx = FnCtxt::new(&inh, param_env, body.value.id);
             let expected_type = tcx.type_of(def_id);
             let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
             fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
@@ -930,6 +932,7 @@ fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
 /// * ...
 /// * inherited: other fields inherited from the enclosing fn (if any)
 fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
+                            param_env: ty::ParamEnv<'tcx>,
                             fn_sig: ty::FnSig<'tcx>,
                             decl: &'gcx hir::FnDecl,
                             fn_id: ast::NodeId,
@@ -938,11 +941,11 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
 {
     let mut fn_sig = fn_sig.clone();
 
-    debug!("check_fn(sig={:?}, fn_id={})", fn_sig, fn_id);
+    debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env);
 
     // Create the function context.  This is either derived from scratch or,
     // in the case of function expressions, based on the outer context.
-    let mut fcx = FnCtxt::new(inherited, body.value.id);
+    let mut fcx = FnCtxt::new(inherited, param_env, body.value.id);
     *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
 
     let ret_ty = fn_sig.output();
@@ -1345,18 +1348,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     }
 
-    let signature = |item: &ty::AssociatedItem| {
-        match item.kind {
-            ty::AssociatedKind::Method => {
-                format!("{}", tcx.type_of(item.def_id).fn_sig().0)
-            }
-            ty::AssociatedKind::Type => format!("type {};", item.name.to_string()),
-            ty::AssociatedKind::Const => {
-                format!("const {}: {:?};", item.name.to_string(), tcx.type_of(item.def_id))
-            }
-        }
-    };
-
     if !missing_items.is_empty() {
         let mut err = struct_span_err!(tcx.sess, impl_span, E0046,
             "not all trait items implemented, missing: `{}`",
@@ -1371,9 +1362,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             if let Some(span) = tcx.hir.span_if_local(trait_item.def_id) {
                 err.span_label(span, format!("`{}` from trait", trait_item.name));
             } else {
-                err.note(&format!("`{}` from trait: `{}`",
-                                  trait_item.name,
-                                  signature(&trait_item)));
+                err.note_trait_signature(trait_item.name.to_string(),
+                                         trait_item.signature(&tcx));
             }
         }
         err.emit();
@@ -1644,10 +1634,12 @@ enum TupleArgumentsFlag {
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
+               param_env: ty::ParamEnv<'tcx>,
                body_id: ast::NodeId)
                -> FnCtxt<'a, 'gcx, 'tcx> {
         FnCtxt {
             body_id: body_id,
+            param_env,
             err_count_on_creation: inh.tcx.sess.err_count(),
             ret_coercion: None,
             ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
@@ -1729,17 +1721,17 @@ fn resolve_type_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
 
     fn record_deferred_call_resolution(&self,
                                        closure_def_id: DefId,
-                                       r: DeferredCallResolutionHandler<'gcx, 'tcx>) {
+                                       r: DeferredCallResolution<'gcx, 'tcx>) {
         let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
         deferred_call_resolutions.entry(closure_def_id).or_insert(vec![]).push(r);
     }
 
     fn remove_deferred_call_resolutions(&self,
                                         closure_def_id: DefId)
-                                        -> Vec<DeferredCallResolutionHandler<'gcx, 'tcx>>
+                                        -> Vec<DeferredCallResolution<'gcx, 'tcx>>
     {
         let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
-        deferred_call_resolutions.remove(&closure_def_id).unwrap_or(Vec::new())
+        deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![])
     }
 
     pub fn tag(&self) -> String {
@@ -1769,65 +1761,54 @@ pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
         }
     }
 
-    pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
-        if !substs.substs.is_noop() {
+    pub fn write_method_call(&self, node_id: ast::NodeId, method: MethodCallee<'tcx>) {
+        self.tables.borrow_mut().type_dependent_defs.insert(node_id, Def::Method(method.def_id));
+        self.write_substs(node_id, method.substs);
+    }
+
+    pub fn write_substs(&self, node_id: ast::NodeId, substs: &'tcx Substs<'tcx>) {
+        if !substs.is_noop() {
             debug!("write_substs({}, {:?}) in fcx {}",
                    node_id,
                    substs,
                    self.tag());
 
-            self.tables.borrow_mut().item_substs.insert(node_id, substs);
+            self.tables.borrow_mut().node_substs.insert(node_id, substs);
         }
     }
 
-    pub fn apply_autoderef_adjustment(&self,
-                                      node_id: ast::NodeId,
-                                      derefs: usize,
-                                      adjusted_ty: Ty<'tcx>) {
-        self.apply_adjustment(node_id, Adjustment {
-            kind: Adjust::DerefRef {
-                autoderefs: derefs,
-                autoref: None,
-                unsize: false
-            },
-            target: adjusted_ty
-        });
-    }
+    pub fn apply_adjustments(&self, expr: &hir::Expr, adj: Vec<Adjustment<'tcx>>) {
+        debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
 
-    pub fn apply_adjustment(&self, node_id: ast::NodeId, adj: Adjustment<'tcx>) {
-        debug!("apply_adjustment(node_id={}, adj={:?})", node_id, adj);
-
-        if adj.is_identity() {
+        if adj.is_empty() {
             return;
         }
 
-        match self.tables.borrow_mut().adjustments.entry(node_id) {
+        match self.tables.borrow_mut().adjustments.entry(expr.id) {
             Entry::Vacant(entry) => { entry.insert(adj); },
             Entry::Occupied(mut entry) => {
                 debug!(" - composing on top of {:?}", entry.get());
-                let composed_kind = match (entry.get().kind, adj.kind) {
+                match (&entry.get()[..], &adj[..]) {
                     // Applying any adjustment on top of a NeverToAny
                     // is a valid NeverToAny adjustment, because it can't
                     // be reached.
-                    (Adjust::NeverToAny, _) => Adjust::NeverToAny,
-                    (Adjust::DerefRef {
-                        autoderefs: 1,
-                        autoref: Some(AutoBorrow::Ref(..)),
-                        unsize: false
-                    }, Adjust::DerefRef { autoderefs, .. }) if autoderefs > 0 => {
+                    (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return,
+                    (&[
+                        Adjustment { kind: Adjust::Deref(_), .. },
+                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
+                    ], &[
+                        Adjustment { kind: Adjust::Deref(_), .. },
+                        .. // Any following adjustments are allowed.
+                    ]) => {
                         // A reborrow has no effect before a dereference.
-                        adj.kind
                     }
                     // FIXME: currently we never try to compose autoderefs
                     // and ReifyFnPointer/UnsafeFnPointer, but we could.
                     _ =>
-                        bug!("while adjusting {}, can't compose {:?} and {:?}",
-                             node_id, entry.get(), adj)
-                };
-                *entry.get_mut() = Adjustment {
-                    kind: composed_kind,
-                    target: adj.target
+                        bug!("while adjusting {:?}, can't compose {:?} and {:?}",
+                             expr, entry.get(), adj)
                 };
+                *entry.get_mut() = adj;
             }
         }
     }
@@ -1892,7 +1873,9 @@ fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
                     // Require that the predicate holds for the concrete type.
                     let cause = traits::ObligationCause::new(span, self.body_id,
                                                              traits::ReturnType);
-                    self.register_predicate(traits::Obligation::new(cause, predicate));
+                    self.register_predicate(traits::Obligation::new(cause,
+                                                                    self.param_env,
+                                                                    predicate));
                 }
 
                 ty_var
@@ -1905,15 +1888,17 @@ fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
     fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
         where T : TypeFoldable<'tcx>
     {
-        let ok = self.normalize_associated_types_in_as_infer_ok(span, value);
-        self.register_infer_ok_obligations(ok)
+        self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value)
     }
 
     fn normalize_associated_types_in_as_infer_ok<T>(&self, span: Span, value: &T)
                                                     -> InferOk<'tcx, T>
         where T : TypeFoldable<'tcx>
     {
-        self.inh.normalize_associated_types_in_as_infer_ok(span, self.body_id, value)
+        self.inh.normalize_associated_types_in_as_infer_ok(span,
+                                                           self.body_id,
+                                                           self.param_env,
+                                                           value)
     }
 
     pub fn write_nil(&self, node_id: ast::NodeId) {
@@ -1951,7 +1936,7 @@ pub fn register_bound(&self,
                           cause: traits::ObligationCause<'tcx>)
     {
         self.fulfillment_cx.borrow_mut()
-            .register_bound(self, ty, def_id, cause);
+                           .register_bound(self, self.param_env, ty, def_id, cause);
     }
 
     pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
@@ -1972,16 +1957,6 @@ pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
         }
     }
 
-    pub fn opt_node_ty_substs<F>(&self,
-                                 id: ast::NodeId,
-                                 f: F) where
-        F: FnOnce(&ty::ItemSubsts<'tcx>),
-    {
-        if let Some(s) = self.tables.borrow().item_substs.get(&id) {
-            f(s);
-        }
-    }
-
     /// Registers an obligation for checking later, during regionck, that the type `ty` must
     /// outlive the region `r`.
     pub fn register_region_obligation(&self,
@@ -2002,7 +1977,9 @@ pub fn register_wf_obligation(&self,
     {
         // WF obligations never themselves fail, so no real need to give a detailed cause:
         let cause = traits::ObligationCause::new(span, self.body_id, code);
-        self.register_predicate(traits::Obligation::new(cause, ty::Predicate::WellFormed(ty)));
+        self.register_predicate(traits::Obligation::new(cause,
+                                                        self.param_env,
+                                                        ty::Predicate::WellFormed(ty)));
     }
 
     pub fn register_old_wf_obligation(&self,
@@ -2055,7 +2032,7 @@ pub fn add_obligations_for_parameters(&self,
         debug!("add_obligations_for_parameters(predicates={:?})",
                predicates);
 
-        for obligation in traits::predicates_for_generics(cause, predicates) {
+        for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) {
             self.register_predicate(obligation);
         }
     }
@@ -2169,8 +2146,7 @@ fn make_overloaded_lvalue_return_type(&self,
     {
         // extract method return type, which will be &T;
         // all LB regions should have been instantiated during method lookup
-        let ret_ty = method.ty.fn_ret();
-        let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap();
+        let ret_ty = method.sig.output();
 
         // method returns &T, but the type as visible to user is T, so deref
         ret_ty.builtin_deref(true, NoPreference).unwrap()
@@ -2189,32 +2165,12 @@ fn lookup_indexing(&self,
         // consolidated.
 
         let mut autoderef = self.autoderef(base_expr.span, base_ty);
-
-        while let Some((adj_ty, autoderefs)) = autoderef.next() {
-            if let Some(final_mt) = self.try_index_step(
-                MethodCall::expr(expr.id), expr, Some(AdjustedRcvr {
-                    rcvr_expr: base_expr,
-                    autoderefs,
-                    unsize: false
-                }), base_expr.span, adj_ty, lvalue_pref, idx_ty)
-            {
-                autoderef.finalize(lvalue_pref, base_expr);
-                return Some(final_mt);
-            }
-
-            if let ty::TyArray(element_ty, _) = adj_ty.sty {
-                autoderef.finalize(lvalue_pref, base_expr);
-                let adj_ty = self.tcx.mk_slice(element_ty);
-                return self.try_index_step(
-                    MethodCall::expr(expr.id), expr, Some(AdjustedRcvr {
-                        rcvr_expr: base_expr,
-                        autoderefs,
-                        unsize: true
-                    }), base_expr.span, adj_ty, lvalue_pref, idx_ty)
-            }
+        let mut result = None;
+        while result.is_none() && autoderef.next().is_some() {
+            result = self.try_index_step(expr, base_expr, &autoderef, lvalue_pref, idx_ty);
         }
-        autoderef.unambiguous_final_ty();
-        None
+        autoderef.finalize();
+        result
     }
 
     /// To type-check `base_expr[index_expr]`, we progressively autoderef
@@ -2223,16 +2179,14 @@ fn lookup_indexing(&self,
     /// This loop implements one step in that search; the autoderef loop
     /// is implemented by `lookup_indexing`.
     fn try_index_step(&self,
-                      method_call: MethodCall,
                       expr: &hir::Expr,
-                      base_expr: Option<AdjustedRcvr>,
-                      base_span: Span,
-                      adjusted_ty: Ty<'tcx>,
+                      base_expr: &hir::Expr,
+                      autoderef: &Autoderef<'a, 'gcx, 'tcx>,
                       lvalue_pref: LvaluePreference,
                       index_ty: Ty<'tcx>)
                       -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
     {
-        let tcx = self.tcx;
+        let adjusted_ty = autoderef.unambiguous_final_ty();
         debug!("try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
                                index_ty={:?})",
                expr,
@@ -2240,35 +2194,67 @@ fn try_index_step(&self,
                adjusted_ty,
                index_ty);
 
-        let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_span));
 
         // First, try built-in indexing.
         match (adjusted_ty.builtin_index(), &index_ty.sty) {
             (Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
                 debug!("try_index_step: success, using built-in indexing");
-                // If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
-                if let Some(base_expr) = base_expr {
-                    assert!(!base_expr.unsize);
-                    self.apply_autoderef_adjustment(
-                        base_expr.rcvr_expr.id, base_expr.autoderefs, adjusted_ty);
-                }
-                return Some((tcx.types.usize, ty));
+                let adjustments = autoderef.adjust_steps(lvalue_pref);
+                self.apply_adjustments(base_expr, adjustments);
+                return Some((self.tcx.types.usize, ty));
             }
             _ => {}
         }
 
-        // If some lookup succeeds, write callee into table and extract index/element
-        // type from the method signature.
-        // If some lookup succeeded, install method in table
-        let method = self.try_overloaded_lvalue_op(
-            expr.span, base_expr, adjusted_ty, &[input_ty], lvalue_pref, LvalueOp::Index);
-
-        method.map(|ok| {
-            debug!("try_index_step: success, using overloaded indexing");
-            let method = self.register_infer_ok_obligations(ok);
-            self.tables.borrow_mut().method_map.insert(method_call, method);
-            (input_ty, self.make_overloaded_lvalue_return_type(method).ty)
-        })
+        for &unsize in &[false, true] {
+            let mut self_ty = adjusted_ty;
+            if unsize {
+                // We only unsize arrays here.
+                if let ty::TyArray(element_ty, _) = adjusted_ty.sty {
+                    self_ty = self.tcx.mk_slice(element_ty);
+                } else {
+                    continue;
+                }
+            }
+
+            // If some lookup succeeds, write callee into table and extract index/element
+            // type from the method signature.
+            // If some lookup succeeded, install method in table
+            let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span));
+            let method = self.try_overloaded_lvalue_op(
+                expr.span, self_ty, &[input_ty], lvalue_pref, LvalueOp::Index);
+
+            let result = method.map(|ok| {
+                debug!("try_index_step: success, using overloaded indexing");
+                let method = self.register_infer_ok_obligations(ok);
+
+                let mut adjustments = autoderef.adjust_steps(lvalue_pref);
+                if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
+                    adjustments.push(Adjustment {
+                        kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
+                        target: self.tcx.mk_ref(region, ty::TypeAndMut {
+                            mutbl: mt.mutbl,
+                            ty: adjusted_ty
+                        })
+                    });
+                }
+                if unsize {
+                    adjustments.push(Adjustment {
+                        kind: Adjust::Unsize,
+                        target: method.sig.inputs()[0]
+                    });
+                }
+                self.apply_adjustments(base_expr, adjustments);
+
+                self.write_method_call(expr.id, method);
+                (input_ty, self.make_overloaded_lvalue_return_type(method).ty)
+            });
+            if result.is_some() {
+                return result;
+            }
+        }
+
+        None
     }
 
     fn resolve_lvalue_op(&self, op: LvalueOp, is_mut: bool) -> (Option<DefId>, Symbol) {
@@ -2287,16 +2273,14 @@ fn resolve_lvalue_op(&self, op: LvalueOp, is_mut: bool) -> (Option<DefId>, Symbo
 
     fn try_overloaded_lvalue_op(&self,
                                 span: Span,
-                                base_expr: Option<AdjustedRcvr>,
                                 base_ty: Ty<'tcx>,
                                 arg_tys: &[Ty<'tcx>],
                                 lvalue_pref: LvaluePreference,
                                 op: LvalueOp)
                                 -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
     {
-        debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?},{:?})",
+        debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?})",
                span,
-               base_expr,
                base_ty,
                lvalue_pref,
                op);
@@ -2305,12 +2289,7 @@ fn try_overloaded_lvalue_op(&self,
         let (mut_tr, mut_op) = self.resolve_lvalue_op(op, true);
         let method = match (lvalue_pref, mut_tr) {
             (PreferMutLvalue, Some(trait_did)) => {
-                self.lookup_method_in_trait_adjusted(span,
-                                                     base_expr,
-                                                     mut_op,
-                                                     trait_did,
-                                                     base_ty,
-                                                     Some(arg_tys.to_owned()))
+                self.lookup_method_in_trait(span, mut_op, trait_did, base_ty, Some(arg_tys))
             }
             _ => None,
         };
@@ -2319,12 +2298,7 @@ fn try_overloaded_lvalue_op(&self,
         let (imm_tr, imm_op) = self.resolve_lvalue_op(op, false);
         let method = match (method, imm_tr) {
             (None, Some(trait_did)) => {
-                self.lookup_method_in_trait_adjusted(span,
-                                                     base_expr,
-                                                     imm_op,
-                                                     trait_did,
-                                                     base_ty,
-                                                     Some(arg_tys.to_owned()))
+                self.lookup_method_in_trait(span, imm_op, trait_did, base_ty, Some(arg_tys))
             }
             (method, _) => method,
         };
@@ -2334,13 +2308,18 @@ fn try_overloaded_lvalue_op(&self,
 
     fn check_method_argument_types(&self,
                                    sp: Span,
-                                   method_fn_ty: Ty<'tcx>,
-                                   callee_expr: &'gcx hir::Expr,
+                                   method: Result<MethodCallee<'tcx>, ()>,
                                    args_no_rcvr: &'gcx [hir::Expr],
                                    tuple_arguments: TupleArgumentsFlag,
                                    expected: Expectation<'tcx>)
                                    -> Ty<'tcx> {
-        if method_fn_ty.references_error() {
+        let has_error = match method {
+            Ok(method) => {
+                method.substs.references_error() || method.sig.references_error()
+            }
+            Err(_) => true
+        };
+        if has_error {
             let err_inputs = self.err_args(args_no_rcvr.len());
 
             let err_inputs = match tuple_arguments {
@@ -2350,27 +2329,21 @@ fn check_method_argument_types(&self,
 
             self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
                                       false, tuple_arguments, None);
-            self.tcx.types.err
-        } else {
-            match method_fn_ty.sty {
-                ty::TyFnDef(def_id, .., ref fty) => {
-                    // HACK(eddyb) ignore self in the definition (see above).
-                    let expected_arg_tys = self.expected_inputs_for_expected_output(
-                        sp,
-                        expected,
-                        fty.0.output(),
-                        &fty.0.inputs()[1..]
-                    );
-                    self.check_argument_types(sp, &fty.0.inputs()[1..], &expected_arg_tys[..],
-                                              args_no_rcvr, fty.0.variadic, tuple_arguments,
-                                              self.tcx.hir.span_if_local(def_id));
-                    fty.0.output()
-                }
-                _ => {
-                    span_bug!(callee_expr.span, "method without bare fn type");
-                }
-            }
+            return self.tcx.types.err;
         }
+
+        let method = method.unwrap();
+        // HACK(eddyb) ignore self in the definition (see above).
+        let expected_arg_tys = self.expected_inputs_for_expected_output(
+            sp,
+            expected,
+            method.sig.output(),
+            &method.sig.inputs()[1..]
+        );
+        self.check_argument_types(sp, &method.sig.inputs()[1..], &expected_arg_tys[..],
+                                  args_no_rcvr, method.sig.variadic, tuple_arguments,
+                                  self.tcx.hir.span_if_local(method.def_id));
+        method.sig.output()
     }
 
     /// Generic function that factors out common logic from function calls,
@@ -2669,10 +2642,10 @@ pub fn check_expr_has_type(&self,
                     "expression with never type wound up being adjusted");
             let adj_ty = self.next_diverging_ty_var(
                 TypeVariableOrigin::AdjustmentType(expr.span));
-            self.apply_adjustment(expr.id, Adjustment {
+            self.apply_adjustments(expr, vec![Adjustment {
                 kind: Adjust::NeverToAny,
                 target: adj_ty
-            });
+            }]);
             ty = adj_ty;
         }
 
@@ -2740,7 +2713,7 @@ fn expected_inputs_for_expected_output(&self,
                 // is polymorphic) and the expected return type.
                 // No argument expectations are produced if unification fails.
                 let origin = self.misc(call_span);
-                let ures = self.sub_types(false, &origin, formal_ret, ret_ty);
+                let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret);
 
                 // FIXME(#15760) can't use try! here, FromError doesn't default
                 // to identity so the resulting type is not constrained.
@@ -2795,17 +2768,15 @@ fn check_method_call(&self,
         let expr_t = self.structurally_resolved_type(expr.span, rcvr_t);
 
         let tps = tps.iter().map(|ast_ty| self.to_ty(&ast_ty)).collect::<Vec<_>>();
-        let fn_ty = match self.lookup_method(method_name.span,
-                                             method_name.node,
-                                             expr_t,
-                                             tps,
-                                             expr,
-                                             rcvr) {
+        let method = match self.lookup_method(method_name.span,
+                                              method_name.node,
+                                              expr_t,
+                                              tps,
+                                              expr,
+                                              rcvr) {
             Ok(method) => {
-                let method_ty = method.ty;
-                let method_call = MethodCall::expr(expr.id);
-                self.tables.borrow_mut().method_map.insert(method_call, method);
-                method_ty
+                self.write_method_call(expr.id, method);
+                Ok(method)
             }
             Err(error) => {
                 if method_name.node != keywords::Invalid.name() {
@@ -2816,18 +2787,15 @@ fn check_method_call(&self,
                                              error,
                                              Some(args));
                 }
-                self.write_error(expr.id);
-                self.tcx.types.err
+                Err(())
             }
         };
 
         // Call the generic checker.
-        let ret_ty = self.check_method_argument_types(method_name.span, fn_ty,
-                                                      expr, &args[1..],
-                                                      DontTupleArguments,
-                                                      expected);
-
-        ret_ty
+        self.check_method_argument_types(method_name.span, method,
+                                         &args[1..],
+                                         DontTupleArguments,
+                                         expected)
     }
 
     fn check_return_expr(&self, return_expr: &'gcx hir::Expr) {
@@ -2912,7 +2880,7 @@ fn check_field(&self,
                                                      expr_t);
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, expr_t);
-        while let Some((base_t, autoderefs)) = autoderef.next() {
+        while let Some((base_t, _)) = autoderef.next() {
             match base_t.sty {
                 ty::TyAdt(base_def, substs) if !base_def.is_enum() => {
                     debug!("struct named {:?}",  base_t);
@@ -2922,8 +2890,9 @@ fn check_field(&self,
                     if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) {
                         let field_ty = self.field_ty(expr.span, field, substs);
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
-                            autoderef.finalize(lvalue_pref, base);
-                            self.apply_autoderef_adjustment(base.id, autoderefs, base_t);
+                            let adjustments = autoderef.adjust_steps(lvalue_pref);
+                            self.apply_adjustments(base, adjustments);
+                            autoderef.finalize();
 
                             self.tcx.check_stability(field.did, expr.id, expr.span);
 
@@ -3020,7 +2989,7 @@ fn check_tup_field(&self,
         let mut private_candidate = None;
         let mut tuple_like = false;
         let mut autoderef = self.autoderef(expr.span, expr_t);
-        while let Some((base_t, autoderefs)) = autoderef.next() {
+        while let Some((base_t, _)) = autoderef.next() {
             let field = match base_t.sty {
                 ty::TyAdt(base_def, substs) if base_def.is_struct() => {
                     tuple_like = base_def.struct_variant().ctor_kind == CtorKind::Fn;
@@ -3055,8 +3024,9 @@ fn check_tup_field(&self,
             };
 
             if let Some(field_ty) = field {
-                autoderef.finalize(lvalue_pref, base);
-                self.apply_autoderef_adjustment(base.id, autoderefs, base_t);
+                let adjustments = autoderef.adjust_steps(lvalue_pref);
+                self.apply_adjustments(base, adjustments);
+                autoderef.finalize();
                 return field_ty;
             }
         }
@@ -3463,18 +3433,22 @@ fn check_expr_kind(&self,
                                                                                lvalue_pref);
 
             if !oprnd_t.references_error() {
+                oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
                 match unop {
                     hir::UnDeref => {
-                        oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
-
                         if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) {
                             oprnd_t = mt.ty;
                         } else if let Some(ok) = self.try_overloaded_deref(
-                                expr.span, Some(&oprnd), oprnd_t, lvalue_pref) {
+                                expr.span, oprnd_t, lvalue_pref) {
                             let method = self.register_infer_ok_obligations(ok);
+                            if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
+                                self.apply_adjustments(oprnd, vec![Adjustment {
+                                    kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
+                                    target: method.sig.inputs()[0]
+                                }]);
+                            }
                             oprnd_t = self.make_overloaded_lvalue_return_type(method).ty;
-                            self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
-                                                                           method);
+                            self.write_method_call(expr.id, method);
                         } else {
                             self.type_error_message(expr.span, |actual| {
                                 format!("type `{}` cannot be \
@@ -3484,22 +3458,14 @@ fn check_expr_kind(&self,
                         }
                     }
                     hir::UnNot => {
-                        oprnd_t = self.structurally_resolved_type(oprnd.span,
-                                                                  oprnd_t);
-                        let result = self.check_user_unop("!", "not",
-                                                          tcx.lang_items.not_trait(),
-                                                          expr, &oprnd, oprnd_t, unop);
+                        let result = self.check_user_unop(expr, oprnd_t, unop);
                         // If it's builtin, we can reuse the type, this helps inference.
                         if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) {
                             oprnd_t = result;
                         }
                     }
                     hir::UnNeg => {
-                        oprnd_t = self.structurally_resolved_type(oprnd.span,
-                                                                  oprnd_t);
-                        let result = self.check_user_unop("-", "neg",
-                                                          tcx.lang_items.neg_trait(),
-                                                          expr, &oprnd, oprnd_t, unop);
+                        let result = self.check_user_unop(expr, oprnd_t, unop);
                         // If it's builtin, we can reuse the type, this helps inference.
                         if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
                             oprnd_t = result;
@@ -3561,9 +3527,8 @@ fn check_expr_kind(&self,
 
               // We always require that the type provided as the value for
               // a type parameter outlives the moment of instantiation.
-              self.opt_node_ty_substs(expr.id, |item_substs| {
-                  self.add_wf_bounds(&item_substs.substs, expr);
-              });
+              let substs = self.tables.borrow().node_substs(expr.id);
+              self.add_wf_bounds(substs, expr);
 
               ty
           }
@@ -3940,7 +3905,7 @@ fn check_expr_kind(&self,
     }
 
     // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
-    // The newly resolved definition is written into `type_relative_path_defs`.
+    // The newly resolved definition is written into `type_dependent_defs`.
     fn finish_resolving_struct_path(&self,
                                     qpath: &hir::QPath,
                                     path_span: Span,
@@ -3965,7 +3930,7 @@ fn finish_resolving_struct_path(&self,
                                                                    ty, def, segment);
 
                 // Write back the new resolution.
-                self.tables.borrow_mut().type_relative_path_defs.insert(node_id, def);
+                self.tables.borrow_mut().type_dependent_defs.insert(node_id, def);
 
                 (def, ty)
             }
@@ -3973,7 +3938,7 @@ fn finish_resolving_struct_path(&self,
     }
 
     // Resolve associated value path into a base type and associated constant or method definition.
-    // The newly resolved definition is written into `type_relative_path_defs`.
+    // The newly resolved definition is written into `type_dependent_defs`.
     pub fn resolve_ty_and_def_ufcs<'b>(&self,
                                        qpath: &'b hir::QPath,
                                        node_id: ast::NodeId,
@@ -4006,7 +3971,7 @@ pub fn resolve_ty_and_def_ufcs<'b>(&self,
         };
 
         // Write back the new resolution.
-        self.tables.borrow_mut().type_relative_path_defs.insert(node_id, def);
+        self.tables.borrow_mut().type_dependent_defs.insert(node_id, def);
         (def, Some(ty), slice::ref_slice(&**item_segment))
     }
 
@@ -4243,7 +4208,7 @@ fn consider_hint_about_removing_semicolon(&self,
             _ => return,
         };
         let last_expr_ty = self.expr_ty(last_expr);
-        if self.can_sub_types(last_expr_ty, expected_ty).is_err() {
+        if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() {
             return;
         }
         let original_span = original_sp(last_stmt.span, blk.span);
@@ -4386,9 +4351,6 @@ pub fn instantiate_value_path(&self,
                 let ty = self.local_ty(span, nid);
                 let ty = self.normalize_associated_types_in(span, &ty);
                 self.write_ty(node_id, ty);
-                self.write_substs(node_id, ty::ItemSubsts {
-                    substs: self.tcx.intern_substs(&[])
-                });
                 return ty;
             }
             _ => {}
@@ -4506,7 +4468,7 @@ pub fn instantiate_value_path(&self,
             let ty = self.tcx.type_of(impl_def_id);
 
             let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
-            match self.sub_types(false, &self.misc(span), self_ty, impl_ty) {
+            match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
                 Ok(ok) => self.register_infer_ok_obligations(ok),
                 Err(_) => {
                     span_bug!(span,
@@ -4520,9 +4482,7 @@ pub fn instantiate_value_path(&self,
         debug!("instantiate_value_path: type of {:?} is {:?}",
                node_id,
                ty_substituted);
-        self.write_substs(node_id, ty::ItemSubsts {
-            substs: substs
-        });
+        self.write_substs(node_id, substs);
         ty_substituted
     }
 
index 3709260acc997a5c09d9c1cdc8def7998c5eab83..4d69b37b113cfbf2bfaf36b49e00f583d15d23ea 100644 (file)
 //! Code related to processing overloaded binary and unary operators.
 
 use super::FnCtxt;
-use hir::def_id::DefId;
-use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants};
+use super::method::MethodCallee;
+use rustc::ty::{self, Ty, TypeFoldable, PreferMutLvalue, TypeVariants};
 use rustc::ty::TypeVariants::{TyStr, TyRef};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::infer::type_variable::TypeVariableOrigin;
 use errors;
-use syntax::ast;
+use syntax_pos::Span;
 use syntax::symbol::Symbol;
 use rustc::hir;
 
@@ -174,8 +175,6 @@ fn check_overloaded_binop(&self,
                lhs_ty,
                is_assign);
 
-        let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign);
-
         // NB: As we have not yet type-checked the RHS, we don't have the
         // type at hand. Make a variable to represent it. The whole reason
         // for this indirection is so that, below, we can check the expr
@@ -184,15 +183,41 @@ fn check_overloaded_binop(&self,
         // particularly for things like `String + &String`.
         let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span));
 
-        let return_ty = self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var],
-                                              Symbol::intern(name), trait_def_id,
-                                              lhs_expr);
+        let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign));
 
         // see `NB` above
         let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
 
-        let return_ty = match return_ty {
-            Ok(return_ty) => return_ty,
+        let return_ty = match result {
+            Ok(method) => {
+                let by_ref_binop = !op.node.is_by_value();
+                if is_assign == IsAssign::Yes || by_ref_binop {
+                    if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
+                        let autoref = Adjustment {
+                            kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
+                            target: method.sig.inputs()[0]
+                        };
+                        self.apply_adjustments(lhs_expr, vec![autoref]);
+                    }
+                }
+                if by_ref_binop {
+                    if let ty::TyRef(region, mt) = method.sig.inputs()[1].sty {
+                        let autoref = Adjustment {
+                            kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
+                            target: method.sig.inputs()[1]
+                        };
+                        // HACK(eddyb) Bypass checks due to reborrows being in
+                        // some cases applied on the RHS, on top of which we need
+                        // to autoref, which is not allowed by apply_adjustments.
+                        // self.apply_adjustments(rhs_expr, vec![autoref]);
+                        self.tables.borrow_mut().adjustments.entry(rhs_expr.id)
+                            .or_insert(vec![]).push(autoref);
+                    }
+                }
+                self.write_method_call(expr.id, method);
+
+                method.sig.output()
+            }
             Err(()) => {
                 // error types are considered "builtin"
                 if !lhs_ty.references_error() {
@@ -213,10 +238,15 @@ fn check_overloaded_binop(&self,
                             lhs_ty);
 
                         if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty {
-                            if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) &&
-                                self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty],
-                                    Symbol::intern(name), trait_def_id,
-                                    lhs_expr).is_ok() {
+                            if {
+                                !self.infcx.type_moves_by_default(self.param_env,
+                                                                  ty_mut.ty,
+                                                                  lhs_expr.span) &&
+                                    self.lookup_op_method(ty_mut.ty,
+                                                          &[rhs_ty],
+                                                          Op::Binary(op, is_assign))
+                                        .is_ok()
+                            } {
                                 err.note(
                                     &format!(
                                         "this is a reference to a type that `{}` can be applied \
@@ -302,38 +332,39 @@ fn check_str_addition(&self,
     }
 
     pub fn check_user_unop(&self,
-                           op_str: &str,
-                           mname: &str,
-                           trait_did: Option<DefId>,
                            ex: &'gcx hir::Expr,
-                           operand_expr: &'gcx hir::Expr,
                            operand_ty: Ty<'tcx>,
                            op: hir::UnOp)
                            -> Ty<'tcx>
     {
         assert!(op.is_by_value());
-        let mname = Symbol::intern(mname);
-        match self.lookup_op_method(ex, operand_ty, vec![], mname, trait_did, operand_expr) {
-            Ok(t) => t,
+        match self.lookup_op_method(operand_ty, &[], Op::Unary(op, ex.span)) {
+            Ok(method) => {
+                self.write_method_call(ex.id, method);
+                method.sig.output()
+            }
             Err(()) => {
                 let actual = self.resolve_type_vars_if_possible(&operand_ty);
                 if !actual.references_error() {
                     struct_span_err!(self.tcx.sess, ex.span, E0600,
                                      "cannot apply unary operator `{}` to type `{}`",
-                                     op_str, actual).emit();
+                                     op.as_str(), actual).emit();
                 }
                 self.tcx.types.err
             }
         }
     }
 
-    fn name_and_trait_def_id(&self,
-                             op: hir::BinOp,
-                             is_assign: IsAssign)
-                             -> (&'static str, Option<DefId>) {
+    fn lookup_op_method(&self, lhs_ty: Ty<'tcx>, other_tys: &[Ty<'tcx>], op: Op)
+                        -> Result<MethodCallee<'tcx>, ()>
+    {
         let lang = &self.tcx.lang_items;
 
-        if let IsAssign::Yes = is_assign {
+        let span = match op {
+            Op::Binary(op, _) => op.span,
+            Op::Unary(_, span) => span
+        };
+        let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op {
             match op.node {
                 hir::BiAdd => ("add_assign", lang.add_assign_trait()),
                 hir::BiSub => ("sub_assign", lang.sub_assign_trait()),
@@ -349,12 +380,12 @@ fn name_and_trait_def_id(&self,
                 hir::BiGe | hir::BiGt |
                 hir::BiEq | hir::BiNe |
                 hir::BiAnd | hir::BiOr => {
-                    span_bug!(op.span,
+                    span_bug!(span,
                               "impossible assignment operation: {}=",
                               op.node.as_str())
                 }
             }
-        } else {
+        } else if let Op::Binary(op, IsAssign::No) = op {
             match op.node {
                 hir::BiAdd => ("add", lang.add_trait()),
                 hir::BiSub => ("sub", lang.sub_trait()),
@@ -373,59 +404,34 @@ fn name_and_trait_def_id(&self,
                 hir::BiEq => ("eq", lang.eq_trait()),
                 hir::BiNe => ("ne", lang.eq_trait()),
                 hir::BiAnd | hir::BiOr => {
-                    span_bug!(op.span, "&& and || are not overloadable")
+                    span_bug!(span, "&& and || are not overloadable")
                 }
             }
-        }
-    }
+        } else if let Op::Unary(hir::UnNot, _) = op {
+            ("not", lang.not_trait())
+        } else if let Op::Unary(hir::UnNeg, _) = op {
+            ("neg", lang.neg_trait())
+        } else {
+            bug!("lookup_op_method: op not supported: {:?}", op)
+        };
 
-    fn lookup_op_method(&self,
-                        expr: &'gcx hir::Expr,
-                        lhs_ty: Ty<'tcx>,
-                        other_tys: Vec<Ty<'tcx>>,
-                        opname: ast::Name,
-                        trait_did: Option<DefId>,
-                        lhs_expr: &'a hir::Expr)
-                        -> Result<Ty<'tcx>,()>
-    {
-        debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, \
-                                 trait_did={:?}, lhs_expr={:?})",
-               expr,
+        debug!("lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})",
                lhs_ty,
+               op,
                opname,
-               trait_did,
-               lhs_expr);
-
-        let method = match trait_did {
-            Some(trait_did) => {
-                let lhs_expr = Some(super::AdjustedRcvr {
-                    rcvr_expr: lhs_expr, autoderefs: 0, unsize: false
-                });
-                self.lookup_method_in_trait_adjusted(expr.span,
-                                                     lhs_expr,
-                                                     opname,
-                                                     trait_did,
-                                                     lhs_ty,
-                                                     Some(other_tys))
-            }
-            None => None
-        };
+               trait_did);
+
+        let method = trait_did.and_then(|trait_did| {
+            let opname = Symbol::intern(opname);
+            self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys))
+        });
 
         match method {
             Some(ok) => {
                 let method = self.register_infer_ok_obligations(ok);
                 self.select_obligations_where_possible();
 
-                let method_ty = method.ty;
-
-                // HACK(eddyb) Fully qualified path to work around a resolve bug.
-                let method_call = ::rustc::ty::MethodCall::expr(expr.id);
-                self.tables.borrow_mut().method_map.insert(method_call, method);
-
-                // extract return type for method; all late bound regions
-                // should have been instantiated by now
-                let ret_ty = method_ty.fn_ret();
-                Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap())
+                Ok(method)
             }
             None => {
                 Err(())
@@ -491,12 +497,18 @@ fn from(op: hir::BinOp) -> BinOpCategory {
 }
 
 /// Whether the binary operation is an assignment (`a += b`), or not (`a + b`)
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 enum IsAssign {
     No,
     Yes,
 }
 
+#[derive(Clone, Copy, Debug)]
+enum Op {
+    Binary(hir::BinOp, IsAssign),
+    Unary(hir::UnOp, Span),
+}
+
 /// Returns true if this is a built-in arithmetic operation (e.g. u32
 /// + u32, i16x4 == i16x4) and false if these types would have to be
 /// overloaded to be legal. There are two reasons that we distinguish
index fd26ff65661ca366c51a9ff77c4bb7db61c21c9f..b66e311f04c6bbac5265f3f0b9b63edb2db2c9d2 100644 (file)
@@ -91,7 +91,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
-use rustc::ty::{self, Ty, MethodCall, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound};
 use rustc::ty::adjustment;
 use rustc::ty::wf::ImpliedBound;
@@ -386,7 +386,8 @@ fn relate_free_regions(&mut self,
         for &ty in fn_sig_tys {
             let ty = self.resolve_type(ty);
             debug!("relate_free_regions(t={:?})", ty);
-            let implied_bounds = ty::wf::implied_bounds(self, body_id, ty, span);
+            let implied_bounds =
+                ty::wf::implied_bounds(self, self.fcx.param_env, body_id, ty, span);
 
             // Record any relations between free regions that we observe into the free-region-map.
             self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds);
@@ -520,15 +521,13 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
         self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span),
                                expr_ty, expr_region);
 
-        let method_call = MethodCall::expr(expr.id);
-        let opt_method_callee = self.tables.borrow().method_map.get(&method_call).cloned();
-        let has_method_map = opt_method_callee.is_some();
+        let is_method_call = self.tables.borrow().is_method_call(expr);
 
         // If we are calling a method (either explicitly or via an
         // overloaded operator), check that all of the types provided as
         // arguments for its type parameters are well-formed, and all the regions
         // provided as arguments outlive the call.
-        if let Some(callee) = opt_method_callee {
+        if is_method_call {
             let origin = match expr.node {
                 hir::ExprMethodCall(..) =>
                     infer::ParameterOrigin::MethodCall,
@@ -538,66 +537,16 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
                     infer::ParameterOrigin::OverloadedOperator
             };
 
-            self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region);
-            self.type_must_outlive(infer::ExprTypeIsNotInScope(callee.ty, expr.span),
-                                   callee.ty, expr_region);
+            let substs = self.tables.borrow().node_substs(expr.id);
+            self.substs_wf_in_scope(origin, substs, expr.span, expr_region);
+            // Arguments (sub-expressions) are checked via `constrain_call`, below.
         }
 
         // Check any autoderefs or autorefs that appear.
-        let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
-        if let Some(adjustment) = adjustment {
-            debug!("adjustment={:?}", adjustment);
-            match adjustment.kind {
-                adjustment::Adjust::DerefRef { autoderefs, ref autoref, .. } => {
-                    let expr_ty = self.resolve_node_type(expr.id);
-                    self.constrain_autoderefs(expr, autoderefs, expr_ty);
-                    if let Some(ref autoref) = *autoref {
-                        self.link_autoref(expr, autoderefs, autoref);
-
-                        // Require that the resulting region encompasses
-                        // the current node.
-                        //
-                        // FIXME(#6268) remove to support nested method calls
-                        self.type_of_node_must_outlive(infer::AutoBorrow(expr.span),
-                                                       expr.id, expr_region);
-                    }
-                }
-                /*
-                adjustment::AutoObject(_, ref bounds, ..) => {
-                    // Determine if we are casting `expr` to a trait
-                    // instance. If so, we have to be sure that the type
-                    // of the source obeys the new region bound.
-                    let source_ty = self.resolve_node_type(expr.id);
-                    self.type_must_outlive(infer::RelateObjectBound(expr.span),
-                                           source_ty, bounds.region_bound);
-                }
-                */
-                _ => {}
-            }
-
-            // If necessary, constrain destructors in the unadjusted form of this
-            // expression.
-            let cmt_result = {
-                let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
-                mc.cat_expr_unadjusted(expr)
-            };
-            match cmt_result {
-                Ok(head_cmt) => {
-                    self.check_safety_of_rvalue_destructor_if_necessary(head_cmt,
-                                                                        expr.span);
-                }
-                Err(..) => {
-                    self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd");
-                }
-            }
-        }
+        let cmt_result = self.constrain_adjustments(expr);
 
         // If necessary, constrain destructors in this expression. This will be
         // the adjusted form if there is an adjustment.
-        let cmt_result = {
-            let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
-            mc.cat_expr(expr)
-        };
         match cmt_result {
             Ok(head_cmt) => {
                 self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span);
@@ -611,57 +560,45 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
                expr, self.repeating_scope);
         match expr.node {
             hir::ExprPath(_) => {
-                self.fcx.opt_node_ty_substs(expr.id, |item_substs| {
-                    let origin = infer::ParameterOrigin::Path;
-                    self.substs_wf_in_scope(origin, &item_substs.substs, expr.span, expr_region);
-                });
+                let substs = self.tables.borrow().node_substs(expr.id);
+                let origin = infer::ParameterOrigin::Path;
+                self.substs_wf_in_scope(origin, substs, expr.span, expr_region);
             }
 
             hir::ExprCall(ref callee, ref args) => {
-                if has_method_map {
-                    self.constrain_call(expr, Some(&callee),
-                                        args.iter().map(|e| &*e), false);
+                if is_method_call {
+                    self.constrain_call(expr, Some(&callee), args.iter().map(|e| &*e));
                 } else {
                     self.constrain_callee(callee.id, expr, &callee);
-                    self.constrain_call(expr, None,
-                                        args.iter().map(|e| &*e), false);
+                    self.constrain_call(expr, None, args.iter().map(|e| &*e));
                 }
 
                 intravisit::walk_expr(self, expr);
             }
 
             hir::ExprMethodCall(.., ref args) => {
-                self.constrain_call(expr, Some(&args[0]),
-                                    args[1..].iter().map(|e| &*e), false);
+                self.constrain_call(expr, Some(&args[0]), args[1..].iter().map(|e| &*e));
 
                 intravisit::walk_expr(self, expr);
             }
 
             hir::ExprAssignOp(_, ref lhs, ref rhs) => {
-                if has_method_map {
-                    self.constrain_call(expr, Some(&lhs),
-                                        Some(&**rhs).into_iter(), false);
+                if is_method_call {
+                    self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
                 }
 
                 intravisit::walk_expr(self, expr);
             }
 
-            hir::ExprIndex(ref lhs, ref rhs) if has_method_map => {
-                self.constrain_call(expr, Some(&lhs),
-                                    Some(&**rhs).into_iter(), true);
+            hir::ExprIndex(ref lhs, ref rhs) if is_method_call => {
+                self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
 
                 intravisit::walk_expr(self, expr);
             },
 
-            hir::ExprBinary(op, ref lhs, ref rhs) if has_method_map => {
-                let implicitly_ref_args = !op.node.is_by_value();
-
-                // As `expr_method_call`, but the call is via an
-                // overloaded op.  Note that we (sadly) currently use an
-                // implicit "by ref" sort of passing style here.  This
-                // should be converted to an adjustment!
-                self.constrain_call(expr, Some(&lhs),
-                                    Some(&**rhs).into_iter(), implicitly_ref_args);
+            hir::ExprBinary(_, ref lhs, ref rhs) if is_method_call => {
+                // As `ExprMethodCall`, but the call is via an overloaded op.
+                self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
 
                 intravisit::walk_expr(self, expr);
             }
@@ -678,29 +615,14 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
                 intravisit::walk_expr(self, expr);
             }
 
-            hir::ExprUnary(op, ref lhs) if has_method_map => {
-                let implicitly_ref_args = !op.is_by_value();
-
-                // As above.
-                self.constrain_call(expr, Some(&lhs),
-                                    None::<hir::Expr>.iter(), implicitly_ref_args);
-
-                intravisit::walk_expr(self, expr);
-            }
-
             hir::ExprUnary(hir::UnDeref, ref base) => {
                 // For *a, the lifetime of a must enclose the deref
-                let method_call = MethodCall::expr(expr.id);
-                let base_ty = match self.tables.borrow().method_map.get(&method_call) {
-                    Some(method) => {
-                        self.constrain_call(expr, Some(&base),
-                                            None::<hir::Expr>.iter(), true);
-                        // late-bound regions in overloaded method calls are instantiated
-                        let fn_ret = self.tcx.no_late_bound_regions(&method.ty.fn_ret());
-                        fn_ret.unwrap()
-                    }
-                    None => self.resolve_node_type(base.id)
-                };
+                if is_method_call {
+                    self.constrain_call(expr, Some(base), None::<hir::Expr>.iter());
+                }
+                // For overloaded derefs, base_ty is the input to `Deref::deref`,
+                // but it's a reference type uing the same region as the output.
+                let base_ty = self.resolve_expr_type_adjusted(base);
                 if let ty::TyRef(r_ptr, _) = base_ty.sty {
                     self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr);
                 }
@@ -708,6 +630,13 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
                 intravisit::walk_expr(self, expr);
             }
 
+            hir::ExprUnary(_, ref lhs) if is_method_call => {
+                // As above.
+                self.constrain_call(expr, Some(&lhs), None::<hir::Expr>.iter());
+
+                intravisit::walk_expr(self, expr);
+            }
+
             hir::ExprIndex(ref vec_expr, _) => {
                 // For a[b], the lifetime of a must enclose the deref
                 let vec_type = self.resolve_expr_type_adjusted(&vec_expr);
@@ -859,19 +788,15 @@ fn constrain_callee(&mut self,
     fn constrain_call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
                                                            call_expr: &hir::Expr,
                                                            receiver: Option<&hir::Expr>,
-                                                           arg_exprs: I,
-                                                           implicitly_ref_args: bool) {
+                                                           arg_exprs: I) {
         //! Invoked on every call site (i.e., normal calls, method calls,
         //! and overloaded operators). Constrains the regions which appear
         //! in the type of the function. Also constrains the regions that
         //! appear in the arguments appropriately.
 
-        debug!("constrain_call(call_expr={:?}, \
-                receiver={:?}, \
-                implicitly_ref_args={})",
+        debug!("constrain_call(call_expr={:?}, receiver={:?})",
                 call_expr,
-                receiver,
-                implicitly_ref_args);
+                receiver);
 
         // `callee_region` is the scope representing the time in which the
         // call occurs.
@@ -889,14 +814,6 @@ fn constrain_call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
             // valid for at least the lifetime of the function:
             self.type_of_node_must_outlive(infer::CallArg(arg_expr.span),
                                            arg_expr.id, callee_region);
-
-            // unfortunately, there are two means of taking implicit
-            // references, and we need to propagate constraints as a
-            // result. modes are going away and the "DerefArgs" code
-            // should be ported to use adjustments
-            if implicitly_ref_args {
-                self.link_by_ref(arg_expr, callee_scope);
-            }
         }
 
         // as loop above, but for receiver
@@ -904,89 +821,83 @@ fn constrain_call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
             debug!("receiver: {:?}", r);
             self.type_of_node_must_outlive(infer::CallRcvr(r.span),
                                            r.id, callee_region);
-            if implicitly_ref_args {
-                self.link_by_ref(&r, callee_scope);
-            }
         }
     }
 
-    /// Invoked on any auto-dereference that occurs. Checks that if this is a region pointer being
+    /// Invoked on any adjustments that occur. Checks that if this is a region pointer being
     /// dereferenced, the lifetime of the pointer includes the deref expr.
-    fn constrain_autoderefs(&mut self,
-                            deref_expr: &hir::Expr,
-                            derefs: usize,
-                            mut derefd_ty: Ty<'tcx>)
-    {
-        debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})",
-               deref_expr,
-               derefs,
-               derefd_ty);
-
-        let r_deref_expr = self.tcx.node_scope_region(deref_expr.id);
-        for i in 0..derefs {
-            let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
-            debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
-
-            let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone());
-
-            derefd_ty = match method {
-                Some(method) => {
-                    debug!("constrain_autoderefs: #{} is overloaded, method={:?}",
-                           i, method);
-
-                    let origin = infer::ParameterOrigin::OverloadedDeref;
-                    self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr);
-
-                    // Treat overloaded autoderefs as if an AutoBorrow adjustment
-                    // was applied on the base type, as that is always the case.
-                    let fn_sig = method.ty.fn_sig();
-                    let fn_sig = // late-bound regions should have been instantiated
-                        self.tcx.no_late_bound_regions(&fn_sig).unwrap();
-                    let self_ty = fn_sig.inputs()[0];
-                    let (m, r) = match self_ty.sty {
-                        ty::TyRef(r, ref m) => (m.mutbl, r),
-                        _ => {
-                            span_bug!(
-                                deref_expr.span,
-                                "bad overloaded deref type {:?}",
-                                method.ty)
-                        }
-                    };
-
-                    debug!("constrain_autoderefs: receiver r={:?} m={:?}",
-                           r, m);
-
-                    {
-                        let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
-                        let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
-                        debug!("constrain_autoderefs: self_cmt={:?}",
-                               self_cmt);
-                        self.link_region(deref_expr.span, r,
-                                         ty::BorrowKind::from_mutbl(m), self_cmt);
-                    }
+    fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult<mc::cmt<'tcx>> {
+        debug!("constrain_adjustments(expr={:?})", expr);
 
-                    // Specialized version of constrain_call.
-                    self.type_must_outlive(infer::CallRcvr(deref_expr.span),
-                                           self_ty, r_deref_expr);
-                    self.type_must_outlive(infer::CallReturn(deref_expr.span),
-                                           fn_sig.output(), r_deref_expr);
-                    fn_sig.output()
-                }
-                None => derefd_ty
-            };
+        let mut cmt = {
+            let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
+            mc.cat_expr_unadjusted(expr)?
+        };
+
+        //NOTE(@jroesch): mixed RefCell borrow causes crash
+        let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec();
+        if adjustments.is_empty() {
+            return Ok(cmt);
+        }
 
-            if let ty::TyRef(r_ptr, _) =  derefd_ty.sty {
-                self.mk_subregion_due_to_dereference(deref_expr.span,
-                                                     r_deref_expr, r_ptr);
+        debug!("constrain_adjustments: adjustments={:?}", adjustments);
+
+        // If necessary, constrain destructors in the unadjusted form of this
+        // expression.
+        self.check_safety_of_rvalue_destructor_if_necessary(cmt.clone(), expr.span);
+
+        let expr_region = self.tcx.node_scope_region(expr.id);
+        for adjustment in adjustments {
+            debug!("constrain_adjustments: adjustment={:?}, cmt={:?}",
+                   adjustment, cmt);
+
+            if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind {
+                debug!("constrain_adjustments: overloaded deref: {:?}", deref);
+
+                // Treat overloaded autoderefs as if an AutoBorrow adjustment
+                // was applied on the base type, as that is always the case.
+                let input = self.tcx.mk_ref(deref.region, ty::TypeAndMut {
+                    ty: cmt.ty,
+                    mutbl: deref.mutbl,
+                });
+                let output = self.tcx.mk_ref(deref.region, ty::TypeAndMut {
+                    ty: adjustment.target,
+                    mutbl: deref.mutbl,
+                });
+
+                self.link_region(expr.span, deref.region,
+                                 ty::BorrowKind::from_mutbl(deref.mutbl), cmt.clone());
+
+                // Specialized version of constrain_call.
+                self.type_must_outlive(infer::CallRcvr(expr.span),
+                                       input, expr_region);
+                self.type_must_outlive(infer::CallReturn(expr.span),
+                                       output, expr_region);
+            }
+
+            if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind {
+                self.link_autoref(expr, cmt.clone(), autoref);
+
+                // Require that the resulting region encompasses
+                // the current node.
+                //
+                // FIXME(#6268) remove to support nested method calls
+                self.type_of_node_must_outlive(infer::AutoBorrow(expr.span),
+                                               expr.id, expr_region);
+            }
+
+            {
+                let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
+                cmt = mc.cat_expr_adjusted(expr, cmt, &adjustment)?;
             }
 
-            match derefd_ty.builtin_deref(true, ty::NoPreference) {
-                Some(mt) => derefd_ty = mt.ty,
-                /* if this type can't be dereferenced, then there's already an error
-                   in the session saying so. Just bail out for now */
-                None => break
+            if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat {
+                self.mk_subregion_due_to_dereference(expr.span,
+                                                     expr_region, r_ptr);
             }
         }
+
+        Ok(cmt)
     }
 
     pub fn mk_subregion_due_to_dereference(&mut self,
@@ -1001,7 +912,7 @@ fn check_safety_of_rvalue_destructor_if_necessary(&mut self,
                                                      cmt: mc::cmt<'tcx>,
                                                      span: Span) {
         match cmt.cat {
-            Categorization::Rvalue(region, _) => {
+            Categorization::Rvalue(region) => {
                 match *region {
                     ty::ReScope(rvalue_scope) => {
                         let typ = self.resolve_type(cmt.ty);
@@ -1053,7 +964,9 @@ fn type_of_node_must_outlive(&mut self,
         // is going to fail anyway, so just stop here and let typeck
         // report errors later on in the writeback phase.
         let ty0 = self.resolve_node_type(id);
-        let ty = self.tables.borrow().adjustments.get(&id).map_or(ty0, |adj| adj.target);
+        let ty = self.tables.borrow().adjustments.get(&id)
+            .and_then(|adj| adj.last())
+            .map_or(ty0, |adj| adj.target);
         let ty = self.resolve_type(ty);
         debug!("constrain_regions_in_type_of_node(\
                 ty={}, ty0={}, id={}, minimum_lifetime={:?})",
@@ -1117,7 +1030,7 @@ fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) {
             let arg_ty = self.node_ty(arg.id);
             let re_scope = self.tcx.mk_region(ty::ReScope(body_scope));
             let arg_cmt = mc.cat_rvalue(
-                arg.id, arg.pat.span, re_scope, re_scope, arg_ty);
+                arg.id, arg.pat.span, re_scope, arg_ty);
             debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
                    arg_ty,
                    arg_cmt,
@@ -1151,13 +1064,10 @@ fn link_pattern<'t>(&self,
     /// autoref'd.
     fn link_autoref(&self,
                     expr: &hir::Expr,
-                    autoderefs: usize,
+                    expr_cmt: mc::cmt<'tcx>,
                     autoref: &adjustment::AutoBorrow<'tcx>)
     {
-        debug!("link_autoref(autoderefs={}, autoref={:?})", autoderefs, autoref);
-        let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
-        let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
-        debug!("expr_cmt={:?}", expr_cmt);
+        debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt);
 
         match *autoref {
             adjustment::AutoBorrow::Ref(r, m) => {
@@ -1172,19 +1082,6 @@ fn link_autoref(&self,
         }
     }
 
-    /// Computes the guarantor for cases where the `expr` is being passed by implicit reference and
-    /// must outlive `callee_scope`.
-    fn link_by_ref(&self,
-                   expr: &hir::Expr,
-                   callee_scope: CodeExtent) {
-        debug!("link_by_ref(expr={:?}, callee_scope={:?})",
-               expr, callee_scope);
-        let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
-        let expr_cmt = ignore_err!(mc.cat_expr(expr));
-        let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope));
-        self.link_region(expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
-    }
-
     /// Like `link_region()`, except that the region is extracted from the type of `id`,
     /// which must be some reference (`&T`, `&str`, etc).
     fn link_region_from_node_type(&self,
@@ -1224,10 +1121,8 @@ fn link_region(&self,
                    borrow_kind,
                    borrow_cmt);
             match borrow_cmt.cat.clone() {
-                Categorization::Deref(ref_cmt, _,
-                                      mc::Implicit(ref_kind, ref_region)) |
-                Categorization::Deref(ref_cmt, _,
-                                      mc::BorrowedPtr(ref_kind, ref_region)) => {
+                Categorization::Deref(ref_cmt, mc::Implicit(ref_kind, ref_region)) |
+                Categorization::Deref(ref_cmt, mc::BorrowedPtr(ref_kind, ref_region)) => {
                     match self.link_reborrowed_region(span,
                                                       borrow_region, borrow_kind,
                                                       ref_cmt, ref_region, ref_kind,
@@ -1243,7 +1138,7 @@ fn link_region(&self,
                 }
 
                 Categorization::Downcast(cmt_base, _) |
-                Categorization::Deref(cmt_base, _, mc::Unique) |
+                Categorization::Deref(cmt_base, mc::Unique) |
                 Categorization::Interior(cmt_base, _) => {
                     // Borrowing interior or owned data requires the base
                     // to be valid and borrowable in the same fashion.
@@ -1251,7 +1146,7 @@ fn link_region(&self,
                     borrow_kind = borrow_kind;
                 }
 
-                Categorization::Deref(.., mc::UnsafePtr(..)) |
+                Categorization::Deref(_, mc::UnsafePtr(..)) |
                 Categorization::StaticItem |
                 Categorization::Upvar(..) |
                 Categorization::Local(..) |
@@ -1766,7 +1661,7 @@ fn declared_projection_bounds_from_trait(&self,
 
                     // check whether this predicate applies to our current projection
                     let cause = self.fcx.misc(span);
-                    match self.eq_types(false, &cause, ty, outlives.0) {
+                    match self.at(&cause, self.fcx.param_env).eq(outlives.0, ty) {
                         Ok(ok) => {
                             self.register_infer_ok_obligations(ok);
                             Ok(outlives.1)
index 114290c52d195469dc23d6fe2b92d29ce182caab..25f5418bea9c5ab8c13e616185625dba0380680a 100644 (file)
@@ -166,9 +166,11 @@ fn analyze_closure(&mut self,
         {
             let body_owner_def_id = self.fcx.tcx.hir.body_owner_def_id(body.id());
             let region_maps = &self.fcx.tcx.region_maps(body_owner_def_id);
+            let param_env = self.fcx.param_env;
             let mut euv =
                 euv::ExprUseVisitor::with_options(self,
                                                   self.fcx,
+                                                  param_env,
                                                   region_maps,
                                                   mc::MemCategorizationOptions {
                                                       during_closure_kind_inference: true
@@ -216,9 +218,9 @@ fn analyze_closure(&mut self,
             let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
             debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
 
-            let mut deferred_call_resolutions =
+            let deferred_call_resolutions =
                 self.fcx.remove_deferred_call_resolutions(closure_def_id);
-            for deferred_call_resolution in &mut deferred_call_resolutions {
+            for deferred_call_resolution in deferred_call_resolutions {
                 deferred_call_resolution.resolve(self.fcx);
             }
         }
@@ -281,8 +283,8 @@ fn adjust_upvar_borrow_kind_for_consume(&mut self,
         debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
                guarantor);
         match guarantor.cat {
-            Categorization::Deref(.., mc::BorrowedPtr(..)) |
-            Categorization::Deref(.., mc::Implicit(..)) => {
+            Categorization::Deref(_, mc::BorrowedPtr(..)) |
+            Categorization::Deref(_, mc::Implicit(..)) => {
                 match cmt.note {
                     mc::NoteUpvarRef(upvar_id) => {
                         debug!("adjust_upvar_borrow_kind_for_consume: \
@@ -327,7 +329,7 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) {
                cmt);
 
         match cmt.cat.clone() {
-            Categorization::Deref(base, _, mc::Unique) |
+            Categorization::Deref(base, mc::Unique) |
             Categorization::Interior(base, _) |
             Categorization::Downcast(base, _) => {
                 // Interior or owned data is mutable if base is
@@ -335,8 +337,8 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) {
                 self.adjust_upvar_borrow_kind_for_mut(base);
             }
 
-            Categorization::Deref(base, _, mc::BorrowedPtr(..)) |
-            Categorization::Deref(base, _, mc::Implicit(..)) => {
+            Categorization::Deref(base, mc::BorrowedPtr(..)) |
+            Categorization::Deref(base, mc::Implicit(..)) => {
                 if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) {
                     // assignment to deref of an `&mut`
                     // borrowed pointer implies that the
@@ -346,7 +348,7 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) {
                 }
             }
 
-            Categorization::Deref(.., mc::UnsafePtr(..)) |
+            Categorization::Deref(_, mc::UnsafePtr(..)) |
             Categorization::StaticItem |
             Categorization::Rvalue(..) |
             Categorization::Local(_) |
@@ -361,7 +363,7 @@ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) {
                cmt);
 
         match cmt.cat.clone() {
-            Categorization::Deref(base, _, mc::Unique) |
+            Categorization::Deref(base, mc::Unique) |
             Categorization::Interior(base, _) |
             Categorization::Downcast(base, _) => {
                 // Interior or owned data is unique if base is
@@ -369,8 +371,8 @@ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) {
                 self.adjust_upvar_borrow_kind_for_unique(base);
             }
 
-            Categorization::Deref(base, _, mc::BorrowedPtr(..)) |
-            Categorization::Deref(base, _, mc::Implicit(..)) => {
+            Categorization::Deref(base, mc::BorrowedPtr(..)) |
+            Categorization::Deref(base, mc::Implicit(..)) => {
                 if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) {
                     // for a borrowed pointer to be unique, its
                     // base must be unique
@@ -378,7 +380,7 @@ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) {
                 }
             }
 
-            Categorization::Deref(.., mc::UnsafePtr(..)) |
+            Categorization::Deref(_, mc::UnsafePtr(..)) |
             Categorization::StaticItem |
             Categorization::Rvalue(..) |
             Categorization::Local(_) |
index 6895d7386256247d96527d88fa6bb42902c5ea13..26f708e934562ba704458f0c361e4dd7d81eda8f 100644 (file)
@@ -37,7 +37,8 @@ struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
     code: ObligationCauseCode<'gcx>,
     id: ast::NodeId,
-    span: Span
+    span: Span,
+    param_env: ty::ParamEnv<'tcx>,
 }
 
 impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
@@ -48,8 +49,9 @@ fn with_fcx<F>(&'tcx mut self, f: F) where
         let code = self.code.clone();
         let id = self.id;
         let span = self.span;
+        let param_env = self.param_env;
         self.inherited.enter(|inh| {
-            let fcx = FnCtxt::new(&inh, id);
+            let fcx = FnCtxt::new(&inh, param_env, id);
             let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
                 tcx: fcx.tcx.global_tcx(),
                 code: code
@@ -206,11 +208,13 @@ fn for_item<'tcx>(&self, item: &hir::Item)
 
     fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
                     -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
+        let def_id = self.tcx.hir.local_def_id(id);
         CheckWfFcxBuilder {
-            inherited: Inherited::build(self.tcx, self.tcx.hir.local_def_id(id)),
+            inherited: Inherited::build(self.tcx, def_id),
             code: self.code.clone(),
             id: id,
-            span: span
+            span: span,
+            param_env: self.tcx.param_env(def_id),
         }
     }
 
@@ -374,6 +378,7 @@ fn check_impl(&mut self,
                             ast_trait_ref.path.span, &trait_ref);
                     let obligations =
                         ty::wf::trait_obligations(fcx,
+                                                  fcx.param_env,
                                                   fcx.body_id,
                                                   &trait_ref,
                                                   ast_trait_ref.path.span);
@@ -405,6 +410,7 @@ fn check_where_clauses<'fcx, 'tcx>(&mut self,
             predicates.predicates
                       .iter()
                       .flat_map(|p| ty::wf::predicate_obligations(fcx,
+                                                                  fcx.param_env,
                                                                   fcx.body_id,
                                                                   p,
                                                                   span));
index b43e2423757d1faef9df751445363881339760d5..012fde16d875e256031ee3415597715ad7dfd31c 100644 (file)
@@ -16,8 +16,7 @@
 use rustc::hir;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::infer::{InferCtxt};
-use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
-use rustc::ty::adjustment;
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::fold::{TypeFolder,TypeFoldable};
 use rustc::util::nodemap::DefIdSet;
 use syntax::ast;
@@ -106,7 +105,9 @@ fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr) {
                 let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty);
 
                 if inner_ty.is_scalar() {
-                    self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
+                    let mut tables = self.fcx.tables.borrow_mut();
+                    tables.type_dependent_defs.remove(&e.id);
+                    tables.node_substs.remove(&e.id);
                 }
             }
             hir::ExprBinary(ref op, ref lhs, ref rhs) |
@@ -118,20 +119,19 @@ fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr) {
                 let rhs_ty = self.fcx.resolve_type_vars_if_possible(&rhs_ty);
 
                 if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
-                    self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
+                    let mut tables = self.fcx.tables.borrow_mut();
+                    tables.type_dependent_defs.remove(&e.id);
+                    tables.node_substs.remove(&e.id);
 
-                    // weird but true: the by-ref binops put an
-                    // adjustment on the lhs but not the rhs; the
-                    // adjustment for rhs is kind of baked into the
-                    // system.
                     match e.node {
                         hir::ExprBinary(..) => {
                             if !op.node.is_by_value() {
-                                self.fcx.tables.borrow_mut().adjustments.remove(&lhs.id);
+                                tables.adjustments.get_mut(&lhs.id).map(|a| a.pop());
+                                tables.adjustments.get_mut(&rhs.id).map(|a| a.pop());
                             }
                         },
                         hir::ExprAssignOp(..) => {
-                            self.fcx.tables.borrow_mut().adjustments.remove(&lhs.id);
+                            tables.adjustments.get_mut(&lhs.id).map(|a| a.pop());
                         },
                         _ => {},
                     }
@@ -164,7 +164,6 @@ fn visit_expr(&mut self, e: &'gcx hir::Expr) {
         self.fix_scalar_builtin_expr(e);
 
         self.visit_node_id(e.span, e.id);
-        self.visit_method_map_entry(e.span, MethodCall::expr(e.id));
 
         if let hir::ExprClosure(_, _, body, _) = e.node {
             let body = self.fcx.tcx.hir.body(body);
@@ -280,9 +279,9 @@ fn visit_anon_types(&mut self) {
     }
 
     fn visit_node_id(&mut self, span: Span, node_id: ast::NodeId) {
-        // Export associated path extensions.
-        if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&node_id) {
-            self.tables.type_relative_path_defs.insert(node_id, def);
+        // Export associated path extensions and method resultions.
+        if let Some(def) = self.fcx.tables.borrow_mut().type_dependent_defs.remove(&node_id) {
+            self.tables.type_dependent_defs.insert(node_id, def);
         }
 
         // Resolve any borrowings for the node with id `node_id`
@@ -295,94 +294,29 @@ fn visit_node_id(&mut self, span: Span, node_id: ast::NodeId) {
         debug!("Node {} has type {:?}", node_id, n_ty);
 
         // Resolve any substitutions
-        self.fcx.opt_node_ty_substs(node_id, |item_substs| {
-            let item_substs = self.resolve(item_substs, &span);
-            if !item_substs.is_noop() {
-                debug!("write_substs_to_tcx({}, {:?})", node_id, item_substs);
-                assert!(!item_substs.substs.needs_infer());
-                self.tables.item_substs.insert(node_id, item_substs);
-            }
-        });
+        if let Some(&substs) = self.fcx.tables.borrow().node_substs.get(&node_id) {
+            let substs = self.resolve(&substs, &span);
+            debug!("write_substs_to_tcx({}, {:?})", node_id, substs);
+            assert!(!substs.needs_infer());
+            self.tables.node_substs.insert(node_id, substs);
+        }
     }
 
     fn visit_adjustments(&mut self, span: Span, node_id: ast::NodeId) {
-        let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&node_id);
-        match adjustments {
+        let adjustment = self.fcx.tables.borrow_mut().adjustments.remove(&node_id);
+        match adjustment {
             None => {
                 debug!("No adjustments for node {}", node_id);
             }
 
             Some(adjustment) => {
-                let resolved_adjustment = match adjustment.kind {
-                    adjustment::Adjust::NeverToAny => {
-                        adjustment::Adjust::NeverToAny
-                    }
-
-                    adjustment::Adjust::ReifyFnPointer => {
-                        adjustment::Adjust::ReifyFnPointer
-                    }
-
-                    adjustment::Adjust::MutToConstPointer => {
-                        adjustment::Adjust::MutToConstPointer
-                    }
-
-                    adjustment::Adjust::ClosureFnPointer => {
-                        adjustment::Adjust::ClosureFnPointer
-                    }
-
-                    adjustment::Adjust::UnsafeFnPointer => {
-                        adjustment::Adjust::UnsafeFnPointer
-                    }
-
-                    adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => {
-                        for autoderef in 0..autoderefs {
-                            let method_call = MethodCall::autoderef(node_id, autoderef as u32);
-                            self.visit_method_map_entry(span, method_call);
-                        }
-
-                        adjustment::Adjust::DerefRef {
-                            autoderefs: autoderefs,
-                            autoref: self.resolve(&autoref, &span),
-                            unsize: unsize,
-                        }
-                    }
-                };
-                let resolved_adjustment = adjustment::Adjustment {
-                    kind: resolved_adjustment,
-                    target: self.resolve(&adjustment.target, &span)
-                };
+                let resolved_adjustment = self.resolve(&adjustment, &span);
                 debug!("Adjustments for node {}: {:?}", node_id, resolved_adjustment);
                 self.tables.adjustments.insert(node_id, resolved_adjustment);
             }
         }
     }
 
-    fn visit_method_map_entry(&mut self,
-                              method_span: Span,
-                              method_call: MethodCall) {
-        // Resolve any method map entry
-        let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&method_call) {
-            Some(method) => {
-                debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
-                       method_call,
-                       method);
-                let new_method = MethodCallee {
-                    def_id: method.def_id,
-                    ty: self.resolve(&method.ty, &method_span),
-                    substs: self.resolve(&method.substs, &method_span),
-                };
-
-                Some(new_method)
-            }
-            None => None
-        };
-
-        //NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE
-        if let Some(method) = new_method {
-            self.tables.method_map.insert(method_call, method);
-        }
-    }
-
     fn visit_liberated_fn_sigs(&mut self) {
         for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() {
             let fn_sig = self.resolve(fn_sig, &node_id);
index ff5599fb1bdbf46c24a1dd0c8474360787035b79..377b7b069d3312ec4a71b9c3b269a78d58a07c2e 100644 (file)
@@ -15,7 +15,7 @@
 use rustc::middle::region::RegionMaps;
 use rustc::middle::lang_items::UnsizeTraitLangItem;
 
-use rustc::traits::{self, ObligationCause, Reveal};
+use rustc::traits::{self, ObligationCause};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::TypeFoldable;
 use rustc::ty::adjustment::CoerceUnsizedInfo;
@@ -208,7 +208,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            source,
            target);
 
-    tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
+    tcx.infer_ctxt(()).enter(|infcx| {
         let cause = ObligationCause::misc(span, impl_node_id);
         let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
                            mt_b: ty::TypeAndMut<'tcx>,
@@ -308,7 +308,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         // we may have to evaluate constraint
                         // expressions in the course of execution.)
                         // See e.g. #41936.
-                        if let Ok(ok) = infcx.eq_types(false, &cause, b, a) {
+                        if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
                             if ok.obligations.is_empty() {
                                 return None;
                             }
@@ -376,7 +376,12 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         // Register an obligation for `A: Trait<B>`.
         let cause = traits::ObligationCause::misc(span, impl_node_id);
-        let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
+        let predicate = tcx.predicate_for_trait_def(param_env,
+                                                    cause,
+                                                    trait_def_id,
+                                                    0,
+                                                    source,
+                                                    &[target]);
         fulfill_cx.register_predicate_obligation(&infcx, predicate);
 
         // Check that all transitive obligations are satisfied.
@@ -387,8 +392,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // Finally, resolve all regions.
         let region_maps = RegionMaps::new();
         let mut free_regions = FreeRegionMap::new();
-        free_regions.relate_free_regions_from_predicates(&infcx.param_env
-            .caller_bounds);
+        free_regions.relate_free_regions_from_predicates(&param_env.caller_bounds);
         infcx.resolve_regions_and_report_errors(impl_did, &region_maps, &free_regions);
 
         CoerceUnsizedInfo {
index 2751e1ff38a5090620344d49ded167658087a8e5..afeb85a7a065698f68593887929e818a86630413 100644 (file)
@@ -11,7 +11,7 @@
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use rustc::traits::{self, Reveal};
+use rustc::traits;
 use rustc::ty::{self, TyCtxt};
 
 pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -70,7 +70,7 @@ fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
 
         for (i, &impl1_def_id) in impls.iter().enumerate() {
             for &impl2_def_id in &impls[(i + 1)..] {
-                self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+                self.tcx.infer_ctxt(()).enter(|infcx| {
                     if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
                         self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
                     }
index 699b5f330d4577ac5dcd10a94b075910608fb49a..06cb9f948c9b3927efde87894b801dba3fc6358f 100644 (file)
 
 #![allow(non_camel_case_types)]
 
+#![feature(advanced_slice_patterns)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(conservative_impl_trait)]
 #![feature(never_type)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(slice_patterns)]
 
 #![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
 #![cfg_attr(stage0, feature(rustc_private))]
@@ -153,9 +155,10 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 expected: Ty<'tcx>,
                                 actual: Ty<'tcx>)
                                 -> bool {
-    tcx.infer_ctxt((), Reveal::UserFacing).enter(|ref infcx| {
+    tcx.infer_ctxt(()).enter(|ref infcx| {
+        let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
         let mut fulfill_cx = FulfillmentContext::new();
-        match infcx.eq_types(false, &cause, expected, actual) {
+        match infcx.at(&cause, param_env).eq(expected, actual) {
             Ok(InferOk { obligations, .. }) => {
                 fulfill_cx.register_predicate_obligations(infcx, obligations);
             }
index 0e8a6606ae79f387aca5d2d7941e2225a98e75af..68f03d32e83cf267237be23ea61b8ad83f5077dd 100644 (file)
@@ -30,4 +30,4 @@ pulldown-cmark = { version = "0.0.14", default-features = false }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
index fcf7366e2b457cb814df040262b7b4f966cb9faa..20ce2c0249625b5270658d1fbbab68816c66f5d1 100644 (file)
@@ -1507,8 +1507,8 @@ pub enum Type {
     /// extern "ABI" fn
     BareFunction(Box<BareFunctionDecl>),
     Tuple(Vec<Type>),
-    Vector(Box<Type>),
-    FixedVector(Box<Type>, String),
+    Slice(Box<Type>),
+    Array(Box<Type>, usize),
     Never,
     Unique(Box<Type>),
     RawPointer(Mutability, Box<Type>),
@@ -1574,10 +1574,8 @@ impl Type {
     pub fn primitive_type(&self) -> Option<PrimitiveType> {
         match *self {
             Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
-            Vector(..) | BorrowedRef{ type_: box Vector(..), ..  } => Some(PrimitiveType::Slice),
-            FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => {
-                Some(PrimitiveType::Array)
-            }
+            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
+            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
             Tuple(..) => Some(PrimitiveType::Tuple),
             RawPointer(..) => Some(PrimitiveType::RawPointer),
             _ => None,
@@ -1718,11 +1716,11 @@ fn clean(&self, cx: &DocContext) -> Type {
                 BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx),
                              type_: box m.ty.clean(cx)}
             }
-            TySlice(ref ty) => Vector(box ty.clean(cx)),
+            TySlice(ref ty) => Slice(box ty.clean(cx)),
             TyArray(ref ty, length) => {
                 use rustc::middle::const_val::eval_length;
                 let n = eval_length(cx.tcx, length, "array length").unwrap();
-                FixedVector(box ty.clean(cx), n.to_string())
+                Array(box ty.clean(cx), n)
             },
             TyTup(ref tys) => Tuple(tys.clean(cx)),
             TyPath(hir::QPath::Resolved(None, ref path)) => {
@@ -1833,9 +1831,8 @@ fn clean(&self, cx: &DocContext) -> Type {
             ty::TyUint(uint_ty) => Primitive(uint_ty.into()),
             ty::TyFloat(float_ty) => Primitive(float_ty.into()),
             ty::TyStr => Primitive(PrimitiveType::Str),
-            ty::TySlice(ty) => Vector(box ty.clean(cx)),
-            ty::TyArray(ty, i) => FixedVector(box ty.clean(cx),
-                                              format!("{}", i)),
+            ty::TySlice(ty) => Slice(box ty.clean(cx)),
+            ty::TyArray(ty, n) => Array(box ty.clean(cx), n),
             ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
             ty::TyRef(r, mt) => BorrowedRef {
                 lifetime: r.clean(cx),
index 6111ea073dd1906b92e102615026e5210cda3a9c..86660c28f80ad848aea2e827034790259ed3d104 100644 (file)
@@ -25,7 +25,6 @@
 use clean::{self, PrimitiveType};
 use core::DocAccessLevels;
 use html::item_type::ItemType;
-use html::escape::Escape;
 use html::render;
 use html::render::{cache, CURRENT_LOCATION_KEY};
 
@@ -643,21 +642,15 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
                 }
             }
         }
-        clean::Vector(ref t) => {
+        clean::Slice(ref t) => {
             primitive_link(f, PrimitiveType::Slice, "[")?;
             fmt::Display::fmt(t, f)?;
             primitive_link(f, PrimitiveType::Slice, "]")
         }
-        clean::FixedVector(ref t, ref s) => {
+        clean::Array(ref t, n) => {
             primitive_link(f, PrimitiveType::Array, "[")?;
             fmt::Display::fmt(t, f)?;
-            if f.alternate() {
-                primitive_link(f, PrimitiveType::Array,
-                               &format!("; {}]", s))
-            } else {
-                primitive_link(f, PrimitiveType::Array,
-                               &format!("; {}]", Escape(s)))
-            }
+            primitive_link(f, PrimitiveType::Array, &format!("; {}]", n))
         }
         clean::Never => f.write_str("!"),
         clean::RawPointer(m, ref t) => {
@@ -685,7 +678,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
             };
             let m = MutableSpace(mutability);
             match **ty {
-                clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
+                clean::Slice(ref bt) => { // BorrowedRef{ ... Slice(T) } is &[T]
                     match **bt {
                         clean::Generic(_) => {
                             if f.alternate() {
index 717892be2abad5f4eb4bf9855527453d81a5228e..e17918506fe5aa62868b1028a28fe4e648facb3c 100644 (file)
@@ -35,7 +35,7 @@ rustc_tsan = { path = "../librustc_tsan" }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-gcc = "0.3.27"
+gcc = "0.3.50"
 
 [features]
 backtrace = []
index fb67eaf3c63a903f4c2b4eb9b994539c04c688f7..0a5804a774411c0b078d8070bc5b944283461dc2 100644 (file)
@@ -208,6 +208,7 @@ fn as_str(&self) -> &'static str {
 /// the heap (for normal construction via Error::new) is too costly.
 #[stable(feature = "io_error_from_errorkind", since = "1.14.0")]
 impl From<ErrorKind> for Error {
+    #[inline]
     fn from(kind: ErrorKind) -> Error {
         Error {
             repr: Repr::Simple(kind)
index 744868e2e23966025da9e1eb94dd5f9a92b106a1..7d5e1929cd2a162683d96884a70085d9c16f6536 100644 (file)
@@ -1370,14 +1370,16 @@ fn recv_max_until(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
     /// let (send, recv) = channel();
     ///
     /// thread::spawn(move || {
-    ///     send.send(1u8).unwrap();
-    ///     send.send(2u8).unwrap();
-    ///     send.send(3u8).unwrap();
+    ///     send.send(1).unwrap();
+    ///     send.send(2).unwrap();
+    ///     send.send(3).unwrap();
     /// });
     ///
-    /// for x in recv.iter() {
-    ///     println!("Got: {}", x);
-    /// }
+    /// let mut iter = recv.iter();
+    /// assert_eq!(iter.next(), Some(1));
+    /// assert_eq!(iter.next(), Some(2));
+    /// assert_eq!(iter.next(), Some(3));
+    /// assert_eq!(iter.next(), None);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter(&self) -> Iter<T> {
@@ -1393,29 +1395,34 @@ pub fn iter(&self) -> Iter<T> {
     ///
     /// # Examples
     ///
-    /// ```rust
+    /// ```no_run
     /// use std::sync::mpsc::channel;
     /// use std::thread;
     /// use std::time::Duration;
     ///
     /// let (sender, receiver) = channel();
     ///
-    /// // Nothing is in the buffer yet
+    /// // nothing is in the buffer yet
     /// assert!(receiver.try_iter().next().is_none());
-    /// println!("Nothing in the buffer...");
     ///
     /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_secs(1));
     ///     sender.send(1).unwrap();
     ///     sender.send(2).unwrap();
     ///     sender.send(3).unwrap();
     /// });
     ///
-    /// println!("Going to sleep...");
-    /// thread::sleep(Duration::from_secs(2)); // block for two seconds
+    /// // nothing is in the buffer yet
+    /// assert!(receiver.try_iter().next().is_none());
+    ///
+    /// // block for two seconds
+    /// thread::sleep(Duration::from_secs(2));
     ///
-    /// for x in receiver.try_iter() {
-    ///     println!("Got: {}", x);
-    /// }
+    /// let mut iter = receiver.try_iter();
+    /// assert_eq!(iter.next(), Some(1));
+    /// assert_eq!(iter.next(), Some(2));
+    /// assert_eq!(iter.next(), Some(3));
+    /// assert_eq!(iter.next(), None);
     /// ```
     #[stable(feature = "receiver_try_iter", since = "1.15.0")]
     pub fn try_iter(&self) -> TryIter<T> {
@@ -1953,7 +1960,7 @@ fn oneshot_single_thread_recv_chan_close() {
     fn oneshot_single_thread_send_then_recv() {
         let (tx, rx) = channel::<Box<i32>>();
         tx.send(box 10).unwrap();
-        assert!(rx.recv().unwrap() == box 10);
+        assert!(*rx.recv().unwrap() == 10);
     }
 
     #[test]
@@ -2010,7 +2017,7 @@ fn oneshot_single_thread_peek_open() {
     fn oneshot_multi_task_recv_then_send() {
         let (tx, rx) = channel::<Box<i32>>();
         let _t = thread::spawn(move|| {
-            assert!(rx.recv().unwrap() == box 10);
+            assert!(*rx.recv().unwrap() == 10);
         });
 
         tx.send(box 10).unwrap();
@@ -2023,7 +2030,7 @@ fn oneshot_multi_task_recv_then_close() {
             drop(tx);
         });
         let res = thread::spawn(move|| {
-            assert!(rx.recv().unwrap() == box 10);
+            assert!(*rx.recv().unwrap() == 10);
         }).join();
         assert!(res.is_err());
     }
@@ -2077,7 +2084,7 @@ fn oneshot_multi_thread_send_recv_stress() {
             let _t = thread::spawn(move|| {
                 tx.send(box 10).unwrap();
             });
-            assert!(rx.recv().unwrap() == box 10);
+            assert!(*rx.recv().unwrap() == 10);
         }
     }
 
@@ -2102,7 +2109,7 @@ fn recv(rx: Receiver<Box<i32>>, i: i32) {
                 if i == 10 { return }
 
                 thread::spawn(move|| {
-                    assert!(rx.recv().unwrap() == box i);
+                    assert!(*rx.recv().unwrap() == i);
                     recv(rx, i + 1);
                 });
             }
@@ -2639,7 +2646,7 @@ fn oneshot_single_thread_recv_chan_close() {
     fn oneshot_single_thread_send_then_recv() {
         let (tx, rx) = sync_channel::<Box<i32>>(1);
         tx.send(box 10).unwrap();
-        assert!(rx.recv().unwrap() == box 10);
+        assert!(*rx.recv().unwrap() == 10);
     }
 
     #[test]
@@ -2711,7 +2718,7 @@ fn oneshot_single_thread_peek_open() {
     fn oneshot_multi_task_recv_then_send() {
         let (tx, rx) = sync_channel::<Box<i32>>(0);
         let _t = thread::spawn(move|| {
-            assert!(rx.recv().unwrap() == box 10);
+            assert!(*rx.recv().unwrap() == 10);
         });
 
         tx.send(box 10).unwrap();
@@ -2724,7 +2731,7 @@ fn oneshot_multi_task_recv_then_close() {
             drop(tx);
         });
         let res = thread::spawn(move|| {
-            assert!(rx.recv().unwrap() == box 10);
+            assert!(*rx.recv().unwrap() == 10);
         }).join();
         assert!(res.is_err());
     }
@@ -2778,7 +2785,7 @@ fn oneshot_multi_thread_send_recv_stress() {
             let _t = thread::spawn(move|| {
                 tx.send(box 10).unwrap();
             });
-            assert!(rx.recv().unwrap() == box 10);
+            assert!(*rx.recv().unwrap() == 10);
         }
     }
 
@@ -2803,7 +2810,7 @@ fn recv(rx: Receiver<Box<i32>>, i: i32) {
                 if i == 10 { return }
 
                 thread::spawn(move|| {
-                    assert!(rx.recv().unwrap() == box i);
+                    assert!(*rx.recv().unwrap() == i);
                     recv(rx, i + 1);
                 });
             }
index a6b0ada72b8fb7ef17172df0e645e3964d858d79..0beb173477d90ab800e9583e9f868b5381a1007f 100644 (file)
@@ -12,7 +12,7 @@
 use core::{mem, slice};
 
 #[derive(Copy, Clone, Debug, Default)]
-#[repr(packed)]
+#[repr(C)]
 pub struct Stat {
     pub st_dev: u64,
     pub st_ino: u64,
@@ -51,7 +51,7 @@ fn deref_mut(&mut self) -> &mut [u8] {
 }
 
 #[derive(Copy, Clone, Debug, Default)]
-#[repr(packed)]
+#[repr(C)]
 pub struct StatVfs {
     pub f_bsize: u32,
     pub f_blocks: u64,
@@ -79,7 +79,7 @@ fn deref_mut(&mut self) -> &mut [u8] {
 }
 
 #[derive(Copy, Clone, Debug, Default)]
-#[repr(packed)]
+#[repr(C)]
 pub struct TimeSpec {
     pub tv_sec: i64,
     pub tv_nsec: i32,
index 5b5e29c0374f021defbeac8ad0bc31410506c43d..ab609126cdb544443c957f14fcfb03351b6f0666 100644 (file)
@@ -102,7 +102,7 @@ pub struct mx_info_process_t {
 }
 
 extern {
-    static __magenta_job_default: mx_handle_t;
+    pub fn mx_job_default() -> mx_handle_t;
 
     pub fn mx_task_kill(handle: mx_handle_t) -> mx_status_t;
 
@@ -119,10 +119,6 @@ pub fn mx_object_get_info(handle: mx_handle_t, topic: u32, buffer: *mut c_void,
                               avail: *mut mx_size_t) -> mx_status_t;
 }
 
-pub fn mx_job_default() -> mx_handle_t {
-    unsafe { return __magenta_job_default; }
-}
-
 // From `enum special_handles` in system/ulib/launchpad/launchpad.c
 // HND_LOADER_SVC = 0
 // HND_EXEC_VMO = 1
index d0e3b00d75fac43fdf2ad5f869e0f1add11be067..64c31c2a681cf2a259006caf7a14822f4a342c9b 100644 (file)
@@ -1094,11 +1094,12 @@ fn join(&mut self) -> Result<T> {
 
 /// An owned permission to join on a thread (block on its termination).
 ///
-/// A `JoinHandle` *detaches* the child thread when it is dropped.
+/// A `JoinHandle` *detaches* the associated thread when it is dropped, which
+/// means that there is no longer any handle to thread and no way to `join`
+/// on it.
 ///
 /// Due to platform restrictions, it is not possible to [`Clone`] this
-/// handle: the ability to join a child thread is a uniquely-owned
-/// permission.
+/// handle: the ability to join a thread is a uniquely-owned permission.
 ///
 /// This `struct` is created by the [`thread::spawn`] function and the
 /// [`thread::Builder::spawn`] method.
@@ -1127,6 +1128,30 @@ fn join(&mut self) -> Result<T> {
 /// }).unwrap();
 /// ```
 ///
+/// Child being detached and outliving its parent:
+///
+/// ```no_run
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let original_thread = thread::spawn(|| {
+///     let _detached_thread = thread::spawn(|| {
+///         // Here we sleep to make sure that the first thread returns before.
+///         thread::sleep(Duration::from_millis(10));
+///         // This will be called, even though the JoinHandle is dropped.
+///         println!("♫ Still alive â™«");
+///     });
+/// });
+///
+/// let _ = original_thread.join();
+/// println!("Original thread is joined.");
+///
+/// // We make sure that the new thread has time to run, before the main
+/// // thread returns.
+///
+/// thread::sleep(Duration::from_millis(1000));
+/// ```
+///
 /// [`Clone`]: ../../std/clone/trait.Clone.html
 /// [`thread::spawn`]: fn.spawn.html
 /// [`thread::Builder::spawn`]: struct.Builder.html#method.spawn
index bbe5bd4a10cf17c4fe026f92bd9aae0c66053f70..830a457df748eeefaaf19b28f9623317d3798511 100644 (file)
@@ -563,6 +563,15 @@ fn span_to_filename(&self, sp: Span) -> FileName {
     fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
         self.merge_spans(sp_lhs, sp_rhs)
     }
+    fn call_span_if_macro(&self, sp: Span) -> Span {
+        if self.span_to_filename(sp.clone()).contains("macros>") {
+            let v = sp.macro_backtrace();
+            if let Some(use_site) = v.last() {
+                return use_site.call_site;
+            }
+        }
+        sp
+    }
 }
 
 #[derive(Clone)]
index 71dc81c37592322da76ee9bddf245d21577ec2ae..8089fad5f36d880ecfb5b6d6f0a020e0f2af0b29 100644 (file)
@@ -552,7 +552,9 @@ pub enum SyntaxExtension {
     BuiltinDerive(BuiltinDeriveFn),
 
     /// A declarative macro, e.g. `macro m() {}`.
-    DeclMacro(Box<TTMacroExpander>, Option<Span> /* definition site span */),
+    ///
+    /// The second element is the definition site span.
+    DeclMacro(Box<TTMacroExpander>, Option<(ast::NodeId, Span)>),
 }
 
 impl SyntaxExtension {
index be077b481113f12c17fad392137df5465040e1b2..c91c77719e699dde0b2f66098b7de075201e6cc1 100644 (file)
@@ -472,8 +472,9 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
 
         let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark));
         let opt_expanded = match *ext {
-            SyntaxExtension::DeclMacro(ref expand, def_site_span) => {
-                if let Err(msg) = validate_and_set_expn_info(def_site_span, false) {
+            SyntaxExtension::DeclMacro(ref expand, def_span) => {
+                if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s),
+                                                             false) {
                     self.cx.span_err(path.span, &msg);
                     return kind.dummy(span);
                 }
index 15042e529e51a8c2970c7a92041ac8697306dba4..0472a94e0ced6378363df313785e33682a2f7eaf 100644 (file)
@@ -266,7 +266,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
         let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable");
         NormalTT(exp, Some((def.id, def.span)), allow_internal_unstable)
     } else {
-        SyntaxExtension::DeclMacro(exp, Some(def.span))
+        SyntaxExtension::DeclMacro(exp, Some((def.id, def.span)))
     }
 }
 
index 0bcd457851890c6db66ecbae0d988c990cbf3865..e2656bea483396006b5ed530b832500bb566ab12 100644 (file)
@@ -480,6 +480,15 @@ fn scan_optional_raw_name(&mut self) -> Option<ast::Name> {
 
         self.with_str_from(start, |string| {
             if string == "_" {
+                self.sess.span_diagnostic
+                    .struct_span_warn(mk_sp(start, self.pos),
+                                      "underscore literal suffix is not allowed")
+                    .warn("this was previously accepted by the compiler but is \
+                          being phased out; it will become a hard error in \
+                          a future release!")
+                    .note("for more information, see issue #42326 \
+                          <https://github.com/rust-lang/rust/issues/42326>")
+                    .emit();
                 None
             } else {
                 Some(Symbol::intern(string))
index 936a2e8b2e1be93ae0c9596d8da869a95e91e233..d9cb2b4ab7db072bcdb45252758adbd280a665d5 100644 (file)
@@ -5985,6 +5985,10 @@ fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
             return Ok(Some(self.parse_item_foreign_fn(visibility, lo, attrs)?));
         }
 
+        if self.check_keyword(keywords::Const) {
+            return Err(self.span_fatal(self.span, "extern items cannot be `const`"));
+        }
+
         // FIXME #5668: this will occur for a macro invocation:
         match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? {
             Some(item) => {
index 1cbde9b1a7c77c137f7b00fd8979f6d55c5a10e5..f02e7e9f0ddcf0bf6accbdea172d218dc9a9c75c 100644 (file)
@@ -37,7 +37,7 @@
 // ignore-tce
 // ignore-thumb
 // ignore-thumbeb
-// ignore-x86_64 no-ignore-x86
+// ignore-x86_64
 // ignore-xcore
 // ignore-nvptx
 // ignore-nvptx64
diff --git a/src/test/codegen/prefetch.rs b/src/test/codegen/prefetch.rs
new file mode 100644 (file)
index 0000000..9ca2f01
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::{prefetch_read_data, prefetch_write_data,
+                      prefetch_read_instruction, prefetch_write_instruction};
+
+#[no_mangle]
+pub fn check_prefetch_read_data(data: &[i8]) {
+    unsafe {
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 0, i32 1)
+        prefetch_read_data(data.as_ptr(), 0);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 1, i32 1)
+        prefetch_read_data(data.as_ptr(), 1);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 2, i32 1)
+        prefetch_read_data(data.as_ptr(), 2);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 3, i32 1)
+        prefetch_read_data(data.as_ptr(), 3);
+    }
+}
+
+#[no_mangle]
+pub fn check_prefetch_write_data(data: &[i8]) {
+    unsafe {
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 0, i32 1)
+        prefetch_write_data(data.as_ptr(), 0);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 1, i32 1)
+        prefetch_write_data(data.as_ptr(), 1);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 2, i32 1)
+        prefetch_write_data(data.as_ptr(), 2);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 1)
+        prefetch_write_data(data.as_ptr(), 3);
+    }
+}
+
+#[no_mangle]
+pub fn check_prefetch_read_instruction(data: &[i8]) {
+    unsafe {
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 0, i32 0)
+        prefetch_read_instruction(data.as_ptr(), 0);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 1, i32 0)
+        prefetch_read_instruction(data.as_ptr(), 1);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 2, i32 0)
+        prefetch_read_instruction(data.as_ptr(), 2);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 3, i32 0)
+        prefetch_read_instruction(data.as_ptr(), 3);
+    }
+}
+
+#[no_mangle]
+pub fn check_prefetch_write_instruction(data: &[i8]) {
+    unsafe {
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 0, i32 0)
+        prefetch_write_instruction(data.as_ptr(), 0);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 1, i32 0)
+        prefetch_write_instruction(data.as_ptr(), 1);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 2, i32 0)
+        prefetch_write_instruction(data.as_ptr(), 2);
+        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 0)
+        prefetch_write_instruction(data.as_ptr(), 3);
+    }
+}
+
+
index 5792ba06eb0ce3d0c0ac18869c51ec4a943734f1..436e4c1f9d22e6b5c047e4e08046f0fdfddc9293 100644 (file)
@@ -12,6 +12,6 @@ fn main() {
     let xs : Vec<Option<i32>> = vec![Some(1), None];
 
     for Some(x) in xs {}
-    //~^ ERROR E0297
+    //~^ ERROR E0005
     //~| NOTE pattern `None` not covered
 }
diff --git a/src/test/compile-fail/E0603.rs b/src/test/compile-fail/E0603.rs
new file mode 100644 (file)
index 0000000..1cc9f6b
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod SomeModule {
+    const PRIVATE: u32 = 0x_a_bad_1dea_u32;
+}
+
+fn main() {
+    SomeModule::PRIVATE; //~ ERROR E0603
+}
diff --git a/src/test/compile-fail/auxiliary/no_method_suggested_traits.rs b/src/test/compile-fail/auxiliary/no_method_suggested_traits.rs
deleted file mode 100644 (file)
index 20cebb9..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub use reexport::Reexported;
-
-pub struct Foo;
-pub enum Bar { X }
-
-pub mod foo {
-    pub trait PubPub {
-        fn method(&self) {}
-
-        fn method3(&self) {}
-    }
-
-    impl PubPub for u32 {}
-    impl PubPub for i32 {}
-}
-pub mod bar {
-    trait PubPriv {
-        fn method(&self);
-    }
-}
-mod qux {
-    pub trait PrivPub {
-        fn method(&self);
-    }
-}
-mod quz {
-    trait PrivPriv {
-        fn method(&self);
-    }
-}
-
-mod reexport {
-    pub trait Reexported {
-        fn method(&self);
-    }
-}
index a1021500be3d7ed959b035c997a1b59e88492644..c388d47da6e517b1dbbd66e36b33f3832b210f29 100644 (file)
@@ -15,6 +15,6 @@ fn main() {
     let red: color = color::rgb(255, 0, 0);
     match red {
       color::rgb(r, g, b) => { println!("rgb"); }
-      color::hsl(h, s, l) => { println!("hsl"); }  //~ ERROR no associated
+      color::hsl(h, s, l) => { println!("hsl"); }  //~ ERROR no function
     }
 }
index af7d5fec07199d4c125fa03fc0bebaa685273518..c5c83977c77fd0ae0e820a8d209b37247b82e9c8 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(unused_macros)]
+
 macro m() {} //~ ERROR `macro` is experimental (see issue #39412)
 //~| HELP add #![feature(decl_macro)] to the crate attributes to enable
 
diff --git a/src/test/compile-fail/for-loop-has-unit-body.rs b/src/test/compile-fail/for-loop-has-unit-body.rs
new file mode 100644 (file)
index 0000000..8c61fc6
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    for x in 0..3 {
+        x //~ ERROR mismatched types
+        //~| NOTE expected ()
+        //~| NOTE expected type `()`
+    }
+}
diff --git a/src/test/compile-fail/issue-21659-show-relevant-trait-impls-3.rs b/src/test/compile-fail/issue-21659-show-relevant-trait-impls-3.rs
deleted file mode 100644 (file)
index 0bb944e..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-trait Foo<A> {
-    fn foo(&self, a: A) -> A {
-        a
-    }
-}
-
-trait NotRelevant<A> {
-    fn nr(&self, a: A) -> A {
-        a
-    }
-}
-
-struct Bar;
-
-impl NotRelevant<usize> for Bar {}
-
-fn main() {
-    let f1 = Bar;
-
-    f1.foo(1usize);
-    //~^ error: method named `foo` found for type `Bar` in the current scope
-    //~| help: items from traits can only be used if the trait is implemented and in scope
-    //~| help: candidate #1: `Foo`
-}
diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs
deleted file mode 100644 (file)
index 2591d7b..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// error-pattern: overflow representing the type
-
-
-trait Mirror { type It: ?Sized; }
-impl<T: ?Sized> Mirror for T { type It = Self; }
-struct S(Option<<S as Mirror>::It>);
-
-fn main() {
-    let _s = S(None);
-}
index 751a42826d2717affdf6a51b3e8f81009c04ca04..d28c314640449cc990bc1e5a89cf3aacbf89ad4c 100644 (file)
@@ -13,9 +13,9 @@
 fn main() {
     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
     //~^ ERROR must be specified
-    //~| no associated item named
+    //~| no function or associated item named
 
     let g = BitXor::bitor;
     //~^ ERROR must be specified
-    //~| no associated item named
-}
\ No newline at end of file
+    //~| no function or associated item named
+}
index ae1320c821f8c96ec43abc5f57884a851939addc..653097ad69f726bdf297fb07040b2197c5f1ba67 100644 (file)
@@ -15,5 +15,5 @@
 
 fn main() {
     let ug = Graph::<i32, i32>::new_undirected();
-    //~^ ERROR no associated item named `new_undirected` found for type
+    //~^ ERROR no function or associated item named `new_undirected` found for type
 }
index cec4b2d15dcd30741bc9ea81fb3bdbd43ed7b8f5..b46756bb8f55401efc52e32525d018e6dcf412d6 100644 (file)
@@ -16,12 +16,10 @@ fn main() {
     let x = RefCell::new((&mut r,s));
 
     let val: &_ = x.borrow().0;
-    //~^ WARNING this temporary used to live longer - see issue #39283
-    //~^^ ERROR borrowed value does not live long enough
+    //~^ ERROR borrowed value does not live long enough
     //~| temporary value dropped here while still borrowed
     //~| temporary value created here
     //~| consider using a `let` binding to increase its lifetime
-    //~| before rustc 1.16, this temporary lived longer - see issue #39283
     println!("{}", val);
 }
 //~^ temporary value needs to live until here
index 871ecf269ceec4b926448bbeb08764e460ad0ba7..8bc1cc7bd1ace3877f8c9eebb773e51c6c0de50b 100644 (file)
@@ -22,7 +22,7 @@ fn dim() -> usize {
 
 pub struct Vector<T, D: Dim> {
     entries: [T; D::dim()]
-    //~^ ERROR no associated item named `dim` found for type `D` in the current scope
+    //~^ ERROR no function or associated item named `dim` found for type `D` in the current scope
 }
 
 fn main() {}
index 92456760b0508971bef2f5cde9506564b39b7f89..67a934fccce4ef79db73855d3b7bb2add1cb09be 100644 (file)
@@ -30,6 +30,6 @@ fn to_string(&self) -> String {
 
 fn main() {
     let p = Point::new(0.0, 0.0);
-    //~^ ERROR no associated item named `new` found for type `Point` in the current scope
+    //~^ ERROR no function or associated item named `new` found for type `Point`
     println!("{}", p.to_string());
 }
index 003329a2d7de22375e6de76df345ac4b697b0e9f..dd3a48cb15559175237f75bcd179f1ddde0c3fc5 100644 (file)
@@ -13,5 +13,6 @@
 struct Foo;
 
 fn main() {
-    Foo::bar(); //~ ERROR no associated item named `bar` found for type `Foo` in the current scope
+    Foo::bar();
+    //~^ ERROR no function or associated item named `bar` found for type `Foo`
 }
index 1ab59e790d7ee5975a6a41524625763b08c24930..39da0d47a95f351a75adc7dc8128e010b68f3065 100644 (file)
@@ -17,7 +17,7 @@ mod Foo {
     pub fn f() {}
 }
 fn g<Foo>() {
-    Foo::f(); //~ ERROR no associated item named `f`
+    Foo::f(); //~ ERROR no function or associated item named `f`
 }
 
 fn main() {}
index b8eb8434b350619ae28e38446843f579038da216..14fa74d1f32e55b33b22a3632194aca8d40ed982 100644 (file)
@@ -33,5 +33,6 @@ fn main() {
     y.zero()
      .take()    //~ ERROR no method named `take` found for type `Foo` in the current scope
      //~^ NOTE the method `take` exists but the following trait bounds were not satisfied
+     //~| NOTE the following traits define an item `take`, perhaps you need to implement one of them
      .one(0);
 }
diff --git a/src/test/compile-fail/method-suggestion-no-duplication.rs b/src/test/compile-fail/method-suggestion-no-duplication.rs
deleted file mode 100644 (file)
index 390b8f0..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// issue #21405
-// ignore-tidy-linelength
-
-struct Foo;
-
-fn foo<F>(f: F) where F: FnMut(Foo) {}
-
-fn main() {
-    foo(|s| s.is_empty());
-    //~^ ERROR no method named `is_empty` found
-    //~^^ HELP #1: `std::iter::ExactSizeIterator`
-    //~^^^ HELP #2: `core::slice::SliceExt`
-    //~^^^^ HELP #3: `core::str::StrExt`
-    //~^^^^^ HELP items from traits can only be used if the trait is implemented and in scope; the following traits define an item `is_empty`, perhaps you need to implement one of them:
-}
diff --git a/src/test/compile-fail/no-method-suggested-traits.rs b/src/test/compile-fail/no-method-suggested-traits.rs
deleted file mode 100644 (file)
index a8d97d4..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2015 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.
-
-// aux-build:no_method_suggested_traits.rs
-
-extern crate no_method_suggested_traits;
-
-struct Foo;
-enum Bar { X }
-
-mod foo {
-    pub trait Bar {
-        fn method(&self) {}
-
-        fn method2(&self) {}
-    }
-
-    impl Bar for u32 {}
-
-    impl Bar for char {}
-}
-
-fn main() {
-    // test the values themselves, and autoderef.
-
-
-    1u32.method();
-    //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them
-    //~^^ ERROR no method named
-    //~^^^ HELP `use foo::Bar;`
-    //~^^^^ HELP `use no_method_suggested_traits::foo::PubPub;`
-    std::rc::Rc::new(&mut Box::new(&1u32)).method();
-    //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them
-    //~^^ ERROR no method named
-    //~^^^ HELP `use foo::Bar;`
-    //~^^^^ HELP `use no_method_suggested_traits::foo::PubPub;`
-
-    'a'.method();
-    //~^ ERROR no method named
-    //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
-    //~^^^ HELP `use foo::Bar;`
-    std::rc::Rc::new(&mut Box::new(&'a')).method();
-    //~^ ERROR no method named
-    //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
-    //~^^^ HELP `use foo::Bar;`
-
-    1i32.method();
-    //~^ ERROR no method named
-    //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
-    //~^^^ HELP `use no_method_suggested_traits::foo::PubPub;`
-    std::rc::Rc::new(&mut Box::new(&1i32)).method();
-    //~^ ERROR no method named
-    //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
-    //~^^^ HELP `use no_method_suggested_traits::foo::PubPub;`
-
-    Foo.method();
-    //~^ ERROR no method named
-    //~^^ HELP following traits define an item `method`, perhaps you need to implement one of them
-    //~^^^ HELP `foo::Bar`
-    //~^^^^ HELP `no_method_suggested_traits::foo::PubPub`
-    //~^^^^^ HELP `no_method_suggested_traits::Reexported`
-    //~^^^^^^ HELP `no_method_suggested_traits::bar::PubPriv`
-    //~^^^^^^^ HELP `no_method_suggested_traits::qux::PrivPub`
-    //~^^^^^^^^ HELP `no_method_suggested_traits::quz::PrivPriv`
-    std::rc::Rc::new(&mut Box::new(&Foo)).method();
-    //~^ ERROR no method named
-    //~^^ HELP following traits define an item `method`, perhaps you need to implement one of them
-    //~^^^ HELP `foo::Bar`
-    //~^^^^ HELP `no_method_suggested_traits::foo::PubPub`
-    //~^^^^^ HELP `no_method_suggested_traits::Reexported`
-    //~^^^^^^ HELP `no_method_suggested_traits::bar::PubPriv`
-    //~^^^^^^^ HELP `no_method_suggested_traits::qux::PrivPub`
-    //~^^^^^^^^ HELP `no_method_suggested_traits::quz::PrivPriv`
-
-    1u64.method2();
-    //~^ ERROR no method named
-    //~^^ HELP the following trait defines an item `method2`, perhaps you need to implement it
-    //~^^^ HELP `foo::Bar`
-    std::rc::Rc::new(&mut Box::new(&1u64)).method2();
-    //~^ ERROR no method named
-    //~^^ HELP the following trait defines an item `method2`, perhaps you need to implement it
-    //~^^^ HELP `foo::Bar`
-
-    no_method_suggested_traits::Foo.method2();
-    //~^ ERROR no method named
-    //~^^ HELP following trait defines an item `method2`, perhaps you need to implement it
-    //~^^^ HELP `foo::Bar`
-    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
-    //~^ ERROR no method named
-    //~^^ HELP following trait defines an item `method2`, perhaps you need to implement it
-    //~^^^ HELP `foo::Bar`
-    no_method_suggested_traits::Bar::X.method2();
-    //~^ ERROR no method named
-    //~^^ HELP following trait defines an item `method2`, perhaps you need to implement it
-    //~^^^ HELP `foo::Bar`
-    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
-    //~^ ERROR no method named
-    //~^^ HELP following trait defines an item `method2`, perhaps you need to implement it
-    //~^^^ HELP `foo::Bar`
-
-    Foo.method3();
-    //~^ ERROR no method named
-    //~^^ HELP following trait defines an item `method3`, perhaps you need to implement it
-    //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
-    std::rc::Rc::new(&mut Box::new(&Foo)).method3();
-    //~^ ERROR no method named
-    //~^^ HELP following trait defines an item `method3`, perhaps you need to implement it
-    //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
-    Bar::X.method3();
-    //~^ ERROR no method named
-    //~^^ HELP following trait defines an item `method3`, perhaps you need to implement it
-    //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
-    std::rc::Rc::new(&mut Box::new(&Bar::X)).method3();
-    //~^ ERROR no method named
-    //~^^ HELP following trait defines an item `method3`, perhaps you need to implement it
-    //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
-
-    // should have no help:
-    1_usize.method3(); //~ ERROR no method named
-    std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); //~ ERROR no method named
-    no_method_suggested_traits::Foo.method3();  //~ ERROR no method named
-    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
-    //~^ ERROR no method named
-    no_method_suggested_traits::Bar::X.method3();  //~ ERROR no method named
-    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();
-    //~^ ERROR no method named
-}
index 721d7583230a7f7cfb0751f571e571edfec1777b..e915ca05f6751c1cf849a1dca2fb6aff3229caf1 100644 (file)
@@ -86,8 +86,10 @@ fn check_method() {
 
     // Methods, UFCS
     // a, b, c are resolved as trait items, their traits need to be in scope
-    S::a(&S); //~ ERROR no associated item named `a` found for type `S` in the current scope
-    S::b(&S); //~ ERROR no associated item named `b` found for type `S` in the current scope
+    S::a(&S);
+    //~^ ERROR no function or associated item named `a` found for type `S`
+    S::b(&S);
+    //~^ ERROR no function or associated item named `b` found for type `S`
     S::c(&S); // OK
     // a, b, c are resolved as inherent items, their traits don't need to be in scope
     C::a(&S); //~ ERROR method `a` is private
index 84bcca3fc7bd3a3726c6387ea087e21b2d6b926a..cf8f3e916022cbfe1d6f59574549419a5f51a8f2 100644 (file)
@@ -18,13 +18,13 @@ pub trait Bar<X=usize, A=Self> {
 
 fn main() {
     let a = Foo::lol();
-    //~^ ERROR no associated item named
+    //~^ ERROR no function or associated item named
     let b = Foo::<_>::lol();
-    //~^ ERROR no associated item named
+    //~^ ERROR no function or associated item named
     let c = Bar::lol();
-    //~^ ERROR no associated item named
+    //~^ ERROR no function or associated item named
     let d = Bar::<usize, _>::lol();
-    //~^ ERROR no associated item named
+    //~^ ERROR no function or associated item named
     let e = Bar::<usize>::lol();
     //~^ ERROR must be explicitly specified
 }
diff --git a/src/test/compile-fail/unused-macro-rules.rs b/src/test/compile-fail/unused-macro-rules.rs
new file mode 100644 (file)
index 0000000..5e401c0
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(unused_macros)]
+
+// Most simple case
+macro_rules! unused { //~ ERROR: unused macro definition
+    () => {};
+}
+
+// Test macros created by macros
+macro_rules! create_macro {
+    () => {
+        macro_rules! m { //~ ERROR: unused macro definition
+            () => {};
+        }
+    };
+}
+create_macro!();
+
+#[allow(unused_macros)]
+mod bar {
+    // Test that putting the #[deny] close to the macro's definition
+    // works.
+
+    #[deny(unused_macros)]
+    macro_rules! unused { //~ ERROR: unused macro definition
+        () => {};
+    }
+}
+
+fn main() {}
index 5e401c09bda597ea340caae3faea955efec496b8..9e32f01724d02892a4bbab44113d333d1161b313 100644 (file)
@@ -8,31 +8,28 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(decl_macro)]
 #![deny(unused_macros)]
 
 // Most simple case
-macro_rules! unused { //~ ERROR: unused macro definition
-    () => {};
+macro unused { //~ ERROR: unused macro definition
+    () => {}
 }
 
-// Test macros created by macros
-macro_rules! create_macro {
-    () => {
-        macro_rules! m { //~ ERROR: unused macro definition
-            () => {};
-        }
-    };
-}
-create_macro!();
-
 #[allow(unused_macros)]
 mod bar {
     // Test that putting the #[deny] close to the macro's definition
     // works.
 
     #[deny(unused_macros)]
-    macro_rules! unused { //~ ERROR: unused macro definition
-        () => {};
+    macro unused { //~ ERROR: unused macro definition
+        () => {}
+    }
+}
+
+mod boo {
+    pub(crate) macro unused { //~ ERROR: unused macro definition
+        () => {}
     }
 }
 
index e632af6c83b1d4f7950fd66e5d38da658321053d..27688867de378b471fcf12a633ee3d08580c862f 100644 (file)
@@ -12,5 +12,5 @@
 
 extern {
     const i: isize;
-    //~^ ERROR expected one of `fn`, `pub`, `static`, or `}`, found `const`
+    //~^ ERROR extern items cannot be `const`
 }
diff --git a/src/test/parse-fail/underscore-suffix-for-string.rs b/src/test/parse-fail/underscore-suffix-for-string.rs
new file mode 100644 (file)
index 0000000..05de5f8
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    let _ = "Foo"_;
+    //~^ WARNING underscore literal suffix is not allowed
+    //~| WARNING this was previously accepted
+    //~| NOTE issue #42326
+}
+
+FAIL
+//~^ ERROR
+//~| NOTE
diff --git a/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs b/src/test/run-pass-fulldeps/auxiliary/lint_group_plugin_test.rs
deleted file mode 100644 (file)
index 490aa0d..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// force-host
-
-#![feature(plugin_registrar)]
-#![feature(box_syntax, rustc_private)]
-
-// Load rustc as a plugin to get macros
-#[macro_use]
-extern crate rustc;
-extern crate rustc_plugin;
-
-use rustc::hir;
-use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray};
-use rustc_plugin::Registry;
-
-declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
-
-declare_lint!(PLEASE_LINT, Warn, "Warn about items named 'pleaselintme'");
-
-struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(TEST_LINT, PLEASE_LINT)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
-    fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
-        match &*it.name.as_str() {
-            "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"),
-            "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"),
-            _ => {}
-        }
-    }
-}
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_late_lint_pass(box Pass);
-    reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]);
-}
diff --git a/src/test/run-pass-fulldeps/auxiliary/lint_plugin_test.rs b/src/test/run-pass-fulldeps/auxiliary/lint_plugin_test.rs
deleted file mode 100644 (file)
index 8647797..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// force-host
-
-#![feature(plugin_registrar)]
-#![feature(box_syntax, rustc_private)]
-
-extern crate syntax;
-
-// Load rustc as a plugin to get macros
-#[macro_use]
-extern crate rustc;
-extern crate rustc_plugin;
-
-use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
-                  EarlyLintPassObject, LintArray};
-use rustc_plugin::Registry;
-use syntax::ast;
-declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
-
-struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(TEST_LINT)
-    }
-}
-
-impl EarlyLintPass for Pass {
-    fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
-        if it.ident.name == "lintme" {
-            cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
-        }
-    }
-}
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
-}
diff --git a/src/test/run-pass-fulldeps/deprecated-derive.rs b/src/test/run-pass-fulldeps/deprecated-derive.rs
deleted file mode 100644 (file)
index be2a45c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 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.
-
-#![feature(rustc_private)]
-#![allow(dead_code)]
-
-extern crate serialize;
-
-#[derive(Encodable)]
-//~^ WARNING derive(Encodable) is deprecated in favor of derive(RustcEncodable)
-struct Test1;
-
-fn main() { }
diff --git a/src/test/run-pass-fulldeps/lint-group-plugin.rs b/src/test/run-pass-fulldeps/lint-group-plugin.rs
deleted file mode 100644 (file)
index 978a78c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:lint_group_plugin_test.rs
-// ignore-stage1
-#![feature(plugin)]
-#![plugin(lint_group_plugin_test)]
-#![allow(dead_code)]
-
-fn lintme() { } //~ WARNING item is named 'lintme'
-fn pleaselintme() { } //~ WARNING item is named 'pleaselintme'
-
-#[allow(lint_me)]
-pub fn main() {
-    fn lintme() { }
-
-    fn pleaselintme() { }
-}
diff --git a/src/test/run-pass-fulldeps/lint-plugin-cmdline-allow.rs b/src/test/run-pass-fulldeps/lint-plugin-cmdline-allow.rs
deleted file mode 100644 (file)
index 2043120..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:lint_plugin_test.rs
-// ignore-stage1
-// compile-flags: -A test-lint
-
-#![feature(plugin)]
-#![plugin(lint_plugin_test)]
-
-fn lintme() { }
-
-pub fn main() {
-}
diff --git a/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs b/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs
deleted file mode 100644 (file)
index 2e86e11..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:lint_plugin_test.rs
-// ignore-stage1
-// compile-flags: -Z extra-plugins=lint_plugin_test
-
-#![allow(dead_code)]
-
-fn lintme() { } //~ WARNING item is named 'lintme'
-
-#[allow(test_lint)]
-pub fn main() {
-    fn lintme() { }
-}
diff --git a/src/test/run-pass-fulldeps/lint-plugin.rs b/src/test/run-pass-fulldeps/lint-plugin.rs
deleted file mode 100644 (file)
index 753ad33..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:lint_plugin_test.rs
-// ignore-stage1
-#![feature(plugin)]
-#![plugin(lint_plugin_test)]
-#![allow(dead_code)]
-
-fn lintme() { } //~ WARNING item is named 'lintme'
-
-#[allow(test_lint)]
-pub fn main() {
-    fn lintme() { }
-}
diff --git a/src/test/run-pass/deprecated-macro_escape-inner.rs b/src/test/run-pass/deprecated-macro_escape-inner.rs
deleted file mode 100644 (file)
index 1a2be7a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-mod foo {
-    #![macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use
-    //~^ HELP consider an outer attribute
-}
-
-fn main() {
-}
diff --git a/src/test/run-pass/deprecated-macro_escape.rs b/src/test/run-pass/deprecated-macro_escape.rs
deleted file mode 100644 (file)
index b9f756c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use
-mod foo {
-}
-
-fn main() {
-}
diff --git a/src/test/run-pass/deriving-meta-empty-trait-list.rs b/src/test/run-pass/deriving-meta-empty-trait-list.rs
deleted file mode 100644 (file)
index ed8a509..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(dead_code)]
-
-#[derive]   //~ WARNING empty trait list in `derive`
-struct Foo;
-
-#[derive()] //~ WARNING empty trait list in `derive`
-struct Bar;
-
-pub fn main() {}
diff --git a/src/test/run-pass/enum-size-variance.rs b/src/test/run-pass/enum-size-variance.rs
deleted file mode 100644 (file)
index a3e95a1..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-//
-#![warn(variant_size_differences)]
-#![allow(dead_code)]
-
-// Note that the following test works because all fields of the enum variants are of the same size.
-// If this test is modified and the reordering logic in librustc/ty/layout.rs kicks in, it fails.
-
-enum Enum1 { }
-
-enum Enum2 { A, B, C }
-
-enum Enum3 { D(isize), E, F }
-
-enum Enum4 { H(isize), I(isize), J }
-
-enum Enum5 {
-    L(isize, isize, isize, isize), //~ WARNING three times larger
-    M(isize),
-    N
-}
-
-enum Enum6<T, U> {
-    O(T),
-    P(U),
-    Q(isize)
-}
-
-#[allow(variant_size_differences)]
-enum Enum7 {
-    R(isize, isize, isize, isize),
-    S(isize),
-    T
-}
-pub fn main() { }
diff --git a/src/test/run-pass/for-loop-has-unit-body.rs b/src/test/run-pass/for-loop-has-unit-body.rs
new file mode 100644 (file)
index 0000000..4036fc8
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    // Check that the tail statement in the body unifies with something
+    for _ in 0..3 {
+        unsafe { std::mem::uninitialized() }
+    }
+
+    // Check that the tail statement in the body can be unit
+    for _ in 0..3 {
+        ()
+    }
+}
index 473f1cc2301dc565f7a30b2761fe8869be17b130..d07fb7b4a7143bdf537b473e0df42287d1f832b1 100644 (file)
@@ -15,7 +15,8 @@
 // ignore-windows
 
 // Ignore 32 bit targets:
-// ignore-x86, ignore-arm
+// ignore-x86
+// ignore-arm
 
 // ignore-emscripten
 
diff --git a/src/test/run-pass/issue-19100.rs b/src/test/run-pass/issue-19100.rs
deleted file mode 100644 (file)
index 7ff9ae9..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(non_snake_case)]
-#![allow(dead_code)]
-#![allow(unused_variables)]
-
-#[derive(Copy, Clone)]
-enum Foo {
-    Bar,
-    Baz
-}
-
-impl Foo {
-    fn foo(&self) {
-        match self {
-            &
-Bar if true
-//~^ WARN pattern binding `Bar` is named the same as one of the variants of the type `Foo`
-//~^^ HELP to match on a variant, consider making the path in the pattern qualified: `Foo::Bar`
-=> println!("bar"),
-            &
-Baz if false
-//~^ WARN pattern binding `Baz` is named the same as one of the variants of the type `Foo`
-//~^^ HELP to match on a variant, consider making the path in the pattern qualified: `Foo::Baz`
-=> println!("baz"),
-_ => ()
-        }
-    }
-}
-
-fn main() {}
diff --git a/src/test/run-pass/path-lookahead.rs b/src/test/run-pass/path-lookahead.rs
deleted file mode 100644 (file)
index 5c195c8..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2016 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.
-
-// Parser test for #37765
-
-fn with_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `with_parens`
-  return (<T as ToString>::to_string(&arg)); //~WARN unnecessary parentheses around `return` value
-}
-
-fn no_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `no_parens`
-  return <T as ToString>::to_string(&arg);
-}
-
-fn main() {
-
-}
diff --git a/src/test/run-pass/test-should-panic-attr.rs b/src/test/run-pass/test-should-panic-attr.rs
deleted file mode 100644 (file)
index 2d06887..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: --test
-
-#[test]
-#[should_panic = "foo"]
-//~^ WARN: attribute must be of the form:
-fn test1() {
-    panic!();
-}
-
-#[test]
-#[should_panic(expected)]
-//~^ WARN: argument must be of the form:
-fn test2() {
-    panic!();
-}
-
-#[test]
-#[should_panic(expect)]
-//~^ WARN: argument must be of the form:
-fn test3() {
-    panic!();
-}
-
-#[test]
-#[should_panic(expected(foo, bar))]
-//~^ WARN: argument must be of the form:
-fn test4() {
-    panic!();
-}
-
-#[test]
-#[should_panic(expected = "foo", bar)]
-//~^ WARN: argument must be of the form:
-fn test5() {
-    panic!();
-}
diff --git a/src/test/ui-fulldeps/auxiliary/lint_group_plugin_test.rs b/src/test/ui-fulldeps/auxiliary/lint_group_plugin_test.rs
new file mode 100644 (file)
index 0000000..490aa0d
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// force-host
+
+#![feature(plugin_registrar)]
+#![feature(box_syntax, rustc_private)]
+
+// Load rustc as a plugin to get macros
+#[macro_use]
+extern crate rustc;
+extern crate rustc_plugin;
+
+use rustc::hir;
+use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray};
+use rustc_plugin::Registry;
+
+declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
+
+declare_lint!(PLEASE_LINT, Warn, "Warn about items named 'pleaselintme'");
+
+struct Pass;
+
+impl LintPass for Pass {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(TEST_LINT, PLEASE_LINT)
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+    fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+        match &*it.name.as_str() {
+            "lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"),
+            "pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"),
+            _ => {}
+        }
+    }
+}
+
+#[plugin_registrar]
+pub fn plugin_registrar(reg: &mut Registry) {
+    reg.register_late_lint_pass(box Pass);
+    reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]);
+}
diff --git a/src/test/ui-fulldeps/auxiliary/lint_plugin_test.rs b/src/test/ui-fulldeps/auxiliary/lint_plugin_test.rs
new file mode 100644 (file)
index 0000000..8647797
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// force-host
+
+#![feature(plugin_registrar)]
+#![feature(box_syntax, rustc_private)]
+
+extern crate syntax;
+
+// Load rustc as a plugin to get macros
+#[macro_use]
+extern crate rustc;
+extern crate rustc_plugin;
+
+use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
+                  EarlyLintPassObject, LintArray};
+use rustc_plugin::Registry;
+use syntax::ast;
+declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
+
+struct Pass;
+
+impl LintPass for Pass {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(TEST_LINT)
+    }
+}
+
+impl EarlyLintPass for Pass {
+    fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
+        if it.ident.name == "lintme" {
+            cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
+        }
+    }
+}
+
+#[plugin_registrar]
+pub fn plugin_registrar(reg: &mut Registry) {
+    reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
+}
diff --git a/src/test/ui-fulldeps/deprecated-derive.rs b/src/test/ui-fulldeps/deprecated-derive.rs
new file mode 100644 (file)
index 0000000..a728523
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2015 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.
+
+// run-pass
+
+#![feature(rustc_private)]
+#![allow(dead_code)]
+
+extern crate serialize;
+
+#[derive(Encodable)]
+//~^ WARNING derive(Encodable) is deprecated in favor of derive(RustcEncodable)
+struct Test1;
+
+fn main() { }
diff --git a/src/test/ui-fulldeps/deprecated-derive.stderr b/src/test/ui-fulldeps/deprecated-derive.stderr
new file mode 100644 (file)
index 0000000..3ab7567
--- /dev/null
@@ -0,0 +1,6 @@
+warning: derive(Encodable) is deprecated in favor of derive(RustcEncodable)
+  --> $DIR/deprecated-derive.rs:18:10
+   |
+18 | #[derive(Encodable)]
+   |          ^^^^^^^^^
+
diff --git a/src/test/ui-fulldeps/lint-group-plugin.rs b/src/test/ui-fulldeps/lint-group-plugin.rs
new file mode 100644 (file)
index 0000000..fee9f45
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+// aux-build:lint_group_plugin_test.rs
+// ignore-stage1
+#![feature(plugin)]
+#![plugin(lint_group_plugin_test)]
+#![allow(dead_code)]
+
+fn lintme() { } //~ WARNING item is named 'lintme'
+fn pleaselintme() { } //~ WARNING item is named 'pleaselintme'
+
+#[allow(lint_me)]
+pub fn main() {
+    fn lintme() { }
+
+    fn pleaselintme() { }
+}
diff --git a/src/test/ui-fulldeps/lint-group-plugin.stderr b/src/test/ui-fulldeps/lint-group-plugin.stderr
new file mode 100644 (file)
index 0000000..1d68e78
--- /dev/null
@@ -0,0 +1,16 @@
+warning: item is named 'lintme'
+  --> $DIR/lint-group-plugin.rs:18:1
+   |
+18 | fn lintme() { } //~ WARNING item is named 'lintme'
+   | ^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(test_lint)] on by default
+
+warning: item is named 'pleaselintme'
+  --> $DIR/lint-group-plugin.rs:19:1
+   |
+19 | fn pleaselintme() { } //~ WARNING item is named 'pleaselintme'
+   | ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(please_lint)] on by default
+
diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs
new file mode 100644 (file)
index 0000000..1e42862
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+// aux-build:lint_plugin_test.rs
+// ignore-stage1
+// compile-flags: -A test-lint
+
+#![feature(plugin)]
+#![plugin(lint_plugin_test)]
+
+fn lintme() { }
+
+pub fn main() {
+}
diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr
new file mode 100644 (file)
index 0000000..b8513b9
--- /dev/null
@@ -0,0 +1,8 @@
+warning: function is never used: `lintme`
+  --> $DIR/lint-plugin-cmdline-allow.rs:19:1
+   |
+19 | fn lintme() { }
+   | ^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(dead_code)] on by default
+
diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-load.rs b/src/test/ui-fulldeps/lint-plugin-cmdline-load.rs
new file mode 100644 (file)
index 0000000..27ef964
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+// aux-build:lint_plugin_test.rs
+// ignore-stage1
+// compile-flags: -Z extra-plugins=lint_plugin_test
+
+#![allow(dead_code)]
+
+fn lintme() { } //~ WARNING item is named 'lintme'
+
+#[allow(test_lint)]
+pub fn main() {
+    fn lintme() { }
+}
diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr b/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr
new file mode 100644 (file)
index 0000000..42ececc
--- /dev/null
@@ -0,0 +1,8 @@
+warning: item is named 'lintme'
+  --> $DIR/lint-plugin-cmdline-load.rs:18:1
+   |
+18 | fn lintme() { } //~ WARNING item is named 'lintme'
+   | ^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(test_lint)] on by default
+
diff --git a/src/test/ui-fulldeps/lint-plugin.rs b/src/test/ui-fulldeps/lint-plugin.rs
new file mode 100644 (file)
index 0000000..304cfc3
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+// aux-build:lint_plugin_test.rs
+// ignore-stage1
+#![feature(plugin)]
+#![plugin(lint_plugin_test)]
+#![allow(dead_code)]
+
+fn lintme() { } //~ WARNING item is named 'lintme'
+
+#[allow(test_lint)]
+pub fn main() {
+    fn lintme() { }
+}
diff --git a/src/test/ui-fulldeps/lint-plugin.stderr b/src/test/ui-fulldeps/lint-plugin.stderr
new file mode 100644 (file)
index 0000000..1fe821d
--- /dev/null
@@ -0,0 +1,8 @@
+warning: item is named 'lintme'
+  --> $DIR/lint-plugin.rs:18:1
+   |
+18 | fn lintme() { } //~ WARNING item is named 'lintme'
+   | ^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(test_lint)] on by default
+
diff --git a/src/test/ui/deprecated-macro_escape-inner.rs b/src/test/ui/deprecated-macro_escape-inner.rs
new file mode 100644 (file)
index 0000000..3d253ba
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+
+mod foo {
+    #![macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use
+    //~^ HELP consider an outer attribute
+}
+
+fn main() {
+}
diff --git a/src/test/ui/deprecated-macro_escape-inner.stderr b/src/test/ui/deprecated-macro_escape-inner.stderr
new file mode 100644 (file)
index 0000000..c91db6c
--- /dev/null
@@ -0,0 +1,8 @@
+warning: macro_escape is a deprecated synonym for macro_use
+  --> $DIR/deprecated-macro_escape-inner.rs:14:5
+   |
+14 |     #![macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: consider an outer attribute, #[macro_use] mod ...
+
diff --git a/src/test/ui/deprecated-macro_escape.rs b/src/test/ui/deprecated-macro_escape.rs
new file mode 100644 (file)
index 0000000..a234572
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+
+#[macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use
+mod foo {
+}
+
+fn main() {
+}
diff --git a/src/test/ui/deprecated-macro_escape.stderr b/src/test/ui/deprecated-macro_escape.stderr
new file mode 100644 (file)
index 0000000..aa77129
--- /dev/null
@@ -0,0 +1,6 @@
+warning: macro_escape is a deprecated synonym for macro_use
+  --> $DIR/deprecated-macro_escape.rs:13:1
+   |
+13 | #[macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use
+   | ^^^^^^^^^^^^^^^
+
diff --git a/src/test/ui/deriving-meta-empty-trait-list.rs b/src/test/ui/deriving-meta-empty-trait-list.rs
new file mode 100644 (file)
index 0000000..cf4dfb9
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+
+#![allow(dead_code)]
+
+#[derive]   //~ WARNING empty trait list in `derive`
+struct Foo;
+
+#[derive()] //~ WARNING empty trait list in `derive`
+struct Bar;
+
+pub fn main() {}
diff --git a/src/test/ui/deriving-meta-empty-trait-list.stderr b/src/test/ui/deriving-meta-empty-trait-list.stderr
new file mode 100644 (file)
index 0000000..58f8714
--- /dev/null
@@ -0,0 +1,12 @@
+warning: empty trait list in `derive`
+  --> $DIR/deriving-meta-empty-trait-list.rs:15:1
+   |
+15 | #[derive]   //~ WARNING empty trait list in `derive`
+   | ^^^^^^^^^
+
+warning: empty trait list in `derive`
+  --> $DIR/deriving-meta-empty-trait-list.rs:18:1
+   |
+18 | #[derive()] //~ WARNING empty trait list in `derive`
+   | ^^^^^^^^^^^
+
diff --git a/src/test/ui/enum-size-variance.rs b/src/test/ui/enum-size-variance.rs
new file mode 100644 (file)
index 0000000..075bd9a
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+// ignore-x86
+// ignore-arm
+// ignore-emscripten
+// ^ ignore 32-bit targets, as the error message is target-dependent. see PR #41968.
+
+#![warn(variant_size_differences)]
+#![allow(dead_code)]
+
+// Note that the following test works because all fields of the enum variants are of the same size.
+// If this test is modified and the reordering logic in librustc/ty/layout.rs kicks in, it fails.
+
+enum Enum1 { }
+
+enum Enum2 { A, B, C }
+
+enum Enum3 { D(isize), E, F }
+
+enum Enum4 { H(isize), I(isize), J }
+
+enum Enum5 {
+    L(isize, isize, isize, isize), //~ WARNING three times larger
+    M(isize),
+    N
+}
+
+enum Enum6<T, U> {
+    O(T),
+    P(U),
+    Q(isize)
+}
+
+#[allow(variant_size_differences)]
+enum Enum7 {
+    R(isize, isize, isize, isize),
+    S(isize),
+    T
+}
+pub fn main() { }
diff --git a/src/test/ui/enum-size-variance.stderr b/src/test/ui/enum-size-variance.stderr
new file mode 100644 (file)
index 0000000..5745b93
--- /dev/null
@@ -0,0 +1,12 @@
+warning: enum variant is more than three times larger (32 bytes) than the next largest
+  --> $DIR/enum-size-variance.rs:32:5
+   |
+32 |     L(isize, isize, isize, isize), //~ WARNING three times larger
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/enum-size-variance.rs:17:9
+   |
+17 | #![warn(variant_size_differences)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/src/test/ui/impl-trait/auxiliary/no_method_suggested_traits.rs b/src/test/ui/impl-trait/auxiliary/no_method_suggested_traits.rs
new file mode 100644 (file)
index 0000000..20cebb9
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use reexport::Reexported;
+
+pub struct Foo;
+pub enum Bar { X }
+
+pub mod foo {
+    pub trait PubPub {
+        fn method(&self) {}
+
+        fn method3(&self) {}
+    }
+
+    impl PubPub for u32 {}
+    impl PubPub for i32 {}
+}
+pub mod bar {
+    trait PubPriv {
+        fn method(&self);
+    }
+}
+mod qux {
+    pub trait PrivPub {
+        fn method(&self);
+    }
+}
+mod quz {
+    trait PrivPriv {
+        fn method(&self);
+    }
+}
+
+mod reexport {
+    pub trait Reexported {
+        fn method(&self);
+    }
+}
index a08e77a2151e210c98916a99200a1848e2b9a60e..2206234b77744ca670a8cbaa52049cd86172c6b3 100644 (file)
@@ -8,10 +8,10 @@ error[E0308]: mismatched types
               found type `u32`
 
 error[E0277]: the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
-  --> $DIR/equality.rs:34:9
+  --> $DIR/equality.rs:34:11
    |
 34 |         n + sum_to(n - 1)
-   |         ^^^^^^^^^^^^^^^^^ no implementation for `u32 + impl Foo`
+   |           ^ no implementation for `u32 + impl Foo`
    |
    = help: the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
 
diff --git a/src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.rs b/src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.rs
new file mode 100644 (file)
index 0000000..0bb944e
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo<A> {
+    fn foo(&self, a: A) -> A {
+        a
+    }
+}
+
+trait NotRelevant<A> {
+    fn nr(&self, a: A) -> A {
+        a
+    }
+}
+
+struct Bar;
+
+impl NotRelevant<usize> for Bar {}
+
+fn main() {
+    let f1 = Bar;
+
+    f1.foo(1usize);
+    //~^ error: method named `foo` found for type `Bar` in the current scope
+    //~| help: items from traits can only be used if the trait is implemented and in scope
+    //~| help: candidate #1: `Foo`
+}
diff --git a/src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.stderr b/src/test/ui/impl-trait/issue-21659-show-relevant-trait-impls-3.stderr
new file mode 100644 (file)
index 0000000..1b1e0ea
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0599]: no method named `foo` found for type `Bar` in the current scope
+  --> $DIR/issue-21659-show-relevant-trait-impls-3.rs:30:8
+   |
+30 |     f1.foo(1usize);
+   |        ^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `foo`, perhaps you need to implement it:
+           candidate #1: `Foo`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.rs b/src/test/ui/impl-trait/method-suggestion-no-duplication.rs
new file mode 100644 (file)
index 0000000..390b8f0
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// issue #21405
+// ignore-tidy-linelength
+
+struct Foo;
+
+fn foo<F>(f: F) where F: FnMut(Foo) {}
+
+fn main() {
+    foo(|s| s.is_empty());
+    //~^ ERROR no method named `is_empty` found
+    //~^^ HELP #1: `std::iter::ExactSizeIterator`
+    //~^^^ HELP #2: `core::slice::SliceExt`
+    //~^^^^ HELP #3: `core::str::StrExt`
+    //~^^^^^ HELP items from traits can only be used if the trait is implemented and in scope; the following traits define an item `is_empty`, perhaps you need to implement one of them:
+}
diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr
new file mode 100644 (file)
index 0000000..fa08c3b
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0599]: no method named `is_empty` found for type `Foo` in the current scope
+  --> $DIR/method-suggestion-no-duplication.rs:19:15
+   |
+19 |     foo(|s| s.is_empty());
+   |               ^^^^^^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following traits define an item `is_empty`, perhaps you need to implement one of them:
+           candidate #1: `std::iter::ExactSizeIterator`
+           candidate #2: `core::slice::SliceExt`
+           candidate #3: `core::str::StrExt`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.rs b/src/test/ui/impl-trait/no-method-suggested-traits.rs
new file mode 100644 (file)
index 0000000..15891b0
--- /dev/null
@@ -0,0 +1,133 @@
+// Copyright 2015 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.
+
+// aux-build:no_method_suggested_traits.rs
+extern crate no_method_suggested_traits;
+
+struct Foo;
+enum Bar { X }
+
+mod foo {
+    pub trait Bar {
+        fn method(&self) {}
+
+        fn method2(&self) {}
+    }
+
+    impl Bar for u32 {}
+
+    impl Bar for char {}
+}
+
+fn main() {
+    // test the values themselves, and autoderef.
+
+
+    1u32.method();
+    //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them
+    //~| ERROR no method named
+    //~| HELP `use foo::Bar;`
+    //~| HELP `use no_method_suggested_traits::foo::PubPub;`
+    std::rc::Rc::new(&mut Box::new(&1u32)).method();
+    //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them
+    //~| ERROR no method named
+    //~| HELP `use foo::Bar;`
+    //~| HELP `use no_method_suggested_traits::foo::PubPub;`
+
+    'a'.method();
+    //~^ ERROR no method named
+    //~| HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
+    //~| HELP `use foo::Bar;`
+    std::rc::Rc::new(&mut Box::new(&'a')).method();
+    //~^ ERROR no method named
+    //~| HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
+    //~| HELP `use foo::Bar;`
+
+    1i32.method();
+    //~^ ERROR no method named
+    //~| HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
+    //~| HELP `use no_method_suggested_traits::foo::PubPub;`
+    std::rc::Rc::new(&mut Box::new(&1i32)).method();
+    //~^ ERROR no method named
+    //~| HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
+    //~| HELP `use no_method_suggested_traits::foo::PubPub;`
+
+    Foo.method();
+    //~^ ERROR no method named
+    //~| HELP following traits define an item `method`, perhaps you need to implement one of them
+    //~| HELP `foo::Bar`
+    //~| HELP `no_method_suggested_traits::foo::PubPub`
+    //~| HELP `no_method_suggested_traits::Reexported`
+    //~| HELP `no_method_suggested_traits::bar::PubPriv`
+    //~| HELP `no_method_suggested_traits::qux::PrivPub`
+    //~| HELP `no_method_suggested_traits::quz::PrivPriv`
+    std::rc::Rc::new(&mut Box::new(&Foo)).method();
+    //~^ ERROR no method named
+    //~| HELP following traits define an item `method`, perhaps you need to implement one of them
+    //~| HELP `foo::Bar`
+    //~| HELP `no_method_suggested_traits::foo::PubPub`
+    //~| HELP `no_method_suggested_traits::Reexported`
+    //~| HELP `no_method_suggested_traits::bar::PubPriv`
+    //~| HELP `no_method_suggested_traits::qux::PrivPub`
+    //~| HELP `no_method_suggested_traits::quz::PrivPriv`
+
+    1u64.method2();
+    //~^ ERROR no method named
+    //~| HELP the following trait defines an item `method2`, perhaps you need to implement it
+    //~| HELP `foo::Bar`
+    std::rc::Rc::new(&mut Box::new(&1u64)).method2();
+    //~^ ERROR no method named
+    //~| HELP the following trait defines an item `method2`, perhaps you need to implement it
+    //~| HELP `foo::Bar`
+
+    no_method_suggested_traits::Foo.method2();
+    //~^ ERROR no method named
+    //~| HELP following trait defines an item `method2`, perhaps you need to implement it
+    //~| HELP `foo::Bar`
+    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
+    //~^ ERROR no method named
+    //~| HELP following trait defines an item `method2`, perhaps you need to implement it
+    //~| HELP `foo::Bar`
+    no_method_suggested_traits::Bar::X.method2();
+    //~^ ERROR no method named
+    //~| HELP following trait defines an item `method2`, perhaps you need to implement it
+    //~| HELP `foo::Bar`
+    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
+    //~^ ERROR no method named
+    //~| HELP following trait defines an item `method2`, perhaps you need to implement it
+    //~| HELP `foo::Bar`
+
+    Foo.method3();
+    //~^ ERROR no method named
+    //~| HELP following trait defines an item `method3`, perhaps you need to implement it
+    //~| HELP `no_method_suggested_traits::foo::PubPub`
+    std::rc::Rc::new(&mut Box::new(&Foo)).method3();
+    //~^ ERROR no method named
+    //~| HELP following trait defines an item `method3`, perhaps you need to implement it
+    //~| HELP `no_method_suggested_traits::foo::PubPub`
+    Bar::X.method3();
+    //~^ ERROR no method named
+    //~| HELP following trait defines an item `method3`, perhaps you need to implement it
+    //~| HELP `no_method_suggested_traits::foo::PubPub`
+    std::rc::Rc::new(&mut Box::new(&Bar::X)).method3();
+    //~^ ERROR no method named
+    //~| HELP following trait defines an item `method3`, perhaps you need to implement it
+    //~| HELP `no_method_suggested_traits::foo::PubPub`
+
+    // should have no help:
+    1_usize.method3(); //~ ERROR no method named
+    std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); //~ ERROR no method named
+    no_method_suggested_traits::Foo.method3();  //~ ERROR no method named
+    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
+    //~^ ERROR no method named
+    no_method_suggested_traits::Bar::X.method3();  //~ ERROR no method named
+    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();
+    //~^ ERROR no method named
+}
diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr
new file mode 100644 (file)
index 0000000..95d3007
--- /dev/null
@@ -0,0 +1,230 @@
+error[E0599]: no method named `method` found for type `u32` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:33:10
+   |
+33 |     1u32.method();
+   |          ^^^^^^
+   |
+   = help: items from traits can only be used if the trait is in scope
+   = note: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
+           candidate #1: `use foo::Bar;`
+           candidate #2: `use no_method_suggested_traits::foo::PubPub;`
+
+error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&u32>>` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:38:44
+   |
+38 |     std::rc::Rc::new(&mut Box::new(&1u32)).method();
+   |                                            ^^^^^^
+   |
+   = help: items from traits can only be used if the trait is in scope
+   = note: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
+           candidate #1: `use foo::Bar;`
+           candidate #2: `use no_method_suggested_traits::foo::PubPub;`
+
+error[E0599]: no method named `method` found for type `char` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:44:9
+   |
+44 |     'a'.method();
+   |         ^^^^^^
+   |
+   = help: items from traits can only be used if the trait is in scope
+   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+           candidate #1: `use foo::Bar;`
+
+error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:48:43
+   |
+48 |     std::rc::Rc::new(&mut Box::new(&'a')).method();
+   |                                           ^^^^^^
+   |
+   = help: items from traits can only be used if the trait is in scope
+   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+           candidate #1: `use foo::Bar;`
+
+error[E0599]: no method named `method` found for type `i32` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:53:10
+   |
+53 |     1i32.method();
+   |          ^^^^^^
+   |
+   = help: items from traits can only be used if the trait is in scope
+   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+           candidate #1: `use no_method_suggested_traits::foo::PubPub;`
+
+error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&i32>>` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:57:44
+   |
+57 |     std::rc::Rc::new(&mut Box::new(&1i32)).method();
+   |                                            ^^^^^^
+   |
+   = help: items from traits can only be used if the trait is in scope
+   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+           candidate #1: `use no_method_suggested_traits::foo::PubPub;`
+
+error[E0599]: no method named `method` found for type `Foo` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:62:9
+   |
+62 |     Foo.method();
+   |         ^^^^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following traits define an item `method`, perhaps you need to implement one of them:
+           candidate #1: `foo::Bar`
+           candidate #2: `no_method_suggested_traits::foo::PubPub`
+           candidate #3: `no_method_suggested_traits::bar::PubPriv`
+           candidate #4: `no_method_suggested_traits::qux::PrivPub`
+           candidate #5: `no_method_suggested_traits::quz::PrivPriv`
+           candidate #6: `no_method_suggested_traits::Reexported`
+
+error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&Foo>>` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:71:43
+   |
+71 |     std::rc::Rc::new(&mut Box::new(&Foo)).method();
+   |                                           ^^^^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following traits define an item `method`, perhaps you need to implement one of them:
+           candidate #1: `foo::Bar`
+           candidate #2: `no_method_suggested_traits::foo::PubPub`
+           candidate #3: `no_method_suggested_traits::bar::PubPriv`
+           candidate #4: `no_method_suggested_traits::qux::PrivPub`
+           candidate #5: `no_method_suggested_traits::quz::PrivPriv`
+           candidate #6: `no_method_suggested_traits::Reexported`
+
+error[E0599]: no method named `method2` found for type `u64` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:81:10
+   |
+81 |     1u64.method2();
+   |          ^^^^^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `method2`, perhaps you need to implement it:
+           candidate #1: `foo::Bar`
+
+error[E0599]: no method named `method2` found for type `std::rc::Rc<&mut std::boxed::Box<&u64>>` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:85:44
+   |
+85 |     std::rc::Rc::new(&mut Box::new(&1u64)).method2();
+   |                                            ^^^^^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `method2`, perhaps you need to implement it:
+           candidate #1: `foo::Bar`
+
+error[E0599]: no method named `method2` found for type `no_method_suggested_traits::Foo` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:90:37
+   |
+90 |     no_method_suggested_traits::Foo.method2();
+   |                                     ^^^^^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `method2`, perhaps you need to implement it:
+           candidate #1: `foo::Bar`
+
+error[E0599]: no method named `method2` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:94:71
+   |
+94 |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
+   |                                                                       ^^^^^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `method2`, perhaps you need to implement it:
+           candidate #1: `foo::Bar`
+
+error[E0599]: no method named `method2` found for type `no_method_suggested_traits::Bar` in the current scope
+  --> $DIR/no-method-suggested-traits.rs:98:40
+   |
+98 |     no_method_suggested_traits::Bar::X.method2();
+   |                                        ^^^^^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `method2`, perhaps you need to implement it:
+           candidate #1: `foo::Bar`
+
+error[E0599]: no method named `method2` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:102:74
+    |
+102 |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
+    |                                                                          ^^^^^^^
+    |
+    = help: items from traits can only be used if the trait is implemented and in scope
+    = note: the following trait defines an item `method2`, perhaps you need to implement it:
+            candidate #1: `foo::Bar`
+
+error[E0599]: no method named `method3` found for type `Foo` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:107:9
+    |
+107 |     Foo.method3();
+    |         ^^^^^^^
+    |
+    = help: items from traits can only be used if the trait is implemented and in scope
+    = note: the following trait defines an item `method3`, perhaps you need to implement it:
+            candidate #1: `no_method_suggested_traits::foo::PubPub`
+
+error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&Foo>>` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:111:43
+    |
+111 |     std::rc::Rc::new(&mut Box::new(&Foo)).method3();
+    |                                           ^^^^^^^
+    |
+    = help: items from traits can only be used if the trait is implemented and in scope
+    = note: the following trait defines an item `method3`, perhaps you need to implement it:
+            candidate #1: `no_method_suggested_traits::foo::PubPub`
+
+error[E0599]: no method named `method3` found for type `Bar` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:115:12
+    |
+115 |     Bar::X.method3();
+    |            ^^^^^^^
+    |
+    = help: items from traits can only be used if the trait is implemented and in scope
+    = note: the following trait defines an item `method3`, perhaps you need to implement it:
+            candidate #1: `no_method_suggested_traits::foo::PubPub`
+
+error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&Bar>>` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:119:46
+    |
+119 |     std::rc::Rc::new(&mut Box::new(&Bar::X)).method3();
+    |                                              ^^^^^^^
+    |
+    = help: items from traits can only be used if the trait is implemented and in scope
+    = note: the following trait defines an item `method3`, perhaps you need to implement it:
+            candidate #1: `no_method_suggested_traits::foo::PubPub`
+
+error[E0599]: no method named `method3` found for type `usize` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:125:13
+    |
+125 |     1_usize.method3(); //~ ERROR no method named
+    |             ^^^^^^^
+
+error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&usize>>` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:126:47
+    |
+126 |     std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); //~ ERROR no method named
+    |                                               ^^^^^^^
+
+error[E0599]: no method named `method3` found for type `no_method_suggested_traits::Foo` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:127:37
+    |
+127 |     no_method_suggested_traits::Foo.method3();  //~ ERROR no method named
+    |                                     ^^^^^^^
+
+error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:128:71
+    |
+128 |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
+    |                                                                       ^^^^^^^
+
+error[E0599]: no method named `method3` found for type `no_method_suggested_traits::Bar` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:130:40
+    |
+130 |     no_method_suggested_traits::Bar::X.method3();  //~ ERROR no method named
+    |                                        ^^^^^^^
+
+error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope
+   --> $DIR/no-method-suggested-traits.rs:131:74
+    |
+131 |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();
+    |                                                                          ^^^^^^^
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/impl-trait/trait_type.rs b/src/test/ui/impl-trait/trait_type.rs
new file mode 100644 (file)
index 0000000..3507dcf
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct MyType;
+struct MyType2;
+struct MyType3;
+struct MyType4;
+
+impl std::fmt::Display for MyType {
+   fn fmt(&self, x: &str) -> () { }
+}
+
+impl std::fmt::Display for MyType2 {
+   fn fmt(&self) -> () { }
+}
+
+impl std::fmt::Display for MyType3 {
+   fn fmt() -> () { }
+}
+
+impl std::fmt::Display for MyType4 {}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr
new file mode 100644 (file)
index 0000000..cc7a715
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0053]: method `fmt` has an incompatible type for trait
+  --> $DIR/trait_type.rs:17:4
+   |
+17 |    fn fmt(&self, x: &str) -> () { }
+   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected type `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
+              found type `fn(&MyType, &str)`
+
+error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2
+  --> $DIR/trait_type.rs:21:11
+   |
+21 |    fn fmt(&self) -> () { }
+   |           ^^^^^ expected 2 parameters, found 1
+   |
+   = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
+
+error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in the impl
+  --> $DIR/trait_type.rs:25:4
+   |
+25 |    fn fmt() -> () { }
+   |    ^^^^^^^^^^^^^^^^^^ expected `&self` in impl
+   |
+   = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
+
+error[E0046]: not all trait items implemented, missing: `fmt`
+  --> $DIR/trait_type.rs:28:1
+   |
+28 | impl std::fmt::Display for MyType4 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation
+   |
+   = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/issue-19100.rs b/src/test/ui/issue-19100.rs
new file mode 100644 (file)
index 0000000..bcadd94
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+
+#![allow(non_snake_case)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+#[derive(Copy, Clone)]
+enum Foo {
+    Bar,
+    Baz
+}
+
+impl Foo {
+    fn foo(&self) {
+        match self {
+            &
+Bar if true
+//~^ WARN pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+//~^^ HELP to match on a variant, consider making the path in the pattern qualified: `Foo::Bar`
+=> println!("bar"),
+            &
+Baz if false
+//~^ WARN pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+//~^^ HELP to match on a variant, consider making the path in the pattern qualified: `Foo::Baz`
+=> println!("baz"),
+_ => ()
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issue-19100.stderr b/src/test/ui/issue-19100.stderr
new file mode 100644 (file)
index 0000000..45e2ef6
--- /dev/null
@@ -0,0 +1,16 @@
+warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+  --> $DIR/issue-19100.rs:27:1
+   |
+27 | Bar if true
+   | ^^^
+   |
+   = help: if you meant to match on a variant, consider making the path in the pattern qualified: `Foo::Bar`
+
+warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+  --> $DIR/issue-19100.rs:32:1
+   |
+32 | Baz if false
+   | ^^^
+   |
+   = help: if you meant to match on a variant, consider making the path in the pattern qualified: `Foo::Baz`
+
diff --git a/src/test/ui/issue-26548.rs b/src/test/ui/issue-26548.rs
new file mode 100644 (file)
index 0000000..2591d7b
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern: overflow representing the type
+
+
+trait Mirror { type It: ?Sized; }
+impl<T: ?Sized> Mirror for T { type It = Self; }
+struct S(Option<<S as Mirror>::It>);
+
+fn main() {
+    let _s = S(None);
+}
diff --git a/src/test/ui/issue-26548.stderr b/src/test/ui/issue-26548.stderr
new file mode 100644 (file)
index 0000000..c27ad76
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0391]: unsupported cyclic reference between types/traits detected
+  |
+note: the cycle begins when computing layout of `S`...
+note: ...which then requires computing layout of `std::option::Option<<S as Mirror>::It>`...
+note: ...which then requires computing layout of `<S as Mirror>::It`...
+  = note: ...which then again requires computing layout of `S`, completing the cycle.
+
+error: aborting due to previous error(s)
+
index d97c78137089ec721e9ee55db27a960e5077f963..1faf72cd760b75ebbb01f299320dcde3c907efb3 100644 (file)
@@ -1,56 +1,56 @@
 error[E0277]: the trait bound `{integer}: std::ops::Add<std::option::Option<{integer}>>` is not satisfied
-  --> $DIR/binops.rs:12:5
+  --> $DIR/binops.rs:12:7
    |
 12 |     1 + Some(1);
-   |     ^^^^^^^^^^^ no implementation for `{integer} + std::option::Option<{integer}>`
+   |       ^ no implementation for `{integer} + std::option::Option<{integer}>`
    |
    = help: the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
 
 error[E0277]: the trait bound `usize: std::ops::Sub<std::option::Option<{integer}>>` is not satisfied
-  --> $DIR/binops.rs:13:5
+  --> $DIR/binops.rs:13:16
    |
 13 |     2 as usize - Some(1);
-   |     ^^^^^^^^^^^^^^^^^^^^ no implementation for `usize - std::option::Option<{integer}>`
+   |                ^ no implementation for `usize - std::option::Option<{integer}>`
    |
    = help: the trait `std::ops::Sub<std::option::Option<{integer}>>` is not implemented for `usize`
 
 error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied
-  --> $DIR/binops.rs:14:5
+  --> $DIR/binops.rs:14:7
    |
 14 |     3 * ();
-   |     ^^^^^^ no implementation for `{integer} * ()`
+   |       ^ no implementation for `{integer} * ()`
    |
    = help: the trait `std::ops::Mul<()>` is not implemented for `{integer}`
 
 error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
-  --> $DIR/binops.rs:15:5
+  --> $DIR/binops.rs:15:7
    |
 15 |     4 / "";
-   |     ^^^^^^ no implementation for `{integer} / &str`
+   |       ^ no implementation for `{integer} / &str`
    |
    = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}`
 
 error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::string::String>` is not satisfied
-  --> $DIR/binops.rs:16:5
+  --> $DIR/binops.rs:16:7
    |
 16 |     5 < String::new();
-   |     ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `std::string::String`
+   |       ^ can't compare `{integer}` with `std::string::String`
    |
    = help: the trait `std::cmp::PartialEq<std::string::String>` is not implemented for `{integer}`
 
 error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd<std::string::String>` is not satisfied
-  --> $DIR/binops.rs:16:5
+  --> $DIR/binops.rs:16:7
    |
 16 |     5 < String::new();
-   |     ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `std::string::String`
+   |       ^ can't compare `{integer}` with `std::string::String`
    |
    = help: the trait `std::cmp::PartialOrd<std::string::String>` is not implemented for `{integer}`
 
 error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not satisfied
-  --> $DIR/binops.rs:17:5
+  --> $DIR/binops.rs:17:7
    |
 17 |     6 == Ok(1);
-   |     ^^^^^^^^^^ can't compare `{integer}` with `std::result::Result<{integer}, _>`
+   |       ^^ can't compare `{integer}` with `std::result::Result<{integer}, _>`
    |
    = help: the trait `std::cmp::PartialEq<std::result::Result<{integer}, _>>` is not implemented for `{integer}`
 
diff --git a/src/test/ui/path-lookahead.rs b/src/test/ui/path-lookahead.rs
new file mode 100644 (file)
index 0000000..c43f222
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+// run-pass
+
+// Parser test for #37765
+
+fn with_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `with_parens`
+  return (<T as ToString>::to_string(&arg)); //~WARN unnecessary parentheses around `return` value
+}
+
+fn no_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `no_parens`
+  return <T as ToString>::to_string(&arg);
+}
+
+fn main() {
+
+}
diff --git a/src/test/ui/path-lookahead.stderr b/src/test/ui/path-lookahead.stderr
new file mode 100644 (file)
index 0000000..1e19977
--- /dev/null
@@ -0,0 +1,28 @@
+warning: unnecessary parentheses around `return` value
+  --> $DIR/path-lookahead.rs:16:10
+   |
+16 |   return (<T as ToString>::to_string(&arg)); //~WARN unnecessary parentheses around `return` value
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(unused_parens)] on by default
+
+warning: function is never used: `with_parens`
+  --> $DIR/path-lookahead.rs:15:1
+   |
+15 | / fn with_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `with_parens`
+16 | |   return (<T as ToString>::to_string(&arg)); //~WARN unnecessary parentheses around `return` value
+17 | | }
+   | |_^
+   |
+   = note: #[warn(dead_code)] on by default
+
+warning: function is never used: `no_parens`
+  --> $DIR/path-lookahead.rs:19:1
+   |
+19 | / fn no_parens<T: ToString>(arg: T) -> String { //~WARN function is never used: `no_parens`
+20 | |   return <T as ToString>::to_string(&arg);
+21 | | }
+   | |_^
+   |
+   = note: #[warn(dead_code)] on by default
+
index b21b10c63b02b7567082762656e09e57253edae6..a1ec5f0b713a5d003cdbc2360954b2c7b991b1f5 100644 (file)
@@ -35,31 +35,31 @@ error[E0423]: expected value, found struct `xcrate::S`
 help: possible better candidate is found in another module, you can import it into scope
    | use m::S;
 
-error: tuple struct `Z` is private
+error[E0603]: tuple struct `Z` is private
   --> $DIR/privacy-struct-ctor.rs:25:9
    |
 25 |         n::Z; //~ ERROR tuple struct `Z` is private
    |         ^^^^
 
-error: tuple struct `S` is private
+error[E0603]: tuple struct `S` is private
   --> $DIR/privacy-struct-ctor.rs:35:5
    |
 35 |     m::S; //~ ERROR tuple struct `S` is private
    |     ^^^^
 
-error: tuple struct `Z` is private
+error[E0603]: tuple struct `Z` is private
   --> $DIR/privacy-struct-ctor.rs:39:5
    |
 39 |     m::n::Z; //~ ERROR tuple struct `Z` is private
    |     ^^^^^^^
 
-error: tuple struct `S` is private
+error[E0603]: tuple struct `S` is private
   --> $DIR/privacy-struct-ctor.rs:41:5
    |
 41 |     xcrate::m::S; //~ ERROR tuple struct `S` is private
    |     ^^^^^^^^^^^^
 
-error: tuple struct `Z` is private
+error[E0603]: tuple struct `Z` is private
   --> $DIR/privacy-struct-ctor.rs:45:5
    |
 45 |     xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private
index bc3122bf71c0e21056a40d31e75e4a41f6e032ed..32d80069f0087eb23836c5858a6b76a598fb3a56 100644 (file)
@@ -43,4 +43,12 @@ fn main() {
     //~| NOTE cyclic type of infinite size
     //~| NOTE expected type `_`
     //~| NOTE found type `Box<_>`
+
+    let s = &mut String::new();
+    s = format!("foo");
+    //~^ ERROR E0308
+    //~| NOTE expected mutable reference, found struct `std::string::String`
+    //~| NOTE expected type `&mut std::string::String`
+    //~| HELP try with `&mut format!("foo")`
+    //~| NOTE this error originates in a macro outside of the current crate
 }
index 47ede6f2eb1a8a718df6dc5b46835ce37adf7d46..e3bc64a2cfd416054826d1ab120a790f0f24758f 100644 (file)
@@ -47,5 +47,16 @@ error[E0308]: mismatched types
    = note: expected type `_`
               found type `std::boxed::Box<_>`
 
+error[E0308]: mismatched types
+  --> $DIR/coerce-suggestions.rs:48:9
+   |
+48 |     s = format!("foo");
+   |         ^^^^^^^^^^^^^^ expected mutable reference, found struct `std::string::String`
+   |
+   = note: expected type `&mut std::string::String`
+              found type `std::string::String`
+   = help: try with `&mut format!("foo")`
+   = note: this error originates in a macro outside of the current crate
+
 error: aborting due to previous error(s)
 
index 9f368f0de9661d1a076b8875690fdbc9fbee32b4..9bf00b1b5749a2091f49c74fbdb9303a90ee7270 100644 (file)
@@ -23,10 +23,11 @@ note: candidate #3 is defined in the trait `UnusedTrait`
 29 |     fn f9(usize) -> usize; //~ NOTE candidate
    |     ^^^^^^^^^^^^^^^^^^^^^^
    = help: to disambiguate the method call, write `UnusedTrait::f9(u, 342)` instead
-   = help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `f9`, perhaps you need to implement one of them:
-   = help: candidate #1: `CtxtFn`
-   = help: candidate #2: `OtherTrait`
-   = help: candidate #3: `UnusedTrait`
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following traits define an item `f9`, perhaps you need to implement one of them:
+           candidate #1: `CtxtFn`
+           candidate #2: `OtherTrait`
+           candidate #3: `UnusedTrait`
 
 error[E0599]: no method named `fff` found for type `Myisize` in the current scope
   --> $DIR/issue-7575.rs:74:30
@@ -58,8 +59,9 @@ note: candidate #1 is defined in the trait `ManyImplTrait`
 59 | |     }
    | |_____^
    = help: to disambiguate the method call, write `ManyImplTrait::is_str(t)` instead
-   = help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `is_str`, perhaps you need to implement it:
-   = help: candidate #1: `ManyImplTrait`
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `is_str`, perhaps you need to implement it:
+           candidate #1: `ManyImplTrait`
 
 error: aborting due to previous error(s)
 
index 057f8fe6ee274f6e22b6682013bc04be2e3a2488..0224cef8da123cbc4eaed2ec89cdb5d35414373b 100644 (file)
@@ -1,13 +1,8 @@
 error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
-  --> $DIR/multiline-span-simple.rs:23:9
+  --> $DIR/multiline-span-simple.rs:23:18
    |
-23 |       foo(1 as u32 +
-   |  _________^
-24 | |
-25 | |         bar(x,
-26 | |
-27 | |             y),
-   | |______________^ no implementation for `u32 + ()`
+23 |     foo(1 as u32 +
+   |                  ^ no implementation for `u32 + ()`
    |
    = help: the trait `std::ops::Add<()>` is not implemented for `u32`
 
diff --git a/src/test/ui/test-should-panic-attr.rs b/src/test/ui/test-should-panic-attr.rs
new file mode 100644 (file)
index 0000000..8986732
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2016 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.
+
+// run-pass
+// compile-flags: --test
+
+#[test]
+#[should_panic = "foo"]
+//~^ WARN: attribute must be of the form:
+fn test1() {
+    panic!();
+}
+
+#[test]
+#[should_panic(expected)]
+//~^ WARN: argument must be of the form:
+fn test2() {
+    panic!();
+}
+
+#[test]
+#[should_panic(expect)]
+//~^ WARN: argument must be of the form:
+fn test3() {
+    panic!();
+}
+
+#[test]
+#[should_panic(expected(foo, bar))]
+//~^ WARN: argument must be of the form:
+fn test4() {
+    panic!();
+}
+
+#[test]
+#[should_panic(expected = "foo", bar)]
+//~^ WARN: argument must be of the form:
+fn test5() {
+    panic!();
+}
diff --git a/src/test/ui/test-should-panic-attr.stderr b/src/test/ui/test-should-panic-attr.stderr
new file mode 100644 (file)
index 0000000..6f143b6
--- /dev/null
@@ -0,0 +1,40 @@
+warning: attribute must be of the form: `#[should_panic]` or `#[should_panic(expected = "error message")]`
+  --> $DIR/test-should-panic-attr.rs:15:1
+   |
+15 | #[should_panic = "foo"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: Errors in this attribute were erroneously allowed and will become a hard error in a future release.
+
+warning: argument must be of the form: `expected = "error message"`
+  --> $DIR/test-should-panic-attr.rs:22:1
+   |
+22 | #[should_panic(expected)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: Errors in this attribute were erroneously allowed and will become a hard error in a future release.
+
+warning: argument must be of the form: `expected = "error message"`
+  --> $DIR/test-should-panic-attr.rs:29:1
+   |
+29 | #[should_panic(expect)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: Errors in this attribute were erroneously allowed and will become a hard error in a future release.
+
+warning: argument must be of the form: `expected = "error message"`
+  --> $DIR/test-should-panic-attr.rs:36:1
+   |
+36 | #[should_panic(expected(foo, bar))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: Errors in this attribute were erroneously allowed and will become a hard error in a future release.
+
+warning: argument must be of the form: `expected = "error message"`
+  --> $DIR/test-should-panic-attr.rs:43:1
+   |
+43 | #[should_panic(expected = "foo", bar)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: Errors in this attribute were erroneously allowed and will become a hard error in a future release.
+
index df41e786be58fc120b37709717e79e2eedc543df..92f6f36d69d99538cd1c8fd248d99b65a3c6cddd 100644 (file)
@@ -13,6 +13,8 @@
 use std::str::FromStr;
 use std::path::PathBuf;
 
+use test::ColorConfig;
+
 #[derive(Clone, Copy, PartialEq, Debug)]
 pub enum Mode {
     CompileFail,
@@ -185,6 +187,9 @@ pub struct Config {
     // Print one character per test instead of one line
     pub quiet: bool,
 
+    // Whether to use colors in test.
+    pub color: ColorConfig,
+
     // where to find the remote test client process, if we're using it
     pub remote_test_client: Option<PathBuf>,
 
index 0f653dfbcf07c9293b1302b44ecbc5433d5e5743..c503ca7d8cd14632d03a02332f90e6521d5b8cf6 100644 (file)
@@ -80,13 +80,12 @@ fn ignore_gdb(config: &Config, line: &str) -> bool {
                 return false;
             }
 
-            if !line.contains("ignore-gdb-version") &&
-               config.parse_name_directive(line, "ignore-gdb") {
+            if config.parse_name_directive(line, "ignore-gdb") {
                 return true;
             }
 
             if let Some(actual_version) = config.gdb_version {
-                if line.contains("min-gdb-version") {
+                if line.starts_with("min-gdb-version") {
                     let (start_ver, end_ver) = extract_gdb_version_range(line);
 
                     if start_ver != end_ver {
@@ -95,7 +94,7 @@ fn ignore_gdb(config: &Config, line: &str) -> bool {
                     // Ignore if actual version is smaller the minimum required
                     // version
                     actual_version < start_ver
-                } else if line.contains("ignore-gdb-version") {
+                } else if line.starts_with("ignore-gdb-version") {
                     let (min_version, max_version) = extract_gdb_version_range(line);
 
                     if max_version < min_version {
@@ -119,20 +118,21 @@ fn ignore_gdb(config: &Config, line: &str) -> bool {
         fn extract_gdb_version_range(line: &str) -> (u32, u32) {
             const ERROR_MESSAGE: &'static str = "Malformed GDB version directive";
 
-            let range_components = line.split(' ')
-                                       .flat_map(|word| word.split('-'))
-                                       .filter(|word| word.len() > 0)
-                                       .skip_while(|word| extract_gdb_version(word).is_none())
-                                       .collect::<Vec<&str>>();
+            let range_components = line.split(&[' ', '-'][..])
+                                       .filter(|word| !word.is_empty())
+                                       .map(extract_gdb_version)
+                                       .skip_while(Option::is_none)
+                                       .take(3) // 3 or more = invalid, so take at most 3.
+                                       .collect::<Vec<Option<u32>>>();
 
             match range_components.len() {
                 1 => {
-                    let v = extract_gdb_version(range_components[0]).unwrap();
+                    let v = range_components[0].unwrap();
                     (v, v)
                 }
                 2 => {
-                    let v_min = extract_gdb_version(range_components[0]).unwrap();
-                    let v_max = extract_gdb_version(range_components[1]).expect(ERROR_MESSAGE);
+                    let v_min = range_components[0].unwrap();
+                    let v_max = range_components[1].expect(ERROR_MESSAGE);
                     (v_min, v_max)
                 }
                 _ => panic!(ERROR_MESSAGE),
@@ -149,10 +149,10 @@ fn ignore_lldb(config: &Config, line: &str) -> bool {
             }
 
             if let Some(ref actual_version) = config.lldb_version {
-                if line.contains("min-lldb-version") {
-                    let min_version = line.trim()
-                        .split(' ')
-                        .last()
+                if line.starts_with("min-lldb-version") {
+                    let min_version = line.trim_right()
+                        .rsplit(' ')
+                        .next()
                         .expect("Malformed lldb version directive");
                     // Ignore if actual version is smaller the minimum required
                     // version
@@ -167,10 +167,10 @@ fn ignore_lldb(config: &Config, line: &str) -> bool {
 
         fn ignore_llvm(config: &Config, line: &str) -> bool {
             if let Some(ref actual_version) = config.llvm_version {
-                if line.contains("min-llvm-version") {
-                    let min_version = line.trim()
-                        .split(' ')
-                        .last()
+                if line.starts_with("min-llvm-version") {
+                    let min_version = line.trim_right()
+                        .rsplit(' ')
+                        .next()
                         .expect("Malformed llvm version directive");
                     // Ignore if actual version is smaller the minimum required
                     // version
@@ -233,6 +233,9 @@ pub struct TestProps {
     pub must_compile_successfully: bool,
     // rustdoc will test the output of the `--test` option
     pub check_test_line_numbers_match: bool,
+    // The test must be compiled and run successfully. Only used in UI tests for
+    // now.
+    pub run_pass: bool,
 }
 
 impl TestProps {
@@ -258,6 +261,7 @@ pub fn new() -> Self {
             incremental_dir: None,
             must_compile_successfully: false,
             check_test_line_numbers_match: false,
+            run_pass: false,
         }
     }
 
@@ -368,6 +372,10 @@ pub fn load_from(&mut self,
             if !self.check_test_line_numbers_match {
                 self.check_test_line_numbers_match = config.parse_check_test_line_numbers_match(ln);
             }
+
+            if !self.run_pass {
+                self.run_pass = config.parse_run_pass(ln);
+            }
         });
 
         for key in vec!["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] {
@@ -405,14 +413,14 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) {
                     None => false,
                 };
                 if matches {
-                    it(&ln[close_brace + 1..]);
+                    it(ln[(close_brace + 1) ..].trim_left());
                 }
             } else {
                 panic!("malformed condition directive: expected `//[foo]`, found `{}`",
                        ln)
             }
         } else if ln.starts_with("//") {
-            it(&ln[2..]);
+            it(ln[2..].trim_left());
         }
     }
     return;
@@ -485,6 +493,10 @@ fn parse_check_test_line_numbers_match(&self, line: &str) -> bool {
         self.parse_name_directive(line, "check-test-line-numbers-match")
     }
 
+    fn parse_run_pass(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "run-pass")
+    }
+
     fn parse_env(&self, line: &str, name: &str) -> Option<(String, String)> {
         self.parse_name_value_directive(line, name).map(|nv| {
             // nv is either FOO or FOO=BAR
@@ -516,15 +528,18 @@ fn parse_pp_exact(&self, line: &str, testfile: &Path) -> Option<PathBuf> {
     }
 
     fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
-        // This 'no-' rule is a quick hack to allow pretty-expanded and
-        // no-pretty-expanded to coexist
-        line.contains(directive) && !line.contains(&("no-".to_owned() + directive))
+        // Ensure the directive is a whole word. Do not match "ignore-x86" when
+        // the line says "ignore-x86_64".
+        line.starts_with(directive) && match line.as_bytes().get(directive.len()) {
+            None | Some(&b' ') | Some(&b':') => true,
+            _ => false
+        }
     }
 
     pub fn parse_name_value_directive(&self, line: &str, directive: &str) -> Option<String> {
-        let keycolon = format!("{}:", directive);
-        if let Some(colon) = line.find(&keycolon) {
-            let value = line[(colon + keycolon.len())..line.len()].to_owned();
+        let colon = directive.len();
+        if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') {
+            let value = line[(colon + 1) ..].to_owned();
             debug!("{}: {}", directive, value);
             Some(expand_variables(value, self))
         } else {
index 6fc7f9f07ac174c407a235adc4e173aea6bf8476..1bb0b765f9f1c8dc6fa4031b11f1242e1d185387 100644 (file)
@@ -37,7 +37,7 @@
 use getopts::{optopt, optflag, reqopt};
 use common::Config;
 use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Mode};
-use test::TestPaths;
+use test::{TestPaths, ColorConfig};
 use util::logv;
 
 use self::header::EarlyProps;
@@ -90,6 +90,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
           optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
           optflag("", "verbose", "run tests verbosely, showing all output"),
           optflag("", "quiet", "print one character per test instead of one line"),
+          optopt("", "color", "coloring: auto, always, never", "WHEN"),
           optopt("", "logfile", "file to log test execution to", "FILE"),
           optopt("", "target", "the target to build for", "TARGET"),
           optopt("", "host", "the host to build for", "HOST"),
@@ -147,6 +148,13 @@ fn make_absolute(path: PathBuf) -> PathBuf {
 
     let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"));
 
+    let color = match matches.opt_str("color").as_ref().map(|x| &**x) {
+        Some("auto") | None => ColorConfig::AutoColor,
+        Some("always") => ColorConfig::AlwaysColor,
+        Some("never") => ColorConfig::NeverColor,
+        Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
+    };
+
     Config {
         compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
         run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
@@ -185,6 +193,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         lldb_python_dir: matches.opt_str("lldb-python-dir"),
         verbose: matches.opt_present("verbose"),
         quiet: matches.opt_present("quiet"),
+        color: color,
         remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from),
 
         cc: matches.opt_str("cc").unwrap(),
@@ -332,7 +341,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
             Ok(val) => &val != "0",
             Err(_) => false
         },
-        color: test::AutoColor,
+        color: config.color,
         test_threads: None,
         skip: vec![],
         list: false,
index 1bec6f6af83814c6f725ff3b529602c040b36a59..01419c4257074a7e8186787f996e504272e8deef 100644 (file)
@@ -214,10 +214,10 @@ fn run_rpass_test(&self) {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
+        // FIXME(#41968): Move this check to tidy?
         let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
-        if !expected_errors.is_empty() {
-            self.check_expected_errors(expected_errors, &proc_res);
-        }
+        assert!(expected_errors.is_empty(),
+                "run-pass tests with expected warnings should be moved to ui/");
 
         let proc_res = self.exec_compiled_test();
 
@@ -1394,7 +1394,6 @@ fn make_compile_args(&self,
         match self.config.mode {
             CompileFail |
             ParseFail |
-            RunPass |
             Incremental => {
                 // If we are extracting and matching errors in the new
                 // fashion, then you want JSON mode. Old-skool error
@@ -1422,6 +1421,7 @@ fn make_compile_args(&self,
 
                 args.push(dir_opt);
             }
+            RunPass |
             RunFail |
             RunPassValgrind |
             Pretty |
@@ -2254,6 +2254,14 @@ fn run_ui_test(&self) {
             self.fatal_proc_rec(&format!("{} errors occurred comparing output.", errors),
                                 &proc_res);
         }
+
+        if self.props.run_pass {
+            let proc_res = self.exec_compiled_test();
+
+            if !proc_res.status.success() {
+                self.fatal_proc_rec("test run failed!", &proc_res);
+            }
+        }
     }
 
     fn run_mir_opt_test(&self) {
index 8707ceaf040f6d87b67a002de16a8d2bc4db7a41..b4ff403041f17957f735ad750c3241a3a428b9b7 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8707ceaf040f6d87b67a002de16a8d2bc4db7a41
+Subproject commit b4ff403041f17957f735ad750c3241a3a428b9b7
index 791b8d77e0b907f635782f1d7b33dec9ec09ae83..e34821e3584c5809953ea732b3e51350924be01d 100644 (file)
@@ -49,7 +49,7 @@ pub struct Feature {
     pub has_gate_test: bool,
 }
 
-pub fn check(path: &Path, bad: &mut bool) {
+pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
     let mut features = collect_lang_features(path);
     assert!(!features.is_empty());
 
@@ -134,6 +134,10 @@ pub fn check(path: &Path, bad: &mut bool) {
     if *bad {
         return;
     }
+    if quiet {
+        println!("* {} features", features.len());
+        return;
+    }
 
     let mut lines = Vec::new();
     for (name, feature) in features.iter() {
index 6b666fa809f7a8cbfeb1d099ff25289eaed5834f..23a31131f7a6ca6aaa1a7aa24d4c9474ce1ace4e 100644 (file)
@@ -57,11 +57,12 @@ fn main() {
     let args: Vec<String> = env::args().skip(1).collect();
 
     let mut bad = false;
+    let quiet = args.iter().any(|s| *s == "--quiet");
     bins::check(&path, &mut bad);
     style::check(&path, &mut bad);
     errors::check(&path, &mut bad);
     cargo::check(&path, &mut bad);
-    features::check(&path, &mut bad);
+    features::check(&path, &mut bad, quiet);
     pal::check(&path, &mut bad);
     unstable_book::check(&path, &mut bad);
     if !args.iter().any(|s| *s == "--no-vendor") {