]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #32239 - alexcrichton:fix-cross-to-freebsd, r=brson
authorbors <bors@rust-lang.org>
Tue, 15 Mar 2016 10:21:40 +0000 (03:21 -0700)
committerbors <bors@rust-lang.org>
Tue, 15 Mar 2016 10:21:40 +0000 (03:21 -0700)
rustbuild: Fix cross compiling to FreeBSD

This commit fixes our support for cross compiling a compiler to run on FreeBSD.
Over the weekend I managed to get a cross compiler from Linux to FreeBSD [1]
which I hope to soon use to start producing FreeBSD nightly compilers. With the
`make dist` support added in #32237 we should be able to produce standard
rustc/rust-std packages for FreeBSD through a new slave with this cross compiler.

Currently, however, we don't "Just Work" when cross compiling FreeBSD and a
number of changes were required (part of this PR). They include:

* A few build fixes were needed in LLVM. Our own branch has been rebased on the
  actual 3.8 release and I applied one extra commit [2] which contains two fixes:

  1. The LLVM CMake build system passes the `-Wl,-z,defs` flag on many
     platforms, but *not* when `CMAKE_SYSTEM_NAME` is "FreeBSD". Unfortunately
     this doesn't take into account when we're cross compiling, and as predicted
     the build will fail if `-Wl,-z,defs` is passed (see [3] for more info). To
     fix this we test `TARGET_TRIPLE` instead of the `CMAKE_SYSTEM_NAME` which
     is what we're compiling for which fixes the problem.
  2. The `PATH_MAX` constant is apparently defined in a different location than
     many other Unix systems, so a file which required this just needed some
     help to keep compiling.

* Support for compiling compiler-rt with CMake has been added to rustbuild. It
  looks like it just emulates Linux in what it compiles as it didn't seem to
  naturally produce anything else... At least the architecture is right, so
  seems good for now at least!

[1]: https://github.com/alexcrichton/port-of-rust/blob/master/prebuilt/freebsd/Dockerfile
[2]: https://github.com/rust-lang/llvm/commit/be89e4b5
[3]: https://bugs.webkit.org/show_bug.cgi?id=138420

207 files changed:
mk/crates.mk
src/bootstrap/build/check.rs
src/bootstrap/build/compile.rs
src/bootstrap/build/doc.rs
src/bootstrap/build/mod.rs
src/bootstrap/build/step.rs
src/compiletest/compiletest.rs
src/etc/platform-intrinsics/x86/avx.json
src/librustc/Cargo.toml
src/librustc/dep_graph/README.md
src/librustc/lib.rs
src/librustc/middle/check_match.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/cstore.rs
src/librustc/middle/infer/mod.rs
src/librustc/middle/subst.rs
src/librustc/middle/traits/README.md
src/librustc/middle/traits/coherence.rs
src/librustc/middle/traits/mod.rs
src/librustc/middle/traits/project.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/traits/specialize/mod.rs [new file with mode: 0644]
src/librustc/middle/traits/specialize/specialization_graph.rs [new file with mode: 0644]
src/librustc/middle/traits/util.rs
src/librustc/middle/ty/context.rs
src/librustc/middle/ty/mod.rs
src/librustc/middle/ty/sty.rs
src/librustc/middle/ty/trait_def.rs
src/librustc/middle/ty/util.rs
src/librustc/mir/repr.rs
src/librustc/mir/tcx.rs
src/librustc/session/config.rs
src/librustc_borrowck/borrowck/check_loans.rs
src/librustc_borrowck/borrowck/gather_loans/mod.rs
src/librustc_const_eval/Cargo.toml [new file with mode: 0644]
src/librustc_const_eval/err.rs [new file with mode: 0644]
src/librustc_const_eval/int.rs [new file with mode: 0644]
src/librustc_const_eval/is.rs [new file with mode: 0644]
src/librustc_const_eval/lib.rs [new file with mode: 0644]
src/librustc_const_eval/us.rs [new file with mode: 0644]
src/librustc_data_structures/obligation_forest/README.md
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/test.rs
src/librustc_front/fold.rs
src/librustc_front/hir.rs
src/librustc_front/lowering.rs
src/librustc_front/print/pprust.rs
src/librustc_lint/builtin.rs
src/librustc_lint/types.rs
src/librustc_llvm/build.rs
src/librustc_metadata/Cargo.toml
src/librustc_metadata/common.rs
src/librustc_metadata/csearch.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/lib.rs
src/librustc_mir/Cargo.toml
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/build/misc.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/hair/cx/pattern.rs
src/librustc_mir/lib.rs
src/librustc_mir/mir_map.rs
src/librustc_mir/transform/type_check.rs
src/librustc_passes/consts.rs
src/librustc_passes/rvalues.rs
src/librustc_platform_intrinsics/x86.rs
src/librustc_trans/Cargo.toml
src/librustc_trans/lib.rs
src/librustc_trans/trans/_match.rs
src/librustc_trans/trans/adt.rs
src/librustc_trans/trans/attributes.rs
src/librustc_trans/trans/closure.rs
src/librustc_trans/trans/collector.rs
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/consts.rs
src/librustc_trans/trans/debuginfo/metadata.rs
src/librustc_trans/trans/declare.rs
src/librustc_trans/trans/disr.rs
src/librustc_trans/trans/intrinsic.rs
src/librustc_trans/trans/meth.rs
src/librustc_trans/trans/mir/constant.rs
src/librustc_trans/trans/mir/rvalue.rs
src/librustc_typeck/Cargo.toml
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/cast.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/dropck.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/coherence/mod.rs
src/librustc_typeck/coherence/overlap.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/diagnostics.rs
src/librustc_typeck/lib.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/test.rs
src/libstd/net/ip.rs
src/libsyntax/ast.rs
src/libsyntax/ext/expand.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax_ext/deriving/generic/mod.rs
src/nightlies.txt
src/rustc/Cargo.lock
src/snapshots.txt
src/test/auxiliary/dummy_mir_pass.rs
src/test/auxiliary/go_trait.rs
src/test/auxiliary/specialization_cross_crate.rs [new file with mode: 0644]
src/test/auxiliary/specialization_cross_crate_defaults.rs [new file with mode: 0755]
src/test/auxiliary/xcrate_associated_type_defaults.rs
src/test/compile-fail/associated-types-coherence-failure.rs
src/test/compile-fail/cast-rfc0401.rs
src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs
src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs
src/test/compile-fail/coherence-blanket-conflicts-with-specific-multidispatch.rs
src/test/compile-fail/coherence-blanket-conflicts-with-specific-trait.rs
src/test/compile-fail/coherence-blanket-conflicts-with-specific.rs
src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs
src/test/compile-fail/coherence-cross-crate-conflict.rs
src/test/compile-fail/coherence-default-trait-impl.rs
src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs [new file with mode: 0644]
src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs
src/test/compile-fail/coherence-overlap-issue-23516.rs
src/test/compile-fail/coherence-overlap-messages.rs
src/test/compile-fail/coherence-projection-conflict-orphan.rs
src/test/compile-fail/coherence-projection-conflict-ty-param.rs
src/test/compile-fail/coherence-projection-conflict.rs
src/test/compile-fail/coherence-tuple-conflict.rs
src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs
src/test/compile-fail/coherence_copy_like_err_struct.rs
src/test/compile-fail/coherence_copy_like_err_tuple.rs
src/test/compile-fail/const-err.rs
src/test/compile-fail/const-eval-overflow-2.rs
src/test/compile-fail/const-eval-overflow-3.rs
src/test/compile-fail/const-eval-overflow-4b.rs
src/test/compile-fail/const-eval-overflow.rs
src/test/compile-fail/const-integer-bool-ops.rs
src/test/compile-fail/const-len-underflow-separate-spans.rs
src/test/compile-fail/const-len-underflow-subspans.rs
src/test/compile-fail/const-tup-index-span.rs
src/test/compile-fail/discrim-overflow-2.rs
src/test/compile-fail/discrim-overflow.rs
src/test/compile-fail/enum-discrim-too-small.rs
src/test/compile-fail/enum-discrim-too-small2.rs [new file with mode: 0644]
src/test/compile-fail/eval-enum.rs
src/test/compile-fail/fat-ptr-cast.rs
src/test/compile-fail/feature-gate-negate-unsigned.rs
src/test/compile-fail/feature-gate-negate-unsigned0.rs [new file with mode: 0644]
src/test/compile-fail/issue-15524.rs
src/test/compile-fail/issue-28568.rs
src/test/compile-fail/issue-31511.rs [new file with mode: 0644]
src/test/compile-fail/issue-8460-const.rs
src/test/compile-fail/issue-8761.rs
src/test/compile-fail/lint-type-limits.rs
src/test/compile-fail/lint-type-limits2.rs [new file with mode: 0644]
src/test/compile-fail/lint-type-limits3.rs [new file with mode: 0644]
src/test/compile-fail/lint-type-overflow.rs
src/test/compile-fail/lint-type-overflow2.rs [new file with mode: 0644]
src/test/compile-fail/private-in-public-warn.rs
src/test/compile-fail/repeat_count.rs
src/test/compile-fail/specialization/README.md [new file with mode: 0644]
src/test/compile-fail/specialization/specialization-default-projection.rs [new file with mode: 0644]
src/test/compile-fail/specialization/specialization-default-types.rs [new file with mode: 0644]
src/test/compile-fail/specialization/specialization-feature-gate-default.rs [new file with mode: 0644]
src/test/compile-fail/specialization/specialization-feature-gate-overlap.rs [new file with mode: 0644]
src/test/compile-fail/specialization/specialization-no-default.rs [new file with mode: 0644]
src/test/compile-fail/specialization/specialization-overlap-negative.rs [new file with mode: 0644]
src/test/compile-fail/specialization/specialization-overlap.rs [new file with mode: 0644]
src/test/compile-fail/specialization/specialization-polarity.rs [new file with mode: 0755]
src/test/parse-fail/default.rs [new file with mode: 0644]
src/test/parse-fail/issue-20711-2.rs
src/test/parse-fail/issue-20711.rs
src/test/parse-fail/removed-syntax-static-fn.rs
src/test/run-make/execution-engine/test.rs
src/test/run-make/issue-19371/foo.rs
src/test/run-pass/const-fn.rs
src/test/run-pass/const-negation.rs [new file with mode: 0644]
src/test/run-pass/default-associated-types.rs
src/test/run-pass/enum-discrim-autosizing.rs
src/test/run-pass/issue-23833.rs [new file with mode: 0644]
src/test/run-pass/issue-29663.rs [new file with mode: 0644]
src/test/run-pass/specialization/README.md [new file with mode: 0644]
src/test/run-pass/specialization/specialization-allowed-cross-crate.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-assoc-fns.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-basics.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-cross-crate-defaults.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-cross-crate-no-gate.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-cross-crate.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-default-methods.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-on-projection.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-out-of-order.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-overlap-projection.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-projection-alias.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-projection.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-super-traits.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-translate-projections-with-params.rs [new file with mode: 0644]
src/test/run-pass/specialization/specialization-translate-projections.rs [new file with mode: 0644]
src/test/run-pass/xcrate-associated-type-defaults.rs
src/tools/linkchecker/main.rs

index d8e0390504b975fd8ee1706c8eb32108f3014109..1c7f141627bb3aabf392c1d07bb86bd6810d9e66 100644 (file)
@@ -53,7 +53,7 @@ TARGET_CRATES := libc std term \
                  getopts collections test rand \
                  core alloc \
                  rustc_unicode rustc_bitflags \
-                alloc_system alloc_jemalloc
+                alloc_system alloc_jemalloc rustc_const_eval
 RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
                 rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
                 rustc_data_structures rustc_front rustc_platform_intrinsics \
@@ -91,8 +91,11 @@ DEPS_test := std getopts term native:rust_test_helpers
 DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode
 DEPS_syntax_ext := syntax fmt_macros
 
+DEPS_rustc_const_eval := std syntax
+
 DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\
-              log graphviz rustc_llvm rustc_back rustc_data_structures
+              log graphviz rustc_llvm rustc_back rustc_data_structures\
+                         rustc_const_eval
 DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
 DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
 DEPS_rustc_data_structures := std log serialize
@@ -103,16 +106,17 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo
 DEPS_rustc_front := std syntax log serialize
 DEPS_rustc_lint := rustc log syntax
 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
-DEPS_rustc_metadata := rustc rustc_front syntax rbml
+DEPS_rustc_metadata := rustc rustc_front syntax rbml rustc_const_eval
 DEPS_rustc_passes := syntax rustc core rustc_front
-DEPS_rustc_mir := rustc rustc_front syntax
+DEPS_rustc_mir := rustc rustc_front syntax rustc_const_eval
 DEPS_rustc_resolve := arena rustc rustc_front log syntax
 DEPS_rustc_platform_intrinsics := rustc rustc_llvm
 DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
 DEPS_rustc_privacy := rustc rustc_front log syntax
 DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
-                    log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
-DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
+                    log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics \
+                                       rustc_const_eval
+DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics rustc_const_eval
 
 DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
                 test rustc_lint rustc_front
index 19293e80217e34b402c32242e93023edf2634cb5..a50b09bcdef130080839c560f604b8a1e7d6dc8b 100644 (file)
@@ -8,14 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::process::Command;
-
 use build::{Build, Compiler};
 
 pub fn linkcheck(build: &Build, stage: u32, host: &str) {
     println!("Linkcheck stage{} ({})", stage, host);
     let compiler = Compiler::new(stage, host);
-    let linkchecker = build.tool(&compiler, "linkchecker");
-    build.run(Command::new(&linkchecker)
-                     .arg(build.out.join(host).join("doc")));
+    build.run(build.tool_cmd(&compiler, "linkchecker")
+                   .arg(build.out.join(host).join("doc")));
 }
index 0a293579cf67d814e0b16bf83c087ad9b2c7f83d..95555aa3796889143df1ef07f87ecec4172064a2 100644 (file)
 /// This will build the standard library for a particular stage of the build
 /// using the `compiler` targeting the `target` architecture. The artifacts
 /// created will also be linked into the sysroot directory.
-pub fn std<'a>(build: &'a Build, stage: u32, target: &str,
-               compiler: &Compiler<'a>) {
-    let host = compiler.host;
-    println!("Building stage{} std artifacts ({} -> {})", stage,
-             host, target);
+pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
+    println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
+             compiler.host, target);
 
     // Move compiler-rt into place as it'll be required by the compiler when
     // building the standard library to link the dylib of libstd
-    let libdir = build.sysroot_libdir(stage, &host, target);
+    let libdir = build.sysroot_libdir(compiler, target);
     let _ = fs::remove_dir_all(&libdir);
     t!(fs::create_dir_all(&libdir));
     t!(fs::hard_link(&build.compiler_rt_built.borrow()[target],
@@ -39,10 +37,9 @@ pub fn std<'a>(build: &'a Build, stage: u32, target: &str,
 
     build_startup_objects(build, target, &libdir);
 
-    let out_dir = build.cargo_out(stage, &host, Mode::Libstd, target);
+    let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
     build.clear_if_dirty(&out_dir, &build.compiler_path(compiler));
-    let mut cargo = build.cargo(stage, compiler, Mode::Libstd, Some(target),
-                                "build");
+    let mut cargo = build.cargo(compiler, Mode::Libstd, target, "build");
     cargo.arg("--features").arg(build.std_features())
          .arg("--manifest-path")
          .arg(build.src.join("src/rustc/std_shim/Cargo.toml"));
@@ -59,7 +56,7 @@ pub fn std<'a>(build: &'a Build, stage: u32, target: &str,
     }
 
     build.run(&mut cargo);
-    std_link(build, stage, target, compiler, host);
+    std_link(build, target, compiler, compiler.host);
 }
 
 /// Link all libstd rlibs/dylibs into the sysroot location.
@@ -67,12 +64,12 @@ pub fn std<'a>(build: &'a Build, stage: u32, target: &str,
 /// Links those artifacts generated in the given `stage` for `target` produced
 /// by `compiler` into `host`'s sysroot.
 pub fn std_link(build: &Build,
-                stage: u32,
                 target: &str,
                 compiler: &Compiler,
                 host: &str) {
-    let libdir = build.sysroot_libdir(stage, host, target);
-    let out_dir = build.cargo_out(stage, compiler.host, Mode::Libstd, target);
+    let target_compiler = Compiler::new(compiler.stage, host);
+    let libdir = build.sysroot_libdir(&target_compiler, target);
+    let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
 
     // If we're linking one compiler host's output into another, then we weren't
     // called from the `std` method above. In that case we clean out what's
@@ -85,7 +82,8 @@ pub fn std_link(build: &Build,
     }
     add_to_sysroot(&out_dir, &libdir);
 
-    if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
+    if target.contains("musl") &&
+       (target.contains("x86_64") || target.contains("i686")) {
         copy_third_party_objects(build, target, &libdir);
     }
 }
@@ -130,17 +128,14 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) {
 /// This will build the compiler for a particular stage of the build using
 /// the `compiler` targeting the `target` architecture. The artifacts
 /// created will also be linked into the sysroot directory.
-pub fn rustc<'a>(build: &'a Build, stage: u32, target: &str,
-                 compiler: &Compiler<'a>) {
-    let host = compiler.host;
-    println!("Building stage{} compiler artifacts ({} -> {})", stage,
-             host, target);
+pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
+    println!("Building stage{} compiler artifacts ({} -> {})",
+             compiler.stage, compiler.host, target);
 
-    let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target);
-    build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target));
+    let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
+    build.clear_if_dirty(&out_dir, &libstd_shim(build, compiler, target));
 
-    let mut cargo = build.cargo(stage, compiler, Mode::Librustc, Some(target),
-                                "build");
+    let mut cargo = build.cargo(compiler, Mode::Librustc, target, "build");
     cargo.arg("--features").arg(build.rustc_features())
          .arg("--manifest-path")
          .arg(build.src.join("src/rustc/Cargo.toml"));
@@ -184,7 +179,7 @@ pub fn rustc<'a>(build: &'a Build, stage: u32, target: &str,
     }
     build.run(&mut cargo);
 
-    rustc_link(build, stage, target, compiler, compiler.host);
+    rustc_link(build, target, compiler, compiler.host);
 }
 
 /// Link all librustc rlibs/dylibs into the sysroot location.
@@ -192,19 +187,19 @@ pub fn rustc<'a>(build: &'a Build, stage: u32, target: &str,
 /// Links those artifacts generated in the given `stage` for `target` produced
 /// by `compiler` into `host`'s sysroot.
 pub fn rustc_link(build: &Build,
-                  stage: u32,
                   target: &str,
                   compiler: &Compiler,
                   host: &str) {
-    let libdir = build.sysroot_libdir(stage, host, target);
-    let out_dir = build.cargo_out(stage, compiler.host, Mode::Librustc, target);
+    let target_compiler = Compiler::new(compiler.stage, host);
+    let libdir = build.sysroot_libdir(&target_compiler, target);
+    let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
     add_to_sysroot(&out_dir, &libdir);
 }
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
-fn libstd_shim(build: &Build, stage: u32, host: &str, target: &str) -> PathBuf {
-    build.cargo_out(stage, host, Mode::Libstd, target).join("libstd_shim.rlib")
+fn libstd_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
+    build.cargo_out(compiler, Mode::Libstd, target).join("libstd_shim.rlib")
 }
 
 fn compiler_file(compiler: &Path, file: &str) -> String {
@@ -219,16 +214,21 @@ fn compiler_file(compiler: &Path, file: &str) -> String {
 /// compiler.
 pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
     assert!(stage > 0, "the stage0 compiler isn't assembled, it's downloaded");
+    // The compiler that we're assembling
+    let target_compiler = Compiler::new(stage, host);
+
+    // The compiler that compiled the compiler we're assembling
+    let build_compiler = Compiler::new(stage - 1, &build.config.build);
 
     // Clear out old files
-    let sysroot = build.sysroot(stage, host);
+    let sysroot = build.sysroot(&target_compiler);
     let _ = fs::remove_dir_all(&sysroot);
     t!(fs::create_dir_all(&sysroot));
 
     // Link in all dylibs to the libdir
     let sysroot_libdir = sysroot.join(libdir(host));
     t!(fs::create_dir_all(&sysroot_libdir));
-    let src_libdir = build.sysroot_libdir(stage - 1, &build.config.build, host);
+    let src_libdir = build.sysroot_libdir(&build_compiler, host);
     for f in t!(fs::read_dir(&src_libdir)).map(|f| t!(f)) {
         let filename = f.file_name().into_string().unwrap();
         if is_dylib(&filename) {
@@ -236,8 +236,7 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
         }
     }
 
-    let out_dir = build.cargo_out(stage - 1, &build.config.build,
-                                  Mode::Librustc, host);
+    let out_dir = build.cargo_out(&build_compiler, Mode::Librustc, host);
 
     // Link the compiler binary itself into place
     let rustc = out_dir.join(exe("rustc", host));
@@ -315,7 +314,7 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) {
     // let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target);
     // build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target));
 
-    let mut cargo = build.cargo(stage, &compiler, Mode::Tool, None, "build");
+    let mut cargo = build.cargo(&compiler, Mode::Tool, host, "build");
     cargo.arg("--manifest-path")
          .arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool)));
     build.run(&mut cargo);
index 51bf752e06d342452455a7d3b2f0c9d2e2a5839d..d8b02dce222cd0312eb3f9d1469cf2cf3d6344f0 100644 (file)
@@ -81,6 +81,7 @@ pub fn standalone(build: &Build, stage: u32, host: &str, out: &Path) {
         }
 
         let mut cmd = Command::new(&rustdoc);
+        build.add_rustc_lib_path(&compiler, &mut cmd);
         cmd.arg("--html-after-content").arg(&footer)
            .arg("--html-before-content").arg(&version_info)
            .arg("--html-in-header").arg(&favicon)
@@ -107,14 +108,13 @@ pub fn standalone(build: &Build, stage: u32, host: &str, out: &Path) {
 pub fn std(build: &Build, stage: u32, host: &str, out: &Path) {
     println!("Documenting stage{} std ({})", stage, host);
     let compiler = Compiler::new(stage, host);
-    let out_dir = build.stage_out(stage, host, Mode::Libstd)
+    let out_dir = build.stage_out(&compiler, Mode::Libstd)
                        .join(host).join("doc");
     let rustdoc = build.rustdoc(&compiler);
 
     build.clear_if_dirty(&out_dir, &rustdoc);
 
-    let mut cargo = build.cargo(stage, &compiler, Mode::Libstd, Some(host),
-                                "doc");
+    let mut cargo = build.cargo(&compiler, Mode::Libstd, host, "doc");
     cargo.arg("--manifest-path")
          .arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
          .arg("--features").arg(build.std_features());
@@ -125,14 +125,13 @@ pub fn std(build: &Build, stage: u32, host: &str, out: &Path) {
 pub fn rustc(build: &Build, stage: u32, host: &str, out: &Path) {
     println!("Documenting stage{} compiler ({})", stage, host);
     let compiler = Compiler::new(stage, host);
-    let out_dir = build.stage_out(stage, host, Mode::Librustc)
+    let out_dir = build.stage_out(&compiler, Mode::Librustc)
                        .join(host).join("doc");
     let rustdoc = build.rustdoc(&compiler);
     if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) {
         t!(fs::remove_dir_all(&out_dir));
     }
-    let mut cargo = build.cargo(stage, &compiler, Mode::Librustc, Some(host),
-                                "doc");
+    let mut cargo = build.cargo(&compiler, Mode::Librustc, host, "doc");
     cargo.arg("--manifest-path")
          .arg(build.src.join("src/rustc/Cargo.toml"))
          .arg("--features").arg(build.rustc_features());
@@ -143,7 +142,7 @@ pub fn rustc(build: &Build, stage: u32, host: &str, out: &Path) {
 pub fn error_index(build: &Build, stage: u32, host: &str, out: &Path) {
     println!("Documenting stage{} error index ({})", stage, host);
     let compiler = Compiler::new(stage, host);
-    let mut index = Command::new(build.tool(&compiler, "error_index_generator"));
+    let mut index = build.tool_cmd(&compiler, "error_index_generator");
     index.arg("html");
     index.arg(out.join("error-index.html"));
 
index 058f27c33f60799d7f4fc767fa7d9462ae7cbf83..39bd74c78ff2a9dfb85f82fbc34bd1bec9961e4a 100644 (file)
@@ -152,19 +152,17 @@ pub fn build(&mut self) {
                 CompilerRt { _dummy } => {
                     native::compiler_rt(self, target.target);
                 }
-                Libstd { stage, compiler } => {
-                    compile::std(self, stage, target.target, &compiler);
+                Libstd { compiler } => {
+                    compile::std(self, target.target, &compiler);
                 }
-                Librustc { stage, compiler } => {
-                    compile::rustc(self, stage, target.target, &compiler);
+                Librustc { compiler } => {
+                    compile::rustc(self, target.target, &compiler);
                 }
-                LibstdLink { stage, compiler, host } => {
-                    compile::std_link(self, stage, target.target,
-                                      &compiler, host);
+                LibstdLink { compiler, host } => {
+                    compile::std_link(self, target.target, &compiler, host);
                 }
-                LibrustcLink { stage, compiler, host } => {
-                    compile::rustc_link(self, stage, target.target,
-                                        &compiler, host);
+                LibrustcLink { compiler, host } => {
+                    compile::rustc_link(self, target.target, &compiler, host);
                 }
                 Rustc { stage: 0 } => {
                     // nothing to do...
@@ -261,58 +259,52 @@ fn clear_if_dirty(&self, dir: &Path, input: &Path) {
     /// This will create a `Command` that represents a pending execution of
     /// Cargo for the specified stage, whether or not the standard library is
     /// being built, and using the specified compiler targeting `target`.
-    // FIXME: aren't stage/compiler duplicated?
     fn cargo(&self,
-             stage: u32,
              compiler: &Compiler,
              mode: Mode,
-             target: Option<&str>,
+             target: &str,
              cmd: &str) -> Command {
         let mut cargo = Command::new(&self.cargo);
-        let host = compiler.host;
-        let out_dir = self.stage_out(stage, host, mode);
+        let out_dir = self.stage_out(compiler, mode);
         cargo.env("CARGO_TARGET_DIR", out_dir)
              .arg(cmd)
-             .arg("-j").arg(self.jobs().to_string());
+             .arg("-j").arg(self.jobs().to_string())
+             .arg("--target").arg(target);
 
         // Customize the compiler we're running. Specify the compiler to cargo
         // as our shim and then pass it some various options used to configure
         // how the actual compiler itself is called.
         cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc"))
              .env("RUSTC_REAL", self.compiler_path(compiler))
-             .env("RUSTC_STAGE", self.stage_arg(stage, compiler).to_string())
+             .env("RUSTC_STAGE", compiler.stage.to_string())
              .env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string())
              .env("RUSTC_CODEGEN_UNITS",
                   self.config.rust_codegen_units.to_string())
              .env("RUSTC_DEBUG_ASSERTIONS",
                   self.config.rust_debug_assertions.to_string())
              .env("RUSTC_SNAPSHOT", &self.rustc)
-             .env("RUSTC_SYSROOT", self.sysroot(stage, host))
+             .env("RUSTC_SYSROOT", self.sysroot(compiler))
              .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir())
              .env("RUSTC_RPATH", self.config.rust_rpath.to_string())
              .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
-             .env("RUSTDOC_REAL", self.rustdoc(compiler));
-
-        if let Some(target) = target {
-             cargo.env("RUSTC_FLAGS", self.rustc_flags(target).join(" "));
-             cargo.arg("--target").arg(target);
-
-            // Specify some various options for build scripts used throughout
-            // the build.
-            //
-            // FIXME: the guard against msvc shouldn't need to be here
-            if !target.contains("msvc") {
-                cargo.env(format!("CC_{}", target), self.cc(target))
-                     .env(format!("AR_{}", target), self.ar(target))
-                     .env(format!("CFLAGS_{}", target), self.cflags(target));
-            }
-
-            // Environment variables *required* needed throughout the build
-            //
-            // FIXME: should update code to not require this env vars
-            cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
+             .env("RUSTDOC_REAL", self.rustdoc(compiler))
+             .env("RUSTC_FLAGS", self.rustc_flags(target).join(" "));
+
+        // Specify some various options for build scripts used throughout
+        // the build.
+        //
+        // FIXME: the guard against msvc shouldn't need to be here
+        if !target.contains("msvc") {
+            cargo.env(format!("CC_{}", target), self.cc(target))
+                 .env(format!("AR_{}", target), self.ar(target))
+                 .env(format!("CFLAGS_{}", target), self.cflags(target));
         }
 
+        // Environment variables *required* needed throughout the build
+        //
+        // FIXME: should update code to not require this env vars
+        cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
+
         if self.config.verbose || self.flags.verbose {
             cargo.arg("-v");
         }
@@ -328,50 +320,37 @@ fn compiler_path(&self, compiler: &Compiler) -> PathBuf {
         if compiler.is_snapshot(self) {
             self.rustc.clone()
         } else {
-            self.sysroot(compiler.stage, compiler.host).join("bin")
-                .join(exe("rustc", compiler.host))
+            self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host))
         }
     }
 
     /// Get the specified tool built by the specified compiler
     fn tool(&self, compiler: &Compiler, tool: &str) -> PathBuf {
-        self.stage_out(compiler.stage, compiler.host, Mode::Tool)
-            .join(self.cargo_dir())
+        self.cargo_out(compiler, Mode::Tool, compiler.host)
             .join(exe(tool, compiler.host))
     }
 
     /// Get the `rustdoc` executable next to the specified compiler
     fn rustdoc(&self, compiler: &Compiler) -> PathBuf {
-        let root = if compiler.is_snapshot(self) {
-            let mut rustdoc = self.rustc.clone();
-            rustdoc.pop();
-            rustdoc
-        } else {
-            let (stage, host) = (compiler.stage, compiler.host);
-            self.cargo_out(stage - 1, host, Mode::Librustc, host)
-        };
-        root.join(exe("rustdoc", compiler.host))
+        let mut rustdoc = self.compiler_path(compiler);
+        rustdoc.pop();
+        rustdoc.push(exe("rustdoc", compiler.host));
+        return rustdoc
     }
 
     /// Get a `Command` which is ready to run `tool` in `stage` built for
     /// `host`.
-    #[allow(dead_code)] // this will be used soon
     fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command {
         let mut cmd = Command::new(self.tool(&compiler, tool));
         let host = compiler.host;
-        let stage = compiler.stage;
         let paths = vec![
-            self.cargo_out(stage, host, Mode::Libstd, host).join("deps"),
-            self.cargo_out(stage, host, Mode::Librustc, host).join("deps"),
+            self.cargo_out(compiler, Mode::Libstd, host).join("deps"),
+            self.cargo_out(compiler, Mode::Librustc, host).join("deps"),
         ];
         add_lib_path(paths, &mut cmd);
         return cmd
     }
 
-    fn stage_arg(&self, stage: u32, compiler: &Compiler) -> u32 {
-        if stage == 0 && compiler.host != self.config.build {1} else {stage}
-    }
-
     /// Get the space-separated set of activated features for the standard
     /// library.
     fn std_features(&self) -> String {
@@ -400,16 +379,16 @@ fn cargo_dir(&self) -> &'static str {
         if self.config.rust_optimize {"release"} else {"debug"}
     }
 
-    fn sysroot(&self, stage: u32, host: &str) -> PathBuf {
-        if stage == 0 {
-            self.stage_out(stage, host, Mode::Librustc)
+    fn sysroot(&self, compiler: &Compiler) -> PathBuf {
+        if compiler.stage == 0 {
+            self.out.join(compiler.host).join("stage0-sysroot")
         } else {
-            self.out.join(host).join(format!("stage{}", stage))
+            self.out.join(compiler.host).join(format!("stage{}", compiler.stage))
         }
     }
 
-    fn sysroot_libdir(&self, stage: u32, host: &str, target: &str) -> PathBuf {
-        self.sysroot(stage, host).join("lib").join("rustlib")
+    fn sysroot_libdir(&self, compiler: &Compiler, target: &str) -> PathBuf {
+        self.sysroot(compiler).join("lib").join("rustlib")
             .join(target).join("lib")
     }
 
@@ -417,20 +396,23 @@ fn sysroot_libdir(&self, stage: u32, host: &str, target: &str) -> PathBuf {
     /// stage when running with a particular host compiler.
     ///
     /// The mode indicates what the root directory is for.
-    fn stage_out(&self, stage: u32, host: &str, mode: Mode) -> PathBuf {
+    fn stage_out(&self, compiler: &Compiler, mode: Mode) -> PathBuf {
         let suffix = match mode {
             Mode::Libstd => "-std",
             _ => "-rustc",
         };
-        self.out.join(host).join(format!("stage{}{}", stage, suffix))
+        self.out.join(compiler.host)
+                .join(format!("stage{}{}", compiler.stage, suffix))
     }
 
     /// Returns the root output directory for all Cargo output in a given stage,
     /// running a particular comipler, wehther or not we're building the
     /// standard library, and targeting the specified architecture.
-    fn cargo_out(&self, stage: u32, host: &str, mode: Mode,
+    fn cargo_out(&self,
+                 compiler: &Compiler,
+                 mode: Mode,
                  target: &str) -> PathBuf {
-        self.stage_out(stage, host, mode).join(target).join(self.cargo_dir())
+        self.stage_out(compiler, mode).join(target).join(self.cargo_dir())
     }
 
     /// Root output directory for LLVM compiled for `target`
@@ -456,8 +438,7 @@ fn rustc_libdir(&self, compiler: &Compiler) -> PathBuf {
         if compiler.is_snapshot(self) {
             self.rustc_snapshot_libdir()
         } else {
-            self.sysroot(compiler.stage, compiler.host)
-                .join(libdir(compiler.host))
+            self.sysroot(compiler).join(libdir(compiler.host))
         }
     }
 
index 720ba4fd2094dc63d58ae010713139afbfe3a822..dfac074e3cd75ea1cab2cf34e6e8780a86fc72f1 100644 (file)
@@ -29,18 +29,16 @@ macro_rules! targets {
             // and one for the compiler itself. These are parameterized over the
             // stage output they're going to be placed in along with the
             // compiler which is producing the copy of libstd or librustc
-            (libstd, Libstd { stage: u32, compiler: Compiler<'a> }),
-            (librustc, Librustc { stage: u32, compiler: Compiler<'a> }),
+            (libstd, Libstd { compiler: Compiler<'a> }),
+            (librustc, Librustc { compiler: Compiler<'a> }),
 
             // Links the standard library/librustc produced by the compiler
             // provided into the host's directory also provided.
             (libstd_link, LibstdLink {
-                stage: u32,
                 compiler: Compiler<'a>,
                 host: &'a str
             }),
             (librustc_link, LibrustcLink {
-                stage: u32,
                 compiler: Compiler<'a>,
                 host: &'a str
             }),
@@ -144,10 +142,9 @@ fn top_level(build: &Build) -> Vec<Step> {
             }
             let host = t.target(host);
             if host.target == build.config.build {
-                targets.push(host.librustc(stage, host.compiler(stage)));
+                targets.push(host.librustc(host.compiler(stage)));
             } else {
-                targets.push(host.librustc_link(stage, t.compiler(stage),
-                                                host.target));
+                targets.push(host.librustc_link(t.compiler(stage), host.target));
             }
             for target in build.config.target.iter() {
                 if !build.flags.target.contains(target) {
@@ -156,11 +153,10 @@ fn top_level(build: &Build) -> Vec<Step> {
 
                 if host.target == build.config.build {
                     targets.push(host.target(target)
-                                     .libstd(stage, host.compiler(stage)));
+                                     .libstd(host.compiler(stage)));
                 } else {
                     targets.push(host.target(target)
-                                     .libstd_link(stage, t.compiler(stage),
-                                                  host.target));
+                                     .libstd_link(t.compiler(stage), host.target));
                 }
             }
         }
@@ -238,29 +234,29 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
             }
             Source::Rustc { stage } => {
                 let compiler = Compiler::new(stage - 1, &build.config.build);
-                vec![self.librustc(stage - 1, compiler)]
+                vec![self.librustc(compiler)]
             }
-            Source::Librustc { stage, compiler } => {
-                vec![self.libstd(stage, compiler), self.llvm(())]
+            Source::Librustc { compiler } => {
+                vec![self.libstd(compiler), self.llvm(())]
             }
-            Source::Libstd { stage: _, compiler } => {
+            Source::Libstd { compiler } => {
                 vec![self.compiler_rt(()),
                      self.rustc(compiler.stage).target(compiler.host)]
             }
-            Source::LibrustcLink { stage, compiler, host } => {
-                vec![self.librustc(stage, compiler),
-                     self.libstd_link(stage, compiler, host)]
+            Source::LibrustcLink { compiler, host } => {
+                vec![self.librustc(compiler),
+                     self.libstd_link(compiler, host)]
             }
-            Source::LibstdLink { stage, compiler, host } => {
-                vec![self.libstd(stage, compiler),
-                     self.target(host).rustc(stage)]
+            Source::LibstdLink { compiler, host } => {
+                vec![self.libstd(compiler),
+                     self.target(host).rustc(compiler.stage)]
             }
             Source::CompilerRt { _dummy } => {
                 vec![self.llvm(()).target(&build.config.build)]
             }
             Source::Llvm { _dummy } => Vec::new(),
             Source::DocStd { stage } => {
-                vec![self.libstd(stage, self.compiler(stage))]
+                vec![self.libstd(self.compiler(stage))]
             }
             Source::DocBook { stage } |
             Source::DocNomicon { stage } |
@@ -290,11 +286,11 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
             }
 
             Source::ToolLinkchecker { stage } => {
-                vec![self.libstd(stage, self.compiler(stage))]
+                vec![self.libstd(self.compiler(stage))]
             }
             Source::ToolErrorIndex { stage } |
             Source::ToolRustbook { stage } => {
-                vec![self.librustc(stage, self.compiler(stage))]
+                vec![self.librustc(self.compiler(stage))]
             }
         }
     }
index 74c02d00a0af1a090306e9b8681c3bd7bf555837..458a3a8c739f435447116d09f1c4423296dfaf01 100644 (file)
@@ -116,12 +116,6 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
         }
     }
 
-    let filter = if !matches.free.is_empty() {
-        Some(matches.free[0].clone())
-    } else {
-        None
-    };
-
     Config {
         compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
         run_lib_path: matches.opt_str("run-lib-path").unwrap(),
@@ -137,7 +131,7 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
         stage_id: matches.opt_str("stage-id").unwrap(),
         mode: matches.opt_str("mode").unwrap().parse().ok().expect("invalid mode"),
         run_ignored: matches.opt_present("ignored"),
-        filter: filter,
+        filter: matches.free.first().cloned(),
         logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
         runtool: matches.opt_str("runtool"),
         host_rustcflags: matches.opt_str("host-rustcflags"),
@@ -251,10 +245,7 @@ pub fn run_tests(config: &Config) {
 
 pub fn test_opts(config: &Config) -> test::TestOpts {
     test::TestOpts {
-        filter: match config.filter {
-            None => None,
-            Some(ref filter) => Some(filter.clone()),
-        },
+        filter: config.filter.clone(),
         run_ignored: config.run_ignored,
         logfile: config.logfile.clone(),
         run_tests: true,
index 08524fbd6dd8a5e2ca27407a23959e084d942aa8..05a4721aed8340e0ce56a1513d899e33e68e2b46 100644 (file)
@@ -8,6 +8,13 @@
             "ret": "f(32-64)",
             "args": ["0", "0"]
         },
+        {
+            "intrinsic": "256_blendv_{0.data_type}",
+            "width": [256],
+            "llvm": "blendv.{0.data_type}.256",
+            "ret": "f(32-64)",
+            "args": ["0", "0", "0"]
+        },
         {
             "intrinsic": "256_broadcast_{0.data_type}",
             "width": [256],
             "ret": "f(32-64)",
             "args": ["s8SPc"]
         },
+        {
+            "intrinsic": "256_cmp_{0.data_type}",
+            "width": [256],
+            "llvm": "cmp.{1.data_type}.256",
+            "ret": "f(32-64)",
+            "args": ["0", "0", "s8S"]
+        },
         {
             "intrinsic": "256_cvtepi32_pd",
             "width": [256],
index e65b4355e9d371c934edcaf2c1a39a9c95d8cd5e..1f000c2af68b880c8310942607cec66b1f07e34d 100644 (file)
@@ -18,6 +18,7 @@ log = { path = "../liblog" }
 rbml = { path = "../librbml" }
 rustc_back = { path = "../librustc_back" }
 rustc_bitflags = { path = "../librustc_bitflags" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_front = { path = "../librustc_front" }
 rustc_llvm = { path = "../librustc_llvm" }
index 21742d9935dc2d8b3ff2f937db958b46fd247218..ece5819829baa67b05adbca4f30a3375dfeda7a7 100644 (file)
@@ -51,7 +51,7 @@ could invalidate work done for other items. So, for example:
    not shared state, because if it changes it does not itself
    invalidate other functions (though it may be that it causes new
    monomorphizations to occur, but that's handled independently).
-   
+
 Put another way: if the HIR for an item changes, we are going to
 recompile that item for sure. But we need the dep tracking map to tell
 us what *else* we have to recompile. Shared state is anything that is
@@ -177,7 +177,7 @@ reads from `item`, there would be missing edges in the graph:
       |                                 ^
       |                                 |
       +---------------------------------+ // added by `visit_all_items_in_krate`
-    
+
 In particular, the edge from `Hir(X)` to `ItemSignature(X)` is only
 present because we called `read` ourselves when entering the `ItemSignature(X)`
 task.
@@ -273,8 +273,8 @@ should not exist.  In contrast, using the memoized helper, you get:
     ... -> MapVariant(key) -> A
                  |
                  +----------> B
-                 
-which is much cleaner.                 
+
+which is much cleaner.
 
 **Be aware though that the closure is executed with `MapVariant(key)`
 pushed onto the stack as the current task!** That means that you must
@@ -387,4 +387,3 @@ RUST_DEP_GRAPH_FILTER='Hir&foo -> TypeckItemBody & bar'
 This will dump out all the nodes that lead from `Hir(foo)` to
 `TypeckItemBody(bar)`, from which you can (hopefully) see the source
 of the erroneous edge.
-
index 4ff3b21dc83f4901bacaabf9f6c15767a719ae0f..3988545c201e0ad7fd62e18ba2196e7c47186941 100644 (file)
@@ -55,6 +55,7 @@
 extern crate rustc_data_structures;
 extern crate serialize;
 extern crate collections;
+extern crate rustc_const_eval;
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
 #[macro_use] #[no_link] extern crate rustc_bitflags;
index 1f79e76f3ac32c2e0200b2b04451886e04e2e06a..89b57e0d90a007031169310e143c2d72d4c0bc6b 100644 (file)
@@ -25,6 +25,7 @@
 use middle::infer;
 use middle::mem_categorization::{cmt};
 use middle::pat_util::*;
+use middle::traits::ProjectionMode;
 use middle::ty::*;
 use middle::ty;
 use std::cmp::Ordering;
@@ -476,7 +477,7 @@ fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
                     Some(Def::AssociatedConst(did)) |
                     Some(Def::Const(did)) => match lookup_const_by_id(self.tcx, did,
                                                                     Some(pat.id), None) {
-                        Some(const_expr) => {
+                        Some((const_expr, _const_ty)) => {
                             const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
 
                                 if let Some(ref mut renaming_map) = self.renaming_map {
@@ -1101,7 +1102,8 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
                         //FIXME: (@jroesch) this code should be floated up as well
                         let infcx = infer::new_infer_ctxt(cx.tcx,
                                                           &cx.tcx.tables,
-                                                          Some(cx.param_env.clone()));
+                                                          Some(cx.param_env.clone()),
+                                                          ProjectionMode::AnyFinal);
                         if infcx.type_moves_by_default(pat_ty, pat.span) {
                             check_move(p, sub.as_ref().map(|p| &**p));
                         }
@@ -1133,7 +1135,8 @@ fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
 
     let infcx = infer::new_infer_ctxt(cx.tcx,
                                       &cx.tcx.tables,
-                                      Some(checker.cx.param_env.clone()));
+                                      Some(checker.cx.param_env.clone()),
+                                      ProjectionMode::AnyFinal);
 
     let mut visitor = ExprUseVisitor::new(&mut checker, &infcx);
     visitor.walk_expr(guard);
index 06030c0021171a2c217ab8153893ce1adb60c442..8a1a0080eb0c27adf0d8c293fca452342cdd2a2e 100644 (file)
 use middle::def_id::DefId;
 use middle::pat_util::def_to_path;
 use middle::ty::{self, Ty, TyCtxt};
+use middle::ty::util::IntTypeExt;
+use middle::traits::ProjectionMode;
 use middle::astconv_util::ast_ty_to_prim_ty;
-use util::num::ToPrimitive;
 use util::nodemap::NodeMap;
-use session::Session;
 
 use graphviz::IntoCow;
 use syntax::ast;
 use syntax::parse::token::InternedString;
 use syntax::ptr::P;
 use syntax::codemap;
+use syntax::attr::IntType;
 
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::collections::hash_map::Entry::Vacant;
 use std::hash;
 use std::mem::transmute;
-use std::{i8, i16, i32, i64, u8, u16, u32, u64};
 use std::rc::Rc;
 
-fn lookup_variant_by_id<'a>(tcx: &'a TyCtxt,
+use rustc_const_eval::*;
+
+macro_rules! math {
+    ($e:expr, $op:expr) => {
+        match $op {
+            Ok(val) => val,
+            Err(e) => signal!($e, Math(e)),
+        }
+    }
+}
+
+fn lookup_variant_by_id<'a>(tcx: &'a ty::TyCtxt,
                             enum_def: DefId,
                             variant_def: DefId)
                             -> Option<&'a Expr> {
@@ -88,13 +99,13 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                                         def_id: DefId,
                                         maybe_ref_id: Option<ast::NodeId>,
                                         param_substs: Option<&'tcx subst::Substs<'tcx>>)
-                                        -> Option<&'tcx Expr> {
+                                        -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
         match tcx.map.find(node_id) {
             None => None,
             Some(ast_map::NodeItem(it)) => match it.node {
-                hir::ItemConst(_, ref const_expr) => {
-                    Some(&const_expr)
+                hir::ItemConst(ref ty, ref const_expr) => {
+                    Some((&const_expr, ast_ty_to_prim_ty(tcx, ty)))
                 }
                 _ => None
             },
@@ -113,8 +124,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                             if let Some(param_substs) = param_substs {
                                 substs = substs.subst(tcx, param_substs);
                             }
-                            resolve_trait_associated_const(tcx, ti, trait_id,
-                                                           substs)
+                            resolve_trait_associated_const(tcx, ti, trait_id, substs)
                         }
                         // Technically, without knowing anything about the
                         // expression that generates the obligation, we could
@@ -128,8 +138,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                 _ => None
             },
             Some(ast_map::NodeImplItem(ii)) => match ii.node {
-                hir::ImplItemKind::Const(_, ref expr) => {
-                    Some(&expr)
+                hir::ImplItemKind::Const(ref ty, ref expr) => {
+                    Some((&expr, ast_ty_to_prim_ty(tcx, ty)))
                 }
                 _ => None
             },
@@ -137,16 +147,18 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
         }
     } else {
         match tcx.extern_const_statics.borrow().get(&def_id) {
-            Some(&ast::DUMMY_NODE_ID) => return None,
-            Some(&expr_id) => {
-                return Some(tcx.map.expect_expr(expr_id));
+            Some(&None) => return None,
+            Some(&Some((expr_id, ty))) => {
+                return Some((tcx.map.expect_expr(expr_id), ty));
             }
             None => {}
         }
         let mut used_ref_id = false;
-        let expr_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
+        let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
             cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
-                hir::ItemConst(_, ref const_expr) => Some(const_expr.id),
+                hir::ItemConst(ref ty, ref const_expr) => {
+                    Some((&**const_expr, ast_ty_to_prim_ty(tcx, ty)))
+                },
                 _ => None
             },
             cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node {
@@ -163,8 +175,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                             if let Some(param_substs) = param_substs {
                                 substs = substs.subst(tcx, param_substs);
                             }
-                            resolve_trait_associated_const(tcx, ti, trait_id,
-                                                           substs).map(|e| e.id)
+                            resolve_trait_associated_const(tcx, ti, trait_id, substs)
                         }
                         None => None
                     }
@@ -172,7 +183,9 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                 _ => None
             },
             cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node {
-                hir::ImplItemKind::Const(_, ref expr) => Some(expr.id),
+                hir::ImplItemKind::Const(ref ty, ref expr) => {
+                    Some((&**expr, ast_ty_to_prim_ty(tcx, ty)))
+                },
                 _ => None
             },
             _ => None
@@ -182,10 +195,10 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
         // lookup with the same def_id may yield a different result.
         if !used_ref_id {
             tcx.extern_const_statics
-               .borrow_mut().insert(def_id,
-                                    expr_id.unwrap_or(ast::DUMMY_NODE_ID));
+               .borrow_mut()
+               .insert(def_id, expr_ty.map(|(e, t)| (e.id, t)));
         }
-        expr_id.map(|id| tcx.map.expect_expr(id))
+        expr_ty
     }
 }
 
@@ -248,8 +261,7 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &TyCtxt<'tcx>, def_id: DefId)
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub enum ConstVal {
     Float(f64),
-    Int(i64),
-    Uint(u64),
+    Integral(ConstInt),
     Str(InternedString),
     ByteStr(Rc<Vec<u8>>),
     Bool(bool),
@@ -258,14 +270,18 @@ pub enum ConstVal {
     Function(DefId),
     Array(ast::NodeId, u64),
     Repeat(ast::NodeId, u64),
+    Char(char),
+    /// A value that only occurs in case `eval_const_expr` reported an error. You should never
+    /// handle this case. Its sole purpose is to allow more errors to be reported instead of
+    /// causing a fatal error.
+    Dummy,
 }
 
 impl hash::Hash for ConstVal {
     fn hash<H: hash::Hasher>(&self, state: &mut H) {
         match *self {
             Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
-            Int(a) => a.hash(state),
-            Uint(a) => a.hash(state),
+            Integral(a) => a.hash(state),
             Str(ref a) => a.hash(state),
             ByteStr(ref a) => a.hash(state),
             Bool(a) => a.hash(state),
@@ -274,6 +290,8 @@ fn hash<H: hash::Hasher>(&self, state: &mut H) {
             Function(a) => a.hash(state),
             Array(a, n) => { a.hash(state); n.hash(state) },
             Repeat(a, n) => { a.hash(state); n.hash(state) },
+            Char(c) => c.hash(state),
+            Dummy => ().hash(state),
         }
     }
 }
@@ -286,8 +304,7 @@ impl PartialEq for ConstVal {
     fn eq(&self, other: &ConstVal) -> bool {
         match (self, other) {
             (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
-            (&Int(a), &Int(b)) => a == b,
-            (&Uint(a), &Uint(b)) => a == b,
+            (&Integral(a), &Integral(b)) => a == b,
             (&Str(ref a), &Str(ref b)) => a == b,
             (&ByteStr(ref a), &ByteStr(ref b)) => a == b,
             (&Bool(a), &Bool(b)) => a == b,
@@ -296,6 +313,8 @@ fn eq(&self, other: &ConstVal) -> bool {
             (&Function(a), &Function(b)) => a == b,
             (&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
             (&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
+            (&Char(a), &Char(b)) => a == b,
+            (&Dummy, &Dummy) => true, // FIXME: should this be false?
             _ => false,
         }
     }
@@ -307,9 +326,7 @@ impl ConstVal {
     pub fn description(&self) -> &'static str {
         match *self {
             Float(_) => "float",
-            Int(i) if i < 0 => "negative integer",
-            Int(_) => "positive integer",
-            Uint(_) => "unsigned integer",
+            Integral(i) => i.description(),
             Str(_) => "string literal",
             ByteStr(_) => "byte string literal",
             Bool(_) => "boolean",
@@ -318,6 +335,8 @@ pub fn description(&self) -> &'static str {
             Function(_) => "function definition",
             Array(..) => "array",
             Repeat(..) => "repeat",
+            Char(..) => "char",
+            Dummy => "dummy value",
         }
     }
 }
@@ -370,7 +389,7 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
                     PatKind::Path(path.clone()),
                 Some(Def::Const(def_id)) |
                 Some(Def::AssociatedConst(def_id)) => {
-                    let expr = lookup_const_by_id(tcx, def_id, Some(expr.id), None).unwrap();
+                    let (expr, _ty) = lookup_const_by_id(tcx, def_id, Some(expr.id), None).unwrap();
                     return const_expr_to_pat(tcx, expr, span);
                 },
                 _ => unreachable!(),
@@ -385,7 +404,12 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
 pub fn eval_const_expr(tcx: &TyCtxt, e: &Expr) -> ConstVal {
     match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
         Ok(r) => r,
-        Err(s) => tcx.sess.span_fatal(s.span, &s.description())
+        // non-const path still needs to be a fatal error, because enums are funky
+        Err(ref s) if s.kind == NonConstPath => tcx.sess.span_fatal(s.span, &s.description()),
+        Err(s) => {
+            tcx.sess.span_err(s.span, &s.description());
+            Dummy
+        },
     }
 }
 
@@ -397,12 +421,11 @@ pub struct ConstEvalErr {
     pub kind: ErrKind,
 }
 
-#[derive(Clone)]
+#[derive(Clone, PartialEq)]
 pub enum ErrKind {
     CannotCast,
     CannotCastTo(&'static str),
     InvalidOpForInts(hir::BinOp_),
-    InvalidOpForUInts(hir::BinOp_),
     InvalidOpForBools(hir::BinOp_),
     InvalidOpForFloats(hir::BinOp_),
     InvalidOpForIntUint(hir::BinOp_),
@@ -442,6 +465,18 @@ pub enum ErrKind {
     MiscCatchAll,
 
     IndexOpFeatureGated,
+    Math(ConstMathErr),
+
+    IntermediateUnsignedNegative,
+    /// Expected, Got
+    TypeMismatch(String, ConstInt),
+    BadType(ConstVal),
+}
+
+impl From<ConstMathErr> for ErrKind {
+    fn from(err: ConstMathErr) -> ErrKind {
+        Math(err)
+    }
 }
 
 impl ConstEvalErr {
@@ -451,8 +486,7 @@ pub fn description(&self) -> Cow<str> {
         match self.kind {
             CannotCast => "can't cast this type".into_cow(),
             CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
-            InvalidOpForInts(_) =>  "can't do this op on signed integrals".into_cow(),
-            InvalidOpForUInts(_) =>  "can't do this op on unsigned integrals".into_cow(),
+            InvalidOpForInts(_) =>  "can't do this op on integrals".into_cow(),
             InvalidOpForBools(_) =>  "can't do this op on bools".into_cow(),
             InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
             InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
@@ -492,6 +526,17 @@ pub fn description(&self) -> Cow<str> {
             MiscBinaryOp => "bad operands for binary".into_cow(),
             MiscCatchAll => "unsupported constant expr".into_cow(),
             IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
+            Math(ref err) => err.description().into_cow(),
+
+            IntermediateUnsignedNegative => "during the computation of an unsigned a negative \
+                                             number was encountered. This is most likely a bug in\
+                                             the constant evaluator".into_cow(),
+
+            TypeMismatch(ref expected, ref got) => {
+                format!("mismatched types: expected `{}`, found `{}`",
+                        expected, got.description()).into_cow()
+            },
+            BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(),
         }
     }
 }
@@ -536,276 +581,12 @@ fn checked_or(&self, ty: Ty<'tcx>) -> EvalHint<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum IntTy { I8, I16, I32, I64 }
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum UintTy { U8, U16, U32, U64 }
-
-impl IntTy {
-    pub fn from(tcx: &TyCtxt, t: ast::IntTy) -> IntTy {
-        let t = if let ast::IntTy::Is = t {
-            tcx.sess.target.int_type
-        } else {
-            t
-        };
-        match t {
-            ast::IntTy::Is => unreachable!(),
-            ast::IntTy::I8  => IntTy::I8,
-            ast::IntTy::I16 => IntTy::I16,
-            ast::IntTy::I32 => IntTy::I32,
-            ast::IntTy::I64 => IntTy::I64,
-        }
-    }
-}
-
-impl UintTy {
-    pub fn from(tcx: &TyCtxt, t: ast::UintTy) -> UintTy {
-        let t = if let ast::UintTy::Us = t {
-            tcx.sess.target.uint_type
-        } else {
-            t
-        };
-        match t {
-            ast::UintTy::Us => unreachable!(),
-            ast::UintTy::U8  => UintTy::U8,
-            ast::UintTy::U16 => UintTy::U16,
-            ast::UintTy::U32 => UintTy::U32,
-            ast::UintTy::U64 => UintTy::U64,
-        }
-    }
-}
-
 macro_rules! signal {
     ($e:expr, $exn:expr) => {
         return Err(ConstEvalErr { span: $e.span, kind: $exn })
     }
 }
 
-// The const_{int,uint}_checked_{neg,add,sub,mul,div,shl,shr} family
-// of functions catch and signal overflow errors during constant
-// evaluation.
-//
-// They all take the operator's arguments (`a` and `b` if binary), the
-// overall expression (`e`) and, if available, whole expression's
-// concrete type (`opt_ety`).
-//
-// If the whole expression's concrete type is None, then this is a
-// constant evaluation happening before type check (e.g. in the check
-// to confirm that a pattern range's left-side is not greater than its
-// right-side). We do not do arithmetic modulo the type's bitwidth in
-// such a case; we just do 64-bit arithmetic and assume that later
-// passes will do it again with the type information, and thus do the
-// overflow checks then.
-
-pub fn const_int_checked_neg<'a>(
-    a: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
-
-    let (min,max) = match opt_ety {
-        // (-i8::MIN is itself not an i8, etc, but this is an easy way
-        // to allow literals to pass the check. Of course that does
-        // not work for i64::MIN.)
-        Some(IntTy::I8) =>  (-(i8::MAX as i64), -(i8::MIN as i64)),
-        Some(IntTy::I16) => (-(i16::MAX as i64), -(i16::MIN as i64)),
-        Some(IntTy::I32) => (-(i32::MAX as i64), -(i32::MIN as i64)),
-        None | Some(IntTy::I64) => (-i64::MAX, -(i64::MIN+1)),
-    };
-
-    let oflo = a < min || a > max;
-    if oflo {
-        signal!(e, NegateWithOverflow(a));
-    } else {
-        Ok(Int(-a))
-    }
-}
-
-pub fn const_uint_checked_neg<'a>(
-    a: u64, _e: &'a Expr, _opt_ety: Option<UintTy>) -> EvalResult {
-    // This always succeeds, and by definition, returns `(!a)+1`.
-    Ok(Uint((!a).wrapping_add(1)))
-}
-
-fn const_uint_not(a: u64, opt_ety: Option<UintTy>) -> ConstVal {
-    let mask = match opt_ety {
-        Some(UintTy::U8) => u8::MAX as u64,
-        Some(UintTy::U16) => u16::MAX as u64,
-        Some(UintTy::U32) => u32::MAX as u64,
-        None | Some(UintTy::U64) => u64::MAX,
-    };
-    Uint(!a & mask)
-}
-
-macro_rules! overflow_checking_body {
-    ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident,
-     lhs: $to_8_lhs:ident $to_16_lhs:ident $to_32_lhs:ident,
-     rhs: $to_8_rhs:ident $to_16_rhs:ident $to_32_rhs:ident $to_64_rhs:ident,
-     $EnumTy:ident $T8: ident $T16: ident $T32: ident $T64: ident,
-     $result_type: ident) => { {
-        let (a,b,opt_ety) = ($a,$b,$ety);
-        match opt_ety {
-            Some($EnumTy::$T8) => match (a.$to_8_lhs(), b.$to_8_rhs()) {
-                (Some(a), Some(b)) => {
-                    let (a, oflo) = a.$overflowing_op(b);
-                    (a as $result_type, oflo)
-                }
-                (None, _) | (_, None) => (0, true)
-            },
-            Some($EnumTy::$T16) => match (a.$to_16_lhs(), b.$to_16_rhs()) {
-                (Some(a), Some(b)) => {
-                    let (a, oflo) = a.$overflowing_op(b);
-                    (a as $result_type, oflo)
-                }
-                (None, _) | (_, None) => (0, true)
-            },
-            Some($EnumTy::$T32) => match (a.$to_32_lhs(), b.$to_32_rhs()) {
-                (Some(a), Some(b)) => {
-                    let (a, oflo) = a.$overflowing_op(b);
-                    (a as $result_type, oflo)
-                }
-                (None, _) | (_, None) => (0, true)
-            },
-            None | Some($EnumTy::$T64) => match b.$to_64_rhs() {
-                Some(b) => a.$overflowing_op(b),
-                None => (0, true),
-            }
-        }
-    } }
-}
-
-macro_rules! int_arith_body {
-    ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
-        overflow_checking_body!(
-            $a, $b, $ety, $overflowing_op,
-            lhs: to_i8 to_i16 to_i32,
-            rhs: to_i8 to_i16 to_i32 to_i64, IntTy I8 I16 I32 I64, i64)
-    }
-}
-
-macro_rules! uint_arith_body {
-    ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
-        overflow_checking_body!(
-            $a, $b, $ety, $overflowing_op,
-            lhs: to_u8 to_u16 to_u32,
-            rhs: to_u8 to_u16 to_u32 to_u64, UintTy U8 U16 U32 U64, u64)
-    }
-}
-
-macro_rules! int_shift_body {
-    ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
-        overflow_checking_body!(
-            $a, $b, $ety, $overflowing_op,
-            lhs: to_i8 to_i16 to_i32,
-            rhs: to_u32 to_u32 to_u32 to_u32, IntTy I8 I16 I32 I64, i64)
-    }
-}
-
-macro_rules! uint_shift_body {
-    ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
-        overflow_checking_body!(
-            $a, $b, $ety, $overflowing_op,
-            lhs: to_u8 to_u16 to_u32,
-            rhs: to_u32 to_u32 to_u32 to_u32, UintTy U8 U16 U32 U64, u64)
-    }
-}
-
-macro_rules! pub_fn_checked_op {
-    {$fn_name:ident ($a:ident : $a_ty:ty, $b:ident : $b_ty:ty,.. $WhichTy:ident) {
-        $ret_oflo_body:ident $overflowing_op:ident
-            $const_ty:ident $signal_exn:expr
-    }} => {
-        pub fn $fn_name<'a>($a: $a_ty,
-                            $b: $b_ty,
-                            e: &'a Expr,
-                            opt_ety: Option<$WhichTy>) -> EvalResult {
-            let (ret, oflo) = $ret_oflo_body!($a, $b, opt_ety, $overflowing_op);
-            if !oflo { Ok($const_ty(ret)) } else { signal!(e, $signal_exn) }
-        }
-    }
-}
-
-pub_fn_checked_op!{ const_int_checked_add(a: i64, b: i64,.. IntTy) {
-           int_arith_body overflowing_add Int AddiWithOverflow(a, b)
-}}
-
-pub_fn_checked_op!{ const_int_checked_sub(a: i64, b: i64,.. IntTy) {
-           int_arith_body overflowing_sub Int SubiWithOverflow(a, b)
-}}
-
-pub_fn_checked_op!{ const_int_checked_mul(a: i64, b: i64,.. IntTy) {
-           int_arith_body overflowing_mul Int MuliWithOverflow(a, b)
-}}
-
-pub fn const_int_checked_div<'a>(
-    a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
-    if b == 0 { signal!(e, DivideByZero); }
-    let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_div);
-    if !oflo { Ok(Int(ret)) } else { signal!(e, DivideWithOverflow) }
-}
-
-pub fn const_int_checked_rem<'a>(
-    a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
-    if b == 0 { signal!(e, ModuloByZero); }
-    let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_rem);
-    if !oflo { Ok(Int(ret)) } else { signal!(e, ModuloWithOverflow) }
-}
-
-pub_fn_checked_op!{ const_int_checked_shl(a: i64, b: i64,.. IntTy) {
-           int_shift_body overflowing_shl Int ShiftLeftWithOverflow
-}}
-
-pub_fn_checked_op!{ const_int_checked_shl_via_uint(a: i64, b: u64,.. IntTy) {
-           int_shift_body overflowing_shl Int ShiftLeftWithOverflow
-}}
-
-pub_fn_checked_op!{ const_int_checked_shr(a: i64, b: i64,.. IntTy) {
-           int_shift_body overflowing_shr Int ShiftRightWithOverflow
-}}
-
-pub_fn_checked_op!{ const_int_checked_shr_via_uint(a: i64, b: u64,.. IntTy) {
-           int_shift_body overflowing_shr Int ShiftRightWithOverflow
-}}
-
-pub_fn_checked_op!{ const_uint_checked_add(a: u64, b: u64,.. UintTy) {
-           uint_arith_body overflowing_add Uint AdduWithOverflow(a, b)
-}}
-
-pub_fn_checked_op!{ const_uint_checked_sub(a: u64, b: u64,.. UintTy) {
-           uint_arith_body overflowing_sub Uint SubuWithOverflow(a, b)
-}}
-
-pub_fn_checked_op!{ const_uint_checked_mul(a: u64, b: u64,.. UintTy) {
-           uint_arith_body overflowing_mul Uint MuluWithOverflow(a, b)
-}}
-
-pub fn const_uint_checked_div<'a>(
-    a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
-    if b == 0 { signal!(e, DivideByZero); }
-    let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_div);
-    if !oflo { Ok(Uint(ret)) } else { signal!(e, DivideWithOverflow) }
-}
-
-pub fn const_uint_checked_rem<'a>(
-    a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
-    if b == 0 { signal!(e, ModuloByZero); }
-    let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_rem);
-    if !oflo { Ok(Uint(ret)) } else { signal!(e, ModuloWithOverflow) }
-}
-
-pub_fn_checked_op!{ const_uint_checked_shl(a: u64, b: u64,.. UintTy) {
-           uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
-}}
-
-pub_fn_checked_op!{ const_uint_checked_shl_via_int(a: u64, b: i64,.. UintTy) {
-           uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
-}}
-
-pub_fn_checked_op!{ const_uint_checked_shr(a: u64, b: u64,.. UintTy) {
-           uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
-}}
-
-pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
-           uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
-}}
-
 /// Evaluate a constant expression in a context where the expression isn't
 /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
 /// but a few places need to evaluate constants during type-checking, like
@@ -833,34 +614,57 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
             tcx.expr_ty_opt(e)
         }
     };
-
-    // If type of expression itself is int or uint, normalize in these
-    // bindings so that isize/usize is mapped to a type with an
-    // inherently known bitwidth.
-    let expr_int_type = ety.and_then(|ty| {
-        if let ty::TyInt(t) = ty.sty {
-            Some(IntTy::from(tcx, t)) } else { None }
-    });
-    let expr_uint_type = ety.and_then(|ty| {
-        if let ty::TyUint(t) = ty.sty {
-            Some(UintTy::from(tcx, t)) } else { None }
-    });
-
     let result = match e.node {
       hir::ExprUnary(hir::UnNeg, ref inner) => {
+        // unary neg literals already got their sign during creation
+        if let hir::ExprLit(ref lit) = inner.node {
+            use syntax::ast::*;
+            use syntax::ast::LitIntType::*;
+            const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1;
+            const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1;
+            const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1;
+            const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1;
+            match (&lit.node, ety.map(|t| &t.sty)) {
+                (&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) |
+                (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
+                    return Ok(Integral(I8(::std::i8::MIN)))
+                },
+                (&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) |
+                (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
+                    return Ok(Integral(I16(::std::i16::MIN)))
+                },
+                (&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) |
+                (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
+                    return Ok(Integral(I32(::std::i32::MIN)))
+                },
+                (&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) |
+                (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
+                    return Ok(Integral(I64(::std::i64::MIN)))
+                },
+                (&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) |
+                (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
+                    match tcx.sess.target.int_type {
+                        IntTy::I32 => if n == I32_OVERFLOW {
+                            return Ok(Integral(Isize(Is32(::std::i32::MIN))));
+                        },
+                        IntTy::I64 => if n == I64_OVERFLOW {
+                            return Ok(Integral(Isize(Is64(::std::i64::MIN))));
+                        },
+                        _ => unreachable!(),
+                    }
+                },
+                _ => {},
+            }
+        }
         match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
           Float(f) => Float(-f),
-          Int(n) =>  try!(const_int_checked_neg(n, e, expr_int_type)),
-          Uint(i) => {
-              try!(const_uint_checked_neg(i, e, expr_uint_type))
-          }
+          Integral(i) => Integral(math!(e, -i)),
           const_val => signal!(e, NegateOn(const_val)),
         }
       }
       hir::ExprUnary(hir::UnNot, ref inner) => {
         match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
-          Int(i) => Int(!i),
-          Uint(i) => const_uint_not(i, expr_uint_type),
+          Integral(i) => Integral(math!(e, !i)),
           Bool(b) => Bool(!b),
           const_val => signal!(e, NotOn(const_val)),
         }
@@ -870,6 +674,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
             hir::BiShl | hir::BiShr => ty_hint.checked_or(tcx.types.usize),
             _ => ty_hint
         };
+        // technically, if we don't have type hints, but integral eval
+        // gives us a type through a type-suffix, cast or const def type
+        // we need to re-eval the other value of the BinOp if it was
+        // not inferred
         match (try!(eval_const_expr_partial(tcx, &a, ty_hint, fn_args)),
                try!(eval_const_expr_partial(tcx, &b, b_ty, fn_args))) {
           (Float(a), Float(b)) => {
@@ -888,63 +696,28 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
               _ => signal!(e, InvalidOpForFloats(op.node)),
             }
           }
-          (Int(a), Int(b)) => {
+          (Integral(a), Integral(b)) => {
+            use std::cmp::Ordering::*;
             match op.node {
-              hir::BiAdd => try!(const_int_checked_add(a,b,e,expr_int_type)),
-              hir::BiSub => try!(const_int_checked_sub(a,b,e,expr_int_type)),
-              hir::BiMul => try!(const_int_checked_mul(a,b,e,expr_int_type)),
-              hir::BiDiv => try!(const_int_checked_div(a,b,e,expr_int_type)),
-              hir::BiRem => try!(const_int_checked_rem(a,b,e,expr_int_type)),
-              hir::BiBitAnd => Int(a & b),
-              hir::BiBitOr => Int(a | b),
-              hir::BiBitXor => Int(a ^ b),
-              hir::BiShl => try!(const_int_checked_shl(a,b,e,expr_int_type)),
-              hir::BiShr => try!(const_int_checked_shr(a,b,e,expr_int_type)),
-              hir::BiEq => Bool(a == b),
-              hir::BiLt => Bool(a < b),
-              hir::BiLe => Bool(a <= b),
-              hir::BiNe => Bool(a != b),
-              hir::BiGe => Bool(a >= b),
-              hir::BiGt => Bool(a > b),
+              hir::BiAdd => Integral(math!(e, a + b)),
+              hir::BiSub => Integral(math!(e, a - b)),
+              hir::BiMul => Integral(math!(e, a * b)),
+              hir::BiDiv => Integral(math!(e, a / b)),
+              hir::BiRem => Integral(math!(e, a % b)),
+              hir::BiBitAnd => Integral(math!(e, a & b)),
+              hir::BiBitOr => Integral(math!(e, a | b)),
+              hir::BiBitXor => Integral(math!(e, a ^ b)),
+              hir::BiShl => Integral(math!(e, a << b)),
+              hir::BiShr => Integral(math!(e, a >> b)),
+              hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
+              hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
+              hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
+              hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
+              hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
+              hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
               _ => signal!(e, InvalidOpForInts(op.node)),
             }
           }
-          (Uint(a), Uint(b)) => {
-            match op.node {
-              hir::BiAdd => try!(const_uint_checked_add(a,b,e,expr_uint_type)),
-              hir::BiSub => try!(const_uint_checked_sub(a,b,e,expr_uint_type)),
-              hir::BiMul => try!(const_uint_checked_mul(a,b,e,expr_uint_type)),
-              hir::BiDiv => try!(const_uint_checked_div(a,b,e,expr_uint_type)),
-              hir::BiRem => try!(const_uint_checked_rem(a,b,e,expr_uint_type)),
-              hir::BiBitAnd => Uint(a & b),
-              hir::BiBitOr => Uint(a | b),
-              hir::BiBitXor => Uint(a ^ b),
-              hir::BiShl => try!(const_uint_checked_shl(a,b,e,expr_uint_type)),
-              hir::BiShr => try!(const_uint_checked_shr(a,b,e,expr_uint_type)),
-              hir::BiEq => Bool(a == b),
-              hir::BiLt => Bool(a < b),
-              hir::BiLe => Bool(a <= b),
-              hir::BiNe => Bool(a != b),
-              hir::BiGe => Bool(a >= b),
-              hir::BiGt => Bool(a > b),
-              _ => signal!(e, InvalidOpForUInts(op.node)),
-            }
-          }
-          // shifts can have any integral type as their rhs
-          (Int(a), Uint(b)) => {
-            match op.node {
-              hir::BiShl => try!(const_int_checked_shl_via_uint(a,b,e,expr_int_type)),
-              hir::BiShr => try!(const_int_checked_shr_via_uint(a,b,e,expr_int_type)),
-              _ => signal!(e, InvalidOpForIntUint(op.node)),
-            }
-          }
-          (Uint(a), Int(b)) => {
-            match op.node {
-              hir::BiShl => try!(const_uint_checked_shl_via_int(a,b,e,expr_uint_type)),
-              hir::BiShr => try!(const_uint_checked_shr_via_int(a,b,e,expr_uint_type)),
-              _ => signal!(e, InvalidOpForUintInt(op.node)),
-            }
-          }
           (Bool(a), Bool(b)) => {
             Bool(match op.node {
               hir::BiAnd => a && b,
@@ -962,7 +735,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
         }
       }
       hir::ExprCast(ref base, ref target_ty) => {
-        let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &target_ty))
+        let ety = ast_ty_to_prim_ty(tcx, &target_ty).or_else(|| ety)
                 .unwrap_or_else(|| {
                     tcx.sess.span_fatal(target_ty.span,
                                         "target type not found for const cast")
@@ -971,16 +744,27 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
         let base_hint = if let ExprTypeChecked = ty_hint {
             ExprTypeChecked
         } else {
-            // FIXME (#23833): the type-hint can cause problems,
-            // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
-            // type to the sum, and thus no overflow is signaled.
             match tcx.expr_ty_opt(&base) {
                 Some(t) => UncheckedExprHint(t),
                 None => ty_hint
             }
         };
 
-        let val = try!(eval_const_expr_partial(tcx, &base, base_hint, fn_args));
+        let val = match eval_const_expr_partial(tcx, &base, base_hint, fn_args) {
+            Ok(val) => val,
+            Err(ConstEvalErr { kind: TypeMismatch(_, val), .. }) => {
+                // Something like `5i8 as usize` doesn't need a type hint for the base
+                // instead take the type hint from the inner value
+                let hint = match val.int_type() {
+                    Some(IntType::UnsignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_uint(ty)),
+                    Some(IntType::SignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_int(ty)),
+                    // we had a type hint, so we can't have an unknown type
+                    None => unreachable!(),
+                };
+                try!(eval_const_expr_partial(tcx, &base, hint, fn_args))
+            },
+            Err(e) => return Err(e),
+        };
         match cast_const(tcx, val, ety) {
             Ok(val) => val,
             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
@@ -997,94 +781,49 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
               if def.depth != 0 {
                   signal!(e, UnresolvedPath);
               }
-              Some(def.full_def())
+              def.full_def()
           } else {
-              None
+              signal!(e, NonConstPath);
           };
-          let (const_expr, const_ty) = match opt_def {
-              Some(Def::Const(def_id)) => {
-                  if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
-                      match tcx.map.find(node_id) {
-                          Some(ast_map::NodeItem(it)) => match it.node {
-                              hir::ItemConst(ref ty, ref expr) => {
-                                  (Some(&**expr), Some(&**ty))
-                              }
-                              _ => (None, None)
-                          },
-                          _ => (None, None)
-                      }
+          match opt_def {
+              Def::Const(def_id) |
+              Def::AssociatedConst(def_id) => {
+                  let maybe_ref_id = if let ExprTypeChecked = ty_hint {
+                      Some(e.id)
                   } else {
-                      (lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
+                      None
+                  };
+                  if let Some((e, ty)) = lookup_const_by_id(tcx, def_id, maybe_ref_id, None) {
+                      let item_hint = match ty {
+                          Some(ty) => ty_hint.checked_or(ty),
+                          None => ty_hint,
+                      };
+                      try!(eval_const_expr_partial(tcx, e, item_hint, None))
+                  } else {
+                      signal!(e, NonConstPath);
                   }
-              }
-              Some(Def::AssociatedConst(def_id)) => {
-                  if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
-                      match impl_or_trait_container(tcx, def_id) {
-                          ty::TraitContainer(trait_id) => match tcx.map.find(node_id) {
-                              Some(ast_map::NodeTraitItem(ti)) => match ti.node {
-                                  hir::ConstTraitItem(ref ty, _) => {
-                                      if let ExprTypeChecked = ty_hint {
-                                          let substs = tcx.node_id_item_substs(e.id).substs;
-                                          (resolve_trait_associated_const(tcx,
-                                                                          ti,
-                                                                          trait_id,
-                                                                          substs),
-                                           Some(&**ty))
-                                       } else {
-                                           (None, None)
-                                       }
-                                  }
-                                  _ => (None, None)
-                              },
-                              _ => (None, None)
-                          },
-                          ty::ImplContainer(_) => match tcx.map.find(node_id) {
-                              Some(ast_map::NodeImplItem(ii)) => match ii.node {
-                                  hir::ImplItemKind::Const(ref ty, ref expr) => {
-                                      (Some(&**expr), Some(&**ty))
-                                  }
-                                  _ => (None, None)
-                              },
-                              _ => (None, None)
-                          },
-                      }
+              },
+              Def::Variant(enum_def, variant_def) => {
+                  if let Some(const_expr) = lookup_variant_by_id(tcx, enum_def, variant_def) {
+                      try!(eval_const_expr_partial(tcx, const_expr, ty_hint, None))
                   } else {
-                      (lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
+                      signal!(e, NonConstPath);
                   }
               }
-              Some(Def::Variant(enum_def, variant_def)) => {
-                  (lookup_variant_by_id(tcx, enum_def, variant_def), None)
+              Def::Struct(..) => {
+                  ConstVal::Struct(e.id)
               }
-              Some(Def::Struct(..)) => {
-                  return Ok(ConstVal::Struct(e.id))
-              }
-              Some(Def::Local(_, id)) => {
+              Def::Local(_, id) => {
                   debug!("Def::Local({:?}): {:?}", id, fn_args);
                   if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
-                      return Ok(val.clone());
+                      val.clone()
                   } else {
-                      (None, None)
+                      signal!(e, NonConstPath);
                   }
               },
-              Some(Def::Method(id)) | Some(Def::Fn(id)) => return Ok(Function(id)),
-              _ => (None, None)
-          };
-          let const_expr = match const_expr {
-              Some(actual_e) => actual_e,
-              None => signal!(e, NonConstPath)
-          };
-          let item_hint = if let UncheckedExprNoHint = ty_hint {
-              match const_ty {
-                  Some(ty) => match ast_ty_to_prim_ty(tcx, ty) {
-                      Some(ty) => UncheckedExprHint(ty),
-                      None => UncheckedExprNoHint
-                  },
-                  None => UncheckedExprNoHint
-              }
-          } else {
-              ty_hint
-          };
-          try!(eval_const_expr_partial(tcx, const_expr, item_hint, fn_args))
+              Def::Method(id) | Def::Fn(id) => Function(id),
+              _ => signal!(e, NonConstPath),
+          }
       }
       hir::ExprCall(ref callee, ref args) => {
           let sub_ty_hint = ty_hint.erase_hint();
@@ -1103,10 +842,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
 
           let mut call_args = NodeMap();
           for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) {
+              let arg_hint = ty_hint.erase_hint();
               let arg_val = try!(eval_const_expr_partial(
                   tcx,
                   arg_expr,
-                  sub_ty_hint,
+                  arg_hint,
                   fn_args
               ));
               debug!("const call arg: {:?}", arg);
@@ -1116,7 +856,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
           debug!("const call({:?})", call_args);
           try!(eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args)))
       },
-      hir::ExprLit(ref lit) => lit_to_const(tcx.sess, e.span, &lit, ety),
+      hir::ExprLit(ref lit) => try!(lit_to_const(&lit.node, tcx, ety, lit.span)),
       hir::ExprBlock(ref block) => {
         match block.expr {
             Some(ref expr) => try!(eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)),
@@ -1134,14 +874,15 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
         let arr = try!(eval_const_expr_partial(tcx, arr, arr_hint, fn_args));
         let idx_hint = ty_hint.checked_or(tcx.types.usize);
         let idx = match try!(eval_const_expr_partial(tcx, idx, idx_hint, fn_args)) {
-            Int(i) if i >= 0 => i as u64,
-            Int(_) => signal!(idx, IndexNegative),
-            Uint(i) => i,
+            Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
+            Integral(_) => unreachable!(),
             _ => signal!(idx, IndexNotInt),
         };
+        assert_eq!(idx as usize as u64, idx);
         match arr {
             Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
-            Array(v, _) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
+            Array(v, n) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
+                assert_eq!(n as usize as u64, n);
                 try!(eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args))
             } else {
                 unreachable!()
@@ -1155,13 +896,13 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
                 fn_args,
             )),
 
-            ByteStr(ref data) if idx as usize >= data.len()
-                => signal!(e, IndexOutOfBounds),
-            ByteStr(data) => Uint(data[idx as usize] as u64),
+            ByteStr(ref data) if idx >= data.len() as u64 => signal!(e, IndexOutOfBounds),
+            ByteStr(data) => {
+                Integral(U8(data[idx as usize]))
+            },
 
-            Str(ref s) if idx as usize >= s.len()
-                => signal!(e, IndexOutOfBounds),
-            Str(_) => unimplemented!(), // there's no const_char type
+            Str(ref s) if idx as usize >= s.len() => signal!(e, IndexOutOfBounds),
+            Str(_) => unimplemented!(), // FIXME: return a const char
             _ => signal!(e, IndexedNonVec),
         }
       }
@@ -1171,9 +912,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
           Repeat(
               e.id,
               match try!(eval_const_expr_partial(tcx, &n, len_hint, fn_args)) {
-                  Int(i) if i >= 0 => i as u64,
-                  Int(_) => signal!(e, RepeatCountNotNatural),
-                  Uint(i) => i,
+                  Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
+                  Integral(_) => signal!(e, RepeatCountNotNatural),
                   _ => signal!(e, RepeatCountNotInt),
               },
           )
@@ -1184,7 +924,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
         if let Tuple(tup_id) = c {
             if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
                 if index.node < fields.len() {
-                    return eval_const_expr_partial(tcx, &fields[index.node], base_hint, fn_args)
+                    try!(eval_const_expr_partial(tcx, &fields[index.node], ty_hint, fn_args))
                 } else {
                     signal!(e, TupleIndexOutOfBounds);
                 }
@@ -1205,7 +945,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
                 // if the idents are compared run-pass/issue-19244 fails
                 if let Some(f) = fields.iter().find(|f| f.name.node
                                                      == field_name.node) {
-                    return eval_const_expr_partial(tcx, &f.expr, base_hint, fn_args)
+                    try!(eval_const_expr_partial(tcx, &f.expr, ty_hint, fn_args))
                 } else {
                     signal!(e, MissingStructField);
                 }
@@ -1219,31 +959,89 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
       _ => signal!(e, MiscCatchAll)
     };
 
-    Ok(result)
+    match (ety.map(|t| &t.sty), result) {
+        (Some(ref ty_hint), Integral(i)) => Ok(Integral(try!(infer(i, tcx, ty_hint, e.span)))),
+        (_, result) => Ok(result),
+    }
 }
 
-fn impl_or_trait_container(tcx: &TyCtxt, def_id: DefId) -> ty::ImplOrTraitItemContainer {
-    // This is intended to be equivalent to tcx.impl_or_trait_item(def_id).container()
-    // for local def_id, but it can be called before tcx.impl_or_trait_items is complete.
-    if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
-        if let Some(ast_map::NodeItem(item)) = tcx.map.find(tcx.map.get_parent_node(node_id)) {
-            let container_id = tcx.map.local_def_id(item.id);
-            match item.node {
-                hir::ItemImpl(..) => return ty::ImplContainer(container_id),
-                hir::ItemTrait(..) => return ty::TraitContainer(container_id),
-                _ => ()
+fn infer<'tcx>(
+    i: ConstInt,
+    tcx: &TyCtxt<'tcx>,
+    ty_hint: &ty::TypeVariants<'tcx>,
+    span: Span
+) -> Result<ConstInt, ConstEvalErr> {
+    use syntax::ast::*;
+
+    let err = |e| ConstEvalErr {
+        span: span,
+        kind: e,
+    };
+
+    match (ty_hint, i) {
+        (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result),
+        (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result),
+        (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result),
+        (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result),
+        (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result),
+
+        (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result),
+        (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result),
+        (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result),
+        (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result),
+        (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result),
+
+        (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i64 as i8)),
+        (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i64 as i16)),
+        (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i64 as i32)),
+        (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i64)),
+        (&ty::TyInt(IntTy::Is), Infer(i)) => {
+            match ConstIsize::new(i as i64, tcx.sess.target.int_type) {
+                Ok(val) => Ok(Isize(val)),
+                Err(_) => Ok(Isize(ConstIsize::Is32(i as i64 as i32))),
             }
-        }
-        panic!("No impl or trait container for {:?}", def_id);
+        },
+
+        (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)),
+        (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)),
+        (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)),
+        (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i)),
+        (&ty::TyInt(IntTy::Is), InferSigned(i)) => {
+            match ConstIsize::new(i, tcx.sess.target.int_type) {
+                Ok(val) => Ok(Isize(val)),
+                Err(_) => Ok(Isize(ConstIsize::Is32(i as i32))),
+            }
+        },
+
+        (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)),
+        (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)),
+        (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)),
+        (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i)),
+        (&ty::TyUint(UintTy::Us), Infer(i)) => {
+            match ConstUsize::new(i, tcx.sess.target.uint_type) {
+                Ok(val) => Ok(Usize(val)),
+                Err(_) => Ok(Usize(ConstUsize::Us32(i as u32))),
+            }
+        },
+        (&ty::TyUint(_), InferSigned(_)) => Err(err(IntermediateUnsignedNegative)),
+
+        (&ty::TyInt(ity), i) => Err(err(TypeMismatch(ity.to_string(), i))),
+        (&ty::TyUint(ity), i) => Err(err(TypeMismatch(ity.to_string(), i))),
+
+        (&ty::TyEnum(ref adt, _), i) => {
+            let hints = tcx.lookup_repr_hints(adt.did);
+            let int_ty = tcx.enum_repr_type(hints.iter().next());
+            infer(i, tcx, &int_ty.to_ty(tcx).sty, span)
+        },
+        (_, i) => Err(err(BadType(ConstVal::Integral(i)))),
     }
-    panic!("{:?} is not local", def_id);
 }
 
 fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                                                 ti: &'tcx hir::TraitItem,
                                                 trait_id: DefId,
                                                 rcvr_substs: subst::Substs<'tcx>)
-                                                -> Option<&'tcx Expr>
+                                                -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
 {
     let trait_ref = ty::Binder(
         rcvr_substs.erase_regions().to_trait_ref(tcx, trait_id)
@@ -1252,7 +1050,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
            trait_ref);
 
     tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
-    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
+    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
 
     let mut selcx = traits::SelectionContext::new(&infcx);
     let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
@@ -1270,13 +1068,20 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
         }
     };
 
+    // NOTE: this code does not currently account for specialization, but when
+    // it does so, it should hook into the ProjectionMode to determine when the
+    // constant should resolve; this will also require plumbing through to this
+    // function whether we are in "trans mode" to pick the right ProjectionMode
+    // when constructing the inference context above.
     match selection {
         traits::VtableImpl(ref impl_data) => {
             match tcx.associated_consts(impl_data.impl_def_id)
                      .iter().find(|ic| ic.name == ti.name) {
                 Some(ic) => lookup_const_by_id(tcx, ic.def_id, None, None),
                 None => match ti.node {
-                    hir::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
+                    hir::ConstTraitItem(ref ty, Some(ref expr)) => {
+                        Some((&*expr, ast_ty_to_prim_ty(tcx, ty)))
+                    },
                     _ => None,
                 },
             }
@@ -1289,100 +1094,141 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
     }
 }
 
-fn cast_const<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstVal, ty: Ty) -> CastResult {
-    macro_rules! convert_val {
-        ($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
-            match val {
-                Bool(b) => Ok($const_type(b as u64 as $intermediate_ty as $target_ty)),
-                Uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
-                Int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
-                Float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),
-                _ => Err(ErrKind::CannotCastTo(stringify!($const_type))),
+fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult {
+    let v = val.to_u64_unchecked();
+    match ty.sty {
+        ty::TyBool if v == 0 => Ok(Bool(false)),
+        ty::TyBool if v == 1 => Ok(Bool(true)),
+        ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i64 as i8))),
+        ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i64 as i16))),
+        ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i64 as i32))),
+        ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i64))),
+        ty::TyInt(ast::IntTy::Is) => {
+            match ConstIsize::new(v as i64, tcx.sess.target.int_type) {
+                Ok(val) => Ok(Integral(Isize(val))),
+                Err(_) => Ok(Integral(Isize(ConstIsize::Is32(v as i64 as i32)))),
             }
-        }
+        },
+        ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
+        ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
+        ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
+        ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v))),
+        ty::TyUint(ast::UintTy::Us) => {
+            match ConstUsize::new(v, tcx.sess.target.uint_type) {
+                Ok(val) => Ok(Integral(Usize(val))),
+                Err(_) => Ok(Integral(Usize(ConstUsize::Us32(v as u32)))),
+            }
+        },
+        ty::TyFloat(ast::FloatTy::F64) if val.is_negative() => {
+            // FIXME: this could probably be prettier
+            // there's no easy way to turn an `Infer` into a f64
+            let val = try!((-val).map_err(Math));
+            let val = val.to_u64().unwrap() as f64;
+            let val = -val;
+            Ok(Float(val))
+        },
+        ty::TyFloat(ast::FloatTy::F64) => Ok(Float(val.to_u64().unwrap() as f64)),
+        ty::TyFloat(ast::FloatTy::F32) if val.is_negative() => {
+            let val = try!((-val).map_err(Math));
+            let val = val.to_u64().unwrap() as f32;
+            let val = -val;
+            Ok(Float(val as f64))
+        },
+        ty::TyFloat(ast::FloatTy::F32) => Ok(Float(val.to_u64().unwrap() as f32 as f64)),
+        _ => Err(CannotCast),
     }
+}
 
-    // Issue #23890: If isize/usize, then dispatch to appropriate target representation type
-    match (&ty.sty, tcx.sess.target.int_type, tcx.sess.target.uint_type) {
-        (&ty::TyInt(ast::IntTy::Is), ast::IntTy::I32, _) => return convert_val!(i32, Int, i64),
-        (&ty::TyInt(ast::IntTy::Is), ast::IntTy::I64, _) => return convert_val!(i64, Int, i64),
-        (&ty::TyInt(ast::IntTy::Is), _, _) => panic!("unexpected target.int_type"),
-
-        (&ty::TyUint(ast::UintTy::Us), _, ast::UintTy::U32) => return convert_val!(u32, Uint, u64),
-        (&ty::TyUint(ast::UintTy::Us), _, ast::UintTy::U64) => return convert_val!(u64, Uint, u64),
-        (&ty::TyUint(ast::UintTy::Us), _, _) => panic!("unexpected target.uint_type"),
-
-        _ => {}
+fn cast_const_float<'tcx>(tcx: &TyCtxt<'tcx>, f: f64, ty: ty::Ty) -> CastResult {
+    match ty.sty {
+        ty::TyInt(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
+        ty::TyInt(_) => cast_const_int(tcx, InferSigned(f as i64), ty),
+        ty::TyUint(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
+        ty::TyFloat(ast::FloatTy::F64) => Ok(Float(f)),
+        ty::TyFloat(ast::FloatTy::F32) => Ok(Float(f as f32 as f64)),
+        _ => Err(CannotCast),
     }
+}
 
-    match ty.sty {
-        ty::TyInt(ast::IntTy::Is) => unreachable!(),
-        ty::TyUint(ast::UintTy::Us) => unreachable!(),
-
-        ty::TyInt(ast::IntTy::I8) => convert_val!(i8, Int, i64),
-        ty::TyInt(ast::IntTy::I16) => convert_val!(i16, Int, i64),
-        ty::TyInt(ast::IntTy::I32) => convert_val!(i32, Int, i64),
-        ty::TyInt(ast::IntTy::I64) => convert_val!(i64, Int, i64),
-
-        ty::TyUint(ast::UintTy::U8) => convert_val!(u8, Uint, u64),
-        ty::TyUint(ast::UintTy::U16) => convert_val!(u16, Uint, u64),
-        ty::TyUint(ast::UintTy::U32) => convert_val!(u32, Uint, u64),
-        ty::TyUint(ast::UintTy::U64) => convert_val!(u64, Uint, u64),
-
-        ty::TyFloat(ast::FloatTy::F32) => convert_val!(f32, Float, f64),
-        ty::TyFloat(ast::FloatTy::F64) => convert_val!(f64, Float, f64),
-        _ => Err(ErrKind::CannotCast),
+fn cast_const<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult {
+    match val {
+        Integral(i) => cast_const_int(tcx, i, ty),
+        Bool(b) => cast_const_int(tcx, Infer(b as u64), ty),
+        Float(f) => cast_const_float(tcx, f, ty),
+        Char(c) => cast_const_int(tcx, Infer(c as u64), ty),
+        _ => Err(CannotCast),
     }
 }
 
-fn lit_to_const(sess: &Session, span: Span, lit: &ast::Lit, ty_hint: Option<Ty>) -> ConstVal {
-    match lit.node {
-        ast::LitKind::Str(ref s, _) => Str((*s).clone()),
-        ast::LitKind::ByteStr(ref data) => {
-            ByteStr(data.clone())
-        }
-        ast::LitKind::Byte(n) => Uint(n as u64),
-        ast::LitKind::Char(n) => Uint(n as u64),
-        ast::LitKind::Int(n, ast::LitIntType::Signed(_)) => Int(n as i64),
-        ast::LitKind::Int(n, ast::LitIntType::Unsuffixed) => {
-            match ty_hint.map(|ty| &ty.sty) {
-                Some(&ty::TyUint(_)) => Uint(n),
-                _ => Int(n as i64)
+fn lit_to_const<'tcx>(lit: &ast::LitKind,
+                      tcx: &TyCtxt<'tcx>,
+                      ty_hint: Option<Ty<'tcx>>,
+                      span: Span,
+                      ) -> Result<ConstVal, ConstEvalErr> {
+    use syntax::ast::*;
+    use syntax::ast::LitIntType::*;
+    match *lit {
+        LitKind::Str(ref s, _) => Ok(Str((*s).clone())),
+        LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
+        LitKind::Byte(n) => Ok(Integral(U8(n))),
+        LitKind::Int(n, Signed(ity)) => {
+            infer(InferSigned(n as i64), tcx, &ty::TyInt(ity), span).map(Integral)
+        },
+
+        LitKind::Int(n, Unsuffixed) => {
+            match ty_hint.map(|t| &t.sty) {
+                Some(&ty::TyInt(ity)) => {
+                    infer(InferSigned(n as i64), tcx, &ty::TyInt(ity), span).map(Integral)
+                },
+                Some(&ty::TyUint(uty)) => {
+                    infer(Infer(n), tcx, &ty::TyUint(uty), span).map(Integral)
+                },
+                None => Ok(Integral(Infer(n))),
+                Some(&ty::TyEnum(ref adt, _)) => {
+                    let hints = tcx.lookup_repr_hints(adt.did);
+                    let int_ty = tcx.enum_repr_type(hints.iter().next());
+                    infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty, span).map(Integral)
+                },
+                Some(ty_hint) => panic!("bad ty_hint: {:?}, {:?}", ty_hint, lit),
             }
-        }
-        ast::LitKind::Int(n, ast::LitIntType::Unsigned(_)) => Uint(n),
-        ast::LitKind::Float(ref n, _) |
-        ast::LitKind::FloatUnsuffixed(ref n) => {
+        },
+        LitKind::Int(n, Unsigned(ity)) => {
+            infer(Infer(n), tcx, &ty::TyUint(ity), span).map(Integral)
+        },
+
+        LitKind::Float(ref n, _) |
+        LitKind::FloatUnsuffixed(ref n) => {
             if let Ok(x) = n.parse::<f64>() {
-                Float(x)
+                Ok(Float(x))
             } else {
                 // FIXME(#31407) this is only necessary because float parsing is buggy
-                sess.span_bug(span, "could not evaluate float literal (see issue #31407)");
+                tcx.sess.span_bug(span, "could not evaluate float literal (see issue #31407)");
             }
         }
-        ast::LitKind::Bool(b) => Bool(b)
+        LitKind::Bool(b) => Ok(Bool(b)),
+        LitKind::Char(c) => Ok(Char(c)),
     }
 }
 
 pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
-    Some(match (a, b) {
-        (&Int(a), &Int(b)) => a.cmp(&b),
-        (&Uint(a), &Uint(b)) => a.cmp(&b),
+    match (a, b) {
+        (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
         (&Float(a), &Float(b)) => {
             // This is pretty bad but it is the existing behavior.
-            if a == b {
+            Some(if a == b {
                 Ordering::Equal
             } else if a < b {
                 Ordering::Less
             } else {
                 Ordering::Greater
-            }
+            })
         }
-        (&Str(ref a), &Str(ref b)) => a.cmp(b),
-        (&Bool(a), &Bool(b)) => a.cmp(&b),
-        (&ByteStr(ref a), &ByteStr(ref b)) => a.cmp(b),
-        _ => return None
-    })
+        (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
+        (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
+        (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
+        (&Char(a), &Char(ref b)) => Some(a.cmp(b)),
+        _ => None,
+    }
 }
 
 pub fn compare_lit_exprs<'tcx>(tcx: &TyCtxt<'tcx>,
index 193492ee7e10c2cda18098bcf410c76d41e27bba..6a4680ecbaf31a082b4d44b251319afc02e7b792 100644 (file)
@@ -176,6 +176,7 @@ fn custom_coerce_unsized_kind(&self, def: DefId)
                                   -> Option<ty::adjustment::CustomCoerceUnsized>;
     fn associated_consts(&self, tcx: &TyCtxt<'tcx>, def: DefId)
                          -> Vec<Rc<ty::AssociatedConst<'tcx>>>;
+    fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
 
     // trait/impl-item info
     fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)
@@ -346,6 +347,7 @@ fn custom_coerce_unsized_kind(&self, def: DefId)
         { unimplemented!() }
     fn associated_consts(&self, tcx: &TyCtxt<'tcx>, def: DefId)
                          -> Vec<Rc<ty::AssociatedConst<'tcx>>> { unimplemented!() }
+    fn impl_parent(&self, def: DefId) -> Option<DefId> { unimplemented!() }
 
     // trait/impl-item info
     fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)
index e671dd73431e6db82bed16a51bc99bc6107ce428..4ff1de422117b2852576828f49634cd790dfc7f5 100644 (file)
@@ -27,7 +27,7 @@
 use middle::subst;
 use middle::subst::Substs;
 use middle::subst::Subst;
-use middle::traits;
+use middle::traits::{self, ProjectionMode};
 use middle::ty::adjustment;
 use middle::ty::{TyVid, IntVid, FloatVid};
 use middle::ty::{self, Ty, TyCtxt};
@@ -99,6 +99,11 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
     // directly.
     normalize: bool,
 
+    // Sadly, the behavior of projection varies a bit depending on the
+    // stage of compilation. The specifics are given in the
+    // documentation for `ProjectionMode`.
+    projection_mode: ProjectionMode,
+
     err_count_on_creation: usize,
 }
 
@@ -354,7 +359,8 @@ pub fn fixup_err_to_string(f: FixupError) -> String {
 
 pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>,
                                 tables: &'a RefCell<ty::Tables<'tcx>>,
-                                param_env: Option<ty::ParameterEnvironment<'a, 'tcx>>)
+                                param_env: Option<ty::ParameterEnvironment<'a, 'tcx>>,
+                                projection_mode: ProjectionMode)
                                 -> InferCtxt<'a, 'tcx> {
     InferCtxt {
         tcx: tcx,
@@ -366,14 +372,16 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>,
         parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
         reported_trait_errors: RefCell::new(FnvHashSet()),
         normalize: false,
+        projection_mode: projection_mode,
         err_count_on_creation: tcx.sess.err_count()
     }
 }
 
 pub fn normalizing_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>,
-                                        tables: &'a RefCell<ty::Tables<'tcx>>)
+                                        tables: &'a RefCell<ty::Tables<'tcx>>,
+                                        projection_mode: ProjectionMode)
                                         -> InferCtxt<'a, 'tcx> {
-    let mut infcx = new_infer_ctxt(tcx, tables, None);
+    let mut infcx = new_infer_ctxt(tcx, tables, None, projection_mode);
     infcx.normalize = true;
     infcx
 }
@@ -514,6 +522,7 @@ pub struct CombinedSnapshot {
     region_vars_snapshot: RegionSnapshot,
 }
 
+// NOTE: Callable from trans only!
 pub fn normalize_associated_type<'tcx,T>(tcx: &TyCtxt<'tcx>, value: &T) -> T
     where T : TypeFoldable<'tcx>
 {
@@ -525,7 +534,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &TyCtxt<'tcx>, value: &T) -> T
         return value;
     }
 
-    let infcx = new_infer_ctxt(tcx, &tcx.tables, None);
+    let infcx = new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Any);
     let mut selcx = traits::SelectionContext::new(&infcx);
     let cause = traits::ObligationCause::dummy();
     let traits::Normalized { value: result, obligations } =
@@ -593,6 +602,10 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+    pub fn projection_mode(&self) -> ProjectionMode {
+        self.projection_mode
+    }
+
     pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
         t.fold_with(&mut self.freshener())
     }
@@ -1025,8 +1038,6 @@ pub fn type_vars_for_defs(&self,
                               substs: &mut Substs<'tcx>,
                               defs: &[ty::TypeParameterDef<'tcx>]) {
 
-        let mut vars = Vec::with_capacity(defs.len());
-
         for def in defs.iter() {
             let default = def.default.map(|default| {
                 type_variable::Default {
@@ -1038,7 +1049,6 @@ pub fn type_vars_for_defs(&self,
 
             let ty_var = self.next_ty_var_with_default(default);
             substs.types.push(space, ty_var);
-            vars.push(ty_var)
         }
     }
 
index 02dfeb80b928f0c5b18e3adc119806c7026742cc..510a3dd454b95fcf3307ae9d0d065c9f2fc0b6b9 100644 (file)
@@ -160,6 +160,15 @@ pub fn with_method_from(&self,
         Substs { types: types, regions: regions }
     }
 
+    pub fn with_method_from_subst(self, other: &Substs<'tcx>) -> Substs<'tcx> {
+        let Substs { types, regions } = self;
+        let types = types.with_slice(FnSpace, other.types.get_slice(FnSpace));
+        let regions = regions.map(|r| {
+            r.with_slice(FnSpace, other.regions().get_slice(FnSpace))
+        });
+        Substs { types: types, regions: regions }
+    }
+
     /// Creates a trait-ref out of this substs, ignoring the FnSpace substs
     pub fn to_trait_ref(&self, tcx: &TyCtxt<'tcx>, trait_id: DefId)
                         -> ty::TraitRef<'tcx> {
index 92982af92dcfe7ad772500cb809f66812070bafa..ff72f9dd07e36096819e2244644099a136cc63c4 100644 (file)
@@ -428,3 +428,43 @@ We used to try and draw finer-grained distinctions, but that led to a
 serious of 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).
+
+# Specialization
+
+Defined in the `specialize` module.
+
+The basic strategy is to build up a *specialization graph* during
+coherence checking. Insertion into the graph locates the right place
+to put an impl in the specialization hierarchy; if there is no right
+place (due to partial overlap but no containment), you get an overlap
+error. Specialization is consulted when selecting an impl (of course),
+and the graph is consulted when propagating defaults down the
+specialization hierarchy.
+
+You might expect that the specialization graph would be used during
+selection -- i.e., when actually performing specialization. This is
+not done for two reasons:
+
+- It's merely an optimization: given a set of candidates that apply,
+  we can determine the most specialized one by comparing them directly
+  for specialization, rather than consulting the graph. Given that we
+  also cache the results of selection, the benefit of this
+  optimization is questionable.
+
+- To build the specialization graph in the first place, we need to use
+  selection (because we need to determine whether one impl specializes
+  another). Dealing with this reentrancy would require some additional
+  mode switch for selection. Given that there seems to be no strong
+  reason to use the graph anyway, we stick with a simpler approach in
+  selection, and use the graph only for propagating default
+  implementations.
+
+Trait impl selection can succeed even when multiple impls can apply,
+as long as they are part of the same specialization family. In that
+case, it returns a *single* impl on success -- this is the most
+specialized impl *known* to apply. However, if there are any inference
+variables in play, the returned impl may not be the actual impl we
+will use at trans time. Thus, we take special care to avoid projecting
+associated types unless either (1) the associated type does not use
+`default` and thus cannot be overridden or (2) all input types are
+known concretely.
index 6005d36ff4eb20c79bc36592fd85fca6fc27d185..64d1c992cbf1d475928d82c2a49a6720abdf946b 100644 (file)
@@ -10,8 +10,7 @@
 
 //! See `README.md` for high-level documentation
 
-use super::{SelectionContext};
-use super::{Obligation, ObligationCause};
+use super::{SelectionContext, Obligation, ObligationCause};
 
 use middle::cstore::LOCAL_CRATE;
 use middle::def_id::DefId;
@@ -23,8 +22,8 @@
 #[derive(Copy, Clone)]
 struct InferIsLocal(bool);
 
-/// If there are types that satisfy both impls, returns an `ImplTy`
-/// with those types substituted (by updating the given `infcx`)
+/// If there are types that satisfy both impls, returns a suitably-freshened
+/// `ImplHeader` with those types substituted
 pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
                                     impl1_def_id: DefId,
                                     impl2_def_id: DefId)
index 8a2f0c0c093041fe9c6011386bd94031794c03a7..5f66e9e6344ad76d6034043ca1d9047c12c4b0de 100644 (file)
 pub use self::coherence::overlapping_impls;
 pub use self::coherence::OrphanCheckErr;
 pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
-pub use self::project::MismatchedProjectionTypes;
-pub use self::project::normalize;
-pub use self::project::Normalized;
+pub use self::project::{MismatchedProjectionTypes, ProjectionMode};
+pub use self::project::{normalize, Normalized};
 pub use self::object_safety::is_object_safe;
 pub use self::object_safety::astconv_object_safety_violations;
 pub use self::object_safety::object_safety_violations;
 pub use self::object_safety::ObjectSafetyViolation;
 pub use self::object_safety::MethodViolationCode;
 pub use self::object_safety::is_vtable_safe_method;
-pub use self::select::EvaluationCache;
-pub use self::select::SelectionContext;
-pub use self::select::SelectionCache;
+pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
 pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
 pub use self::select::{MethodMatchedData}; // intentionally don't export variants
+pub use self::specialize::{Overlap, specialization_graph, specializes, translate_substs};
 pub use self::util::elaborate_predicates;
 pub use self::util::get_vtable_index_of_object_method;
 pub use self::util::trait_ref_for_builtin_bound;
@@ -67,6 +65,7 @@
 mod project;
 mod object_safety;
 mod select;
+mod specialize;
 mod structural_impls;
 mod util;
 
@@ -434,7 +433,10 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
 
     let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
 
-    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(elaborated_env));
+    let infcx = infer::new_infer_ctxt(tcx,
+                                      &tcx.tables,
+                                      Some(elaborated_env),
+                                      ProjectionMode::AnyFinal);
     let predicates = match fully_normalize(&infcx,
                                            cause,
                                            &infcx.parameter_environment.caller_bounds) {
index e36307feddbf79b3a7ec68bdfcd414bbd19cf97a..e86f3ed01a49d6c8ceb0558259edc58072983417 100644 (file)
@@ -12,6 +12,8 @@
 
 use super::elaborate_predicates;
 use super::report_overflow_error;
+use super::specialization_graph;
+use super::translate_substs;
 use super::Obligation;
 use super::ObligationCause;
 use super::PredicateObligation;
 use super::VtableImplData;
 use super::util;
 
+use middle::def_id::DefId;
 use middle::infer::{self, TypeOrigin};
 use middle::subst::Subst;
 use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
 use middle::ty::fold::{TypeFoldable, TypeFolder};
 use syntax::parse::token;
+use syntax::ast;
 use util::common::FN_OUTPUT_NAME;
 
+use std::rc::Rc;
+
+/// Depending on the stage of compilation, we want projection to be
+/// more or less conservative.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum ProjectionMode {
+    /// FIXME (#32205)
+    /// At coherence-checking time, we're still constructing the
+    /// specialization graph, and thus we only project project
+    /// non-`default` associated types that are defined directly in
+    /// the applicable impl. (This behavior should be improved over
+    /// time, to allow for successful projections modulo cycles
+    /// between different impls).
+    ///
+    /// Here's an example that will fail due to the restriction:
+    ///
+    /// ```
+    /// trait Assoc {
+    ///     type Output;
+    /// }
+    ///
+    /// impl<T> Assoc for T {
+    ///     type Output = bool;
+    /// }
+    ///
+    /// impl Assoc for u8 {} // <- inherits the non-default type from above
+    ///
+    /// trait Foo {}
+    /// impl Foo for u32 {}
+    /// impl Foo for <u8 as Assoc>::Output {}  // <- this projection will fail
+    /// ```
+    ///
+    /// The projection would succeed if `Output` had been defined
+    /// directly in the impl for `u8`.
+    Topmost,
+
+    /// At type-checking time, we refuse to project any associated
+    /// type that is marked `default`. Non-`default` ("final") types
+    /// are always projected. This is necessary in general for
+    /// soundness of specialization. However, we *could* allow
+    /// projections in fully-monomorphic cases. We choose not to,
+    /// because we prefer for `default type` to force the type
+    /// definition to be treated abstractly by any consumers of the
+    /// impl. Concretely, that means that the following example will
+    /// fail to compile:
+    ///
+    /// ```
+    /// trait Assoc {
+    ///     type Output;
+    /// }
+    ///
+    /// impl<T> Assoc for T {
+    ///     default type Output = bool;
+    /// }
+    ///
+    /// fn main() {
+    ///     let <() as Assoc>::Output = true;
+    /// }
+    AnyFinal,
+
+    /// At trans time, all projections will succeed.
+    Any,
+}
+
+impl ProjectionMode {
+    pub fn is_topmost(&self) -> bool {
+        match *self {
+            ProjectionMode::Topmost => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_any_final(&self) -> bool {
+        match *self {
+            ProjectionMode::AnyFinal => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_any(&self) -> bool {
+        match *self {
+            ProjectionMode::Any => true,
+            _ => false,
+        }
+    }
+}
+
+
 pub type PolyProjectionObligation<'tcx> =
     Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
 
@@ -566,7 +658,76 @@ fn project_type<'cx,'tcx>(
 
     assert!(candidates.vec.len() <= 1);
 
-    match candidates.vec.pop() {
+    let possible_candidate = candidates.vec.pop().and_then(|candidate| {
+        // In Any (i.e. trans) mode, all projections succeed;
+        // otherwise, we need to be sensitive to `default` and
+        // specialization.
+        if !selcx.projection_mode().is_any() {
+            if let ProjectionTyCandidate::Impl(ref impl_data) = candidate {
+                if let Some(node_item) = assoc_ty_def(selcx,
+                                                      impl_data.impl_def_id,
+                                                      obligation.predicate.item_name) {
+                    if node_item.node.is_from_trait() {
+                        if node_item.item.ty.is_some() {
+                            // If the associated type has a default from the
+                            // trait, that should be considered `default` and
+                            // hence not projected.
+                            //
+                            // Note, however, that we allow a projection from
+                            // the trait specifically in the case that the trait
+                            // does *not* give a default. This is purely to
+                            // avoid spurious errors: the situation can only
+                            // arise when *no* impl in the specialization chain
+                            // has provided a definition for the type. When we
+                            // confirm the candidate, we'll turn the projection
+                            // into a TyError, since the actual error will be
+                            // reported in `check_impl_items_against_trait`.
+                            return None;
+                        }
+                    } else if node_item.item.defaultness.is_default() {
+                        return None;
+                    }
+                } else {
+                    // Normally this situation could only arise througha
+                    // compiler bug, but at coherence-checking time we only look
+                    // at the topmost impl (we don't even consider the trait
+                    // itself) for the definition -- so we can fail to find a
+                    // definition of the type even if it exists.
+
+                    // For now, we just unconditionally ICE, because otherwise,
+                    // examples like the following will succeed:
+                    //
+                    // ```
+                    // trait Assoc {
+                    //     type Output;
+                    // }
+                    //
+                    // impl<T> Assoc for T {
+                    //     default type Output = bool;
+                    // }
+                    //
+                    // impl Assoc for u8 {}
+                    // impl Assoc for u16 {}
+                    //
+                    // trait Foo {}
+                    // impl Foo for <u8 as Assoc>::Output {}
+                    // impl Foo for <u16 as Assoc>::Output {}
+                    //     return None;
+                    // }
+                    // ```
+                    //
+                    // The essential problem here is that the projection fails,
+                    // leaving two unnormalized types, which appear not to unify
+                    // -- so the overlap check succeeds, when it should fail.
+                    selcx.tcx().sess.bug("Tried to project an inherited associated type during \
+                                          coherence checking, which is currently not supported.");
+                }
+            }
+        }
+        Some(candidate)
+    });
+
+    match possible_candidate {
         Some(candidate) => {
             let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
             Ok(ProjectedTy::Progress(ty, obligations))
@@ -941,43 +1102,63 @@ fn confirm_impl_candidate<'cx,'tcx>(
     impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>)
     -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
 {
-    // there don't seem to be nicer accessors to these:
-    let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
-
-    // Look for the associated type in the impl
-    for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] {
-        if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] {
-            if assoc_ty.name == obligation.predicate.item_name {
-                return (assoc_ty.ty.unwrap().subst(selcx.tcx(), impl_vtable.substs),
-                        impl_vtable.nested);
-            }
+    let VtableImplData { substs, nested, impl_def_id } = impl_vtable;
+
+    let tcx = selcx.tcx();
+    let trait_ref = obligation.predicate.trait_ref;
+    let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name);
+
+    match assoc_ty {
+        Some(node_item) => {
+            let ty = node_item.item.ty.unwrap_or_else(|| {
+                // This means that the impl is missing a definition for the
+                // associated type. This error will be reported by the type
+                // checker method `check_impl_items_against_trait`, so here we
+                // just return TyError.
+                debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
+                       node_item.item.name,
+                       obligation.predicate.trait_ref);
+                tcx.types.err
+            });
+            let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node);
+            (ty.subst(tcx, substs), nested)
+        }
+        None => {
+            tcx.sess.span_bug(obligation.cause.span,
+                              &format!("No associated type for {:?}", trait_ref));
         }
     }
+}
 
-    // It is not in the impl - get the default from the trait.
-    let trait_ref = obligation.predicate.trait_ref;
-    for trait_item in selcx.tcx().trait_items(trait_ref.def_id).iter() {
-        if let &ty::TypeTraitItem(ref assoc_ty) = trait_item {
-            if assoc_ty.name == obligation.predicate.item_name {
-                if let Some(ty) = assoc_ty.ty {
-                    return (ty.subst(selcx.tcx(), trait_ref.substs),
-                            impl_vtable.nested);
-                } else {
-                    // This means that the impl is missing a
-                    // definition for the associated type. This error
-                    // ought to be reported by the type checker method
-                    // `check_impl_items_against_trait`, so here we
-                    // just return TyError.
-                    debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
-                           assoc_ty.name,
-                           trait_ref);
-                    return (selcx.tcx().types.err, vec!());
+/// Locate the definition of an associated type in the specialization hierarchy,
+/// starting from the given impl.
+///
+/// Based on the "projection mode", this lookup may in fact only examine the
+/// topmost impl. See the comments for `ProjectionMode` for more details.
+fn assoc_ty_def<'cx, 'tcx>(selcx: &SelectionContext<'cx, 'tcx>,
+                           impl_def_id: DefId,
+                           assoc_ty_name: ast::Name)
+                           -> Option<specialization_graph::NodeItem<Rc<ty::AssociatedType<'tcx>>>>
+{
+    let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
+
+    if selcx.projection_mode().is_topmost() {
+        let impl_node = specialization_graph::Node::Impl(impl_def_id);
+        for item in impl_node.items(selcx.tcx()) {
+            if let ty::TypeTraitItem(assoc_ty) = item {
+                if assoc_ty.name == assoc_ty_name {
+                    return Some(specialization_graph::NodeItem {
+                        node: specialization_graph::Node::Impl(impl_def_id),
+                        item: assoc_ty,
+                    });
                 }
             }
         }
+        None
+    } else {
+        selcx.tcx().lookup_trait_def(trait_def_id)
+            .ancestors(impl_def_id)
+            .type_defs(selcx.tcx(), assoc_ty_name)
+            .next()
     }
-
-    selcx.tcx().sess.span_bug(obligation.cause.span,
-                              &format!("No associated type for {:?}",
-                                       trait_ref));
 }
index fbfd4b67b5bd5393b8c71ad2b62f98ca8f281bec..3ef163f225c4aa956c5a7abeab396c79448b7a59 100644 (file)
@@ -25,6 +25,7 @@
 use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
 use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
 use super::{ObjectCastObligation, Obligation};
+use super::ProjectionMode;
 use super::TraitNotObjectSafe;
 use super::Selection;
 use super::SelectionResult;
@@ -40,6 +41,7 @@
 use middle::infer::{InferCtxt, TypeFreshener, TypeOrigin};
 use middle::subst::{Subst, Substs, TypeSpace};
 use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
+use middle::traits;
 use middle::ty::fast_reject;
 use middle::ty::relate::TypeRelation;
 
@@ -75,7 +77,6 @@ pub struct SelectionContext<'cx, 'tcx:'cx> {
     /// other words, we consider `$0 : Bar` to be unimplemented if
     /// there is no type that the user could *actually name* that
     /// would satisfy it. This avoids crippling inference, basically.
-
     intercrate: bool,
 }
 
@@ -224,6 +225,12 @@ struct SelectionCandidateSet<'tcx> {
     ambiguous: bool,
 }
 
+#[derive(PartialEq,Eq,Debug,Clone)]
+struct EvaluatedCandidate<'tcx> {
+    candidate: SelectionCandidate<'tcx>,
+    evaluation: EvaluationResult,
+}
+
 enum BuiltinBoundConditions<'tcx> {
     If(ty::Binder<Vec<Ty<'tcx>>>),
     ParameterBuiltin,
@@ -251,8 +258,7 @@ pub struct EvaluationCache<'tcx> {
 }
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
-    pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>)
-               -> SelectionContext<'cx, 'tcx> {
+    pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
             infcx: infcx,
             freshener: infcx.freshener(),
@@ -260,8 +266,7 @@ pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>)
         }
     }
 
-    pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>)
-                      -> SelectionContext<'cx, 'tcx> {
+    pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
             infcx: infcx,
             freshener: infcx.freshener(),
@@ -285,6 +290,10 @@ pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> {
         self.infcx
     }
 
+    pub fn projection_mode(&self) -> ProjectionMode {
+        self.infcx.projection_mode()
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Selection
     //
@@ -558,7 +567,7 @@ fn evaluate_stack<'o>(&mut self,
         // this crate, perhaps the type would be unified with
         // something from another crate that does provide an impl.
         //
-        // In intracrate mode, we must still be conservative. The reason is
+        // In intra mode, we must still be conservative. The reason is
         // that we want to avoid cycles. Imagine an impl like:
         //
         //     impl<T:Eq> Eq for Vec<T>
@@ -746,6 +755,17 @@ fn candidate_from_obligation<'o>(&mut self,
         candidate
     }
 
+    // Treat negative impls as unimplemented
+    fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
+                             -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+        if let ImplCandidate(def_id) = candidate {
+            if self.tcx().trait_impl_polarity(def_id) == Some(hir::ImplPolarity::Negative) {
+                return Err(Unimplemented)
+            }
+        }
+        Ok(Some(candidate))
+    }
+
     fn candidate_from_obligation_no_cache<'o>(&mut self,
                                               stack: &TraitObligationStack<'o, 'tcx>)
                                               -> SelectionResult<'tcx, SelectionCandidate<'tcx>>
@@ -762,7 +782,7 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
         }
 
         if !self.is_knowable(stack) {
-            debug!("intercrate not knowable");
+            debug!("coherence stage: not knowable");
             return Ok(None);
         }
 
@@ -803,12 +823,27 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
         // we were to winnow, we'd wind up with zero candidates.
         // Instead, we select the right impl now but report `Bar does
         // not implement Clone`.
-        if candidates.len() > 1 {
-            candidates.retain(|c| self.evaluate_candidate(stack, c).may_apply())
-        }
+        if candidates.len() == 1 {
+            return self.filter_negative_impls(candidates.pop().unwrap());
+        }
+
+        // Winnow, but record the exact outcome of evaluation, which
+        // is needed for specialization.
+        let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| {
+            let eval = self.evaluate_candidate(stack, &c);
+            if eval.may_apply() {
+                Some(EvaluatedCandidate {
+                    candidate: c,
+                    evaluation: eval,
+                })
+            } else {
+                None
+            }
+        }).collect();
 
-        // If there are STILL multiple candidate, we can further reduce
-        // the list by dropping duplicates.
+        // If there are STILL multiple candidate, we can further
+        // reduce the list by dropping duplicates -- including
+        // resolving specializations.
         if candidates.len() > 1 {
             let mut i = 0;
             while i < candidates.len() {
@@ -836,8 +871,7 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
             return Ok(None);
         }
 
-
-        // If there are *NO* candidates, that there are no impls --
+        // If there are *NO* candidates, then there are no impls --
         // that we know of, anyway. Note that in the case where there
         // are unbound type variables within the obligation, it might
         // be the case that you could still satisfy the obligation
@@ -851,19 +885,7 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
         }
 
         // Just one candidate left.
-        let candidate = candidates.pop().unwrap();
-
-        match candidate {
-            ImplCandidate(def_id) => {
-                match self.tcx().trait_impl_polarity(def_id) {
-                    Some(hir::ImplPolarity::Negative) => return Err(Unimplemented),
-                    _ => {}
-                }
-            }
-            _ => {}
-        }
-
-        Ok(Some(candidate))
+        self.filter_negative_impls(candidates.pop().unwrap().candidate)
     }
 
     fn is_knowable<'o>(&mut self,
@@ -1565,41 +1587,54 @@ fn assemble_candidates_for_unsizing(&mut self,
     /// candidates and prefer where-clause candidates.
     ///
     /// See the comment for "SelectionCandidate" for more details.
-    fn candidate_should_be_dropped_in_favor_of<'o>(&mut self,
-                                                   victim: &SelectionCandidate<'tcx>,
-                                                   other: &SelectionCandidate<'tcx>)
-                                                   -> bool
+    fn candidate_should_be_dropped_in_favor_of<'o>(
+        &mut self,
+        victim: &EvaluatedCandidate<'tcx>,
+        other: &EvaluatedCandidate<'tcx>)
+        -> bool
     {
-        if victim == other {
+        if victim.candidate == other.candidate {
             return true;
         }
 
-        match other {
-            &ObjectCandidate |
-            &ParamCandidate(_) | &ProjectionCandidate => match victim {
-                &DefaultImplCandidate(..) => {
+        match other.candidate {
+            ObjectCandidate |
+            ParamCandidate(_) | ProjectionCandidate => match victim.candidate {
+                DefaultImplCandidate(..) => {
                     self.tcx().sess.bug(
                         "default implementations shouldn't be recorded \
                          when there are other valid candidates");
                 }
-                &ImplCandidate(..) |
-                &ClosureCandidate(..) |
-                &FnPointerCandidate |
-                &BuiltinObjectCandidate |
-                &BuiltinUnsizeCandidate |
-                &DefaultImplObjectCandidate(..) |
-                &BuiltinCandidate(..) => {
+                ImplCandidate(..) |
+                ClosureCandidate(..) |
+                FnPointerCandidate |
+                BuiltinObjectCandidate |
+                BuiltinUnsizeCandidate |
+                DefaultImplObjectCandidate(..) |
+                BuiltinCandidate(..) => {
                     // We have a where-clause so don't go around looking
                     // for impls.
                     true
                 }
-                &ObjectCandidate |
-                &ProjectionCandidate => {
+                ObjectCandidate |
+                ProjectionCandidate => {
                     // Arbitrarily give param candidates priority
                     // over projection and object candidates.
                     true
                 },
-                &ParamCandidate(..) => false,
+                ParamCandidate(..) => false,
+            },
+            ImplCandidate(other_def) => {
+                // See if we can toss out `victim` based on specialization.
+                // This requires us to know *for sure* that the `other` impl applies
+                // i.e. EvaluatedToOk:
+                if other.evaluation == EvaluatedToOk {
+                    if let ImplCandidate(victim_def) = victim.candidate {
+                        return traits::specializes(self.tcx(), other_def, victim_def);
+                    }
+                }
+
+                false
             },
             _ => false
         }
diff --git a/src/librustc/middle/traits/specialize/mod.rs b/src/librustc/middle/traits/specialize/mod.rs
new file mode 100644 (file)
index 0000000..a692fe5
--- /dev/null
@@ -0,0 +1,229 @@
+// 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.
+
+// Logic and data structures related to impl specialization, explained in
+// greater detail below.
+//
+// At the moment, this implementation support only the simple "chain" rule:
+// If any two impls overlap, one must be a strict subset of the other.
+//
+// See traits/README.md for a bit more detail on how specialization
+// fits together with the rest of the trait machinery.
+
+use super::{SelectionContext, FulfillmentContext};
+use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig};
+
+use middle::cstore::CrateStore;
+use middle::def_id::DefId;
+use middle::infer::{self, InferCtxt, TypeOrigin};
+use middle::region;
+use middle::subst::{Subst, Substs};
+use middle::traits::{self, ProjectionMode, ObligationCause, Normalized};
+use middle::ty::{self, TyCtxt};
+use syntax::codemap::DUMMY_SP;
+
+pub mod specialization_graph;
+
+/// Information pertinent to an overlapping impl error.
+pub struct Overlap<'a, 'tcx: 'a> {
+    pub in_context: InferCtxt<'a, 'tcx>,
+    pub with_impl: DefId,
+    pub on_trait_ref: ty::TraitRef<'tcx>,
+}
+
+/// 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
+/// selected, and `source_substs` is a substitution of its generics (and
+/// possibly some relevant `FnSpace` variables as well). And `target_node` is
+/// the impl/trait we're actually going to get the definition from. The resulting
+/// substitution will map from `target_node`'s generics to `source_impl`'s
+/// generics as instantiated by `source_subst`.
+///
+/// For example, consider the following scenario:
+///
+/// ```rust
+/// trait Foo { ... }
+/// impl<T, U> Foo for (T, U) { ... }  // target impl
+/// impl<V> Foo for (V, V) { ... }     // source impl
+/// ```
+///
+/// Suppose we have selected "source impl" with `V` instantiated with `u32`.
+/// This function will produce a substitution with `T` and `U` both mapping to `u32`.
+///
+/// Where clauses add some trickiness here, because they can be used to "define"
+/// an argument indirectly:
+///
+/// ```rust
+/// impl<'a, I, T: 'a> Iterator for Cloned<I>
+///    where I: Iterator<Item=&'a T>, T: Clone
+/// ```
+///
+/// In a case like this, the substitution for `T` is determined indirectly,
+/// through associated type projection. We deal with such cases by using
+/// *fulfillment* to relate the two impls, requiring that all projections are
+/// resolved.
+pub fn translate_substs<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                  source_impl: DefId,
+                                  source_substs: &'tcx Substs<'tcx>,
+                                  target_node: specialization_graph::Node)
+                                  -> &'tcx Substs<'tcx> {
+    let source_trait_ref = infcx.tcx
+                                .impl_trait_ref(source_impl)
+                                .unwrap()
+                                .subst(infcx.tcx, &source_substs);
+
+    // translate the Self and TyParam parts of the substitution, since those
+    // vary across impls
+    let target_substs = match target_node {
+        specialization_graph::Node::Impl(target_impl) => {
+            // no need to translate if we're targetting the impl we started with
+            if source_impl == target_impl {
+                return source_substs;
+            }
+
+            fulfill_implication(infcx, source_trait_ref, target_impl).unwrap_or_else(|_| {
+                infcx.tcx
+                     .sess
+                     .bug("When translating substitutions for specialization, the expected \
+                           specializaiton failed to hold")
+            })
+        }
+        specialization_graph::Node::Trait(..) => source_trait_ref.substs.clone(),
+    };
+
+    // retain erasure mode
+    // NB: this must happen before inheriting method generics below
+    let target_substs = if source_substs.regions.is_erased() {
+        target_substs.erase_regions()
+    } else {
+        target_substs
+    };
+
+    // directly inherent the method generics, since those do not vary across impls
+    infcx.tcx.mk_substs(target_substs.with_method_from_subst(source_substs))
+}
+
+/// Is impl1 a specialization of impl2?
+///
+/// Specialization is determined by the sets of types to which the impls apply;
+/// impl1 specializes impl2 if it applies to a subset of the types impl2 applies
+/// to.
+pub fn specializes(tcx: &TyCtxt, impl1_def_id: DefId, impl2_def_id: DefId) -> bool {
+    // The feature gate should prevent introducing new specializations, but not
+    // taking advantage of upstream ones.
+    if !tcx.sess.features.borrow().specialization &&
+        (impl1_def_id.is_local() || impl2_def_id.is_local()) {
+        return false;
+    }
+
+    // We determine whether there's a subset relationship by:
+    //
+    // - skolemizing impl1,
+    // - assuming the where clauses for impl1,
+    // - instantiating impl2 with fresh inference variables,
+    // - unifying,
+    // - attempting to prove the where clauses for impl2
+    //
+    // The last three steps are encapsulated in `fulfill_implication`.
+    //
+    // See RFC 1210 for more details and justification.
+
+    // Currently we do not allow e.g. a negative impl to specialize a positive one
+    if tcx.trait_impl_polarity(impl1_def_id) != tcx.trait_impl_polarity(impl2_def_id) {
+        return false;
+    }
+
+    let mut infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Topmost);
+
+    // create a parameter environment corresponding to a (skolemized) instantiation of impl1
+    let scheme = tcx.lookup_item_type(impl1_def_id);
+    let predicates = tcx.lookup_predicates(impl1_def_id);
+    let mut penv = tcx.construct_parameter_environment(DUMMY_SP,
+                                                       &scheme.generics,
+                                                       &predicates,
+                                                       region::DUMMY_CODE_EXTENT);
+    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
+                             .unwrap()
+                             .subst(tcx, &penv.free_substs);
+
+    // Normalize the trait reference, adding any obligations that arise into the impl1 assumptions
+    let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
+        let selcx = &mut SelectionContext::new(&infcx);
+        traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
+    };
+    penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| o.predicate));
+
+    // Install the parameter environment, taking the predicates of impl1 as assumptions:
+    infcx.parameter_environment = penv;
+
+    // Attempt to prove that impl2 applies, given all of the above.
+    fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
+}
+
+/// Attempt to fulfill all obligations of `target_impl` after unification with
+/// `source_trait_ref`. If successful, returns a substitution for *all* the
+/// generics of `target_impl`, including both those needed to unify with
+/// `source_trait_ref` and those whose identity is determined via a where
+/// clause in the impl.
+fn fulfill_implication<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                 source_trait_ref: ty::TraitRef<'tcx>,
+                                 target_impl: DefId)
+                                 -> Result<Substs<'tcx>, ()> {
+    infcx.commit_if_ok(|_| {
+        let selcx = &mut SelectionContext::new(&infcx);
+        let target_substs = fresh_type_vars_for_impl(&infcx, DUMMY_SP, target_impl);
+        let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx,
+                                                                       target_impl,
+                                                                       &target_substs);
+
+        // do the impls unify? If not, no specialization.
+        if let Err(_) = infer::mk_eq_trait_refs(&infcx,
+                                                true,
+                                                TypeOrigin::Misc(DUMMY_SP),
+                                                source_trait_ref,
+                                                target_trait_ref) {
+            debug!("fulfill_implication: {:?} does not unify with {:?}",
+                   source_trait_ref,
+                   target_trait_ref);
+            return Err(());
+        }
+
+        // attempt to prove all of the predicates for impl2 given those for impl1
+        // (which are packed up in penv)
+
+        let mut fulfill_cx = FulfillmentContext::new();
+        for oblig in obligations.into_iter() {
+            fulfill_cx.register_predicate_obligation(&infcx, oblig);
+        }
+
+        if let Err(errors) = infer::drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()) {
+            // no dice!
+            debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \
+                    {:?}",
+                   source_trait_ref,
+                   target_trait_ref,
+                   errors,
+                   infcx.parameter_environment.caller_bounds);
+            Err(())
+        } else {
+            debug!("fulfill_implication: an impl for {:?} specializes {:?}",
+                   source_trait_ref,
+                   target_trait_ref);
+
+            // Now resolve the *substitution* we built for the target earlier, replacing
+            // the inference variables inside with whatever we got from fulfillment.
+            Ok(infcx.resolve_type_vars_if_possible(&target_substs))
+        }
+    })
+}
diff --git a/src/librustc/middle/traits/specialize/specialization_graph.rs b/src/librustc/middle/traits/specialize/specialization_graph.rs
new file mode 100644 (file)
index 0000000..f2170f7
--- /dev/null
@@ -0,0 +1,393 @@
+// 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.
+
+use std::cell;
+use std::rc::Rc;
+
+use super::{Overlap, specializes};
+
+use middle::cstore::CrateStore;
+use middle::def_id::DefId;
+use middle::infer;
+use middle::traits::{self, ProjectionMode};
+use middle::ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable};
+use syntax::ast::Name;
+use util::nodemap::DefIdMap;
+
+/// A per-trait graph of impls in specialization order. At the moment, this
+/// graph forms a tree rooted with the trait itself, with all other nodes
+/// representing impls, and parent-child relationships representing
+/// specializations.
+///
+/// The graph provides two key services:
+///
+/// - Construction, which implicitly checks for overlapping impls (i.e., impls
+///   that overlap but where neither specializes the other -- an artifact of the
+///   simple "chain" rule.
+///
+/// - Parent extraction. In particular, the graph can give you the *immediate*
+///   parents of a given specializing impl, which is needed for extracting
+///   default items amongst other thigns. In the simple "chain" rule, every impl
+///   has at most one parent.
+pub struct Graph {
+    // all impls have a parent; the "root" impls have as their parent the def_id
+    // of the trait
+    parent: DefIdMap<DefId>,
+
+    // the "root" impls are found by looking up the trait's def_id.
+    children: DefIdMap<Vec<DefId>>,
+}
+
+impl Graph {
+    pub fn new() -> Graph {
+        Graph {
+            parent: Default::default(),
+            children: Default::default(),
+        }
+    }
+
+    /// Insert a local impl into the specialization graph. If an existing impl
+    /// conflicts with it (has overlap, but neither specializes the other),
+    /// information about the area of overlap is returned in the `Err`.
+    pub fn insert<'a, 'tcx>(&mut self,
+                            tcx: &'a TyCtxt<'tcx>,
+                            impl_def_id: DefId)
+                            -> Result<(), Overlap<'a, 'tcx>> {
+        assert!(impl_def_id.is_local());
+
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+        let trait_def_id = trait_ref.def_id;
+
+        debug!("insert({:?}): inserting TraitRef {:?} into specialization graph",
+               impl_def_id, trait_ref);
+
+        // if the reference itself contains an earlier error (e.g., due to a
+        // resolution failure), then we just insert the impl at the top level of
+        // the graph and claim that there's no overlap (in order to supress
+        // bogus errors).
+        if trait_ref.references_error() {
+            debug!("insert: inserting dummy node for erroneous TraitRef {:?}, \
+                    impl_def_id={:?}, trait_def_id={:?}",
+                   trait_ref, impl_def_id, trait_def_id);
+
+            self.parent.insert(impl_def_id, trait_def_id);
+            self.children.entry(trait_def_id).or_insert(vec![]).push(impl_def_id);
+            return Ok(());
+        }
+
+        let mut parent = trait_def_id;
+
+        // Ugly hack around borrowck limitations. Assigned only in the case
+        // where we bump downward an existing node in the graph.
+        let child_to_insert;
+
+        'descend: loop {
+            let mut possible_siblings = self.children.entry(parent).or_insert(vec![]);
+
+            for slot in possible_siblings.iter_mut() {
+                let possible_sibling = *slot;
+
+                let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Topmost);
+                let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id);
+
+                if let Some(impl_header) = overlap {
+                    let le = specializes(tcx, impl_def_id, possible_sibling);
+                    let ge = specializes(tcx, possible_sibling, impl_def_id);
+
+                    if le && !ge {
+                        debug!("descending as child of TraitRef {:?}",
+                               tcx.impl_trait_ref(possible_sibling).unwrap());
+
+                        // the impl specializes possible_sibling
+                        parent = possible_sibling;
+                        continue 'descend;
+                    } else if ge && !le {
+                        debug!("placing as parent of TraitRef {:?}",
+                               tcx.impl_trait_ref(possible_sibling).unwrap());
+
+                        // possible_sibling specializes the impl
+                        *slot = impl_def_id;
+                        self.parent.insert(impl_def_id, parent);
+                        self.parent.insert(possible_sibling, impl_def_id);
+                        // we have to defer the insertion, because we can't
+                        // relinquish the borrow of `self.children`
+                        child_to_insert = possible_sibling;
+                        break 'descend;
+                    } else {
+                        // overlap, but no specialization; error out
+                        return Err(Overlap {
+                            with_impl: possible_sibling,
+                            on_trait_ref: impl_header.trait_ref.unwrap(),
+                            in_context: infcx,
+                        });
+                    }
+                }
+            }
+
+            // no overlap with any potential siblings, so add as a new sibling
+            debug!("placing as new sibling");
+            self.parent.insert(impl_def_id, parent);
+            possible_siblings.push(impl_def_id);
+            return Ok(());
+        }
+
+        self.children.insert(impl_def_id, vec![child_to_insert]);
+        Ok(())
+    }
+
+    /// Insert cached metadata mapping from a child impl back to its parent.
+    pub fn record_impl_from_cstore(&mut self, parent: DefId, child: DefId) {
+        if self.parent.insert(child, parent).is_some() {
+            panic!("When recording an impl from the crate store, information about its parent \
+                    was already present.");
+        }
+
+        self.children.entry(parent).or_insert(vec![]).push(child);
+    }
+
+    /// The parent of a given impl, which is the def id of the trait when the
+    /// impl is a "specialization root".
+    pub fn parent(&self, child: DefId) -> DefId {
+        *self.parent.get(&child).unwrap()
+    }
+}
+
+/// A node in the specialization graph is either an impl or a trait
+/// definition; either can serve as a source of item definitions.
+/// There is always exactly one trait definition node: the root.
+#[derive(Debug, Copy, Clone)]
+pub enum Node {
+    Impl(DefId),
+    Trait(DefId),
+}
+
+impl Node {
+    pub fn is_from_trait(&self) -> bool {
+        match *self {
+            Node::Trait(..) => true,
+            _ => false,
+        }
+    }
+
+    /// Iterate over the items defined directly by the given (impl or trait) node.
+    pub fn items<'a, 'tcx>(&self, tcx: &'a TyCtxt<'tcx>) -> NodeItems<'a, 'tcx> {
+        match *self {
+            Node::Impl(impl_def_id) => {
+                NodeItems::Impl {
+                    tcx: tcx,
+                    items: cell::Ref::map(tcx.impl_items.borrow(),
+                                          |impl_items| &impl_items[&impl_def_id]),
+                    idx: 0,
+                }
+            }
+            Node::Trait(trait_def_id) => {
+                NodeItems::Trait {
+                    items: tcx.trait_items(trait_def_id).clone(),
+                    idx: 0,
+                }
+            }
+        }
+    }
+
+    pub fn def_id(&self) -> DefId {
+        match *self {
+            Node::Impl(did) => did,
+            Node::Trait(did) => did,
+        }
+    }
+}
+
+/// An iterator over the items defined within a trait or impl.
+pub enum NodeItems<'a, 'tcx: 'a> {
+    Impl {
+        tcx: &'a TyCtxt<'tcx>,
+        items: cell::Ref<'a, Vec<ty::ImplOrTraitItemId>>,
+        idx: usize,
+    },
+    Trait {
+        items: Rc<Vec<ImplOrTraitItem<'tcx>>>,
+        idx: usize,
+    },
+}
+
+impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> {
+    type Item = ImplOrTraitItem<'tcx>;
+    fn next(&mut self) -> Option<ImplOrTraitItem<'tcx>> {
+        match *self {
+            NodeItems::Impl { tcx, ref items, ref mut idx } => {
+                let items_table = tcx.impl_or_trait_items.borrow();
+                if *idx < items.len() {
+                    let item_def_id = items[*idx].def_id();
+                    let item = items_table[&item_def_id].clone();
+                    *idx += 1;
+                    Some(item)
+                } else {
+                    None
+                }
+            }
+            NodeItems::Trait { ref items, ref mut idx } => {
+                if *idx < items.len() {
+                    let item = items[*idx].clone();
+                    *idx += 1;
+                    Some(item)
+                } else {
+                    None
+                }
+            }
+        }
+    }
+}
+
+pub struct Ancestors<'a, 'tcx: 'a> {
+    trait_def: &'a TraitDef<'tcx>,
+    current_source: Option<Node>,
+}
+
+impl<'a, 'tcx> Iterator for Ancestors<'a, 'tcx> {
+    type Item = Node;
+    fn next(&mut self) -> Option<Node> {
+        let cur = self.current_source.take();
+        if let Some(Node::Impl(cur_impl)) = cur {
+            let parent = self.trait_def.specialization_graph.borrow().parent(cur_impl);
+            if parent == self.trait_def.def_id() {
+                self.current_source = Some(Node::Trait(parent));
+            } else {
+                self.current_source = Some(Node::Impl(parent));
+            }
+        }
+        cur
+    }
+}
+
+pub struct NodeItem<T> {
+    pub node: Node,
+    pub item: T,
+}
+
+impl<T> NodeItem<T> {
+    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
+        NodeItem {
+            node: self.node,
+            item: f(self.item),
+        }
+    }
+}
+
+pub struct TypeDefs<'a, 'tcx: 'a> {
+    // generally only invoked once or twice, so the box doesn't hurt
+    iter: Box<Iterator<Item = NodeItem<Rc<ty::AssociatedType<'tcx>>>> + 'a>,
+}
+
+impl<'a, 'tcx> Iterator for TypeDefs<'a, 'tcx> {
+    type Item = NodeItem<Rc<ty::AssociatedType<'tcx>>>;
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
+
+pub struct FnDefs<'a, 'tcx: 'a> {
+    // generally only invoked once or twice, so the box doesn't hurt
+    iter: Box<Iterator<Item = NodeItem<Rc<ty::Method<'tcx>>>> + 'a>,
+}
+
+impl<'a, 'tcx> Iterator for FnDefs<'a, 'tcx> {
+    type Item = NodeItem<Rc<ty::Method<'tcx>>>;
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
+
+pub struct ConstDefs<'a, 'tcx: 'a> {
+    // generally only invoked once or twice, so the box doesn't hurt
+    iter: Box<Iterator<Item = NodeItem<Rc<ty::AssociatedConst<'tcx>>>> + 'a>,
+}
+
+impl<'a, 'tcx> Iterator for ConstDefs<'a, 'tcx> {
+    type Item = NodeItem<Rc<ty::AssociatedConst<'tcx>>>;
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
+
+impl<'a, 'tcx> Ancestors<'a, 'tcx> {
+    /// Search the items from the given ancestors, returning each type definition
+    /// with the given name.
+    pub fn type_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> TypeDefs<'a, 'tcx> {
+        let iter = self.flat_map(move |node| {
+            node.items(tcx)
+                .filter_map(move |item| {
+                    if let ty::TypeTraitItem(assoc_ty) = item {
+                        if assoc_ty.name == name {
+                            return Some(NodeItem {
+                                node: node,
+                                item: assoc_ty,
+                            });
+                        }
+                    }
+                    None
+                })
+
+        });
+        TypeDefs { iter: Box::new(iter) }
+    }
+
+    /// Search the items from the given ancestors, returning each fn definition
+    /// with the given name.
+    pub fn fn_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> FnDefs<'a, 'tcx> {
+        let iter = self.flat_map(move |node| {
+            node.items(tcx)
+                .filter_map(move |item| {
+                    if let ty::MethodTraitItem(method) = item {
+                        if method.name == name {
+                            return Some(NodeItem {
+                                node: node,
+                                item: method,
+                            });
+                        }
+                    }
+                    None
+                })
+
+        });
+        FnDefs { iter: Box::new(iter) }
+    }
+
+    /// Search the items from the given ancestors, returning each const
+    /// definition with the given name.
+    pub fn const_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> ConstDefs<'a, 'tcx> {
+        let iter = self.flat_map(move |node| {
+            node.items(tcx)
+                .filter_map(move |item| {
+                    if let ty::ConstTraitItem(konst) = item {
+                        if konst.name == name {
+                            return Some(NodeItem {
+                                node: node,
+                                item: konst,
+                            });
+                        }
+                    }
+                    None
+                })
+
+        });
+        ConstDefs { iter: Box::new(iter) }
+    }
+}
+
+/// Walk up the specialization ancestors of a given impl, starting with that
+/// impl itself.
+pub fn ancestors<'a, 'tcx>(trait_def: &'a TraitDef<'tcx>,
+                           start_from_impl: DefId)
+                           -> Ancestors<'a, 'tcx> {
+    Ancestors {
+        trait_def: trait_def,
+        current_source: Some(Node::Impl(start_from_impl)),
+    }
+}
index 08d504143c7cc589782405aa32dc125895f67cb5..1e37600bc0449cacec00743c0963f4926539c23b 100644 (file)
 
 use middle::def_id::DefId;
 use middle::infer::InferCtxt;
-use middle::subst::Substs;
+use middle::subst::{Subst, Substs};
 use middle::ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
 use syntax::codemap::Span;
 use util::common::ErrorReported;
 use util::nodemap::FnvHashSet;
 
-use super::{Obligation, ObligationCause, PredicateObligation};
+use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized};
 
 struct PredicateSet<'a,'tcx:'a> {
     tcx: &'a TyCtxt<'tcx>,
@@ -299,6 +299,38 @@ fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
 // Other
 ///////////////////////////////////////////////////////////////////////////
 
+/// Instantiate all bound parameters of the impl with the given substs,
+/// returning the resulting trait ref and all obligations that arise.
+/// The obligations are closed under normalization.
+pub fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
+                                         impl_def_id: DefId,
+                                         impl_substs: &Substs<'tcx>)
+                                         -> (ty::TraitRef<'tcx>,
+                                             Vec<PredicateObligation<'tcx>>)
+{
+    let impl_trait_ref =
+        selcx.tcx().impl_trait_ref(impl_def_id).unwrap();
+    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);
+
+    let predicates = selcx.tcx().lookup_predicates(impl_def_id);
+    let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
+    let Normalized { value: predicates, obligations: normalization_obligations2 } =
+        super::normalize(selcx, ObligationCause::dummy(), &predicates);
+    let impl_obligations =
+        predicates_for_generics(ObligationCause::dummy(), 0, &predicates);
+
+    let impl_obligations: Vec<_> =
+        impl_obligations.into_iter()
+        .chain(normalization_obligations1)
+        .chain(normalization_obligations2)
+        .collect();
+
+    (impl_trait_ref, impl_obligations)
+}
+
 // determine the `self` type, using fresh variables for all variables
 // declared on the impl declaration e.g., `impl<A,B> for Box<[(A,B)]>`
 // would return ($0, $1) where $0 and $1 are freshly instantiated type
@@ -349,7 +381,6 @@ pub fn trait_ref_for_builtin_bound<'tcx>(
     }
 }
 
-
 pub fn predicate_for_trait_ref<'tcx>(
     cause: ObligationCause<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
index 61a7f49f45d4e7fd267db5be9e68a57633dfac3e..03c13115aea626fc91fc16747cbe1326594619f0 100644 (file)
@@ -342,8 +342,12 @@ pub struct TyCtxt<'tcx> {
     /// FIXME(arielb1): why is this separate from populated_external_types?
     pub populated_external_primitive_impls: RefCell<DefIdSet>,
 
-    /// These caches are used by const_eval when decoding external constants.
-    pub extern_const_statics: RefCell<DefIdMap<NodeId>>,
+    /// Cache used by const_eval when decoding external constants.
+    /// Contains `None` when the constant has been fetched but doesn't exist.
+    /// Constains `Some(expr_id, type)` otherwise.
+    /// `type` is `None` in case it's not a primitive type
+    pub extern_const_statics: RefCell<DefIdMap<Option<(NodeId, Option<Ty<'tcx>>)>>>,
+    /// Cache used by const_eval when decoding extern const fns
     pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
 
     pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
index b54b0b73ef292fd4e92577aaa3142195453371e5..081196835936cbb3a3b1462f6366d3ee62d06dde 100644 (file)
@@ -50,6 +50,8 @@
 use syntax::codemap::{DUMMY_SP, Span};
 use syntax::parse::token::InternedString;
 
+use rustc_const_eval::ConstInt;
+
 use rustc_front::hir;
 use rustc_front::hir::{ItemImpl, ItemTrait, PatKind};
 use rustc_front::intravisit::Visitor;
 mod structural_impls;
 mod sty;
 
-pub type Disr = u64;
-pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
+pub type Disr = ConstInt;
 
 // Data types
 
@@ -280,6 +281,7 @@ pub struct Method<'tcx> {
     pub fty: BareFnTy<'tcx>,
     pub explicit_self: ExplicitSelfCategory,
     pub vis: hir::Visibility,
+    pub defaultness: hir::Defaultness,
     pub def_id: DefId,
     pub container: ImplOrTraitItemContainer,
 }
@@ -291,16 +293,18 @@ pub fn new(name: Name,
                fty: BareFnTy<'tcx>,
                explicit_self: ExplicitSelfCategory,
                vis: hir::Visibility,
+               defaultness: hir::Defaultness,
                def_id: DefId,
                container: ImplOrTraitItemContainer)
                -> Method<'tcx> {
-       Method {
+        Method {
             name: name,
             generics: generics,
             predicates: predicates,
             fty: fty,
             explicit_self: explicit_self,
             vis: vis,
+            defaultness: defaultness,
             def_id: def_id,
             container: container,
         }
@@ -333,6 +337,7 @@ pub struct AssociatedConst<'tcx> {
     pub name: Name,
     pub ty: Ty<'tcx>,
     pub vis: hir::Visibility,
+    pub defaultness: hir::Defaultness,
     pub def_id: DefId,
     pub container: ImplOrTraitItemContainer,
     pub has_value: bool
@@ -343,6 +348,7 @@ pub struct AssociatedType<'tcx> {
     pub name: Name,
     pub ty: Option<Ty<'tcx>>,
     pub vis: hir::Visibility,
+    pub defaultness: hir::Defaultness,
     pub def_id: DefId,
     pub container: ImplOrTraitItemContainer,
 }
@@ -1580,7 +1586,7 @@ pub fn has_dtor(&self) -> bool {
     /// Asserts this is a struct and returns the struct's unique
     /// variant.
     pub fn struct_variant(&self) -> &VariantDefData<'tcx, 'container> {
-        assert!(self.adt_kind() == AdtKind::Struct);
+        assert_eq!(self.adt_kind(), AdtKind::Struct);
         &self.variants[0]
     }
 
@@ -2450,8 +2456,13 @@ pub fn populate_implementations_for_trait_if_necessary(&self, trait_id: DefId) {
         for impl_def_id in self.sess.cstore.implementations_of_trait(trait_id) {
             let impl_items = self.sess.cstore.impl_items(impl_def_id);
             let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
+
             // Record the trait->implementation mapping.
-            def.record_impl(self, impl_def_id, trait_ref);
+            if let Some(parent) = self.sess.cstore.impl_parent(impl_def_id) {
+                def.record_remote_impl(self, impl_def_id, trait_ref, parent);
+            } else {
+                def.record_remote_impl(self, impl_def_id, trait_ref, trait_id);
+            }
 
             // For any methods that use a default implementation, add them to
             // the map. This is a bit unfortunate.
@@ -2659,7 +2670,6 @@ pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
         Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone())
     }
 
-
     pub fn visit_all_items_in_krate<V,F>(&self,
                                          dep_node_fn: F,
                                          visitor: &mut V)
@@ -2667,6 +2677,16 @@ pub fn visit_all_items_in_krate<V,F>(&self,
     {
         dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor);
     }
+    /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
+    /// with the name of the crate containing the impl.
+    pub fn span_of_impl(&self, impl_did: DefId) -> Result<Span, String> {
+        if impl_did.is_local() {
+            let node_id = self.map.as_local_node_id(impl_did).unwrap();
+            Ok(self.map.span(node_id))
+        } else {
+            Err(self.sess.cstore.crate_name(impl_did.krate))
+        }
+    }
 }
 
 /// The category of explicit self.
@@ -2708,28 +2728,4 @@ pub fn with_freevars<T, F>(&self, fid: NodeId, f: F) -> T where
             Some(d) => f(&d[..])
         }
     }
-
-    pub fn make_substs_for_receiver_types(&self,
-                                          trait_ref: &ty::TraitRef<'tcx>,
-                                          method: &ty::Method<'tcx>)
-                                          -> subst::Substs<'tcx>
-    {
-        /*!
-         * Substitutes the values for the receiver's type parameters
-         * that are found in method, leaving the method's type parameters
-         * intact.
-         */
-
-        let meth_tps: Vec<Ty> =
-            method.generics.types.get_slice(subst::FnSpace)
-                  .iter()
-                  .map(|def| self.mk_param_from_def(def))
-                  .collect();
-        let meth_regions: Vec<ty::Region> =
-            method.generics.regions.get_slice(subst::FnSpace)
-                  .iter()
-                  .map(|def| def.to_early_bound_region())
-                  .collect();
-        trait_ref.substs.clone().with_method(meth_tps, meth_regions)
-    }
 }
index 2d7b7dc6e9b58b7662ac6b50fa6dc3e8f6b469f4..bbc5948f2cac71f5eff6c444a3f5aa29868ea8ba 100644 (file)
@@ -1106,6 +1106,13 @@ pub fn is_machine(&self) -> bool {
         }
     }
 
+    pub fn has_concrete_skeleton(&self) -> bool {
+        match self.sty {
+            TyParam(_) | TyInfer(_) | TyError => false,
+            _ => true,
+        }
+    }
+
     // Returns the type and mutability of *ty.
     //
     // The parameter `explicit` indicates if this is an *explicit* dereference.
index 5ecbbbcfbde6dd93d23919090a0f79f0f77dca43..3d7b3bf2634254649f068af19e18b8a00a92da6f 100644 (file)
 
 use dep_graph::DepNode;
 use middle::def_id::DefId;
+use middle::traits::{self, specialization_graph};
 use middle::ty;
 use middle::ty::fast_reject;
-use middle::ty::{Ty, TyCtxt};
+use middle::ty::{Ty, TyCtxt, TraitRef};
 use std::borrow::{Borrow};
 use std::cell::{Cell, Ref, RefCell};
 use syntax::ast::Name;
@@ -59,6 +60,9 @@ pub struct TraitDef<'tcx> {
     /// Blanket impls associated with the trait.
     blanket_impls: RefCell<Vec<DefId>>,
 
+    /// The specialization order for impls of this trait.
+    pub specialization_graph: RefCell<traits::specialization_graph::Graph>,
+
     /// Various flags
     pub flags: Cell<TraitFlags>
 }
@@ -78,7 +82,8 @@ pub fn new(unsafety: hir::Unsafety,
             associated_type_names: associated_type_names,
             nonblanket_impls: RefCell::new(FnvHashMap()),
             blanket_impls: RefCell::new(vec![]),
-            flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS)
+            flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
+            specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
         }
     }
 
@@ -114,11 +119,14 @@ fn read_trait_impls(&self, tcx: &TyCtxt<'tcx>) {
         tcx.dep_graph.read(DepNode::TraitImpls(self.trait_ref.def_id));
     }
 
-    /// Records a trait-to-implementation mapping.
-    pub fn record_impl(&self,
-                       tcx: &TyCtxt<'tcx>,
-                       impl_def_id: DefId,
-                       impl_trait_ref: ty::TraitRef<'tcx>) {
+    /// Records a basic trait-to-implementation mapping.
+    ///
+    /// Returns `true` iff the impl has not previously been recorded.
+    fn record_impl(&self,
+                   tcx: &TyCtxt<'tcx>,
+                   impl_def_id: DefId,
+                   impl_trait_ref: TraitRef<'tcx>)
+                   -> bool {
         debug!("TraitDef::record_impl for {:?}, from {:?}",
                self, impl_trait_ref);
 
@@ -134,22 +142,71 @@ pub fn record_impl(&self,
                                                       impl_trait_ref.self_ty(), false) {
             if let Some(is) = self.nonblanket_impls.borrow().get(&sty) {
                 if is.contains(&impl_def_id) {
-                    return // duplicate - skip
+                    return false; // duplicate - skip
                 }
             }
 
             self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id)
         } else {
             if self.blanket_impls.borrow().contains(&impl_def_id) {
-                return // duplicate - skip
+                return false; // duplicate - skip
             }
             self.blanket_impls.borrow_mut().push(impl_def_id)
         }
+
+        true
     }
 
-    pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: &TyCtxt<'tcx>, mut f: F)  {
-        self.read_trait_impls(tcx);
+    /// Records a trait-to-implementation mapping for a crate-local impl.
+    pub fn record_local_impl(&self,
+                             tcx: &TyCtxt<'tcx>,
+                             impl_def_id: DefId,
+                             impl_trait_ref: TraitRef<'tcx>) {
+        assert!(impl_def_id.is_local());
+        let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref);
+        assert!(was_new);
+    }
+
+    /// Records a trait-to-implementation mapping for a non-local impl.
+    ///
+    /// The `parent_impl` is the immediately-less-specialized impl, or the
+    /// trait's def ID if the impl is is not a specialization -- information that
+    /// should be pulled from the metadata.
+    pub fn record_remote_impl(&self,
+                              tcx: &TyCtxt<'tcx>,
+                              impl_def_id: DefId,
+                              impl_trait_ref: TraitRef<'tcx>,
+                              parent_impl: DefId) {
+        assert!(!impl_def_id.is_local());
+
+        // if the impl has not previously been recorded
+        if self.record_impl(tcx, impl_def_id, impl_trait_ref) {
+            // if the impl is non-local, it's placed directly into the
+            // specialization graph using parent information drawn from metadata.
+            self.specialization_graph.borrow_mut()
+                .record_impl_from_cstore(parent_impl, impl_def_id)
+        }
+    }
+
+    /// Adds a local impl into the specialization graph, returning an error with
+    /// overlap information if the impl overlaps but does not specialize an
+    /// existing impl.
+    pub fn add_impl_for_specialization<'a>(&self,
+                                           tcx: &'a TyCtxt<'tcx>,
+                                           impl_def_id: DefId)
+                                           -> Result<(), traits::Overlap<'a, 'tcx>> {
+        assert!(impl_def_id.is_local());
+
+        self.specialization_graph.borrow_mut()
+            .insert(tcx, impl_def_id)
+    }
 
+    pub fn ancestors<'a>(&'a self, of_impl: DefId) -> specialization_graph::Ancestors<'a, 'tcx> {
+        specialization_graph::ancestors(self, of_impl)
+    }
+
+        pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: &TyCtxt<'tcx>, mut f: F)  {
+            self.read_trait_impls(tcx);
         tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
 
         for &impl_def_id in self.blanket_impls.borrow().iter() {
@@ -223,4 +280,3 @@ pub fn borrow_impl_lists<'s>(&'s self, tcx: &TyCtxt<'tcx>)
         const IMPLS_VALID           = 1 << 3,
     }
 }
-
index 2b83aaccdc46bba7fa554266b9b27864723765ac..5af40a3675ff7c199b7498ed3ca489e9a4b4b699 100644 (file)
 use middle::const_eval::{self, ConstVal, ErrKind};
 use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::def_id::DefId;
-use middle::subst::{self, Subst, Substs};
+use middle::subst;
 use middle::infer;
 use middle::pat_util;
-use middle::traits;
+use middle::traits::{self, ProjectionMode};
 use middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
 use middle::ty::{Disr, ParameterEnvironment};
 use middle::ty::TypeVariants::*;
-use util::num::ToPrimitive;
+
+use rustc_const_eval::{ConstInt, ConstIsize, ConstUsize};
 
 use std::cmp;
 use std::hash::{Hash, SipHasher, Hasher};
-use std::rc::Rc;
 use syntax::ast::{self, Name};
 use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
 use syntax::codemap::Span;
 
 pub trait IntTypeExt {
     fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx>;
-    fn i64_to_disr(&self, val: i64) -> Option<Disr>;
-    fn u64_to_disr(&self, val: u64) -> Option<Disr>;
     fn disr_incr(&self, val: Disr) -> Option<Disr>;
-    fn disr_string(&self, val: Disr) -> String;
-    fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr;
+    fn assert_ty_matches(&self, val: Disr);
+    fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr;
 }
 
 impl IntTypeExt for attr::IntType {
@@ -57,98 +55,48 @@ fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn i64_to_disr(&self, val: i64) -> Option<Disr> {
+    fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr {
         match *self {
-            SignedInt(ast::IntTy::I8)    => val.to_i8()  .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I16)   => val.to_i16() .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I32)   => val.to_i32() .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I64)   => val.to_i64() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U8)  => val.to_u8()  .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U16) => val.to_u16() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U32) => val.to_u32() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U64) => val.to_u64() .map(|v| v as Disr),
-
-            UnsignedInt(ast::UintTy::Us) |
-            SignedInt(ast::IntTy::Is) => unreachable!(),
+            SignedInt(ast::IntTy::I8)    => ConstInt::I8(0),
+            SignedInt(ast::IntTy::I16)   => ConstInt::I16(0),
+            SignedInt(ast::IntTy::I32)   => ConstInt::I32(0),
+            SignedInt(ast::IntTy::I64)   => ConstInt::I64(0),
+            SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type {
+                ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)),
+                ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)),
+                _ => unreachable!(),
+            },
+            UnsignedInt(ast::UintTy::U8)  => ConstInt::U8(0),
+            UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0),
+            UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0),
+            UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0),
+            UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type {
+                ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)),
+                ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)),
+                _ => unreachable!(),
+            },
         }
     }
 
-    fn u64_to_disr(&self, val: u64) -> Option<Disr> {
-        match *self {
-            SignedInt(ast::IntTy::I8)    => val.to_i8()  .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I16)   => val.to_i16() .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I32)   => val.to_i32() .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I64)   => val.to_i64() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U8)  => val.to_u8()  .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U16) => val.to_u16() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U32) => val.to_u32() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U64) => val.to_u64() .map(|v| v as Disr),
-
-            UnsignedInt(ast::UintTy::Us) |
-            SignedInt(ast::IntTy::Is) => unreachable!(),
+    fn assert_ty_matches(&self, val: Disr) {
+        match (*self, val) {
+            (SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
+            (SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
+            (SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
+            (SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
+            (SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
+            (UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
+            (UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
+            (UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
+            (UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
+            (UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
+            _ => panic!("disr type mismatch: {:?} vs {:?}", self, val),
         }
     }
 
     fn disr_incr(&self, val: Disr) -> Option<Disr> {
-        macro_rules! add1 {
-            ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) }
-        }
-        match *self {
-            // SignedInt repr means we *want* to reinterpret the bits
-            // treating the highest bit of Disr as a sign-bit, so
-            // cast to i64 before range-checking.
-            SignedInt(ast::IntTy::I8)    => add1!((val as i64).to_i8()),
-            SignedInt(ast::IntTy::I16)   => add1!((val as i64).to_i16()),
-            SignedInt(ast::IntTy::I32)   => add1!((val as i64).to_i32()),
-            SignedInt(ast::IntTy::I64)   => add1!(Some(val as i64)),
-
-            UnsignedInt(ast::UintTy::U8)  => add1!(val.to_u8()),
-            UnsignedInt(ast::UintTy::U16) => add1!(val.to_u16()),
-            UnsignedInt(ast::UintTy::U32) => add1!(val.to_u32()),
-            UnsignedInt(ast::UintTy::U64) => add1!(Some(val)),
-
-            UnsignedInt(ast::UintTy::Us) |
-            SignedInt(ast::IntTy::Is) => unreachable!(),
-        }
-    }
-
-    // This returns a String because (1.) it is only used for
-    // rendering an error message and (2.) a string can represent the
-    // full range from `i64::MIN` through `u64::MAX`.
-    fn disr_string(&self, val: Disr) -> String {
-        match *self {
-            SignedInt(ast::IntTy::I8)    => format!("{}", val as i8 ),
-            SignedInt(ast::IntTy::I16)   => format!("{}", val as i16),
-            SignedInt(ast::IntTy::I32)   => format!("{}", val as i32),
-            SignedInt(ast::IntTy::I64)   => format!("{}", val as i64),
-            UnsignedInt(ast::UintTy::U8)  => format!("{}", val as u8 ),
-            UnsignedInt(ast::UintTy::U16) => format!("{}", val as u16),
-            UnsignedInt(ast::UintTy::U32) => format!("{}", val as u32),
-            UnsignedInt(ast::UintTy::U64) => format!("{}", val as u64),
-
-            UnsignedInt(ast::UintTy::Us) |
-            SignedInt(ast::IntTy::Is) => unreachable!(),
-        }
-    }
-
-    fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr {
-        macro_rules! add1 {
-            ($e:expr) => { ($e).wrapping_add(1) as Disr }
-        }
-        let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE);
-        match *self {
-            SignedInt(ast::IntTy::I8)    => add1!(val as i8 ),
-            SignedInt(ast::IntTy::I16)   => add1!(val as i16),
-            SignedInt(ast::IntTy::I32)   => add1!(val as i32),
-            SignedInt(ast::IntTy::I64)   => add1!(val as i64),
-            UnsignedInt(ast::UintTy::U8)  => add1!(val as u8 ),
-            UnsignedInt(ast::UintTy::U16) => add1!(val as u16),
-            UnsignedInt(ast::UintTy::U32) => add1!(val as u32),
-            UnsignedInt(ast::UintTy::U64) => add1!(val as u64),
-
-            UnsignedInt(ast::UintTy::Us) |
-            SignedInt(ast::IntTy::Is) => unreachable!(),
-        }
+        self.assert_ty_matches(val);
+        (val + ConstInt::Infer(1)).ok()
     }
 }
 
@@ -182,7 +130,10 @@ pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span)
         let tcx = self.tcx;
 
         // FIXME: (@jroesch) float this code up
-        let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()));
+        let infcx = infer::new_infer_ctxt(tcx,
+                                          &tcx.tables,
+                                          Some(self.clone()),
+                                          ProjectionMode::AnyFinal);
 
         let adt = match self_type.sty {
             ty::TyStruct(struct_def, substs) => {
@@ -266,13 +217,11 @@ pub fn named_element_ty(&self,
         }
     }
 
-    /// Returns `(normalized_type, ty)`, where `normalized_type` is the
-    /// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8},
-    /// and `ty` is the original type (i.e. may include `isize` or
-    /// `usize`).
-    pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>)
-                          -> (attr::IntType, Ty<'tcx>) {
-        let repr_type = match opt_hint {
+    /// Returns the IntType representation.
+    /// This used to ensure `int_ty` doesn't contain `usize` and `isize`
+    /// by converting them to their actual types. That doesn't happen anymore.
+    pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
+        match opt_hint {
             // Feed in the given type
             Some(&attr::ReprInt(_, int_t)) => int_t,
             // ... but provide sensible default if none provided
@@ -280,18 +229,7 @@ pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>)
             // NB. Historically `fn enum_variants` generate i64 here, while
             // rustc_typeck::check would generate isize.
             _ => SignedInt(ast::IntTy::Is),
-        };
-
-        let repr_type_ty = repr_type.to_ty(self);
-        let repr_type = match repr_type {
-            SignedInt(ast::IntTy::Is) =>
-                SignedInt(self.sess.target.int_type),
-            UnsignedInt(ast::UintTy::Us) =>
-                UnsignedInt(self.sess.target.uint_type),
-            other => other
-        };
-
-        (repr_type, repr_type_ty)
+        }
     }
 
     /// Returns the deeply last field of nested structures, or the same type,
@@ -335,15 +273,16 @@ pub fn struct_lockstep_tails(&self,
     pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
         let hint = UncheckedExprHint(self.types.usize);
         match const_eval::eval_const_expr_partial(self, count_expr, hint, None) {
-            Ok(val) => {
-                let found = match val {
-                    ConstVal::Uint(count) => return count as usize,
-                    ConstVal::Int(count) if count >= 0 => return count as usize,
-                    const_val => const_val.description(),
-                };
+            Ok(ConstVal::Integral(ConstInt::Usize(count))) => {
+                let val = count.as_u64(self.sess.target.uint_type);
+                assert_eq!(val as usize as u64, val);
+                val as usize
+            },
+            Ok(const_val) => {
                 span_err!(self.sess, count_expr.span, E0306,
-                    "expected positive integer for repeat count, found {}",
-                    found);
+                          "expected positive integer for repeat count, found {}",
+                          const_val.description());
+                0
             }
             Err(err) => {
                 let err_msg = match count_expr.node {
@@ -360,9 +299,9 @@ pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
                 };
                 span_err!(self.sess, count_expr.span, E0307,
                     "expected constant integer for repeat count, {}", err_msg);
+                0
             }
         }
-        0
     }
 
     /// Given a set of predicates that apply to an object type, returns
@@ -599,58 +538,6 @@ pub fn is_adt_dtorck(&self, adt: ty::AdtDef<'tcx>) -> bool {
     }
 }
 
-#[derive(Debug)]
-pub struct ImplMethod<'tcx> {
-    pub method: Rc<ty::Method<'tcx>>,
-    pub substs: &'tcx Substs<'tcx>,
-    pub is_provided: bool
-}
-
-impl<'tcx> TyCtxt<'tcx> {
-    pub fn get_impl_method(&self,
-                           impl_def_id: DefId,
-                           substs: &'tcx Substs<'tcx>,
-                           name: Name)
-                           -> ImplMethod<'tcx>
-    {
-        // there don't seem to be nicer accessors to these:
-        let impl_or_trait_items_map = self.impl_or_trait_items.borrow();
-
-        for impl_item in &self.impl_items.borrow()[&impl_def_id] {
-            if let ty::MethodTraitItem(ref meth) =
-                impl_or_trait_items_map[&impl_item.def_id()] {
-                if meth.name == name {
-                    return ImplMethod {
-                        method: meth.clone(),
-                        substs: substs,
-                        is_provided: false
-                    }
-                }
-            }
-        }
-
-        // It is not in the impl - get the default from the trait.
-        let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
-        for trait_item in self.trait_items(trait_ref.def_id).iter() {
-            if let &ty::MethodTraitItem(ref meth) = trait_item {
-                if meth.name == name {
-                    let impl_to_trait_substs = self
-                        .make_substs_for_receiver_types(&trait_ref, meth);
-                    let substs = impl_to_trait_substs.subst(self, substs);
-                    return ImplMethod {
-                        method: meth.clone(),
-                        substs: self.mk_substs(substs),
-                        is_provided: true
-                    }
-                }
-            }
-        }
-
-        self.sess.bug(&format!("method {:?} not found in {:?}",
-                               name, impl_def_id))
-    }
-}
-
 impl<'tcx> ty::TyS<'tcx> {
     fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
                        bound: ty::BuiltinBound,
@@ -658,7 +545,10 @@ fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
                        -> bool
     {
         let tcx = param_env.tcx;
-        let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()));
+        let infcx = infer::new_infer_ctxt(tcx,
+                                          &tcx.tables,
+                                          Some(param_env.clone()),
+                                          ProjectionMode::AnyFinal);
 
         let is_impld = traits::type_known_to_meet_builtin_bound(&infcx,
                                                                 self, bound, span);
index 127cc96859a808f97766e6cd46160901d97602a8..11bb381ec33bb756790480e56ac1b55b5319fbe5 100644 (file)
@@ -10,6 +10,7 @@
 
 use graphviz::IntoCow;
 use middle::const_eval::ConstVal;
+use rustc_const_eval::{ConstUsize, ConstInt};
 use middle::def_id::DefId;
 use middle::subst::Substs;
 use middle::ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
@@ -851,13 +852,12 @@ pub struct Constant<'tcx> {
 pub struct TypedConstVal<'tcx> {
     pub ty: Ty<'tcx>,
     pub span: Span,
-    pub value: ConstVal
+    pub value: ConstUsize,
 }
 
 impl<'tcx> Debug for TypedConstVal<'tcx> {
     fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
-        try!(write!(fmt, "const "));
-        fmt_const_val(fmt, &self.value)
+        write!(fmt, "const {}", ConstInt::Usize(self.value))
     }
 }
 
@@ -897,8 +897,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
     use middle::const_eval::ConstVal::*;
     match *const_val {
         Float(f) => write!(fmt, "{:?}", f),
-        Int(n) => write!(fmt, "{:?}", n),
-        Uint(n) => write!(fmt, "{:?}", n),
+        Integral(n) => write!(fmt, "{}", n),
         Str(ref s) => write!(fmt, "{:?}", s),
         ByteStr(ref bytes) => {
             let escaped: String = bytes
@@ -911,6 +910,8 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
         Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
         Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
             write!(fmt, "{}", node_to_string(node_id)),
+        Char(c) => write!(fmt, "{:?}", c),
+        Dummy => unreachable!(),
     }
 }
 
index 26f6db4aa4fc17b9549842b0ea74bbeae19d9124..b6b2694a7cbe1c2d3d53f4e8f148930a683794c3 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 use mir::repr::*;
-use middle::const_eval::ConstVal;
 use middle::subst::{Subst, Substs};
 use middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_front::hir;
@@ -144,12 +143,10 @@ pub fn rvalue_ty(&self,
         match *rvalue {
             Rvalue::Use(ref operand) => Some(self.operand_ty(tcx, operand)),
             Rvalue::Repeat(ref operand, ref count) => {
-                if let ConstVal::Uint(u) = count.value {
-                    let op_ty = self.operand_ty(tcx, operand);
-                    Some(tcx.mk_array(op_ty, u as usize))
-                } else {
-                    None
-                }
+                let op_ty = self.operand_ty(tcx, operand);
+                let count = count.value.as_u64(tcx.sess.target.uint_type);
+                assert_eq!(count as usize as u64, count);
+                Some(tcx.mk_array(op_ty, count as usize))
             }
             Rvalue::Ref(reg, bk, ref lv) => {
                 let lv_ty = self.lvalue_ty(tcx, lv).to_ty(tcx);
index dba0bcf19be1362b908f2fc6a38b75fd899c8b75..9f097215a8ac5254ace403e67a8f8e9f1fc4a4a7 100644 (file)
@@ -172,8 +172,12 @@ pub enum PrintRequest {
 pub enum Input {
     /// Load source from file
     File(PathBuf),
-    /// The string is the source
-    Str(String)
+    Str {
+        /// String that is shown in place of a filename
+        name: String,
+        /// Anonymous source string
+        input: String,
+    },
 }
 
 impl Input {
@@ -181,7 +185,7 @@ pub fn filestem(&self) -> String {
         match *self {
             Input::File(ref ifile) => ifile.file_stem().unwrap()
                                            .to_str().unwrap().to_string(),
-            Input::Str(_) => "rust_out".to_string(),
+            Input::Str { .. } => "rust_out".to_string(),
         }
     }
 }
index 4a1c115e65599cde3f34e0bd158d3ec4c43466fa..9186765e6d02c0c49f9cf0f84dd7cc45a551e865 100644 (file)
@@ -27,6 +27,7 @@
 use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::region;
 use rustc::middle::ty::{self, TyCtxt};
+use rustc::middle::traits::ProjectionMode;
 use syntax::ast;
 use syntax::codemap::Span;
 use rustc_front::hir;
@@ -202,7 +203,10 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     debug!("check_loans(body id={})", body.id);
 
     let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
-    let infcx = infer::new_infer_ctxt(bccx.tcx, &bccx.tcx.tables, Some(param_env));
+    let infcx = infer::new_infer_ctxt(bccx.tcx,
+                                      &bccx.tcx.tables,
+                                      Some(param_env),
+                                      ProjectionMode::AnyFinal);
 
     let mut clcx = CheckLoanCtxt {
         bccx: bccx,
index e2543b289103a6d66e7656a979955e36cf3b9d1a..2d255c054548f42e8c0a6e06710d5b4ea8f8433a 100644 (file)
@@ -24,6 +24,7 @@
 use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::region;
 use rustc::middle::ty::{self, TyCtxt};
+use rustc::middle::traits::ProjectionMode;
 
 use syntax::ast;
 use syntax::codemap::Span;
@@ -55,7 +56,10 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     };
 
     let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
-    let infcx = infer::new_infer_ctxt(bccx.tcx, &bccx.tcx.tables, Some(param_env));
+    let infcx = infer::new_infer_ctxt(bccx.tcx,
+                                      &bccx.tcx.tables,
+                                      Some(param_env),
+                                      ProjectionMode::AnyFinal);
     {
         let mut euv = euv::ExprUseVisitor::new(&mut glcx, &infcx);
         euv.walk_fn(decl, body);
@@ -525,7 +529,10 @@ struct StaticInitializerCtxt<'a, 'tcx: 'a> {
 impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
     fn visit_expr(&mut self, ex: &Expr) {
         if let hir::ExprAddrOf(mutbl, ref base) = ex.node {
-            let infcx = infer::new_infer_ctxt(self.bccx.tcx, &self.bccx.tcx.tables, None);
+            let infcx = infer::new_infer_ctxt(self.bccx.tcx,
+                                              &self.bccx.tcx.tables,
+                                              None,
+                                              ProjectionMode::AnyFinal);
             let mc = mc::MemCategorizationContext::new(&infcx);
             let base_cmt = mc.cat_expr(&base).unwrap();
             let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml
new file mode 100644 (file)
index 0000000..f885e9a
--- /dev/null
@@ -0,0 +1,14 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_const_eval"
+version = "0.0.0"
+
+[lib]
+name = "rustc_const_eval"
+path = "lib.rs"
+crate-type = ["dylib"]
+
+[dependencies]
+log = { path = "../liblog" }
+serialize = { path = "../libserialize" }
+syntax = { path = "../libsyntax" }
diff --git a/src/librustc_const_eval/err.rs b/src/librustc_const_eval/err.rs
new file mode 100644 (file)
index 0000000..126b382
--- /dev/null
@@ -0,0 +1,85 @@
+// 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 syntax::ast;
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum ConstMathErr {
+    NotInRange,
+    CmpBetweenUnequalTypes,
+    UnequalTypes(Op),
+    Overflow(Op),
+    ShiftNegative,
+    DivisionByZero,
+    RemainderByZero,
+    UnsignedNegation,
+    ULitOutOfRange(ast::UintTy),
+    LitOutOfRange(ast::IntTy),
+}
+pub use self::ConstMathErr::*;
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum Op {
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Rem,
+    Shr,
+    Shl,
+    Neg,
+    BitAnd,
+    BitOr,
+    BitXor,
+}
+
+impl ConstMathErr {
+    pub fn description(&self) -> &'static str {
+        use self::Op::*;
+        match *self {
+            NotInRange => "inferred value out of range",
+            CmpBetweenUnequalTypes => "compared two integrals of different types",
+            UnequalTypes(Add) => "tried to add two integrals of different types",
+            UnequalTypes(Sub) => "tried to subtract two integrals of different types",
+            UnequalTypes(Mul) => "tried to multiply two integrals of different types",
+            UnequalTypes(Div) => "tried to divide two integrals of different types",
+            UnequalTypes(Rem) => {
+                "tried to calculate the remainder of two integrals of different types"
+            },
+            UnequalTypes(BitAnd) => "tried to bitand two integrals of different types",
+            UnequalTypes(BitOr) => "tried to bitor two integrals of different types",
+            UnequalTypes(BitXor) => "tried to xor two integrals of different types",
+            UnequalTypes(_) => unreachable!(),
+            Overflow(Add) => "attempted to add with overflow",
+            Overflow(Sub) => "attempted to subtract with overflow",
+            Overflow(Mul) => "attempted to multiply with overflow",
+            Overflow(Div) => "attempted to divide with overflow",
+            Overflow(Rem) => "attempted to calculate the remainder with overflow",
+            Overflow(Neg) => "attempted to negate with overflow",
+            Overflow(Shr) => "attempted to shift right with overflow",
+            Overflow(Shl) => "attempted to shift left with overflow",
+            Overflow(_) => unreachable!(),
+            ShiftNegative => "attempted to shift by a negative amount",
+            DivisionByZero => "attempted to divide by zero",
+            RemainderByZero => "attempted to calculate the remainder with a divisor of zero",
+            UnsignedNegation => "unary negation of unsigned integer",
+            ULitOutOfRange(ast::UintTy::U8) => "literal out of range for u8",
+            ULitOutOfRange(ast::UintTy::U16) => "literal out of range for u16",
+            ULitOutOfRange(ast::UintTy::U32) => "literal out of range for u32",
+            ULitOutOfRange(ast::UintTy::U64) => "literal out of range for u64",
+            ULitOutOfRange(ast::UintTy::Us) => "literal out of range for usize",
+            LitOutOfRange(ast::IntTy::I8) => "literal out of range for i8",
+            LitOutOfRange(ast::IntTy::I16) => "literal out of range for i16",
+            LitOutOfRange(ast::IntTy::I32) => "literal out of range for i32",
+            LitOutOfRange(ast::IntTy::I64) => "literal out of range for i64",
+            LitOutOfRange(ast::IntTy::Is) => "literal out of range for isize",
+        }
+    }
+}
diff --git a/src/librustc_const_eval/int.rs b/src/librustc_const_eval/int.rs
new file mode 100644 (file)
index 0000000..1525398
--- /dev/null
@@ -0,0 +1,569 @@
+// 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::cmp::Ordering;
+use syntax::attr::IntType;
+use syntax::ast::{IntTy, UintTy};
+
+use super::is::*;
+use super::us::*;
+use super::err::*;
+
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
+pub enum ConstInt {
+    I8(i8),
+    I16(i16),
+    I32(i32),
+    I64(i64),
+    Isize(ConstIsize),
+    U8(u8),
+    U16(u16),
+    U32(u32),
+    U64(u64),
+    Usize(ConstUsize),
+    Infer(u64),
+    InferSigned(i64),
+}
+pub use self::ConstInt::*;
+
+
+macro_rules! bounds {
+    ($($t:ident $min:ident $max:ident)*) => {
+        mod as_u64 {
+            $(
+                #[allow(dead_code)]
+                pub const $min: u64 = ::std::$t::MIN as u64;
+                #[allow(dead_code)]
+                pub const $max: u64 = ::std::$t::MAX as u64;
+            )*
+        }
+        mod as_i64 {
+            $(
+                #[allow(dead_code)]
+                pub const $min: i64 = ::std::$t::MIN as i64;
+                #[allow(dead_code)]
+                pub const $max: i64 = ::std::$t::MAX as i64;
+            )*
+        }
+    }
+}
+
+bounds!{
+    i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX isize IMIN IMAX
+    u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX usize UMIN UMAX
+}
+
+impl ConstInt {
+    /// If either value is `Infer` or `InferSigned`, try to turn the value into the type of
+    /// the other value. If both values have no type, don't do anything
+    pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> {
+        let inferred = match (self, other) {
+            (InferSigned(_), InferSigned(_))
+            | (Infer(_), Infer(_)) => self, // no inference possible
+            // kindof wrong, you could have had values > I64MAX during computation of a
+            (Infer(a @ 0...as_u64::I64MAX), InferSigned(_)) => InferSigned(a as i64),
+            (Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange),
+            (_, InferSigned(_))
+            | (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)),
+
+            (Infer(a @ 0...as_u64::I8MAX), I8(_)) => I8(a as i64 as i8),
+            (Infer(a @ 0...as_u64::I16MAX), I16(_)) => I16(a as i64 as i16),
+            (Infer(a @ 0...as_u64::I32MAX), I32(_)) => I32(a as i64 as i32),
+            (Infer(a @ 0...as_u64::I64MAX), I64(_)) => I64(a as i64),
+            (Infer(a @ 0...as_u64::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)),
+            (Infer(a @ 0...as_u64::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)),
+            (Infer(a @ 0...as_u64::U8MAX), U8(_)) => U8(a as u8),
+            (Infer(a @ 0...as_u64::U16MAX), U16(_)) => U16(a as u16),
+            (Infer(a @ 0...as_u64::U32MAX), U32(_)) => U32(a as u32),
+            (Infer(a), U64(_)) => U64(a),
+            (Infer(a @ 0...as_u64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
+            (Infer(a), Usize(Us64(_))) => Usize(Us64(a)),
+
+            (Infer(_), _) => return Err(ConstMathErr::NotInRange),
+
+            (InferSigned(a @ as_i64::I8MIN...as_i64::I8MAX), I8(_)) => I8(a as i8),
+            (InferSigned(a @ as_i64::I16MIN...as_i64::I16MAX), I16(_)) => I16(a as i16),
+            (InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), I32(_)) => I32(a as i32),
+            (InferSigned(a), I64(_)) => I64(a),
+            (InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), Isize(Is32(_))) => {
+                Isize(Is32(a as i32))
+            },
+            (InferSigned(a), Isize(Is64(_))) => Isize(Is64(a)),
+            (InferSigned(a @ 0...as_i64::U8MAX), U8(_)) => U8(a as u8),
+            (InferSigned(a @ 0...as_i64::U16MAX), U16(_)) => U16(a as u16),
+            (InferSigned(a @ 0...as_i64::U32MAX), U32(_)) => U32(a as u32),
+            (InferSigned(a @ 0...as_i64::I64MAX), U64(_)) => U64(a as u64),
+            (InferSigned(a @ 0...as_i64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
+            (InferSigned(a @ 0...as_i64::I64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
+            (InferSigned(_), _) => return Err(ConstMathErr::NotInRange),
+            _ => self, // already known types
+        };
+        Ok((inferred, other))
+    }
+
+    /// Turn this value into an `Infer` or an `InferSigned`
+    pub fn erase_type(self) -> Self {
+        match self {
+            Infer(i) => Infer(i),
+            InferSigned(i) if i < 0 => InferSigned(i),
+            I8(i) if i < 0 => InferSigned(i as i64),
+            I16(i) if i < 0 => InferSigned(i as i64),
+            I32(i) if i < 0 => InferSigned(i as i64),
+            I64(i) if i < 0 => InferSigned(i as i64),
+            Isize(Is32(i)) if i < 0 => InferSigned(i as i64),
+            Isize(Is64(i)) if i < 0 => InferSigned(i as i64),
+            InferSigned(i) => Infer(i as u64),
+            I8(i) => Infer(i as u64),
+            I16(i) => Infer(i as u64),
+            I32(i) => Infer(i as u64),
+            I64(i) => Infer(i as u64),
+            Isize(Is32(i)) => Infer(i as u64),
+            Isize(Is64(i)) => Infer(i as u64),
+            U8(i) => Infer(i as u64),
+            U16(i) => Infer(i as u64),
+            U32(i) => Infer(i as u64),
+            U64(i) => Infer(i as u64),
+            Usize(Us32(i)) => Infer(i as u64),
+            Usize(Us64(i)) => Infer(i),
+        }
+    }
+
+    /// Description of the type, not the value
+    pub fn description(&self) -> &'static str {
+        match *self {
+            Infer(_) => "not yet inferred integral",
+            InferSigned(_) => "not yet inferred signed integral",
+            I8(_) => "i8",
+            I16(_) => "i16",
+            I32(_) => "i32",
+            I64(_) => "i64",
+            Isize(_) => "isize",
+            U8(_) => "u8",
+            U16(_) => "u16",
+            U32(_) => "u32",
+            U64(_) => "u64",
+            Usize(_) => "usize",
+        }
+    }
+
+    /// Erases the type and returns a u64.
+    /// This is not the same as `-5i8 as u64` but as `-5i8 as i64 as u64`
+    pub fn to_u64_unchecked(self) -> u64 {
+        match self.erase_type() {
+            ConstInt::Infer(i) => i,
+            ConstInt::InferSigned(i) => i as u64,
+            _ => unreachable!(),
+        }
+    }
+
+    /// Converts the value to a `u32` if it's in the range 0...std::u32::MAX
+    pub fn to_u32(&self) -> Option<u32> {
+        match *self {
+            I8(v) if v >= 0 => Some(v as u32),
+            I16(v) if v >= 0 => Some(v as u32),
+            I32(v) if v >= 0 => Some(v as u32),
+            InferSigned(v)
+            | Isize(Is64(v))
+            | I64(v) if v >= 0 && v <= ::std::u32::MAX as i64 => Some(v as u32),
+            Isize(Is32(v)) if v >= 0 => Some(v as u32),
+            U8(v) => Some(v as u32),
+            U16(v) => Some(v as u32),
+            U32(v) => Some(v),
+            Infer(v)
+            | Usize(Us64(v))
+            | U64(v) if v <= ::std::u32::MAX as u64 => Some(v as u32),
+            Usize(Us32(v)) => Some(v),
+            _ => None,
+        }
+    }
+
+    /// Converts the value to a `u64` if it's >= 0
+    pub fn to_u64(&self) -> Option<u64> {
+        match *self {
+            Infer(v) => Some(v),
+            InferSigned(v) if v >= 0 => Some(v as u64),
+            I8(v) if v >= 0 => Some(v as u64),
+            I16(v) if v >= 0 => Some(v as u64),
+            I32(v) if v >= 0 => Some(v as u64),
+            I64(v) if v >= 0 => Some(v as u64),
+            Isize(Is32(v)) if v >= 0 => Some(v as u64),
+            Isize(Is64(v)) if v >= 0 => Some(v as u64),
+            U8(v) => Some(v as u64),
+            U16(v) => Some(v as u64),
+            U32(v) => Some(v as u64),
+            U64(v) => Some(v),
+            Usize(Us32(v)) => Some(v as u64),
+            Usize(Us64(v)) => Some(v),
+            _ => None,
+        }
+    }
+
+    pub fn is_negative(&self) -> bool {
+        match *self {
+            I8(v) => v < 0,
+            I16(v) => v < 0,
+            I32(v) => v < 0,
+            I64(v) => v < 0,
+            Isize(Is32(v)) => v < 0,
+            Isize(Is64(v)) => v < 0,
+            InferSigned(v) => v < 0,
+            _ => false,
+        }
+    }
+
+    /// Compares the values if they are of the same type
+    pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
+        match try!(self.infer(rhs)) {
+            (I8(a), I8(b)) => Ok(a.cmp(&b)),
+            (I16(a), I16(b)) => Ok(a.cmp(&b)),
+            (I32(a), I32(b)) => Ok(a.cmp(&b)),
+            (I64(a), I64(b)) => Ok(a.cmp(&b)),
+            (Isize(Is32(a)), Isize(Is32(b))) => Ok(a.cmp(&b)),
+            (Isize(Is64(a)), Isize(Is64(b))) => Ok(a.cmp(&b)),
+            (U8(a), U8(b)) => Ok(a.cmp(&b)),
+            (U16(a), U16(b)) => Ok(a.cmp(&b)),
+            (U32(a), U32(b)) => Ok(a.cmp(&b)),
+            (U64(a), U64(b)) => Ok(a.cmp(&b)),
+            (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
+            (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
+            (Infer(a), Infer(b)) => Ok(a.cmp(&b)),
+            (InferSigned(a), InferSigned(b)) => Ok(a.cmp(&b)),
+            _ => Err(CmpBetweenUnequalTypes),
+        }
+    }
+
+    /// Adds 1 to the value and wraps around if the maximum for the type is reached
+    pub fn wrap_incr(self) -> Self {
+        macro_rules! add1 {
+            ($e:expr) => { ($e).wrapping_add(1) }
+        }
+        match self {
+            ConstInt::I8(i) => ConstInt::I8(add1!(i)),
+            ConstInt::I16(i) => ConstInt::I16(add1!(i)),
+            ConstInt::I32(i) => ConstInt::I32(add1!(i)),
+            ConstInt::I64(i) => ConstInt::I64(add1!(i)),
+            ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))),
+            ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))),
+            ConstInt::U8(i) => ConstInt::U8(add1!(i)),
+            ConstInt::U16(i) => ConstInt::U16(add1!(i)),
+            ConstInt::U32(i) => ConstInt::U32(add1!(i)),
+            ConstInt::U64(i) => ConstInt::U64(add1!(i)),
+            ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
+            ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
+            ConstInt::Infer(_) | ConstInt::InferSigned(_) => panic!("no type info for const int"),
+        }
+    }
+
+    pub fn int_type(self) -> Option<IntType> {
+        match self {
+            ConstInt::I8(_) => Some(IntType::SignedInt(IntTy::I8)),
+            ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)),
+            ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)),
+            ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)),
+            ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)),
+            ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)),
+            ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)),
+            ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)),
+            ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)),
+            ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)),
+            _ => None,
+        }
+    }
+}
+
+impl ::std::cmp::PartialOrd for ConstInt {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.try_cmp(*other).ok()
+    }
+}
+
+impl ::std::cmp::Ord for ConstInt {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.try_cmp(*other).unwrap()
+    }
+}
+
+impl ::std::fmt::Display for ConstInt {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
+        match *self {
+            Infer(i) => write!(fmt, "{}", i),
+            InferSigned(i) => write!(fmt, "{}", i),
+            I8(i) => write!(fmt, "{}i8", i),
+            I16(i) => write!(fmt, "{}i16", i),
+            I32(i) => write!(fmt, "{}i32", i),
+            I64(i) => write!(fmt, "{}i64", i),
+            Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i),
+            Isize(ConstIsize::Is32(i)) => write!(fmt, "{}isize", i),
+            U8(i) => write!(fmt, "{}u8", i),
+            U16(i) => write!(fmt, "{}u16", i),
+            U32(i) => write!(fmt, "{}u32", i),
+            U64(i) => write!(fmt, "{}u64", i),
+            Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i),
+            Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i),
+        }
+    }
+}
+
+macro_rules! overflowing {
+    ($e:expr, $err:expr) => {{
+        if $e.1 {
+            return Err(Overflow($err));
+        } else {
+            $e.0
+        }
+    }}
+}
+
+macro_rules! impl_binop {
+    ($op:ident, $func:ident, $checked_func:ident) => {
+        impl ::std::ops::$op for ConstInt {
+            type Output = Result<Self, ConstMathErr>;
+            fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
+                match try!(self.infer(rhs)) {
+                    (I8(a), I8(b)) => a.$checked_func(b).map(I8),
+                    (I16(a), I16(b)) => a.$checked_func(b).map(I16),
+                    (I32(a), I32(b)) => a.$checked_func(b).map(I32),
+                    (I64(a), I64(b)) => a.$checked_func(b).map(I64),
+                    (Isize(Is32(a)), Isize(Is32(b))) => a.$checked_func(b).map(Is32).map(Isize),
+                    (Isize(Is64(a)), Isize(Is64(b))) => a.$checked_func(b).map(Is64).map(Isize),
+                    (U8(a), U8(b)) => a.$checked_func(b).map(U8),
+                    (U16(a), U16(b)) => a.$checked_func(b).map(U16),
+                    (U32(a), U32(b)) => a.$checked_func(b).map(U32),
+                    (U64(a), U64(b)) => a.$checked_func(b).map(U64),
+                    (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
+                    (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
+                    (Infer(a), Infer(b)) => a.$checked_func(b).map(Infer),
+                    (InferSigned(a), InferSigned(b)) => a.$checked_func(b).map(InferSigned),
+                    _ => return Err(UnequalTypes(Op::$op)),
+                }.ok_or(Overflow(Op::$op))
+            }
+        }
+    }
+}
+
+macro_rules! derive_binop {
+    ($op:ident, $func:ident) => {
+        impl ::std::ops::$op for ConstInt {
+            type Output = Result<Self, ConstMathErr>;
+            fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
+                match try!(self.infer(rhs)) {
+                    (I8(a), I8(b)) => Ok(I8(a.$func(b))),
+                    (I16(a), I16(b)) => Ok(I16(a.$func(b))),
+                    (I32(a), I32(b)) => Ok(I32(a.$func(b))),
+                    (I64(a), I64(b)) => Ok(I64(a.$func(b))),
+                    (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a.$func(b)))),
+                    (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a.$func(b)))),
+                    (U8(a), U8(b)) => Ok(U8(a.$func(b))),
+                    (U16(a), U16(b)) => Ok(U16(a.$func(b))),
+                    (U32(a), U32(b)) => Ok(U32(a.$func(b))),
+                    (U64(a), U64(b)) => Ok(U64(a.$func(b))),
+                    (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
+                    (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
+                    (Infer(a), Infer(b)) => Ok(Infer(a.$func(b))),
+                    (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a.$func(b))),
+                    _ => Err(UnequalTypes(Op::$op)),
+                }
+            }
+        }
+    }
+}
+
+impl_binop!(Add, add, checked_add);
+impl_binop!(Sub, sub, checked_sub);
+impl_binop!(Mul, mul, checked_mul);
+derive_binop!(BitAnd, bitand);
+derive_binop!(BitOr, bitor);
+derive_binop!(BitXor, bitxor);
+
+fn check_division(
+    lhs: ConstInt,
+    rhs: ConstInt,
+    op: Op,
+    zerr: ConstMathErr,
+) -> Result<(), ConstMathErr> {
+    match (lhs, rhs) {
+        (I8(_), I8(0)) => Err(zerr),
+        (I16(_), I16(0)) => Err(zerr),
+        (I32(_), I32(0)) => Err(zerr),
+        (I64(_), I64(0)) => Err(zerr),
+        (Isize(_), Isize(Is32(0))) => Err(zerr),
+        (Isize(_), Isize(Is64(0))) => Err(zerr),
+        (InferSigned(_), InferSigned(0)) => Err(zerr),
+
+        (U8(_), U8(0)) => Err(zerr),
+        (U16(_), U16(0)) => Err(zerr),
+        (U32(_), U32(0)) => Err(zerr),
+        (U64(_), U64(0)) => Err(zerr),
+        (Usize(_), Usize(Us32(0))) => Err(zerr),
+        (Usize(_), Usize(Us64(0))) => Err(zerr),
+        (Infer(_), Infer(0)) => Err(zerr),
+
+        (I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
+        (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
+        (I32(::std::i32::MIN), I32(-1)) => Err(Overflow(op)),
+        (I64(::std::i64::MIN), I64(-1)) => Err(Overflow(op)),
+        (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
+        (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
+        (InferSigned(::std::i64::MIN), InferSigned(-1)) => Err(Overflow(op)),
+
+        _ => Ok(()),
+    }
+}
+
+impl ::std::ops::Div for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
+        let (lhs, rhs) = try!(self.infer(rhs));
+        try!(check_division(lhs, rhs, Op::Div, DivisionByZero));
+        match (lhs, rhs) {
+            (I8(a), I8(b)) => Ok(I8(a/b)),
+            (I16(a), I16(b)) => Ok(I16(a/b)),
+            (I32(a), I32(b)) => Ok(I32(a/b)),
+            (I64(a), I64(b)) => Ok(I64(a/b)),
+            (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
+            (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
+            (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a/b)),
+
+            (U8(a), U8(b)) => Ok(U8(a/b)),
+            (U16(a), U16(b)) => Ok(U16(a/b)),
+            (U32(a), U32(b)) => Ok(U32(a/b)),
+            (U64(a), U64(b)) => Ok(U64(a/b)),
+            (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
+            (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
+            (Infer(a), Infer(b)) => Ok(Infer(a/b)),
+
+            _ => Err(UnequalTypes(Op::Div)),
+        }
+    }
+}
+
+impl ::std::ops::Rem for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
+        let (lhs, rhs) = try!(self.infer(rhs));
+        // should INT_MIN%-1 be zero or an error?
+        try!(check_division(lhs, rhs, Op::Rem, RemainderByZero));
+        match (lhs, rhs) {
+            (I8(a), I8(b)) => Ok(I8(a%b)),
+            (I16(a), I16(b)) => Ok(I16(a%b)),
+            (I32(a), I32(b)) => Ok(I32(a%b)),
+            (I64(a), I64(b)) => Ok(I64(a%b)),
+            (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
+            (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
+            (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a%b)),
+
+            (U8(a), U8(b)) => Ok(U8(a%b)),
+            (U16(a), U16(b)) => Ok(U16(a%b)),
+            (U32(a), U32(b)) => Ok(U32(a%b)),
+            (U64(a), U64(b)) => Ok(U64(a%b)),
+            (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
+            (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
+            (Infer(a), Infer(b)) => Ok(Infer(a%b)),
+
+            _ => Err(UnequalTypes(Op::Rem)),
+        }
+    }
+}
+
+impl ::std::ops::Shl<ConstInt> for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn shl(self, rhs: Self) -> Result<Self, ConstMathErr> {
+        let b = try!(rhs.to_u32().ok_or(ShiftNegative));
+        match self {
+            I8(a) => Ok(I8(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            I16(a) => Ok(I16(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            I32(a) => Ok(I32(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            I64(a) => Ok(I64(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
+            Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
+            U8(a) => Ok(U8(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            U16(a) => Ok(U16(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            U32(a) => Ok(U32(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            U64(a) => Ok(U64(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
+            Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
+            Infer(a) => Ok(Infer(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shl(b), Op::Shl))),
+        }
+    }
+}
+
+impl ::std::ops::Shr<ConstInt> for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn shr(self, rhs: Self) -> Result<Self, ConstMathErr> {
+        let b = try!(rhs.to_u32().ok_or(ShiftNegative));
+        match self {
+            I8(a) => Ok(I8(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shl))),
+            Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
+            Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
+            U8(a) => Ok(U8(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            U16(a) => Ok(U16(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            U32(a) => Ok(U32(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            U64(a) => Ok(U64(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
+            Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
+            Infer(a) => Ok(Infer(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shr(b), Op::Shr))),
+        }
+    }
+}
+
+impl ::std::ops::Neg for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn neg(self) -> Result<Self, ConstMathErr> {
+        match self {
+            I8(a) => Ok(I8(overflowing!(a.overflowing_neg(), Op::Neg))),
+            I16(a) => Ok(I16(overflowing!(a.overflowing_neg(), Op::Neg))),
+            I32(a) => Ok(I32(overflowing!(a.overflowing_neg(), Op::Neg))),
+            I64(a) => Ok(I64(overflowing!(a.overflowing_neg(), Op::Neg))),
+            Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_neg(), Op::Neg)))),
+            Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_neg(), Op::Neg)))),
+            U8(0) => Ok(U8(0)),
+            U16(0) => Ok(U16(0)),
+            U32(0) => Ok(U32(0)),
+            U64(0) => Ok(U64(0)),
+            Usize(Us32(0)) => Ok(Usize(Us32(0))),
+            Usize(Us64(0)) => Ok(Usize(Us64(0))),
+            U8(_) => Err(UnsignedNegation),
+            U16(_) => Err(UnsignedNegation),
+            U32(_) => Err(UnsignedNegation),
+            U64(_) => Err(UnsignedNegation),
+            Usize(_) => Err(UnsignedNegation),
+            Infer(a @ 0...as_u64::I64MAX) => Ok(InferSigned(-(a as i64))),
+            Infer(_) => Err(Overflow(Op::Neg)),
+            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
+        }
+    }
+}
+
+impl ::std::ops::Not for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn not(self) -> Result<Self, ConstMathErr> {
+        match self {
+            I8(a) => Ok(I8(!a)),
+            I16(a) => Ok(I16(!a)),
+            I32(a) => Ok(I32(!a)),
+            I64(a) => Ok(I64(!a)),
+            Isize(Is32(a)) => Ok(Isize(Is32(!a))),
+            Isize(Is64(a)) => Ok(Isize(Is64(!a))),
+            U8(a) => Ok(U8(!a)),
+            U16(a) => Ok(U16(!a)),
+            U32(a) => Ok(U32(!a)),
+            U64(a) => Ok(U64(!a)),
+            Usize(Us32(a)) => Ok(Usize(Us32(!a))),
+            Usize(Us64(a)) => Ok(Usize(Us64(!a))),
+            Infer(a) => Ok(Infer(!a)),
+            InferSigned(a) => Ok(InferSigned(!a)),
+        }
+    }
+}
diff --git a/src/librustc_const_eval/is.rs b/src/librustc_const_eval/is.rs
new file mode 100644 (file)
index 0000000..082c651
--- /dev/null
@@ -0,0 +1,39 @@
+// 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 syntax::ast;
+use super::err::*;
+
+/// Depending on the target only one variant is ever used in a compilation.
+/// Anything else is an error. This invariant is checked at several locations
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
+pub enum ConstIsize {
+    Is32(i32),
+    Is64(i64),
+}
+pub use self::ConstIsize::*;
+
+impl ConstIsize {
+    pub fn as_i64(self, target_int_ty: ast::IntTy) -> i64 {
+        match (self, target_int_ty) {
+            (Is32(i), ast::IntTy::I32) => i as i64,
+            (Is64(i), ast::IntTy::I64) => i,
+            _ => panic!("got invalid isize size for target"),
+        }
+    }
+    pub fn new(i: i64, target_int_ty: ast::IntTy) -> Result<Self, ConstMathErr> {
+        match target_int_ty {
+            ast::IntTy::I32 if i as i32 as i64 == i => Ok(Is32(i as i32)),
+            ast::IntTy::I32 => Err(LitOutOfRange(ast::IntTy::Is)),
+            ast::IntTy::I64 => Ok(Is64(i)),
+            _ => unreachable!(),
+        }
+    }
+}
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
new file mode 100644 (file)
index 0000000..e4c702f
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Rusty Mathematics
+//!
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![crate_name = "rustc_const_eval"]
+#![unstable(feature = "rustc_private", issue = "27812")]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+      html_root_url = "https://doc.rust-lang.org/nightly/")]
+
+
+#![feature(rustc_private)]
+#![feature(staged_api)]
+
+#[macro_use] extern crate log;
+#[macro_use] extern crate syntax;
+
+extern crate serialize as rustc_serialize; // used by deriving
+
+mod int;
+mod us;
+mod is;
+mod err;
+
+pub use int::*;
+pub use us::*;
+pub use is::*;
+pub use err::ConstMathErr;
diff --git a/src/librustc_const_eval/us.rs b/src/librustc_const_eval/us.rs
new file mode 100644 (file)
index 0000000..e5a7086
--- /dev/null
@@ -0,0 +1,39 @@
+// 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 syntax::ast;
+use super::err::*;
+
+/// Depending on the target only one variant is ever used in a compilation.
+/// Anything else is an error. This invariant is checked at several locations
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
+pub enum ConstUsize {
+    Us32(u32),
+    Us64(u64),
+}
+pub use self::ConstUsize::*;
+
+impl ConstUsize {
+    pub fn as_u64(self, target_uint_ty: ast::UintTy) -> u64 {
+        match (self, target_uint_ty) {
+            (Us32(i), ast::UintTy::U32) => i as u64,
+            (Us64(i), ast::UintTy::U64) => i,
+            _ => panic!("got invalid usize size for target"),
+        }
+    }
+    pub fn new(i: u64, target_uint_ty: ast::UintTy) -> Result<Self, ConstMathErr> {
+        match target_uint_ty {
+            ast::UintTy::U32 if i as u32 as u64 == i => Ok(Us32(i as u32)),
+            ast::UintTy::U32 => Err(ULitOutOfRange(ast::UintTy::Us)),
+            ast::UintTy::U64 => Ok(Us64(i)),
+            _ => unreachable!(),
+        }
+    }
+}
index d76d7f6ba340e67c9e563594ed084378ce91cf09..982a2bacce1648459cffea4dc3cde3e83d0fb5b2 100644 (file)
@@ -60,7 +60,7 @@ which includes three bits of information:
   `process_obligations` would simply yield back further ambiguous
   results. This is used by the `FulfillmentContext` to decide when it
   has reached a steady state.
-  
+
 #### Snapshots
 
 The `ObligationForest` supports a limited form of snapshots; see
@@ -79,5 +79,3 @@ parent and (for convenience) its root (which may be itself). It also
 has a current state, described by `NodeState`. After each
 processing step, we compress the vector to remove completed and error
 nodes, which aren't needed anymore.
-
-  
index 46e06d21c7c249c47e66f54eed0c7eb54ebac699..8dac25cc0cbf1193dd635ed2d47f382c07bd0d5d 100644 (file)
@@ -231,7 +231,6 @@ macro_rules! controller_entry_point {
     Ok(())
 }
 
-
 /// The name used for source code that doesn't originate in a file
 /// (e.g. source from stdin or a string)
 pub fn anon_src() -> String {
@@ -242,7 +241,7 @@ pub fn source_name(input: &Input) -> String {
     match *input {
         // FIXME (#9639): This needs to handle non-utf8 paths
         Input::File(ref ifile) => ifile.to_str().unwrap().to_string(),
-        Input::Str(_) => anon_src(),
+        Input::Str { ref name, .. } => name.clone(),
     }
 }
 
@@ -434,9 +433,9 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session,
             Input::File(ref file) => {
                 parse::parse_crate_from_file(file, cfg.clone(), &sess.parse_sess)
             }
-            Input::Str(ref src) => {
-                parse::parse_crate_from_source_str(anon_src().to_string(),
-                                                   src.to_string(),
+            Input::Str { ref input, ref name } => {
+                parse::parse_crate_from_source_str(name.clone(),
+                                                   input.clone(),
                                                    cfg.clone(),
                                                    &sess.parse_sess)
             }
index d1c287b1e39325c1af71e8efdd74a495684e1f82..357c7238c1f6c9572a939d1b90615c005083688d 100644 (file)
@@ -223,7 +223,8 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>)> {
         if ifile == "-" {
             let mut src = String::new();
             io::stdin().read_to_string(&mut src).unwrap();
-            Some((Input::Str(src), None))
+            Some((Input::Str { name: driver::anon_src(), input: src },
+                  None))
         } else {
             Some((Input::File(PathBuf::from(ifile)),
                   Some(PathBuf::from(ifile))))
@@ -511,7 +512,7 @@ pub fn list_metadata(sess: &Session, matches: &getopts::Matches, input: &Input)
                         .unwrap();
                     println!("{}", String::from_utf8(v).unwrap());
                 }
-                &Input::Str(_) => {
+                &Input::Str { .. } => {
                     early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
                 }
             }
@@ -994,9 +995,9 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<as
         Input::File(ref ifile) => {
             parse::parse_crate_attrs_from_file(ifile, Vec::new(), &sess.parse_sess)
         }
-        Input::Str(ref src) => {
-            parse::parse_crate_attrs_from_source_str(driver::anon_src().to_string(),
-                                                     src.to_string(),
+        Input::Str { ref name, ref input } => {
+            parse::parse_crate_attrs_from_source_str(name.clone(),
+                                                     input.clone(),
                                                      Vec::new(),
                                                      &sess.parse_sess)
         }
index 3cab9cfb88ca90758bf3d89437cb01a881fbe6cd..1a5e7cb54f2e3a0bb60a29bdbe5e706130330c5d 100644 (file)
@@ -22,6 +22,7 @@
 use rustc_typeck::middle::stability;
 use rustc_typeck::middle::subst;
 use rustc_typeck::middle::subst::Subst;
+use rustc_typeck::middle::traits::ProjectionMode;
 use rustc_typeck::middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_typeck::middle::ty::relate::TypeRelation;
 use rustc_typeck::middle::infer::{self, TypeOrigin};
@@ -113,7 +114,10 @@ fn test_env<F>(source_string: &str,
                                        Rc::new(CodeMap::new()), cstore.clone());
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     let krate_config = Vec::new();
-    let input = config::Input::Str(source_string.to_string());
+    let input = config::Input::Str {
+        name: driver::anon_src(),
+        input: source_string.to_string(),
+    };
     let krate = driver::phase_1_parse_input(&sess, krate_config, &input).unwrap();
     let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "test", None)
                     .expect("phase 2 aborted");
@@ -143,7 +147,10 @@ fn test_env<F>(source_string: &str,
                                lang_items,
                                index,
                                |tcx| {
-                                   let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
+                                   let infcx = infer::new_infer_ctxt(tcx,
+                                                                     &tcx.tables,
+                                                                     None,
+                                                                     ProjectionMode::AnyFinal);
                                    body(Env { infcx: &infcx });
                                    let free_regions = FreeRegionMap::new();
                                    infcx.resolve_regions_and_report_errors(&free_regions,
index beedb3d70b69917e93b62cda7e41cb506c938cdb..6ae59122f71c49a85525eb8534972ecfa41eca3c 100644 (file)
@@ -839,6 +839,7 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T) -> ImplItem {
         name: folder.fold_name(i.name),
         attrs: fold_attrs(i.attrs, folder),
         vis: i.vis,
+        defaultness: i.defaultness,
         node: match i.node {
             ImplItemKind::Const(ty, expr) => {
                 ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr))
index cc7c0f7865ea56de6965f5314d231a597a2d9f0b..0b1418fc878452b83ecb51a054e6a3f47abe1b7e 100644 (file)
@@ -864,10 +864,10 @@ pub struct MethodSig {
     pub explicit_self: ExplicitSelf,
 }
 
-/// Represents a method declaration in a trait declaration, possibly including
-/// a default implementation A trait method is either required (meaning it
-/// doesn't have an implementation, just a signature) or provided (meaning it
-/// has a default implementation).
+/// Represents an item declaration within a trait declaration,
+/// possibly including a default implementation. A trait item is
+/// either required (meaning it doesn't have an implementation, just a
+/// signature) or provided (meaning it has a default implementation).
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct TraitItem {
     pub id: NodeId,
@@ -889,6 +889,7 @@ pub struct ImplItem {
     pub id: NodeId,
     pub name: Name,
     pub vis: Visibility,
+    pub defaultness: Defaultness,
     pub attrs: HirVec<Attribute>,
     pub node: ImplItemKind,
     pub span: Span,
@@ -1046,6 +1047,22 @@ pub enum Constness {
     NotConst,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum Defaultness {
+    Default,
+    Final,
+}
+
+impl Defaultness {
+    pub fn is_final(&self) -> bool {
+        *self == Defaultness::Final
+    }
+
+    pub fn is_default(&self) -> bool {
+        *self == Defaultness::Default
+    }
+}
+
 impl fmt::Display for Unsafety {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt::Display::fmt(match *self {
index 291df66755e7d80359f00920936b6357318b2b6d..825ab3fbd4c8227107c4c71846e79b5bb3972b5d 100644 (file)
@@ -756,6 +756,7 @@ pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> hir::ImplItem {
         name: i.ident.name,
         attrs: lower_attrs(lctx, &i.attrs),
         vis: lower_visibility(lctx, i.vis),
+        defaultness: lower_defaultness(lctx, i.defaultness),
         node: match i.node {
             ImplItemKind::Const(ref ty, ref expr) => {
                 hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr))
@@ -1707,6 +1708,13 @@ pub fn lower_visibility(_lctx: &LoweringContext, v: Visibility) -> hir::Visibili
     }
 }
 
+pub fn lower_defaultness(_lctx: &LoweringContext, d: Defaultness) -> hir::Defaultness {
+    match d {
+        Defaultness::Default => hir::Defaultness::Default,
+        Defaultness::Final => hir::Defaultness::Final,
+    }
+}
+
 pub fn lower_block_check_mode(lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode {
     match *b {
         BlockCheckMode::Default => hir::DefaultBlock,
index 143dfce09b6029f1ee20cd12a22f22797edb7b9b..1100f084454c729747c50c057819d5e80acbecda 100644 (file)
@@ -1014,6 +1014,11 @@ pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> {
         try!(self.hardbreak_if_not_bol());
         try!(self.maybe_print_comment(ii.span.lo));
         try!(self.print_outer_attributes(&ii.attrs));
+
+        if let hir::Defaultness::Default = ii.defaultness {
+            try!(self.word_nbsp("default"));
+        }
+
         match ii.node {
             hir::ImplItemKind::Const(ref ty, ref expr) => {
                 try!(self.print_associated_const(ii.name, &ty, Some(&expr), ii.vis));
index 0c906f8eb546c2fd68da66c513d8d9532a37b708..88027931022e755824cee9766c6c91b3e63509f1 100644 (file)
@@ -35,6 +35,7 @@
 use middle::subst::Substs;
 use middle::ty::{self, Ty, TyCtxt};
 use middle::ty::adjustment;
+use middle::traits::ProjectionMode;
 use rustc::front::map as hir_map;
 use util::nodemap::{NodeSet};
 use lint::{Level, LateContext, LintContext, LintArray, Lint};
@@ -868,7 +869,10 @@ fn method_call_refers_to_method<'tcx>(tcx: &TyCtxt<'tcx>,
                     let node_id = tcx.map.as_local_node_id(method.def_id).unwrap();
 
                     let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
-                    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
+                    let infcx = infer::new_infer_ctxt(tcx,
+                                                      &tcx.tables,
+                                                      Some(param_env),
+                                                      ProjectionMode::AnyFinal);
                     let mut selcx = traits::SelectionContext::new(&infcx);
                     match selcx.select(&obligation) {
                         // The method comes from a `T: Trait` bound.
index 10535549ceb7715f8d9818bcecd8bd5b0240d8a6..4d844bbf032b6f2d23b8fde149cad38dbcda9cc1 100644 (file)
@@ -143,8 +143,11 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
                             else { false }
                         } else {
                             match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
-                                Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
-                                Ok(ConstVal::Uint(shift)) => { shift >= bits },
+                                Ok(ConstVal::Integral(i)) => {
+                                    i.is_negative() || i.to_u64()
+                                                        .map(|i| i >= bits)
+                                                        .unwrap_or(true)
+                                },
                                 _ => { false }
                             }
                         };
index 59164161b3d5ec12289ebec50f883f762dca9517..dcfb518ba793815527411421cafe914845875474 100644 (file)
@@ -47,14 +47,20 @@ fn main() {
     // the host platform. This only really works if the host LLVM and target
     // LLVM are compiled the same way, but for us that's typically the case.
     //
-    // We detect this cross compiling situation by asking llvm-config what it's
-    // host-target is. If that's not the TARGET, then we're cross compiling.
-    // This generally just means that we can't trust all the output of
-    // llvm-config becaues it might be targeted for the host rather than the
-    // target.
+    // We *want* detect this cross compiling situation by asking llvm-config
+    // what it's host-target is. If that's not the TARGET, then we're cross
+    // compiling. Unfortunately `llvm-config` seems either be buggy, or we're
+    // misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will
+    // report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This
+    // tricks us into thinking we're doing a cross build when we aren't, so
+    // havoc ensues.
+    //
+    // In any case, if we're cross compiling, this generally just means that we
+    // can't trust all the output of llvm-config becaues it might be targeted
+    // for the host rather than the target. As a result a bunch of blocks below
+    // are gated on `if !is_crossed`
     let target = env::var("TARGET").unwrap();
-    let host = output(Command::new(&llvm_config).arg("--host-target"));
-    let host = host.trim();
+    let host = env::var("HOST").unwrap();
     let is_crossed = target != host;
 
     let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc",
index d6bb4b157a6a3d2471c531c50d4e0ab8094c6190..e8b5a7efdd96bf68af35bf2402c04e7abcbf47ff 100644 (file)
@@ -15,6 +15,7 @@ rbml = { path = "../librbml" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
 rustc_bitflags = { path = "../librustc_bitflags" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_front = { path = "../librustc_front" }
 rustc_llvm = { path = "../librustc_llvm" }
 serialize = { path = "../libserialize" }
index 991cbe137ecf91cf41aaa670d1aee666a0642757..a0cbba279acc05e3bf88f440f085c425e3a96266 100644 (file)
@@ -241,6 +241,10 @@ pub enum astencode_tag { // Reserves 0x50 -- 0x6f
 
 pub const tag_items_data_item_deprecation: usize = 0xa7;
 
+pub const tag_items_data_item_defaultness: usize = 0xa8;
+
+pub const tag_items_data_parent_impl: usize = 0xa9;
+
 pub const tag_rustc_version: usize = 0x10f;
 pub fn rustc_version() -> String {
     format!(
index b3f24b8f16b1631273878d5485d9670a250902b5..2cd119cfc48be081d444945fe539524976ad2a06 100644 (file)
@@ -225,6 +225,11 @@ fn associated_consts(&self, tcx: &TyCtxt<'tcx>, def: DefId)
         decoder::get_associated_consts(self.intr.clone(), &cdata, def.index, tcx)
     }
 
+    fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
+        let cdata = self.get_crate_data(impl_def.krate);
+        decoder::get_parent_impl(&*cdata, impl_def.index)
+    }
+
     fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId) -> Option<DefId>
     {
         let cdata = self.get_crate_data(def_id.krate);
index 06f81a17a061c774b3744ea95b28ad16c4721d87..38a2a7794bcbd5a01768c343efc2bb65384855f3 100644 (file)
@@ -35,6 +35,8 @@
 use middle::ty::{ImplContainer, TraitContainer};
 use middle::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind};
 
+use rustc_const_eval::ConstInt;
+
 use rustc::mir;
 use rustc::mir::visit::MutVisitor;
 
@@ -163,6 +165,19 @@ fn fn_constness(item: rbml::Doc) -> hir::Constness {
     }
 }
 
+fn item_defaultness(item: rbml::Doc) -> hir::Defaultness {
+    match reader::maybe_get_doc(item, tag_items_data_item_defaultness) {
+        None => hir::Defaultness::Default, // should occur only for default impls on traits
+        Some(defaultness_doc) => {
+            match reader::doc_as_u8(defaultness_doc) as char {
+                'd' => hir::Defaultness::Default,
+                'f' => hir::Defaultness::Final,
+                _ => panic!("unknown defaultness character")
+            }
+        }
+    }
+}
+
 fn item_sort(item: rbml::Doc) -> Option<char> {
     reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| {
         doc.as_str_slice().as_bytes()[0] as char
@@ -198,7 +213,7 @@ fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> {
     reader::tagged_docs(d, tag_items_data_item_reexport)
 }
 
-fn variant_disr_val(d: rbml::Doc) -> Option<ty::Disr> {
+fn variant_disr_val(d: rbml::Doc) -> Option<u64> {
     reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| {
         reader::with_doc_data(val_doc, |data| {
             str::from_utf8(data).ok().and_then(|s| s.parse().ok())
@@ -396,7 +411,7 @@ fn get_enum_variants<'tcx>(intr: &IdentInterner,
                 did: did,
                 name: item_name(intr, item),
                 fields: get_variant_fields(intr, cdata, item, tcx),
-                disr_val: disr,
+                disr_val: ConstInt::Infer(disr),
                 kind: expect_variant_kind(item_family(item), tcx),
             }
         }).collect()
@@ -432,7 +447,7 @@ fn get_struct_variant<'tcx>(intr: &IdentInterner,
             did: did,
             name: item_name(intr, doc),
             fields: get_variant_fields(intr, cdata, doc, tcx),
-            disr_val: 0,
+            disr_val: ConstInt::Infer(0),
             kind: expect_variant_kind(item_family(doc), tcx),
         }
     }
@@ -549,6 +564,13 @@ pub fn get_visibility(cdata: Cmd, id: DefIndex) -> hir::Visibility {
     item_visibility(cdata.lookup_item(id))
 }
 
+pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option<DefId> {
+    let item = cdata.lookup_item(id);
+    reader::maybe_get_doc(item, tag_items_data_parent_impl).map(|doc| {
+        translated_def_id(cdata, doc)
+    })
+}
+
 pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec<attr::ReprAttr> {
     let item = cdata.lookup_item(id);
     match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| {
@@ -974,6 +996,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
 
     let name = item_name(&intr, item_doc);
     let vis = item_visibility(item_doc);
+    let defaultness = item_defaultness(item_doc);
 
     match item_sort(item_doc) {
         sort @ Some('C') | sort @ Some('c') => {
@@ -982,6 +1005,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
                 name: name,
                 ty: ty,
                 vis: vis,
+                defaultness: defaultness,
                 def_id: def_id,
                 container: container,
                 has_value: sort == Some('C')
@@ -1005,6 +1029,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
                                                         fty,
                                                         explicit_self,
                                                         vis,
+                                                        defaultness,
                                                         def_id,
                                                         container)))
         }
@@ -1014,6 +1039,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
                 name: name,
                 ty: ty,
                 vis: vis,
+                defaultness: defaultness,
                 def_id: def_id,
                 container: container,
             }))
index 1d1cd38225522b8ef5732ebc4cbf4ef8ba29b07e..41baa0b159148798edff3d086a15d0bf5d2a05c0 100644 (file)
@@ -25,7 +25,9 @@
 use middle::dependency_format::Linkage;
 use middle::stability;
 use middle::subst;
+use middle::traits::specialization_graph;
 use middle::ty::{self, Ty, TyCtxt};
+use middle::ty::util::IntTypeExt;
 
 use rustc::back::svh::Svh;
 use rustc::front::map::{LinkedPath, PathElem, PathElems};
@@ -238,7 +240,8 @@ fn encode_symbol(ecx: &EncodeContext,
 fn encode_disr_val(_: &EncodeContext,
                    rbml_w: &mut Encoder,
                    disr_val: ty::Disr) {
-    rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_string());
+    // convert to u64 so just the number is printed, without any type info
+    rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string());
 }
 
 fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) {
@@ -262,13 +265,14 @@ fn encode_struct_fields(rbml_w: &mut Encoder,
 
 fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                       rbml_w: &mut Encoder,
-                                      id: NodeId,
+                                      did: DefId,
                                       vis: hir::Visibility,
                                       index: &mut CrateIndex<'tcx>) {
-    debug!("encode_enum_variant_info(id={})", id);
-
-    let mut disr_val = 0;
-    let def = ecx.tcx.lookup_adt_def(ecx.tcx.map.local_def_id(id));
+    debug!("encode_enum_variant_info(did={:?})", did);
+    let repr_hints = ecx.tcx.lookup_repr_hints(did);
+    let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0));
+    let mut disr_val = repr_type.initial_discriminant(&ecx.tcx);
+    let def = ecx.tcx.lookup_adt_def(did);
     for variant in &def.variants {
         let vid = variant.did;
         let variant_node_id = ecx.local_id(vid);
@@ -290,7 +294,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             ty::VariantKind::Unit => 'w',
         });
         encode_name(rbml_w, variant.name);
-        encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id));
+        encode_parent_item(rbml_w, did);
         encode_visibility(rbml_w, vis);
 
         let attrs = ecx.tcx.get_attrs(vid);
@@ -313,7 +317,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
         ecx.tcx.map.with_path(variant_node_id, |path| encode_path(rbml_w, path));
         rbml_w.end_tag();
-        disr_val = disr_val.wrapping_add(1);
+        disr_val = disr_val.wrap_incr();
     }
 }
 
@@ -448,6 +452,14 @@ fn encode_constness(rbml_w: &mut Encoder, constness: hir::Constness) {
     rbml_w.end_tag();
 }
 
+fn encode_defaultness(rbml_w: &mut Encoder, defaultness: hir::Defaultness) {
+    let ch = match defaultness {
+        hir::Defaultness::Default => 'd',
+        hir::Defaultness::Final => 'f',
+    };
+    rbml_w.wr_tagged_u8(tag_items_data_item_defaultness, ch as u8);
+}
+
 fn encode_explicit_self(rbml_w: &mut Encoder,
                         explicit_self: &ty::ExplicitSelfCategory) {
     let tag = tag_item_trait_method_explicit_self;
@@ -671,6 +683,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
     if let Some(ii) = impl_item_opt {
         encode_attributes(rbml_w, &ii.attrs);
+        encode_defaultness(rbml_w, ii.defaultness);
         encode_inlined_item(ecx,
                             rbml_w,
                             InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
@@ -722,6 +735,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                                              impl_item));
             }
             encode_constness(rbml_w, sig.constness);
+            encode_defaultness(rbml_w, impl_item.defaultness);
             if !any_types {
                 let m_id = ecx.local_id(m.def_id);
                 encode_symbol(ecx, rbml_w, m_id);
@@ -764,6 +778,7 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
     if let Some(ii) = impl_item_opt {
         encode_attributes(rbml_w, &ii.attrs);
+        encode_defaultness(rbml_w, ii.defaultness);
     } else {
         encode_predicates(rbml_w, ecx, index,
                           &ecx.tcx.lookup_predicates(associated_type.def_id),
@@ -870,6 +885,12 @@ fn encode_deprecation(rbml_w: &mut Encoder, depr_opt: Option<attr::Deprecation>)
     });
 }
 
+fn encode_parent_impl(rbml_w: &mut Encoder, parent_opt: Option<DefId>) {
+    parent_opt.map(|parent| {
+        rbml_w.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent));
+    });
+}
+
 fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                           rbml_w: &mut Encoder,
                           xrefs: FnvHashMap<XRef<'tcx>, u32>)
@@ -1035,7 +1056,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
         encode_enum_variant_info(ecx,
                                  rbml_w,
-                                 item.id,
+                                 def_id,
                                  vis,
                                  index);
       }
@@ -1147,8 +1168,19 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             }
             rbml_w.end_tag();
         }
-        if let Some(trait_ref) = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)) {
+        let did = ecx.tcx.map.local_def_id(item.id);
+        if let Some(trait_ref) = tcx.impl_trait_ref(did) {
             encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
+
+            let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
+            let parent = trait_def.ancestors(did)
+                .skip(1)
+                .next()
+                .and_then(|node| match node {
+                    specialization_graph::Node::Impl(parent) => Some(parent),
+                    _ => None,
+                });
+            encode_parent_impl(rbml_w, parent);
         }
         encode_path(rbml_w, path.clone());
         encode_stability(rbml_w, stab);
index 5386c5b77c2121255ef4f7f0fe1a5b3d4fdfb479..f0f0fb847540a58303657908cdc5e12c76de031b 100644 (file)
@@ -36,6 +36,7 @@
 extern crate rustc_back;
 extern crate rustc_front;
 extern crate rustc_llvm;
+extern crate rustc_const_eval;
 
 pub use rustc::middle;
 
index 93817ab0db61b782f7d0512e12430e8a69c277d6..99237c9fa5f47bc1c4feb4ecb3c8cd20abe4229a 100644 (file)
@@ -13,6 +13,7 @@ graphviz = { path = "../libgraphviz" }
 log = { path = "../liblog" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_front = { path = "../librustc_front" }
 syntax = { path = "../libsyntax" }
index e6430b7d63404cbff54f12d8543b37f7bc0cedc6..9ecbf748d7c8311f4de4205a64e67e34946232fc 100644 (file)
@@ -269,7 +269,7 @@ enum TestKind<'tcx> {
 
     // test length of the slice is equal to len
     Len {
-        len: usize,
+        len: u64,
         op: BinOp,
     },
 }
index 02f32da2b83fc23d796bda27ff78ebc1a09d93e6..d42c8ff7bd79fab67f204babfd78e5ac6f8fb703 100644 (file)
@@ -84,7 +84,7 @@ pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
                 };
                 Test {
                     span: match_pair.pattern.span,
-                    kind: TestKind::Len { len: len, op: op },
+                    kind: TestKind::Len { len: len as u64, op: op },
                 }
             }
 
index 8c435b45daeff14953d8e049184d75049f68dad8..13ab26c358d6a6a9fd6d52637a22e42ff1c24e30 100644 (file)
@@ -46,7 +46,7 @@ pub fn literal_operand(&mut self,
         Operand::Constant(constant)
     }
 
-    pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: usize) -> Lvalue<'tcx> {
+    pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: u64) -> Lvalue<'tcx> {
         let usize_ty = self.hir.usize_ty();
         let temp = self.temp(usize_ty);
         self.cfg.push_assign_constant(
index 3d14ad2374bb43e1fdff70b97d652fc3ee12e972..6d411b9c07b311dc5394b1bc2cc0c4b946d53f8c 100644 (file)
@@ -94,6 +94,8 @@
 use rustc::mir::repr::*;
 use syntax::codemap::{Span, DUMMY_SP};
 use syntax::parse::token::intern_and_get_ident;
+use rustc::middle::const_eval::ConstVal;
+use rustc_const_eval::ConstInt;
 
 pub struct Scope<'tcx> {
     extent: CodeExtent,
@@ -517,7 +519,9 @@ fn span_to_fileline_args(&mut self, span: Span) -> (Constant<'tcx>, Constant<'tc
         }, Constant {
             span: span,
             ty: self.hir.tcx().types.u32,
-            literal: self.hir.usize_literal(span_lines.line)
+            literal: Literal::Value {
+                value: ConstVal::Integral(ConstInt::U32(span_lines.line as u32)),
+            },
         })
     }
 
index cbd6bed81a68fcfd7f53e337d84d4fa245de2ed4..1f8a5da9c1b9d598d89e32719cbab9c8a5d9abbc 100644 (file)
 
 use hair::*;
 use rustc_data_structures::fnv::FnvHashMap;
+use rustc_const_eval::ConstInt;
 use hair::cx::Cx;
 use hair::cx::block;
 use hair::cx::to_ref::ToRef;
 use rustc::front::map;
 use rustc::middle::def::Def;
-use rustc::middle::const_eval;
+use rustc::middle::const_eval::{self, ConstVal};
 use rustc::middle::region::CodeExtent;
 use rustc::middle::pat_util;
 use rustc::middle::ty::{self, VariantDef, Ty};
@@ -227,28 +228,37 @@ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
                 }
             }
 
-            hir::ExprUnary(op, ref arg) => {
+            hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
                 if cx.tcx.is_method_call(self.id) {
                     overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
                                         PassArgs::ByValue, arg.to_ref(), vec![])
                 } else {
-                    // FIXME overflow
-                    let op = match op {
-                        hir::UnOp::UnNot => UnOp::Not,
-                        hir::UnOp::UnNeg => UnOp::Neg,
-                        hir::UnOp::UnDeref => {
-                            cx.tcx.sess.span_bug(
-                                self.span,
-                                "UnDeref should have been handled elsewhere");
-                        }
-                    };
                     ExprKind::Unary {
-                        op: op,
+                        op: UnOp::Not,
                         arg: arg.to_ref(),
                     }
                 }
             }
 
+            hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
+                if cx.tcx.is_method_call(self.id) {
+                    overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
+                                        PassArgs::ByValue, arg.to_ref(), vec![])
+                } else {
+                    // FIXME runtime-overflow
+                    if let hir::ExprLit(_) = arg.node {
+                        ExprKind::Literal {
+                            literal: cx.const_eval_literal(self),
+                        }
+                    } else {
+                        ExprKind::Unary {
+                            op: UnOp::Neg,
+                            arg: arg.to_ref(),
+                        }
+                    }
+                }
+            }
+
             hir::ExprStruct(_, ref fields, ref base) => {
                 match expr_ty.sty {
                     ty::TyStruct(adt, substs) => {
@@ -338,7 +348,10 @@ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
                 count: TypedConstVal {
                     ty: cx.tcx.expr_ty(c),
                     span: c.span,
-                    value: const_eval::eval_const_expr(cx.tcx, c)
+                    value: match const_eval::eval_const_expr(cx.tcx, c) {
+                        ConstVal::Integral(ConstInt::Usize(u)) => u,
+                        other => panic!("constant evaluation of repeat count yielded {:?}", other),
+                    },
                 }
             },
             hir::ExprRet(ref v) =>
index f1b74ca1288f3fa74ec435ef927eb9b6a2b4d01f..fd4cf7c04734a6124966936ea0b463976aa1d5b0 100644 (file)
@@ -24,6 +24,7 @@
 use syntax::codemap::Span;
 use syntax::parse::token;
 use rustc_front::hir;
+use rustc_const_eval::{ConstInt, ConstUsize};
 
 #[derive(Copy, Clone)]
 pub struct Cx<'a, 'tcx: 'a> {
@@ -50,8 +51,11 @@ pub fn usize_ty(&mut self) -> Ty<'tcx> {
         self.tcx.types.usize
     }
 
-    pub fn usize_literal(&mut self, value: usize) -> Literal<'tcx> {
-        Literal::Value { value: ConstVal::Uint(value as u64) }
+    pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
+        match ConstUsize::new(value, self.tcx.sess.target.uint_type) {
+            Ok(val) => Literal::Value { value: ConstVal::Integral(ConstInt::Usize(val))},
+            Err(_) => panic!("usize literal out of range for target"),
+        }
     }
 
     pub fn bool_ty(&mut self) -> Ty<'tcx> {
index 6f4375d53ec4bf95f24531532d08b93682fa575d..d1e3f08aff894d01ea538f23b4e943bfba94bace 100644 (file)
@@ -87,7 +87,7 @@ fn to_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
                     Def::Const(def_id) | Def::AssociatedConst(def_id) =>
                         match const_eval::lookup_const_by_id(self.cx.tcx, def_id,
                                                              Some(pat.id), None) {
-                            Some(const_expr) => {
+                            Some((const_expr, _const_ty)) => {
                                 let pat = const_eval::const_expr_to_pat(self.cx.tcx, const_expr,
                                                                         pat.span);
                                 return self.to_pattern(&pat);
index 5d915f37f6ebf8653ffbcfc6e1081f4eac617e54..7c8c8945bbc9109dd2cf4c719ed3525fc00ce9d5 100644 (file)
@@ -31,6 +31,7 @@
 extern crate rustc_front;
 extern crate rustc_back;
 extern crate syntax;
+extern crate rustc_const_eval;
 
 pub mod build;
 pub mod graphviz;
index 2e13e7b42bd6c0dad193b89037f27b6bbe58c1eb..13521de78af28edd54fe9ca4440d04740887c7ce 100644 (file)
@@ -27,6 +27,7 @@
 use rustc::mir::mir_map::MirMap;
 use rustc::middle::infer;
 use rustc::middle::region::CodeExtentData;
+use rustc::middle::traits::ProjectionMode;
 use rustc::middle::ty::{self, Ty, TyCtxt};
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::NodeMap;
@@ -137,7 +138,11 @@ fn visit_fn(&mut self,
         };
 
         let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
-        let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));
+        let infcx = infer::new_infer_ctxt(self.tcx,
+                                          &self.tcx.tables,
+                                          Some(param_env),
+                                          ProjectionMode::AnyFinal);
+
         match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
             Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()),
             Err(ErrorReported) => {}
index 45393d57101e577c1b0779a4350d53910b36c5b5..d99e6ff4bf55de40e53fd87fe34b594b44a8d795 100644 (file)
@@ -13,7 +13,7 @@
 
 use rustc::dep_graph::DepNode;
 use rustc::middle::infer::{self, InferCtxt};
-use rustc::middle::traits;
+use rustc::middle::traits::{self, ProjectionMode};
 use rustc::middle::ty::fold::TypeFoldable;
 use rustc::middle::ty::{self, Ty, TyCtxt};
 use rustc::mir::repr::*;
@@ -582,7 +582,10 @@ fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, id: NodeId, mir: &mut Mir<'tcx>) {
         }
         let _task = tcx.dep_graph.in_task(DepNode::MirTypeck(id));
         let param_env = ty::ParameterEnvironment::for_item(tcx, id);
-        let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
+        let infcx = infer::new_infer_ctxt(tcx,
+                                          &tcx.tables,
+                                          Some(param_env),
+                                          ProjectionMode::AnyFinal);
         let mut checker = TypeChecker::new(&infcx);
         {
             let mut verifier = TypeVerifier::new(&mut checker, mir);
index 3a39a3c6dd1947ecb18c1feb08144e98114f85c6..6be7f6c200247a01abd0fefdb2bd35d62a5cefe5 100644 (file)
@@ -35,8 +35,8 @@
 use rustc::middle::infer;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
-use rustc::middle::traits;
 use rustc::middle::ty::{self, Ty, TyCtxt};
+use rustc::middle::traits::{self, ProjectionMode};
 use rustc::util::nodemap::NodeMap;
 use rustc::middle::const_qualif::ConstQualif;
 use rustc::lint::builtin::CONST_ERR;
@@ -92,7 +92,10 @@ fn with_euv<'b, F, R>(&'b mut self, item_id: Option<ast::NodeId>, f: F) -> R whe
             None => self.tcx.empty_parameter_environment()
         };
 
-        let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));
+        let infcx = infer::new_infer_ctxt(self.tcx,
+                                          &self.tcx.tables,
+                                          Some(param_env),
+                                          ProjectionMode::AnyFinal);
 
         f(&mut euv::ExprUseVisitor::new(self, &infcx))
     }
@@ -247,7 +250,10 @@ fn check_static_mut_type(&self, e: &hir::Expr) {
 
     fn check_static_type(&self, e: &hir::Expr) {
         let ty = self.tcx.node_id_to_type(e.id);
-        let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
+        let infcx = infer::new_infer_ctxt(self.tcx,
+                                          &self.tcx.tables,
+                                          None,
+                                          ProjectionMode::AnyFinal);
         let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
         let mut fulfillment_cx = traits::FulfillmentContext::new();
         fulfillment_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
@@ -604,7 +610,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                 }
                 Some(Def::Const(did)) |
                 Some(Def::AssociatedConst(did)) => {
-                    if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
+                    if let Some((expr, _ty)) = const_eval::lookup_const_by_id(v.tcx, did,
                                                                        Some(e.id),
                                                                        None) {
                         let inner = v.global_expr(Mode::Const, expr);
index 7eef69ca50fd0e8883c4da61c710ac796d6205c6..88048b514e1f50784c5f0f5b9840ac93a52fa729 100644 (file)
@@ -16,6 +16,7 @@
 use rustc::middle::infer;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::ty::{self, TyCtxt, ParameterEnvironment};
+use rustc::middle::traits::ProjectionMode;
 
 use rustc_front::hir;
 use rustc_front::intravisit;
@@ -43,7 +44,8 @@ fn visit_fn(&mut self,
             let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
             let infcx = infer::new_infer_ctxt(self.tcx,
                                               &self.tcx.tables,
-                                              Some(param_env.clone()));
+                                              Some(param_env.clone()),
+                                              ProjectionMode::AnyFinal);
             let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: &param_env };
             let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
             euv.walk_fn(fd, b);
index d8aaf151267f6e1280b6085fdf3b88a9b99f6c0a..c5d3e414c7cab491c7c2fec94f1492817be59065 100644 (file)
@@ -498,6 +498,16 @@ pub fn find<'tcx>(_tcx: &TyCtxt<'tcx>, name: &str) -> Option<Intrinsic> {
             output: v(f(64), 4),
             definition: Named("llvm.x86.avx.addsub.pd.256")
         },
+        "256_blendv_ps" => Intrinsic {
+            inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)],
+            output: v(f(32), 8),
+            definition: Named("llvm.x86.avx.blendv.ps.256")
+        },
+        "256_blendv_pd" => Intrinsic {
+            inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)],
+            output: v(f(64), 4),
+            definition: Named("llvm.x86.avx.blendv.pd.256")
+        },
         "256_broadcast_ps" => Intrinsic {
             inputs: vec![p(true, i(8), None)],
             output: v(f(32), 8),
@@ -508,6 +518,16 @@ pub fn find<'tcx>(_tcx: &TyCtxt<'tcx>, name: &str) -> Option<Intrinsic> {
             output: v(f(64), 4),
             definition: Named("llvm.x86.avx.vbroadcastf128.pd.256")
         },
+        "256_cmp_ps" => Intrinsic {
+            inputs: vec![v(f(32), 8), v(f(32), 8), i(8)],
+            output: v(f(32), 8),
+            definition: Named("llvm.x86.avx.cmp.ps.256")
+        },
+        "256_cmp_pd" => Intrinsic {
+            inputs: vec![v(f(64), 4), v(f(64), 4), i(8)],
+            output: v(f(64), 4),
+            definition: Named("llvm.x86.avx.cmp.pd.256")
+        },
         "256_cvtepi32_pd" => Intrinsic {
             inputs: vec![v(i(32), 4)],
             output: v(f(64), 4),
index 24320c4d563bc259ce81295b53998fc04b61b91a..b7faafeba9aa1b9fd66a940f1af24a48a60a3bcb 100644 (file)
@@ -16,6 +16,7 @@ graphviz = { path = "../libgraphviz" }
 log = { path = "../liblog" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_front = { path = "../librustc_front" }
 rustc_llvm = { path = "../librustc_llvm" }
index 6f596b15b9214fd29b4832f76314021760aa6b54..d7e79e46720b37749bf14110bc5ba8f8bcd2a38e 100644 (file)
@@ -50,6 +50,7 @@
 extern crate rustc_mir;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate serialize;
+extern crate rustc_const_eval;
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
index d1567cc6fa543052d885d7f4cea3ea8e655f27ac..f5fbec0b1879e65653e4e9e4660e73f7d4781aca 100644 (file)
 use trans::type_of;
 use trans::Disr;
 use middle::ty::{self, Ty, TyCtxt};
+use middle::traits::ProjectionMode;
 use session::config::NoDebugInfo;
 use util::common::indenter;
 use util::nodemap::FnvHashMap;
@@ -1475,7 +1476,9 @@ fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool
         reassigned: false
     };
     {
-        let infcx = infer::normalizing_infer_ctxt(bcx.tcx(), &bcx.tcx().tables);
+        let infcx = infer::normalizing_infer_ctxt(bcx.tcx(),
+                                                  &bcx.tcx().tables,
+                                                  ProjectionMode::Any);
         let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx);
         visitor.walk_expr(body);
     }
index c5508a8268fe2ea80f51647ca8d40540bbb849dd..320bb1eab3c63fb66cd64a6a89330b0117d44e13 100644 (file)
@@ -1035,7 +1035,7 @@ fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) {
     match ity {
         attr::UnsignedInt(_) => {
             assert!(min <= discr);
-            assert!(discr <= max)
+            assert!(discr <= max);
         },
         attr::SignedInt(_) => {
             assert!(min.0 as i64 <= discr.0 as i64);
index 009d43e813ebc26cc3e8cc7ff70d9b92b07f283b..d93d32f8e0d068b327fc411d397372d3cb800403 100644 (file)
@@ -13,6 +13,7 @@
 use llvm::{self, ValueRef, AttrHelper};
 use middle::ty;
 use middle::infer;
+use middle::traits::ProjectionMode;
 use session::config::NoDebugInfo;
 use syntax::abi::Abi;
 pub use syntax::attr::InlineAttr;
@@ -133,7 +134,9 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
     let (fn_sig, abi, env_ty) = match fn_type.sty {
         ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => (&f.sig, f.abi, None),
         ty::TyClosure(closure_did, ref substs) => {
-            let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
+            let infcx = infer::normalizing_infer_ctxt(ccx.tcx(),
+                                                      &ccx.tcx().tables,
+                                                      ProjectionMode::Any);
             function_type = infcx.closure_type(closure_did, substs);
             let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
             (&function_type.sig, Abi::RustCall, Some(self_type))
index 95ca250e8444525f812696a08731ee10780a6252..11c03fe7a7dc7b87eeb4637191671925009f96fd 100644 (file)
@@ -13,6 +13,7 @@
 use llvm::{ValueRef, get_params};
 use middle::def_id::DefId;
 use middle::infer;
+use middle::traits::ProjectionMode;
 use trans::adt;
 use trans::attributes;
 use trans::base::*;
@@ -206,7 +207,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
     // this function (`trans_closure`) is invoked at the point
     // of the closure expression.
 
-    let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
+    let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables, ProjectionMode::Any);
     let function_type = infcx.closure_type(closure_def_id, closure_substs);
 
     let freevars: Vec<ty::Freevar> =
@@ -329,7 +330,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
            ccx.tn().val_to_string(llreffn));
 
     let tcx = ccx.tcx();
-    let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
+    let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables, ProjectionMode::Any);
 
     // Find a version of the closure type. Substitute static for the
     // region since it doesn't really matter.
index abfd127f38860d9ff4026fbf813423cbc01d17ce..cea97c1a1e77fc854cdc006a3a64f22580b90863 100644 (file)
@@ -819,10 +819,11 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             nested: _ }) =>
         {
             let callee_substs = impl_substs.with_method_from(&rcvr_substs);
-            let impl_method = tcx.get_impl_method(impl_did,
-                                                  tcx.mk_substs(callee_substs),
-                                                  trait_method.name);
-            Some((impl_method.method.def_id, impl_method.substs))
+            let impl_method = meth::get_impl_method(tcx,
+                                                    impl_did,
+                                                    tcx.mk_substs(callee_substs),
+                                                    trait_method.name);
+            Some((impl_method.method.def_id, &impl_method.substs))
         }
         // If we have a closure or a function pointer, we will also encounter
         // the concrete closure/function somewhere else (during closure or fn
@@ -982,7 +983,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                             if can_have_local_instance(ccx, impl_method.method.def_id) {
                                 Some(create_fn_trans_item(ccx,
                                                           impl_method.method.def_id,
-                                                          impl_method.substs,
+                                                          &impl_method.substs,
                                                           &Substs::trans_empty()))
                             } else {
                                 None
@@ -1160,13 +1161,14 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
                     // The substitutions we have are on the impl, so we grab
                     // the method type from the impl to substitute into.
-                    let mth = tcx.get_impl_method(impl_def_id,
-                                                  callee_substs,
-                                                  default_impl.name);
+                    let mth = meth::get_impl_method(tcx,
+                                                    impl_def_id,
+                                                    callee_substs,
+                                                    default_impl.name);
 
                     assert!(mth.is_provided);
 
-                    let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
+                    let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
                     if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
                         continue;
                     }
index 34ef4f4acec5e4d763eaa6b19f530f6081256bed..0aa69dec253a1b7eb6713059788ab7b587abddae 100644 (file)
@@ -37,8 +37,8 @@
 use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of;
-use middle::traits;
 use middle::ty::{self, Ty, TyCtxt};
+use middle::traits::{self, SelectionContext, ProjectionMode};
 use middle::ty::fold::{TypeFolder, TypeFoldable};
 use rustc_front::hir;
 use rustc::mir::repr::Mir;
@@ -1137,8 +1137,8 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
-    let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables);
-    let mut selcx = traits::SelectionContext::new(&infcx);
+    let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
+    let mut selcx = SelectionContext::new(&infcx);
 
     let obligation =
         traits::Obligation::new(traits::ObligationCause::misc(span, ast::DUMMY_NODE_ID),
@@ -1198,8 +1198,8 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
            predicates);
 
     let tcx = ccx.tcx();
-    let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables);
-    let mut selcx = traits::SelectionContext::new(&infcx);
+    let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
+    let mut selcx = SelectionContext::new(&infcx);
     let mut fulfill_cx = traits::FulfillmentContext::new();
     let cause = traits::ObligationCause::dummy();
     let traits::Normalized { value: predicates, obligations } =
index 6c47cab64effe7f2a2ec1111e7a4e620ff8086ae..7d37627ad0eea53a7145e286857c7c80f8d2a77a 100644 (file)
 use llvm::{InternalLinkage, ValueRef, Bool, True};
 use middle::const_qualif::ConstQualif;
 use middle::cstore::LOCAL_CRATE;
-use middle::const_eval::{self, ConstVal, ConstEvalErr};
-use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
-use middle::const_eval::{const_int_checked_add, const_uint_checked_add};
-use middle::const_eval::{const_int_checked_sub, const_uint_checked_sub};
-use middle::const_eval::{const_int_checked_mul, const_uint_checked_mul};
-use middle::const_eval::{const_int_checked_div, const_uint_checked_div};
-use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem};
-use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl};
-use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
+use middle::const_eval::{self, ConstEvalErr};
 use middle::def::Def;
 use middle::def_id::DefId;
 use trans::{adt, closure, debuginfo, expr, inline, machine};
 use middle::subst::Substs;
 use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
 use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
-use middle::ty::{self, Ty};
+use middle::ty::{self, Ty, TyCtxt};
 use middle::ty::cast::{CastTy,IntTy};
 use util::nodemap::NodeMap;
+use rustc_const_eval::{ConstInt, ConstMathErr, ConstUsize, ConstIsize};
 
 use rustc_front::hir;
 
@@ -234,7 +227,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 
     match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id), Some(param_substs)) {
-        Some(ref expr) => expr,
+        Some((ref expr, _ty)) => expr,
         None => {
             ccx.sess().span_bug(ref_expr.span, "constant item not found")
         }
@@ -469,35 +462,70 @@ fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
         // Catch this up front by looking for ExprLit directly,
         // and just accepting it.
         if let hir::ExprLit(_) = inner_e.node { return Ok(()); }
-
-        let result = match t.sty {
-            ty::TyInt(int_type) => {
-                let input = match const_to_opt_int(te) {
-                    Some(v) => v,
-                    None => return Ok(()),
-                };
-                const_int_checked_neg(
-                    input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
-            }
-            ty::TyUint(uint_type) => {
-                let input = match const_to_opt_uint(te) {
-                    Some(v) => v,
-                    None => return Ok(()),
-                };
-                const_uint_checked_neg(
-                    input, e, Some(const_eval::UintTy::from(cx.tcx(), uint_type)))
-            }
-            _ => return Ok(()),
+        let cval = match to_const_int(te, t, cx.tcx()) {
+            Some(v) => v,
+            None => return Ok(()),
         };
-        const_err(cx, e, result, trueconst)
+        match -cval {
+            Ok(_) => return Ok(()),
+            Err(err) => const_err(cx, e, Err(err), trueconst),
+        }
     } else {
         Ok(())
     }
 }
 
+fn to_const_int(value: ValueRef, t: Ty, tcx: &TyCtxt) -> Option<ConstInt> {
+    match t.sty {
+        ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type {
+            ast::IntTy::I8 => {
+                assert_eq!(input as i8 as i64, input);
+                Some(ConstInt::I8(input as i8))
+            },
+            ast::IntTy::I16 => {
+                assert_eq!(input as i16 as i64, input);
+                Some(ConstInt::I16(input as i16))
+            },
+            ast::IntTy::I32 => {
+                assert_eq!(input as i32 as i64, input);
+                Some(ConstInt::I32(input as i32))
+            },
+            ast::IntTy::I64 => {
+                Some(ConstInt::I64(input))
+            },
+            ast::IntTy::Is => {
+                ConstIsize::new(input, tcx.sess.target.int_type)
+                    .ok().map(ConstInt::Isize)
+            },
+        }),
+        ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type {
+            ast::UintTy::U8 => {
+                assert_eq!(input as u8 as u64, input);
+                Some(ConstInt::U8(input as u8))
+            },
+            ast::UintTy::U16 => {
+                assert_eq!(input as u16 as u64, input);
+                Some(ConstInt::U16(input as u16))
+            },
+            ast::UintTy::U32 => {
+                assert_eq!(input as u32 as u64, input);
+                Some(ConstInt::U32(input as u32))
+            },
+            ast::UintTy::U64 => {
+                Some(ConstInt::U64(input))
+            },
+            ast::UintTy::Us => {
+                ConstUsize::new(input, tcx.sess.target.uint_type)
+                    .ok().map(ConstInt::Usize)
+            },
+        }),
+        _ => None,
+    }
+}
+
 fn const_err(cx: &CrateContext,
              e: &hir::Expr,
-             result: Result<ConstVal, ConstEvalErr>,
+             result: Result<ConstInt, ConstMathErr>,
              trueconst: TrueConst)
              -> Result<(), ConstEvalFailure> {
     match (result, trueconst) {
@@ -506,10 +534,12 @@ fn const_err(cx: &CrateContext,
             Ok(())
         },
         (Err(err), TrueConst::Yes) => {
+            let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
             cx.tcx().sess.span_err(e.span, &err.description());
             Err(Compiletime(err))
         },
         (Err(err), TrueConst::No) => {
+            let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
             cx.tcx().sess.span_warn(e.span, &err.description());
             Err(Runtime(err))
         },
@@ -520,46 +550,18 @@ fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
                               te1: ValueRef, te2: ValueRef,
                               trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
     let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { unreachable!() };
-
-    let result = match t.sty {
-        ty::TyInt(int_type) => {
-            let (lhs, rhs) = match (const_to_opt_int(te1),
-                                    const_to_opt_int(te2)) {
-                (Some(v1), Some(v2)) => (v1, v2),
-                _ => return Ok(()),
-            };
-
-            let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type));
-            match b.node {
-                hir::BiAdd => const_int_checked_add(lhs, rhs, e, opt_ety),
-                hir::BiSub => const_int_checked_sub(lhs, rhs, e, opt_ety),
-                hir::BiMul => const_int_checked_mul(lhs, rhs, e, opt_ety),
-                hir::BiDiv => const_int_checked_div(lhs, rhs, e, opt_ety),
-                hir::BiRem => const_int_checked_rem(lhs, rhs, e, opt_ety),
-                hir::BiShl => const_int_checked_shl(lhs, rhs, e, opt_ety),
-                hir::BiShr => const_int_checked_shr(lhs, rhs, e, opt_ety),
-                _ => return Ok(()),
-            }
-        }
-        ty::TyUint(uint_type) => {
-            let (lhs, rhs) = match (const_to_opt_uint(te1),
-                                    const_to_opt_uint(te2)) {
-                (Some(v1), Some(v2)) => (v1, v2),
-                _ => return Ok(()),
-            };
-
-            let opt_ety = Some(const_eval::UintTy::from(cx.tcx(), uint_type));
-            match b.node {
-                hir::BiAdd => const_uint_checked_add(lhs, rhs, e, opt_ety),
-                hir::BiSub => const_uint_checked_sub(lhs, rhs, e, opt_ety),
-                hir::BiMul => const_uint_checked_mul(lhs, rhs, e, opt_ety),
-                hir::BiDiv => const_uint_checked_div(lhs, rhs, e, opt_ety),
-                hir::BiRem => const_uint_checked_rem(lhs, rhs, e, opt_ety),
-                hir::BiShl => const_uint_checked_shl(lhs, rhs, e, opt_ety),
-                hir::BiShr => const_uint_checked_shr(lhs, rhs, e, opt_ety),
-                _ => return Ok(()),
-            }
-        }
+    let (lhs, rhs) = match (to_const_int(te1, t, cx.tcx()), to_const_int(te2, t, cx.tcx())) {
+        (Some(v1), Some(v2)) => (v1, v2),
+        _ => return Ok(()),
+    };
+    let result = match b.node {
+        hir::BiAdd => lhs + rhs,
+        hir::BiSub => lhs - rhs,
+        hir::BiMul => lhs * rhs,
+        hir::BiDiv => lhs / rhs,
+        hir::BiRem => lhs % rhs,
+        hir::BiShl => lhs << rhs,
+        hir::BiShr => lhs >> rhs,
         _ => return Ok(()),
     };
     const_err(cx, e, result, trueconst)
index 0cd1f4e7fbf3e184dda828212ac17ec4bf06d19a..e22d42e9d28da5f7f9faa28a363115cf7226c25b 100644 (file)
@@ -1597,7 +1597,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 llvm::LLVMDIBuilderCreateEnumerator(
                     DIB(cx),
                     name.as_ptr(),
-                    v.disr_val as u64)
+                    v.disr_val.to_u64_unchecked())
             }
         })
         .collect();
index 38e456c068829ee6b9add7189ec8cebbfbd3e8db..0c512200ff3d560ad19708b950e7978896340568 100644 (file)
@@ -22,6 +22,7 @@
 use llvm::{self, ValueRef};
 use middle::ty;
 use middle::infer;
+use middle::traits::ProjectionMode;
 use syntax::abi::Abi;
 use trans::attributes;
 use trans::base;
@@ -111,7 +112,9 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
             (&f.sig, f.abi, None)
         }
         ty::TyClosure(closure_did, ref substs) => {
-            let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
+            let infcx = infer::normalizing_infer_ctxt(ccx.tcx(),
+                                                      &ccx.tcx().tables,
+                                                      ProjectionMode::Any);
             function_type = infcx.closure_type(closure_did, substs);
             let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
             let llenvironment_type = type_of::type_of_explicit_arg(ccx, self_type);
index 7cb10a8bc44c44555e223950edbdefe044308ee2..d74c1ac50ad74b14ec703ab494c53adb356c0178 100644 (file)
@@ -26,7 +26,7 @@ fn bitand(self, other: Self) -> Self {
 
 impl From<::middle::ty::Disr> for Disr {
     fn from(i: ::middle::ty::Disr) -> Disr {
-        Disr(i)
+        Disr(i.to_u64_unchecked())
     }
 }
 
index 96c1d6a4d691a4ba74a0dea7cb2e3fb15268498f..ac1d34f17064eb050d991efc3b8a79ef108538a5 100644 (file)
@@ -609,7 +609,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         (_, "volatile_store") => {
             let tp_ty = *substs.types.get(FnSpace, 0);
             let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
-            let val = from_arg_ty(bcx, llargs[1], tp_ty);
+            let val = if type_is_immediate(bcx.ccx(), tp_ty) {
+                from_arg_ty(bcx, llargs[1], tp_ty)
+            } else {
+                Load(bcx, llargs[1])
+            };
             let store = VolatileStore(bcx, val, ptr);
             unsafe {
                 llvm::LLVMSetAlignment(store, type_of::align_of(ccx, tp_ty));
index 78b86dafa18ad83dd31172f1930d6036fb916f5e..7397ccc2505f173a3d984591ad7f9ad5645fdfc4 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::rc::Rc;
+
 use arena::TypedArena;
 use back::link;
 use llvm::{ValueRef, get_params};
@@ -15,7 +17,7 @@
 use middle::infer;
 use middle::subst::{Subst, Substs};
 use middle::subst;
-use middle::traits;
+use middle::traits::{self, ProjectionMode};
 use trans::base::*;
 use trans::build::*;
 use trans::callee::{Callee, Virtual, ArgVals,
@@ -31,9 +33,9 @@
 use trans::machine;
 use trans::type_::Type;
 use trans::type_of::*;
-use middle::ty::{self, Ty, TyCtxt};
+use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 
-use syntax::ast;
+use syntax::ast::{self, Name};
 use syntax::attr;
 use syntax::codemap::DUMMY_SP;
 
@@ -107,7 +109,7 @@ pub fn callee_for_trait_impl<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             // those from the impl and those from the method:
             let impl_substs = vtable_impl.substs.with_method_from(&substs);
             let substs = ccx.tcx().mk_substs(impl_substs);
-            let mth = ccx.tcx().get_impl_method(impl_did, substs, mname);
+            let mth = get_impl_method(ccx.tcx(), impl_did, substs, mname);
 
             // Translate the function, bypassing Callee::def.
             // That is because default methods have the same ID as the
@@ -315,7 +317,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 trans_fn_ref_with_substs(ccx,
                                                          mth.method.def_id,
                                                          None,
-                                                         mth.substs).val
+                                                         &mth.substs).val
                             }
                             None => nullptr
                         }
@@ -378,7 +380,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                     impl_id: DefId,
                                     substs: &'tcx subst::Substs<'tcx>)
-                                    -> Vec<Option<ty::util::ImplMethod<'tcx>>>
+                                    -> Vec<Option<ImplMethod<'tcx>>>
 {
     let tcx = ccx.tcx();
 
@@ -428,7 +430,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
             // The substitutions we have are on the impl, so we grab
             // the method type from the impl to substitute into.
-            let mth = tcx.get_impl_method(impl_id, substs, name);
+            let mth = get_impl_method(tcx, impl_id, substs, name);
 
             debug!("get_vtable_methods: mth={:?}", mth);
 
@@ -438,7 +440,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             // method could then never be called, so we do not want to
             // try and trans it, in that case. Issue #23435.
             if mth.is_provided {
-                let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
+                let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
                 if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
                     debug!("get_vtable_methods: predicates do not hold");
                     return None;
@@ -466,3 +468,37 @@ fn opaque_method_ty<'tcx>(tcx: &TyCtxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
         }),
     })
 }
+
+#[derive(Debug)]
+pub struct ImplMethod<'tcx> {
+    pub method: Rc<ty::Method<'tcx>>,
+    pub substs: &'tcx Substs<'tcx>,
+    pub is_provided: bool
+}
+
+/// Locates the applicable definition of a method, given its name.
+pub fn get_impl_method<'tcx>(tcx: &TyCtxt<'tcx>,
+                             impl_def_id: DefId,
+                             substs: &'tcx Substs<'tcx>,
+                             name: Name)
+                             -> ImplMethod<'tcx>
+{
+    assert!(!substs.types.needs_infer());
+
+    let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
+    let trait_def = tcx.lookup_trait_def(trait_def_id);
+    let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
+
+    match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
+        Some(node_item) => {
+            ImplMethod {
+                method: node_item.item,
+                substs: traits::translate_substs(&infcx, impl_def_id, substs, node_item.node),
+                is_provided: node_item.node.is_from_trait(),
+            }
+        }
+        None => {
+            tcx.sess.bug(&format!("method {:?} not found in {:?}", name, impl_def_id))
+        }
+    }
+}
index a0615a6cf5b18041c5e57e78e30cc3e10c3e9a95..c20d8b01eb773ab3e5d7604775822502324b3e6e 100644 (file)
@@ -12,6 +12,7 @@
 use llvm::ValueRef;
 use middle::ty::{Ty, TypeFoldable};
 use rustc::middle::const_eval::{self, ConstVal};
+use rustc_const_eval::ConstInt::*;
 use rustc::mir::repr as mir;
 use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
                     C_str_slice, C_nil, C_undef};
@@ -19,6 +20,7 @@
 use trans::expr;
 use trans::inline;
 use trans::type_of;
+use trans::type_::Type;
 
 use super::operand::{OperandRef, OperandValue};
 use super::MirContext;
@@ -63,8 +65,24 @@ fn trans_constval_inner(&mut self,
         match *cv {
             ConstVal::Float(v) => C_floating_f64(v, llty),
             ConstVal::Bool(v) => C_bool(ccx, v),
-            ConstVal::Int(v) => C_integral(llty, v as u64, true),
-            ConstVal::Uint(v) => C_integral(llty, v, false),
+            ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true),
+            ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true),
+            ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true),
+            ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true),
+            ConstVal::Integral(Isize(v)) => {
+                let i = v.as_i64(ccx.tcx().sess.target.int_type);
+                C_integral(Type::int(ccx), i as u64, true)
+            },
+            ConstVal::Integral(U8(v)) => C_integral(Type::i8(ccx), v as u64, false),
+            ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false),
+            ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false),
+            ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false),
+            ConstVal::Integral(Usize(v)) => {
+                let u = v.as_u64(ccx.tcx().sess.target.uint_type);
+                C_integral(Type::int(ccx), u, false)
+            },
+            ConstVal::Integral(Infer(v)) => C_integral(llty, v as u64, false),
+            ConstVal::Integral(InferSigned(v)) => C_integral(llty, v as u64, true),
             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
             ConstVal::Struct(id) | ConstVal::Tuple(id) |
@@ -74,6 +92,8 @@ fn trans_constval_inner(&mut self,
                     expr::trans(bcx, expr).datum.val
                 })
             },
+            ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
+            ConstVal::Dummy => unreachable!(),
             ConstVal::Function(_) => C_nil(ccx)
         }
     }
@@ -99,7 +119,7 @@ pub fn trans_constant(&mut self,
                 let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs));
                 let def_id = inline::maybe_instantiate_inline(bcx.ccx(), def_id);
                 let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, None, Some(substs))
-                            .expect("def was const, but lookup_const_by_id failed");
+                            .expect("def was const, but lookup_const_by_id failed").0;
                 // FIXME: this is falling back to translating from HIR. This is not easy to fix,
                 // because we would have somehow adapt const_eval to work on MIR rather than HIR.
                 let d = bcx.with_block(|bcx| {
index ce10ed425f63afe92ff8b15425ee77910d5cc47e..ea80af14f1f2f18528d3470aca9ddab0d5124d71 100644 (file)
@@ -11,6 +11,8 @@
 use llvm::ValueRef;
 use rustc::middle::ty::{self, Ty};
 use middle::ty::cast::{CastTy, IntTy};
+use middle::const_eval::ConstVal;
+use rustc_const_eval::ConstInt;
 use rustc::mir::repr as mir;
 
 use trans::asm;
@@ -95,7 +97,8 @@ pub fn trans_rvalue(&mut self,
 
             mir::Rvalue::Repeat(ref elem, ref count) => {
                 let tr_elem = self.trans_operand(&bcx, elem);
-                let size = self.trans_constval(&bcx, &count.value, count.ty).immediate();
+                let count = ConstVal::Integral(ConstInt::Usize(count.value));
+                let size = self.trans_constval(&bcx, &count, bcx.tcx().types.usize).immediate();
                 let bcx = bcx.map_block(|block| {
                     let base = expr::get_dataptr(block, dest.llval);
                     tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| {
index fd33e9da1f93786acdce840e06917d915448dec4..1c907972863b6422878adaad1759ea8aaac0d195 100644 (file)
@@ -15,5 +15,6 @@ arena = { path = "../libarena" }
 fmt_macros = { path = "../libfmt_macros" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_front = { path = "../librustc_front" }
 rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
index 1938fa7582918dc57836f5d4453d9ac4757c07da..ba56c5d24ab6e286a431f1cbad2dc4527c719ed5 100644 (file)
@@ -65,6 +65,8 @@
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::FnvHashSet;
 
+use rustc_const_eval::ConstInt;
+
 use syntax::{abi, ast};
 use syntax::codemap::{Span, Pos};
 use syntax::errors::DiagnosticBuilder;
@@ -1680,22 +1682,16 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
         hir::TyFixedLengthVec(ref ty, ref e) => {
             let hint = UncheckedExprHint(tcx.types.usize);
             match const_eval::eval_const_expr_partial(tcx, &e, hint, None) {
-                Ok(r) => {
-                    match r {
-                        ConstVal::Int(i) =>
-                            tcx.mk_array(ast_ty_to_ty(this, rscope, &ty),
-                                         i as usize),
-                        ConstVal::Uint(i) =>
-                            tcx.mk_array(ast_ty_to_ty(this, rscope, &ty),
-                                         i as usize),
-                        _ => {
-                            span_err!(tcx.sess, ast_ty.span, E0249,
-                                      "expected constant integer expression \
-                                       for array length");
-                            this.tcx().types.err
-                        }
-                    }
-                }
+                Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
+                    let i = i.as_u64(tcx.sess.target.uint_type);
+                    assert_eq!(i as usize as u64, i);
+                    tcx.mk_array(ast_ty_to_ty(this, rscope, &ty), i as usize)
+                },
+                Ok(val) => {
+                    span_err!(tcx.sess, ast_ty.span, E0249,
+                              "expected usize value for array length, got {}", val.description());
+                    this.tcx().types.err
+                },
                 Err(ref r) => {
                     let mut err = struct_span_err!(tcx.sess, r.span, E0250,
                                                    "array length constant evaluation error: {}",
index b5cd5d7f8e5a38d391ab2f056ff70de16cc60d56..31c0fea5c2d97229bdb3f199edf4d51d7046a1f2 100644 (file)
@@ -100,6 +100,8 @@ enum CastError {
     CastToBool,
     CastToChar,
     DifferingKinds,
+    /// Cast of thin to fat raw ptr (eg. `*const () as *const [u8]`)
+    SizedUnsizedCast,
     IllegalCast,
     NeedViaPtr,
     NeedViaThinPtr,
@@ -165,6 +167,13 @@ fn report_cast_error<'a>(&self, fcx: &FnCtxt<'a, 'tcx>,
                             fcx.infcx().ty_to_string(self.cast_ty))
                 }, self.expr_ty, None);
             }
+            CastError::SizedUnsizedCast => {
+                fcx.type_error_message(self.span, |actual| {
+                    format!("cannot cast thin pointer `{}` to fat pointer `{}`",
+                            actual,
+                            fcx.infcx().ty_to_string(self.cast_ty))
+                }, self.expr_ty, None)
+            }
             CastError::DifferingKinds => {
                 fcx.type_error_struct(self.span, |actual| {
                     format!("casting `{}` as `{}` is invalid",
@@ -312,7 +321,7 @@ fn check_ptr_ptr_cast<'a>(&self,
 
         // sized -> unsized? report invalid cast (don't complain about vtable kinds)
         if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
-            return Err(CastError::IllegalCast);
+            return Err(CastError::SizedUnsizedCast);
         }
 
         // vtable kinds must match
index ff7b809577f64a693f13d36fc1e7be3ac7efcea7..899f79b3dff94f1dd1729ee231d2f9001b27484a 100644 (file)
@@ -10,8 +10,8 @@
 
 use middle::free_region::FreeRegionMap;
 use middle::infer::{self, TypeOrigin};
-use middle::traits;
 use middle::ty::{self, TyCtxt};
+use middle::traits::{self, ProjectionMode};
 use middle::subst::{self, Subst, Substs, VecPerParamSpace};
 
 use syntax::ast;
@@ -42,7 +42,7 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>,
     debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
            impl_trait_ref);
 
-    let mut infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
+    let mut infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
     let mut fulfillment_cx = traits::FulfillmentContext::new();
 
     let trait_to_impl_substs = &impl_trait_ref.substs;
@@ -416,7 +416,7 @@ pub fn compare_const_impl<'tcx>(tcx: &TyCtxt<'tcx>,
     debug!("compare_const_impl(impl_trait_ref={:?})",
            impl_trait_ref);
 
-    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
+    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
     let mut fulfillment_cx = traits::FulfillmentContext::new();
 
     // The below is for the most part highly similar to the procedure
index 4ebe4c25dd1d3799f3c813f1045fa5ceeb93963c..4ed1bab46b2d9664be25848b6434d736ff6fe5f6 100644 (file)
@@ -15,8 +15,8 @@
 use middle::infer;
 use middle::region;
 use middle::subst::{self, Subst};
-use middle::traits;
 use middle::ty::{self, Ty, TyCtxt};
+use middle::traits::{self, ProjectionMode};
 use util::nodemap::FnvHashSet;
 
 use syntax::ast;
@@ -82,7 +82,10 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
     // check that the impl type can be made to match the trait type.
 
     let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
-    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(impl_param_env));
+    let infcx = infer::new_infer_ctxt(tcx,
+                                      &tcx.tables,
+                                      Some(impl_param_env),
+                                      ProjectionMode::AnyFinal);
     let mut fulfillment_cx = traits::FulfillmentContext::new();
 
     let named_type = tcx.lookup_item_type(self_type_did).ty;
index 0743c0b9e187b560da663928c4c773b9a7234e7d..0d5e25efd68c91b93f88f37c0ba5c03d4e470e55 100644 (file)
@@ -92,9 +92,9 @@
 use middle::infer::{TypeOrigin, TypeTrace, type_variable};
 use middle::pat_util::{self, pat_id_map};
 use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
-use middle::traits::{self, report_fulfillment_errors};
+use middle::traits::{self, report_fulfillment_errors, ProjectionMode};
 use middle::ty::{GenericPredicates, TypeScheme};
-use middle::ty::{Disr, ParamTy, ParameterEnvironment};
+use middle::ty::{ParamTy, ParameterEnvironment};
 use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
 use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt};
 use middle::ty::{MethodCall, MethodCallee};
 use middle::ty::error::TypeError;
 use middle::ty::fold::{TypeFolder, TypeFoldable};
 use middle::ty::relate::TypeRelation;
-use middle::ty::util::Representability;
+use middle::ty::util::{Representability, IntTypeExt};
 use require_c_abi_if_variadic;
 use rscope::{ElisionFailureInfo, RegionScope};
 use session::{Session, CompileResult};
@@ -307,7 +307,7 @@ fn new(tcx: &'a TyCtxt<'tcx>,
            -> Inherited<'a, 'tcx> {
 
         Inherited {
-            infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env)),
+            infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env), ProjectionMode::AnyFinal),
             fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
             locals: RefCell::new(NodeMap()),
             tables: tables,
@@ -672,10 +672,12 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
       hir::ItemFn(..) => {} // entirely within check_item_body
       hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
           debug!("ItemImpl {} with id {}", it.name, it.id);
-          match ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(it.id)) {
+          let impl_def_id = ccx.tcx.map.local_def_id(it.id);
+          match ccx.tcx.impl_trait_ref(impl_def_id) {
               Some(impl_trait_ref) => {
                 check_impl_items_against_trait(ccx,
                                                it.span,
+                                               impl_def_id,
                                                &impl_trait_ref,
                                                impl_items);
               }
@@ -862,12 +864,71 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     check_bare_fn(ccx, &sig.decl, body, id, span, fty, param_env);
 }
 
+fn report_forbidden_specialization(tcx: &TyCtxt,
+                                   impl_item: &hir::ImplItem,
+                                   parent_impl: DefId)
+{
+    let mut err = struct_span_err!(
+        tcx.sess, impl_item.span, E0520,
+        "item `{}` is provided by an `impl` that specializes \
+         another, but the item in the parent `impl` is not \
+         marked `default` and so it cannot be specialized.",
+        impl_item.name);
+
+    match tcx.span_of_impl(parent_impl) {
+        Ok(span) => {
+            err.span_note(span, "parent implementation is here:");
+        }
+        Err(cname) => {
+            err.note(&format!("parent implementation is in crate `{}`", cname));
+        }
+    }
+
+    err.emit();
+}
+
+fn check_specialization_validity<'tcx>(tcx: &TyCtxt<'tcx>, trait_def: &ty::TraitDef<'tcx>,
+                                       impl_id: DefId, impl_item: &hir::ImplItem)
+{
+    let ancestors = trait_def.ancestors(impl_id);
+
+    let parent = match impl_item.node {
+        hir::ImplItemKind::Const(..) => {
+            ancestors.const_defs(tcx, impl_item.name).skip(1).next()
+                .map(|node_item| node_item.map(|parent| parent.defaultness))
+        }
+        hir::ImplItemKind::Method(..) => {
+            ancestors.fn_defs(tcx, impl_item.name).skip(1).next()
+                .map(|node_item| node_item.map(|parent| parent.defaultness))
+
+        }
+        hir::ImplItemKind::Type(_) => {
+            ancestors.type_defs(tcx, impl_item.name).skip(1).next()
+                .map(|node_item| node_item.map(|parent| parent.defaultness))
+        }
+    };
+
+    if let Some(parent) = parent {
+        if parent.item.is_final() {
+            report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
+        }
+    }
+
+}
+
 fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                             impl_span: Span,
+                                            impl_id: DefId,
                                             impl_trait_ref: &ty::TraitRef<'tcx>,
                                             impl_items: &[hir::ImplItem]) {
-    // Locate trait methods
+    // If the trait reference itself is erroneous (so the compilation is going
+    // to fail), skip checking the items here -- the `impl_item` table in `tcx`
+    // isn't populated for such impls.
+    if impl_trait_ref.references_error() { return; }
+
+    // Locate trait definition and items
     let tcx = ccx.tcx;
+    let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id);
     let trait_items = tcx.trait_items(impl_trait_ref.def_id);
     let mut overridden_associated_type = None;
 
@@ -878,6 +939,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let ty_trait_item = trait_items.iter()
             .find(|ac| ac.name() == ty_impl_item.name());
 
+        // Check that impl definition matches trait definition
         if let Some(ty_trait_item) = ty_trait_item {
             match impl_item.node {
                 hir::ImplItemKind::Const(..) => {
@@ -944,6 +1006,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 }
             }
         }
+
+        check_specialization_validity(tcx, trait_def, impl_id, impl_item);
     }
 
     // Check for missing items from trait
@@ -952,9 +1016,13 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let mut invalidated_items = Vec::new();
     let associated_type_overridden = overridden_associated_type.is_some();
     for trait_item in trait_items.iter() {
+        let is_implemented;
+        let is_provided;
+
         match *trait_item {
             ty::ConstTraitItem(ref associated_const) => {
-                let is_implemented = impl_items.iter().any(|ii| {
+                is_provided = associated_const.has_value;
+                is_implemented = impl_items.iter().any(|ii| {
                     match ii.node {
                         hir::ImplItemKind::Const(..) => {
                             ii.name == associated_const.name
@@ -962,53 +1030,30 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         _ => false,
                     }
                 });
-                let is_provided = associated_const.has_value;
-
-                if !is_implemented {
-                    if !is_provided {
-                        missing_items.push(associated_const.name);
-                    } else if associated_type_overridden {
-                        invalidated_items.push(associated_const.name);
-                    }
-                }
             }
             ty::MethodTraitItem(ref trait_method) => {
-                let is_implemented =
-                    impl_items.iter().any(|ii| {
-                        match ii.node {
-                            hir::ImplItemKind::Method(..) => {
-                                ii.name == trait_method.name
-                            }
-                            _ => false,
-                        }
-                    });
-                let is_provided =
-                    provided_methods.iter().any(|m| m.name == trait_method.name);
-                if !is_implemented {
-                    if !is_provided {
-                        missing_items.push(trait_method.name);
-                    } else if associated_type_overridden {
-                        invalidated_items.push(trait_method.name);
-                    }
-                }
+                is_provided = provided_methods.iter().any(|m| m.name == trait_method.name);
+                is_implemented = trait_def.ancestors(impl_id)
+                    .fn_defs(tcx, trait_method.name)
+                    .next()
+                    .map(|node_item| !node_item.node.is_from_trait())
+                    .unwrap_or(false);
             }
-            ty::TypeTraitItem(ref associated_type) => {
-                let is_implemented = impl_items.iter().any(|ii| {
-                    match ii.node {
-                        hir::ImplItemKind::Type(_) => {
-                            ii.name == associated_type.name
-                        }
-                        _ => false,
-                    }
-                });
-                let is_provided = associated_type.ty.is_some();
-                if !is_implemented {
-                    if !is_provided {
-                        missing_items.push(associated_type.name);
-                    } else if associated_type_overridden {
-                        invalidated_items.push(associated_type.name);
-                    }
-                }
+            ty::TypeTraitItem(ref trait_assoc_ty) => {
+                is_provided = trait_assoc_ty.ty.is_some();
+                is_implemented = trait_def.ancestors(impl_id)
+                    .type_defs(tcx, trait_assoc_ty.name)
+                    .next()
+                    .map(|node_item| !node_item.node.is_from_trait())
+                    .unwrap_or(false);
+            }
+        }
+
+        if !is_implemented {
+            if !is_provided {
+                missing_items.push(trait_item.name());
+            } else if associated_type_overridden {
+                invalidated_items.push(trait_item.name());
             }
         }
     }
@@ -4076,34 +4121,6 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                                     sp: Span,
                                     vs: &'tcx [hir::Variant],
                                     id: ast::NodeId) {
-    // disr_in_range should be removed once we have forced type hints for consts
-    fn disr_in_range(ccx: &CrateCtxt,
-                     ty: attr::IntType,
-                     disr: ty::Disr) -> bool {
-        fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
-            match ty {
-                ast::UintTy::U8 => disr as u8 as Disr == disr,
-                ast::UintTy::U16 => disr as u16 as Disr == disr,
-                ast::UintTy::U32 => disr as u32 as Disr == disr,
-                ast::UintTy::U64 => disr as u64 as Disr == disr,
-                ast::UintTy::Us => uint_in_range(ccx, ccx.tcx.sess.target.uint_type, disr)
-            }
-        }
-        fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
-            match ty {
-                ast::IntTy::I8 => disr as i8 as Disr == disr,
-                ast::IntTy::I16 => disr as i16 as Disr == disr,
-                ast::IntTy::I32 => disr as i32 as Disr == disr,
-                ast::IntTy::I64 => disr as i64 as Disr == disr,
-                ast::IntTy::Is => int_in_range(ccx, ccx.tcx.sess.target.int_type, disr)
-            }
-        }
-        match ty {
-            attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
-            attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
-        }
-    }
-
     fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                           vs: &'tcx [hir::Variant],
                           id: ast::NodeId,
@@ -4117,7 +4134,7 @@ fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let inh = static_inherited_fields(ccx, &tables);
         let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id);
 
-        let (_, repr_type_ty) = ccx.tcx.enum_repr_type(Some(&hint));
+        let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(&ccx.tcx);
         for v in vs {
             if let Some(ref e) = v.node.disr_expr {
                 check_const_with_ty(&fcx, e.span, e, repr_type_ty);
@@ -4142,23 +4159,7 @@ fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 }
                 None => {}
             }
-            // Check for unrepresentable discriminant values
-            match hint {
-                attr::ReprAny | attr::ReprExtern => {
-                    disr_vals.push(current_disr_val);
-                }
-                attr::ReprInt(sp, ity) => {
-                    if !disr_in_range(ccx, ity, current_disr_val) {
-                        let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0082,
-                            "discriminant value outside specified type");
-                        span_note!(&mut err, sp,
-                            "discriminant type specified here");
-                        err.emit();
-                    }
-                }
-                // Error reported elsewhere.
-                attr::ReprSimd | attr::ReprPacked => {}
-            }
+            disr_vals.push(current_disr_val);
         }
     }
 
index 9dc8d7ae943a110ace0790197552e9f4d90afa1d..278d4d8b5b44a41fa378e5e0602babfd408d7821 100644 (file)
 // done by the orphan and overlap modules. Then we build up various
 // mappings. That mapping code resides here.
 
-
 use middle::def_id::DefId;
 use middle::lang_items::UnsizeTraitLangItem;
 use middle::subst::{self, Subst};
-use middle::traits;
 use middle::ty::{self, TyCtxt, TypeFoldable};
+use middle::traits::{self, ProjectionMode};
 use middle::ty::{ImplOrTraitItemId, ConstTraitItemId};
 use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
 use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
@@ -197,7 +196,7 @@ fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId)
         debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
                impl_trait_ref, impl_def_id);
         let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
-        trait_def.record_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
+        trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
     }
 
     // Converts an implementation in the AST to a vector of items.
@@ -385,7 +384,7 @@ fn check_implementations_of_coerce_unsized(&self) {
             debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
                    source, target);
 
-            let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
+            let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env), ProjectionMode::Topmost);
 
             let origin = TypeOrigin::Misc(span);
             let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>,
@@ -530,7 +529,10 @@ pub fn report_duplicate_item<'tcx>(tcx: &TyCtxt<'tcx>, sp: Span, name: ast::Name
 
 pub fn check_coherence(crate_context: &CrateCtxt) {
     let _task = crate_context.tcx.dep_graph.in_task(DepNode::Coherence);
-    let infcx = new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None);
+    let infcx = new_infer_ctxt(crate_context.tcx,
+                               &crate_context.tcx.tables,
+                               None,
+                               ProjectionMode::Topmost);
     CoherenceChecker {
         crate_context: crate_context,
         inference_context: infcx,
index 80430076f197d6294d6403ff043f8ea0590e94a8..f7fa3e1b1429aa0c02773cfe70ef9f7732f90fd5 100644 (file)
 //! same type. Likewise, no two inherent impls for a given type
 //! constructor provide a method with the same name.
 
-use middle::cstore::{CrateStore, LOCAL_CRATE};
+use middle::cstore::CrateStore;
 use middle::def_id::DefId;
-use middle::traits;
-use middle::ty::{self, TyCtxt};
+use middle::traits::{self, ProjectionMode};
 use middle::infer;
+use middle::ty::{self, TyCtxt};
 use syntax::ast;
 use syntax::codemap::Span;
 use rustc::dep_graph::DepNode;
 use rustc_front::hir;
 use rustc_front::intravisit;
-use util::nodemap::{DefIdMap, DefIdSet};
+use util::nodemap::DefIdMap;
 
 pub fn check(tcx: &TyCtxt) {
     let mut overlap = OverlapChecker { tcx: tcx,
-                                       traits_checked: DefIdSet(),
                                        default_impls: DefIdMap() };
 
     // this secondary walk specifically checks for some other cases,
@@ -37,134 +36,11 @@ pub fn check(tcx: &TyCtxt) {
 struct OverlapChecker<'cx, 'tcx:'cx> {
     tcx: &'cx TyCtxt<'tcx>,
 
-    // The set of traits where we have checked for overlap.  This is
-    // used to avoid checking the same trait twice.
-    //
-    // NB. It's ok to skip tracking this set because we fully
-    // encapsulate it, and we always create a task
-    // (`CoherenceOverlapCheck`) corresponding to each entry.
-    traits_checked: DefIdSet,
-
     // maps from a trait def-id to an impl id
     default_impls: DefIdMap<ast::NodeId>,
 }
 
 impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
-    fn check_for_overlapping_impls_of_trait(&mut self, trait_def_id: DefId) {
-        debug!("check_for_overlapping_impls_of_trait(trait_def_id={:?})",
-               trait_def_id);
-
-        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
-        if !self.traits_checked.insert(trait_def_id) {
-            return;
-        }
-
-        let trait_def = self.tcx.lookup_trait_def(trait_def_id);
-        self.tcx.populate_implementations_for_trait_if_necessary(
-            trait_def.trait_ref.def_id);
-
-        // We should already know all impls of this trait, so these
-        // borrows are safe.
-        let (blanket_impls, nonblanket_impls) = trait_def.borrow_impl_lists(self.tcx);
-
-        // Conflicts can only occur between a blanket impl and another impl,
-        // or between 2 non-blanket impls of the same kind.
-
-        for (i, &impl1_def_id) in blanket_impls.iter().enumerate() {
-            for &impl2_def_id in &blanket_impls[(i+1)..] {
-                self.check_if_impls_overlap(impl1_def_id,
-                                            impl2_def_id);
-            }
-
-            for v in nonblanket_impls.values() {
-                for &impl2_def_id in v {
-                    self.check_if_impls_overlap(impl1_def_id,
-                                                impl2_def_id);
-                }
-            }
-        }
-
-        for impl_group in nonblanket_impls.values() {
-            for (i, &impl1_def_id) in impl_group.iter().enumerate() {
-                for &impl2_def_id in &impl_group[(i+1)..] {
-                    self.check_if_impls_overlap(impl1_def_id,
-                                                impl2_def_id);
-                }
-            }
-        }
-    }
-
-    // We need to coherently pick which impl will be displayed
-    // as causing the error message, and it must be the in the current
-    // crate. Just pick the smaller impl in the file.
-    fn order_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId)
-            -> Option<(DefId, DefId)> {
-        if impl1_def_id.krate != LOCAL_CRATE {
-            if impl2_def_id.krate != LOCAL_CRATE {
-                // we don't need to check impls if both are external;
-                // that's the other crate's job.
-                None
-            } else {
-                Some((impl2_def_id, impl1_def_id))
-            }
-        } else if impl2_def_id.krate != LOCAL_CRATE {
-            Some((impl1_def_id, impl2_def_id))
-        } else if impl1_def_id < impl2_def_id {
-            Some((impl1_def_id, impl2_def_id))
-        } else {
-            Some((impl2_def_id, impl1_def_id))
-        }
-    }
-
-    fn check_if_impls_overlap(&self,
-                              impl1_def_id: DefId,
-                              impl2_def_id: DefId)
-    {
-        if let Some((impl1_def_id, impl2_def_id)) = self.order_impls(
-            impl1_def_id, impl2_def_id)
-        {
-            debug!("check_if_impls_overlap({:?}, {:?})",
-                   impl1_def_id,
-                   impl2_def_id);
-
-            let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
-            if let Some(header) = traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
-                self.report_overlap_error(impl1_def_id, impl2_def_id, header.trait_ref.unwrap());
-            }
-        }
-    }
-
-    fn report_overlap_error(&self,
-                            impl1: DefId,
-                            impl2: DefId,
-                            trait_ref: ty::TraitRef)
-    {
-        // only print the Self type if it's concrete; otherwise, it's not adding much information.
-        let self_type = {
-            trait_ref.substs.self_ty().and_then(|ty| {
-                if let ty::TyInfer(_) = ty.sty {
-                    None
-                } else {
-                    Some(format!(" for type `{}`", ty))
-                }
-            }).unwrap_or(String::new())
-        };
-
-        let mut err = struct_span_err!(self.tcx.sess, self.span_of_def_id(impl1), E0119,
-                                       "conflicting implementations of trait `{}`{}:",
-                                       trait_ref,
-                                       self_type);
-
-        if impl2.is_local() {
-            span_note!(&mut err, self.span_of_def_id(impl2),
-                       "conflicting implementation is here:");
-        } else {
-            let cname = self.tcx.sess.cstore.crate_name(impl2.krate);
-            err.note(&format!("conflicting implementation in crate `{}`", cname));
-        }
-        err.emit();
-    }
-
     fn span_of_def_id(&self, did: DefId) -> Span {
         let node_id = self.tcx.map.as_local_node_id(did).unwrap();
         self.tcx.map.span(node_id)
@@ -213,7 +89,10 @@ 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)..] {
-                let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
+                let infcx = infer::new_infer_ctxt(self.tcx,
+                                                  &self.tcx.tables,
+                                                  None,
+                                                  ProjectionMode::Topmost);
                 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)
                 }
@@ -222,15 +101,9 @@ fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
     }
 }
 
-
 impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
-            hir::ItemTrait(..) => {
-                let trait_def_id = self.tcx.map.local_def_id(item.id);
-                self.check_for_overlapping_impls_of_trait(trait_def_id);
-            }
-
             hir::ItemEnum(..) | hir::ItemStruct(..) => {
                 let type_def_id = self.tcx.map.local_def_id(item.id);
                 self.check_for_overlapping_inherent_impls(type_def_id);
@@ -243,50 +116,90 @@ fn visit_item(&mut self, item: &'v hir::Item) {
                 let impl_def_id = self.tcx.map.local_def_id(item.id);
                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
 
-                self.check_for_overlapping_impls_of_trait(trait_ref.def_id);
-
                 let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
-                match prev_default_impl {
-                    Some(prev_id) => {
-                        self.report_overlap_error(impl_def_id,
-                                                  self.tcx.map.local_def_id(prev_id),
-                                                  trait_ref);
-                    }
-                    None => { }
+                if let Some(prev_id) = prev_default_impl {
+                    let mut err = struct_span_err!(
+                        self.tcx.sess,
+                        self.tcx.span_of_impl(impl_def_id).unwrap(), E0521,
+                        "redundant default implementations of trait `{}`:",
+                        trait_ref);
+                    err.span_note(self.tcx.span_of_impl(self.tcx.map.local_def_id(prev_id))
+                                      .unwrap(),
+                                  "redundant implementation is here:");
+                    err.emit();
                 }
             }
             hir::ItemImpl(_, _, _, Some(_), _, _) => {
                 let impl_def_id = self.tcx.map.local_def_id(item.id);
                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                 let trait_def_id = trait_ref.def_id;
-                self.check_for_overlapping_impls_of_trait(trait_def_id);
-                match trait_ref.self_ty().sty {
-                    ty::TyTrait(ref data) => {
-                        // This is something like impl Trait1 for Trait2. Illegal
-                        // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
 
-                        if !traits::is_object_safe(self.tcx, data.principal_def_id()) {
-                            // This is an error, but it will be
-                            // reported by wfcheck.  Ignore it
-                            // here. This is tested by
-                            // `coherence-impl-trait-for-trait-object-safe.rs`.
-                        } else {
-                            let mut supertrait_def_ids =
-                                traits::supertrait_def_ids(self.tcx, data.principal_def_id());
-                            if supertrait_def_ids.any(|d| d == trait_def_id) {
-                                span_err!(self.tcx.sess, item.span, E0371,
-                                          "the object type `{}` automatically \
-                                           implements the trait `{}`",
-                                          trait_ref.self_ty(),
-                                          self.tcx.item_path_str(trait_def_id));
+                let _task = self.tcx.dep_graph.in_task(
+                    DepNode::CoherenceOverlapCheck(trait_def_id));
+
+                let def = self.tcx.lookup_trait_def(trait_def_id);
+
+                // attempt to insert into the specialization graph
+                let insert_result = def.add_impl_for_specialization(self.tcx, impl_def_id);
+
+                // insertion failed due to overlap
+                if let Err(overlap) = insert_result {
+                    // only print the Self type if it has at least some outer
+                    // concrete shell; otherwise, it's not adding much
+                    // information.
+                    let self_type = {
+                        overlap.on_trait_ref.substs.self_ty().and_then(|ty| {
+                            if ty.has_concrete_skeleton() {
+                                Some(format!(" for type `{}`", ty))
+                            } else {
+                                None
                             }
+                        }).unwrap_or(String::new())
+                    };
+
+                    let mut err = struct_span_err!(
+                        self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119,
+                        "conflicting implementations of trait `{}`{}:",
+                        overlap.on_trait_ref,
+                        self_type);
+
+                    match self.tcx.span_of_impl(overlap.with_impl) {
+                        Ok(span) => {
+                            err.span_note(span, "conflicting implementation is here:");
+                        }
+                        Err(cname) => {
+                            err.note(&format!("conflicting implementation in crate `{}`",
+                                              cname));
+                        }
+                    }
+
+                    err.emit();
+                }
+
+                // check for overlap with the automatic `impl Trait for Trait`
+                if let ty::TyTrait(ref data) = trait_ref.self_ty().sty {
+                    // This is something like impl Trait1 for Trait2. Illegal
+                    // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
+
+                    if !traits::is_object_safe(self.tcx, data.principal_def_id()) {
+                        // This is an error, but it will be
+                        // reported by wfcheck.  Ignore it
+                        // here. This is tested by
+                        // `coherence-impl-trait-for-trait-object-safe.rs`.
+                    } else {
+                        let mut supertrait_def_ids =
+                            traits::supertrait_def_ids(self.tcx, data.principal_def_id());
+                        if supertrait_def_ids.any(|d| d == trait_def_id) {
+                            span_err!(self.tcx.sess, item.span, E0371,
+                                      "the object type `{}` automatically \
+                                       implements the trait `{}`",
+                                      trait_ref.self_ty(),
+                                      self.tcx.item_path_str(trait_def_id));
                         }
                     }
-                    _ => { }
                 }
             }
-            _ => {
-            }
+            _ => {}
         }
     }
 }
index b493b64a45fcf9f650c3bc0fa76ec1377fb6a88b..0f88640b629510040efdab8a9fa7c1c9638a7f17 100644 (file)
@@ -81,6 +81,8 @@
 use util::nodemap::{FnvHashMap, FnvHashSet};
 use write_ty_to_tcx;
 
+use rustc_const_eval::ConstInt;
+
 use std::cell::RefCell;
 use std::collections::HashSet;
 use std::rc::Rc;
@@ -531,6 +533,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             id: ast::NodeId,
                             vis: hir::Visibility,
                             sig: &hir::MethodSig,
+                            defaultness: hir::Defaultness,
                             untransformed_rcvr_ty: Ty<'tcx>,
                             rcvr_ty_generics: &ty::Generics<'tcx>,
                             rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
@@ -552,6 +555,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                     fty,
                                     explicit_self_category,
                                     vis,
+                                    defaultness,
                                     def_id,
                                     container);
 
@@ -598,6 +602,7 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                       name: ast::Name,
                                       id: ast::NodeId,
                                       vis: hir::Visibility,
+                                      defaultness: hir::Defaultness,
                                       ty: ty::Ty<'tcx>,
                                       has_value: bool)
 {
@@ -609,6 +614,7 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let associated_const = Rc::new(ty::AssociatedConst {
         name: name,
         vis: vis,
+        defaultness: defaultness,
         def_id: ccx.tcx.map.local_def_id(id),
         container: container,
         ty: ty,
@@ -623,11 +629,13 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                      name: ast::Name,
                                      id: ast::NodeId,
                                      vis: hir::Visibility,
+                                     defaultness: hir::Defaultness,
                                      ty: Option<Ty<'tcx>>)
 {
     let associated_type = Rc::new(ty::AssociatedType {
         name: name,
         vis: vis,
+        defaultness: defaultness,
         ty: ty,
         def_id: ccx.tcx.map.local_def_id(id),
         container: container
@@ -765,6 +773,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                     convert_associated_const(ccx, ImplContainer(def_id),
                                              impl_item.name, impl_item.id,
                                              impl_item.vis.inherit_from(parent_visibility),
+                                             impl_item.defaultness,
                                              ty, true /* has_value */);
                 }
             }
@@ -781,7 +790,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
                     convert_associated_type(ccx, ImplContainer(def_id),
                                             impl_item.name, impl_item.id, impl_item.vis,
-                                            Some(typ));
+                                            impl_item.defaultness, Some(typ));
                 }
             }
 
@@ -795,7 +804,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
                     convert_method(ccx, ImplContainer(def_id),
                                    impl_item.name, impl_item.id, method_vis,
-                                   sig, selfty, &ty_generics, &ty_predicates);
+                                   sig, impl_item.defaultness, selfty, &ty_generics,
+                                   &ty_predicates);
                 }
             }
 
@@ -829,6 +839,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                                              trait_item.name,
                                              trait_item.id,
                                              hir::Public,
+                                             hir::Defaultness::Default,
                                              ty,
                                              default.is_some())
                 }
@@ -846,6 +857,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                                             trait_item.name,
                                             trait_item.id,
                                             hir::Public,
+                                            hir::Defaultness::Default,
                                             typ);
                 }
             }
@@ -859,6 +871,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                                    trait_item.id,
                                    hir::Inherited,
                                    sig,
+                                   hir::Defaultness::Default,
                                    tcx.mk_self_type(),
                                    &trait_def.generics,
                                    &trait_predicates);
@@ -1012,7 +1025,7 @@ fn convert_struct_def<'tcx>(tcx: &TyCtxt<'tcx>,
     tcx.intern_adt_def(
         did,
         ty::AdtKind::Struct,
-        vec![convert_struct_variant(tcx, ctor_id, it.name, 0, def)]
+        vec![convert_struct_variant(tcx, ctor_id, it.name, ConstInt::Infer(0), def)]
     )
 }
 
@@ -1021,24 +1034,39 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
                           def: &hir::EnumDef)
                           -> ty::AdtDefMaster<'tcx>
 {
+    fn print_err(tcx: &TyCtxt, span: Span, ty: ty::Ty, cv: ConstVal) {
+        span_err!(tcx.sess, span, E0079, "mismatched types: expected `{}` got `{}`",
+                  ty, cv.description());
+    }
     fn evaluate_disr_expr<'tcx>(tcx: &TyCtxt<'tcx>,
-                                repr_ty: Ty<'tcx>,
+                                repr_ty: attr::IntType,
                                 e: &hir::Expr) -> Option<ty::Disr> {
         debug!("disr expr, checking {}", pprust::expr_to_string(e));
 
-        let hint = UncheckedExprHint(repr_ty);
+        let ty_hint = repr_ty.to_ty(tcx);
+        let hint = UncheckedExprHint(ty_hint);
         match const_eval::eval_const_expr_partial(tcx, e, hint, None) {
-            Ok(ConstVal::Int(val)) => Some(val as ty::Disr),
-            Ok(ConstVal::Uint(val)) => Some(val as ty::Disr),
-            Ok(_) => {
-                let sign_desc = if repr_ty.is_signed() {
-                    "signed"
-                } else {
-                    "unsigned"
-                };
-                span_err!(tcx.sess, e.span, E0079,
-                          "expected {} integer constant",
-                          sign_desc);
+            Ok(ConstVal::Integral(i)) => {
+                // FIXME: eval_const_expr_partial should return an error if the hint is wrong
+                match (repr_ty, i) {
+                    (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => Some(i),
+                    (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => Some(i),
+                    (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => Some(i),
+                    (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => Some(i),
+                    (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => Some(i),
+                    (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => Some(i),
+                    (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => Some(i),
+                    (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => Some(i),
+                    (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => Some(i),
+                    (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Some(i),
+                    (_, i) => {
+                        print_err(tcx, e.span, ty_hint, ConstVal::Integral(i));
+                        None
+                    },
+                }
+            },
+            Ok(cv) => {
+                print_err(tcx, e.span, ty_hint, cv);
                 None
             },
             Err(err) => {
@@ -1057,16 +1085,11 @@ fn evaluate_disr_expr<'tcx>(tcx: &TyCtxt<'tcx>,
     fn report_discrim_overflow(tcx: &TyCtxt,
                                variant_span: Span,
                                variant_name: &str,
-                               repr_type: attr::IntType,
                                prev_val: ty::Disr) {
-        let computed_value = repr_type.disr_wrap_incr(Some(prev_val));
-        let computed_value = repr_type.disr_string(computed_value);
-        let prev_val = repr_type.disr_string(prev_val);
-        let repr_type = repr_type.to_ty(tcx);
         span_err!(tcx.sess, variant_span, E0370,
-                  "enum discriminant overflowed on value after {}: {}; \
+                  "enum discriminant overflowed on value after {}; \
                    set explicitly via {} = {} if that is desired outcome",
-                  prev_val, repr_type, variant_name, computed_value);
+                  prev_val, variant_name, prev_val.wrap_incr());
     }
 
     fn next_disr(tcx: &TyCtxt,
@@ -1076,12 +1099,11 @@ fn next_disr(tcx: &TyCtxt,
         if let Some(prev_disr_val) = prev_disr_val {
             let result = repr_type.disr_incr(prev_disr_val);
             if let None = result {
-                report_discrim_overflow(tcx, v.span, &v.node.name.as_str(),
-                                             repr_type, prev_disr_val);
+                report_discrim_overflow(tcx, v.span, &v.node.name.as_str(), prev_disr_val);
             }
             result
         } else {
-            Some(ty::INITIAL_DISCRIMINANT_VALUE)
+            Some(repr_type.initial_discriminant(tcx))
         }
     }
     fn convert_enum_variant<'tcx>(tcx: &TyCtxt<'tcx>,
@@ -1095,17 +1117,19 @@ fn convert_enum_variant<'tcx>(tcx: &TyCtxt<'tcx>,
     }
     let did = tcx.map.local_def_id(it.id);
     let repr_hints = tcx.lookup_repr_hints(did);
-    let (repr_type, repr_type_ty) = tcx.enum_repr_type(repr_hints.get(0));
+    let repr_type = tcx.enum_repr_type(repr_hints.get(0));
     let mut prev_disr = None;
     let variants = def.variants.iter().map(|v| {
         let disr = match v.node.disr_expr {
-            Some(ref e) => evaluate_disr_expr(tcx, repr_type_ty, e),
+            Some(ref e) => evaluate_disr_expr(tcx, repr_type, e),
             None => next_disr(tcx, v, repr_type, prev_disr)
-        }.unwrap_or(repr_type.disr_wrap_incr(prev_disr));
+        }.unwrap_or_else(|| {
+            prev_disr.map(ty::Disr::wrap_incr)
+                     .unwrap_or(repr_type.initial_discriminant(tcx))
+        });
 
-        let v = convert_enum_variant(tcx, v, disr);
         prev_disr = Some(disr);
-        v
+        convert_enum_variant(tcx, v, disr)
     }).collect();
     tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants)
 }
index 5c411bec5065d132b2c08385b65649de6e604239..19cfc13ea615c03ca237e15bd951107693a11d05 100644 (file)
@@ -3695,5 +3695,7 @@ fn main() {
     E0399, // trait items need to be implemented because the associated
            // type `{}` was overridden
     E0436, // functional record update requires a struct
-    E0513  // no type for local variable ..
+    E0513, // no type for local variable ..
+    E0520, // cannot specialize non-default item
+    E0521  // redundant default implementations of trait
 }
index 035f8c60500228effcd27706afd5acbf75c19d02..936be8091940679db53387c4537e2612cfc93b20 100644 (file)
@@ -91,6 +91,7 @@
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate rustc_front;
 extern crate rustc_back;
+extern crate rustc_const_eval;
 
 pub use rustc::dep_graph;
 pub use rustc::front;
 use middle::infer::{self, TypeOrigin};
 use middle::subst::Substs;
 use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use middle::traits::ProjectionMode;
 use session::{config, CompileResult};
 use util::common::time;
 use rustc_front::hir;
@@ -195,7 +197,7 @@ fn require_same_types<'a, 'tcx, M>(tcx: &TyCtxt<'tcx>,
 {
     let result = match maybe_infcx {
         None => {
-            let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
+            let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
             infer::mk_eqty(&infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
         }
         Some(infcx) => {
index 061047cbd2f6d9c6c34c86a534b5eea65f7add85..ef54be720376a7a79f96eb40491fa71d6ef2a8a2 100644 (file)
@@ -337,7 +337,7 @@ pub fn build_impl(cx: &DocContext,
                 let type_scheme = tcx.lookup_item_type(did);
                 let default = if assoc_const.has_value {
                     Some(const_eval::lookup_const_by_id(tcx, did, None, None)
-                         .unwrap().span.to_src(cx))
+                         .unwrap().0.span.to_src(cx))
                 } else {
                     None
                 };
@@ -479,7 +479,7 @@ fn build_const(cx: &DocContext, tcx: &TyCtxt,
     use rustc::middle::const_eval;
     use rustc_front::print::pprust;
 
-    let expr = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| {
+    let (expr, ty) = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| {
         panic!("expected lookup_const_by_id to succeed for {:?}", did);
     });
     debug!("converting constant expr {:?} to snippet", expr);
@@ -487,7 +487,7 @@ fn build_const(cx: &DocContext, tcx: &TyCtxt,
     debug!("got snippet {}", sn);
 
     clean::Constant {
-        type_: tcx.lookup_item_type(did).ty.clean(cx),
+        type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.lookup_item_type(did).ty.clean(cx)),
         expr: sn
     }
 }
index a4b8c9bf5f7db4aae9fb74b5e3ae6271c32c7a39..54821bd1161ee41648a7c94f0d2e069fb48045bf 100644 (file)
@@ -205,7 +205,7 @@ fn clean(&self, cx: &DocContext) -> Crate {
                     current_dir().unwrap().join(path)
                 }
             },
-            Input::Str(_) => PathBuf::new() // FIXME: this is wrong
+            Input::Str { ref name, .. } => PathBuf::from(name.clone()),
         };
 
         Crate {
index 129039b1a06fd3f09b8628b75886faff0ec1cdeb..7d4061b655941e539775313ca1c16a77e1d185e9 100644 (file)
@@ -180,7 +180,10 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
     // the test harness wants its own `main` & top level functions, so
     // never wrap the test in `fn main() { ... }`
     let test = maketest(test, Some(cratename), as_test_harness, opts);
-    let input = config::Input::Str(test.to_string());
+    let input = config::Input::Str {
+        name: driver::anon_src(),
+        input: test.to_owned(),
+    };
     let mut outputs = HashMap::new();
     outputs.insert(OutputType::Exe, None);
 
index 9c8ff44c7043f55aa5e84dc8521cf7080fa6996d..bb688ab484ad31ed446c6b3889837cfac1c3df3c 100644 (file)
@@ -371,10 +371,12 @@ pub fn is_unicast_site_local(&self) -> bool {
     /// - the link-local addresses
     /// - the (deprecated) site-local addresses
     /// - unique local addresses
+    /// - the unspecified address
     pub fn is_unicast_global(&self) -> bool {
         !self.is_multicast()
             && !self.is_loopback() && !self.is_unicast_link_local()
             && !self.is_unicast_site_local() && !self.is_unique_local()
+            && !self.is_unspecified()
     }
 
     /// Returns the address's multicast scope if the address is multicast.
@@ -768,7 +770,7 @@ fn check(str_addr: &str, unspec: bool, loopback: bool,
 
         //    unspec loopbk uniqlo global unill  unisl  uniglo mscope
         check("::",
-              true,  false, false, true,  false, false, true,  None);
+              true,  false, false, false,  false, false, false,  None);
         check("::1",
               false, true,  false, false, false, false, false, None);
         check("::0.0.0.2",
index f7621b0131ad45d919bae6619518b18de8984e6c..c830fed5db9a71a0c70a87a500cc784c114cba52 100644 (file)
@@ -1328,10 +1328,10 @@ pub struct MethodSig {
     pub explicit_self: ExplicitSelf,
 }
 
-/// Represents a method declaration in a trait declaration, possibly including
-/// a default implementation. A trait method is either required (meaning it
-/// doesn't have an implementation, just a signature) or provided (meaning it
-/// has a default implementation).
+/// Represents an item declaration within a trait declaration,
+/// possibly including a default implementation. A trait item is
+/// either required (meaning it doesn't have an implementation, just a
+/// signature) or provided (meaning it has a default implementation).
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct TraitItem {
     pub id: NodeId,
@@ -1353,6 +1353,7 @@ pub struct ImplItem {
     pub id: NodeId,
     pub ident: Ident,
     pub vis: Visibility,
+    pub defaultness: Defaultness,
     pub attrs: Vec<Attribute>,
     pub node: ImplItemKind,
     pub span: Span,
@@ -1654,6 +1655,12 @@ pub enum Constness {
     NotConst,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum Defaultness {
+    Default,
+    Final,
+}
+
 impl fmt::Display for Unsafety {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt::Display::fmt(match *self {
index f5794f7219bcf224c7c1ae1a3f08f208de9b480f..5bfdab791d638a0b4d72e8324fcec42423fcaecc 100644 (file)
@@ -1061,6 +1061,7 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
             ident: ii.ident,
             attrs: ii.attrs,
             vis: ii.vis,
+            defaultness: ii.defaultness,
             node: match ii.node  {
                 ast::ImplItemKind::Method(sig, body) => {
                     let (sig, body) = expand_and_rename_method(sig, body, fld);
index 14a3f93738a32a9aa6dc7d43595593d7ba661830..fbaf28332c42c5dd475910ca8f99759052a8581c 100644 (file)
     ("inclusive_range_syntax", "1.7.0", Some(28237), Active),
 
     // `expr?`
-    ("question_mark", "1.9.0", Some(31436), Active)
+    ("question_mark", "1.9.0", Some(31436), Active),
+
+    // impl specialization (RFC 1210)
+    ("specialization", "1.7.0", Some(31844), Active),
 ];
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -574,6 +577,7 @@ pub struct Features {
     pub stmt_expr_attributes: bool,
     pub deprecated: bool,
     pub question_mark: bool,
+    pub specialization: bool,
 }
 
 impl Features {
@@ -608,6 +612,7 @@ pub fn new() -> Features {
             stmt_expr_attributes: false,
             deprecated: false,
             question_mark: false,
+            specialization: false,
         }
     }
 }
@@ -1102,6 +1107,12 @@ fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
     }
 
     fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
+        if ii.defaultness == ast::Defaultness::Default {
+            self.gate_feature("specialization",
+                              ii.span,
+                              "specialization is unstable");
+        }
+
         match ii.node {
             ast::ImplItemKind::Const(..) => {
                 self.gate_feature("associated_consts",
@@ -1212,6 +1223,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
         stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"),
         deprecated: cx.has_feature("deprecated"),
         question_mark: cx.has_feature("question_mark"),
+        specialization: cx.has_feature("specialization"),
     }
 }
 
index 9056103d30086bbdd7e1bd6f9f45a355e4dae187..cd8998a211ae7491e37448ace64086a0609b136e 100644 (file)
@@ -993,6 +993,7 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T)
         ident: folder.fold_ident(i.ident),
         attrs: fold_attrs(i.attrs, folder),
         vis: i.vis,
+        defaultness: i.defaultness,
         node: match i.node  {
             ast::ImplItemKind::Const(ty, expr) => {
                 ast::ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr))
index 5884be401503df31374d1c4e666107483bbc7838..6839f11cd709d1113009b818ac3fb53b548cc886 100644 (file)
@@ -18,7 +18,7 @@
 use ast::Block;
 use ast::{BlockCheckMode, CaptureBy};
 use ast::{Constness, Crate, CrateConfig};
-use ast::{Decl, DeclKind};
+use ast::{Decl, DeclKind, Defaultness};
 use ast::{EMPTY_CTXT, EnumDef, ExplicitSelf};
 use ast::{Expr, ExprKind, RangeLimits};
 use ast::{Field, FnDecl};
@@ -644,6 +644,25 @@ pub fn eat_keyword_noexpect(&mut self, kw: keywords::Keyword) -> bool {
         }
     }
 
+    pub fn check_contextual_keyword(&mut self, ident: Ident) -> bool {
+        let tok = token::Ident(ident, token::Plain);
+        self.expected_tokens.push(TokenType::Token(tok));
+        if let token::Ident(ref cur_ident, _) = self.token {
+            cur_ident.name == ident.name
+        } else {
+            false
+        }
+    }
+
+    pub fn eat_contextual_keyword(&mut self, ident: Ident) -> bool {
+        if self.check_contextual_keyword(ident) {
+            self.bump();
+            true
+        } else {
+            false
+        }
+    }
+
     /// If the given word is not a keyword, signal an error.
     /// If the next token is not the given word, signal an error.
     /// Otherwise, eat it.
@@ -705,7 +724,6 @@ pub fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>)
         }
     }
 
-
     /// Attempt to consume a `<`. If `<<` is seen, replace it with a single
     /// `<` and continue. If a `<` is not seen, return false.
     ///
@@ -4846,6 +4864,7 @@ pub fn parse_impl_item(&mut self) -> PResult<'a, ImplItem> {
         let mut attrs = try!(self.parse_outer_attributes());
         let lo = self.span.lo;
         let vis = try!(self.parse_visibility());
+        let defaultness = try!(self.parse_defaultness());
         let (name, node) = if self.eat_keyword(keywords::Type) {
             let name = try!(self.parse_ident());
             try!(self.expect(&token::Eq));
@@ -4872,6 +4891,7 @@ pub fn parse_impl_item(&mut self) -> PResult<'a, ImplItem> {
             span: mk_sp(lo, self.last_span.hi),
             ident: name,
             vis: vis,
+            defaultness: defaultness,
             attrs: attrs,
             node: node
         })
@@ -5208,6 +5228,15 @@ fn parse_visibility(&mut self) -> PResult<'a, Visibility> {
         else { Ok(Visibility::Inherited) }
     }
 
+    /// Parse defaultness: DEFAULT or nothing
+    fn parse_defaultness(&mut self) -> PResult<'a, Defaultness> {
+        if self.eat_contextual_keyword(special_idents::DEFAULT) {
+            Ok(Defaultness::Default)
+        } else {
+            Ok(Defaultness::Final)
+        }
+    }
+
     /// Given a termination token, parse all of the items in a module
     fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<'a, Mod> {
         let mut items = vec![];
index 294cbf358954f32124bdc1eb9c8524d9a8e00809..033ac9440bcecbc0e7802db682862155d5d74ebc 100644 (file)
@@ -545,66 +545,67 @@ pub mod special_idents {
         (9,                          __unused1,              "<__unused1>");
         (super::SELF_TYPE_KEYWORD_NAME_NUM, type_self,       "Self");
         (11,                         prelude_import,         "prelude_import");
+        (12,                         DEFAULT,                "default");
     }
 
     pub mod keywords {
         // These ones are variants of the Keyword enum
 
         'strict:
-        (12,                         As,         "as");
-        (13,                         Break,      "break");
-        (14,                         Crate,      "crate");
-        (15,                         Else,       "else");
-        (16,                         Enum,       "enum");
-        (17,                         Extern,     "extern");
-        (18,                         False,      "false");
-        (19,                         Fn,         "fn");
-        (20,                         For,        "for");
-        (21,                         If,         "if");
-        (22,                         Impl,       "impl");
-        (23,                         In,         "in");
-        (24,                         Let,        "let");
-        (25,                         Loop,       "loop");
-        (26,                         Match,      "match");
-        (27,                         Mod,        "mod");
-        (28,                         Move,       "move");
-        (29,                         Mut,        "mut");
-        (30,                         Pub,        "pub");
-        (31,                         Ref,        "ref");
-        (32,                         Return,     "return");
+        (13,                         As,         "as");
+        (14,                         Break,      "break");
+        (15,                         Crate,      "crate");
+        (16,                         Else,       "else");
+        (17,                         Enum,       "enum");
+        (18,                         Extern,     "extern");
+        (19,                         False,      "false");
+        (20,                         Fn,         "fn");
+        (21,                         For,        "for");
+        (22,                         If,         "if");
+        (23,                         Impl,       "impl");
+        (24,                         In,         "in");
+        (25,                         Let,        "let");
+        (26,                         Loop,       "loop");
+        (27,                         Match,      "match");
+        (28,                         Mod,        "mod");
+        (29,                         Move,       "move");
+        (30,                         Mut,        "mut");
+        (31,                         Pub,        "pub");
+        (32,                         Ref,        "ref");
+        (33,                         Return,     "return");
         // Static and Self are also special idents (prefill de-dupes)
         (super::STATIC_KEYWORD_NAME_NUM, Static, "static");
         (super::SELF_KEYWORD_NAME_NUM, SelfValue, "self");
         (super::SELF_TYPE_KEYWORD_NAME_NUM, SelfType, "Self");
-        (33,                         Struct,     "struct");
+        (34,                         Struct,     "struct");
         (super::SUPER_KEYWORD_NAME_NUM, Super,   "super");
-        (34,                         True,       "true");
-        (35,                         Trait,      "trait");
-        (36,                         Type,       "type");
-        (37,                         Unsafe,     "unsafe");
-        (38,                         Use,        "use");
-        (39,                         While,      "while");
-        (40,                         Continue,   "continue");
-        (41,                         Box,        "box");
-        (42,                         Const,      "const");
-        (43,                         Where,      "where");
+        (35,                         True,       "true");
+        (36,                         Trait,      "trait");
+        (37,                         Type,       "type");
+        (38,                         Unsafe,     "unsafe");
+        (39,                         Use,        "use");
+        (40,                         While,      "while");
+        (41,                         Continue,   "continue");
+        (42,                         Box,        "box");
+        (43,                         Const,      "const");
+        (44,                         Where,      "where");
         'reserved:
-        (44,                         Virtual,    "virtual");
-        (45,                         Proc,       "proc");
-        (46,                         Alignof,    "alignof");
-        (47,                         Become,     "become");
-        (48,                         Offsetof,   "offsetof");
-        (49,                         Priv,       "priv");
-        (50,                         Pure,       "pure");
-        (51,                         Sizeof,     "sizeof");
-        (52,                         Typeof,     "typeof");
-        (53,                         Unsized,    "unsized");
-        (54,                         Yield,      "yield");
-        (55,                         Do,         "do");
-        (56,                         Abstract,   "abstract");
-        (57,                         Final,      "final");
-        (58,                         Override,   "override");
-        (59,                         Macro,      "macro");
+        (45,                         Virtual,    "virtual");
+        (46,                         Proc,       "proc");
+        (47,                         Alignof,    "alignof");
+        (48,                         Become,     "become");
+        (49,                         Offsetof,   "offsetof");
+        (50,                         Priv,       "priv");
+        (51,                         Pure,       "pure");
+        (52,                         Sizeof,     "sizeof");
+        (53,                         Typeof,     "typeof");
+        (54,                         Unsized,    "unsized");
+        (55,                         Yield,      "yield");
+        (56,                         Do,         "do");
+        (57,                         Abstract,   "abstract");
+        (58,                         Final,      "final");
+        (59,                         Override,   "override");
+        (60,                         Macro,      "macro");
     }
 }
 
index 2cfed1f82f7ecd455788845cfa85db68f1ba2043..533487ae1c547cb59fa0e613a43e38df08f195b5 100644 (file)
@@ -1582,6 +1582,9 @@ pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
         try!(self.hardbreak_if_not_bol());
         try!(self.maybe_print_comment(ii.span.lo));
         try!(self.print_outer_attributes(&ii.attrs));
+        if let ast::Defaultness::Default = ii.defaultness {
+            try!(self.word_nbsp("default"));
+        }
         match ii.node {
             ast::ImplItemKind::Const(ref ty, ref expr) => {
                 try!(self.print_associated_const(ii.ident, &ty, Some(&expr), ii.vis));
index c0237a5d29a4103dbf8e535ba9800cc474929fca..937055fcfa6724f55d6456893bc76f7a05f4ed9f 100644 (file)
@@ -476,6 +476,7 @@ fn create_derived_impl(&self,
                 span: self.span,
                 ident: ident,
                 vis: ast::Visibility::Inherited,
+                defaultness: ast::Defaultness::Final,
                 attrs: Vec::new(),
                 node: ast::ImplItemKind::Type(type_def.to_ty(cx,
                     self.span,
@@ -893,6 +894,7 @@ fn create_method(&self,
             attrs: self.attributes.clone(),
             span: trait_.span,
             vis: ast::Visibility::Inherited,
+            defaultness: ast::Defaultness::Final,
             ident: method_ident,
             node: ast::ImplItemKind::Method(ast::MethodSig {
                 generics: fn_generics,
index 59e2fce6f0938b2dda0d7fed95650519864ac35a..778380d935c8d31fc08f2afe087c37cf7cd50398 100644 (file)
@@ -1,2 +1,2 @@
 rustc: 2016-02-17
-cargo: 2016-01-21
+cargo: 2016-03-11
index a27183516404388e13f50f84e102022500a40ec8..0e7537a9cbd04b37b53c226cd4c2d7830084f13d 100644 (file)
@@ -349,7 +349,6 @@ name = "test"
 version = "0.0.0"
 dependencies = [
  "getopts 0.0.0",
- "serialize 0.0.0",
  "term 0.0.0",
 ]
 
index 3f9d8e5e9ec1b90eb44b4ab625026f645bdd0ee2..44316b89abf1529c91e75ea0280c46f1b5c79756 100644 (file)
@@ -6,7 +6,7 @@ S 2016-02-17 4d3eebf
   winnt-i386 0c336d794a65f8e285c121866c7d59aa2dd0d1e1
   winnt-x86_64 27e75b1bf99770b3564bcebd7f3230be01135a92
   openbsd-x86_64 ac957c6b84de2bd67f01df085d9ea515f96e22f3
-  freebsd-x86_64 395adf223f3f25514c9dffecb524f493c42a0e5d
+  freebsd-x86_64 f38991fbb81c1cd8d0bbda396f98f13a55b42804
 
 S 2015-12-18 3391630
   bitrig-x86_64 6476e1562df02389b55553b4c88b1f4fd121cd40
index 89101fe709d97d0c1770ccbaa69b90c46dc45f88..fdfbc98b0078a0bb266cd7e8dd7ee20c574c42a8 100644 (file)
@@ -16,6 +16,7 @@
 #[macro_use] extern crate rustc;
 extern crate rustc_front;
 extern crate rustc_plugin;
+extern crate rustc_const_eval;
 extern crate syntax;
 
 use rustc::mir::transform::{self, MirPass};
@@ -23,6 +24,7 @@
 use rustc::mir::visit::MutVisitor;
 use rustc::middle::ty;
 use rustc::middle::const_eval::ConstVal;
+use rustc_const_eval::ConstInt;
 use rustc_plugin::Registry;
 
 use syntax::ast::NodeId;
@@ -40,8 +42,10 @@ fn run_pass(&mut self, _: &ty::TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
 
 impl<'tcx> MutVisitor<'tcx> for Visitor {
     fn visit_literal(&mut self, literal: &mut Literal<'tcx>) {
-        if let Literal::Value { value: ConstVal::Int(ref mut i @ 11) } = *literal {
-            *i = 42;
+        if let Literal::Value { ref mut value } = *literal {
+            if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value {
+                *i = 42;
+            }
         }
     }
 }
index 0a921c8f5b3a0b1eb8fe6110786cf19a49977ba5..044bb606b40e224b15a0dd6766a72f4e1fec9155 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(specialization)]
+
 // Common code used for tests that model the Fn/FnMut/FnOnce hierarchy.
 
 pub trait Go {
@@ -37,7 +39,7 @@ pub fn go_once<G:GoOnce>(this: G, arg: isize) {
 impl<G> GoMut for G
     where G : Go
 {
-    fn go_mut(&mut self, arg: isize) {
+    default fn go_mut(&mut self, arg: isize) {
         go(&*self, arg)
     }
 }
@@ -45,7 +47,7 @@ fn go_mut(&mut self, arg: isize) {
 impl<G> GoOnce for G
     where G : GoMut
 {
-    fn go_once(mut self, arg: isize) {
+    default fn go_once(mut self, arg: isize) {
         go_mut(&mut self, arg)
     }
 }
diff --git a/src/test/auxiliary/specialization_cross_crate.rs b/src/test/auxiliary/specialization_cross_crate.rs
new file mode 100644 (file)
index 0000000..1d23533
--- /dev/null
@@ -0,0 +1,82 @@
+// 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(specialization)]
+
+pub trait Foo {
+    fn foo(&self) -> &'static str;
+}
+
+impl<T> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic"
+    }
+}
+
+impl<T: Clone> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic Clone"
+    }
+}
+
+impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
+    default fn foo(&self) -> &'static str {
+        "generic pair"
+    }
+}
+
+impl<T: Clone> Foo for (T, T) {
+    default fn foo(&self) -> &'static str {
+        "generic uniform pair"
+    }
+}
+
+impl Foo for (u8, u32) {
+    default fn foo(&self) -> &'static str {
+        "(u8, u32)"
+    }
+}
+
+impl Foo for (u8, u8) {
+    default fn foo(&self) -> &'static str {
+        "(u8, u8)"
+    }
+}
+
+impl<T: Clone> Foo for Vec<T> {
+    default fn foo(&self) -> &'static str {
+        "generic Vec"
+    }
+}
+
+impl Foo for Vec<i32> {
+    fn foo(&self) -> &'static str {
+        "Vec<i32>"
+    }
+}
+
+impl Foo for String {
+    fn foo(&self) -> &'static str {
+        "String"
+    }
+}
+
+impl Foo for i32 {
+    fn foo(&self) -> &'static str {
+        "i32"
+    }
+}
+
+pub trait MyMarker {}
+impl<T: Clone + MyMarker> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic Clone + MyMarker"
+    }
+}
diff --git a/src/test/auxiliary/specialization_cross_crate_defaults.rs b/src/test/auxiliary/specialization_cross_crate_defaults.rs
new file mode 100755 (executable)
index 0000000..b62d80b
--- /dev/null
@@ -0,0 +1,49 @@
+// 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(specialization)]
+
+// First, test only use of explicit `default` items:
+
+pub trait Foo {
+    fn foo(&self) -> bool;
+}
+
+impl<T> Foo for T {
+    default fn foo(&self) -> bool { false }
+}
+
+impl Foo for i32 {}
+
+impl Foo for i64 {
+    fn foo(&self) -> bool { true }
+}
+
+// Next, test mixture of explicit `default` and provided methods:
+
+pub trait Bar {
+    fn bar(&self) -> i32 { 0 }
+}
+
+impl<T> Bar for T {} // use the provided method
+
+impl Bar for i32 {
+    fn bar(&self) -> i32 { 1 }
+}
+impl<'a> Bar for &'a str {}
+
+impl<T> Bar for Vec<T> {
+    default fn bar(&self) -> i32 { 2 }
+}
+impl Bar for Vec<i32> {}
+impl Bar for Vec<i64> {
+    fn bar(&self) -> i32 { 3 }
+}
index 43852a4e793f363a6477cb8dc7df1caf906c2a65..6779438c67226783e1d63bf6095cb790be532578 100644 (file)
 
 #![feature(associated_type_defaults)]
 
-pub trait Foo {
-    type Input = usize;
-    fn bar(&self, _: Self::Input) {}
+pub trait Foo<T: Default + ToString> {
+    type Out: Default + ToString = T;
 }
 
-impl Foo for () {}
+impl Foo<u32> for () {
+}
+
+impl Foo<u64> for () {
+    type Out = bool;
+}
index 6d68da54112f24da473b778e0780319813873246..786a25500a886284c4b1bcd9fa4a9ca7f9fcb361 100644 (file)
@@ -22,21 +22,21 @@ pub trait IntoCow<'a, B: ?Sized> {
     fn into_cow(self) -> Cow<'a, B>;
 }
 
-impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned {
-//~^ ERROR E0119
+impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned {
     fn into_cow(self) -> Cow<'a, B> {
-        self
+        Cow(PhantomData)
     }
 }
 
-impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned {
+impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned {
 //~^ ERROR E0119
     fn into_cow(self) -> Cow<'a, B> {
-        Cow(PhantomData)
+        self
     }
 }
 
 impl<'a, B: ?Sized> IntoCow<'a, B> for &'a B where B: ToOwned {
+//~^ ERROR E0119
     fn into_cow(self) -> Cow<'a, B> {
         Cow(PhantomData)
     }
index d14b0fa9e6602a397e3a715961b44370909aa0df..8e129722722aaa3be723d8a9cdb014a70c14e78b 100644 (file)
@@ -87,7 +87,7 @@ fn main()
     //~^^ HELP through a usize first
 
     let _ = 42usize as *const [u8]; //~ ERROR casting
-    let _ = v as *const [u8]; //~ ERROR casting
+    let _ = v as *const [u8]; //~ ERROR cannot cast
     let _ = fat_v as *const Foo;
     //~^ ERROR `core::marker::Sized` is not implemented for the type `[u8]`
     let _ = foo as *const str; //~ ERROR casting
index b771b959d3e507ef1cf5001777109b9f1cef7e94..434d77828b44ae203c3632f44b7a384c8d22b9a1 100644 (file)
@@ -27,11 +27,11 @@ impl Even for isize { }
 
 impl Odd for usize { }
 
-impl<T:Even> MyTrait for T { //~ ERROR E0119
+impl<T:Even> MyTrait for T {
     fn get(&self) -> usize { 0 }
 }
 
-impl<T:Odd> MyTrait for T {
+impl<T:Odd> MyTrait for T { //~ ERROR E0119
     fn get(&self) -> usize { 0 }
 }
 
index d3b0e7f10b91bc815a32a1f21384bc2bfd9fd5e9..7ad5cd71ca8c2a0e343db9a8bed5998ee7ba60d1 100644 (file)
@@ -23,11 +23,11 @@ trait Even {}
 
 trait Odd {}
 
-impl<T:Even> MyTrait for T { //~ ERROR E0119
+impl<T:Even> MyTrait for T {
     fn get(&self) -> usize { 0 }
 }
 
-impl<T:Odd> MyTrait for T {
+impl<T:Odd> MyTrait for T { //~ ERROR E0119
     fn get(&self) -> usize { 0 }
 }
 
index 7b60a5ecbd71f4ac8533599cfb20cb73c4b42a71..1defe6c8b20e3e16a53ca178db9e42e59a39729c 100644 (file)
@@ -18,7 +18,7 @@ trait MyTrait<T> {
     fn get(&self) -> T;
 }
 
-impl<T> MyTrait<T> for T { //~ ERROR E0119
+impl<T> MyTrait<T> for T {
     fn get(&self) -> T {
         panic!()
     }
@@ -29,7 +29,7 @@ struct MyType {
     dummy: usize
 }
 
-impl MyTrait<MyType> for MyType {
+impl MyTrait<MyType> for MyType { //~ ERROR E0119
     fn get(&self) -> usize { (*self).clone() }
 }
 
index eeaa68677eb670c37c44e7852401966608bfcbb3..5c5c4d32d675cd7ac1a4c37a180198ffa0771676 100644 (file)
@@ -19,7 +19,7 @@ trait MyTrait {
     fn get(&self) -> usize;
 }
 
-impl<T:OtherTrait> MyTrait for T { //~ ERROR E0119
+impl<T:OtherTrait> MyTrait for T {
     fn get(&self) -> usize { 0 }
 }
 
@@ -27,7 +27,7 @@ struct MyType {
     dummy: usize
 }
 
-impl MyTrait for MyType {
+impl MyTrait for MyType { //~ ERROR E0119
     fn get(&self) -> usize { self.dummy }
 }
 
index d218b64af05270f0dec430b4b1001d410edfd0e9..57d71b44b0f6b29aa5452a08183ed5bddecad80d 100644 (file)
@@ -18,7 +18,7 @@ trait MyTrait {
     fn get(&self) -> usize;
 }
 
-impl<T> MyTrait for T { //~ ERROR E0119
+impl<T> MyTrait for T {
     fn get(&self) -> usize { 0 }
 }
 
@@ -26,7 +26,7 @@ struct MyType {
     dummy: usize
 }
 
-impl MyTrait for MyType {
+impl MyTrait for MyType { //~ ERROR E0119
     fn get(&self) -> usize { self.dummy }
 }
 
index 344ec89d25de915e58de8021481d9ce2a632df69..c123e381ab7d733fd02efc7a9d5d3feff217e6c3 100644 (file)
@@ -15,8 +15,6 @@ trait MyTrait {}
 struct TestType<T>(::std::marker::PhantomData<T>);
 
 unsafe impl<T: MyTrait+'static> Send for TestType<T> {}
-//~^ ERROR conflicting implementations of trait `core::marker::Send`
-//~^^ ERROR conflicting implementations of trait `core::marker::Send`
 
 impl<T: MyTrait> !Send for TestType<T> {}
 //~^ ERROR conflicting implementations of trait `core::marker::Send`
index a020b518d8273a9ad0e1d6b1812f07cd7c9900ce..9f74afbb2b3b5493ba7b30472b627a51e7685f18 100644 (file)
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Regression test for #3512 - conflicting trait impls in different crates should give a
-// 'conflicting implementations' error message.
+// The error here is strictly due to orphan rules; the impl here
+// generalizes the one upstream
 
 // aux-build:trait_impl_conflict.rs
 extern crate trait_impl_conflict;
@@ -17,7 +17,6 @@
 
 impl<A> Foo for A {
     //~^ ERROR type parameter `A` must be used as the type parameter for some local type
-    //~^^ ERROR E0119
 }
 
 fn main() {
index 0705702b031ee007b2731320f50b4d4885908fbe..3d109de76ccd1c21908c0ff5a46dbef64fd0a072 100644 (file)
@@ -15,7 +15,7 @@ trait MyTrait {}
 impl MyTrait for .. {}
 
 impl MyTrait for .. {}
-//~^ ERROR conflicting implementations of trait `MyTrait`
+//~^ ERROR redundant default implementations of trait `MyTrait`
 
 trait MySafeTrait {}
 
diff --git a/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs b/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs
new file mode 100644 (file)
index 0000000..6de338f
--- /dev/null
@@ -0,0 +1,18 @@
+// 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.
+
+// Test that you cannot *directly* dispatch on lifetime requirements
+
+trait MyTrait {}
+
+impl<T> MyTrait for T {}
+impl<T: 'static> MyTrait for T {} //~ ERROR E0119
+
+fn main() {}
index 3fd635b3d616f33840d8571ef21d620c7f22ebc4..928ba7a36db266ddb3534eba302fbff8125d4013 100644 (file)
 trait From<U> {
 }
 
-impl <T> From<T> for T { //~ ERROR E0119
+impl <T> From<T> for T {
 }
 
-impl <T11, U11> From<(U11,)> for (T11,) {
+impl <T11, U11> From<(U11,)> for (T11,) { //~ ERROR E0119
 }
 
 fn main() { }
index d7f060a3bfe73dfb87be02c0858c64ef255a8e51..51d7c3e8b4cb17962f0809276d5abf49b84a85af 100644 (file)
@@ -14,6 +14,6 @@
 
 pub trait Sugar { fn dummy(&self) { } }
 pub trait Sweet { fn dummy(&self) { } }
-impl<T:Sugar> Sweet for T { } //~ ERROR E0119
-impl<U:Sugar> Sweet for Box<U> { }
+impl<T:Sugar> Sweet for T { }
+impl<U:Sugar> Sweet for Box<U> { } //~ ERROR E0119
 fn main() { }
index 4f1092f960e0d2d41ea5e4f55297992a5a9e57e8..0ae8135221c21fc9a54f3094a711234c17ce9bff 100644 (file)
 
 trait Foo {}
 
-impl<T> Foo for T {} //~ ERROR conflicting implementations of trait `Foo`:
-impl<U> Foo for U {}
+impl<T> Foo for T {}
+impl<U> Foo for U {} //~ ERROR conflicting implementations of trait `Foo`:
 
 trait Bar {}
 
-impl<T> Bar for T {} //~ ERROR conflicting implementations of trait `Bar` for type `u8`:
-impl Bar for u8 {}
+impl<T> Bar for (T, u8) {}
+impl<T> Bar for (u8, T) {} //~ ERROR conflicting implementations of trait `Bar` for type `(u8, u8)`:
 
 trait Baz<T> {}
 
-impl<T, U> Baz<U> for T {} //~ ERROR conflicting implementations of trait `Baz<_>` for type `u8`:
-impl<T> Baz<T> for u8 {}
+impl<T> Baz<u8> for T {}
+impl<T> Baz<T> for u8 {} //~ ERROR conflicting implementations of trait `Baz<u8>` for type `u8`:
 
-trait Quux<T> {}
+trait Quux<U, V> {}
 
-impl<T, U> Quux<U> for T {} //~ ERROR conflicting implementations of trait `Quux<_>`:
-impl<T> Quux<T> for T {}
-
-trait Qaar<T> {}
-
-impl<T, U> Qaar<U> for T {} //~ ERROR conflicting implementations of trait `Qaar<u8>`:
-impl<T> Qaar<u8> for T {}
-
-trait Qaax<T> {}
-
-impl<T, U> Qaax<U> for T {}
-//~^ ERROR conflicting implementations of trait `Qaax<u8>` for type `u32`:
-impl Qaax<u8> for u32 {}
+impl<T, U, V> Quux<U, V> for T {}
+impl<T, U> Quux<U, U> for T {} //~ ERROR conflicting implementations of trait `Quux<_, _>`:
+impl<T, V> Quux<T, V> for T {} //~ ERROR conflicting implementations of trait `Quux<_, _>`:
 
 fn main() {}
index 3de79454398387338cdf8498c8a94d8383692f7b..3ed3549de89aaa214b9191d281a47429c741af58 100644 (file)
@@ -21,8 +21,8 @@ pub trait Bar {
     type Output: 'static;
 }
 
-impl Foo<i32> for i32 { } //~ ERROR E0119
+impl Foo<i32> for i32 { }
 
-impl<A:Iterator> Foo<A::Item> for A { }
+impl<A:Iterator> Foo<A::Item> for A { }  //~ ERROR E0119
 
 fn main() {}
index 6880f3e9a3cc9aeecd0ad58182c3b493a03202c8..f04902a70f68c20e490b1719efaefe4b58d38096 100644 (file)
@@ -15,8 +15,8 @@
 
 pub trait Foo<P> {}
 
-impl <P, T: Foo<P>> Foo<P> for Option<T> {} //~ ERROR E0119
+impl <P, T: Foo<P>> Foo<P> for Option<T> {}
 
-impl<T, U> Foo<T> for Option<U> { }
+impl<T, U> Foo<T> for Option<U> { } //~ ERROR E0119
 
 fn main() {}
index 2236e71b53fff1cd7aaa516e972bbc97a88ab3a2..6d3ab32f06f43d08327af11f3d2088ae8c643935 100644 (file)
@@ -16,9 +16,9 @@ pub trait Bar {
     type Output: 'static;
 }
 
-impl Foo<i32> for i32 { } //~ ERROR E0119
+impl Foo<i32> for i32 { }
 
-impl<A:Bar> Foo<A::Output> for A { }
+impl<A:Bar> Foo<A::Output> for A { } //~ ERROR E0119
 
 impl Bar for i32 {
     type Output = i32;
index 87b007fdd698239d3af23c2558975c29ad994eb2..7807f93df1a673d8810010f82c027e0d014dd49a 100644 (file)
@@ -18,11 +18,11 @@ trait MyTrait {
     fn get(&self) -> usize;
 }
 
-impl<T> MyTrait for (T,T) { //~ ERROR E0119
+impl<T> MyTrait for (T,T) {
     fn get(&self) -> usize { 0 }
 }
 
-impl<A,B> MyTrait for (A,B) {
+impl<A,B> MyTrait for (A,B) { //~ ERROR E0119
     fn get(&self) -> usize { self.dummy }
 }
 
index a6b62d17bc4e6aa9ac34540d80911fa8b0865294..8e3e3f31cb5f1434356b5b9aa5bfd199a475cf8f 100644 (file)
@@ -21,10 +21,10 @@ struct MyType { x: i32 }
 
 trait MyTrait { }
 
-impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
+impl<T: lib::MyCopy> MyTrait for T { }
 
 // Tuples are not fundamental.
-impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { }
+impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { } //~ ERROR E0119
 
 #[rustc_error]
 fn main() { }
index 5a9f440f8bb6a98900bb406b1976d6a056232c1b..35bc17b8e887036a93bb4e1675aca4786795e1d8 100644 (file)
@@ -18,7 +18,7 @@
 struct MyType { x: i32 }
 
 trait MyTrait { }
-impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
+impl<T: lib::MyCopy> MyTrait for T { }
 
 // `MyStruct` is not declared fundamental, therefore this would
 // require that
@@ -26,6 +26,6 @@ impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
 //     MyStruct<MyType>: !MyTrait
 //
 // which we cannot approve.
-impl MyTrait for lib::MyStruct<MyType> { }
+impl MyTrait for lib::MyStruct<MyType> { } //~ ERROR E0119
 
 fn main() { }
index ee0d5550fd61f0ea8e514bec49a723935cf31ac6..a70cc92955fb0d6a76e0a5672e0d4764a976d470 100644 (file)
 struct MyType { x: i32 }
 
 trait MyTrait { }
-impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
+impl<T: lib::MyCopy> MyTrait for T { }
 
 // Tuples are not fundamental, therefore this would require that
 //
 //     (MyType,): !MyTrait
 //
 // which we cannot approve.
-impl MyTrait for (MyType,) { }
+impl MyTrait for (MyType,) { } //~ ERROR E0119
 
 fn main() { }
index be67e06d99fee0f0cc8fc3a22b02857cf4f23b14..4d156a49192fd403fb0b894aafb74292c4865eaf 100644 (file)
@@ -25,9 +25,9 @@ fn main() {
     //~^ WARN attempted to add with overflow
     //~^^ WARN attempted to add with overflow
     let c = 200u8 * 4;
-    //~^ WARN attempted to mul with overflow
+    //~^ WARN attempted to multiply with overflow
     let d = 42u8 - (42u8 + 1);
-    //~^ WARN attempted to sub with overflow
+    //~^ WARN attempted to subtract with overflow
     let _e = BLA;
     black_box(a);
     black_box(b);
index be04bc9bd3b732effbb96c0d55258242f7ed6c8d..07e27a7dc9a9a412b2eb14155044584b7980c325 100644 (file)
 const NEG_NEG_128: i8 = -NEG_128;
 //~^ ERROR constant evaluation error: attempted to negate with overflow
 //~| ERROR attempted to negate with overflow
+//~| ERROR attempted to negate with overflow
 
 fn main() {
     match -128i8 {
-        NEG_NEG_128 => println!("A"),
+        NEG_NEG_128 => println!("A"), //~ NOTE in pattern here
         _ => println!("B"),
     }
 }
index c2bc5b2648af3c4d8393998c707801ab514fda41..c90ae045f96b4aa0430e2b3c020f47d33caeba1a 100644 (file)
@@ -36,4 +36,3 @@ fn main() {
 fn foo<T:fmt::Debug>(x: T) {
     println!("{:?}", x);
 }
-
index 253285d3919c21937c4c5ebb4ee90fdfc7eb6a44..5aa93cf6383fe4c37e2209f3c33cb350e1ed2681 100644 (file)
@@ -21,8 +21,9 @@
 
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1u8) as usize]
-    //~^ ERROR mismatched types
-    //~| ERROR the trait `core::ops::Add<u8>` is not implemented for the type `i8`
+    //~^ ERROR mismatched types:
+    //~| expected `i8`,
+    //~| found `u8` [E0250]
     = [0; (i8::MAX as usize) + 1];
 
 fn main() {
index 2a2fc2ef080dbf30cacd440ff6d482e0c7eda65d..3dfcb5bb29a24a68701b48d195f62aca3361240c 100644 (file)
     (-i8::MIN,
      //~^ ERROR attempted to negate with overflow
      i8::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      i8::MAX + 1,
      //~^ ERROR attempted to add with overflow
      i8::MIN * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_I16: (i16, i16, i16, i16) =
     (-i16::MIN,
      //~^ ERROR attempted to negate with overflow
      i16::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      i16::MAX + 1,
      //~^ ERROR attempted to add with overflow
      i16::MIN * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_I32: (i32, i32, i32, i32) =
     (-i32::MIN,
      //~^ ERROR attempted to negate with overflow
      i32::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      i32::MAX + 1,
      //~^ ERROR attempted to add with overflow
      i32::MIN * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_I64: (i64, i64, i64, i64) =
     (-i64::MIN,
      //~^ ERROR attempted to negate with overflow
      i64::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      i64::MAX + 1,
      //~^ ERROR attempted to add with overflow
      i64::MAX * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_U8: (u8, u8, u8, u8) =
     (-(u8::MIN as i8) as u8,
      u8::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      u8::MAX + 1,
      //~^ ERROR attempted to add with overflow
      u8::MAX * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_U16: (u16, u16, u16, u16) =
     (-(u16::MIN as i16) as u16,
      u16::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      u16::MAX + 1,
      //~^ ERROR attempted to add with overflow
      u16::MAX * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_U32: (u32, u32, u32, u32) =
     (-(u32::MIN as i32) as u32,
      u32::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      u32::MAX + 1,
      //~^ ERROR attempted to add with overflow
      u32::MAX * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_U64: (u64, u64, u64, u64) =
     (-(u64::MIN as i64) as u64,
      u64::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      u64::MAX + 1,
      //~^ ERROR attempted to add with overflow
      u64::MAX * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 fn main() {
index 37a93ec954d8dbd2152760eeee431fdbf776b114..0d6cf3bab453fac0892aca6ff79efa9986f75507 100644 (file)
@@ -8,32 +8,30 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-const X: usize = 42 && 39; //~ ERROR: can't do this op on unsigned integrals
+const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals
 const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
 
-const X1: usize = 42 || 39; //~ ERROR: can't do this op on unsigned integrals
+const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals
 const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
 
-// FIXME: the error should be `on signed integrals`
-const X2: usize = -42 || -39; //~ ERROR: can't do this op on unsigned integrals
+const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer
 const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
 
-// FIXME: the error should be `on signed integrals`
-const X3: usize = -42 && -39; //~ ERROR: can't do this op on unsigned integrals
+const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer
 const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
 
 const Y: usize = 42.0 == 42.0;
-const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
+const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
 const Y1: usize = 42.0 >= 42.0;
-const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
+const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
 const Y2: usize = 42.0 <= 42.0;
-const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
+const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
 const Y3: usize = 42.0 > 42.0;
-const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
+const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
 const Y4: usize = 42.0 < 42.0;
-const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
+const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
 const Y5: usize = 42.0 != 42.0;
-const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
+const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
 
 fn main() {
     let _ = ARR;
index 786c72b66f36fe812677a781aacf61f9f7a3d85d..9c6b774b99039811fb6482e80d2e98c649f5f6aa 100644 (file)
@@ -15,7 +15,7 @@
 const ONE: usize = 1;
 const TWO: usize = 2;
 const LEN: usize = ONE - TWO;
-//~^ ERROR array length constant evaluation error: attempted to sub with overflow [E0250]
+//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
 
 fn main() {
     let a: [i8; LEN] = unimplemented!();
index 020717dc1e18f8fbfccefd584da4e2c296e99e6c..d51f31087d0df1494c5cce1005433e6839109a92 100644 (file)
@@ -16,5 +16,5 @@
 
 fn main() {
     let a: [i8; ONE - TWO] = unimplemented!();
-    //~^ ERROR array length constant evaluation error: attempted to sub with overflow [E0250]
+    //~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
 }
index 8c607fc7e32b2ecbfa091fff24cdcb5c781d1888..9d3c432d14878de269cf86ba9616dc7cc7c9d7af 100644 (file)
@@ -11,7 +11,7 @@
 // Test spans of errors
 
 const TUP: (usize,) = 5 << 64;
-//~^ ERROR: attempted left shift with overflow [E0250]
+//~^ ERROR: attempted to shift left with overflow [E0250]
 const ARR: [i32; TUP.0] = [];
 
 fn main() {
index 76378d5c8021bd03eac59f856ba9ad41e5c766aa..0ff740212e8fa46cec39e66a28c8b00de66ce70b 100644 (file)
@@ -24,7 +24,7 @@ fn f_i8() {
     enum A {
         Ok = i8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
     }
 }
 
@@ -33,7 +33,7 @@ fn f_u8() {
     enum A {
         Ok = u8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
     }
 }
 
index 5d7e61e9d1eec67fcb340de8ca036661ab9236e9..7316e737b6da8680379b2c617430e54b2703b4ad 100644 (file)
@@ -22,7 +22,7 @@ fn f_i8() {
     enum A {
         Ok = i8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
     }
 
     let x = A::Ok;
@@ -33,7 +33,7 @@ fn f_u8() {
     enum A {
         Ok = u8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
     }
 
     let x = A::Ok;
index 84a27a382006988820be6dac882733a5b7b3c9f0..d6ba09bb4c5bf072692b9677f3f4883dc99e4951 100644 (file)
@@ -9,46 +9,32 @@
 // except according to those terms.
 
 
-#[repr(u8)] //~ NOTE discriminant type specified here
+#[repr(u8)]
 enum Eu8 {
     Au8 = 23,
     Bu8 = 223,
-    Cu8 = -23, //~ ERROR discriminant value outside specified type
+    Cu8 = -23, //~ ERROR unary negation of unsigned integer
 }
 
-#[repr(i8)] //~ NOTE discriminant type specified here
-enum Ei8 {
-    Ai8 = 23,
-    Bi8 = -23,
-    Ci8 = 223, //~ ERROR discriminant value outside specified type
-}
-
-#[repr(u16)] //~ NOTE discriminant type specified here
+#[repr(u16)]
 enum Eu16 {
     Au16 = 23,
     Bu16 = 55555,
-    Cu16 = -22333, //~ ERROR discriminant value outside specified type
-}
-
-#[repr(i16)] //~ NOTE discriminant type specified here
-enum Ei16 {
-    Ai16 = 23,
-    Bi16 = -22333,
-    Ci16 = 55555, //~ ERROR discriminant value outside specified type
+    Cu16 = -22333, //~ ERROR unary negation of unsigned integer
 }
 
-#[repr(u32)] //~ NOTE discriminant type specified here
+#[repr(u32)]
 enum Eu32 {
     Au32 = 23,
     Bu32 = 3_000_000_000,
-    Cu32 = -2_000_000_000, //~ ERROR discriminant value outside specified type
+    Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
 }
 
-#[repr(i32)] //~ NOTE discriminant type specified here
-enum Ei32 {
-    Ai32 = 23,
-    Bi32 = -2_000_000_000,
-    Ci32 = 3_000_000_000, //~ ERROR discriminant value outside specified type
+#[repr(u64)]
+enum Eu64 {
+    Au32 = 23,
+    Bu32 = 3_000_000_000,
+    Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
 }
 
 // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`.  This is a
diff --git a/src/test/compile-fail/enum-discrim-too-small2.rs b/src/test/compile-fail/enum-discrim-too-small2.rs
new file mode 100644 (file)
index 0000000..d66716c
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(overflowing_literals)]
+#![allow(dead_code)]
+
+#[repr(i8)]
+enum Ei8 {
+    Ai8 = 23,
+    Bi8 = -23,
+    Ci8 = 223, //~ ERROR literal out of range for i8
+}
+
+#[repr(i16)]
+enum Ei16 {
+    Ai16 = 23,
+    Bi16 = -22333,
+    Ci16 = 55555, //~ ERROR literal out of range for i16
+}
+
+#[repr(i32)]
+enum Ei32 {
+    Ai32 = 23,
+    Bi32 = -2_000_000_000,
+    Ci32 = 3_000_000_000, //~ ERROR literal out of range for i32
+}
+
+#[repr(i64)]
+enum Ei64 {
+    Ai64 = 23,
+    Bi64 = -9223372036854775808,
+    Ci64 = 9223372036854775809, //~ ERROR literal out of range for i64
+}
+
+// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`.  This is a
+// little counterintuitive, but since the discriminant can store all the bits, and extracting it
+// with a cast requires specifying the signedness, there is no loss of information in those cases.
+// This also applies to isize and usize on 64-bit targets.
+
+pub fn main() { }
index ed1327f31185e8d565dd95307800193381e584a5..7ca274b81e574a5c6cf6962b926ddfb3ceff5b05 100644 (file)
@@ -10,7 +10,8 @@
 
 enum test {
     div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero
-    rem_zero = 1%0  //~ERROR constant evaluation error: attempted remainder with a divisor of zero
+    rem_zero = 1%0,
+//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero
 }
 
 fn main() {}
index 1c462779b433c707541e1bd19d0fafef17fb3f99..c920b6c171e3267be059344350416739d44b0141 100644 (file)
@@ -24,7 +24,7 @@ fn main() {
     //~^^ HELP cast through a thin pointer
 
     // #22955
-    q as *const [i32]; //~ ERROR casting
+    q as *const [i32]; //~ ERROR cannot cast
 
     // #21397
     let t: *mut (Trait + 'static) = 0 as *mut _; //~ ERROR casting
index 15cc17b19db33bfc9bb1b2695d95fa6bdfb3df20..546fc5e3c6063f91ae24b9d1f271697cbb817b76 100644 (file)
@@ -21,22 +21,7 @@ fn neg(self) -> u32 { 0 }
 //~| HELP use a cast or the `!` operator
 
 fn main() {
-    let a = -1;
-    //~^ ERROR unary negation of unsigned integer
-    //~| HELP use a cast or the `!` operator
-    let _b : u8 = a; // for infering variable a to u8.
-
-    -a;
-    //~^ ERROR unary negation of unsigned integer
-    //~| HELP use a cast or the `!` operator
-
-    let _d = -1u8;
-    //~^ ERROR unary negation of unsigned integer
-    //~| HELP use a cast or the `!` operator
-
-    for _ in -10..10u8 {}
-    //~^ ERROR unary negation of unsigned integer
-    //~| HELP use a cast or the `!` operator
-
+    let x = 5u8;
+    let _y = -x; //~ ERROR unary negation of unsigned integer
     -S; // should not trigger the gate; issue 26840
 }
diff --git a/src/test/compile-fail/feature-gate-negate-unsigned0.rs b/src/test/compile-fail/feature-gate-negate-unsigned0.rs
new file mode 100644 (file)
index 0000000..05b1943
--- /dev/null
@@ -0,0 +1,31 @@
+// 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.
+
+// Test that negating unsigned integers doesn't compile
+
+struct S;
+impl std::ops::Neg for S {
+    type Output = u32;
+    fn neg(self) -> u32 { 0 }
+}
+
+fn main() {
+    let a = -1;
+    //~^ ERROR unary negation of unsigned integer
+    let _b : u8 = a; // for infering variable a to u8.
+
+    let _d = -1u8;
+    //~^ ERROR unary negation of unsigned integer
+
+    for _ in -10..10u8 {}
+    //~^ ERROR unary negation of unsigned integer
+
+    -S; // should not trigger the gate; issue 26840
+}
index b378d2f885e833a754a7e4ed8fb92f75fe8c4943..bdf344dcdfe8da8377ba866e99756a1fb1ad3b39 100644 (file)
 
 enum Foo {
     A = 1,
-    B = 1, //~ ERROR discriminant value `1` already exists
+    B = 1, //~ ERROR discriminant value `1isize` already exists
     //~^^ NOTE conflicting
     C = 0,
-    D, //~ ERROR discriminant value `1` already exists
+    D, //~ ERROR discriminant value `1isize` already exists
     //~^^^^^ NOTE conflicting
-    E = N, //~ ERROR discriminant value `1` already exists
+    E = N, //~ ERROR discriminant value `1isize` already exists
     //~^^^^^^^ NOTE conflicting
 }
 
index 1dfff144cef98770b8661d782e4c2b231f8213c0..7c051784f61a7dbbf253550c40cb03dffad0dcee 100644 (file)
 struct MyStruct;
 
 impl Drop for MyStruct {
-//~^ ERROR conflicting implementations of trait
+//~^ NOTE conflicting implementation is here
     fn drop(&mut self) { }
 }
 
 impl Drop for MyStruct {
-//~^ NOTE conflicting implementation is here
+//~^ ERROR conflicting implementations of trait
     fn drop(&mut self) { }
 }
 
diff --git a/src/test/compile-fail/issue-31511.rs b/src/test/compile-fail/issue-31511.rs
new file mode 100644 (file)
index 0000000..dd1af2f
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.
+
+fn cast_thin_to_fat(x: *const ()) {
+    x as *const [u8];
+    //~^ ERROR: cannot cast thin pointer `*const ()` to fat pointer `*const [u8]`
+}
+
+fn main() {}
index 95921556c7db1de120f85c73887fc83e8fe23c87..fe51d0b69987a5142775be84bf7f3b54364bcac4 100644 (file)
@@ -35,23 +35,23 @@ fn main() {
     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
     //~^ ERROR attempted to divide by zero
     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow
+    //~^ ERROR attempted to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow
+    //~^ ERROR attempted to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow
+    //~^ ERROR attempted to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow
+    //~^ ERROR attempted to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow
+    //~^ ERROR attempted to calculate the remainder with overflow
     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero
+    //~^ ERROR attempted to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero
+    //~^ ERROR attempted to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero
+    //~^ ERROR attempted to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero
+    //~^ ERROR attempted to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero
+    //~^ ERROR attempted to calculate the remainder with a divisor of zero
 }
index 35be01970cb56d4acfef455f7ff060e05c899026..1c98abce0304e149f092ea7e0a4137c0cac303d5 100644 (file)
 
 enum Foo {
     A = 1i64,
-    //~^ ERROR mismatched types
-    //~| expected `isize`
-    //~| found `i64`
+    //~^ ERROR mismatched types:
+    //~| expected `isize`,
+    //~| found `i64` [E0080]
     B = 2u8
-    //~^ ERROR mismatched types
-    //~| expected `isize`
-    //~| found `u8`
+    //~^ ERROR mismatched types:
+    //~| expected `isize`,
+    //~| found `u8` [E0080]
 }
 
 fn main() {}
index 0b414ad73db6f9109bd33fc5106102bae088e7e5..29929c120c30f75784f2e4bd67adce7ad37be3e1 100644 (file)
@@ -24,11 +24,6 @@ fn bar() -> i8 {
     return 123;
 }
 
-fn baz() -> bool {
-    128 > bar() //~ ERROR comparison is useless due to type limits
-                //~^ WARNING literal out of range for i8
-}
-
 fn bleh() {
     let u = 42u8;
     let _ = u > 255; //~ ERROR comparison is useless due to type limits
@@ -40,11 +35,3 @@ fn bleh() {
     let _ = u >= 0; //~ ERROR comparison is useless due to type limits
     let _ = 0 <= u; //~ ERROR comparison is useless due to type limits
 }
-
-fn qux() {
-    let mut i = 1i8;
-    while 200 != i { //~ ERROR comparison is useless due to type limits
-                     //~^ WARNING literal out of range for i8
-        i += 1;
-    }
-}
diff --git a/src/test/compile-fail/lint-type-limits2.rs b/src/test/compile-fail/lint-type-limits2.rs
new file mode 100644 (file)
index 0000000..8fc18d1
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+// compile-flags: -D unused-comparisons
+fn main() { }
+
+
+fn bar() -> i8 {
+    return 123;
+}
+
+fn baz() -> bool {
+    128 > bar() //~ ERROR comparison is useless due to type limits
+                //~| WARN literal out of range for i8
+}
diff --git a/src/test/compile-fail/lint-type-limits3.rs b/src/test/compile-fail/lint-type-limits3.rs
new file mode 100644 (file)
index 0000000..b09dc0a
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+// compile-flags: -D unused-comparisons
+fn main() { }
+
+fn qux() {
+    let mut i = 1i8;
+    while 200 != i { //~ ERROR comparison is useless due to type limits
+                     //~| WARN literal out of range for i8
+        i += 1;
+    }
+}
index eb5b77f7a45a352a3d7fa6a0287e26e7ff188cf0..ce336905c0139e77ea5b6fcd9f47b86e09c7188a 100644 (file)
@@ -25,7 +25,6 @@ fn main() {
 
     let x2: i8 = -128; // should be OK
     let x1: i8 = 128; //~ error: literal out of range for i8
-    let x2: i8 = --128; //~ error: literal out of range for i8
 
     let x3: i8 = -129; //~ error: literal out of range for i8
     let x3: i8 = -(129); //~ error: literal out of range for i8
@@ -54,9 +53,4 @@ fn main() {
     let x = 18446744073709551615_i64; //~ error: literal out of range for i64
     let x: i64 = -9223372036854775809; //~ error: literal out of range for i64
     let x = -9223372036854775809_i64; //~ error: literal out of range for i64
-
-    let x = -3.40282348e+38_f32; //~ error: literal out of range for f32
-    let x =  3.40282348e+38_f32; //~ error: literal out of range for f32
-    let x = -1.7976931348623159e+308_f64; //~ error: literal out of range for f64
-    let x =  1.7976931348623159e+308_f64; //~ error: literal out of range for f64
 }
diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs
new file mode 100644 (file)
index 0000000..83300f1
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+
+#![deny(overflowing_literals)]
+
+#[allow(unused_variables)]
+fn main() {
+    let x2: i8 = --128; //~ error: literal out of range for i8
+
+    let x = -3.40282348e+38_f32; //~ error: literal out of range for f32
+    let x =  3.40282348e+38_f32; //~ error: literal out of range for f32
+    let x = -1.7976931348623159e+308_f64; //~ error: literal out of range for f64
+    let x =  1.7976931348623159e+308_f64; //~ error: literal out of range for f64
+}
index 9aab06ce14ee16b324075fcaed44fbedc7c63766..b9d632a8cf07e6ce33dcbcd4271e05758769b5d0 100644 (file)
@@ -198,9 +198,11 @@ pub trait PubTr<T = u8> {
     use self::m::PubTr as PrivUseAliasTr;
     type PrivAlias = m::Pub2;
     trait PrivTr {
+        type AssocAlias;
+    }
+    impl PrivTr for Priv {
         type AssocAlias = m::Pub3;
     }
-    impl PrivTr for Priv {}
 
     pub fn f1(arg: PrivUseAlias) {} // OK
 
@@ -245,9 +247,11 @@ trait PrivTr1<T = u8> {
     use self::PrivTr1 as PrivUseAliasTr;
     type PrivAlias = Priv2;
     trait PrivTr {
+        type AssocAlias;
+    }
+    impl PrivTr for Priv {
         type AssocAlias = Priv3;
     }
-    impl PrivTr for Priv {}
 
     pub trait Tr1: PrivUseAliasTr {} //~ WARN private trait in public interface
         //~^ WARNING hard error
index 9aa61418d6d047d60d2270c5d09de01525a8ab78..10b722946a8a89f847c5af45081ee29e40f9470c 100644 (file)
@@ -43,13 +43,17 @@ fn main() {
     let f = [0; -4_isize];
     //~^ ERROR mismatched types
     //~| expected `usize`
-    //~| found `isize`
-    //~| ERROR expected positive integer for repeat count, found negative integer [E0306]
+    //~| found `isize` [E0308]
+    //~| ERROR mismatched types:
+    //~| expected `usize`,
+    //~| found `isize` [E0307]
     let f = [0_usize; -1_isize];
     //~^ ERROR mismatched types
     //~| expected `usize`
-    //~| found `isize`
-    //~| ERROR expected positive integer for repeat count, found negative integer [E0306]
+    //~| found `isize` [E0308]
+    //~| ERROR mismatched types
+    //~| expected `usize`
+    //~| found `isize` [E0307]
     struct G {
         g: (),
     }
diff --git a/src/test/compile-fail/specialization/README.md b/src/test/compile-fail/specialization/README.md
new file mode 100644 (file)
index 0000000..f2b4bf9
--- /dev/null
@@ -0,0 +1,21 @@
+This directory contains the test for incorrect usage of specialization that
+should lead to compile failure. Those tests break down into a few categories:
+
+- Feature gating
+  - [On use of the `default` keyword](specialization-feature-gate-default.rs)
+  - [On overlapping impls](specialization-feature-gate-overlap.rs)
+
+- Overlap checking with specialization enabled
+  - [Basic overlap scenarios](specialization-overlap.rs)
+    - Includes purely structural overlap
+    - Includes purely trait-based overlap
+    - Includes mix
+  - [Overlap with differing polarity](specialization-overlap-negative.rs)
+
+- [Attempt to specialize without using `default`](specialization-no-default.rs)
+
+- [Attempt to change impl polarity in a specialization](specialization-polarity.rs)
+
+- Attempt to rely on projection of a `default` type
+  - [Rely on it externally in both generic and monomorphic contexts](specialization-default-projection.rs)
+  - [Rely on it both within an impl and outside it](specialization-default-types.rs)
diff --git a/src/test/compile-fail/specialization/specialization-default-projection.rs b/src/test/compile-fail/specialization/specialization-default-projection.rs
new file mode 100644 (file)
index 0000000..96cbd7a
--- /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.
+
+#![feature(specialization)]
+
+// Make sure we can't project defaulted associated types
+
+trait Foo {
+    type Assoc;
+}
+
+impl<T> Foo for T {
+    default type Assoc = ();
+}
+
+impl Foo for u8 {
+    type Assoc = String;
+}
+
+fn generic<T>() -> <T as Foo>::Assoc {
+    // `T` could be some downstream crate type that specializes (or,
+    // for that matter, `u8`).
+
+    () //~ ERROR mismatched types
+}
+
+fn monomorphic() -> () {
+    // Even though we know that `()` is not specialized in a
+    // downstream crate, typeck refuses to project here.
+
+    generic::<()>() //~ ERROR mismatched types
+}
+
+fn main() {
+    // No error here, we CAN project from `u8`, as there is no `default`
+    // in that impl.
+    let s: String = generic::<u8>();
+    println!("{}", s); // bad news if this all compiles
+}
diff --git a/src/test/compile-fail/specialization/specialization-default-types.rs b/src/test/compile-fail/specialization/specialization-default-types.rs
new file mode 100644 (file)
index 0000000..18acecb
--- /dev/null
@@ -0,0 +1,45 @@
+// 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.
+
+// It should not be possible to use the concrete value of a defaulted
+// associated type in the impl defining it -- otherwise, what happens
+// if it's overridden?
+
+#![feature(specialization)]
+
+trait Example {
+    type Output;
+    fn generate(self) -> Self::Output;
+}
+
+impl<T> Example for T {
+    default type Output = Box<T>;
+    default fn generate(self) -> Self::Output {
+        Box::new(self) //~ ERROR mismatched types
+    }
+}
+
+impl Example for bool {
+    type Output = bool;
+    fn generate(self) -> bool { self }
+}
+
+fn trouble<T>(t: T) -> Box<T> {
+    Example::generate(t) //~ ERROR mismatched types
+}
+
+fn weaponize() -> bool {
+    let b: Box<bool> = trouble(true);
+    *b
+}
+
+fn main() {
+    weaponize();
+}
diff --git a/src/test/compile-fail/specialization/specialization-feature-gate-default.rs b/src/test/compile-fail/specialization/specialization-feature-gate-default.rs
new file mode 100644 (file)
index 0000000..e7c194c
--- /dev/null
@@ -0,0 +1,21 @@
+// 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.
+
+// Check that specialization must be ungated to use the `default` keyword
+
+trait Foo {
+    fn foo(&self);
+}
+
+impl<T> Foo for T {
+    default fn foo(&self) {} //~ ERROR specialization is unstable
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/specialization/specialization-feature-gate-overlap.rs b/src/test/compile-fail/specialization/specialization-feature-gate-overlap.rs
new file mode 100644 (file)
index 0000000..d11ab56
--- /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.
+
+// Check that writing an overlapping impl is not allow unless specialization is ungated.
+
+trait Foo {
+    fn foo(&self);
+}
+
+impl<T> Foo for T {
+    fn foo(&self) {}
+}
+
+impl Foo for u8 { //~ ERROR E0119
+    fn foo(&self) {}
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/specialization/specialization-no-default.rs b/src/test/compile-fail/specialization/specialization-no-default.rs
new file mode 100644 (file)
index 0000000..9615616
--- /dev/null
@@ -0,0 +1,95 @@
+// 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(specialization)]
+
+// Check a number of scenarios in which one impl tries to override another,
+// without correctly using `default`.
+
+////////////////////////////////////////////////////////////////////////////////
+// Test 1: one layer of specialization, multiple methods, missing `default`
+////////////////////////////////////////////////////////////////////////////////
+
+trait Foo {
+    fn foo(&self);
+    fn bar(&self);
+}
+
+impl<T> Foo for T {
+    fn foo(&self) {}
+    fn bar(&self) {}
+}
+
+impl Foo for u8 {}
+impl Foo for u16 {
+    fn foo(&self) {} //~ ERROR E0520
+}
+impl Foo for u32 {
+    fn bar(&self) {} //~ ERROR E0520
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Test 2: one layer of specialization, missing `default` on associated type
+////////////////////////////////////////////////////////////////////////////////
+
+trait Bar {
+    type T;
+}
+
+impl<T> Bar for T {
+    type T = u8;
+}
+
+impl Bar for u8 {
+    type T = (); //~ ERROR E0520
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Test 3a: multiple layers of specialization, missing interior `default`
+////////////////////////////////////////////////////////////////////////////////
+
+trait Baz {
+    fn baz(&self);
+}
+
+impl<T> Baz for T {
+    default fn baz(&self) {}
+}
+
+impl<T: Clone> Baz for T {
+    fn baz(&self) {}
+}
+
+impl Baz for i32 {
+    fn baz(&self) {} //~ ERROR E0520
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Test 3b: multiple layers of specialization, missing interior `default`,
+// redundant `default` in bottom layer.
+////////////////////////////////////////////////////////////////////////////////
+
+trait Redundant {
+    fn redundant(&self);
+}
+
+impl<T> Redundant for T {
+    default fn redundant(&self) {}
+}
+
+impl<T: Clone> Redundant for T {
+    fn redundant(&self) {}
+}
+
+impl Redundant for i32 {
+    default fn redundant(&self) {} //~ ERROR E0520
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/specialization/specialization-overlap-negative.rs b/src/test/compile-fail/specialization/specialization-overlap-negative.rs
new file mode 100644 (file)
index 0000000..62a6d8d
--- /dev/null
@@ -0,0 +1,21 @@
+// 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(optin_builtin_traits)]
+#![feature(specialization)]
+
+trait MyTrait {}
+
+struct TestType<T>(::std::marker::PhantomData<T>);
+
+unsafe impl<T: Clone> Send for TestType<T> {}
+impl<T: MyTrait> !Send for TestType<T> {} //~ ERROR E0119
+
+fn main() {}
diff --git a/src/test/compile-fail/specialization/specialization-overlap.rs b/src/test/compile-fail/specialization/specialization-overlap.rs
new file mode 100644 (file)
index 0000000..f579817
--- /dev/null
@@ -0,0 +1,29 @@
+// 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(specialization)]
+
+trait Foo {}
+impl<T: Clone> Foo for T {}
+impl<T> Foo for Vec<T> {} //~ ERROR E0119
+
+trait Bar {}
+impl<T> Bar for (T, u8) {}
+impl<T> Bar for (u8, T) {} //~ ERROR E0119
+
+trait Baz<U> {}
+impl<T> Baz<T> for u8 {}
+impl<T> Baz<u8> for T {} //~ ERROR E0119
+
+trait Qux {}
+impl<T: Clone> Qux for T {}
+impl<T: Eq> Qux for T {} //~ ERROR E0119
+
+fn main() {}
diff --git a/src/test/compile-fail/specialization/specialization-polarity.rs b/src/test/compile-fail/specialization/specialization-polarity.rs
new file mode 100755 (executable)
index 0000000..27a3e31
--- /dev/null
@@ -0,0 +1,30 @@
+// 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.
+
+// Make sure specialization cannot change impl polarity
+
+#![feature(optin_builtin_traits)]
+#![feature(specialization)]
+
+trait Foo {}
+
+impl Foo for .. {}
+
+impl<T> Foo for T {}
+impl !Foo for u8 {} //~ ERROR E0119
+
+trait Bar {}
+
+impl Bar for .. {}
+
+impl<T> !Bar for T {}
+impl Bar for u8 {} //~ ERROR E0119
+
+fn main() {}
diff --git a/src/test/parse-fail/default.rs b/src/test/parse-fail/default.rs
new file mode 100644 (file)
index 0000000..d18401e
--- /dev/null
@@ -0,0 +1,35 @@
+// 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.
+
+// compile-flags: -Z parse-only
+
+// Test successful and unsucessful parsing of the `default` contextual keyword
+
+trait Foo {
+    fn foo<T: Default>() -> T;
+}
+
+impl Foo for u8 {
+    default fn foo<T: Default>() -> T {
+        T::default()
+    }
+}
+
+impl Foo for u16 {
+    pub default fn foo<T: Default>() -> T {
+        T::default()
+    }
+}
+
+impl Foo for u32 {
+    default pub fn foo<T: Default>() -> T { T::default() } //~ ERROR expected one of
+}
+
+fn main() {}
index be6bd516d6fe439388160260d61fc3c4f824d302..a489864e3f7370cb8ae0b6b8321106f2a2c2176b 100644 (file)
@@ -16,6 +16,6 @@ impl Foo {
     fn foo() {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
+} //~ ERROR expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
 
 fn main() {}
index d1d8d3acf91871bc581d3799380a47aca6d1126f..d9789d55a6faf51d160a585d0645ca7c2ce7dfa3 100644 (file)
@@ -14,6 +14,6 @@
 
 impl Foo {
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
+} //~ ERROR expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
 
 fn main() {}
index 7b6caad86b6ccc0b6005dc41c869648a065650ec..b4c25a75c9086b4f2ef118c8038097fb7fe7a609 100644 (file)
@@ -15,4 +15,4 @@
 impl S {
     static fn f() {}
 }
-//~^^ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
+//~^^ ERROR expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`
index 29063c5a607e59c0dcf3dea14c96ac24c38184ef..4ff531d4755c80c41b3191188736af04cbfa243c 100644 (file)
@@ -216,7 +216,10 @@ fn build_exec_options(sysroot: PathBuf) -> Options {
 /// for crates used in the given input.
 fn compile_program(input: &str, sysroot: PathBuf)
                    -> Option<(llvm::ModuleRef, Vec<PathBuf>)> {
-    let input = Input::Str(input.to_string());
+    let input = Input::Str {
+        name: driver::anon_src(),
+        input: input.to_string(),
+    };
     let thread = Builder::new().name("compile_program".to_string());
 
     let handle = thread.spawn(move || {
index 43ae356feede66dbac5a6c19d6bcf29b51f26000..80c06ca3274f245af1bd718ae3ae7edfc31d0782 100644 (file)
@@ -18,7 +18,7 @@
 
 use rustc::session::{build_session, Session};
 use rustc::session::config::{basic_options, build_configuration, Input, OutputType};
-use rustc_driver::driver::{compile_input, CompileController};
+use rustc_driver::driver::{compile_input, CompileController, anon_src};
 use rustc_metadata::cstore::CStore;
 use syntax::diagnostics::registry::Registry;
 use syntax::parse::token;
@@ -67,7 +67,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
 
     compile_input(&sess, &cstore,
             cfg,
-            &Input::Str(code),
+            &Input::Str { name: anon_src(), input: code },
             &None,
             &Some(output),
             None,
index 5961ed8d3390d9ac4a1266e77e9c24622f7270c0..562040dc5620ba2fc54dea65eb878d5bc6bebcd5 100644 (file)
@@ -10,7 +10,7 @@
 
 // A very basic test of const fn functionality.
 
-#![feature(const_fn)]
+#![feature(const_fn, const_indexing)]
 
 const fn add(x: u32, y: u32) -> u32 {
     x + y
@@ -24,6 +24,14 @@ const fn sub(x: u32, y: u32) -> u32 {
     x / y
 }
 
+const fn generic<T>(t: T) -> T {
+    t
+}
+
+const fn generic_arr<T: Copy>(t: [T; 1]) -> T {
+    t[0]
+}
+
 const SUM: u32 = add(44, 22);
 const DIFF: u32 = sub(44, 22);
 const DIV: u32 = unsafe{div(44, 22)};
@@ -36,4 +44,6 @@ fn main() {
     assert_eq!(DIV, 2);
 
     let _: [&'static str; sub(100, 99) as usize] = ["hi"];
+    let _: [&'static str; generic(1)] = ["hi"];
+    let _: [&'static str; generic_arr([1])] = ["hi"];
 }
diff --git a/src/test/run-pass/const-negation.rs b/src/test/run-pass/const-negation.rs
new file mode 100644 (file)
index 0000000..96f4217
--- /dev/null
@@ -0,0 +1,42 @@
+// 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.
+
+#![feature(stmt_expr_attributes)]
+
+#[deny(const_err)]
+
+fn main() {
+    #[cfg(target_pointer_width = "32")]
+    const I: isize = -2147483648isize;
+    #[cfg(target_pointer_width = "64")]
+    const I: isize = -9223372036854775808isize;
+    assert_eq!(::std::i32::MIN as u64, 0xffffffff80000000);
+    assert_eq!(-2147483648isize as u64, 0xffffffff80000000);
+    assert_eq!(::std::i64::MIN as u64, 0x8000000000000000);
+    #[cfg(target_pointer_width = "64")]
+    assert_eq!(-9223372036854775808isize as u64, 0x8000000000000000);
+    #[cfg(target_pointer_width = "32")]
+    assert_eq!(-9223372036854775808isize as u64, 0);
+    const J: usize = ::std::i32::MAX as usize;
+    const K: usize = -1i32 as u32 as usize;
+    const L: usize = ::std::i32::MIN as usize;
+    const M: usize = ::std::i64::MIN as usize;
+    match 5 {
+        J => {},
+        K => {},
+        L => {},
+        M => {},
+        _ => {}
+    }
+    match 5 {
+        I => {},
+        _ => {}
+    }
+}
index 3e6c72c993a0aa5e480919674aff6b4b0cdc62db..ed55d5c8b171e6180b0296c4201e2b80796fbb0b 100644 (file)
 
 #![feature(associated_type_defaults)]
 
-trait Foo<T> {
-    type Out = T;
-    fn foo(&self) -> Self::Out;
+trait Foo<T: Default + ToString> {
+    type Out: Default + ToString = T;
 }
 
 impl Foo<u32> for () {
-    fn foo(&self) -> u32 {
-        4u32
-    }
 }
 
-impl Foo<u64> for bool {
-    type Out = ();
-    fn foo(&self) {}
+impl Foo<u64> for () {
+    type Out = bool;
 }
 
 fn main() {
-    assert_eq!(<() as Foo<u32>>::foo(&()), 4u32);
-    assert_eq!(<bool as Foo<u64>>::foo(&true), ());
+    assert_eq!(
+        <() as Foo<u32>>::Out::default().to_string(),
+        "0");
+    assert_eq!(
+        <() as Foo<u64>>::Out::default().to_string(),
+        "false");
 }
index 99e44735d0f03a11a25a9517d08c8480bdb089b6..53c44f2bb24b5f16ce3eae5d008182fa2ebaba30 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(stmt_expr_attributes)]
 
 use std::mem::size_of;
 
@@ -46,11 +47,6 @@ enum Ei64 {
     Bi64 = 0x8000_0000
 }
 
-enum Eu64 {
-    Au64 = 0,
-    Bu64 = 0x8000_0000_0000_0000
-}
-
 pub fn main() {
     assert_eq!(size_of::<Ei8>(), 1);
     assert_eq!(size_of::<Eu8>(), 1);
@@ -58,6 +54,8 @@ pub fn main() {
     assert_eq!(size_of::<Eu16>(), 2);
     assert_eq!(size_of::<Ei32>(), 4);
     assert_eq!(size_of::<Eu32>(), 4);
+    #[cfg(target_pointer_width = "64")]
     assert_eq!(size_of::<Ei64>(), 8);
-    assert_eq!(size_of::<Eu64>(), 8);
+    #[cfg(target_pointer_width = "32")]
+    assert_eq!(size_of::<Ei64>(), 4);
 }
diff --git a/src/test/run-pass/issue-23833.rs b/src/test/run-pass/issue-23833.rs
new file mode 100644 (file)
index 0000000..7d63c41
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const A_I8_T
+    : [u32; (i8::MAX as i8 - 1i8) as usize]
+    = [0; (i8::MAX as usize) - 1];
+
+fn main() {
+    foo(&A_I8_T[..]);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+    println!("{:?}", x);
+}
diff --git a/src/test/run-pass/issue-29663.rs b/src/test/run-pass/issue-29663.rs
new file mode 100644 (file)
index 0000000..9a77be0
--- /dev/null
@@ -0,0 +1,64 @@
+// 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.
+
+// write_volatile causes an LLVM assert with composite types
+
+#![feature(volatile)]
+use std::ptr::{read_volatile, write_volatile};
+
+#[derive(Debug, Eq, PartialEq)]
+struct A(u32);
+#[derive(Debug, Eq, PartialEq)]
+struct B(u64);
+#[derive(Debug, Eq, PartialEq)]
+struct C(u32, u32);
+#[derive(Debug, Eq, PartialEq)]
+struct D(u64, u64);
+#[derive(Debug, Eq, PartialEq)]
+struct E([u64; 32]);
+
+fn main() {
+    unsafe {
+        let mut x: u32 = 0;
+        write_volatile(&mut x, 1);
+        assert_eq!(read_volatile(&x), 1);
+        assert_eq!(x, 1);
+
+        let mut x: u64 = 0;
+        write_volatile(&mut x, 1);
+        assert_eq!(read_volatile(&x), 1);
+        assert_eq!(x, 1);
+
+        let mut x = A(0);
+        write_volatile(&mut x, A(1));
+        assert_eq!(read_volatile(&x), A(1));
+        assert_eq!(x, A(1));
+
+        let mut x = B(0);
+        write_volatile(&mut x, B(1));
+        assert_eq!(read_volatile(&x), B(1));
+        assert_eq!(x, B(1));
+
+        let mut x = C(0, 0);
+        write_volatile(&mut x, C(1, 1));
+        assert_eq!(read_volatile(&x), C(1, 1));
+        assert_eq!(x, C(1, 1));
+
+        let mut x = D(0, 0);
+        write_volatile(&mut x, D(1, 1));
+        assert_eq!(read_volatile(&x), D(1, 1));
+        assert_eq!(x, D(1, 1));
+
+        let mut x = E([0; 32]);
+        write_volatile(&mut x, E([1; 32]));
+        assert_eq!(read_volatile(&x), E([1; 32]));
+        assert_eq!(x, E([1; 32]));
+    }
+}
diff --git a/src/test/run-pass/specialization/README.md b/src/test/run-pass/specialization/README.md
new file mode 100644 (file)
index 0000000..1373a2c
--- /dev/null
@@ -0,0 +1,37 @@
+Tests that specialization is working correctly:
+
+- Dispatch
+  - [On methods](specialization-basics.rs), includes:
+    - Specialization via adding a trait bound
+      - Including both remote and local traits
+    - Specialization via pure structure (e.g. `(T, U)` vs `(T, T)`)
+    - Specialization via concrete types vs unknown types
+      - In top level of the trait reference
+      - Embedded within another type (`Vec<T>` vs `Vec<i32>`)
+  - [Specialization based on super trait relationships](specialization-super-traits.rs)
+  - [On assoc fns](specialization-assoc-fns.rs)
+  - [Ensure that impl order doesn't matter](specialization-out-of-order.rs)
+
+- Item inheritance
+  - [Correct default cascading for methods](specialization-default-methods.rs)
+  - Inheritance works across impls with varying generics
+    - [With projections](specialization-translate-projections.rs)
+    - [With projections that involve input types](specialization-translate-projections-with-params.rs)
+
+- Normalization issues
+  - [Non-default assoc types can be projected](specialization-projection.rs)
+    - Including non-specialized cases
+    - Including specialized cases
+  - [Specialized Impls can happen on projections](specialization-on-projection.rs)
+  - [Projections and aliases play well together](specialization-projection-alias.rs)
+  - [Projections involving specialization allowed in the trait ref for impls, and overlap can still be determined](specialization-overlap-projection.rs)
+    - Only works for the simple case where the most specialized impl directly
+      provides a non-`default` associated type
+
+- Across crates
+  - [For traits defined in upstream crate](specialization-allowed-cross-crate.rs)
+  - [Full method dispatch tests, drawing from upstream crate](specialization-cross-crate.rs)
+    - Including *additional* local specializations
+  - [Full method dispatch tests, *without* turning on specialization in local crate](specialization-cross-crate-no-gate.rs)
+  - [Test that defaults cascade correctly from upstream crates](specialization-cross-crate-defaults.rs)
+    - Including *additional* local use of defaults
diff --git a/src/test/run-pass/specialization/specialization-allowed-cross-crate.rs b/src/test/run-pass/specialization/specialization-allowed-cross-crate.rs
new file mode 100644 (file)
index 0000000..6b999f3
--- /dev/null
@@ -0,0 +1,31 @@
+// 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:go_trait.rs
+
+#![feature(specialization)]
+
+extern crate go_trait;
+
+use go_trait::{Go,GoMut};
+use std::fmt::Debug;
+use std::default::Default;
+
+struct MyThingy;
+
+impl Go for MyThingy {
+    fn go(&self, arg: isize) { }
+}
+
+impl GoMut for MyThingy {
+    fn go_mut(&mut self, arg: isize) { }
+}
+
+fn main() { }
diff --git a/src/test/run-pass/specialization/specialization-assoc-fns.rs b/src/test/run-pass/specialization/specialization-assoc-fns.rs
new file mode 100644 (file)
index 0000000..577f217
--- /dev/null
@@ -0,0 +1,37 @@
+// 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.
+
+// Test that non-method associated functions can be specialized
+
+#![feature(specialization)]
+
+trait Foo {
+    fn mk() -> Self;
+}
+
+impl<T: Default> Foo for T {
+    default fn mk() -> T {
+        T::default()
+    }
+}
+
+impl Foo for Vec<u8> {
+    fn mk() -> Vec<u8> {
+        vec![0]
+    }
+}
+
+fn main() {
+    let v1: Vec<i32> = Foo::mk();
+    let v2: Vec<u8> = Foo::mk();
+
+    assert!(v1.len() == 0);
+    assert!(v2.len() == 1);
+}
diff --git a/src/test/run-pass/specialization/specialization-basics.rs b/src/test/run-pass/specialization/specialization-basics.rs
new file mode 100644 (file)
index 0000000..b11495e
--- /dev/null
@@ -0,0 +1,106 @@
+// 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.
+
+#![feature(specialization)]
+
+// Tests a variety of basic specialization scenarios and method
+// dispatch for them.
+
+trait Foo {
+    fn foo(&self) -> &'static str;
+}
+
+impl<T> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic"
+    }
+}
+
+impl<T: Clone> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic Clone"
+    }
+}
+
+impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
+    default fn foo(&self) -> &'static str {
+        "generic pair"
+    }
+}
+
+impl<T: Clone> Foo for (T, T) {
+    default fn foo(&self) -> &'static str {
+        "generic uniform pair"
+    }
+}
+
+impl Foo for (u8, u32) {
+    default fn foo(&self) -> &'static str {
+        "(u8, u32)"
+    }
+}
+
+impl Foo for (u8, u8) {
+    default fn foo(&self) -> &'static str {
+        "(u8, u8)"
+    }
+}
+
+impl<T: Clone> Foo for Vec<T> {
+    default fn foo(&self) -> &'static str {
+        "generic Vec"
+    }
+}
+
+impl Foo for Vec<i32> {
+    fn foo(&self) -> &'static str {
+        "Vec<i32>"
+    }
+}
+
+impl Foo for String {
+    fn foo(&self) -> &'static str {
+        "String"
+    }
+}
+
+impl Foo for i32 {
+    fn foo(&self) -> &'static str {
+        "i32"
+    }
+}
+
+struct NotClone;
+
+trait MyMarker {}
+impl<T: Clone + MyMarker> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic Clone + MyMarker"
+    }
+}
+
+#[derive(Clone)]
+struct MarkedAndClone;
+impl MyMarker for MarkedAndClone {}
+
+fn  main() {
+    assert!(NotClone.foo() == "generic");
+    assert!(0u8.foo() == "generic Clone");
+    assert!(vec![NotClone].foo() == "generic");
+    assert!(vec![0u8].foo() == "generic Vec");
+    assert!(vec![0i32].foo() == "Vec<i32>");
+    assert!(0i32.foo() == "i32");
+    assert!(String::new().foo() == "String");
+    assert!(((), 0).foo() == "generic pair");
+    assert!(((), ()).foo() == "generic uniform pair");
+    assert!((0u8, 0u32).foo() == "(u8, u32)");
+    assert!((0u8, 0u8).foo() == "(u8, u8)");
+    assert!(MarkedAndClone.foo() == "generic Clone + MyMarker");
+}
diff --git a/src/test/run-pass/specialization/specialization-cross-crate-defaults.rs b/src/test/run-pass/specialization/specialization-cross-crate-defaults.rs
new file mode 100644 (file)
index 0000000..bc695ea
--- /dev/null
@@ -0,0 +1,49 @@
+// 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:specialization_cross_crate_defaults.rs
+
+#![feature(specialization)]
+
+extern crate specialization_cross_crate_defaults;
+
+use specialization_cross_crate_defaults::*;
+
+struct LocalDefault;
+struct LocalOverride;
+
+impl Foo for LocalDefault {}
+
+impl Foo for LocalOverride {
+    fn foo(&self) -> bool { true }
+}
+
+fn test_foo() {
+    assert!(0i8.foo() == false);
+    assert!(0i32.foo() == false);
+    assert!(0i64.foo() == true);
+
+    assert!(LocalDefault.foo() == false);
+    assert!(LocalOverride.foo() == true);
+}
+
+fn test_bar() {
+    assert!(0u8.bar() == 0);
+    assert!(0i32.bar() == 1);
+    assert!("hello".bar() == 0);
+    assert!(vec![()].bar() == 2);
+    assert!(vec![0i32].bar() == 2);
+    assert!(vec![0i64].bar() == 3);
+}
+
+fn main() {
+    test_foo();
+    test_bar();
+}
diff --git a/src/test/run-pass/specialization/specialization-cross-crate-no-gate.rs b/src/test/run-pass/specialization/specialization-cross-crate-no-gate.rs
new file mode 100644 (file)
index 0000000..b954853
--- /dev/null
@@ -0,0 +1,29 @@
+// 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.
+
+// Test that specialization works even if only the upstream crate enables it
+
+// aux-build:specialization_cross_crate.rs
+
+extern crate specialization_cross_crate;
+
+use specialization_cross_crate::*;
+
+fn  main() {
+    assert!(0u8.foo() == "generic Clone");
+    assert!(vec![0u8].foo() == "generic Vec");
+    assert!(vec![0i32].foo() == "Vec<i32>");
+    assert!(0i32.foo() == "i32");
+    assert!(String::new().foo() == "String");
+    assert!(((), 0).foo() == "generic pair");
+    assert!(((), ()).foo() == "generic uniform pair");
+    assert!((0u8, 0u32).foo() == "(u8, u32)");
+    assert!((0u8, 0u8).foo() == "(u8, u8)");
+}
diff --git a/src/test/run-pass/specialization/specialization-cross-crate.rs b/src/test/run-pass/specialization/specialization-cross-crate.rs
new file mode 100644 (file)
index 0000000..7593ac4
--- /dev/null
@@ -0,0 +1,58 @@
+// 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:specialization_cross_crate.rs
+
+#![feature(specialization)]
+
+extern crate specialization_cross_crate;
+
+use specialization_cross_crate::*;
+
+struct NotClone;
+
+#[derive(Clone)]
+struct MarkedAndClone;
+impl MyMarker for MarkedAndClone {}
+
+struct MyType<T>(T);
+impl<T> Foo for MyType<T> {
+    default fn foo(&self) -> &'static str {
+        "generic MyType"
+    }
+}
+
+impl Foo for MyType<u8> {
+    fn foo(&self) -> &'static str {
+        "MyType<u8>"
+    }
+}
+
+struct MyOtherType;
+impl Foo for MyOtherType {}
+
+fn  main() {
+    assert!(NotClone.foo() == "generic");
+    assert!(0u8.foo() == "generic Clone");
+    assert!(vec![NotClone].foo() == "generic");
+    assert!(vec![0u8].foo() == "generic Vec");
+    assert!(vec![0i32].foo() == "Vec<i32>");
+    assert!(0i32.foo() == "i32");
+    assert!(String::new().foo() == "String");
+    assert!(((), 0).foo() == "generic pair");
+    assert!(((), ()).foo() == "generic uniform pair");
+    assert!((0u8, 0u32).foo() == "(u8, u32)");
+    assert!((0u8, 0u8).foo() == "(u8, u8)");
+    assert!(MarkedAndClone.foo() == "generic Clone + MyMarker");
+
+    assert!(MyType(()).foo() == "generic MyType");
+    assert!(MyType(0u8).foo() == "MyType<u8>");
+    assert!(MyOtherType.foo() == "generic");
+}
diff --git a/src/test/run-pass/specialization/specialization-default-methods.rs b/src/test/run-pass/specialization/specialization-default-methods.rs
new file mode 100644 (file)
index 0000000..3f0f21f
--- /dev/null
@@ -0,0 +1,94 @@
+// 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(specialization)]
+
+// Test that default methods are cascaded correctly
+
+// First, test only use of explicit `default` items:
+
+trait Foo {
+    fn foo(&self) -> bool;
+}
+
+// Specialization tree for Foo:
+//
+//        T
+//       / \
+//    i32   i64
+
+impl<T> Foo for T {
+    default fn foo(&self) -> bool { false }
+}
+
+impl Foo for i32 {}
+
+impl Foo for i64 {
+    fn foo(&self) -> bool { true }
+}
+
+fn test_foo() {
+    assert!(0i8.foo() == false);
+    assert!(0i32.foo() == false);
+    assert!(0i64.foo() == true);
+}
+
+// Next, test mixture of explicit `default` and provided methods:
+
+trait Bar {
+    fn bar(&self) -> i32 { 0 }
+}
+
+// Specialization tree for Bar.
+// Uses of $ designate that method is provided
+//
+//           $Bar   (the trait)
+//             |
+//             T
+//            /|\
+//           / | \
+//          /  |  \
+//         /   |   \
+//        /    |    \
+//       /     |     \
+//     $i32   &str  $Vec<T>
+//                    /\
+//                   /  \
+//            Vec<i32>  $Vec<i64>
+
+// use the provided method
+impl<T> Bar for T {}
+
+impl Bar for i32 {
+    fn bar(&self) -> i32 { 1 }
+}
+impl<'a> Bar for &'a str {}
+
+impl<T> Bar for Vec<T> {
+    default fn bar(&self) -> i32 { 2 }
+}
+impl Bar for Vec<i32> {}
+impl Bar for Vec<i64> {
+    fn bar(&self) -> i32 { 3 }
+}
+
+fn test_bar() {
+    assert!(0u8.bar() == 0);
+    assert!(0i32.bar() == 1);
+    assert!("hello".bar() == 0);
+    assert!(vec![()].bar() == 2);
+    assert!(vec![0i32].bar() == 2);
+    assert!(vec![0i64].bar() == 3);
+}
+
+fn main() {
+    test_foo();
+    test_bar();
+}
diff --git a/src/test/run-pass/specialization/specialization-on-projection.rs b/src/test/run-pass/specialization/specialization-on-projection.rs
new file mode 100644 (file)
index 0000000..acf78de
--- /dev/null
@@ -0,0 +1,31 @@
+// 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(specialization)]
+
+// Ensure that specialization works for impls defined directly on a projection
+
+trait Foo<T> {}
+
+trait Assoc {
+    type Item;
+}
+
+impl<T: Assoc> Foo<T::Item> for T {}
+
+struct Struct;
+
+impl Assoc for Struct {
+    type Item = u8;
+}
+
+impl Foo<u8> for Struct {}
+
+fn main() {}
diff --git a/src/test/run-pass/specialization/specialization-out-of-order.rs b/src/test/run-pass/specialization/specialization-out-of-order.rs
new file mode 100644 (file)
index 0000000..2d293f4
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+// Test that you can list the more specific impl before the more general one.
+
+#![feature(specialization)]
+
+trait Foo {
+    type Out;
+}
+
+impl Foo for bool {
+    type Out = ();
+}
+
+impl<T> Foo for T {
+    default type Out = bool;
+}
+
+fn main() {}
diff --git a/src/test/run-pass/specialization/specialization-overlap-projection.rs b/src/test/run-pass/specialization/specialization-overlap-projection.rs
new file mode 100644 (file)
index 0000000..20046ee
--- /dev/null
@@ -0,0 +1,33 @@
+// 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.
+
+// Test that impls on projected self types can resolve overlap, even when the
+// projections involve specialization, so long as the associated type is
+// provided by the most specialized impl.
+
+#![feature(specialization)]
+
+trait Assoc {
+    type Output;
+}
+
+impl<T> Assoc for T {
+    default type Output = bool;
+}
+
+impl Assoc for u8 { type Output = u8; }
+impl Assoc for u16 { type Output = u16; }
+
+trait Foo {}
+impl Foo for u32 {}
+impl Foo for <u8 as Assoc>::Output {}
+impl Foo for <u16 as Assoc>::Output {}
+
+fn main() {}
diff --git a/src/test/run-pass/specialization/specialization-projection-alias.rs b/src/test/run-pass/specialization/specialization-projection-alias.rs
new file mode 100644 (file)
index 0000000..7fce1cc
--- /dev/null
@@ -0,0 +1,32 @@
+// 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.
+
+#![feature(specialization)]
+
+// Regression test for ICE when combining specialized associated types and type
+// aliases
+
+trait Id_ {
+    type Out;
+}
+
+type Id<T> = <T as Id_>::Out;
+
+impl<T> Id_ for T {
+    default type Out = T;
+}
+
+fn test_proection() {
+    let x: Id<bool> = panic!();
+}
+
+fn main() {
+
+}
diff --git a/src/test/run-pass/specialization/specialization-projection.rs b/src/test/run-pass/specialization/specialization-projection.rs
new file mode 100644 (file)
index 0000000..4e0bdec
--- /dev/null
@@ -0,0 +1,49 @@
+// 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(specialization)]
+
+// Make sure we *can* project non-defaulted associated types
+// cf compile-fail/specialization-default-projection.rs
+
+// First, do so without any use of specialization
+
+trait Foo {
+    type Assoc;
+}
+
+impl<T> Foo for T {
+    type Assoc = ();
+}
+
+fn generic_foo<T>() -> <T as Foo>::Assoc {
+    ()
+}
+
+// Next, allow for one layer of specialization
+
+trait Bar {
+    type Assoc;
+}
+
+impl<T> Bar for T {
+    default type Assoc = ();
+}
+
+impl<T: Clone> Bar for T {
+    type Assoc = u8;
+}
+
+fn generic_bar_clone<T: Clone>() -> <T as Bar>::Assoc {
+    0u8
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/specialization/specialization-super-traits.rs b/src/test/run-pass/specialization/specialization-super-traits.rs
new file mode 100644 (file)
index 0000000..a9b3bfc
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+
+#![feature(specialization)]
+
+// Test that you can specialize via an explicit trait hierarchy
+
+// FIXME: this doesn't work yet...
+
+trait Parent {}
+trait Child: Parent {}
+
+trait Foo {}
+
+impl<T: Parent> Foo for T {}
+impl<T: Child> Foo for T {}
+
+fn main() {}
diff --git a/src/test/run-pass/specialization/specialization-translate-projections-with-params.rs b/src/test/run-pass/specialization/specialization-translate-projections-with-params.rs
new file mode 100644 (file)
index 0000000..647d552
--- /dev/null
@@ -0,0 +1,40 @@
+// 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.
+
+// Ensure that provided items are inherited properly even when impls vary in
+// type parameters *and* rely on projections, and the type parameters are input
+// types on the trait.
+
+#![feature(specialization)]
+
+trait Trait<T> {
+    fn convert(&self) -> T;
+}
+trait WithAssoc {
+    type Item;
+    fn as_item(&self) -> &Self::Item;
+}
+
+impl<T, U> Trait<U> for T where T: WithAssoc<Item=U>, U: Clone {
+    fn convert(&self) -> U {
+        self.as_item().clone()
+    }
+}
+
+impl WithAssoc for u8 {
+    type Item = u8;
+    fn as_item(&self) -> &u8 { self }
+}
+
+impl Trait<u8> for u8 {}
+
+fn main() {
+    assert!(3u8.convert() == 3u8);
+}
diff --git a/src/test/run-pass/specialization/specialization-translate-projections.rs b/src/test/run-pass/specialization/specialization-translate-projections.rs
new file mode 100644 (file)
index 0000000..11e1d99
--- /dev/null
@@ -0,0 +1,41 @@
+// 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.
+
+// Ensure that provided items are inherited properly even when impls vary in
+// type parameters *and* rely on projections.
+
+#![feature(specialization)]
+
+use std::convert::Into;
+
+trait Trait {
+    fn to_u8(&self) -> u8;
+}
+trait WithAssoc {
+    type Item;
+    fn to_item(&self) -> Self::Item;
+}
+
+impl<T, U> Trait for T where T: WithAssoc<Item=U>, U: Into<u8> {
+    fn to_u8(&self) -> u8 {
+        self.to_item().into()
+    }
+}
+
+impl WithAssoc for u8 {
+    type Item = u8;
+    fn to_item(&self) -> u8 { *self }
+}
+
+impl Trait for u8 {}
+
+fn main() {
+    assert!(3u8.to_u8() == 3u8);
+}
index 1b6de3b2f7bcf029a4e1cb236b0f0a1227a60842..2dacbe0966ee37b68d6b7299b4737b2d0001ccf5 100644 (file)
 extern crate xcrate_associated_type_defaults;
 use xcrate_associated_type_defaults::Foo;
 
+struct LocalDefault;
+impl Foo<u32> for LocalDefault {}
+
+struct LocalOverride;
+impl Foo<u64> for LocalOverride {
+    type Out = bool;
+}
+
 fn main() {
-    ().bar(5);
+    assert_eq!(
+        <() as Foo<u32>>::Out::default().to_string(),
+        "0");
+    assert_eq!(
+        <() as Foo<u64>>::Out::default().to_string(),
+        "false");
+
+    assert_eq!(
+        <LocalDefault as Foo<u32>>::Out::default().to_string(),
+        "0");
+    assert_eq!(
+        <LocalOverride as Foo<u64>>::Out::default().to_string(),
+        "false");
 }
index e5e88081bc43ed23e91b11f8cd92c05dbfb5671b..19037a2c4d7f2b5076085ac0e7d4a17a31ea2131 100644 (file)
@@ -76,29 +76,28 @@ fn check(root: &Path, file: &Path, base: &Url, errors: &mut bool) {
 
     // Unfortunately we're not 100% full of valid links today to we need a few
     // whitelists to get this past `make check` today.
-    if let Some(path) = pretty_file.to_str() {
-        // FIXME(#32129)
-        if path == "std/string/struct.String.html" {
-            return
-        }
-        // FIXME(#32130)
-        if path.contains("btree_set/struct.BTreeSet.html") ||
-           path == "collections/struct.BTreeSet.html" {
-            return
-        }
-        // FIXME(#31948)
-        if path.contains("ParseFloatError") {
-            return
-        }
+    // FIXME(#32129)
+    if file.ends_with("std/string/struct.String.html") {
+        return
+    }
+    // FIXME(#32130)
+    if file.ends_with("btree_set/struct.BTreeSet.html") ||
+       file.ends_with("collections/struct.BTreeSet.html") {
+        return
+    }
+
+    if file.ends_with("std/sys/ext/index.html") {
+        return
+    }
 
-        // currently
-        if path == "std/sys/ext/index.html" {
+    if let Some(file) = file.to_str() {
+        // FIXME(#31948)
+        if file.contains("ParseFloatError") {
             return
         }
-
         // weird reexports, but this module is on its way out, so chalk it up to
         // "rustdoc weirdness" and move on from there
-        if path.contains("scoped_tls") {
+        if file.contains("scoped_tls") {
             return
         }
     }