diff --git a/.gitignore b/.gitignore index 5d5da135a8272..572111bf96158 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ *.exe *.fn *.html +*.kdev4 *.ky *.ll *.llvm diff --git a/Makefile.in b/Makefile.in index d3bb5a541a470..8968fabf1b4b3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -62,6 +62,7 @@ # * tidy-basic - show file / line stats # * tidy-errors - show the highest rustc error code # * tidy-features - show the status of language and lib features +# * rustc-stage$(stage) - Only build up to a specific stage # # Then mix in some of these environment variables to harness the # ultimate power of The Rust Build System. @@ -90,7 +91,7 @@ # # # Rust recipes for build system success # -# // Modifying libstd? Use this comment to run unit tests just on your change +# // Modifying libstd? Use this command to run unit tests just on your change # make check-stage1-std NO_REBUILD=1 NO_BENCH=1 # # // Added a run-pass test? Use this to test running your test diff --git a/README.md b/README.md index c8f00ba1acd8d..9e54704a5ebad 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Rust is a fast systems programming language that guarantees memory safety and offers painless concurrency ([no data races]). It does not employ a garbage collector and has minimal runtime overhead. -This repo contains the code for `rustc`, the Rust compiler, as well +This repo contains the code for the compiler (`rustc`), as well as standard libraries, tools and documentation for Rust. [no data races]: http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html @@ -73,7 +73,7 @@ Read ["Installing Rust"] from [The Book]. ``` 3. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed - MYSY2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust. + MSYS2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust. 4. Navigate to Rust's source code, configure and build it: diff --git a/RELEASES.md b/RELEASES.md index 203da02c373ef..751205f8219ac 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,18 @@ +Version 1.2.0 (August 2015) +=========================== + +Highlights +---------- + +* [Parallel codegen][parcodegen] is now working again, which can substantially + speed up large builds in debug mode; It also gets another ~33% speedup when + bootstrapping on a 4 core machine (using 8 jobs). It's not enabled by default, + but will be "in the near future" + + +[parcodegen]: https://github.com/rust-lang/rust/pull/26018 + + Version 1.1.0 (June 2015) ========================= @@ -6,7 +21,7 @@ Version 1.1.0 (June 2015) Highlights ---------- -* The [`std::fs` module has been expanded][fs-expand] to expand the set of +* The [`std::fs` module has been expanded][fs] to expand the set of functionality exposed: * `DirEntry` now supports optimizations like `file_type` and `metadata` which don't incur a syscall on some platforms. @@ -23,11 +38,11 @@ Highlights Libraries --------- -* The `str::split_whitespace` method splits a string on unicode +* The [`str::split_whitespace`] method splits a string on unicode whitespace boundaries. * On both Windows and Unix, new extension traits provide conversion of I/O types to and from the underlying system handles. On Unix, these - traits are [`FrowRawFd`] and [`AsRawFd`], on Windows `FromRawHandle` + traits are [`FromRawFd`] and [`AsRawFd`], on Windows `FromRawHandle` and `AsRawHandle`. These are implemented for `File`, `TcpStream`, `TcpListener`, and `UpdSocket`. Further implementations for `std::process` will be stabilized later. @@ -79,8 +94,7 @@ Misc * [The `drop_with_repr_extern` lint warns about mixing `repr(C)` with `Drop`][drop]. -[`split_whitespace`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_whitespace -[`Iterator::cloned`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.cloned +[`str::split_whitespace`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_whitespace [`FromRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html [`AsRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.AsRawFd.html [`std::os::unix::symlink`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/fn.symlink.html @@ -250,7 +264,6 @@ Misc [sw]: https://github.com/rust-lang/rfcs/blob/master/text/1054-str-words.md [th]: https://github.com/rust-lang/rfcs/blob/master/text/0909-move-thread-local-to-std-thread.md [send-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0458-send-improvements.md -[scoped]: http://static.rust-lang.org/doc/master/std/thread/fn.scoped.html [moar-ufcs]: https://github.com/rust-lang/rust/pull/22172 [prim-inherent]: https://github.com/rust-lang/rust/pull/23104 [overflow]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md @@ -260,12 +273,10 @@ Misc [string-pattern]: https://github.com/rust-lang/rust/pull/22466 [oibit-final]: https://github.com/rust-lang/rust/pull/21689 [reflect]: https://github.com/rust-lang/rust/pull/23712 -[debug-builder]: https://github.com/rust-lang/rfcs/blob/master/text/0640-debug-improvements.md [conversion]: https://github.com/rust-lang/rfcs/pull/529 [num-traits]: https://github.com/rust-lang/rust/pull/23549 [index-value]: https://github.com/rust-lang/rust/pull/23601 [dropck]: https://github.com/rust-lang/rfcs/pull/769 -[fundamental]: https://github.com/rust-lang/rfcs/pull/1023 [ci-compare]: https://gist.github.com/brson/a30a77836fbec057cbee [fn-inherit]: https://github.com/rust-lang/rust/pull/23282 [fn-blanket]: https://github.com/rust-lang/rust/pull/23895 @@ -368,7 +379,6 @@ Version 1.0.0-alpha.2 (February 2015) [osstr]: https://github.com/rust-lang/rust/pull/21488 [osstr-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md [Self]: https://github.com/rust-lang/rust/pull/22158 -[ufcs]: https://github.com/rust-lang/rust/pull/21077 [ufcs-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md [un]: https://github.com/rust-lang/rust/pull/22256 diff --git a/configure b/configure index 891f524a706e0..1d3611f88f0a9 100755 --- a/configure +++ b/configure @@ -405,6 +405,10 @@ case $CFG_OSTYPE in CFG_OSTYPE=unknown-openbsd ;; + NetBSD) + CFG_OSTYPE=unknown-netbsd + ;; + Darwin) CFG_OSTYPE=apple-darwin ;; @@ -1114,7 +1118,7 @@ do fi ;; - x86_64-*-msvc) + *-msvc) # Currently the build system is not configured to build jemalloc # with MSVC, so we omit this optional dependency. step_msg "targeting MSVC, disabling jemalloc" @@ -1154,22 +1158,45 @@ do CFG_MSVC_ROOT=$(echo "$install" | grep InstallDir | sed 's/.*REG_SZ[ ]*//') CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT") CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT") - CFG_MSVC_CL="${CFG_MSVC_ROOT}/VC/bin/amd64/cl.exe" - CFG_MSVC_LIB="${CFG_MSVC_ROOT}/VC/bin/amd64/lib.exe" - CFG_MSVC_LINK="${CFG_MSVC_ROOT}/VC/bin/amd64/link.exe" + putvar CFG_MSVC_ROOT + + case $i in + x86_64-*) + bits=x86_64 + msvc_part=amd64 + ;; + i686-*) + bits=i386 + msvc_part= + ;; + *) + err "can only target x86 targets for MSVC" + ;; + esac + bindir="${CFG_MSVC_ROOT}/VC/bin" + if [ ! -z "$msvc_part" ]; then + bindir="$bindir/$msvc_part" + fi + eval CFG_MSVC_BINDIR_$bits="\"$bindir\"" + eval CFG_MSVC_CL_$bits="\"$bindir/cl.exe\"" + eval CFG_MSVC_LIB_$bits="\"$bindir/lib.exe\"" + eval CFG_MSVC_LINK_$bits="\"$bindir/link.exe\"" vcvarsall="${CFG_MSVC_ROOT}/VC/vcvarsall.bat" - CFG_MSVC_INCLUDE_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %INCLUDE%") + include_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %INCLUDE%") need_ok "failed to learn about MSVC's INCLUDE" - CFG_MSVC_LIB_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %LIB%") + lib_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %LIB%") need_ok "failed to learn about MSVC's LIB" - putvar CFG_MSVC_ROOT - putvar CFG_MSVC_CL - putvar CFG_MSVC_LIB - putvar CFG_MSVC_LINK - putvar CFG_MSVC_INCLUDE_PATH - putvar CFG_MSVC_LIB_PATH + eval CFG_MSVC_INCLUDE_PATH_${bits}="\"$include_path\"" + eval CFG_MSVC_LIB_PATH_${bits}="\"$lib_path\"" + + putvar CFG_MSVC_BINDIR_${bits} + putvar CFG_MSVC_CL_${bits} + putvar CFG_MSVC_LIB_${bits} + putvar CFG_MSVC_LINK_${bits} + putvar CFG_MSVC_INCLUDE_PATH_${bits} + putvar CFG_MSVC_LIB_PATH_${bits} ;; *) @@ -1408,8 +1435,19 @@ do msg "configuring LLVM with:" msg "$CMAKE_ARGS" + case "$t" in + x86_64-*) + generator="Visual Studio 12 2013 Win64" + ;; + i686-*) + generator="Visual Studio 12 2013" + ;; + *) + err "can only build LLVM for x86 platforms" + ;; + esac (cd $LLVM_BUILD_DIR && "$CFG_CMAKE" $CFG_LLVM_SRC_DIR \ - -G "Visual Studio 12 2013 Win64" \ + -G "$generator" \ $CMAKE_ARGS) need_ok "LLVM cmake configure failed" fi diff --git a/mk/cfg/i686-pc-windows-msvc.mk b/mk/cfg/i686-pc-windows-msvc.mk new file mode 100644 index 0000000000000..bb1280688a716 --- /dev/null +++ b/mk/cfg/i686-pc-windows-msvc.mk @@ -0,0 +1,29 @@ +# i686-pc-windows-msvc configuration +CC_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo +LINK_i686-pc-windows-msvc="$(CFG_MSVC_LINK_i386)" -nologo +CXX_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo +CPP_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo +AR_i686-pc-windows-msvc="$(CFG_MSVC_LIB_i386)" -nologo +CFG_LIB_NAME_i686-pc-windows-msvc=$(1).dll +CFG_STATIC_LIB_NAME_i686-pc-windows-msvc=$(1).lib +CFG_LIB_GLOB_i686-pc-windows-msvc=$(1)-*.{dll,lib} +CFG_LIB_DSYM_GLOB_i686-pc-windows-msvc=$(1)-*.dylib.dSYM +CFG_JEMALLOC_CFLAGS_i686-pc-windows-msvc := +CFG_GCCISH_CFLAGS_i686-pc-windows-msvc := -MD +CFG_GCCISH_CXXFLAGS_i686-pc-windows-msvc := -MD +CFG_GCCISH_LINK_FLAGS_i686-pc-windows-msvc := +CFG_GCCISH_DEF_FLAG_i686-pc-windows-msvc := +CFG_LLC_FLAGS_i686-pc-windows-msvc := +CFG_INSTALL_NAME_i686-pc-windows-msvc = +CFG_EXE_SUFFIX_i686-pc-windows-msvc := .exe +CFG_WINDOWSY_i686-pc-windows-msvc := 1 +CFG_UNIXY_i686-pc-windows-msvc := +CFG_LDPATH_i686-pc-windows-msvc := +CFG_RUN_i686-pc-windows-msvc=$(2) +CFG_RUN_TARG_i686-pc-windows-msvc=$(call CFG_RUN_i686-pc-windows-msvc,,$(2)) +CFG_GNU_TRIPLE_i686-pc-windows-msvc := i686-pc-win32 + +# All windows nightiles are currently a GNU triple, so this MSVC triple is not +# bootstrapping from itself. This is relevant during stage0, and other parts of +# the build system take this into account. +BOOTSTRAP_FROM_i686-pc-windows-msvc := i686-pc-windows-gnu diff --git a/mk/cfg/x86_64-pc-windows-msvc.mk b/mk/cfg/x86_64-pc-windows-msvc.mk index 69a26c03fb664..6f12836f05624 100644 --- a/mk/cfg/x86_64-pc-windows-msvc.mk +++ b/mk/cfg/x86_64-pc-windows-msvc.mk @@ -1,9 +1,9 @@ # x86_64-pc-windows-msvc configuration -CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo -LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK)" -nologo -CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo -CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo -AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB)" -nologo +CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo +LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK_x86_64)" -nologo +CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo +CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo +AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB_x86_64)" -nologo CFG_LIB_NAME_x86_64-pc-windows-msvc=$(1).dll CFG_STATIC_LIB_NAME_x86_64-pc-windows-msvc=$(1).lib CFG_LIB_GLOB_x86_64-pc-windows-msvc=$(1)-*.{dll,lib} @@ -23,64 +23,6 @@ CFG_RUN_x86_64-pc-windows-msvc=$(2) CFG_RUN_TARG_x86_64-pc-windows-msvc=$(call CFG_RUN_x86_64-pc-windows-msvc,,$(2)) CFG_GNU_TRIPLE_x86_64-pc-windows-msvc := x86_64-pc-win32 -# These two environment variables are scraped by the `./configure` script and -# are necessary for `cl.exe` to find standard headers (the INCLUDE variable) and -# for `link.exe` to find standard libraries (the LIB variable). -ifdef CFG_MSVC_INCLUDE_PATH -export INCLUDE := $(CFG_MSVC_INCLUDE_PATH) -endif -ifdef CFG_MSVC_LIB_PATH -export LIB := $(CFG_MSVC_LIB_PATH) -endif - -# Unfortunately `link.exe` is also a program in `/usr/bin` on MinGW installs, -# but it's not the one that we want. As a result we make sure that our detected -# `link.exe` shows up in PATH first. -ifdef CFG_MSVC_LINK -export PATH := $(CFG_MSVC_ROOT)/VC/bin/amd64:$(PATH) -endif - -# There are more comments about this available in the target specification for -# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe` -# instead of `lib.exe` for assembling archives, so we need to inject this custom -# dependency here. -NATIVE_TOOL_DEPS_core_T_x86_64-pc-windows-msvc += llvm-ar.exe -INSTALLED_BINS_x86_64-pc-windows-msvc += llvm-ar.exe - -# When working with MSVC on windows, each DLL needs to explicitly declare its -# interface to the outside world through some means. The options for doing so -# include: -# -# 1. A custom attribute on each function itself -# 2. A linker argument saying what to export -# 3. A file which lists all symbols that need to be exported -# -# The Rust compiler takes care (1) for us for all Rust code by annotating all -# public-facing functions with dllexport, but we have a few native dependencies -# which need to cross the DLL boundary. The most important of these dependencies -# is LLVM which is linked into `rustc_llvm.dll` but primarily used from -# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be -# exposed from `rustc_llvm.dll` to be forwarded over the boundary. -# -# Unfortunately, at this time, LLVM does not handle this sort of exportation on -# Windows for us, so we're forced to do it ourselves if we want it (which seems -# like the path of least resistance right now). To do this we generate a `.DEF` -# file [1] which we then custom-pass to the linker when building the rustc_llvm -# crate. This DEF file list all symbols that are exported from -# `src/librustc_llvm/lib.rs` and is generated by a small python script. -# -# Fun times! -# -# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx -RUSTFLAGS_rustc_llvm_T_x86_64-pc-windows-msvc += \ - -C link-args="-DEF:x86_64-pc-windows-msvc/rt/rustc_llvm.def" -CUSTOM_DEPS_rustc_llvm_T_x86_64-pc-windows-msvc += \ - x86_64-pc-windows-msvc/rt/rustc_llvm.def - -x86_64-pc-windows-msvc/rt/rustc_llvm.def: $(S)src/etc/mklldef.py \ - $(S)src/librustc_llvm/lib.rs - $(CFG_PYTHON) $^ $@ rustc_llvm-$(CFG_FILENAME_EXTRA) - # All windows nightiles are currently a GNU triple, so this MSVC triple is not # bootstrapping from itself. This is relevant during stage0, and other parts of # the build system take this into account. diff --git a/mk/cfg/x86_64-unknown-netbsd.mk b/mk/cfg/x86_64-unknown-netbsd.mk new file mode 100644 index 0000000000000..401b0fb7ab008 --- /dev/null +++ b/mk/cfg/x86_64-unknown-netbsd.mk @@ -0,0 +1,22 @@ +# x86_64-unknown-netbsd configuration +CC_x86_64-unknown-netbsd=$(CC) +CXX_x86_64-unknown-netbsd=$(CXX) +CPP_x86_64-unknown-netbsd=$(CPP) +AR_x86_64-unknown-netbsd=$(AR) +CFG_LIB_NAME_x86_64-unknown-netbsd=lib$(1).so +CFG_STATIC_LIB_NAME_x86_64-unknown-netbsd=lib$(1).a +CFG_LIB_GLOB_x86_64-unknown-netbsd=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_x86_64-unknown-netbsd=$(1)-*.dylib.dSYM +CFG_JEMALLOC_CFLAGS_x86_64-unknown-netbsd := -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-netbsd := -Wall -Werror -g -fPIC -I/usr/local/include $(CFLAGS) +CFG_GCCISH_LINK_FLAGS_x86_64-unknown-netbsd := -shared -fPIC -g -pthread -lrt +CFG_GCCISH_DEF_FLAG_x86_64-unknown-netbsd := -Wl,--export-dynamic,--dynamic-list= +CFG_LLC_FLAGS_x86_64-unknown-netbsd := +CFG_INSTALL_NAME_x86_64-unknown-netbsd = +CFG_EXE_SUFFIX_x86_64-unknown-netbsd := +CFG_WINDOWSY_x86_64-unknown-netbsd := +CFG_UNIXY_x86_64-unknown-netbsd := 1 +CFG_LDPATH_x86_64-unknown-netbsd := +CFG_RUN_x86_64-unknown-netbsd=$(2) +CFG_RUN_TARG_x86_64-unknown-netbsd=$(call CFG_RUN_x86_64-unknown-netbsd,,$(2)) +CFG_GNU_TRIPLE_x86_64-unknown-netbsd := x86_64-unknown-netbsd diff --git a/mk/platform.mk b/mk/platform.mk index 8a5e58c46f676..60fe22cb32ee6 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -238,3 +238,56 @@ endef $(foreach target,$(CFG_TARGET), \ $(eval $(call CFG_MAKE_TOOLCHAIN,$(target)))) + +# There are more comments about this available in the target specification for +# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe` +# instead of `lib.exe` for assembling archives, so we need to inject this custom +# dependency here. +define ADD_LLVM_AR_TO_MSVC_DEPS +ifeq ($$(findstring msvc,$(1)),msvc) +NATIVE_TOOL_DEPS_core_T_$(1) += llvm-ar.exe +INSTALLED_BINS_$(1) += llvm-ar.exe +endif +endef + +$(foreach target,$(CFG_TARGET), \ + $(eval $(call ADD_LLVM_AR_TO_MSVC_DEPS,$(target)))) + +# When working with MSVC on windows, each DLL needs to explicitly declare its +# interface to the outside world through some means. The options for doing so +# include: +# +# 1. A custom attribute on each function itself +# 2. A linker argument saying what to export +# 3. A file which lists all symbols that need to be exported +# +# The Rust compiler takes care (1) for us for all Rust code by annotating all +# public-facing functions with dllexport, but we have a few native dependencies +# which need to cross the DLL boundary. The most important of these dependencies +# is LLVM which is linked into `rustc_llvm.dll` but primarily used from +# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be +# exposed from `rustc_llvm.dll` to be forwarded over the boundary. +# +# Unfortunately, at this time, LLVM does not handle this sort of exportation on +# Windows for us, so we're forced to do it ourselves if we want it (which seems +# like the path of least resistance right now). To do this we generate a `.DEF` +# file [1] which we then custom-pass to the linker when building the rustc_llvm +# crate. This DEF file list all symbols that are exported from +# `src/librustc_llvm/lib.rs` and is generated by a small python script. +# +# Fun times! +# +# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx +define ADD_RUSTC_LLVM_DEF_TO_MSVC +ifeq ($$(findstring msvc,$(1)),msvc) +RUSTFLAGS_rustc_llvm_T_$(1) += -C link-args="-DEF:$(1)/rt/rustc_llvm.def" +CUSTOM_DEPS_rustc_llvm_T_$(1) += $(1)/rt/rustc_llvm.def + +$(1)/rt/rustc_llvm.def: $$(S)src/etc/mklldef.py $$(S)src/librustc_llvm/lib.rs + $$(CFG_PYTHON) $$^ $$@ rustc_llvm-$$(CFG_FILENAME_EXTRA) +endif +endef + +$(foreach target,$(CFG_TARGET), \ + $(eval $(call ADD_RUSTC_LLVM_DEF_TO_MSVC,$(target)))) + diff --git a/mk/rt.mk b/mk/rt.mk index 777a2a0fd3b4b..c70f9e8a37add 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -53,9 +53,16 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \ NATIVE_DEPS_miniz_$(1) = miniz.c NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \ rust_android_dummy.c -NATIVE_DEPS_rustrt_native_$(1) := \ - rust_try.ll \ - arch/$$(HOST_$(1))/record_sp.S +NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S +ifeq ($$(findstring msvc,$(1)),msvc) +ifeq ($$(findstring i686,$(1)),i686) +NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_32.ll +else +NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_64.ll +endif +else +NATIVE_DEPS_rustrt_native_$(1) += rust_try.ll +endif NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S @@ -90,6 +97,17 @@ $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.S $$(MKFILE_DEPS) \ @mkdir -p $$(@D) @$$(call E, compile: $$@) $$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<) + +# On MSVC targets the compiler's default include path (e.g. where to find system +# headers) is specified by the INCLUDE environment variable. This may not be set +# so the ./configure script scraped the relevant values and this is the location +# that we put them into cl.exe's environment. +ifeq ($$(findstring msvc,$(1)),msvc) +$$(RT_OUTPUT_DIR_$(1))/%.o: \ + export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1))) +$(1)/rustllvm/%.o: \ + export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1))) +endif endef $(foreach target,$(CFG_TARGET),$(eval $(call NATIVE_LIBRARIES,$(target)))) @@ -237,8 +255,12 @@ COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) ifeq ($$(findstring msvc,$(1)),msvc) COMPRT_CC_$(1) := gcc COMPRT_AR_$(1) := ar +ifeq ($$(findstring i686,$(1)),i686) +COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m32 +else COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m64 endif +endif $$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS) @$$(call E, make: compiler-rt) diff --git a/mk/target.mk b/mk/target.mk index 3c274dc4fd5f2..c398950965f54 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -220,3 +220,40 @@ $(foreach target,$(CFG_TARGET), \ $(foreach crate,$(CRATES), \ $(foreach tool,$(NATIVE_TOOL_DEPS_$(crate)_T_$(target)), \ $(eval $(call MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR,0,$(target),$(BOOTSTRAP_FROM_$(target)),$(crate),$(tool)))))) + +# For MSVC targets we need to set up some environment variables for the linker +# to work correctly when building Rust crates. These two variables are: +# +# - LIB tells the linker the default search path for finding system libraries, +# for example kernel32.dll +# - PATH needs to be modified to ensure that MSVC's link.exe is first in the +# path instead of MinGW's /usr/bin/link.exe (entirely unrelated) +# +# The values for these variables are detected by the configure script. +define SETUP_LIB_MSVC_ENV_VARS +ifeq ($$(findstring msvc,$(2)),msvc) +$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \ + export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2))) +$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \ + export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH) +endif +endef +define SETUP_TOOL_MSVC_ENV_VARS +ifeq ($$(findstring msvc,$(2)),msvc) +$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \ + export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2))) +$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \ + export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH) +endif +endef + +$(foreach host,$(CFG_HOST), \ + $(foreach target,$(CFG_TARGET), \ + $(foreach stage,$(STAGES), \ + $(foreach crate,$(CRATES), \ + $(eval $(call SETUP_LIB_MSVC_ENV_VARS,$(stage),$(target),$(host),$(crate))))))) +$(foreach host,$(CFG_HOST), \ + $(foreach target,$(CFG_TARGET), \ + $(foreach stage,$(STAGES), \ + $(foreach tool,$(TOOLS), \ + $(eval $(call SETUP_TOOL_MSVC_ENV_VARS,$(stage),$(target),$(host),$(tool))))))) diff --git a/src/compiletest/util.rs b/src/compiletest/util.rs index 184d62db45114..13d6c029ff584 100644 --- a/src/compiletest/util.rs +++ b/src/compiletest/util.rs @@ -21,6 +21,7 @@ const OS_TABLE: &'static [(&'static str, &'static str)] = &[ ("ios", "ios"), ("linux", "linux"), ("mingw32", "windows"), + ("netbsd", "netbsd"), ("openbsd", "openbsd"), ("win32", "windows"), ("windows", "windows"), diff --git a/src/doc/guide-pointers.md b/src/doc/guide-pointers.md index 0374166405c62..dc80ec4399131 100644 --- a/src/doc/guide-pointers.md +++ b/src/doc/guide-pointers.md @@ -1,4 +1,7 @@ -% The (old) Rust Pointer Guide +% The Rust Pointer Guide -This content has moved into -[the Rust Programming Language book](book/pointers.html). +This content has been removed, with no direct replacement. Rust only +has two built-in pointer types now, +[references](book/references-and-borrowing.html) and [raw +pointers](book/raw-pointers.html). Older Rusts had many more pointer +types, they’re gone now. diff --git a/src/doc/index.md b/src/doc/index.md index fba919b711586..c1f9ea6b3b003 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -20,6 +20,13 @@ series of small examples. [rbe]: http://rustbyexample.com/ +# The Standard Library + +We have [API documentation for the entire standard +library](std/index.html). There's a list of crates on the left with more +specific sections, or you can use the search bar at the top to search for +something if you know its name. + # Community & Getting Help If you need help with something, or just want to talk about Rust with others, @@ -75,13 +82,6 @@ There are questions that are asked quite often, so we've made FAQs for them: * [Project FAQ](complement-project-faq.html) * [How to submit a bug report](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports) -# The Standard Library - -We have [API documentation for the entire standard -library](std/index.html). There's a list of crates on the left with more -specific sections, or you can use the search bar at the top to search for -something if you know its name. - # The Error Index If you encounter an error while compiling your code you may be able to look it diff --git a/src/doc/reference.md b/src/doc/reference.md index 2b288aa2d3f2c..7f40d569308de 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -338,12 +338,16 @@ type of the literal. The integer suffix must be the name of one of the integral types: `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `isize`, or `usize`. -The type of an _unsuffixed_ integer literal is determined by type inference. -If an integer type can be _uniquely_ determined from the surrounding program -context, the unsuffixed integer literal has that type. If the program context -underconstrains the type, it defaults to the signed 32-bit integer `i32`; if -the program context overconstrains the type, it is considered a static type -error. +The type of an _unsuffixed_ integer literal is determined by type inference: + +* If an integer type can be _uniquely_ determined from the surrounding + program context, the unsuffixed integer literal has that type. + +* If the program context underconstrains the type, it defaults to the + signed 32-bit integer `i32`. + +* If the program context overconstrains the type, it is considered a + static type error. Examples of integer literals of various forms: @@ -371,12 +375,17 @@ The suffix forcibly sets the type of the literal. There are two valid _floating-point suffixes_, `f32` and `f64` (the 32-bit and 64-bit floating point types), which explicitly determine the type of the literal. -The type of an _unsuffixed_ floating-point literal is determined by type -inference. If a floating-point type can be _uniquely_ determined from the -surrounding program context, the unsuffixed floating-point literal has that type. -If the program context underconstrains the type, it defaults to double-precision `f64`; -if the program context overconstrains the type, it is considered a static type -error. +The type of an _unsuffixed_ floating-point literal is determined by +type inference: + +* If a floating-point type can be _uniquely_ determined from the + surrounding program context, the unsuffixed floating-point literal + has that type. + +* If the program context underconstrains the type, it defaults to `f64`. + +* If the program context overconstrains the type, it is considered a + static type error. Examples of floating-point literals of various forms: @@ -1047,11 +1056,8 @@ This is a list of behavior not considered *unsafe* in Rust terms, but that may be undesired. * Deadlocks -* Reading data from private fields (`std::repr`) * Leaks of memory and other resources * Exiting without calling destructors -* Sending signals -* Accessing/modifying the file system * Integer overflow - Overflow is considered "unexpected" behavior and is always user-error, unless the `wrapping` primitives are used. In non-optimized builds, the compiler @@ -2026,7 +2032,7 @@ The following configurations must be defined by the implementation: as a configuration itself, like `unix` or `windows`. * `target_os = "..."`. Operating system of the target, examples include `"windows"`, `"macos"`, `"ios"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"`, - `"bitrig"` or `"openbsd"`. + `"bitrig"` , `"openbsd"` or `"netbsd"`. * `target_pointer_width = "..."`. Target pointer width in bits. This is set to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for 64-bit pointers. @@ -2966,14 +2972,12 @@ move values (depending on their type) from the environment into the lambda expression's captured environment. In this example, we define a function `ten_times` that takes a higher-order -function argument, and call it with a lambda expression as an argument: +function argument, and we then call it with a lambda expression as an argument: ``` fn ten_times(f: F) where F: Fn(i32) { - let mut i = 0i32; - while i < 10 { - f(i); - i += 1; + for index in 0..10 { + f(index); } } @@ -3322,10 +3326,13 @@ An example of a tuple type and its use: ``` type Pair<'a> = (i32, &'a str); -let p: Pair<'static> = (10, "hello"); +let p: Pair<'static> = (10, "ten"); let (a, b) = p; -assert!(b != "world"); -assert!(p.0 == 10); + +assert_eq!(a, 10); +assert_eq!(b, "ten"); +assert_eq!(p.0, 10); +assert_eq!(p.1, "ten"); ``` For historical reasons and convenience, the tuple type with no elements (`()`) @@ -3335,8 +3342,8 @@ is often called ‘unit’ or ‘the unit type’. Rust has two different types for a list of items: -* `[T; N]`, an 'array'. -* `&[T]`, a 'slice'. +* `[T; N]`, an 'array' +* `&[T]`, a 'slice' An array has a fixed size, and can be allocated on either the stack or the heap. @@ -3489,7 +3496,7 @@ x = bo(5,7); #### Function types for specific items -Internally to the compiler, there are also function types that are specific to a particular +Internal to the compiler, there are also function types that are specific to a particular function item. In the following snippet, for example, the internal types of the functions `foo` and `bar` are different, despite the fact that they have the same signature: diff --git a/src/doc/trpl/academic-research.md b/src/doc/trpl/academic-research.md index dec46de650133..e317f67934498 100644 --- a/src/doc/trpl/academic-research.md +++ b/src/doc/trpl/academic-research.md @@ -12,7 +12,7 @@ Recommended for inspiration and a better understanding of Rust's background. * [Macros that work together](https://www.cs.utah.edu/plt/publications/jfp12-draft-fcdf.pdf) * [Traits: composable units of behavior](http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf) * [Alias burying](http://www.cs.uwm.edu/faculty/boyland/papers/unique-preprint.ps) - We tried something similar and abandoned it. -* [External uniqueness is unique enough](http://www.computingscience.nl/research/techreps/repo/CS-2002/2002-048.pdf) +* [External uniqueness is unique enough](http://www.cs.uu.nl/research/techreps/UU-CS-2002-048.html) * [Uniqueness and Reference Immutability for Safe Parallelism](https://research.microsoft.com/pubs/170528/msr-tr-2012-79.pdf) * [Region Based Memory Management](http://www.cs.ucla.edu/~palsberg/tba/papers/tofte-talpin-iandc97.pdf) @@ -26,10 +26,10 @@ Recommended for inspiration and a better understanding of Rust's background. * [Dynamic circular work stealing deque](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.170.1097&rep=rep1&type=pdf) - The Chase/Lev deque * [Work-first and help-first scheduling policies for async-finish task parallelism](http://www.cs.rice.edu/%7Eyguo/pubs/PID824943.pdf) - More general than fully-strict work stealing * [A Java fork/join calamity](http://www.coopsoft.com/ar/CalamityArticle.html) - critique of Java's fork/join library, particularly its application of work stealing to non-strict computation -* [Scheduling techniques for concurrent systems](http://www.ece.rutgers.edu/%7Eparashar/Classes/ece572-papers/05/ps-ousterhout.pdf) +* [Scheduling techniques for concurrent systems](http://www.stanford.edu/~ouster/cgi-bin/papers/coscheduling.pdf) * [Contention aware scheduling](http://www.blagodurov.net/files/a8-blagodurov.pdf) * [Balanced work stealing for time-sharing multicores](http://www.cse.ohio-state.edu/hpcs/WWW/HTML/publications/papers/TR-12-1.pdf) -* [Three layer cake](http://www.upcrc.illinois.edu/workshops/paraplop10/papers/paraplop10_submission_8.pdf) +* [Three layer cake for shared-memory programming](http://dl.acm.org/citation.cfm?id=1953616&dl=ACM&coll=DL&CFID=524387192&CFTOKEN=44362705) * [Non-blocking steal-half work queues](http://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf) * [Reagents: expressing and composing fine-grained concurrency](http://www.mpi-sws.org/~turon/reagents.pdf) * [Algorithms for scalable synchronization of shared-memory multiprocessors](https://www.cs.rochester.edu/u/scott/papers/1991_TOCS_synch.pdf) diff --git a/src/doc/trpl/documentation.md b/src/doc/trpl/documentation.md index 7102158383a9b..01b53a6c49d8b 100644 --- a/src/doc/trpl/documentation.md +++ b/src/doc/trpl/documentation.md @@ -33,8 +33,10 @@ pub fn new(value: T) -> Rc { ``` This code generates documentation that looks [like this][rc-new]. I've left the -implementation out, with a regular comment in its place. That's the first thing -to notice about this annotation: it uses `///`, instead of `//`. The triple slash +implementation out, with a regular comment in its place. + +The first thing to notice about this annotation is that it uses +`///` instead of `//`. The triple slash indicates a documentation comment. Documentation comments are written in Markdown. @@ -375,7 +377,7 @@ $ rustdoc --test path/to/my/crate/root.rs $ cargo test ``` -That's right, `cargo test` tests embedded documentation too. However, +That's right, `cargo test` tests embedded documentation too. However, `cargo test` will not test binary crates, only library ones. This is due to the way `rustdoc` works: it links against the library to be tested, but with a binary, there’s nothing to link to. diff --git a/src/doc/trpl/link-args.md b/src/doc/trpl/link-args.md index ee5159afb8e6f..cdaef6cd9b510 100644 --- a/src/doc/trpl/link-args.md +++ b/src/doc/trpl/link-args.md @@ -17,7 +17,7 @@ Note that this feature is currently hidden behind the `feature(link_args)` gate because this is not a sanctioned way of performing linking. Right now rustc shells out to the system linker, so it makes sense to provide extra command line arguments, but this will not always be the case. In the future rustc may use -LLVM directly to link native libraries in which case `link_args` will have no +LLVM directly to link native libraries, in which case `link_args` will have no meaning. It is highly recommended to *not* use this attribute, and rather use the more diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md index b27db2ab7bea8..d1d3063138e7e 100644 --- a/src/doc/trpl/references-and-borrowing.md +++ b/src/doc/trpl/references-and-borrowing.md @@ -336,7 +336,9 @@ In other words, `y` is only valid for the scope where `x` exists. As soon as the borrow ‘doesn’t live long enough’ because it’s not valid for the right amount of time. -The same problem occurs when the reference is declared _before_ the variable it refers to: +The same problem occurs when the reference is declared _before_ the variable it +refers to. This is because resources within the same scope are freed in the +opposite order they were declared: ```rust,ignore let y: &i32; @@ -369,3 +371,6 @@ statement 1 at 3:14 println!("{}", y); } ``` + +In the above example, `y` is declared before `x`, meaning that `y` lives longer +than `x`, which is not allowed. diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index fdb9c33a2b0b5..e8f1b829061c2 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -12,7 +12,7 @@ two contexts. The first one is to mark a function as unsafe: ```rust unsafe fn danger_will_robinson() { - // scary stuff + // scary stuff } ``` @@ -68,11 +68,8 @@ Whew! That’s a bunch of stuff. It’s also important to notice all kinds of behaviors that are certainly bad, but are expressly _not_ unsafe: * Deadlocks -* Reading data from private fields -* Leaks due to reference count cycles +* Leaks of memory or other resources * Exiting without calling destructors -* Sending signals -* Accessing/modifying the file system * Integer overflow Rust cannot prevent all kinds of software problems. Buggy code can and will be diff --git a/src/etc/snapshot.py b/src/etc/snapshot.py index 0349ccf9b6640..6d62a45c703a2 100644 --- a/src/etc/snapshot.py +++ b/src/etc/snapshot.py @@ -41,13 +41,14 @@ def scrub(b): download_unpack_base = os.path.join(download_dir_base, "unpack") snapshot_files = { + "bitrig": ["bin/rustc"], + "dragonfly": ["bin/rustc"], + "freebsd": ["bin/rustc"], "linux": ["bin/rustc"], "macos": ["bin/rustc"], - "winnt": ["bin/rustc.exe"], - "freebsd": ["bin/rustc"], - "dragonfly": ["bin/rustc"], - "bitrig": ["bin/rustc"], + "netbsd": ["bin/rustc"], "openbsd": ["bin/rustc"], + "winnt": ["bin/rustc.exe"], } winnt_runtime_deps_32 = ["libgcc_s_dw2-1.dll", "libstdc++-6.dll"] @@ -103,6 +104,8 @@ def get_kernel(triple): return "dragonfly" if os_name == "bitrig": return "bitrig" + if os_name == "netbsd": + return "netbsd" if os_name == "openbsd": return "openbsd" return "linux" diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 7bfeaec36d729..2a47fd29bd653 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -77,13 +77,15 @@ use core::atomic; use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst}; use core::fmt; use core::cmp::Ordering; -use core::mem::{min_align_of_val, size_of_val}; +use core::mem::{align_of_val, size_of_val}; use core::intrinsics::drop_in_place; use core::mem; use core::nonzero::NonZero; use core::ops::{Deref, CoerceUnsized}; +use core::ptr; use core::marker::Unsize; use core::hash::{Hash, Hasher}; +use core::usize; use heap::deallocate; /// An atomically reference counted wrapper for shared state. @@ -145,6 +147,8 @@ pub struct Weak { unsafe impl Send for Weak { } unsafe impl Sync for Weak { } +impl, U: ?Sized> CoerceUnsized> for Weak {} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -154,7 +158,12 @@ impl fmt::Debug for Weak { struct ArcInner { strong: atomic::AtomicUsize, + + // the value usize::MAX acts as a sentinel for temporarily "locking" the + // ability to upgrade weak pointers or downgrade strong ones; this is used + // to avoid races in `make_unique` and `get_mut`. weak: atomic::AtomicUsize, + data: T, } @@ -201,9 +210,25 @@ impl Arc { #[unstable(feature = "arc_weak", reason = "Weak pointers may not belong in this module.")] pub fn downgrade(&self) -> Weak { - // See the clone() impl for why this is relaxed - self.inner().weak.fetch_add(1, Relaxed); - Weak { _ptr: self._ptr } + loop { + // This Relaxed is OK because we're checking the value in the CAS + // below. + let cur = self.inner().weak.load(Relaxed); + + // check if the weak counter is currently "locked"; if so, spin. + if cur == usize::MAX { continue } + + // NOTE: this code currently ignores the possibility of overflow + // into usize::MAX; in general both Rc and Arc need to be adjusted + // to deal with overflow. + + // Unlike with Clone(), we need this to be an Acquire read to + // synchronize with the write coming from `is_unique`, so that the + // events prior to that write happen before this read. + if self.inner().weak.compare_and_swap(cur, cur + 1, Acquire) == cur { + return Weak { _ptr: self._ptr } + } + } } /// Get the number of weak references to this value. @@ -241,7 +266,7 @@ impl Arc { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - deallocate(ptr as *mut u8, size_of_val(&*ptr), min_align_of_val(&*ptr)) + deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) } } } @@ -258,51 +283,6 @@ pub fn weak_count(this: &Arc) -> usize { Arc::weak_count(this) } #[deprecated(since = "1.2.0", reason = "renamed to Arc::strong_count")] pub fn strong_count(this: &Arc) -> usize { Arc::strong_count(this) } - -/// Returns a mutable reference to the contained value if the `Arc` is unique. -/// -/// Returns `None` if the `Arc` is not unique. -/// -/// This function is marked **unsafe** because it is racy if weak pointers -/// are active. -/// -/// # Examples -/// -/// ``` -/// # #![feature(arc_unique, alloc)] -/// extern crate alloc; -/// # fn main() { -/// use alloc::arc::{Arc, get_mut}; -/// -/// # unsafe { -/// let mut x = Arc::new(3); -/// *get_mut(&mut x).unwrap() = 4; -/// assert_eq!(*x, 4); -/// -/// let _y = x.clone(); -/// assert!(get_mut(&mut x).is_none()); -/// # } -/// # } -/// ``` -#[inline] -#[unstable(feature = "arc_unique")] -#[deprecated(since = "1.2.0", - reason = "this function is unsafe with weak pointers")] -pub unsafe fn get_mut(this: &mut Arc) -> Option<&mut T> { - // FIXME(#24880) potential race with upgraded weak pointers here - if Arc::strong_count(this) == 1 && Arc::weak_count(this) == 0 { - // This unsafety is ok because we're guaranteed that the pointer - // returned is the *only* pointer that will ever be returned to T. Our - // reference count is guaranteed to be 1 at this point, and we required - // the Arc itself to be `mut`, so we're returning the only possible - // reference to the inner data. - let inner = &mut **this._ptr; - Some(&mut inner.data) - } else { - None - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Arc { /// Makes a clone of the `Arc`. @@ -350,10 +330,9 @@ impl Arc { /// Make a mutable reference from the given `Arc`. /// /// This is also referred to as a copy-on-write operation because the inner - /// data is cloned if the reference count is greater than one. - /// - /// This method is marked **unsafe** because it is racy if weak pointers - /// are active. + /// data is cloned if the (strong) reference count is greater than one. If + /// we hold the only strong reference, any existing weak references will no + /// longer be upgradeable. /// /// # Examples /// @@ -361,33 +340,140 @@ impl Arc { /// # #![feature(arc_unique)] /// use std::sync::Arc; /// - /// # unsafe { /// let mut five = Arc::new(5); /// - /// let mut_five = five.make_unique(); - /// # } + /// let mut_five = Arc::make_unique(&mut five); /// ``` #[inline] #[unstable(feature = "arc_unique")] - #[deprecated(since = "1.2.0", - reason = "this function is unsafe with weak pointers")] - pub unsafe fn make_unique(&mut self) -> &mut T { - // FIXME(#24880) potential race with upgraded weak pointers here + pub fn make_unique(this: &mut Arc) -> &mut T { + // Note that we hold both a strong reference and a weak reference. + // Thus, releasing our strong reference only will not, by itself, cause + // the memory to be deallocated. // - // Note that we hold a strong reference, which also counts as a weak - // reference, so we only clone if there is an additional reference of - // either kind. - if self.inner().strong.load(SeqCst) != 1 || - self.inner().weak.load(SeqCst) != 1 { - *self = Arc::new((**self).clone()) + // Use Acquire to ensure that we see any writes to `weak` that happen + // before release writes (i.e., decrements) to `strong`. Since we hold a + // weak count, there's no chance the ArcInner itself could be + // deallocated. + if this.inner().strong.compare_and_swap(1, 0, Acquire) != 1 { + // Another srong pointer exists; clone + *this = Arc::new((**this).clone()); + } else if this.inner().weak.load(Relaxed) != 1 { + // Relaxed suffices in the above because this is fundamentally an + // optimization: we are always racing with weak pointers being + // dropped. Worst case, we end up allocated a new Arc unnecessarily. + + // We removed the last strong ref, but there are additional weak + // refs remaining. We'll move the contents to a new Arc, and + // invalidate the other weak refs. + + // Note that it is not possible for the read of `weak` to yield + // usize::MAX (i.e., locked), since the weak count can only be + // locked by a thread with a strong reference. + + // Materialize our own implicit weak pointer, so that it can clean + // up the ArcInner as needed. + let weak = Weak { _ptr: this._ptr }; + + // mark the data itself as already deallocated + unsafe { + // there is no data race in the implicit write caused by `read` + // here (due to zeroing) because data is no longer accessed by + // other threads (due to there being no more strong refs at this + // point). + let mut swap = Arc::new(ptr::read(&(**weak._ptr).data)); + mem::swap(this, &mut swap); + mem::forget(swap); + } + } else { + // We were the sole reference of either kind; bump back up the + // strong ref count. + this.inner().strong.store(1, Release); } + // As with `get_mut()`, the unsafety is ok because our reference was // either unique to begin with, or became one upon cloning the contents. - let inner = &mut **self._ptr; - &mut inner.data + unsafe { + let inner = &mut **this._ptr; + &mut inner.data + } } } +impl Arc { + /// Returns a mutable reference to the contained value if the `Arc` is unique. + /// + /// Returns `None` if the `Arc` is not unique. + /// + /// # Examples + /// + /// ``` + /// # #![feature(arc_unique, alloc)] + /// extern crate alloc; + /// # fn main() { + /// use alloc::arc::Arc; + /// + /// let mut x = Arc::new(3); + /// *Arc::get_mut(&mut x).unwrap() = 4; + /// assert_eq!(*x, 4); + /// + /// let _y = x.clone(); + /// assert!(Arc::get_mut(&mut x).is_none()); + /// # } + /// ``` + #[inline] + #[unstable(feature = "arc_unique")] + pub fn get_mut(this: &mut Arc) -> Option<&mut T> { + if this.is_unique() { + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the Arc itself to be `mut`, so we're returning the only possible + // reference to the inner data. + unsafe { + let inner = &mut **this._ptr; + Some(&mut inner.data) + } + } else { + None + } + } + + /// Determine whether this is the unique reference (including weak refs) to + /// the underlying data. + /// + /// Note that this requires locking the weak ref count. + fn is_unique(&mut self) -> bool { + // lock the weak pointer count if we appear to be the sole weak pointer + // holder. + // + // The acquire label here ensures a happens-before relationship with any + // writes to `strong` prior to decrements of the `weak` count (via drop, + // which uses Release). + if self.inner().weak.compare_and_swap(1, usize::MAX, Acquire) == 1 { + // Due to the previous acquire read, this will observe any writes to + // `strong` that were due to upgrading weak pointers; only strong + // clones remain, which require that the strong count is > 1 anyway. + let unique = self.inner().strong.load(Relaxed) == 1; + + // The release write here synchronizes with a read in `downgrade`, + // effectively preventing the above read of `strong` from happening + // after the write. + self.inner().weak.store(1, Release); // release the lock + unique + } else { + false + } + } +} + +#[inline] +#[unstable(feature = "arc_unique")] +#[deprecated(since = "1.2", reason = "use Arc::get_mut instead")] +pub fn get_mut(this: &mut Arc) -> Option<&mut T> { + Arc::get_mut(this) +} + #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Arc { /// Drops the `Arc`. @@ -483,9 +569,15 @@ impl Weak { // fetch_add because once the count hits 0 it must never be above 0. let inner = self.inner(); loop { - let n = inner.strong.load(SeqCst); + // Relaxed load because any write of 0 that we can observe + // leaves the field in a permanently zero state (so a + // "stale" read of 0 is fine), and any other value is + // confirmed via the CAS below. + let n = inner.strong.load(Relaxed); if n == 0 { return None } - let old = inner.strong.compare_and_swap(n, n + 1, SeqCst); + + // Relaxed is valid for the same reason it is on Arc's Clone impl + let old = inner.strong.compare_and_swap(n, n + 1, Relaxed); if old == n { return Some(Arc { _ptr: self._ptr }) } } } @@ -516,9 +608,12 @@ impl Clone for Weak { /// ``` #[inline] fn clone(&self) -> Weak { - // See comments in Arc::clone() for why this is relaxed + // See comments in Arc::clone() for why this is relaxed. This can use a + // fetch_add (ignoring the lock) because the weak count is only locked + // where are *no other* weak pointers in existence. (So we can't be + // running this code in that case). self.inner().weak.fetch_add(1, Relaxed); - Weak { _ptr: self._ptr } + return Weak { _ptr: self._ptr } } } @@ -561,11 +656,16 @@ impl Drop for Weak { // If we find out that we were the last weak pointer, then its time to // deallocate the data entirely. See the discussion in Arc::drop() about // the memory orderings + // + // It's not necessary to check for the locked state here, because the + // weak count can only be locked if there was precisely one weak ref, + // meaning that drop could only subsequently run ON that remaining weak + // ref, which can only happen after the lock is released. if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { deallocate(ptr as *mut u8, size_of_val(&*ptr), - min_align_of_val(&*ptr)) } + align_of_val(&*ptr)) } } } } @@ -792,13 +892,13 @@ mod tests { let mut cow1 = cow0.clone(); let mut cow2 = cow1.clone(); - assert!(75 == *cow0.make_unique()); - assert!(75 == *cow1.make_unique()); - assert!(75 == *cow2.make_unique()); + assert!(75 == *Arc::make_unique(&mut cow0)); + assert!(75 == *Arc::make_unique(&mut cow1)); + assert!(75 == *Arc::make_unique(&mut cow2)); - *cow0.make_unique() += 1; - *cow1.make_unique() += 2; - *cow2.make_unique() += 3; + *Arc::make_unique(&mut cow0) += 1; + *Arc::make_unique(&mut cow1) += 2; + *Arc::make_unique(&mut cow2) += 3; assert!(76 == *cow0); assert!(77 == *cow1); @@ -822,7 +922,7 @@ mod tests { assert!(75 == *cow2); unsafe { - *cow0.make_unique() += 1; + *Arc::make_unique(&mut cow0) += 1; } assert!(76 == *cow0); @@ -845,7 +945,7 @@ mod tests { assert!(75 == *cow1_weak.upgrade().unwrap()); unsafe { - *cow0.make_unique() += 1; + *Arc::make_unique(&mut cow0) += 1; } assert!(76 == *cow0); diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 1039756363e9f..c941629b871ef 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -116,7 +116,7 @@ impl Box { /// of `T` and releases memory. Since the way `Box` allocates and /// releases memory is unspecified, the only valid pointer to pass /// to this function is the one taken from another `Box` with - /// `boxed::into_raw` function. + /// `Box::into_raw` function. /// /// Function is unsafe, because improper use of this function may /// lead to memory problems like double-free, for example if the @@ -140,10 +140,8 @@ impl Box { /// # Examples /// ``` /// # #![feature(box_raw)] - /// use std::boxed; - /// /// let seventeen = Box::new(17u32); - /// let raw = boxed::into_raw(seventeen); + /// let raw = Box::into_raw(seventeen); /// let boxed_again = unsafe { Box::from_raw(raw) }; /// ``` #[unstable(feature = "box_raw", reason = "may be renamed")] diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index fc44ac4eac628..2ef23b26a56a7 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -76,9 +76,9 @@ fn deref() { #[test] fn raw_sized() { + let x = Box::new(17); + let p = Box::into_raw(x); unsafe { - let x = Box::new(17); - let p = boxed::into_raw(x); assert_eq!(17, *p); *p = 19; let y = Box::from_raw(p); @@ -105,9 +105,9 @@ fn raw_trait() { } } + let x: Box = Box::new(Bar(17)); + let p = Box::into_raw(x); unsafe { - let x: Box = Box::new(Bar(17)); - let p = boxed::into_raw(x); assert_eq!(17, (*p).get()); (*p).set(19); let y: Box = Box::from_raw(p); diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index d5b6c86ef359a..d461eeea0b7eb 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -162,7 +162,7 @@ use core::fmt; use core::hash::{Hasher, Hash}; use core::intrinsics::{assume, drop_in_place}; use core::marker::{self, Unsize}; -use core::mem::{self, min_align_of, size_of, min_align_of_val, size_of_val, forget}; +use core::mem::{self, align_of, size_of, align_of_val, size_of_val, forget}; use core::nonzero::NonZero; use core::ops::{CoerceUnsized, Deref}; use core::ptr; @@ -246,7 +246,7 @@ impl Rc { // destruct the box and skip our Drop // we can ignore the refcounts because we know we're unique deallocate(*rc._ptr as *mut u8, size_of::>(), - min_align_of::>()); + align_of::>()); forget(rc); Ok(val) } @@ -496,7 +496,7 @@ impl Drop for Rc { if self.weak() == 0 { deallocate(ptr as *mut u8, size_of_val(&*ptr), - min_align_of_val(&*ptr)) + align_of_val(&*ptr)) } } } @@ -734,6 +734,8 @@ pub struct Weak { impl !marker::Send for Weak {} impl !marker::Sync for Weak {} +impl, U: ?Sized> CoerceUnsized> for Weak {} + #[unstable(feature = "rc_weak", reason = "Weak pointers may not belong in this module.")] impl Weak { @@ -805,7 +807,7 @@ impl Drop for Weak { // the strong pointers have disappeared. if self.weak() == 0 { deallocate(ptr as *mut u8, size_of_val(&*ptr), - min_align_of_val(&*ptr)) + align_of_val(&*ptr)) } } } diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 109ad8a942c84..4d064b16ad027 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -244,7 +244,7 @@ impl<'longer_than_self> Arena<'longer_than_self> { fn alloc_copy(&self, op: F) -> &mut T where F: FnOnce() -> T { unsafe { let ptr = self.alloc_copy_inner(mem::size_of::(), - mem::min_align_of::()); + mem::align_of::()); let ptr = ptr as *mut T; ptr::write(&mut (*ptr), op()); return &mut *ptr; @@ -300,7 +300,7 @@ impl<'longer_than_self> Arena<'longer_than_self> { let tydesc = get_tydesc::(); let (ty_ptr, ptr) = self.alloc_noncopy_inner(mem::size_of::(), - mem::min_align_of::()); + mem::align_of::()); let ty_ptr = ty_ptr as *mut usize; let ptr = ptr as *mut T; // Write in our tydesc along with a bit indicating that it @@ -393,7 +393,7 @@ struct TypedArenaChunk { fn calculate_size(capacity: usize) -> usize { let mut size = mem::size_of::>(); - size = round_up(size, mem::min_align_of::()); + size = round_up(size, mem::align_of::()); let elem_size = mem::size_of::(); let elems_size = elem_size.checked_mul(capacity).unwrap(); size = size.checked_add(elems_size).unwrap(); @@ -405,7 +405,7 @@ impl TypedArenaChunk { unsafe fn new(next: *mut TypedArenaChunk, capacity: usize) -> *mut TypedArenaChunk { let size = calculate_size::(capacity); - let chunk = allocate(size, mem::min_align_of::>()) + let chunk = allocate(size, mem::align_of::>()) as *mut TypedArenaChunk; if chunk.is_null() { alloc::oom() } (*chunk).next = next; @@ -431,7 +431,7 @@ impl TypedArenaChunk { let size = calculate_size::(self.capacity); let self_ptr: *mut TypedArenaChunk = self; deallocate(self_ptr as *mut u8, size, - mem::min_align_of::>()); + mem::align_of::>()); if !next.is_null() { let capacity = (*next).capacity; (*next).destroy(capacity); @@ -444,7 +444,7 @@ impl TypedArenaChunk { let this: *const TypedArenaChunk = self; unsafe { mem::transmute(round_up(this.offset(1) as usize, - mem::min_align_of::())) + mem::align_of::())) } } diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 51914900fdd99..a8d638028be3a 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![deprecated(reason = "BitVec and BitSet have been migrated to cargo as bit-vec and bit-set", + since = "1.3.0")] +#![unstable(feature = "collections", reason = "deprecated")] +#![allow(deprecated)] + // FIXME(Gankro): BitVec and BitSet are very tightly coupled. Ideally (for // maintenance), they should be in separate files/modules, with BitSet only // using BitVec's public API. This will be hard for performance though, because diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index 2d8335d373473..4d76a986700a2 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -163,12 +163,12 @@ fn test_offset_calculation() { } fn calculate_allocation_generic(capacity: usize, is_leaf: bool) -> (usize, usize) { - let (keys_size, keys_align) = (capacity * mem::size_of::(), mem::min_align_of::()); - let (vals_size, vals_align) = (capacity * mem::size_of::(), mem::min_align_of::()); + let (keys_size, keys_align) = (capacity * mem::size_of::(), mem::align_of::()); + let (vals_size, vals_align) = (capacity * mem::size_of::(), mem::align_of::()); let (edges_size, edges_align) = if is_leaf { (0, 1) } else { - ((capacity + 1) * mem::size_of::>(), mem::min_align_of::>()) + ((capacity + 1) * mem::size_of::>(), mem::align_of::>()) }; calculate_allocation( @@ -181,11 +181,11 @@ fn calculate_allocation_generic(capacity: usize, is_leaf: bool) -> (usize, fn calculate_offsets_generic(capacity: usize, is_leaf: bool) -> (usize, usize) { let keys_size = capacity * mem::size_of::(); let vals_size = capacity * mem::size_of::(); - let vals_align = mem::min_align_of::(); + let vals_align = mem::align_of::(); let edges_align = if is_leaf { 1 } else { - mem::min_align_of::>() + mem::align_of::>() }; calculate_offsets( diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 72d0ca85357a4..7df259e9b36a8 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -128,15 +128,15 @@ //! This allows multiple actual types to be formatted via `{:x}` (like `i8` as //! well as `isize`). The current mapping of types to traits is: //! -//! * *nothing* ⇒ `Display` -//! * `?` ⇒ `Debug` -//! * `o` ⇒ `Octal` -//! * `x` ⇒ `LowerHex` -//! * `X` ⇒ `UpperHex` -//! * `p` ⇒ `Pointer` -//! * `b` ⇒ `Binary` -//! * `e` ⇒ `LowerExp` -//! * `E` ⇒ `UpperExp` +//! * *nothing* ⇒ [`Display`](trait.Display.html) +//! * `?` ⇒ [`Debug`](trait.Debug.html) +//! * `o` ⇒ [`Octal`](trait.Octal.html) +//! * `x` ⇒ [`LowerHex`](trait.LowerHex.html) +//! * `X` ⇒ [`UpperHex`](trait.UpperHex.html) +//! * `p` ⇒ [`Pointer`](trait.Pointer.html) +//! * `b` ⇒ [`Binary`](trait.Binary.html) +//! * `e` ⇒ [`LowerExp`](trait.LowerExp.html) +//! * `E` ⇒ [`UpperExp`](trait.UpperExp.html) //! //! What this means is that any type of argument which implements the //! `fmt::Binary` trait can then be formatted with `{:b}`. Implementations @@ -367,11 +367,11 @@ //! should always be printed. //! * '-' - Currently not used //! * '#' - This flag is indicates that the "alternate" form of printing should -//! be used. For array slices, the alternate form omits the brackets. -//! For the integer formatting traits, the alternate forms are: +//! be used. The alternate forms are: +//! * `#?` - pretty-print the `Debug` formatting //! * `#x` - precedes the argument with a "0x" //! * `#X` - precedes the argument with a "0x" -//! * `#t` - precedes the argument with a "0b" +//! * `#b` - precedes the argument with a "0b" //! * `#o` - precedes the argument with a "0o" //! * '0' - This is used to indicate for integer formats that the padding should //! both be done with a `0` character as well as be sign-aware. A format @@ -408,19 +408,20 @@ //! //! There are three possible ways to specify the desired `precision`: //! -//! There are three possible ways to specify the desired `precision`: -//! 1. An integer `.N`, -//! 2. an integer followed by dollar sign `.N$`, or -//! 3. an asterisk `.*`. +//! 1. An integer `.N`: +//! +//! the integer `N` itself is the precision. +//! +//! 2. An integer followed by dollar sign `.N$`: //! -//! The first specification, `.N`, means the integer `N` itself is the precision. +//! use format *argument* `N` (which must be a `usize`) as the precision. //! -//! The second, `.N$`, means use format *argument* `N` (which must be a `usize`) as the precision. +//! 3. An asterisk `.*`: //! -//! Finally, `.*` means that this `{...}` is associated with *two* format inputs rather than one: -//! the first input holds the `usize` precision, and the second holds the value to print. Note -//! that in this case, if one uses the format string `{:.*}`, then the `` part -//! refers to the *value* to print, and the `precision` must come in the input preceding ``. +//! `.*` means that this `{...}` is associated with *two* format inputs rather than one: the +//! first input holds the `usize` precision, and the second holds the value to print. Note that +//! in this case, if one uses the format string `{:.*}`, then the `` part refers +//! to the *value* to print, and the `precision` must come in the input preceding ``. //! //! For example, these: //! diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 8d0f57de4c595..42adbe10e5051 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -77,7 +77,9 @@ extern crate alloc; #[cfg(test)] extern crate test; pub use binary_heap::BinaryHeap; +#[allow(deprecated)] pub use bit_vec::BitVec; +#[allow(deprecated)] pub use bit_set::BitSet; pub use btree_map::BTreeMap; pub use btree_set::BTreeSet; @@ -111,11 +113,13 @@ pub mod vec_map; #[unstable(feature = "bitvec", reason = "RFC 509")] pub mod bit_vec { + #![allow(deprecated)] pub use bit::{BitVec, Iter}; } #[unstable(feature = "bitset", reason = "RFC 509")] pub mod bit_set { + #![allow(deprecated)] pub use bit::{BitSet, Union, Intersection, Difference, SymmetricDifference}; pub use bit::SetIter as Iter; } diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 5e8a9bca342b0..7e72ad1569a1f 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -483,9 +483,7 @@ impl str { /// considered to be /// boundaries. /// - /// # Panics - /// - /// Panics if `index` is greater than `self.len()`. + /// Returns `false` if `index` is greater than `self.len()`. /// /// # Examples /// @@ -1859,8 +1857,6 @@ impl str { /// # Examples /// /// ``` - /// #![feature(str_casing)] - /// /// let s = "HELLO"; /// assert_eq!(s.to_lowercase(), "hello"); /// ``` @@ -1905,8 +1901,6 @@ impl str { /// # Examples /// /// ``` - /// #![feature(str_casing)] - /// /// let s = "hello"; /// assert_eq!(s.to_uppercase(), "HELLO"); /// ``` diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 6e37a5731b384..6b20d6e2a3f9b 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -317,9 +317,14 @@ impl String { /// Creates a new `String` from a length, capacity, and pointer. /// - /// This is unsafe because: + /// # Unsafety /// - /// * We call `Vec::from_raw_parts` to get a `Vec`; + /// This is _very_ unsafe because: + /// + /// * We call `Vec::from_raw_parts` to get a `Vec`. Therefore, this + /// function inherits all of its unsafety, see [its + /// documentation](../vec/struct.Vec.html#method.from_raw_parts) + /// for the invariants it expects, they also apply to this function. /// * We assume that the `Vec` contains valid UTF-8. #[inline] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 3aac1829a0c73..5b326b1a5b0ac 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -219,7 +219,7 @@ impl Vec { } else { let size = capacity.checked_mul(mem::size_of::()) .expect("capacity overflow"); - let ptr = unsafe { allocate(size, mem::min_align_of::()) }; + let ptr = unsafe { allocate(size, mem::align_of::()) }; if ptr.is_null() { ::alloc::oom() } unsafe { Vec::from_raw_parts(ptr as *mut T, 0, capacity) } } @@ -227,7 +227,17 @@ impl Vec { /// Creates a `Vec` directly from the raw components of another vector. /// - /// This is highly unsafe, due to the number of invariants that aren't checked. + /// # Unsafety + /// + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * `ptr` needs to have been previously allocated via `String`/`Vec` + /// (at least, it's highly likely to be incorrect if it wasn't). + /// * `capacity` needs to be the capacity that the pointer was allocated with. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal datastructures. /// /// # Examples /// @@ -393,7 +403,7 @@ impl Vec { let ptr = reallocate(*self.ptr as *mut u8, self.cap * mem::size_of::(), self.len * mem::size_of::(), - mem::min_align_of::()) as *mut T; + mem::align_of::()) as *mut T; if ptr.is_null() { ::alloc::oom() } self.ptr = Unique::new(ptr); } @@ -866,9 +876,9 @@ impl Vec { // FIXME: Assert statically that the types `T` and `U` have the // same minimal alignment in case they are not zero-sized. - // These asserts are necessary because the `min_align_of` of the + // These asserts are necessary because the `align_of` of the // types are passed to the allocator by `Vec`. - assert!(mem::min_align_of::() == mem::min_align_of::()); + assert!(mem::align_of::() == mem::align_of::()); // This `as isize` cast is safe, because the size of the elements of the // vector is not 0, and: @@ -1269,9 +1279,9 @@ impl Vec { #[inline(never)] unsafe fn alloc_or_realloc(ptr: *mut T, old_size: usize, size: usize) -> *mut T { if old_size == 0 { - allocate(size, mem::min_align_of::()) as *mut T + allocate(size, mem::align_of::()) as *mut T } else { - reallocate(ptr as *mut u8, old_size, size, mem::min_align_of::()) as *mut T + reallocate(ptr as *mut u8, old_size, size, mem::align_of::()) as *mut T } } @@ -1280,7 +1290,7 @@ unsafe fn dealloc(ptr: *mut T, len: usize) { if mem::size_of::() != 0 { deallocate(ptr as *mut u8, len * mem::size_of::(), - mem::min_align_of::()) + mem::align_of::()) } } diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index edcd1008747fd..ed47c06e7cd08 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -67,7 +67,7 @@ impl Drop for VecDeque { if mem::size_of::() != 0 { heap::deallocate(*self.ptr as *mut u8, self.cap * mem::size_of::(), - mem::min_align_of::()) + mem::align_of::()) } } } @@ -172,7 +172,7 @@ impl VecDeque { let ptr = unsafe { if mem::size_of::() != 0 { - let ptr = heap::allocate(size, mem::min_align_of::()) as *mut T;; + let ptr = heap::allocate(size, mem::align_of::()) as *mut T;; if ptr.is_null() { ::alloc::oom() } Unique::new(ptr) } else { @@ -340,7 +340,7 @@ impl VecDeque { let ptr = heap::reallocate(*self.ptr as *mut u8, old, new, - mem::min_align_of::()) as *mut T; + mem::align_of::()) as *mut T; if ptr.is_null() { ::alloc::oom() } self.ptr = Unique::new(ptr); } @@ -460,7 +460,7 @@ impl VecDeque { let ptr = heap::reallocate(*self.ptr as *mut u8, old, new_size, - mem::min_align_of::()) as *mut T; + mem::align_of::()) as *mut T; if ptr.is_null() { ::alloc::oom() } self.ptr = Unique::new(ptr); } diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 3f32136bc2639..87a018ced195a 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -705,7 +705,7 @@ fn test_split_at() { #[should_panic] fn test_split_at_boundscheck() { let s = "ศไทย中华Việt Nam"; - let (a, b) = s.split_at(1); + s.split_at(1); } #[test] @@ -1820,6 +1820,14 @@ mod pattern { Match (4, 6), Reject(6, 7), ]); + make_test!(str_searcher_ascii_haystack_seq, "bb", "abbcbbbbd", [ + Reject(0, 1), + Match (1, 3), + Reject(3, 4), + Match (4, 6), + Match (6, 8), + Reject(8, 9), + ]); make_test!(str_searcher_empty_needle_ascii_haystack, "", "abbcbbd", [ Match (0, 0), Reject(0, 1), diff --git a/src/libcore/any.rs b/src/libcore/any.rs index f0c77ae866d59..e7b39c11f4c1b 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Traits for dynamic typing of any `'static` type (through runtime reflection) -//! //! This module implements the `Any` trait, which enables dynamic typing //! of any `'static` type through runtime reflection. //! //! `Any` itself can be used to get a `TypeId`, and has more features when used //! as a trait object. As `&Any` (a borrowed trait object), it has the `is` and //! `as_ref` methods, to test if the contained value is of a given type, and to -//! get a reference to the inner value as a type. As`&mut Any`, there is also +//! get a reference to the inner value as a type. As `&mut Any`, there is also //! the `as_mut` method, for getting a mutable reference to the inner value. //! `Box` adds the `move` method, which will unwrap a `Box` from the //! object. See the extension traits (`*Ext`) for the full details. diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index 1b8ee8db5f47a..a77df09664313 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -272,13 +272,13 @@ impl AtomicBool { unsafe { atomic_swap(self.v.get(), val, order) > 0 } } - /// Stores a value into the bool if the current value is the same as the expected value. + /// Stores a value into the `bool` if the current value is the same as the `current` value. /// - /// The return value is always the previous value. If it is equal to `old`, then the value was - /// updated. + /// The return value is always the previous value. If it is equal to `current`, then the value + /// was updated. /// - /// `swap` also takes an `Ordering` argument which describes the memory ordering of this - /// operation. + /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of + /// this operation. /// /// # Examples /// @@ -295,11 +295,11 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn compare_and_swap(&self, old: bool, new: bool, order: Ordering) -> bool { - let old = if old { UINT_TRUE } else { 0 }; + pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { + let current = if current { UINT_TRUE } else { 0 }; let new = if new { UINT_TRUE } else { 0 }; - unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) > 0 } + unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) > 0 } } /// Logical "and" with a boolean value. @@ -515,10 +515,10 @@ impl AtomicIsize { unsafe { atomic_swap(self.v.get(), val, order) } } - /// Stores a value into the isize if the current value is the same as the expected value. + /// Stores a value into the `isize` if the current value is the same as the `current` value. /// - /// The return value is always the previous value. If it is equal to `old`, then the value was - /// updated. + /// The return value is always the previous value. If it is equal to `current`, then the value + /// was updated. /// /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of /// this operation. @@ -538,8 +538,8 @@ impl AtomicIsize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn compare_and_swap(&self, old: isize, new: isize, order: Ordering) -> isize { - unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) } + pub fn compare_and_swap(&self, current: isize, new: isize, order: Ordering) -> isize { + unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) } } /// Add an isize to the current value, returning the previous value. @@ -709,10 +709,10 @@ impl AtomicUsize { unsafe { atomic_swap(self.v.get(), val, order) } } - /// Stores a value into the usize if the current value is the same as the expected value. + /// Stores a value into the `usize` if the current value is the same as the `current` value. /// - /// The return value is always the previous value. If it is equal to `old`, then the value was - /// updated. + /// The return value is always the previous value. If it is equal to `current`, then the value + /// was updated. /// /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of /// this operation. @@ -732,8 +732,8 @@ impl AtomicUsize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn compare_and_swap(&self, old: usize, new: usize, order: Ordering) -> usize { - unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) } + pub fn compare_and_swap(&self, current: usize, new: usize, order: Ordering) -> usize { + unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) } } /// Add to the current usize, returning the previous value. @@ -910,10 +910,10 @@ impl AtomicPtr { unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T } } - /// Stores a value into the pointer if the current value is the same as the expected value. + /// Stores a value into the pointer if the current value is the same as the `current` value. /// - /// The return value is always the previous value. If it is equal to `old`, then the value was - /// updated. + /// The return value is always the previous value. If it is equal to `current`, then the value + /// was updated. /// /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of /// this operation. @@ -933,9 +933,9 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn compare_and_swap(&self, old: *mut T, new: *mut T, order: Ordering) -> *mut T { + pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T { unsafe { - atomic_compare_and_swap(self.p.get() as *mut usize, old as usize, + atomic_compare_and_swap(self.p.get() as *mut usize, current as usize, new as usize, order) as *mut T } } @@ -953,7 +953,6 @@ unsafe fn atomic_store(dst: *mut T, val: T, order:Ordering) { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_load(dst: *const T, order:Ordering) -> T { match order { Acquire => intrinsics::atomic_load_acq(dst), @@ -965,7 +964,6 @@ unsafe fn atomic_load(dst: *const T, order:Ordering) -> T { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xchg_acq(dst, val), @@ -978,7 +976,6 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the old value (like __sync_fetch_and_add). #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xadd_acq(dst, val), @@ -991,7 +988,6 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the old value (like __sync_fetch_and_sub). #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xsub_acq(dst, val), @@ -1003,7 +999,6 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_compare_and_swap(dst: *mut T, old:T, new:T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_cxchg_acq(dst, old, new), @@ -1015,7 +1010,6 @@ unsafe fn atomic_compare_and_swap(dst: *mut T, old:T, new:T, order: Ordering) } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_and_acq(dst, val), @@ -1027,7 +1021,6 @@ unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_nand_acq(dst, val), @@ -1040,7 +1033,6 @@ unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_or_acq(dst, val), @@ -1053,7 +1045,6 @@ unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xor_acq(dst, val), diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 0269499ad5414..52ed29c1b61f4 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -166,6 +166,8 @@ impl Ordering { /// /// - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true; and /// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. +/// +/// When this trait is `derive`d, it produces a lexicographic ordering. #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index cbbb186af7609..f735ed7b78b17 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -267,7 +267,7 @@ impl<'a> Display for Arguments<'a> { } } -/// Format trait for the `:?` format. Useful for debugging, all types +/// Format trait for the `?` character. Useful for debugging, all types /// should implement this. /// /// Generally speaking, you should just `derive` a `Debug` implementation. @@ -312,6 +312,9 @@ impl<'a> Display for Arguments<'a> { /// There are a number of `debug_*` methods on `Formatter` to help you with manual /// implementations, such as [`debug_struct`][debug_struct]. /// +/// `Debug` implementations using either `derive` or the debug builder API +/// on `Formatter` support pretty printing using the alternate flag: `{:#?}`. +/// /// [debug_struct]: ../std/fmt/struct.Formatter.html#method.debug_struct #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \ @@ -980,7 +983,14 @@ impl Debug for char { #[stable(feature = "rust1", since = "1.0.0")] impl Display for char { fn fmt(&self, f: &mut Formatter) -> Result { - f.write_char(*self) + if f.width.is_none() && f.precision.is_none() { + f.write_char(*self) + } else { + let mut utf8 = [0; 4]; + let amt = self.encode_utf8(&mut utf8).unwrap_or(0); + let s: &str = unsafe { mem::transmute(&utf8[..amt]) }; + f.pad(s) + } } } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 3026f91e853ee..4c8511eb1902c 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2655,8 +2655,8 @@ macro_rules! step_impl_signed { #[allow(trivial_numeric_casts)] fn steps_between(start: &$t, end: &$t, by: &$t) -> Option { if *by == 0 { return None; } - let mut diff: usize; - let mut by_u: usize; + let diff: usize; + let by_u: usize; if *by > 0 { if *start >= *end { return Some(0); diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 15e7cdbde408d..3bcb499de47f4 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -155,6 +155,7 @@ pub fn size_of_val(val: &T) -> usize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(reason = "use `align_of` instead", since = "1.2.0")] pub fn min_align_of() -> usize { unsafe { intrinsics::min_align_of::() } } @@ -170,14 +171,14 @@ pub fn min_align_of() -> usize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(reason = "use `align_of_val` instead", since = "1.2.0")] pub fn min_align_of_val(val: &T) -> usize { unsafe { intrinsics::min_align_of_val(val) } } /// Returns the alignment in memory for a type. /// -/// This function will return the alignment, in bytes, of a type in memory. If the alignment -/// returned is adhered to, then the type is guaranteed to function properly. +/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. /// /// # Examples /// @@ -189,17 +190,10 @@ pub fn min_align_of_val(val: &T) -> usize { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn align_of() -> usize { - // We use the preferred alignment as the default alignment for a type. This - // appears to be what clang migrated towards as well: - // - // http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20110725/044411.html - unsafe { intrinsics::pref_align_of::() } + unsafe { intrinsics::min_align_of::() } } -/// Returns the alignment of the type of the value that `_val` points to. -/// -/// This is similar to `align_of`, but function will properly handle types such as trait objects -/// (in the future), returning the alignment for an arbitrary value at runtime. +/// Returns the ABI-required minimum alignment of the type of the value that `val` points to /// /// # Examples /// @@ -210,8 +204,8 @@ pub fn align_of() -> usize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn align_of_val(_val: &T) -> usize { - align_of::() +pub fn align_of_val(val: &T) -> usize { + unsafe { intrinsics::min_align_of_val(val) } } /// Creates a value initialized to zero. @@ -371,11 +365,48 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// Disposes of a value. /// -/// This function can be used to destroy any value by allowing `drop` to take ownership of its -/// argument. +/// While this does call the argument's implementation of `Drop`, it will not +/// release any borrows, as borrows are based on lexical scope. /// /// # Examples /// +/// Basic usage: +/// +/// ``` +/// let v = vec![1, 2, 3]; +/// +/// drop(v); // explicitly drop the vector +/// ``` +/// +/// Borrows are based on lexical scope, so this produces an error: +/// +/// ```ignore +/// let mut v = vec![1, 2, 3]; +/// let x = &v[0]; +/// +/// drop(x); // explicitly drop the reference, but the borrow still exists +/// +/// v.push(4); // error: cannot borrow `v` as mutable because it is also +/// // borrowed as immutable +/// ``` +/// +/// An inner scope is needed to fix this: +/// +/// ``` +/// let mut v = vec![1, 2, 3]; +/// +/// { +/// let x = &v[0]; +/// +/// drop(x); // this is now redundant, as `x` is going out of scope anyway +/// } +/// +/// v.push(4); // no problems +/// ``` +/// +/// Since `RefCell` enforces the borrow rules at runtime, `drop()` can +/// seemingly release a borrow of one: +/// /// ``` /// use std::cell::RefCell; /// diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index aade9061657b7..c8f95a3672d4a 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -215,13 +215,37 @@ impl Float for f32 { /// Rounds towards minus infinity. #[inline] fn floor(self) -> f32 { - unsafe { intrinsics::floorf32(self) } + return floorf(self); + + // On MSVC LLVM will lower many math intrinsics to a call to the + // corresponding function. On MSVC, however, many of these functions + // aren't actually available as symbols to call, but rather they are all + // `static inline` functions in header files. This means that from a C + // perspective it's "compatible", but not so much from an ABI + // perspective (which we're worried about). + // + // The inline header functions always just cast to a f64 and do their + // operation, so we do that here as well, but only for MSVC targets. + // + // Note that there are many MSVC-specific float operations which + // redirect to this comment, so `floorf` is just one case of a missing + // function on MSVC, but there are many others elsewhere. + #[cfg(target_env = "msvc")] + fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 } + #[cfg(not(target_env = "msvc"))] + fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } } } /// Rounds towards plus infinity. #[inline] fn ceil(self) -> f32 { - unsafe { intrinsics::ceilf32(self) } + return ceilf(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 } + #[cfg(not(target_env = "msvc"))] + fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } } } /// Rounds to nearest integer. Rounds half-way cases away from zero. @@ -299,7 +323,13 @@ impl Float for f32 { #[inline] fn powf(self, n: f32) -> f32 { - unsafe { intrinsics::powf32(self, n) } + return powf(self, n); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 } + #[cfg(not(target_env = "msvc"))] + fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } } } #[inline] @@ -317,7 +347,13 @@ impl Float for f32 { /// Returns the exponential of the number. #[inline] fn exp(self) -> f32 { - unsafe { intrinsics::expf32(self) } + return expf(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn expf(f: f32) -> f32 { (f as f64).exp() as f32 } + #[cfg(not(target_env = "msvc"))] + fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } } } /// Returns 2 raised to the power of the number. @@ -329,7 +365,13 @@ impl Float for f32 { /// Returns the natural logarithm of the number. #[inline] fn ln(self) -> f32 { - unsafe { intrinsics::logf32(self) } + return logf(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn logf(f: f32) -> f32 { (f as f64).ln() as f32 } + #[cfg(not(target_env = "msvc"))] + fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } } } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -345,7 +387,13 @@ impl Float for f32 { /// Returns the base 10 logarithm of the number. #[inline] fn log10(self) -> f32 { - unsafe { intrinsics::log10f32(self) } + return log10f(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 } + #[cfg(not(target_env = "msvc"))] + fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } } } /// Converts to degrees, assuming the number is in radians. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 97b4f77675533..fd5ef4b1cccca 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -668,10 +668,12 @@ macro_rules! uint_impl { $mul_with_overflow:path) => { /// Returns the smallest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn min_value() -> Self { 0 } /// Returns the largest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn max_value() -> Self { !0 } /// Converts a string slice in a given base to an integer. diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 48b1cbeef4fdd..9a22fe3a493f1 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -419,26 +419,40 @@ macro_rules! rem_impl { )*) } -macro_rules! rem_float_impl { - ($t:ty, $fmod:ident) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl Rem for $t { - type Output = $t; +rem_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } - #[inline] - fn rem(self, other: $t) -> $t { - extern { fn $fmod(a: $t, b: $t) -> $t; } - unsafe { $fmod(self, other) } - } - } +#[stable(feature = "rust1", since = "1.0.0")] +impl Rem for f32 { + type Output = f32; + + // see notes in `core::f32::Float::floor` + #[inline] + #[cfg(target_env = "msvc")] + fn rem(self, other: f32) -> f32 { + (self as f64).rem(other as f64) as f32 + } - forward_ref_binop! { impl Rem, rem for $t, $t } + #[inline] + #[cfg(not(target_env = "msvc"))] + fn rem(self, other: f32) -> f32 { + extern { fn fmodf(a: f32, b: f32) -> f32; } + unsafe { fmodf(self, other) } } } -rem_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } -rem_float_impl! { f32, fmodf } -rem_float_impl! { f64, fmod } +#[stable(feature = "rust1", since = "1.0.0")] +impl Rem for f64 { + type Output = f64; + + #[inline] + fn rem(self, other: f64) -> f64 { + extern { fn fmod(a: f64, b: f64) -> f64; } + unsafe { fmod(self, other) } + } +} + +forward_ref_binop! { impl Rem, rem for f64, f64 } +forward_ref_binop! { impl Rem, rem for f32, f32 } /// The `Neg` trait is used to specify the functionality of unary `-`. /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f2792a525d66b..7b33a41f9556a 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -50,14 +50,12 @@ //! //! ``` //! # #![feature(box_raw)] -//! use std::boxed; +//! let my_speed: Box = Box::new(88); +//! let my_speed: *mut i32 = Box::into_raw(my_speed); //! +//! // By taking ownership of the original `Box` though +//! // we are obligated to put it together later to be destroyed. //! unsafe { -//! let my_speed: Box = Box::new(88); -//! let my_speed: *mut i32 = boxed::into_raw(my_speed); -//! -//! // By taking ownership of the original `Box` though -//! // we are obligated to put it together later to be destroyed. //! drop(Box::from_raw(my_speed)); //! } //! ``` diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5a621176c4a81..bd6e1a4063abd 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -15,13 +15,12 @@ #![doc(primitive = "str")] #![stable(feature = "rust1", since = "1.0.0")] -use self::OldSearcher::{TwoWay, TwoWayLong}; use self::pattern::Pattern; use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char::CharExt; use clone::Clone; -use cmp::{self, Eq}; +use cmp::Eq; use convert::AsRef; use default::Default; use fmt; @@ -33,7 +32,6 @@ use option::Option::{self, None, Some}; use raw::{Repr, Slice}; use result::Result::{self, Ok, Err}; use slice::{self, SliceExt}; -use usize; pub mod pattern; @@ -870,301 +868,6 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> { } } -/// The internal state of an iterator that searches for matches of a substring -/// within a larger string using two-way search -#[derive(Clone)] -struct TwoWaySearcher { - // constants - crit_pos: usize, - period: usize, - byteset: u64, - - // variables - position: usize, - memory: usize -} - -/* - This is the Two-Way search algorithm, which was introduced in the paper: - Crochemore, M., Perrin, D., 1991, Two-way string-matching, Journal of the ACM 38(3):651-675. - - Here's some background information. - - A *word* is a string of symbols. The *length* of a word should be a familiar - notion, and here we denote it for any word x by |x|. - (We also allow for the possibility of the *empty word*, a word of length zero). - - If x is any non-empty word, then an integer p with 0 < p <= |x| is said to be a - *period* for x iff for all i with 0 <= i <= |x| - p - 1, we have x[i] == x[i+p]. - For example, both 1 and 2 are periods for the string "aa". As another example, - the only period of the string "abcd" is 4. - - We denote by period(x) the *smallest* period of x (provided that x is non-empty). - This is always well-defined since every non-empty word x has at least one period, - |x|. We sometimes call this *the period* of x. - - If u, v and x are words such that x = uv, where uv is the concatenation of u and - v, then we say that (u, v) is a *factorization* of x. - - Let (u, v) be a factorization for a word x. Then if w is a non-empty word such - that both of the following hold - - - either w is a suffix of u or u is a suffix of w - - either w is a prefix of v or v is a prefix of w - - then w is said to be a *repetition* for the factorization (u, v). - - Just to unpack this, there are four possibilities here. Let w = "abc". Then we - might have: - - - w is a suffix of u and w is a prefix of v. ex: ("lolabc", "abcde") - - w is a suffix of u and v is a prefix of w. ex: ("lolabc", "ab") - - u is a suffix of w and w is a prefix of v. ex: ("bc", "abchi") - - u is a suffix of w and v is a prefix of w. ex: ("bc", "a") - - Note that the word vu is a repetition for any factorization (u,v) of x = uv, - so every factorization has at least one repetition. - - If x is a string and (u, v) is a factorization for x, then a *local period* for - (u, v) is an integer r such that there is some word w such that |w| = r and w is - a repetition for (u, v). - - We denote by local_period(u, v) the smallest local period of (u, v). We sometimes - call this *the local period* of (u, v). Provided that x = uv is non-empty, this - is well-defined (because each non-empty word has at least one factorization, as - noted above). - - It can be proven that the following is an equivalent definition of a local period - for a factorization (u, v): any positive integer r such that x[i] == x[i+r] for - all i such that |u| - r <= i <= |u| - 1 and such that both x[i] and x[i+r] are - defined. (i.e. i > 0 and i + r < |x|). - - Using the above reformulation, it is easy to prove that - - 1 <= local_period(u, v) <= period(uv) - - A factorization (u, v) of x such that local_period(u,v) = period(x) is called a - *critical factorization*. - - The algorithm hinges on the following theorem, which is stated without proof: - - **Critical Factorization Theorem** Any word x has at least one critical - factorization (u, v) such that |u| < period(x). - - The purpose of maximal_suffix is to find such a critical factorization. - -*/ -impl TwoWaySearcher { - #[allow(dead_code)] - fn new(needle: &[u8]) -> TwoWaySearcher { - let (crit_pos_false, period_false) = TwoWaySearcher::maximal_suffix(needle, false); - let (crit_pos_true, period_true) = TwoWaySearcher::maximal_suffix(needle, true); - - let (crit_pos, period) = - if crit_pos_false > crit_pos_true { - (crit_pos_false, period_false) - } else { - (crit_pos_true, period_true) - }; - - // This isn't in the original algorithm, as far as I'm aware. - let byteset = needle.iter() - .fold(0, |a, &b| (1 << ((b & 0x3f) as usize)) | a); - - // A particularly readable explanation of what's going on here can be found - // in Crochemore and Rytter's book "Text Algorithms", ch 13. Specifically - // see the code for "Algorithm CP" on p. 323. - // - // What's going on is we have some critical factorization (u, v) of the - // needle, and we want to determine whether u is a suffix of - // &v[..period]. If it is, we use "Algorithm CP1". Otherwise we use - // "Algorithm CP2", which is optimized for when the period of the needle - // is large. - if &needle[..crit_pos] == &needle[period.. period + crit_pos] { - TwoWaySearcher { - crit_pos: crit_pos, - period: period, - byteset: byteset, - - position: 0, - memory: 0 - } - } else { - TwoWaySearcher { - crit_pos: crit_pos, - period: cmp::max(crit_pos, needle.len() - crit_pos) + 1, - byteset: byteset, - - position: 0, - memory: usize::MAX // Dummy value to signify that the period is long - } - } - } - - // One of the main ideas of Two-Way is that we factorize the needle into - // two halves, (u, v), and begin trying to find v in the haystack by scanning - // left to right. If v matches, we try to match u by scanning right to left. - // How far we can jump when we encounter a mismatch is all based on the fact - // that (u, v) is a critical factorization for the needle. - #[inline] - fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool) - -> Option<(usize, usize)> { - 'search: loop { - // Check that we have room to search in - if self.position + needle.len() > haystack.len() { - return None; - } - - // Quickly skip by large portions unrelated to our substring - if (self.byteset >> - ((haystack[self.position + needle.len() - 1] & 0x3f) - as usize)) & 1 == 0 { - self.position += needle.len(); - if !long_period { - self.memory = 0; - } - continue 'search; - } - - // See if the right part of the needle matches - let start = if long_period { self.crit_pos } - else { cmp::max(self.crit_pos, self.memory) }; - for i in start..needle.len() { - if needle[i] != haystack[self.position + i] { - self.position += i - self.crit_pos + 1; - if !long_period { - self.memory = 0; - } - continue 'search; - } - } - - // See if the left part of the needle matches - let start = if long_period { 0 } else { self.memory }; - for i in (start..self.crit_pos).rev() { - if needle[i] != haystack[self.position + i] { - self.position += self.period; - if !long_period { - self.memory = needle.len() - self.period; - } - continue 'search; - } - } - - // We have found a match! - let match_pos = self.position; - self.position += needle.len(); // add self.period for all matches - if !long_period { - self.memory = 0; // set to needle.len() - self.period for all matches - } - return Some((match_pos, match_pos + needle.len())); - } - } - - // Computes a critical factorization (u, v) of `arr`. - // Specifically, returns (i, p), where i is the starting index of v in some - // critical factorization (u, v) and p = period(v) - #[inline] - #[allow(dead_code)] - #[allow(deprecated)] - fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) { - let mut left: usize = !0; // Corresponds to i in the paper - let mut right = 0; // Corresponds to j in the paper - let mut offset = 1; // Corresponds to k in the paper - let mut period = 1; // Corresponds to p in the paper - - while right + offset < arr.len() { - let a; - let b; - if reversed { - a = arr[left.wrapping_add(offset)]; - b = arr[right + offset]; - } else { - a = arr[right + offset]; - b = arr[left.wrapping_add(offset)]; - } - if a < b { - // Suffix is smaller, period is entire prefix so far. - right += offset; - offset = 1; - period = right.wrapping_sub(left); - } else if a == b { - // Advance through repetition of the current period. - if offset == period { - right += offset; - offset = 1; - } else { - offset += 1; - } - } else { - // Suffix is larger, start over from current location. - left = right; - right += 1; - offset = 1; - period = 1; - } - } - (left.wrapping_add(1), period) - } -} - -/// The internal state of an iterator that searches for matches of a substring -/// within a larger string using a dynamically chosen search algorithm -#[derive(Clone)] -// NB: This is kept around for convenience because -// it is planned to be used again in the future -enum OldSearcher { - TwoWay(TwoWaySearcher), - TwoWayLong(TwoWaySearcher), -} - -impl OldSearcher { - #[allow(dead_code)] - fn new(haystack: &[u8], needle: &[u8]) -> OldSearcher { - if needle.is_empty() { - // Handle specially - unimplemented!() - // FIXME: Tune this. - // FIXME(#16715): This unsigned integer addition will probably not - // overflow because that would mean that the memory almost solely - // consists of the needle. Needs #16715 to be formally fixed. - } else if needle.len() + 20 > haystack.len() { - // Use naive searcher - unimplemented!() - } else { - let searcher = TwoWaySearcher::new(needle); - if searcher.memory == usize::MAX { // If the period is long - TwoWayLong(searcher) - } else { - TwoWay(searcher) - } - } - } -} - -#[derive(Clone)] -// NB: This is kept around for convenience because -// it is planned to be used again in the future -struct OldMatchIndices<'a, 'b> { - // constants - haystack: &'a str, - needle: &'b str, - searcher: OldSearcher -} - -impl<'a, 'b> OldMatchIndices<'a, 'b> { - #[inline] - #[allow(dead_code)] - fn next(&mut self) -> Option<(usize, usize)> { - match self.searcher { - TwoWay(ref mut searcher) - => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), false), - TwoWayLong(ref mut searcher) - => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), true), - } - } -} - /* Section: Comparing strings */ diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 8bdbab55211d8..707f7fcf2abcf 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -17,6 +17,8 @@ reason = "API not fully fleshed out and ready to be stabilized")] use prelude::*; +use core::cmp; +use usize; // Pattern @@ -341,148 +343,6 @@ unsafe impl<'a, C: CharEq> ReverseSearcher<'a> for CharEqSearcher<'a, C> { impl<'a, C: CharEq> DoubleEndedSearcher<'a> for CharEqSearcher<'a, C> {} -///////////////////////////////////////////////////////////////////////////// -// Impl for &str -///////////////////////////////////////////////////////////////////////////// - -// Todo: Optimize the naive implementation here - -/// Associated type for `<&str as Pattern<'a>>::Searcher`. -#[derive(Clone)] -pub struct StrSearcher<'a, 'b> { - haystack: &'a str, - needle: &'b str, - start: usize, - end: usize, - state: State, -} - -#[derive(Clone, PartialEq)] -enum State { Done, NotDone, Reject(usize, usize) } -impl State { - #[inline] fn done(&self) -> bool { *self == State::Done } - #[inline] fn take(&mut self) -> State { ::mem::replace(self, State::NotDone) } -} - -/// Non-allocating substring search. -/// -/// Will handle the pattern `""` as returning empty matches at each utf8 -/// boundary. -impl<'a, 'b> Pattern<'a> for &'b str { - type Searcher = StrSearcher<'a, 'b>; - - #[inline] - fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> { - StrSearcher { - haystack: haystack, - needle: self, - start: 0, - end: haystack.len(), - state: State::NotDone, - } - } -} - -unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> { - #[inline] - fn haystack(&self) -> &'a str { - self.haystack - } - - #[inline] - fn next(&mut self) -> SearchStep { - str_search_step(self, - |m: &mut StrSearcher| { - // Forward step for empty needle - let current_start = m.start; - if !m.state.done() { - m.start = m.haystack.char_range_at(current_start).next; - m.state = State::Reject(current_start, m.start); - } - SearchStep::Match(current_start, current_start) - }, - |m: &mut StrSearcher| { - // Forward step for nonempty needle - let current_start = m.start; - // Compare byte window because this might break utf8 boundaries - let possible_match = &m.haystack.as_bytes()[m.start .. m.start + m.needle.len()]; - if possible_match == m.needle.as_bytes() { - m.start += m.needle.len(); - SearchStep::Match(current_start, m.start) - } else { - // Skip a char - let haystack_suffix = &m.haystack[m.start..]; - m.start += haystack_suffix.chars().next().unwrap().len_utf8(); - SearchStep::Reject(current_start, m.start) - } - }) - } -} - -unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> { - #[inline] - fn next_back(&mut self) -> SearchStep { - str_search_step(self, - |m: &mut StrSearcher| { - // Backward step for empty needle - let current_end = m.end; - if !m.state.done() { - m.end = m.haystack.char_range_at_reverse(current_end).next; - m.state = State::Reject(m.end, current_end); - } - SearchStep::Match(current_end, current_end) - }, - |m: &mut StrSearcher| { - // Backward step for nonempty needle - let current_end = m.end; - // Compare byte window because this might break utf8 boundaries - let possible_match = &m.haystack.as_bytes()[m.end - m.needle.len() .. m.end]; - if possible_match == m.needle.as_bytes() { - m.end -= m.needle.len(); - SearchStep::Match(m.end, current_end) - } else { - // Skip a char - let haystack_prefix = &m.haystack[..m.end]; - m.end -= haystack_prefix.chars().rev().next().unwrap().len_utf8(); - SearchStep::Reject(m.end, current_end) - } - }) - } -} - -// Helper function for encapsulating the common control flow -// of doing a search step from the front or doing a search step from the back -fn str_search_step(mut m: &mut StrSearcher, - empty_needle_step: F, - nonempty_needle_step: G) -> SearchStep - where F: FnOnce(&mut StrSearcher) -> SearchStep, - G: FnOnce(&mut StrSearcher) -> SearchStep -{ - if m.state.done() { - SearchStep::Done - } else if m.needle.is_empty() && m.start <= m.end { - // Case for needle == "" - if let State::Reject(a, b) = m.state.take() { - SearchStep::Reject(a, b) - } else { - if m.start == m.end { - m.state = State::Done; - } - empty_needle_step(&mut m) - } - } else if m.start + m.needle.len() <= m.end { - // Case for needle != "" - nonempty_needle_step(&mut m) - } else if m.start < m.end { - // Remaining slice shorter than needle, reject it - m.state = State::Done; - SearchStep::Reject(m.start, m.end) - } else { - m.state = State::Done; - SearchStep::Done - } -} - ///////////////////////////////////////////////////////////////////////////// macro_rules! pattern_methods { @@ -633,3 +493,578 @@ impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool { impl<'a, 'b> Pattern<'a> for &'b &'b str { pattern_methods!(StrSearcher<'a, 'b>, |&s| s, |s| s); } + +///////////////////////////////////////////////////////////////////////////// +// Impl for &str +///////////////////////////////////////////////////////////////////////////// + +/// Non-allocating substring search. +/// +/// Will handle the pattern `""` as returning empty matches at each character +/// boundary. +impl<'a, 'b> Pattern<'a> for &'b str { + type Searcher = StrSearcher<'a, 'b>; + + #[inline] + fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> { + StrSearcher::new(haystack, self) + } + + /// Checks whether the pattern matches at the front of the haystack + #[inline] + fn is_prefix_of(self, haystack: &'a str) -> bool { + haystack.is_char_boundary(self.len()) && + self == &haystack[..self.len()] + } + + /// Checks whether the pattern matches at the back of the haystack + #[inline] + fn is_suffix_of(self, haystack: &'a str) -> bool { + self.len() <= haystack.len() && + haystack.is_char_boundary(haystack.len() - self.len()) && + self == &haystack[haystack.len() - self.len()..] + } +} + + +///////////////////////////////////////////////////////////////////////////// +// Two Way substring searcher +///////////////////////////////////////////////////////////////////////////// + +#[derive(Clone, Debug)] +/// Associated type for `<&str as Pattern<'a>>::Searcher`. +pub struct StrSearcher<'a, 'b> { + haystack: &'a str, + needle: &'b str, + + searcher: StrSearcherImpl, +} + +#[derive(Clone, Debug)] +enum StrSearcherImpl { + Empty(EmptyNeedle), + TwoWay(TwoWaySearcher), +} + +#[derive(Clone, Debug)] +struct EmptyNeedle { + position: usize, + end: usize, + is_match_fw: bool, + is_match_bw: bool, +} + +impl<'a, 'b> StrSearcher<'a, 'b> { + fn new(haystack: &'a str, needle: &'b str) -> StrSearcher<'a, 'b> { + if needle.is_empty() { + StrSearcher { + haystack: haystack, + needle: needle, + searcher: StrSearcherImpl::Empty(EmptyNeedle { + position: 0, + end: haystack.len(), + is_match_fw: true, + is_match_bw: true, + }), + } + } else { + StrSearcher { + haystack: haystack, + needle: needle, + searcher: StrSearcherImpl::TwoWay( + TwoWaySearcher::new(needle.as_bytes(), haystack.len()) + ), + } + } + } +} + +unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> { + fn haystack(&self) -> &'a str { self.haystack } + + #[inline] + fn next(&mut self) -> SearchStep { + match self.searcher { + StrSearcherImpl::Empty(ref mut searcher) => { + // empty needle rejects every char and matches every empty string between them + let is_match = searcher.is_match_fw; + searcher.is_match_fw = !searcher.is_match_fw; + let pos = searcher.position; + match self.haystack[pos..].chars().next() { + _ if is_match => SearchStep::Match(pos, pos), + None => SearchStep::Done, + Some(ch) => { + searcher.position += ch.len_utf8(); + SearchStep::Reject(pos, searcher.position) + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + // TwoWaySearcher produces valid *Match* indices that split at char boundaries + // as long as it does correct matching and that haystack and needle are + // valid UTF-8 + // *Rejects* from the algorithm can fall on any indices, but we will walk them + // manually to the next character boundary, so that they are utf-8 safe. + if searcher.position == self.haystack.len() { + return SearchStep::Done; + } + let is_long = searcher.memory == usize::MAX; + match searcher.next::(self.haystack.as_bytes(), + self.needle.as_bytes(), + is_long) + { + SearchStep::Reject(a, mut b) => { + // skip to next char boundary + while !self.haystack.is_char_boundary(b) { + b += 1; + } + searcher.position = cmp::max(b, searcher.position); + SearchStep::Reject(a, b) + } + otherwise => otherwise, + } + } + } + } + + #[inline(always)] + fn next_match(&mut self) -> Option<(usize, usize)> { + match self.searcher { + StrSearcherImpl::Empty(..) => { + loop { + match self.next() { + SearchStep::Match(a, b) => return Some((a, b)), + SearchStep::Done => return None, + SearchStep::Reject(..) => { } + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + let is_long = searcher.memory == usize::MAX; + if is_long { + searcher.next::(self.haystack.as_bytes(), + self.needle.as_bytes(), + true) + } else { + searcher.next::(self.haystack.as_bytes(), + self.needle.as_bytes(), + false) + } + } + } + } + +} +unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> { + #[inline] + fn next_back(&mut self) -> SearchStep { + match self.searcher { + StrSearcherImpl::Empty(ref mut searcher) => { + let is_match = searcher.is_match_bw; + searcher.is_match_bw = !searcher.is_match_bw; + let end = searcher.end; + match self.haystack[..end].chars().next_back() { + _ if is_match => SearchStep::Match(end, end), + None => SearchStep::Done, + Some(ch) => { + searcher.end -= ch.len_utf8(); + SearchStep::Reject(searcher.end, end) + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + if searcher.end == 0 { + return SearchStep::Done; + } + match searcher.next_back::(self.haystack.as_bytes(), + self.needle.as_bytes()) + { + SearchStep::Reject(mut a, b) => { + // skip to next char boundary + while !self.haystack.is_char_boundary(a) { + a -= 1; + } + searcher.end = cmp::min(a, searcher.end); + SearchStep::Reject(a, b) + } + otherwise => otherwise, + } + } + } + } + + #[inline] + fn next_match_back(&mut self) -> Option<(usize, usize)> { + match self.searcher { + StrSearcherImpl::Empty(..) => { + loop { + match self.next_back() { + SearchStep::Match(a, b) => return Some((a, b)), + SearchStep::Done => return None, + SearchStep::Reject(..) => { } + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + searcher.next_back::(self.haystack.as_bytes(), + self.needle.as_bytes()) + } + } + } +} + +/// The internal state of an iterator that searches for matches of a substring +/// within a larger string using two-way search +#[derive(Clone, Debug)] +struct TwoWaySearcher { + // constants + crit_pos: usize, + period: usize, + byteset: u64, + + // variables + position: usize, + end: usize, + memory: usize +} + +/* + This is the Two-Way search algorithm, which was introduced in the paper: + Crochemore, M., Perrin, D., 1991, Two-way string-matching, Journal of the ACM 38(3):651-675. + + Here's some background information. + + A *word* is a string of symbols. The *length* of a word should be a familiar + notion, and here we denote it for any word x by |x|. + (We also allow for the possibility of the *empty word*, a word of length zero). + + If x is any non-empty word, then an integer p with 0 < p <= |x| is said to be a + *period* for x iff for all i with 0 <= i <= |x| - p - 1, we have x[i] == x[i+p]. + For example, both 1 and 2 are periods for the string "aa". As another example, + the only period of the string "abcd" is 4. + + We denote by period(x) the *smallest* period of x (provided that x is non-empty). + This is always well-defined since every non-empty word x has at least one period, + |x|. We sometimes call this *the period* of x. + + If u, v and x are words such that x = uv, where uv is the concatenation of u and + v, then we say that (u, v) is a *factorization* of x. + + Let (u, v) be a factorization for a word x. Then if w is a non-empty word such + that both of the following hold + + - either w is a suffix of u or u is a suffix of w + - either w is a prefix of v or v is a prefix of w + + then w is said to be a *repetition* for the factorization (u, v). + + Just to unpack this, there are four possibilities here. Let w = "abc". Then we + might have: + + - w is a suffix of u and w is a prefix of v. ex: ("lolabc", "abcde") + - w is a suffix of u and v is a prefix of w. ex: ("lolabc", "ab") + - u is a suffix of w and w is a prefix of v. ex: ("bc", "abchi") + - u is a suffix of w and v is a prefix of w. ex: ("bc", "a") + + Note that the word vu is a repetition for any factorization (u,v) of x = uv, + so every factorization has at least one repetition. + + If x is a string and (u, v) is a factorization for x, then a *local period* for + (u, v) is an integer r such that there is some word w such that |w| = r and w is + a repetition for (u, v). + + We denote by local_period(u, v) the smallest local period of (u, v). We sometimes + call this *the local period* of (u, v). Provided that x = uv is non-empty, this + is well-defined (because each non-empty word has at least one factorization, as + noted above). + + It can be proven that the following is an equivalent definition of a local period + for a factorization (u, v): any positive integer r such that x[i] == x[i+r] for + all i such that |u| - r <= i <= |u| - 1 and such that both x[i] and x[i+r] are + defined. (i.e. i > 0 and i + r < |x|). + + Using the above reformulation, it is easy to prove that + + 1 <= local_period(u, v) <= period(uv) + + A factorization (u, v) of x such that local_period(u,v) = period(x) is called a + *critical factorization*. + + The algorithm hinges on the following theorem, which is stated without proof: + + **Critical Factorization Theorem** Any word x has at least one critical + factorization (u, v) such that |u| < period(x). + + The purpose of maximal_suffix is to find such a critical factorization. + +*/ +impl TwoWaySearcher { + fn new(needle: &[u8], end: usize) -> TwoWaySearcher { + let (crit_pos_false, period_false) = TwoWaySearcher::maximal_suffix(needle, false); + let (crit_pos_true, period_true) = TwoWaySearcher::maximal_suffix(needle, true); + + let (crit_pos, period) = + if crit_pos_false > crit_pos_true { + (crit_pos_false, period_false) + } else { + (crit_pos_true, period_true) + }; + + // This isn't in the original algorithm, as far as I'm aware. + let byteset = needle.iter() + .fold(0, |a, &b| (1 << ((b & 0x3f) as usize)) | a); + + // A particularly readable explanation of what's going on here can be found + // in Crochemore and Rytter's book "Text Algorithms", ch 13. Specifically + // see the code for "Algorithm CP" on p. 323. + // + // What's going on is we have some critical factorization (u, v) of the + // needle, and we want to determine whether u is a suffix of + // &v[..period]. If it is, we use "Algorithm CP1". Otherwise we use + // "Algorithm CP2", which is optimized for when the period of the needle + // is large. + if &needle[..crit_pos] == &needle[period.. period + crit_pos] { + // short period case + TwoWaySearcher { + crit_pos: crit_pos, + period: period, + byteset: byteset, + + position: 0, + end: end, + memory: 0 + } + } else { + // long period case + // we have an approximation to the actual period, and don't use memory. + TwoWaySearcher { + crit_pos: crit_pos, + period: cmp::max(crit_pos, needle.len() - crit_pos) + 1, + byteset: byteset, + + position: 0, + end: end, + memory: usize::MAX // Dummy value to signify that the period is long + } + } + } + + #[inline(always)] + fn byteset_contains(&self, byte: u8) -> bool { + (self.byteset >> ((byte & 0x3f) as usize)) & 1 != 0 + } + + // One of the main ideas of Two-Way is that we factorize the needle into + // two halves, (u, v), and begin trying to find v in the haystack by scanning + // left to right. If v matches, we try to match u by scanning right to left. + // How far we can jump when we encounter a mismatch is all based on the fact + // that (u, v) is a critical factorization for the needle. + #[inline(always)] + fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool) + -> S::Output + where S: TwoWayStrategy + { + // `next()` uses `self.position` as its cursor + let old_pos = self.position; + 'search: loop { + // Check that we have room to search in + if needle.len() > haystack.len() - self.position { + self.position = haystack.len(); + return S::rejecting(old_pos, self.position); + } + + if S::use_early_reject() && old_pos != self.position { + return S::rejecting(old_pos, self.position); + } + + // Quickly skip by large portions unrelated to our substring + if !self.byteset_contains(haystack[self.position + needle.len() - 1]) { + self.position += needle.len(); + if !long_period { + self.memory = 0; + } + continue 'search; + } + + // See if the right part of the needle matches + let start = if long_period { self.crit_pos } + else { cmp::max(self.crit_pos, self.memory) }; + for i in start..needle.len() { + if needle[i] != haystack[self.position + i] { + self.position += i - self.crit_pos + 1; + if !long_period { + self.memory = 0; + } + continue 'search; + } + } + + // See if the left part of the needle matches + let start = if long_period { 0 } else { self.memory }; + for i in (start..self.crit_pos).rev() { + if needle[i] != haystack[self.position + i] { + self.position += self.period; + if !long_period { + self.memory = needle.len() - self.period; + } + continue 'search; + } + } + + // We have found a match! + let match_pos = self.position; + + // Note: add self.period instead of needle.len() to have overlapping matches + self.position += needle.len(); + if !long_period { + self.memory = 0; // set to needle.len() - self.period for overlapping matches + } + + return S::matching(match_pos, match_pos + needle.len()); + } + } + + // Follows the ideas in `next()`. + // + // All the definitions are completely symmetrical, with period(x) = period(reverse(x)) + // and local_period(u, v) = local_period(reverse(v), reverse(u)), so if (u, v) + // is a critical factorization, so is (reverse(v), reverse(u)). Similarly, + // the "period" stored in self.period is the real period if long_period is + // false, and so is still valid for a reversed needle, and if long_period is + // true, all the algorithm requires is that self.period is less than or + // equal to the real period, which must be true for the forward case anyway. + // + // To search in reverse through the haystack, we search forward through + // a reversed haystack with a reversed needle, and the above paragraph shows + // that the precomputed parameters can be left alone. + #[inline] + fn next_back(&mut self, haystack: &[u8], needle: &[u8]) + -> S::Output + where S: TwoWayStrategy + { + // `next_back()` uses `self.end` as its cursor -- so that `next()` and `next_back()` + // are independent. + let old_end = self.end; + 'search: loop { + // Check that we have room to search in + if needle.len() > self.end { + self.end = 0; + return S::rejecting(0, old_end); + } + + if S::use_early_reject() && old_end != self.end { + return S::rejecting(self.end, old_end); + } + + // Quickly skip by large portions unrelated to our substring + if !self.byteset_contains(haystack[self.end - needle.len()]) { + self.end -= needle.len(); + continue 'search; + } + + // See if the left part of the needle matches + for i in (0..self.crit_pos).rev() { + if needle[i] != haystack[self.end - needle.len() + i] { + self.end -= self.crit_pos - i; + continue 'search; + } + } + + // See if the right part of the needle matches + for i in self.crit_pos..needle.len() { + if needle[i] != haystack[self.end - needle.len() + i] { + self.end -= self.period; + continue 'search; + } + } + + // We have found a match! + let match_pos = self.end - needle.len(); + // Note: sub self.period instead of needle.len() to have overlapping matches + self.end -= needle.len(); + + return S::matching(match_pos, match_pos + needle.len()); + } + } + + // Computes a critical factorization (u, v) of `arr`. + // Specifically, returns (i, p), where i is the starting index of v in some + // critical factorization (u, v) and p = period(v) + #[inline] + fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) { + let mut left: usize = !0; // Corresponds to i in the paper + let mut right = 0; // Corresponds to j in the paper + let mut offset = 1; // Corresponds to k in the paper + let mut period = 1; // Corresponds to p in the paper + + while right + offset < arr.len() { + let a; + let b; + if reversed { + a = arr[left.wrapping_add(offset)]; + b = arr[right + offset]; + } else { + a = arr[right + offset]; + b = arr[left.wrapping_add(offset)]; + } + if a < b { + // Suffix is smaller, period is entire prefix so far. + right += offset; + offset = 1; + period = right.wrapping_sub(left); + } else if a == b { + // Advance through repetition of the current period. + if offset == period { + right += offset; + offset = 1; + } else { + offset += 1; + } + } else { + // Suffix is larger, start over from current location. + left = right; + right += 1; + offset = 1; + period = 1; + } + } + (left.wrapping_add(1), period) + } +} + +// TwoWayStrategy allows the algorithm to either skip non-matches as quickly +// as possible, or to work in a mode where it emits Rejects relatively quickly. +trait TwoWayStrategy { + type Output; + fn use_early_reject() -> bool; + fn rejecting(usize, usize) -> Self::Output; + fn matching(usize, usize) -> Self::Output; +} + +/// Skip to match intervals as quickly as possible +enum MatchOnly { } + +impl TwoWayStrategy for MatchOnly { + type Output = Option<(usize, usize)>; + + #[inline] + fn use_early_reject() -> bool { false } + #[inline] + fn rejecting(_a: usize, _b: usize) -> Self::Output { None } + #[inline] + fn matching(a: usize, b: usize) -> Self::Output { Some((a, b)) } +} + +/// Emit Rejects regularly +enum RejectAndMatch { } + +impl TwoWayStrategy for RejectAndMatch { + type Output = SearchStep; + + #[inline] + fn use_early_reject() -> bool { true } + #[inline] + fn rejecting(a: usize, b: usize) -> Self::Output { SearchStep::Reject(a, b) } + #[inline] + fn matching(a: usize, b: usize) -> Self::Output { SearchStep::Match(a, b) } +} diff --git a/src/libcoretest/fmt/mod.rs b/src/libcoretest/fmt/mod.rs index cdb9c38f027f7..42872589bb01f 100644 --- a/src/libcoretest/fmt/mod.rs +++ b/src/libcoretest/fmt/mod.rs @@ -16,4 +16,6 @@ fn test_format_flags() { // No residual flags left by pointer formatting let p = "".as_ptr(); assert_eq!(format!("{:p} {:x}", p, 16), format!("{:p} 10", p)); + + assert_eq!(format!("{: >3}", 'a'), " a"); } diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index c2b28bd134d47..7ca89cfd0c9cc 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -399,7 +399,7 @@ impl<'a> Parser<'a> { } Some(..) | None => { return &self.input[..0]; } }; - let mut end; + let end; loop { match self.cur.clone().next() { Some((_, c)) if c.is_xid_continue() => { diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 6e01796ad8227..f66811e561adf 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -1322,7 +1322,7 @@ pub mod types { } } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os ="openbsd"))] pub mod os { pub mod common { pub mod posix01 { @@ -1351,7 +1351,7 @@ pub mod types { pub __unused7: *mut c_void, } - #[cfg(target_os = "openbsd")] + #[cfg(any(target_os = "netbsd", target_os="openbsd"))] #[repr(C)] #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: c_int, @@ -4323,7 +4323,7 @@ pub mod consts { } } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] pub mod os { pub mod c95 { use types::os::arch::c95::{c_int, c_uint}; @@ -5568,6 +5568,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "nacl"))] pub mod posix88 { @@ -5584,6 +5585,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "ios", @@ -5602,6 +5604,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "ios", @@ -5889,6 +5892,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "nacl"))] pub mod posix01 { @@ -5901,6 +5905,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "ios", @@ -6019,16 +6024,17 @@ pub mod funcs { } - #[cfg(any(target_os = "windows", - target_os = "linux", - target_os = "android", - target_os = "macos", + #[cfg(any(target_os = "android", + target_os = "bitrig", + target_os = "dragonfly", target_os = "ios", target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", + target_os = "linux", + target_os = "macos", + target_os = "nacl", + target_os = "netbsd", target_os = "openbsd", - target_os = "nacl"))] + target_os = "windows"))] pub mod posix08 { pub mod unistd { } @@ -6115,6 +6121,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub mod bsd44 { use types::common::c95::{c_void}; @@ -6192,6 +6199,7 @@ pub mod funcs { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub mod extra { } diff --git a/src/librand/distributions/range.rs b/src/librand/distributions/range.rs index 4916e305b70e3..dce114d1fc21b 100644 --- a/src/librand/distributions/range.rs +++ b/src/librand/distributions/range.rs @@ -58,6 +58,7 @@ impl IndependentSample for Range { /// The helper trait for types that have a sensible way to sample /// uniformly between two values. This should not be used directly, /// and is only to facilitate `Range`. +#[doc(hidden)] pub trait SampleRange { /// Construct the `Range` object that `sample_range` /// requires. This should not ever be called directly, only via diff --git a/src/librand/lib.rs b/src/librand/lib.rs index ec510b4a5bdfb..2f76aa53f83ae 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -66,6 +66,7 @@ pub mod reseeding; mod rand_impls; /// A type that can be randomly generated using an `Rng`. +#[doc(hidden)] pub trait Rand : Sized { /// Generates a random instance of this type using the specified source of /// randomness. diff --git a/src/librustc/ast_map/mod.rs b/src/librustc/ast_map/mod.rs index 06d87f5333ad3..3205141e604c2 100644 --- a/src/librustc/ast_map/mod.rs +++ b/src/librustc/ast_map/mod.rs @@ -121,7 +121,7 @@ pub enum Node<'ast> { NodeLifetime(&'ast Lifetime), } -/// Represents an entry and its parent Node ID +/// Represents an entry and its parent NodeID. /// The odd layout is to bring down the total size. #[derive(Copy, Debug)] enum MapEntry<'ast> { @@ -179,7 +179,7 @@ impl<'ast> MapEntry<'ast> { } } - fn parent(self) -> Option { + fn parent_node(self) -> Option { Some(match self { EntryItem(id, _) => id, EntryForeignItem(id, _) => id, @@ -283,10 +283,88 @@ impl<'ast> Map<'ast> { self.find_entry(id).and_then(|x| x.to_node()) } - /// Retrieve the parent NodeId for `id`, or `id` itself if no - /// parent is registered in this map. + /// Similar to get_parent, returns the parent node id or id if there is no + /// parent. + /// This function returns the immediate parent in the AST, whereas get_parent + /// returns the enclosing item. Note that this might not be the actual parent + /// node in the AST - some kinds of nodes are not in the map and these will + /// never appear as the parent_node. So you can always walk the parent_nodes + /// from a node to the root of the ast (unless you get the same id back here + /// that can happen if the id is not in the map itself or is just weird). + pub fn get_parent_node(&self, id: NodeId) -> NodeId { + self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id) + } + + /// If there is some error when walking the parents (e.g., a node does not + /// have a parent in the map or a node can't be found), then we return the + /// last good node id we found. Note that reaching the crate root (id == 0), + /// is not an error, since items in the crate module have the crate root as + /// parent. + fn walk_parent_nodes(&self, start_id: NodeId, found: F) -> Result + where F: Fn(&Node<'ast>) -> bool + { + let mut id = start_id; + loop { + let parent_node = self.get_parent_node(id); + if parent_node == 0 { + return Ok(0); + } + if parent_node == id { + return Err(id); + } + + let node = self.find_entry(parent_node); + if node.is_none() { + return Err(id); + } + let node = node.unwrap().to_node(); + match node { + Some(ref node) => { + if found(node) { + return Ok(parent_node); + } + } + None => { + return Err(parent_node); + } + } + id = parent_node; + } + } + + /// Retrieve the NodeId for `id`'s parent item, or `id` itself if no + /// parent item is in this map. The "parent item" is the closest parent node + /// in the AST which is recorded by the map and is an item, either an item + /// in a module, trait, or impl. pub fn get_parent(&self, id: NodeId) -> NodeId { - self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id) + match self.walk_parent_nodes(id, |node| match *node { + NodeItem(_) | + NodeForeignItem(_) | + NodeTraitItem(_) | + NodeImplItem(_) => true, + _ => false, + }) { + Ok(id) => id, + Err(id) => id, + } + } + + /// Returns the nearest enclosing scope. A scope is an item or block. + /// FIXME it is not clear to me that all items qualify as scopes - statics + /// and associated types probably shouldn't, for example. Behaviour in this + /// regard should be expected to be highly unstable. + pub fn get_enclosing_scope(&self, id: NodeId) -> Option { + match self.walk_parent_nodes(id, |node| match *node { + NodeItem(_) | + NodeForeignItem(_) | + NodeTraitItem(_) | + NodeImplItem(_) | + NodeBlock(_) => true, + _ => false, + }) { + Ok(id) => Some(id), + Err(_) => None, + } } pub fn get_parent_did(&self, id: NodeId) -> DefId { @@ -590,15 +668,15 @@ impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> { return None; } self.idx += 1; - let (p, name) = match self.map.find_entry(idx) { - Some(EntryItem(p, n)) => (p, n.name()), - Some(EntryForeignItem(p, n))=> (p, n.name()), - Some(EntryTraitItem(p, n)) => (p, n.name()), - Some(EntryImplItem(p, n)) => (p, n.name()), - Some(EntryVariant(p, n)) => (p, n.name()), + let name = match self.map.find_entry(idx) { + Some(EntryItem(_, n)) => n.name(), + Some(EntryForeignItem(_, n))=> n.name(), + Some(EntryTraitItem(_, n)) => n.name(), + Some(EntryImplItem(_, n)) => n.name(), + Some(EntryVariant(_, n)) => n.name(), _ => continue, }; - if self.matches_names(p, name) { + if self.matches_names(self.map.get_parent(idx), name) { return Some(idx) } } @@ -647,8 +725,7 @@ impl Folder for IdAndSpanUpdater { /// A Visitor that walks over an AST and collects Node's into an AST Map. struct NodeCollector<'ast> { map: Vec>, - /// The node in which we are currently mapping (an item or a method). - parent: NodeId + parent_node: NodeId, } impl<'ast> NodeCollector<'ast> { @@ -662,7 +739,7 @@ impl<'ast> NodeCollector<'ast> { } fn insert(&mut self, id: NodeId, node: Node<'ast>) { - let entry = MapEntry::from_node(self.parent, node); + let entry = MapEntry::from_node(self.parent_node, node); self.insert_entry(id, entry); } @@ -676,8 +753,10 @@ impl<'ast> NodeCollector<'ast> { impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_item(&mut self, i: &'ast Item) { self.insert(i.id, NodeItem(i)); - let parent = self.parent; - self.parent = i.id; + + let parent_node = self.parent_node; + self.parent_node = i.id; + match i.node { ItemImpl(_, _, _, _, _, ref impl_items) => { for ii in impl_items { @@ -727,21 +806,23 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { _ => {} } visit::walk_item(self, i); - self.parent = parent; + self.parent_node = parent_node; } fn visit_trait_item(&mut self, ti: &'ast TraitItem) { - let parent = self.parent; - self.parent = ti.id; + let parent_node = self.parent_node; + self.parent_node = ti.id; visit::walk_trait_item(self, ti); - self.parent = parent; + self.parent_node = parent_node; } fn visit_impl_item(&mut self, ii: &'ast ImplItem) { - let parent = self.parent; - self.parent = ii.id; + let parent_node = self.parent_node; + self.parent_node = ii.id; + visit::walk_impl_item(self, ii); - self.parent = parent; + + self.parent_node = parent_node; } fn visit_pat(&mut self, pat: &'ast Pat) { @@ -750,26 +831,42 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { PatIdent(..) => NodeLocal(pat), _ => NodePat(pat) }); + + let parent_node = self.parent_node; + self.parent_node = pat.id; visit::walk_pat(self, pat); + self.parent_node = parent_node; } fn visit_expr(&mut self, expr: &'ast Expr) { self.insert(expr.id, NodeExpr(expr)); + let parent_node = self.parent_node; + self.parent_node = expr.id; visit::walk_expr(self, expr); + self.parent_node = parent_node; } fn visit_stmt(&mut self, stmt: &'ast Stmt) { - self.insert(ast_util::stmt_id(stmt), NodeStmt(stmt)); + let id = ast_util::stmt_id(stmt); + self.insert(id, NodeStmt(stmt)); + let parent_node = self.parent_node; + self.parent_node = id; visit::walk_stmt(self, stmt); + self.parent_node = parent_node; } fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl, - b: &'ast Block, s: Span, _: NodeId) { + b: &'ast Block, s: Span, id: NodeId) { + let parent_node = self.parent_node; + self.parent_node = id; self.visit_fn_decl(fd); visit::walk_fn(self, fk, fd, b, s); + self.parent_node = parent_node; } fn visit_ty(&mut self, ty: &'ast Ty) { + let parent_node = self.parent_node; + self.parent_node = ty.id; match ty.node { TyBareFn(ref fd) => { self.visit_fn_decl(&*fd.decl); @@ -777,11 +874,15 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { _ => {} } visit::walk_ty(self, ty); + self.parent_node = parent_node; } fn visit_block(&mut self, block: &'ast Block) { self.insert(block.id, NodeBlock(block)); + let parent_node = self.parent_node; + self.parent_node = block.id; visit::walk_block(self, block); + self.parent_node = parent_node; } fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) { @@ -809,7 +910,7 @@ pub fn map_crate<'ast, F: FoldOps>(forest: &'ast mut Forest, fold_ops: F) -> Map let mut collector = NodeCollector { map: vec![], - parent: CRATE_NODE_ID + parent_node: CRATE_NODE_ID, }; collector.insert_entry(CRATE_NODE_ID, RootCrate); visit::walk_crate(&mut collector, &forest.krate); @@ -864,11 +965,11 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, ii: ii }); + let ii_parent_id = fld.new_id(DUMMY_NODE_ID); let mut collector = NodeCollector { map: mem::replace(&mut *map.map.borrow_mut(), vec![]), - parent: fld.new_id(DUMMY_NODE_ID) + parent_node: ii_parent_id, }; - let ii_parent_id = collector.parent; collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent)); visit::walk_inlined_item(&mut collector, &ii_parent.ii); diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 034d3ee1604a0..eb504d03209f6 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -357,7 +357,41 @@ Ensure that the expressions given can be evaluated as the desired integer type. See the FFI section of the Reference for more information about using a custom integer type: -http://doc.rust-lang.org/reference.html#ffi-attributes +https://doc.rust-lang.org/reference.html#ffi-attributes +"##, + +E0109: r##" +You tried to give a type parameter to a type which doesn't need it. Erroneous +code example: + +``` +type X = u32; // error: type parameters are not allowed on this type +``` + +Please check that you used the correct type and recheck its definition. Perhaps +it doesn't need the type parameter. +Example: + +``` +type X = u32; // ok! +``` +"##, + +E0110: r##" +You tried to give a lifetime parameter to a type which doesn't need it. +Erroneous code example: + +``` +type X = u32<'static>; // error: lifetime parameters are not allowed on + // this type +``` + +Please check that you used the correct type and recheck its definition, +perhaps it doesn't need the lifetime parameter. Example: + +``` +type X = u32; // ok! +``` "##, E0133: r##" @@ -374,7 +408,7 @@ fn main() { } ``` -See also http://doc.rust-lang.org/book/unsafe.html +See also https://doc.rust-lang.org/book/unsafe.html "##, E0137: r##" @@ -568,15 +602,47 @@ const Y: u32 = X; E0267: r##" This error indicates the use of a loop keyword (`break` or `continue`) inside a -closure but outside of any loop. Break and continue can be used as normal inside -closures as long as they are also contained within a loop. To halt the execution -of a closure you should instead use a return statement. +closure but outside of any loop. Erroneous code example: + +``` +let w = || { break; }; // error: `break` inside of a closure +``` + +`break` and `continue` keywords can be used as normal inside closures as long as +they are also contained within a loop. To halt the execution of a closure you +should instead use a return statement. Example: + +``` +let w = || { + for _ in 0..10 { + break; + } +}; + +w(); +``` "##, E0268: r##" This error indicates the use of a loop keyword (`break` or `continue`) outside of a loop. Without a loop to break out of or continue in, no sensible action can -be taken. +be taken. Erroneous code example: + +``` +fn some_func() { + break; // error: `break` outside of loop +} +``` + +Please verify that you are using `break` and `continue` only in loops. Example: + +``` +fn some_func() { + for _ in 0..10 { + break; // ok! + } +} +``` "##, E0271: r##" @@ -715,6 +781,54 @@ for v in &vs { ``` "##, +E0277: r##" +You tried to use a type which doesn't implement some trait in a place which +expected that trait. Erroneous code example: + +``` +// here we declare the Foo trait with a bar method +trait Foo { + fn bar(&self); +} + +// we now declare a function which takes an object with Foo trait implemented +// as parameter +fn some_func(foo: T) { + foo.bar(); +} + +fn main() { + // we now call the method with the i32 type, which doesn't implement + // the Foo trait + some_func(5i32); // error: the trait `Foo` is not implemented for the + // type `i32` +} +``` + +In order to fix this error, verify that the type you're using does implement +the trait. Example: + +``` +trait Foo { + fn bar(&self); +} + +fn some_func(foo: T) { + foo.bar(); // we can now use this method since i32 implements the + // Foo trait +} + +// we implement the trait on the i32 type +impl Foo for i32 { + fn bar(&self) {} +} + +fn main() { + some_func(5i32); // ok! +} +``` +"##, + E0282: r##" This error indicates that type inference did not result in one unique possible type, and extra information is required. In most cases this can be provided @@ -1046,6 +1160,42 @@ static mut FOO: Option> = None; // error: mutable statics are not allowed to have destructors static mut BAR: Option> = None; ``` +"##, + +E0398: r##" +In Rust 1.3, the default object lifetime bounds are expected to +change, as described in RFC #1156 [1]. You are getting a warning +because the compiler thinks it is possible that this change will cause +a compilation error in your code. It is possible, though unlikely, +that this is a false alarm. + +The heart of the change is that where `&'a Box` used to +default to `&'a Box`, it now defaults to `&'a +Box` (here, `SomeTrait` is the name of some trait +type). Note that the only types which are affected are references to +boxes, like `&Box` or `&[Box]`. More common +types like `&SomeTrait` or `Box` are unaffected. + +To silence this warning, edit your code to use an explicit bound. +Most of the time, this means that you will want to change the +signature of a function that you are calling. For example, if +the error is reported on a call like `foo(x)`, and `foo` is +defined as follows: + +``` +fn foo(arg: &Box) { ... } +``` + +you might change it to: + +``` +fn foo<'a>(arg: &Box) { ... } +``` + +This explicitly states that you expect the trait object `SomeTrait` to +contain references (with a maximum lifetime of `'a`). + +[1]: https://github.com/rust-lang/rfcs/pull/1156 "## } @@ -1055,10 +1205,8 @@ register_diagnostics! { E0017, E0022, E0038, - E0109, - E0110, - E0134, - E0135, +// E0134, +// E0135, E0136, E0138, E0139, @@ -1071,7 +1219,6 @@ register_diagnostics! { E0274, // rustc_on_unimplemented must have a value E0275, // overflow evaluating requirement E0276, // requirement appears on impl method but not on corresponding trait method - E0277, // trait is not implemented for type E0278, // requirement is not satisfied E0279, // requirement is not satisfied E0280, // requirement is not satisfied diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c19ba19f5b76b..e4e7459f8c605 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -61,6 +61,8 @@ #![feature(str_match_indices)] #![feature(vec_push_all)] #![feature(wrapping)] +#![feature(cell_extras)] +#![feature(page_size)] #![cfg_attr(test, feature(test))] #![allow(trivial_casts)] diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index b217eabec6e6a..b677e7b85703b 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -23,7 +23,6 @@ use metadata::cstore; use metadata::decoder; use metadata::tyencode; use middle::def; -use middle::ty::lookup_item_type; use middle::ty::{self, Ty}; use middle::stability; use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; @@ -133,7 +132,7 @@ pub fn def_to_string(did: DefId) -> String { fn encode_item_variances(rbml_w: &mut Encoder, ecx: &EncodeContext, id: NodeId) { - let v = ty::item_variances(ecx.tcx, ast_util::local_def(id)); + let v = ecx.tcx.item_variances(ast_util::local_def(id)); rbml_w.start_tag(tag_item_variances); v.encode(rbml_w); rbml_w.end_tag(); @@ -144,8 +143,8 @@ fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, id: ast::NodeId) { encode_bounds_and_type(rbml_w, ecx, - &ty::lookup_item_type(ecx.tcx, local_def(id)), - &ty::lookup_predicates(ecx.tcx, local_def(id))); + &ecx.tcx.lookup_item_type(local_def(id)), + &ecx.tcx.lookup_predicates(local_def(id))); } fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, @@ -293,8 +292,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext, let mut disr_val = 0; let mut i = 0; - let vi = ty::enum_variants(ecx.tcx, - DefId { krate: ast::LOCAL_CRATE, node: id }); + let vi = ecx.tcx.enum_variants(local_def(id)); for variant in variants { let def_id = local_def(variant.node.id); index.push(entry { @@ -319,7 +317,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext, match variant.node.kind { ast::TupleVariantKind(_) => {}, ast::StructVariantKind(_) => { - let fields = ty::lookup_struct_fields(ecx.tcx, def_id); + let fields = ecx.tcx.lookup_struct_fields(def_id); let idx = encode_info_for_struct(ecx, rbml_w, &fields[..], @@ -328,9 +326,10 @@ fn encode_enum_variant_info(ecx: &EncodeContext, encode_index(rbml_w, idx, write_i64); } } - if (*vi)[i].disr_val != disr_val { - encode_disr_val(ecx, rbml_w, (*vi)[i].disr_val); - disr_val = (*vi)[i].disr_val; + let specified_disr_val = vi[i].disr_val; + if specified_disr_val != disr_val { + encode_disr_val(ecx, rbml_w, specified_disr_val); + disr_val = specified_disr_val; } encode_bounds_and_type_for_item(rbml_w, ecx, def_id.local_id()); @@ -379,9 +378,7 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext, Some(implementations) => { for base_impl_did in implementations.iter() { for &method_did in impl_items.get(base_impl_did).unwrap() { - let impl_item = ty::impl_or_trait_item( - ecx.tcx, - method_did.def_id()); + let impl_item = ecx.tcx.impl_or_trait_item(method_did.def_id()); if let ty::MethodTraitItem(ref m) = impl_item { encode_reexported_static_method(rbml_w, exp, @@ -875,7 +872,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, if let Some(impl_item) = impl_item_opt { if let ast::MethodImplItem(ref sig, _) = impl_item.node { encode_attributes(rbml_w, &impl_item.attrs); - let scheme = ty::lookup_item_type(ecx.tcx, m.def_id); + let scheme = ecx.tcx.lookup_item_type(m.def_id); let any_types = !scheme.generics.types.is_empty(); let needs_inline = any_types || is_default_impl || attr::requests_inline(&impl_item.attrs); @@ -923,7 +920,7 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_attributes(rbml_w, &ii.attrs); } else { encode_predicates(rbml_w, ecx, - &ty::lookup_predicates(ecx.tcx, associated_type.def_id), + &ecx.tcx.lookup_predicates(associated_type.def_id), tag_item_generics); } @@ -995,7 +992,7 @@ fn encode_extension_implementations(ecx: &EncodeContext, rbml_w: &mut Encoder, trait_def_id: DefId) { assert!(ast_util::is_local(trait_def_id)); - let def = ty::lookup_trait_def(ecx.tcx, trait_def_id); + let def = ecx.tcx.lookup_trait_def(trait_def_id); def.for_each_impl(ecx.tcx, |impl_def_id| { rbml_w.start_tag(tag_items_data_item_extension_impl); @@ -1161,7 +1158,7 @@ fn encode_info_for_item(ecx: &EncodeContext, index); } ast::ItemStruct(ref struct_def, _) => { - let fields = ty::lookup_struct_fields(tcx, def_id); + let fields = tcx.lookup_struct_fields(def_id); /* First, encode the fields These come first because we need to write them to make @@ -1220,7 +1217,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_name(rbml_w, item.ident.name); encode_unsafety(rbml_w, unsafety); - let trait_ref = ty::impl_trait_ref(tcx, local_def(item.id)).unwrap(); + let trait_ref = tcx.impl_trait_ref(local_def(item.id)).unwrap(); encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); rbml_w.end_tag(); } @@ -1274,7 +1271,7 @@ fn encode_info_for_item(ecx: &EncodeContext, } rbml_w.end_tag(); } - if let Some(trait_ref) = ty::impl_trait_ref(tcx, local_def(item.id)) { + if let Some(trait_ref) = tcx.impl_trait_ref(local_def(item.id)) { encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); } encode_path(rbml_w, path.clone()); @@ -1298,7 +1295,7 @@ fn encode_info_for_item(ecx: &EncodeContext, pos: rbml_w.mark_stable_position(), }); - match ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()) { + match tcx.impl_or_trait_item(trait_item_def_id.def_id()) { ty::ConstTraitItem(ref associated_const) => { encode_info_for_associated_const(ecx, rbml_w, @@ -1333,22 +1330,22 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_def_id(rbml_w, def_id); encode_family(rbml_w, 'I'); encode_item_variances(rbml_w, ecx, item.id); - let trait_def = ty::lookup_trait_def(tcx, def_id); - let trait_predicates = ty::lookup_predicates(tcx, def_id); + let trait_def = tcx.lookup_trait_def(def_id); + let trait_predicates = tcx.lookup_predicates(def_id); encode_unsafety(rbml_w, trait_def.unsafety); encode_paren_sugar(rbml_w, trait_def.paren_sugar); - encode_defaulted(rbml_w, ty::trait_has_default_impl(tcx, def_id)); + encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id)); encode_associated_type_names(rbml_w, &trait_def.associated_type_names); encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates, tag_item_generics); - encode_predicates(rbml_w, ecx, &ty::lookup_super_predicates(tcx, def_id), + encode_predicates(rbml_w, ecx, &tcx.lookup_super_predicates(def_id), tag_item_super_predicates); encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); encode_name(rbml_w, item.ident.name); encode_attributes(rbml_w, &item.attrs); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); - for &method_def_id in ty::trait_item_def_ids(tcx, def_id).iter() { + for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { rbml_w.start_tag(tag_item_trait_item); match method_def_id { ty::ConstTraitItemId(const_def_id) => { @@ -1380,7 +1377,7 @@ fn encode_info_for_item(ecx: &EncodeContext, rbml_w.end_tag(); // Now output the trait item info for each trait item. - let r = ty::trait_item_def_ids(tcx, def_id); + let r = tcx.trait_item_def_ids(def_id); for (i, &item_def_id) in r.iter().enumerate() { assert_eq!(item_def_id.def_id().krate, ast::LOCAL_CRATE); @@ -1397,7 +1394,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_stability(rbml_w, stab); let trait_item_type = - ty::impl_or_trait_item(tcx, item_def_id.def_id()); + tcx.impl_or_trait_item(item_def_id.def_id()); let is_nonstatic_method; match trait_item_type { ty::ConstTraitItem(associated_const) => { @@ -1454,6 +1451,10 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_item_sort(rbml_w, 't'); encode_family(rbml_w, 'y'); + if let Some(ty) = associated_type.ty { + encode_type(ecx, rbml_w, ty); + } + is_nonstatic_method = false; } } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 3907b0624b42e..61fce699dd555 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -21,7 +21,7 @@ pub use self::DefIdSource::*; use middle::region; use middle::subst; use middle::subst::VecPerParamSpace; -use middle::ty::{self, AsPredicate, Ty}; +use middle::ty::{self, ToPredicate, Ty, HasTypeFlags}; use std::str; use syntax::abi; @@ -471,14 +471,14 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w let def = parse_def_(st, NominalType, conv); let substs = parse_substs_(st, conv); assert_eq!(next(st), ']'); - return ty::mk_enum(tcx, def, st.tcx.mk_substs(substs)); + return tcx.mk_enum(def, st.tcx.mk_substs(substs)); } 'x' => { assert_eq!(next(st), '['); let trait_ref = ty::Binder(parse_trait_ref_(st, conv)); let bounds = parse_existential_bounds_(st, conv); assert_eq!(next(st), ']'); - return ty::mk_trait(tcx, trait_ref, bounds); + return tcx.mk_trait(trait_ref, bounds); } 'p' => { assert_eq!(next(st), '['); @@ -487,38 +487,38 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w let space = parse_param_space(st); assert_eq!(next(st), '|'); let name = token::intern(&parse_str(st, ']')); - return ty::mk_param(tcx, space, index, name); + return tcx.mk_param(space, index, name); } - '~' => return ty::mk_uniq(tcx, parse_ty_(st, conv)), - '*' => return ty::mk_ptr(tcx, parse_mt_(st, conv)), + '~' => return tcx.mk_box(parse_ty_(st, conv)), + '*' => return tcx.mk_ptr(parse_mt_(st, conv)), '&' => { let r = parse_region_(st, conv); let mt = parse_mt_(st, conv); - return ty::mk_rptr(tcx, tcx.mk_region(r), mt); + return tcx.mk_ref(tcx.mk_region(r), mt); } 'V' => { let t = parse_ty_(st, conv); - let sz = parse_size(st); - return ty::mk_vec(tcx, t, sz); + return match parse_size(st) { + Some(n) => tcx.mk_array(t, n), + None => tcx.mk_slice(t) + }; } 'v' => { - return ty::mk_str(tcx); + return tcx.mk_str(); } 'T' => { assert_eq!(next(st), '['); let mut params = Vec::new(); while peek(st) != ']' { params.push(parse_ty_(st, conv)); } st.pos = st.pos + 1; - return ty::mk_tup(tcx, params); + return tcx.mk_tup(params); } 'F' => { let def_id = parse_def_(st, NominalType, conv); - return ty::mk_bare_fn(tcx, Some(def_id), - tcx.mk_bare_fn(parse_bare_fn_ty_(st, conv))); + return tcx.mk_fn(Some(def_id), tcx.mk_bare_fn(parse_bare_fn_ty_(st, conv))); } 'G' => { - return ty::mk_bare_fn(tcx, None, - tcx.mk_bare_fn(parse_bare_fn_ty_(st, conv))); + return tcx.mk_fn(None, tcx.mk_bare_fn(parse_bare_fn_ty_(st, conv))); } '#' => { let pos = parse_hex(st); @@ -534,7 +534,7 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w // If there is a closure buried in the type some where, then we // need to re-convert any def ids (see case 'k', below). That means // we can't reuse the cached version. - if !ty::type_has_ty_closure(tt) { + if !tt.has_closure_types() { return tt; } } @@ -558,20 +558,20 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w let did = parse_def_(st, NominalType, conv); let substs = parse_substs_(st, conv); assert_eq!(next(st), ']'); - return ty::mk_struct(st.tcx, did, st.tcx.mk_substs(substs)); + return st.tcx.mk_struct(did, st.tcx.mk_substs(substs)); } 'k' => { assert_eq!(next(st), '['); let did = parse_def_(st, ClosureSource, conv); let substs = parse_substs_(st, conv); assert_eq!(next(st), ']'); - return ty::mk_closure(st.tcx, did, st.tcx.mk_substs(substs)); + return st.tcx.mk_closure(did, st.tcx.mk_substs(substs)); } 'P' => { assert_eq!(next(st), '['); let trait_ref = parse_trait_ref_(st, conv); let name = token::intern(&parse_str(st, ']')); - return ty::mk_projection(tcx, trait_ref, name); + return tcx.mk_projection(trait_ref, name); } 'e' => { return tcx.types.err; @@ -775,14 +775,14 @@ fn parse_predicate_<'a,'tcx, F>(st: &mut PState<'a, 'tcx>, F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { match next(st) { - 't' => ty::Binder(parse_trait_ref_(st, conv)).as_predicate(), + 't' => ty::Binder(parse_trait_ref_(st, conv)).to_predicate(), 'e' => ty::Binder(ty::EquatePredicate(parse_ty_(st, conv), - parse_ty_(st, conv))).as_predicate(), + parse_ty_(st, conv))).to_predicate(), 'r' => ty::Binder(ty::OutlivesPredicate(parse_region_(st, conv), - parse_region_(st, conv))).as_predicate(), + parse_region_(st, conv))).to_predicate(), 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty_(st, conv), - parse_region_(st, conv))).as_predicate(), - 'p' => ty::Binder(parse_projection_predicate_(st, conv)).as_predicate(), + parse_region_(st, conv))).to_predicate(), + 'p' => ty::Binder(parse_projection_predicate_(st, conv)).to_predicate(), c => panic!("Encountered invalid character in metadata: {}", c) } } @@ -843,15 +843,15 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) fn parse_object_lifetime_default<'a,'tcx, F>(st: &mut PState<'a,'tcx>, conv: &mut F) - -> Option + -> ty::ObjectLifetimeDefault where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { match next(st) { - 'n' => None, - 'a' => Some(ty::ObjectLifetimeDefault::Ambiguous), + 'a' => ty::ObjectLifetimeDefault::Ambiguous, + 'b' => ty::ObjectLifetimeDefault::BaseDefault, 's' => { let region = parse_region_(st, conv); - Some(ty::ObjectLifetimeDefault::Specific(region)) + ty::ObjectLifetimeDefault::Specific(region) } _ => panic!("parse_object_lifetime_default: bad input") } @@ -887,9 +887,16 @@ fn parse_existential_bounds_<'a,'tcx, F>(st: &mut PState<'a,'tcx>, } } + let region_bound_will_change = match next(st) { + 'y' => true, + 'n' => false, + c => panic!("parse_ty: expected y/n not '{}'", c) + }; + return ty::ExistentialBounds { region_bound: region_bound, builtin_bounds: builtin_bounds, - projection_bounds: projection_bounds }; + projection_bounds: projection_bounds, + region_bound_will_change: region_bound_will_change }; } fn parse_builtin_bounds(st: &mut PState, mut _conv: F) -> ty::BuiltinBounds where diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index c078b62dd2d8a..441f9f102aea9 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -390,6 +390,8 @@ pub fn enc_existential_bounds<'a,'tcx>(w: &mut Encoder, } mywrite!(w, "."); + + mywrite!(w, "{}", if bs.region_bound_will_change {'y'} else {'n'}); } pub fn enc_region_bounds<'a, 'tcx>(w: &mut Encoder, @@ -414,12 +416,12 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, - default: Option) + default: ty::ObjectLifetimeDefault) { match default { - None => mywrite!(w, "n"), - Some(ty::ObjectLifetimeDefault::Ambiguous) => mywrite!(w, "a"), - Some(ty::ObjectLifetimeDefault::Specific(r)) => { + ty::ObjectLifetimeDefault::Ambiguous => mywrite!(w, "a"), + ty::ObjectLifetimeDefault::BaseDefault => mywrite!(w, "b"), + ty::ObjectLifetimeDefault::Specific(r) => { mywrite!(w, "s"); enc_region(w, cx, r); } diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index 33d37b285890a..fb0131f258d43 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -49,10 +49,10 @@ pub fn prim_ty_to_ty<'tcx>(tcx: &ty::ctxt<'tcx>, match nty { ast::TyBool => tcx.types.bool, ast::TyChar => tcx.types.char, - ast::TyInt(it) => ty::mk_mach_int(tcx, it), - ast::TyUint(uit) => ty::mk_mach_uint(tcx, uit), - ast::TyFloat(ft) => ty::mk_mach_float(tcx, ft), - ast::TyStr => ty::mk_str(tcx) + ast::TyInt(it) => tcx.mk_mach_int(it), + ast::TyUint(uit) => tcx.mk_mach_uint(uit), + ast::TyFloat(ft) => tcx.mk_mach_float(ft), + ast::TyStr => tcx.mk_str() } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 21e2ad198810e..7c76f4fe289df 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -26,11 +26,10 @@ use metadata::tydecode::{RegionParameter, ClosureSource}; use metadata::tyencode; use middle::cast; use middle::check_const::ConstQualif; -use middle::mem_categorization::Typer; use middle::privacy::{AllPublic, LastMod}; use middle::subst; use middle::subst::VecPerParamSpace; -use middle::ty::{self, Ty, MethodCall, MethodCallee, MethodOrigin}; +use middle::ty::{self, Ty}; use syntax::{ast, ast_util, codemap, fold}; use syntax::codemap::Span; @@ -601,21 +600,21 @@ impl tr for ty::UpvarCapture { trait read_method_callee_helper<'tcx> { fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> (u32, MethodCallee<'tcx>); + -> (u32, ty::MethodCallee<'tcx>); } fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, autoderef: u32, - method: &MethodCallee<'tcx>) { + method: &ty::MethodCallee<'tcx>) { use serialize::Encoder; rbml_w.emit_struct("MethodCallee", 4, |rbml_w| { rbml_w.emit_struct_field("autoderef", 0, |rbml_w| { autoderef.encode(rbml_w) }); - rbml_w.emit_struct_field("origin", 1, |rbml_w| { - Ok(rbml_w.emit_method_origin(ecx, &method.origin)) + rbml_w.emit_struct_field("def_id", 1, |rbml_w| { + Ok(rbml_w.emit_def_id(method.def_id)) }); rbml_w.emit_struct_field("ty", 2, |rbml_w| { Ok(rbml_w.emit_ty(ecx, method.ty)) @@ -628,21 +627,20 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> (u32, MethodCallee<'tcx>) { + -> (u32, ty::MethodCallee<'tcx>) { self.read_struct("MethodCallee", 4, |this| { - let autoderef = this.read_struct_field("autoderef", 0, |this| { - Decodable::decode(this) - }).unwrap(); - Ok((autoderef, MethodCallee { - origin: this.read_struct_field("origin", 1, |this| { - Ok(this.read_method_origin(dcx)) + let autoderef = this.read_struct_field("autoderef", 0, + Decodable::decode).unwrap(); + Ok((autoderef, ty::MethodCallee { + def_id: this.read_struct_field("def_id", 1, |this| { + Ok(this.read_def_id(dcx)) }).unwrap(), ty: this.read_struct_field("ty", 2, |this| { Ok(this.read_ty(dcx)) }).unwrap(), substs: this.read_struct_field("substs", 3, |this| { - Ok(this.read_substs(dcx)) + Ok(dcx.tcx.mk_substs(this.read_substs(dcx))) }).unwrap() })) }).unwrap() @@ -708,9 +706,6 @@ impl<'a, 'tcx> get_ty_str_ctxt<'tcx> for e::EncodeContext<'a, 'tcx> { trait rbml_writer_helpers<'tcx> { fn emit_closure_type<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, closure_type: &ty::ClosureTy<'tcx>); - fn emit_method_origin<'a>(&mut self, - ecx: &e::EncodeContext<'a, 'tcx>, - method_origin: &ty::MethodOrigin<'tcx>); fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>); fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]); fn emit_type_param_def<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, @@ -742,73 +737,6 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { }); } - fn emit_method_origin<'b>(&mut self, - ecx: &e::EncodeContext<'b, 'tcx>, - method_origin: &ty::MethodOrigin<'tcx>) - { - use serialize::Encoder; - - self.emit_enum("MethodOrigin", |this| { - match *method_origin { - ty::MethodStatic(def_id) => { - this.emit_enum_variant("MethodStatic", 0, 1, |this| { - Ok(this.emit_def_id(def_id)) - }) - } - - ty::MethodStaticClosure(def_id) => { - this.emit_enum_variant("MethodStaticClosure", 1, 1, |this| { - Ok(this.emit_def_id(def_id)) - }) - } - - ty::MethodTypeParam(ref p) => { - this.emit_enum_variant("MethodTypeParam", 2, 1, |this| { - this.emit_struct("MethodParam", 2, |this| { - try!(this.emit_struct_field("trait_ref", 0, |this| { - Ok(this.emit_trait_ref(ecx, &p.trait_ref)) - })); - try!(this.emit_struct_field("method_num", 0, |this| { - this.emit_uint(p.method_num) - })); - try!(this.emit_struct_field("impl_def_id", 0, |this| { - this.emit_option(|this| { - match p.impl_def_id { - None => this.emit_option_none(), - Some(did) => this.emit_option_some(|this| { - Ok(this.emit_def_id(did)) - }) - } - }) - })); - Ok(()) - }) - }) - } - - ty::MethodTraitObject(ref o) => { - this.emit_enum_variant("MethodTraitObject", 3, 1, |this| { - this.emit_struct("MethodObject", 2, |this| { - try!(this.emit_struct_field("trait_ref", 0, |this| { - Ok(this.emit_trait_ref(ecx, &o.trait_ref)) - })); - try!(this.emit_struct_field("object_trait_id", 0, |this| { - Ok(this.emit_def_id(o.object_trait_id)) - })); - try!(this.emit_struct_field("method_num", 0, |this| { - this.emit_uint(o.method_num) - })); - try!(this.emit_struct_field("vtable_index", 0, |this| { - this.emit_uint(o.vtable_index) - })); - Ok(()) - }) - }) - } - } - }); - } - fn emit_ty<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, ty: Ty<'tcx>) { self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty))); } @@ -1027,7 +955,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) } - if let Some(item_substs) = tcx.item_substs.borrow().get(&id) { + if let Some(item_substs) = tcx.tables.borrow().item_substs.get(&id) { rbml_w.tag(c::tag_table_item_subst, |rbml_w| { rbml_w.id(id); rbml_w.emit_substs(ecx, &item_substs.substs); @@ -1051,7 +979,12 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, var_id: var_id, closure_expr_id: id }; - let upvar_capture = tcx.upvar_capture_map.borrow().get(&upvar_id).unwrap().clone(); + let upvar_capture = tcx.tables + .borrow() + .upvar_capture_map + .get(&upvar_id) + .unwrap() + .clone(); var_id.encode(rbml_w); upvar_capture.encode(rbml_w); }) @@ -1073,20 +1006,20 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) } - let method_call = MethodCall::expr(id); - if let Some(method) = tcx.method_map.borrow().get(&method_call) { + let method_call = ty::MethodCall::expr(id); + if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { rbml_w.tag(c::tag_table_method_map, |rbml_w| { rbml_w.id(id); encode_method_callee(ecx, rbml_w, method_call.autoderef, method) }) } - if let Some(adjustment) = tcx.adjustments.borrow().get(&id) { + if let Some(adjustment) = tcx.tables.borrow().adjustments.get(&id) { match *adjustment { ty::AdjustDerefRef(ref adj) => { for autoderef in 0..adj.autoderefs { - let method_call = MethodCall::autoderef(id, autoderef as u32); - if let Some(method) = tcx.method_map.borrow().get(&method_call) { + let method_call = ty::MethodCall::autoderef(id, autoderef as u32); + if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { rbml_w.tag(c::tag_table_method_map, |rbml_w| { rbml_w.id(id); encode_method_callee(ecx, rbml_w, @@ -1104,14 +1037,14 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) } - if let Some(closure_type) = tcx.closure_tys.borrow().get(&ast_util::local_def(id)) { + if let Some(closure_type) = tcx.tables.borrow().closure_tys.get(&ast_util::local_def(id)) { rbml_w.tag(c::tag_table_closure_tys, |rbml_w| { rbml_w.id(id); rbml_w.emit_closure_type(ecx, closure_type); }) } - if let Some(closure_kind) = tcx.closure_kinds.borrow().get(&ast_util::local_def(id)) { + if let Some(closure_kind) = tcx.tables.borrow().closure_kinds.get(&ast_util::local_def(id)) { rbml_w.tag(c::tag_table_closure_kinds, |rbml_w| { rbml_w.id(id); encode_closure_kind(rbml_w, *closure_kind) @@ -1146,8 +1079,6 @@ impl<'a> doc_decoder_helpers for rbml::Doc<'a> { } trait rbml_decoder_decoder_helpers<'tcx> { - fn read_method_origin<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::MethodOrigin<'tcx>; fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>; fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec>; fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1231,88 +1162,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap() } - fn read_method_origin<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::MethodOrigin<'tcx> - { - self.read_enum("MethodOrigin", |this| { - let variants = &["MethodStatic", "MethodStaticClosure", - "MethodTypeParam", "MethodTraitObject"]; - this.read_enum_variant(variants, |this, i| { - Ok(match i { - 0 => { - let def_id = this.read_def_id(dcx); - ty::MethodStatic(def_id) - } - - 1 => { - let def_id = this.read_def_id(dcx); - ty::MethodStaticClosure(def_id) - } - - 2 => { - this.read_struct("MethodTypeParam", 2, |this| { - Ok(ty::MethodTypeParam( - ty::MethodParam { - trait_ref: { - this.read_struct_field("trait_ref", 0, |this| { - Ok(this.read_trait_ref(dcx)) - }).unwrap() - }, - method_num: { - this.read_struct_field("method_num", 1, |this| { - this.read_uint() - }).unwrap() - }, - impl_def_id: { - this.read_struct_field("impl_def_id", 2, |this| { - this.read_option(|this, b| { - if b { - Ok(Some(this.read_def_id(dcx))) - } else { - Ok(None) - } - }) - }).unwrap() - } - })) - }).unwrap() - } - - 3 => { - this.read_struct("MethodTraitObject", 2, |this| { - Ok(ty::MethodTraitObject( - ty::MethodObject { - trait_ref: { - this.read_struct_field("trait_ref", 0, |this| { - Ok(this.read_trait_ref(dcx)) - }).unwrap() - }, - object_trait_id: { - this.read_struct_field("object_trait_id", 1, |this| { - Ok(this.read_def_id(dcx)) - }).unwrap() - }, - method_num: { - this.read_struct_field("method_num", 2, |this| { - this.read_uint() - }).unwrap() - }, - vtable_index: { - this.read_struct_field("vtable_index", 3, |this| { - this.read_uint() - }).unwrap() - }, - })) - }).unwrap() - } - - _ => panic!("..") - }) - }) - }).unwrap() - } - - fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode @@ -1630,7 +1479,7 @@ fn decode_side_tables(dcx: &DecodeContext, let item_substs = ty::ItemSubsts { substs: val_dsr.read_substs(dcx) }; - dcx.tcx.item_substs.borrow_mut().insert( + dcx.tcx.tables.borrow_mut().item_substs.insert( id, item_substs); } c::tag_table_freevars => { @@ -1646,12 +1495,12 @@ fn decode_side_tables(dcx: &DecodeContext, closure_expr_id: id }; let ub: ty::UpvarCapture = Decodable::decode(val_dsr).unwrap(); - dcx.tcx.upvar_capture_map.borrow_mut().insert(upvar_id, ub.tr(dcx)); + dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub.tr(dcx)); } c::tag_table_tcache => { let type_scheme = val_dsr.read_type_scheme(dcx); let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id }; - dcx.tcx.tcache.borrow_mut().insert(lid, type_scheme); + dcx.tcx.register_item_type(lid, type_scheme); } c::tag_table_param_defs => { let bounds = val_dsr.read_type_param_def(dcx); @@ -1659,26 +1508,26 @@ fn decode_side_tables(dcx: &DecodeContext, } c::tag_table_method_map => { let (autoderef, method) = val_dsr.read_method_callee(dcx); - let method_call = MethodCall { + let method_call = ty::MethodCall { expr_id: id, autoderef: autoderef }; - dcx.tcx.method_map.borrow_mut().insert(method_call, method); + dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method); } c::tag_table_adjustments => { let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(dcx); - dcx.tcx.adjustments.borrow_mut().insert(id, adj); + dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj); } c::tag_table_closure_tys => { let closure_ty = val_dsr.read_closure_ty(dcx); - dcx.tcx.closure_tys.borrow_mut().insert(ast_util::local_def(id), + dcx.tcx.tables.borrow_mut().closure_tys.insert(ast_util::local_def(id), closure_ty); } c::tag_table_closure_kinds => { let closure_kind = val_dsr.read_closure_kind(dcx); - dcx.tcx.closure_kinds.borrow_mut().insert(ast_util::local_def(id), + dcx.tcx.tables.borrow_mut().closure_kinds.insert(ast_util::local_def(id), closure_kind); } c::tag_table_cast_kinds => { diff --git a/src/librustc/middle/cast.rs b/src/librustc/middle/cast.rs index 34088d5f13ee7..ec1fd67616b81 100644 --- a/src/librustc/middle/cast.rs +++ b/src/librustc/middle/cast.rs @@ -66,8 +66,8 @@ impl<'tcx> CastTy<'tcx> { ty::TyInt(_) => Some(CastTy::Int(IntTy::I)), ty::TyUint(u) => Some(CastTy::Int(IntTy::U(u))), ty::TyFloat(_) => Some(CastTy::Float), - ty::TyEnum(..) if ty::type_is_c_like_enum( - tcx, t) => Some(CastTy::Int(IntTy::CEnum)), + ty::TyEnum(..) if t.is_c_like_enum(tcx) => + Some(CastTy::Int(IntTy::CEnum)), ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)), ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)), ty::TyBareFn(..) => Some(CastTy::FnPtr), diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index e782a03176d67..7d62b6ff90040 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -411,14 +411,14 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { func_or_rcvr: &ast::Expr, args: I) -> CFGIndex { let method_call = ty::MethodCall::expr(call_expr.id); - let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().get(&method_call) { + let fn_ty = match self.tcx.tables.borrow().method_map.get(&method_call) { Some(method) => method.ty, - None => ty::expr_ty_adjusted(self.tcx, func_or_rcvr) - }); + None => self.tcx.expr_ty_adjusted(func_or_rcvr) + }; let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); let ret = self.straightline(call_expr, func_or_rcvr_exit, args); - if return_ty.diverges() { + if fn_ty.fn_ret().diverges() { self.add_unreachable_node() } else { ret @@ -634,6 +634,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn is_method_call(&self, expr: &ast::Expr) -> bool { let method_call = ty::MethodCall::expr(expr.id); - self.tcx.method_map.borrow().contains_key(&method_call) + self.tcx.tables.borrow().method_map.contains_key(&method_call) } } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 8af6946d3c3b1..b5c78340d022d 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -110,14 +110,16 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { } fn with_euv<'b, F, R>(&'b mut self, item_id: Option, f: F) -> R where - F: for<'t> FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'tcx, - ty::ParameterEnvironment<'a, 'tcx>>) -> R, + F: for<'t> FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'b, 'tcx>) -> R, { let param_env = match item_id { Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id), - None => ty::empty_parameter_environment(self.tcx) + None => self.tcx.empty_parameter_environment() }; - f(&mut euv::ExprUseVisitor::new(self, ¶m_env)) + + let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env), false); + + f(&mut euv::ExprUseVisitor::new(self, &infcx)) } fn global_expr(&mut self, mode: Mode, expr: &ast::Expr) -> ConstQualif { @@ -231,7 +233,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { fn_like.id()); self.add_qualif(qualif); - if ty::type_contents(self.tcx, ret_ty).interior_unsafe() { + if ret_ty.type_contents(self.tcx).interior_unsafe() { self.add_qualif(ConstQualif::MUTABLE_MEM); } @@ -266,8 +268,8 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { } fn check_static_mut_type(&self, e: &ast::Expr) { - let node_ty = ty::node_id_to_type(self.tcx, e.id); - let tcontents = ty::type_contents(self.tcx, node_ty); + let node_ty = self.tcx.node_id_to_type(e.id); + let tcontents = node_ty.type_contents(self.tcx); let suffix = if tcontents.has_dtor() { "destructors" @@ -282,13 +284,12 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { } fn check_static_type(&self, e: &ast::Expr) { - let ty = ty::node_id_to_type(self.tcx, e.id); - let infcx = infer::new_infer_ctxt(self.tcx); - let mut fulfill_cx = traits::FulfillmentContext::new(false); + let ty = self.tcx.node_id_to_type(e.id); + let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false); let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic); + let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut(); fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause); - let env = ty::empty_parameter_environment(self.tcx); - match fulfill_cx.select_all_or_error(&infcx, &env) { + match fulfill_cx.select_all_or_error(&infcx) { Ok(()) => { }, Err(ref errors) => { traits::report_fulfillment_errors(&infcx, errors); @@ -402,7 +403,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { let mut outer = self.qualif; self.qualif = ConstQualif::empty(); - let node_ty = ty::node_id_to_type(self.tcx, ex.id); + let node_ty = self.tcx.node_id_to_type(ex.id); check_expr(self, ex, node_ty); // Special-case some expressions to avoid certain flags bubbling up. @@ -479,7 +480,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { // initializer values (very bad). // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has // propagated from another error, so erroring again would be just noise. - let tc = ty::type_contents(self.tcx, node_ty); + let tc = node_ty.type_contents(self.tcx); if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() { outer = outer | ConstQualif::NOT_CONST; if self.mode != Mode::Var { @@ -529,7 +530,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &ast::Expr, node_ty: Ty<'tcx>) { match node_ty.sty { ty::TyStruct(did, _) | - ty::TyEnum(did, _) if ty::has_dtor(v.tcx, did) => { + ty::TyEnum(did, _) if v.tcx.has_dtor(did) => { v.add_qualif(ConstQualif::NEEDS_DROP); if v.mode != Mode::Var { v.tcx.sess.span_err(e.span, @@ -544,7 +545,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, match e.node { ast::ExprUnary(..) | ast::ExprBinary(..) | - ast::ExprIndex(..) if v.tcx.method_map.borrow().contains_key(&method_call) => { + ast::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => { v.add_qualif(ConstQualif::NOT_CONST); if v.mode != Mode::Var { span_err!(v.tcx.sess, e.span, E0011, @@ -560,7 +561,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } } ast::ExprUnary(op, ref inner) => { - match ty::node_id_to_type(v.tcx, inner.id).sty { + match v.tcx.node_id_to_type(inner.id).sty { ty::TyRawPtr(_) => { assert!(op == ast::UnDeref); @@ -574,7 +575,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } } ast::ExprBinary(op, ref lhs, _) => { - match ty::node_id_to_type(v.tcx, lhs.id).sty { + match v.tcx.node_id_to_type(lhs.id).sty { ty::TyRawPtr(_) => { assert!(op.node == ast::BiEq || op.node == ast::BiNe || op.node == ast::BiLe || op.node == ast::BiLt || @@ -695,13 +696,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } } ast::ExprMethodCall(..) => { - let method_did = match v.tcx.method_map.borrow()[&method_call].origin { - ty::MethodStatic(did) => Some(did), - _ => None - }; - let is_const = match method_did { - Some(did) => v.handle_const_fn_call(e, did, node_ty), - None => false + let method = v.tcx.tables.borrow().method_map[&method_call]; + let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() { + ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty), + ty::TraitContainer(_) => false }; if !is_const { v.add_qualif(ConstQualif::NOT_CONST); @@ -731,7 +729,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, ast::ExprClosure(..) => { // Paths in constant contexts cannot refer to local variables, // as there are none, and thus closures can't have upvars there. - if ty::with_freevars(v.tcx, e.id, |fv| !fv.is_empty()) { + if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) { assert!(v.mode == Mode::Var, "global closures can't capture anything"); v.add_qualif(ConstQualif::NOT_CONST); diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 1ec6e0d6d80d0..a303c49bf8db7 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -20,7 +20,8 @@ use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init}; use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode}; use middle::expr_use_visitor::WriteAndRead; use middle::expr_use_visitor as euv; -use middle::mem_categorization::cmt; +use middle::infer; +use middle::mem_categorization::{cmt}; use middle::pat_util::*; use middle::ty::*; use middle::ty; @@ -98,6 +99,7 @@ impl<'a> FromIterator> for Matrix<'a> { } } +//NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv pub struct MatchCheckCtxt<'a, 'tcx: 'a> { pub tcx: &'a ty::ctxt<'tcx>, pub param_env: ParameterEnvironment<'a, 'tcx>, @@ -149,7 +151,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchCheckCtxt<'a, 'tcx> { pub fn check_crate(tcx: &ty::ctxt) { visit::walk_crate(&mut MatchCheckCtxt { tcx: tcx, - param_env: ty::empty_parameter_environment(tcx), + param_env: tcx.empty_parameter_environment(), }, tcx.map.krate()); tcx.sess.abort_if_errors(); } @@ -203,9 +205,9 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &ast::Expr) { // Finally, check if the whole match expression is exhaustive. // Check for empty enum, because is_useful only works on inhabited types. - let pat_ty = node_id_to_type(cx.tcx, scrut.id); + let pat_ty = cx.tcx.node_id_to_type(scrut.id); if inlined_arms.is_empty() { - if !type_is_empty(cx.tcx, pat_ty) { + if !pat_ty.is_empty(cx.tcx) { // We know the type is inhabited, so this must be wrong span_err!(cx.tcx.sess, ex.span, E0002, "non-exhaustive patterns: type {} is non-empty", @@ -231,11 +233,11 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) ast_util::walk_pat(pat, |p| { match p.node { ast::PatIdent(ast::BindByValue(ast::MutImmutable), ident, None) => { - let pat_ty = ty::pat_ty(cx.tcx, p); + let pat_ty = cx.tcx.pat_ty(p); if let ty::TyEnum(def_id, _) = pat_ty.sty { let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); if let Some(DefLocal(_)) = def { - if ty::enum_variants(cx.tcx, def_id).iter().any(|variant| + if cx.tcx.enum_variants(def_id).iter().any(|variant| token::get_name(variant.name) == token::get_name(ident.node.name) && variant.args.is_empty() ) { @@ -509,12 +511,12 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, ty::TyEnum(cid, _) | ty::TyStruct(cid, _) => { let (vid, is_structure) = match ctor { &Variant(vid) => - (vid, ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()), + (vid, cx.tcx.enum_variant_with_id(cid, vid).arg_names.is_some()), _ => - (cid, !ty::is_tuple_struct(cx.tcx, cid)) + (cid, !cx.tcx.is_tuple_struct(cid)) }; if is_structure { - let fields = ty::lookup_struct_fields(cx.tcx, vid); + let fields = cx.tcx.lookup_struct_fields(vid); let field_pats: Vec<_> = fields.into_iter() .zip(pats) .filter(|&(_, ref pat)| pat.node != ast::PatWild(ast::PatWildSingle)) @@ -605,7 +607,7 @@ fn all_constructors(cx: &MatchCheckCtxt, left_ty: Ty, }, ty::TyEnum(eid, _) => - ty::enum_variants(cx.tcx, eid) + cx.tcx.enum_variants(eid) .iter() .map(|va| Variant(va.id)) .collect(), @@ -651,12 +653,14 @@ fn is_useful(cx: &MatchCheckCtxt, None => v[0] }; let left_ty = if real_pat.id == DUMMY_NODE_ID { - ty::mk_nil(cx.tcx) + cx.tcx.mk_nil() } else { - let left_ty = ty::pat_ty(cx.tcx, &*real_pat); + let left_ty = cx.tcx.pat_ty(&*real_pat); match real_pat.node { - ast::PatIdent(ast::BindByRef(..), _, _) => ty::deref(left_ty, false).unwrap().ty, + ast::PatIdent(ast::BindByRef(..), _, _) => { + left_ty.builtin_deref(false).unwrap().ty + } _ => left_ty, } }; @@ -815,11 +819,11 @@ pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usi }, ty::TyEnum(eid, _) => { match *ctor { - Variant(id) => enum_variant_with_id(cx.tcx, eid, id).args.len(), + Variant(id) => cx.tcx.enum_variant_with_id(eid, id).args.len(), _ => unreachable!() } } - ty::TyStruct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(), + ty::TyStruct(cid, _) => cx.tcx.lookup_struct_fields(cid).len(), ty::TyArray(_, n) => n, _ => 0 } @@ -911,7 +915,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], }, _ => { // Assume this is a struct. - match ty::ty_to_def_id(node_id_to_type(cx.tcx, pat_id)) { + match cx.tcx.node_id_to_type(pat_id).ty_to_def_id() { None => { cx.tcx.sess.span_bug(pat_span, "struct pattern wasn't of a \ @@ -922,7 +926,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } }; class_id.map(|variant_id| { - let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id); + let struct_fields = cx.tcx.lookup_struct_fields(variant_id); let args = struct_fields.iter().map(|sf| { match pattern_fields.iter().find(|f| f.node.ident.name == sf.name) { Some(ref f) => &*f.node.pat, @@ -1107,8 +1111,13 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, if pat_is_binding(def_map, &*p) { match p.node { ast::PatIdent(ast::BindByValue(_), _, ref sub) => { - let pat_ty = ty::node_id_to_type(tcx, p.id); - if ty::type_moves_by_default(&cx.param_env, pat.span, pat_ty) { + let pat_ty = tcx.node_id_to_type(p.id); + //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()), + false); + if infcx.type_moves_by_default(pat_ty, pat.span) { check_move(p, sub.as_ref().map(|p| &**p)); } } @@ -1136,8 +1145,13 @@ fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>, let mut checker = MutationChecker { cx: cx, }; - let mut visitor = ExprUseVisitor::new(&mut checker, - &checker.cx.param_env); + + let infcx = infer::new_infer_ctxt(cx.tcx, + &cx.tcx.tables, + Some(checker.cx.param_env.clone()), + false); + + let mut visitor = ExprUseVisitor::new(&mut checker, &infcx); visitor.walk_expr(guard); } diff --git a/src/librustc/middle/check_rvalues.rs b/src/librustc/middle/check_rvalues.rs index f5934751c58b2..c9017432473a7 100644 --- a/src/librustc/middle/check_rvalues.rs +++ b/src/librustc/middle/check_rvalues.rs @@ -12,6 +12,7 @@ // is the public starting point. use middle::expr_use_visitor as euv; +use middle::infer; use middle::mem_categorization as mc; use middle::ty::ParameterEnvironment; use middle::ty; @@ -38,9 +39,14 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> { s: Span, fn_id: ast::NodeId) { { + // FIXME (@jroesch) change this to be an inference context 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()), + false); let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: ¶m_env }; - let mut euv = euv::ExprUseVisitor::new(&mut delegate, ¶m_env); + let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx); euv.walk_fn(fd, b); } visit::walk_fn(self, fk, fd, b, s) @@ -59,7 +65,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> { cmt: mc::cmt<'tcx>, _: euv::ConsumeMode) { debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty); - if !ty::type_is_sized(Some(self.param_env), self.tcx, span, cmt.ty) { + if !cmt.ty.is_sized(self.param_env, span) { span_err!(self.tcx.sess, span, E0161, "cannot move a value of type {0}: the size of {0} cannot be statically determined", cmt.ty); diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index ed06ccf1ec649..7d54b8c284f1f 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -126,9 +126,9 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, // `resolve_trait_associated_const` will select an impl // or the default. Some(ref_id) => { - let trait_id = ty::trait_of_item(tcx, def_id) + let trait_id = tcx.trait_of_item(def_id) .unwrap(); - let substs = ty::node_id_item_substs(tcx, ref_id) + let substs = tcx.node_id_item_substs(ref_id) .substs; resolve_trait_associated_const(tcx, ti, trait_id, substs) @@ -176,7 +176,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, // a trait-associated const if the caller gives us // the expression that refers to it. Some(ref_id) => { - let substs = ty::node_id_item_substs(tcx, ref_id) + let substs = tcx.node_id_item_substs(ref_id) .substs; resolve_trait_associated_const(tcx, ti, trait_id, substs).map(|e| e.id) @@ -714,7 +714,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, e: &Expr, ty_hint: Option>) -> EvalResult { eval_const_expr_with_substs(tcx, e, ty_hint, |id| { - ty::node_id_item_substs(tcx, id).substs + tcx.node_id_item_substs(id).substs }) } @@ -725,7 +725,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, where S: Fn(ast::NodeId) -> subst::Substs<'tcx> { fn fromb(b: bool) -> ConstVal { Int(b as i64) } - let ety = ty_hint.or_else(|| ty::expr_ty_opt(tcx, e)); + let ety = ty_hint.or_else(|| 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 @@ -882,7 +882,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, // 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. - let base_hint = ty::expr_ty_opt(tcx, &**base).unwrap_or(ety); + let base_hint = tcx.expr_ty_opt(&**base).unwrap_or(ety); let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint))); match cast_const(tcx, val, ety) { Ok(val) => val, @@ -1030,11 +1030,10 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id, substs: trait_substs }); - ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id()); - let infcx = infer::new_infer_ctxt(tcx); + tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id()); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); - let param_env = ty::empty_parameter_environment(tcx); - let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env); + let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), trait_ref.to_poly_trait_predicate()); let selection = match selcx.select(&obligation) { @@ -1056,7 +1055,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, match selection { traits::VtableImpl(ref impl_data) => { - match ty::associated_consts(tcx, impl_data.impl_def_id) + match tcx.associated_consts(impl_data.impl_def_id) .iter().find(|ic| ic.name == ti.ident.name) { Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), None => match ti.node { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index fd810429c86e0..8d2d6889b5efa 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -93,48 +93,16 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { }); } - fn lookup_and_handle_method(&mut self, id: ast::NodeId, - span: codemap::Span) { + fn lookup_and_handle_method(&mut self, id: ast::NodeId) { let method_call = ty::MethodCall::expr(id); - match self.tcx.method_map.borrow().get(&method_call) { - Some(method) => { - match method.origin { - ty::MethodStatic(def_id) => { - match ty::provided_source(self.tcx, def_id) { - Some(p_did) => self.check_def_id(p_did), - None => self.check_def_id(def_id) - } - } - ty::MethodStaticClosure(_) => {} - ty::MethodTypeParam(ty::MethodParam { - ref trait_ref, - method_num: index, - .. - }) | - ty::MethodTraitObject(ty::MethodObject { - ref trait_ref, - method_num: index, - .. - }) => { - let trait_item = ty::trait_item(self.tcx, - trait_ref.def_id, - index); - self.check_def_id(trait_item.def_id()); - } - } - } - None => { - self.tcx.sess.span_bug(span, - "method call expression not \ - in method map?!") - } - } + let method = self.tcx.tables.borrow().method_map[&method_call]; + self.check_def_id(method.def_id); } fn handle_field_access(&mut self, lhs: &ast::Expr, name: ast::Name) { - match ty::expr_ty_adjusted(self.tcx, lhs).sty { + match self.tcx.expr_ty_adjusted(lhs).sty { ty::TyStruct(id, _) => { - let fields = ty::lookup_struct_fields(self.tcx, id); + let fields = self.tcx.lookup_struct_fields(id); let field_id = fields.iter() .find(|field| field.name == name).unwrap().id; self.live_symbols.insert(field_id.node); @@ -144,9 +112,9 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn handle_tup_field_access(&mut self, lhs: &ast::Expr, idx: usize) { - match ty::expr_ty_adjusted(self.tcx, lhs).sty { + match self.tcx.expr_ty_adjusted(lhs).sty { ty::TyStruct(id, _) => { - let fields = ty::lookup_struct_fields(self.tcx, id); + let fields = self.tcx.lookup_struct_fields(id); let field_id = fields[idx].id; self.live_symbols.insert(field_id.node); }, @@ -159,8 +127,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { let id = match self.tcx.def_map.borrow().get(&lhs.id).unwrap().full_def() { def::DefVariant(_, id, _) => id, _ => { - match ty::ty_to_def_id(ty::node_id_to_type(self.tcx, - lhs.id)) { + match self.tcx.node_id_to_type(lhs.id).ty_to_def_id() { None => { self.tcx.sess.span_bug(lhs.span, "struct pattern wasn't of a \ @@ -170,7 +137,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } } }; - let fields = ty::lookup_struct_fields(self.tcx, id); + let fields = self.tcx.lookup_struct_fields(id); for pat in pats { if let ast::PatWild(ast::PatWildSingle) = pat.node.pat.node { continue; @@ -265,7 +232,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &ast::Expr) { match expr.node { ast::ExprMethodCall(..) => { - self.lookup_and_handle_method(expr.id, expr.span); + self.lookup_and_handle_method(expr.id); } ast::ExprField(ref lhs, ref ident) => { self.handle_field_access(&**lhs, ident.node.name); @@ -480,8 +447,8 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { fn should_warn_about_field(&mut self, node: &ast::StructField_) -> bool { let is_named = node.ident().is_some(); - let field_type = ty::node_id_to_type(self.tcx, node.id); - let is_marker_field = match ty::ty_to_def_id(field_type) { + let field_type = self.tcx.node_id_to_type(node.id); + let is_marker_field = match field_type.ty_to_def_id() { Some(def_id) => self.tcx.lang_items.items().any(|(_, item)| *item == Some(def_id)), _ => false }; diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index bb63ec42d8c0c..b2a064bf86c6a 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -59,26 +59,6 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { UnsafeFn => {} } } - - fn check_str_index(&mut self, e: &ast::Expr) { - let base_type = match e.node { - ast::ExprIndex(ref base, _) => ty::node_id_to_type(self.tcx, base.id), - _ => return - }; - debug!("effect: checking index with base type {:?}", - base_type); - match base_type.sty { - ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) => if ty::TyStr == ty.sty { - span_err!(self.tcx.sess, e.span, E0134, - "modification of string types is not allowed"); - }, - ty::TyStr => { - span_err!(self.tcx.sess, e.span, E0135, - "modification of string types is not allowed"); - } - _ => {} - } - } } impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { @@ -140,7 +120,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { match expr.node { ast::ExprMethodCall(_, _, _) => { let method_call = MethodCall::expr(expr.id); - let base_type = self.tcx.method_map.borrow().get(&method_call).unwrap().ty; + let base_type = self.tcx.tables.borrow().method_map[&method_call].ty; debug!("effect: method call case, base type is {:?}", base_type); if type_is_unsafe_function(base_type) { @@ -149,7 +129,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } ast::ExprCall(ref base, _) => { - let base_type = ty::node_id_to_type(self.tcx, base.id); + let base_type = self.tcx.node_id_to_type(base.id); debug!("effect: call case, base type is {:?}", base_type); if type_is_unsafe_function(base_type) { @@ -157,24 +137,18 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } ast::ExprUnary(ast::UnDeref, ref base) => { - let base_type = ty::node_id_to_type(self.tcx, base.id); + let base_type = self.tcx.node_id_to_type(base.id); debug!("effect: unary case, base type is {:?}", base_type); if let ty::TyRawPtr(_) = base_type.sty { self.require_unsafe(expr.span, "dereference of raw pointer") } } - ast::ExprAssign(ref base, _) | ast::ExprAssignOp(_, ref base, _) => { - self.check_str_index(&**base); - } - ast::ExprAddrOf(ast::MutMutable, ref base) => { - self.check_str_index(&**base); - } ast::ExprInlineAsm(..) => { self.require_unsafe(expr.span, "use of inline assembly"); } ast::ExprPath(..) => { - if let def::DefStatic(_, true) = ty::resolve_expr(self.tcx, expr) { + if let def::DefStatic(_, true) = self.tcx.resolve_expr(expr) { self.require_unsafe(expr.span, "use of mutable static"); } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index ab67c68be124b..0d204a823af04 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -21,12 +21,9 @@ use self::TrackMatchMode::*; use self::OverloadedCallType::*; use middle::{def, region, pat_util}; +use middle::infer; use middle::mem_categorization as mc; -use middle::mem_categorization::Typer; -use middle::ty::{self}; -use middle::ty::{MethodCall, MethodObject, MethodTraitObject}; -use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam}; -use middle::ty::{MethodStatic, MethodStaticClosure}; +use middle::ty; use syntax::{ast, ast_util}; use syntax::ptr::P; @@ -229,56 +226,8 @@ impl OverloadedCallType { fn from_method_id(tcx: &ty::ctxt, method_id: ast::DefId) -> OverloadedCallType { - let method_descriptor = match ty::impl_or_trait_item(tcx, method_id) { - ty::MethodTraitItem(ref method_descriptor) => { - (*method_descriptor).clone() - } - _ => { - tcx.sess.bug("overloaded call method wasn't in method map") - } - }; - let impl_id = match method_descriptor.container { - ty::TraitContainer(_) => { - tcx.sess.bug("statically resolved overloaded call method \ - belonged to a trait?!") - } - ty::ImplContainer(impl_id) => impl_id, - }; - let trait_ref = match ty::impl_trait_ref(tcx, impl_id) { - None => { - tcx.sess.bug("statically resolved overloaded call impl \ - didn't implement a trait?!") - } - Some(ref trait_ref) => (*trait_ref).clone(), - }; - OverloadedCallType::from_trait_id(tcx, trait_ref.def_id) - } - - fn from_closure(tcx: &ty::ctxt, closure_did: ast::DefId) - -> OverloadedCallType { - let trait_did = - tcx.closure_kinds - .borrow() - .get(&closure_did) - .expect("OverloadedCallType::from_closure: didn't find closure id") - .trait_did(tcx); - OverloadedCallType::from_trait_id(tcx, trait_did) - } - - fn from_method_origin(tcx: &ty::ctxt, origin: &MethodOrigin) - -> OverloadedCallType { - match *origin { - MethodStatic(def_id) => { - OverloadedCallType::from_method_id(tcx, def_id) - } - MethodStaticClosure(def_id) => { - OverloadedCallType::from_closure(tcx, def_id) - } - MethodTypeParam(MethodParam { ref trait_ref, .. }) | - MethodTraitObject(MethodObject { ref trait_ref, .. }) => { - OverloadedCallType::from_trait_id(tcx, trait_ref.def_id) - } - } + let method = tcx.impl_or_trait_item(method_id); + OverloadedCallType::from_trait_id(tcx, method.container().id()) } } @@ -290,9 +239,9 @@ impl OverloadedCallType { // supplies types from the tree. After type checking is complete, you // can just use the tcx as the typer. -pub struct ExprUseVisitor<'d,'t,'tcx:'t,TYPER:'t> { - typer: &'t TYPER, - mc: mc::MemCategorizationContext<'t,TYPER>, +pub struct ExprUseVisitor<'d,'t,'a: 't, 'tcx:'a> { + typer: &'t infer::InferCtxt<'a, 'tcx>, + mc: mc::MemCategorizationContext<'t, 'a, 'tcx>, delegate: &'d mut (Delegate<'tcx>+'d), } @@ -318,10 +267,10 @@ enum PassArgs { ByRef, } -impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { +impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { pub fn new(delegate: &'d mut Delegate<'tcx>, - typer: &'t TYPER) - -> ExprUseVisitor<'d,'t,'tcx,TYPER> { + typer: &'t infer::InferCtxt<'a, 'tcx>) + -> ExprUseVisitor<'d,'t,'a, 'tcx> { ExprUseVisitor { typer: typer, mc: mc::MemCategorizationContext::new(typer), @@ -354,7 +303,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } fn tcx(&self) -> &'t ty::ctxt<'tcx> { - self.typer.tcx() + self.typer.tcx } fn delegate_consume(&mut self, @@ -502,9 +451,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: let expr_ty = return_if_err!(self.typer.node_ty(expr.id)); - let r = ty::ty_region(self.tcx(), expr.span, expr_ty); - let bk = ty::BorrowKind::from_mutbl(m); - self.borrow_expr(&**base, r, bk, AddrOf); + if let ty::TyRef(&r, _) = expr_ty.sty { + let bk = ty::BorrowKind::from_mutbl(m); + self.borrow_expr(&**base, r, bk, AddrOf); + } } ast::ExprInlineAsm(ref ia) => { @@ -627,11 +577,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { ty::TyError => { } _ => { let overloaded_call_type = - match self.typer.node_method_origin(MethodCall::expr(call.id)) { - Some(method_origin) => { - OverloadedCallType::from_method_origin( - self.tcx(), - &method_origin) + match self.typer.node_method_id(ty::MethodCall::expr(call.id)) { + Some(method_id) => { + OverloadedCallType::from_method_id(self.tcx(), method_id) } None => { self.tcx().sess.span_bug( @@ -688,7 +636,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { match local.init { None => { let delegate = &mut self.delegate; - pat_util::pat_bindings(&self.typer.tcx().def_map, &*local.pat, + pat_util::pat_bindings(&self.typer.tcx.def_map, &*local.pat, |_, id, span, _| { delegate.decl_without_init(id, span); }) @@ -740,7 +688,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // expression that will actually be used let with_fields = match with_cmt.ty.sty { ty::TyStruct(did, substs) => { - ty::struct_fields(self.tcx(), did, substs) + self.tcx().struct_fields(did, substs) } _ => { // the base expression should always evaluate to a @@ -786,8 +734,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // process. fn walk_adjustment(&mut self, expr: &ast::Expr) { let typer = self.typer; - if let Some(adjustment) = typer.adjustments().borrow().get(&expr.id) { - match *adjustment { + //NOTE(@jroesch): mixed RefCell borrow causes crash + let adj = typer.adjustments().get(&expr.id).map(|x| x.clone()); + if let Some(adjustment) = adj { + match adjustment { ty::AdjustReifyFnPointer | ty::AdjustUnsafeFnPointer => { // Creating a closure/fn-pointer or unsizing consumes @@ -821,8 +771,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // the method call infrastructure should have // replaced all late-bound regions with variables: - let self_ty = ty::ty_fn_sig(method_ty).input(0); - let self_ty = ty::no_late_bound_regions(self.tcx(), &self_ty).unwrap(); + let self_ty = method_ty.fn_sig().input(0); + let self_ty = self.tcx().no_late_bound_regions(&self_ty).unwrap(); let (m, r) = match self_ty.sty { ty::TyRef(r, ref m) => (m.mutbl, r), @@ -922,10 +872,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // This is always an rvalue, since we are producing a new // (temporary) indirection. - let adj_ty = - ty::adjust_ty_for_autoref(self.tcx(), - cmt_base_ty, - opt_autoref); + let adj_ty = cmt_base_ty.adjust_for_autoref(self.tcx(), opt_autoref); self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty) } @@ -1051,7 +998,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { let delegate = &mut self.delegate; return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| { if pat_util::pat_is_binding(def_map, pat) { - let tcx = typer.tcx(); + let tcx = typer.tcx; debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, @@ -1074,12 +1021,11 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // It is also a borrow or copy/move of the value being matched. match pat.node { ast::PatIdent(ast::BindByRef(m), _, _) => { - let (r, bk) = { - (ty::ty_region(tcx, pat.span, pat_ty), - ty::BorrowKind::from_mutbl(m)) - }; - delegate.borrow(pat.id, pat.span, cmt_pat, - r, bk, RefBinding); + if let ty::TyRef(&r, _) = pat_ty.sty { + let bk = ty::BorrowKind::from_mutbl(m); + delegate.borrow(pat.id, pat.span, cmt_pat, + r, bk, RefBinding); + } } ast::PatIdent(ast::BindByValue(_), _, _) => { let mode = copy_or_move(typer, &cmt_pat, PatBindingMove); @@ -1139,7 +1085,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // the leaves of the pattern tree structure. return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| { let def_map = def_map.borrow(); - let tcx = typer.tcx(); + let tcx = typer.tcx; match pat.node { ast::PatEnum(_, _) | ast::PatQPath(..) | @@ -1152,7 +1098,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { Some(def::DefVariant(enum_did, variant_did, _is_struct)) => { let downcast_cmt = - if ty::enum_is_univariant(tcx, enum_did) { + if tcx.enum_is_univariant(enum_did) { cmt_pat } else { let cmt_pat_ty = cmt_pat.ty; @@ -1238,7 +1184,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { fn walk_captures(&mut self, closure_expr: &ast::Expr) { debug!("walk_captures({:?})", closure_expr); - ty::with_freevars(self.tcx(), closure_expr.id, |freevars| { + self.tcx().with_freevars(closure_expr.id, |freevars| { for freevar in freevars { let id_var = freevar.def.def_id().node; let upvar_id = ty::UpvarId { var_id: id_var, @@ -1278,12 +1224,12 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } } -fn copy_or_move<'tcx>(typer: &mc::Typer<'tcx>, +fn copy_or_move<'a, 'tcx>(typer: &infer::InferCtxt<'a, 'tcx>, cmt: &mc::cmt<'tcx>, move_reason: MoveReason) -> ConsumeMode { - if typer.type_moves_by_default(cmt.span, cmt.ty) { + if typer.type_moves_by_default(cmt.ty, cmt.span) { Move(move_reason) } else { Copy diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs index bbfa3c9fdfa3f..3e097578857e9 100644 --- a/src/librustc/middle/implicator.rs +++ b/src/librustc/middle/implicator.rs @@ -13,7 +13,7 @@ use middle::infer::{InferCtxt, GenericKind}; use middle::subst::Substs; use middle::traits; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, AsPredicate, Ty}; +use middle::ty::{self, RegionEscape, ToPolyTraitRef, ToPredicate, Ty}; use middle::ty_fold::{TypeFoldable, TypeFolder}; use syntax::ast; @@ -34,7 +34,6 @@ pub enum Implication<'tcx> { struct Implicator<'a, 'tcx: 'a> { infcx: &'a InferCtxt<'a,'tcx>, - closure_typer: &'a (ty::ClosureTyper<'tcx>+'a), body_id: ast::NodeId, stack: Vec<(ty::Region, Option>)>, span: Span, @@ -46,7 +45,6 @@ struct Implicator<'a, 'tcx: 'a> { /// appear in a context with lifetime `outer_region` pub fn implications<'a,'tcx>( infcx: &'a InferCtxt<'a,'tcx>, - closure_typer: &ty::ClosureTyper<'tcx>, body_id: ast::NodeId, ty: Ty<'tcx>, outer_region: ty::Region, @@ -60,8 +58,7 @@ pub fn implications<'a,'tcx>( let mut stack = Vec::new(); stack.push((outer_region, None)); - let mut wf = Implicator { closure_typer: closure_typer, - infcx: infcx, + let mut wf = Implicator { infcx: infcx, body_id: body_id, span: span, stack: stack, @@ -112,7 +109,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { ty::TyEnum(def_id, substs) | ty::TyStruct(def_id, substs) => { - let item_scheme = ty::lookup_item_type(self.tcx(), def_id); + let item_scheme = self.tcx().lookup_item_type(def_id); self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs) } @@ -236,7 +233,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { substs: &Substs<'tcx>) { let predicates = - ty::lookup_predicates(self.tcx(), def_id).instantiate(self.tcx(), substs); + self.tcx().lookup_predicates(def_id).instantiate(self.tcx(), substs); let predicates = match self.fully_normalize(&predicates) { Ok(predicates) => predicates, Err(ErrorReported) => { return; } @@ -250,7 +247,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { ty::Predicate::Equate(..) => { } ty::Predicate::Projection(..) => { } ty::Predicate::RegionOutlives(ref data) => { - match ty::no_late_bound_regions(self.tcx(), data) { + match self.tcx().no_late_bound_regions(data) { None => { } Some(ty::OutlivesPredicate(r_a, r_b)) => { self.push_sub_region_constraint(Some(ty), r_b, r_a); @@ -258,7 +255,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { } } ty::Predicate::TypeOutlives(ref data) => { - match ty::no_late_bound_regions(self.tcx(), data) { + match self.tcx().no_late_bound_regions(data) { None => { } Some(ty::OutlivesPredicate(ty_a, r_b)) => { self.stack.push((r_b, Some(ty))); @@ -275,7 +272,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { .map(|pred| Implication::Predicate(def_id, pred)); self.out.extend(obligations); - let variances = ty::item_variances(self.tcx(), def_id); + let variances = self.tcx().item_variances(def_id); for (®ion, &variance) in substs.regions().iter().zip(&variances.regions) { match variance { @@ -316,7 +313,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { data); for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) { - match ty::no_late_bound_regions(self.tcx(), &poly_trait_ref) { + match self.tcx().no_late_bound_regions(&poly_trait_ref) { Some(trait_ref) => { self.accumulate_from_assoc_types(trait_ref); } None => { } } @@ -330,11 +327,11 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { trait_ref); let trait_def_id = trait_ref.def_id; - let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id); + let trait_def = self.tcx().lookup_trait_def(trait_def_id); let assoc_type_projections: Vec<_> = trait_def.associated_type_names .iter() - .map(|&name| ty::mk_projection(self.tcx(), trait_ref.clone(), name)) + .map(|&name| self.tcx().mk_projection(trait_ref.clone(), name)) .collect(); debug!("accumulate_from_assoc_types: assoc_type_projections={:?}", assoc_type_projections); @@ -400,11 +397,10 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { } fn fully_normalize(&self, value: &T) -> Result - where T : TypeFoldable<'tcx> + ty::HasProjectionTypes + where T : TypeFoldable<'tcx> + ty::HasTypeFlags { let value = traits::fully_normalize(self.infcx, - self.closure_typer, traits::ObligationCause::misc(self.span, self.body_id), value); match value { @@ -437,7 +433,7 @@ pub fn object_region_bounds<'tcx>( // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically // a skolemized type. - let open_ty = ty::mk_infer(tcx, ty::FreshTy(0)); + let open_ty = tcx.mk_infer(ty::FreshTy(0)); // Note that we preserve the overall binding levels here. assert!(!open_ty.has_escaping_regions()); @@ -445,7 +441,7 @@ pub fn object_region_bounds<'tcx>( let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs))); let mut predicates = others.to_predicates(tcx, open_ty); - predicates.extend(trait_refs.iter().map(|t| t.as_predicate())); + predicates.extend(trait_refs.iter().map(|t| t.to_predicate())); - ty::required_region_bounds(tcx, open_ty, predicates) + tcx.required_region_bounds(open_ty, predicates) } diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs index 742ad3f29b780..ad53fb4a8a270 100644 --- a/src/librustc/middle/infer/bivariate.rs +++ b/src/librustc/middle/infer/bivariate.rs @@ -49,6 +49,11 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> { fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn will_change(&mut self, _: bool, _: bool) -> bool { + // since we are not comparing regions, we don't care + false + } + fn relate_with_variance>(&mut self, variance: ty::Variance, a: &T, @@ -109,8 +114,8 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> { -> RelateResult<'tcx, ty::Binder> where T: Relate<'a,'tcx> { - let a1 = ty::erase_late_bound_regions(self.tcx(), a); - let b1 = ty::erase_late_bound_regions(self.tcx(), b); + let a1 = self.tcx().erase_late_bound_regions(a); + let b1 = self.tcx().erase_late_bound_regions(b); let c = try!(self.relate(&a1, &b1)); Ok(ty::Binder(c)) } diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 17d545212c281..0d081cfeee041 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -56,6 +56,7 @@ pub struct CombineFields<'a, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'tcx>, pub a_is_expected: bool, pub trace: TypeTrace<'tcx>, + pub cause: Option, } pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>, @@ -129,8 +130,8 @@ fn unify_integral_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, .unify_var_value(vid, val) .map_err(|e| int_unification_error(vid_is_expected, e))); match val { - IntType(v) => Ok(ty::mk_mach_int(infcx.tcx, v)), - UintType(v) => Ok(ty::mk_mach_uint(infcx.tcx, v)), + IntType(v) => Ok(infcx.tcx.mk_mach_int(v)), + UintType(v) => Ok(infcx.tcx.mk_mach_uint(v)), } } @@ -145,7 +146,7 @@ fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, .borrow_mut() .unify_var_value(vid, val) .map_err(|e| float_unification_error(vid_is_expected, e))); - Ok(ty::mk_mach_float(infcx.tcx, val)) + Ok(infcx.tcx.mk_mach_float(val)) } impl<'a, 'tcx> CombineFields<'a, 'tcx> { diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index cbbf73d942073..c0dcda1792be5 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -34,6 +34,11 @@ impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> { fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn will_change(&mut self, a: bool, b: bool) -> bool { + // if either side changed from what it was, that could cause equality to fail + a || b + } + fn relate_with_variance>(&mut self, _: ty::Variance, a: &T, diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 4ae618d45b728..8d226739e1688 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -77,7 +77,7 @@ use middle::def; use middle::infer; use middle::region; use middle::subst; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty::{Region, ReFree}; use std::cell::{Cell, RefCell}; @@ -91,123 +91,125 @@ use syntax::parse::token; use syntax::print::pprust; use syntax::ptr::P; -pub fn note_and_explain_region(tcx: &ty::ctxt, - prefix: &str, - region: ty::Region, - suffix: &str) { - fn item_scope_tag(item: &ast::Item) -> &'static str { - match item.node { - ast::ItemImpl(..) => "impl", - ast::ItemStruct(..) => "struct", - ast::ItemEnum(..) => "enum", - ast::ItemTrait(..) => "trait", - ast::ItemFn(..) => "function body", - _ => "item" +impl<'tcx> ty::ctxt<'tcx> { + pub fn note_and_explain_region(&self, + prefix: &str, + region: ty::Region, + suffix: &str) { + fn item_scope_tag(item: &ast::Item) -> &'static str { + match item.node { + ast::ItemImpl(..) => "impl", + ast::ItemStruct(..) => "struct", + ast::ItemEnum(..) => "enum", + ast::ItemTrait(..) => "trait", + ast::ItemFn(..) => "function body", + _ => "item" + } } - } - - fn explain_span(tcx: &ty::ctxt, heading: &str, span: Span) - -> (String, Option) { - let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo); - (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()), - Some(span)) - } - let (description, span) = match region { - ty::ReScope(scope) => { - let new_string; - let unknown_scope = || { - format!("{}unknown scope: {:?}{}. Please report a bug.", - prefix, scope, suffix) - }; - let span = match scope.span(&tcx.map) { - Some(s) => s, - None => return tcx.sess.note(&unknown_scope()) - }; - let tag = match tcx.map.find(scope.node_id()) { - Some(ast_map::NodeBlock(_)) => "block", - Some(ast_map::NodeExpr(expr)) => match expr.node { - ast::ExprCall(..) => "call", - ast::ExprMethodCall(..) => "method call", - ast::ExprMatch(_, _, ast::MatchSource::IfLetDesugar { .. }) => "if let", - ast::ExprMatch(_, _, ast::MatchSource::WhileLetDesugar) => "while let", - ast::ExprMatch(_, _, ast::MatchSource::ForLoopDesugar) => "for", - ast::ExprMatch(..) => "match", - _ => "expression", - }, - Some(ast_map::NodeStmt(_)) => "statement", - Some(ast_map::NodeItem(it)) => item_scope_tag(&*it), - Some(_) | None => { - return tcx.sess.span_note(span, &unknown_scope()); - } - }; - let scope_decorated_tag = match scope { - region::CodeExtent::Misc(_) => tag, - region::CodeExtent::ParameterScope { .. } => { - "scope of parameters for function" - } - region::CodeExtent::DestructionScope(_) => { - new_string = format!("destruction scope surrounding {}", tag); - &new_string[..] - } - region::CodeExtent::Remainder(r) => { - new_string = format!("block suffix following statement {}", - r.first_statement_index); - &new_string[..] - } - }; - explain_span(tcx, scope_decorated_tag, span) + fn explain_span(tcx: &ty::ctxt, heading: &str, span: Span) + -> (String, Option) { + let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo); + (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()), + Some(span)) } - ty::ReFree(ref fr) => { - let prefix = match fr.bound_region { - ty::BrAnon(idx) => { - format!("the anonymous lifetime #{} defined on", idx + 1) - } - ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(), - _ => { - format!("the lifetime {} as defined on", - fr.bound_region) - } - }; + let (description, span) = match region { + ty::ReScope(scope) => { + let new_string; + let unknown_scope = || { + format!("{}unknown scope: {:?}{}. Please report a bug.", + prefix, scope, suffix) + }; + let span = match scope.span(&self.map) { + Some(s) => s, + None => return self.sess.note(&unknown_scope()) + }; + let tag = match self.map.find(scope.node_id()) { + Some(ast_map::NodeBlock(_)) => "block", + Some(ast_map::NodeExpr(expr)) => match expr.node { + ast::ExprCall(..) => "call", + ast::ExprMethodCall(..) => "method call", + ast::ExprMatch(_, _, ast::MatchSource::IfLetDesugar { .. }) => "if let", + ast::ExprMatch(_, _, ast::MatchSource::WhileLetDesugar) => "while let", + ast::ExprMatch(_, _, ast::MatchSource::ForLoopDesugar) => "for", + ast::ExprMatch(..) => "match", + _ => "expression", + }, + Some(ast_map::NodeStmt(_)) => "statement", + Some(ast_map::NodeItem(it)) => item_scope_tag(&*it), + Some(_) | None => { + return self.sess.span_note(span, &unknown_scope()); + } + }; + let scope_decorated_tag = match scope { + region::CodeExtent::Misc(_) => tag, + region::CodeExtent::ParameterScope { .. } => { + "scope of parameters for function" + } + region::CodeExtent::DestructionScope(_) => { + new_string = format!("destruction scope surrounding {}", tag); + &new_string[..] + } + region::CodeExtent::Remainder(r) => { + new_string = format!("block suffix following statement {}", + r.first_statement_index); + &new_string[..] + } + }; + explain_span(self, scope_decorated_tag, span) + } - match tcx.map.find(fr.scope.node_id) { - Some(ast_map::NodeBlock(ref blk)) => { - let (msg, opt_span) = explain_span(tcx, "block", blk.span); - (format!("{} {}", prefix, msg), opt_span) - } - Some(ast_map::NodeItem(it)) => { - let tag = item_scope_tag(&*it); - let (msg, opt_span) = explain_span(tcx, tag, it.span); - (format!("{} {}", prefix, msg), opt_span) - } - Some(_) | None => { - // this really should not happen - (format!("{} unknown free region bounded by scope {:?}", - prefix, fr.scope), None) + ty::ReFree(ref fr) => { + let prefix = match fr.bound_region { + ty::BrAnon(idx) => { + format!("the anonymous lifetime #{} defined on", idx + 1) + } + ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(), + _ => { + format!("the lifetime {} as defined on", + fr.bound_region) + } + }; + + match self.map.find(fr.scope.node_id) { + Some(ast_map::NodeBlock(ref blk)) => { + let (msg, opt_span) = explain_span(self, "block", blk.span); + (format!("{} {}", prefix, msg), opt_span) + } + Some(ast_map::NodeItem(it)) => { + let tag = item_scope_tag(&*it); + let (msg, opt_span) = explain_span(self, tag, it.span); + (format!("{} {}", prefix, msg), opt_span) + } + Some(_) | None => { + // this really should not happen + (format!("{} unknown free region bounded by scope {:?}", + prefix, fr.scope), None) + } } } - } - ty::ReStatic => ("the static lifetime".to_owned(), None), + ty::ReStatic => ("the static lifetime".to_owned(), None), - ty::ReEmpty => ("the empty lifetime".to_owned(), None), + ty::ReEmpty => ("the empty lifetime".to_owned(), None), - ty::ReEarlyBound(ref data) => { - (format!("{}", token::get_name(data.name)), None) - } + ty::ReEarlyBound(ref data) => { + (format!("{}", token::get_name(data.name)), None) + } - // I believe these cases should not occur (except when debugging, - // perhaps) - ty::ReInfer(_) | ty::ReLateBound(..) => { - (format!("lifetime {:?}", region), None) + // I believe these cases should not occur (except when debugging, + // perhaps) + ty::ReInfer(_) | ty::ReLateBound(..) => { + (format!("lifetime {:?}", region), None) + } + }; + let message = format!("{}{}{}", prefix, description, suffix); + if let Some(span) = span { + self.sess.span_note(span, &message); + } else { + self.sess.note(&message); } - }; - let message = format!("{}{}{}", prefix, description, suffix); - if let Some(span) = span { - tcx.sess.span_note(span, &message); - } else { - tcx.sess.note(&message); } } @@ -226,7 +228,7 @@ pub trait ErrorReporting<'tcx> { fn values_str(&self, values: &ValuePairs<'tcx>) -> Option; - fn expected_found_str>( + fn expected_found_str + HasTypeFlags>( &self, exp_found: &ty::expected_found) -> Option; @@ -491,7 +493,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { terr: &ty::type_err<'tcx>) { let span = trace.origin.span(); self.report_type_error(trace, terr); - ty::note_and_explain_type_err(self.tcx, terr, span); + self.tcx.note_and_explain_type_err(terr, span); } /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived @@ -504,18 +506,18 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { } } - fn expected_found_str>( + fn expected_found_str + HasTypeFlags>( &self, exp_found: &ty::expected_found) -> Option { let expected = exp_found.expected.resolve(self); - if expected.contains_error() { + if expected.references_error() { return None; } let found = exp_found.found.resolve(self); - if found.contains_error() { + if found.references_error() { return None; } @@ -576,8 +578,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { &format!( "consider adding an explicit lifetime bound for `{}`", bound_kind)); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( &format!("{} must be valid for ", labeled_user_string), sub, "..."); @@ -592,7 +593,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sub: Region, sup: Region) { match origin { - infer::Subtype(trace) => { + infer::Subtype(trace) | + infer::DefaultExistentialBound(trace) => { let terr = ty::terr_regions_does_not_outlive(sup, sub); self.report_and_explain_type_error(trace, &terr); } @@ -600,13 +602,11 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { span_err!(self.tcx.sess, span, E0312, "lifetime of reference outlines \ lifetime of borrowed content..."); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "...the reference is valid for ", sub, "..."); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "...but the borrowed content is only valid for ", sup, ""); @@ -615,33 +615,25 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { span_err!(self.tcx.sess, span, E0313, "lifetime of borrowed pointer outlives \ lifetime of captured variable `{}`...", - ty::local_var_name_str(self.tcx, - upvar_id.var_id) - .to_string()); - note_and_explain_region( - self.tcx, + self.tcx.local_var_name_str(upvar_id.var_id)); + self.tcx.note_and_explain_region( "...the borrowed pointer is valid for ", sub, "..."); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( &format!("...but `{}` is only valid for ", - ty::local_var_name_str(self.tcx, - upvar_id.var_id) - .to_string()), + self.tcx.local_var_name_str(upvar_id.var_id)), sup, ""); } infer::InfStackClosure(span) => { span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "...the closure must be valid for ", sub, "..."); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "...but the closure's stack frame is only valid for ", sup, ""); @@ -649,8 +641,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { infer::InvokeClosure(span) => { span_err!(self.tcx.sess, span, E0315, "cannot invoke closure outside of its lifetime"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the closure is only valid for ", sup, ""); @@ -659,8 +650,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.tcx.sess.span_err( span, "dereference of reference outside its lifetime"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the reference is only valid for ", sup, ""); @@ -669,16 +659,13 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.tcx.sess.span_err( span, &format!("captured variable `{}` does not \ - outlive the enclosing closure", - ty::local_var_name_str(self.tcx, - id).to_string())); - note_and_explain_region( - self.tcx, + outlive the enclosing closure", + self.tcx.local_var_name_str(id))); + self.tcx.note_and_explain_region( "captured variable is valid for ", sup, ""); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "closure is valid for ", sub, ""); @@ -686,8 +673,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { infer::IndexSlice(span) => { self.tcx.sess.span_err(span, "index of slice outside its lifetime"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the slice is only valid for ", sup, ""); @@ -697,13 +683,11 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { span, "lifetime of the source pointer does not outlive \ lifetime bound of the object type"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "object type is valid for ", sub, ""); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "source pointer is only valid for ", sup, ""); @@ -714,7 +698,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { &format!("the type `{}` does not fulfill the \ required lifetime", self.ty_to_string(ty))); - note_and_explain_region(self.tcx, + self.tcx.note_and_explain_region( "type must outlive ", sub, ""); @@ -723,13 +707,11 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.tcx.sess.span_err( span, "lifetime bound not satisfied"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "lifetime parameter instantiated with ", sup, ""); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "but lifetime parameter must outlive ", sub, ""); @@ -740,7 +722,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { &format!("the type `{}` (provided as the value of \ a type parameter) is not valid at this point", self.ty_to_string(ty))); - note_and_explain_region(self.tcx, + self.tcx.note_and_explain_region( "type must outlive ", sub, ""); @@ -750,8 +732,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { span, "lifetime of method receiver does not outlive \ the method call"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the receiver is only valid for ", sup, ""); @@ -761,8 +742,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { span, "lifetime of function argument does not outlive \ the function call"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the function argument is only valid for ", sup, ""); @@ -772,8 +752,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { span, "lifetime of return value does not outlive \ the function call"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the return value is only valid for ", sup, ""); @@ -783,8 +762,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { span, "lifetime of operand does not outlive \ the operation"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the operand is only valid for ", sup, ""); @@ -794,8 +772,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { span, "reference is not valid \ at the time of borrow"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the borrow is only valid for ", sup, ""); @@ -805,8 +782,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { span, "automatically reference is not valid \ at the time of borrow"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the automatic borrow is only valid for ", sup, ""); @@ -817,8 +793,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { &format!("type of expression contains references \ that are not valid during the expression: `{}`", self.ty_to_string(t))); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "type is only valid for ", sup, ""); @@ -829,13 +804,11 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "unsafe use of destructor: destructor might be called \ while references are dead"); // FIXME (22171): terms "super/subregion" are suboptimal - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "superregion: ", sup, ""); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "subregion: ", sub, ""); @@ -844,8 +817,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.tcx.sess.span_err( span, "lifetime of variable does not enclose its declaration"); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the variable is only valid for ", sup, ""); @@ -856,13 +828,11 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { &format!("in type `{}`, reference has a longer lifetime \ than the data it references", self.ty_to_string(ty))); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "the pointer is valid for ", sub, ""); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "but the referenced data is only valid for ", sup, ""); @@ -878,16 +848,14 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sup_region: Region) { self.report_inference_failure(var_origin); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "first, the lifetime cannot outlive ", sup_region, "..."); self.note_region_origin(&sup_origin); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "but, the lifetime must be valid for ", sub_region, "..."); @@ -903,16 +871,14 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { region2: Region) { self.report_inference_failure(var_origin); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "first, the lifetime must be contained by ", region1, "..."); self.note_region_origin(&origin1); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "but, the lifetime must also be contained by ", region2, "..."); @@ -1353,7 +1319,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { }; match a_def { def::DefTy(did, _) | def::DefStruct(did) => { - let generics = ty::lookup_item_type(self.tcx, did).generics; + let generics = self.tcx.lookup_item_type(did).generics; let expected = generics.regions.len(subst::TypeSpace) as u32; @@ -1591,7 +1557,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { } infer::UpvarRegion(ref upvar_id, _) => { format!(" for capture of `{}` by closure", - ty::local_var_name_str(self.tcx, upvar_id.var_id).to_string()) + self.tcx.local_var_name_str(upvar_id.var_id).to_string()) } }; @@ -1604,7 +1570,8 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) { match *origin { - infer::Subtype(ref trace) => { + infer::Subtype(ref trace) | + infer::DefaultExistentialBound(ref trace) => { let desc = match trace.origin { infer::Misc(_) => { "types are compatible" @@ -1671,7 +1638,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { span, &format!( "...so that closure can access `{}`", - ty::local_var_name_str(self.tcx, upvar_id.var_id) + self.tcx.local_var_name_str(upvar_id.var_id) .to_string())) } infer::InfStackClosure(span) => { @@ -1695,9 +1662,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { span, &format!("...so that captured variable `{}` \ does not outlive the enclosing closure", - ty::local_var_name_str( - self.tcx, - id).to_string())); + self.tcx.local_var_name_str(id))); } infer::IndexSlice(span) => { self.tcx.sess.span_note( @@ -1793,16 +1758,12 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { pub trait Resolvable<'tcx> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Self; - fn contains_error(&self) -> bool; } impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> { infcx.resolve_type_vars_if_possible(self) } - fn contains_error(&self) -> bool { - ty::type_is_error(*self) - } } impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> { @@ -1810,9 +1771,6 @@ impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> { -> ty::TraitRef<'tcx> { infcx.resolve_type_vars_if_possible(self) } - fn contains_error(&self) -> bool { - ty::trait_ref_contains_error(self) - } } impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> { @@ -1822,10 +1780,6 @@ impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> { { infcx.resolve_type_vars_if_possible(self) } - - fn contains_error(&self) -> bool { - ty::trait_ref_contains_error(&self.0) - } } fn lifetimes_in_scope(tcx: &ty::ctxt, @@ -1902,7 +1856,7 @@ impl LifeGiver { } fn give_lifetime(&self) -> ast::Lifetime { - let mut lifetime; + let lifetime; loop { let mut s = String::from("'"); s.push_str(&num_to_string(self.counter.get())); diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index 1aa54863c203a..d65c4061f11eb 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -30,7 +30,7 @@ //! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type //! inferencer knows "so far". -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty_fold; use middle::ty_fold::TypeFoldable; use middle::ty_fold::TypeFolder; @@ -71,7 +71,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { Entry::Vacant(entry) => { let index = self.freshen_count; self.freshen_count += 1; - let t = ty::mk_infer(self.infcx.tcx, freshener(index)); + let t = self.infcx.tcx.mk_infer(freshener(index)); entry.insert(t); t } @@ -104,7 +104,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_needs_infer(t) && !ty::type_has_erasable_regions(t) { + if !t.needs_infer() && !t.has_erasable_regions() { return t; } diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index d6b03266b1fe7..adfd1a8a7d794 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -35,6 +35,16 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> { fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn will_change(&mut self, a: bool, b: bool) -> bool { + // Hmm, so the result of GLB will still be a LB if one or both + // sides change to 'static, but it may no longer be the GLB. + // I'm going to go with `a || b` here to be conservative, + // since the result of this operation may be affected, though + // I think it would mostly be more accepting than before (since the result + // would be a bigger region). + a || b + } + fn relate_with_variance>(&mut self, variance: ty::Variance, a: &T, diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 7b26f6b153733..64063623f6776 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -359,7 +359,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, where T: TypeFoldable<'tcx>, F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, { - unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| { + ty_fold::fold_regions(tcx, unbound_value, &mut false, |region, current_depth| { // we should only be encountering "escaping" late-bound regions here, // because the ones at the current level should have been replaced // with fresh variables @@ -369,7 +369,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, }); fldr(region, ty::DebruijnIndex::new(current_depth)) - })) + }) } impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { @@ -437,11 +437,10 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { let escaping_types = self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot); - let escaping_region_vars: FnvHashSet<_> = - escaping_types - .iter() - .flat_map(|&t| ty_fold::collect_regions(self.tcx, &t)) - .collect(); + let mut escaping_region_vars = FnvHashSet(); + for ty in &escaping_types { + ty_fold::collect_regions(self.tcx, ty, &mut escaping_region_vars); + } region_vars.retain(|®ion_vid| { let r = ty::ReInfer(ty::ReVar(region_vid)); @@ -507,7 +506,7 @@ pub fn construct_skolemized_substs<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, types: &mut subst::VecPerParamSpace>, defs: &[ty::TypeParameterDef<'tcx>]) { for def in defs { - let ty = ty::mk_param_from_def(tcx, def); + let ty = tcx.mk_param_from_def(def); types.push(def.space, ty); } } @@ -649,7 +648,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, // binder is that we encountered in `value`. The caller is // responsible for ensuring that (a) `value` contains at least one // binder and (b) that binder is the one we want to use. - let result = ty_fold::fold_regions(infcx.tcx, &value, |r, current_depth| { + let result = ty_fold::fold_regions(infcx.tcx, &value, &mut false, |r, current_depth| { match inv_skol_map.get(&r) { None => r, Some(br) => { diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index 9d993ead5ca20..f10d4adc8e5f2 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -35,6 +35,11 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> { fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn will_change(&mut self, a: bool, b: bool) -> bool { + // result will be 'static if a || b + a || b + } + fn relate_with_variance>(&mut self, variance: ty::Variance, a: &T, diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 2df335b5c3c0a..63f31921ec2ec 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -23,19 +23,25 @@ pub use self::freshen::TypeFreshener; pub use self::region_inference::GenericKind; use middle::free_region::FreeRegionMap; +use middle::mem_categorization as mc; +use middle::mem_categorization::McResult; +use middle::region::CodeExtent; use middle::subst; use middle::subst::Substs; +use middle::subst::Subst; +use middle::traits::{self, FulfillmentContext, Normalized, + SelectionContext, ObligationCause}; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric}; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; use middle::ty_relate::{Relate, RelateResult, TypeRelation}; use rustc_data_structures::unify::{self, UnificationTable}; -use std::cell::{RefCell}; +use std::cell::{RefCell, Ref}; use std::fmt; use syntax::ast; use syntax::codemap; -use syntax::codemap::Span; -use util::nodemap::FnvHashMap; +use syntax::codemap::{Span, DUMMY_SP}; +use util::nodemap::{FnvHashMap, NodeMap}; use self::combine::CombineFields; use self::region_inference::{RegionVarBindings, RegionSnapshot}; @@ -64,6 +70,8 @@ pub type fres = Result; // "fixup result" pub struct InferCtxt<'a, 'tcx: 'a> { pub tcx: &'a ty::ctxt<'tcx>, + pub tables: &'a RefCell>, + // We instantiate UnificationTable with bounds because the // types that might instantiate a general type variable have an // order, represented by its upper and lower bounds. @@ -77,6 +85,19 @@ pub struct InferCtxt<'a, 'tcx: 'a> { // For region variables. region_vars: RegionVarBindings<'a, 'tcx>, + + pub parameter_environment: ty::ParameterEnvironment<'a, 'tcx>, + + pub fulfillment_cx: RefCell>, + + // This is a temporary field used for toggling on normalization in the inference context, + // as we move towards the approach described here: + // https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293 + // At a point sometime in the future normalization will be done by the typing context + // directly. + normalize: bool, + + err_count_on_creation: usize, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -173,6 +194,9 @@ pub enum SubregionOrigin<'tcx> { // Arose from a subtyping relation Subtype(TypeTrace<'tcx>), + // Arose from a subtyping relation + DefaultExistentialBound(TypeTrace<'tcx>), + // Stack-allocated closures cannot outlive innermost loop // or function so as to ensure we only require finite stack InfStackClosure(Span), @@ -309,17 +333,39 @@ pub fn fixup_err_to_string(f: fixup_err) -> String { } } -pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>) +/// errors_will_be_reported is required to proxy to the fulfillment context +/// FIXME -- a better option would be to hold back on modifying +/// the global cache until we know that all dependent obligations +/// are also satisfied. In that case, we could actually remove +/// this boolean flag, and we'd also avoid the problem of squelching +/// duplicate errors that occur across fns. +pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>, + tables: &'a RefCell>, + param_env: Option>, + errors_will_be_reported: bool) -> InferCtxt<'a, 'tcx> { InferCtxt { tcx: tcx, + tables: tables, type_variables: RefCell::new(type_variable::TypeVariableTable::new()), int_unification_table: RefCell::new(UnificationTable::new()), float_unification_table: RefCell::new(UnificationTable::new()), region_vars: RegionVarBindings::new(tcx), + parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()), + fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)), + normalize: false, + err_count_on_creation: tcx.sess.err_count() } } +pub fn normalizing_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>, + tables: &'a RefCell>) + -> InferCtxt<'a, 'tcx> { + let mut infcx = new_infer_ctxt(tcx, tables, None, false); + infcx.normalize = true; + infcx +} + /// Computes the least upper-bound of `a` and `b`. If this is not possible, reports an error and /// returns ty::err. pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, @@ -431,6 +477,149 @@ pub struct CombinedSnapshot { region_vars_snapshot: RegionSnapshot, } +pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T + where T : TypeFoldable<'tcx> + HasTypeFlags +{ + debug!("normalize_associated_type(t={:?})", value); + + let value = erase_regions(tcx, value); + + if !value.has_projection_types() { + return value; + } + + let infcx = new_infer_ctxt(tcx, &tcx.tables, None, true); + let mut selcx = traits::SelectionContext::new(&infcx); + let cause = traits::ObligationCause::dummy(); + let traits::Normalized { value: result, obligations } = + traits::normalize(&mut selcx, cause, &value); + + debug!("normalize_associated_type: result={:?} obligations={:?}", + result, + obligations); + + let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut(); + + for obligation in obligations { + fulfill_cx.register_predicate_obligation(&infcx, obligation); + } + + let result = drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result); + + result +} + +pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span, + infcx: &InferCtxt<'a,'tcx>, + fulfill_cx: &mut traits::FulfillmentContext<'tcx>, + result: &T) + -> T + where T : TypeFoldable<'tcx> +{ + match drain_fulfillment_cx(infcx, fulfill_cx, result) { + Ok(v) => v, + Err(errors) => { + infcx.tcx.sess.span_bug( + span, + &format!("Encountered errors `{:?}` fulfilling during trans", + errors)); + } + } +} + +/// Finishes processes any obligations that remain in the fulfillment +/// context, and then "freshens" and returns `result`. This is +/// primarily used during normalization and other cases where +/// processing the obligations in `fulfill_cx` may cause type +/// inference variables that appear in `result` to be unified, and +/// hence we need to process those obligations to get the complete +/// picture of the type. +pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + fulfill_cx: &mut traits::FulfillmentContext<'tcx>, + result: &T) + -> Result>> + where T : TypeFoldable<'tcx> +{ + debug!("drain_fulfillment_cx(result={:?})", + result); + + // In principle, we only need to do this so long as `result` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + match fulfill_cx.select_all_or_error(infcx) { + Ok(()) => { } + Err(errors) => { + return Err(errors); + } + } + + // Use freshen to simultaneously replace all type variables with + // their bindings and replace all regions with 'static. This is + // sort of overkill because we do not expect there to be any + // unbound type variables, hence no `TyFresh` types should ever be + // inserted. + Ok(result.fold_with(&mut infcx.freshener())) +} + +/// Returns an equivalent value with all free regions removed (note +/// that late-bound regions remain, because they are important for +/// subtyping, but they are anonymized and normalized as well). This +/// is a stronger, caching version of `ty_fold::erase_regions`. +pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T + where T : TypeFoldable<'tcx> +{ + let value1 = value.fold_with(&mut RegionEraser(cx)); + debug!("erase_regions({:?}) = {:?}", + value, value1); + return value1; + + struct RegionEraser<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>); + + impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { self.0 } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match self.tcx().normalized_cache.borrow().get(&ty).cloned() { + None => {} + Some(u) => return u + } + + let t_norm = ty_fold::super_fold_ty(self, ty); + self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm); + return t_norm; + } + + fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder + where T : TypeFoldable<'tcx> + { + let u = self.tcx().anonymize_late_bound_regions(t); + ty_fold::super_fold_binder(self, &u) + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + // because late-bound regions affect subtyping, we can't + // erase the bound/free distinction, but we can replace + // all free regions with 'static. + // + // Note that we *CAN* replace early-bound regions -- the + // type system never "sees" those, they get substituted + // away. In trans, they will always be erased to 'static + // whenever a substitution occurs. + match r { + ty::ReLateBound(..) => r, + _ => ty::ReStatic + } + } + + fn fold_substs(&mut self, + substs: &subst::Substs<'tcx>) + -> subst::Substs<'tcx> { + subst::Substs { regions: subst::ErasedRegions, + types: substs.types.fold_with(self) } + } + } +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn freshen>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) @@ -472,7 +661,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { -> CombineFields<'a, 'tcx> { CombineFields {infcx: self, a_is_expected: a_is_expected, - trace: trace} + trace: trace, + cause: None} } // public so that it can be used from the rustc_driver unit tests @@ -772,11 +962,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn next_ty_var(&self) -> Ty<'tcx> { - ty::mk_var(self.tcx, self.next_ty_var_id(false)) + self.tcx.mk_var(self.next_ty_var_id(false)) } pub fn next_diverging_ty_var(&self) -> Ty<'tcx> { - ty::mk_var(self.tcx, self.next_ty_var_id(true)) + self.tcx.mk_var(self.next_ty_var_id(true)) } pub fn next_ty_vars(&self, n: usize) -> Vec> { @@ -852,6 +1042,49 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.region_vars.new_bound(debruijn) } + /// Apply `adjustment` to the type of `expr` + pub fn adjust_expr_ty(&self, + expr: &ast::Expr, + adjustment: Option<&ty::AutoAdjustment<'tcx>>) + -> Ty<'tcx> + { + let raw_ty = self.expr_ty(expr); + let raw_ty = self.shallow_resolve(raw_ty); + let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty); + raw_ty.adjust(self.tcx, + expr.span, + expr.id, + adjustment, + |method_call| self.tables + .borrow() + .method_map + .get(&method_call) + .map(|method| resolve_ty(method.ty))) + } + + pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> { + match self.tables.borrow().node_types.get(&id) { + Some(&t) => t, + // FIXME + None if self.tcx.sess.err_count() - self.err_count_on_creation != 0 => + self.tcx.types.err, + None => { + self.tcx.sess.bug( + &format!("no type for node {}: {} in fcx", + id, self.tcx.map.node_to_string(id))); + } + } + } + + pub fn expr_ty(&self, ex: &ast::Expr) -> Ty<'tcx> { + match self.tables.borrow().node_types.get(&ex.id) { + Some(&t) => t, + None => { + self.tcx.sess.bug(&format!("no type for expr in fcx")); + } + } + } + pub fn resolve_regions_and_report_errors(&self, free_regions: &FreeRegionMap, subject_node_id: ast::NodeId) { @@ -926,6 +1159,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { value.fold_with(&mut r) } + /// Resolves all type variables in `t` and then, if any were left + /// unresolved, substitutes an error type. This is used after the + /// main checking when doing a second pass before writeback. The + /// justification is that writeback will produce an error for + /// these unconstrained type variables. + fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult> { + let ty = self.resolve_type_vars_if_possible(t); + if ty.has_infer_types() || ty.references_error() { Err(()) } else { Ok(ty) } + } + pub fn fully_resolve>(&self, value: &T) -> fres { /*! * Attempts to resolve all type/region variables in @@ -973,20 +1216,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty)); - match resolved_expected { - Some(t) if ty::type_is_error(t) => (), - _ => { - let error_str = err.map_or("".to_string(), |t_err| { - format!(" ({})", t_err) - }); + if !resolved_expected.references_error() { + let error_str = err.map_or("".to_string(), |t_err| { + format!(" ({})", t_err) + }); - self.tcx.sess.span_err(sp, &format!("{}{}", - mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty), - error_str)); + self.tcx.sess.span_err(sp, &format!("{}{}", + mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty), + error_str)); - if let Some(err) = err { - ty::note_and_explain_type_err(self.tcx, err, sp) - } + if let Some(err) = err { + self.tcx.note_and_explain_type_err(err, sp) } } } @@ -1001,7 +1241,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); // Don't report an error if actual type is TyError. - if ty::type_is_error(actual_ty) { + if actual_ty.references_error() { return; } @@ -1068,6 +1308,108 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.equate(true, trace).relate(a, b) }).map(|_| ()) } + + pub fn node_ty(&self, id: ast::NodeId) -> McResult> { + let ty = self.node_type(id); + self.resolve_type_vars_or_error(&ty) + } + + pub fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult> { + let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id)); + self.resolve_type_vars_or_error(&ty) + } + + pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool { + let ty = self.resolve_type_vars_if_possible(&ty); + !traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundCopy, span) + // FIXME(@jroesch): should be able to use: + // ty.moves_by_default(&self.parameter_environment, span) + } + + pub fn node_method_ty(&self, method_call: ty::MethodCall) + -> Option> { + self.tables + .borrow() + .method_map + .get(&method_call) + .map(|method| method.ty) + .map(|ty| self.resolve_type_vars_if_possible(&ty)) + } + + pub fn node_method_id(&self, method_call: ty::MethodCall) + -> Option { + self.tables + .borrow() + .method_map + .get(&method_call) + .map(|method| method.def_id) + } + + pub fn adjustments(&self) -> Ref>> { + fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>) + -> &'a NodeMap> { + &tables.adjustments + } + + Ref::map(self.tables.borrow(), project_adjustments) + } + + pub fn is_method_call(&self, id: ast::NodeId) -> bool { + self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id)) + } + + pub fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { + self.tcx.region_maps.temporary_scope(rvalue_id) + } + + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { + self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() + } + + pub fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> { + &self.parameter_environment + } + + pub fn closure_kind(&self, + def_id: ast::DefId) + -> Option + { + self.tables.borrow().closure_kinds.get(&def_id).cloned() + } + + pub fn closure_type(&self, + def_id: ast::DefId, + substs: &subst::Substs<'tcx>) + -> ty::ClosureTy<'tcx> + { + + let closure_ty = self.tables + .borrow() + .closure_tys + .get(&def_id) + .unwrap() + .subst(self.tcx, substs); + + if self.normalize { + normalize_associated_type(&self.tcx, &closure_ty) + } else { + closure_ty + } + } + + pub fn closure_upvars(&self, + def_id: ast::DefId, + substs: &Substs<'tcx>) + -> Option>> + { + let result = ty::ctxt::closure_upvars(self, def_id, substs); + + if self.normalize { + normalize_associated_type(&self.tcx, &result) + } else { + result + } + } } impl<'tcx> TypeTrace<'tcx> { @@ -1125,6 +1467,7 @@ impl<'tcx> SubregionOrigin<'tcx> { pub fn span(&self) -> Span { match *self { Subtype(ref a) => a.span(), + DefaultExistentialBound(ref a) => a.span(), InfStackClosure(a) => a, InvokeClosure(a) => a, DerefPointer(a) => a, diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index e397f35685559..891a39e723a62 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -1358,9 +1358,56 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } } + // Check for future hostile edges tied to a bad default + self.report_future_hostility(&graph); + (0..self.num_vars() as usize).map(|idx| var_data[idx].value).collect() } + fn report_future_hostility(&self, graph: &RegionGraph) { + let constraints = self.constraints.borrow(); + for edge in graph.all_edges() { + match constraints[&edge.data] { + SubregionOrigin::DefaultExistentialBound(_) => { + // this will become 'static in the future + } + _ => { continue; } + } + + // this constraint will become a 'static constraint in the + // future, so walk outward and see if we have any hard + // bounds that could not be inferred to 'static + for nid in graph.depth_traverse(edge.target()) { + for (_, succ) in graph.outgoing_edges(nid) { + match succ.data { + ConstrainVarSubReg(_, r) => { + match r { + ty::ReStatic | ty::ReInfer(_) => { + /* OK */ + } + ty::ReFree(_) | ty::ReScope(_) | ty::ReEmpty => { + span_warn!( + self.tcx.sess, + constraints[&edge.data].span(), + E0398, + "this code may fail to compile in Rust 1.3 due to \ + the proposed change in object lifetime bound defaults"); + return; // only issue the warning once per fn + } + ty::ReEarlyBound(..) | ty::ReLateBound(..) => { + self.tcx.sess.span_bug( + constraints[&succ.data].span(), + "relation to bound region"); + } + } + } + _ => { } + } + } + } + } + } + fn construct_graph(&self) -> RegionGraph { let num_vars = self.num_vars(); @@ -1672,7 +1719,7 @@ impl<'tcx> GenericKind<'tcx> { GenericKind::Param(ref p) => p.to_ty(tcx), GenericKind::Projection(ref p) => - ty::mk_projection(tcx, p.trait_ref.clone(), p.item_name), + tcx.mk_projection(p.trait_ref.clone(), p.item_name), } } } diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index b67437fd12781..41a0d373fba43 100644 --- a/src/librustc/middle/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -9,7 +9,7 @@ // except according to those terms. use super::{InferCtxt, fixup_err, fres, unresolved_ty, unresolved_int_ty, unresolved_float_ty}; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty_fold::{self, TypeFoldable}; /////////////////////////////////////////////////////////////////////////// @@ -36,7 +36,7 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_has_ty_infer(t) { + if !t.has_infer_types() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { let t0 = self.infcx.shallow_resolve(t); @@ -75,7 +75,7 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_needs_infer(t) { + if !t.needs_infer() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { let t = self.infcx.shallow_resolve(t); diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 2b7f9a74b8bd5..7c40e96a2f7a5 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -10,16 +10,17 @@ use super::combine::{self, CombineFields}; use super::higher_ranked::HigherRankedRelations; -use super::Subtype; +use super::SubregionOrigin; use super::type_variable::{SubtypeOf, SupertypeOf}; use middle::ty::{self, Ty}; use middle::ty::TyVar; -use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use middle::ty_relate::{Cause, Relate, RelateResult, TypeRelation}; +use std::mem; /// "Greatest lower bound" (common subtype) pub struct Sub<'a, 'tcx: 'a> { - fields: CombineFields<'a, 'tcx> + fields: CombineFields<'a, 'tcx>, } impl<'a, 'tcx> Sub<'a, 'tcx> { @@ -33,6 +34,25 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> { fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.infcx.tcx } fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn with_cause(&mut self, cause: Cause, f: F) -> R + where F: FnOnce(&mut Self) -> R + { + debug!("sub with_cause={:?}", cause); + let old_cause = mem::replace(&mut self.fields.cause, Some(cause)); + let r = f(self); + debug!("sub old_cause={:?}", old_cause); + self.fields.cause = old_cause; + r + } + + fn will_change(&mut self, a: bool, b: bool) -> bool { + // if we have (Foo+'a) <: (Foo+'b), this requires that 'a:'b. + // So if 'a becomes 'static, no additional errors can occur. + // OTOH, if 'a stays the same, but 'b becomes 'static, we + // could have a problem. + !a && b + } + fn relate_with_variance>(&mut self, variance: ty::Variance, a: &T, @@ -84,11 +104,14 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> { } fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { - debug!("{}.regions({:?}, {:?})", - self.tag(), - a, - b); - let origin = Subtype(self.fields.trace.clone()); + debug!("{}.regions({:?}, {:?}) self.cause={:?}", + self.tag(), a, b, self.fields.cause); + let origin = match self.fields.cause { + Some(Cause::ExistentialRegionBound(true)) => + SubregionOrigin::DefaultExistentialBound(self.fields.trace.clone()), + _ => + SubregionOrigin::Subtype(self.fields.trace.clone()), + }; self.fields.infcx.region_vars.make_subregion(origin, a, b); Ok(a) } diff --git a/src/librustc/middle/infer/unify_key.rs b/src/librustc/middle/infer/unify_key.rs index 6b23e2c5029b8..c13cec45dc44a 100644 --- a/src/librustc/middle/infer/unify_key.rs +++ b/src/librustc/middle/infer/unify_key.rs @@ -26,8 +26,8 @@ impl UnifyKey for ty::IntVid { impl<'tcx> ToType<'tcx> for IntVarValue { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { match *self { - ty::IntType(i) => ty::mk_mach_int(tcx, i), - ty::UintType(i) => ty::mk_mach_uint(tcx, i), + ty::IntType(i) => tcx.mk_mach_int(i), + ty::UintType(i) => tcx.mk_mach_uint(i), } } } @@ -43,6 +43,6 @@ impl UnifyKey for ty::FloatVid { impl<'tcx> ToType<'tcx> for ast::FloatTy { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { - ty::mk_mach_float(tcx, *self) + tcx.mk_mach_float(*self) } } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index c4d924d676c89..c5f6f0126de37 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -13,7 +13,7 @@ use metadata::csearch; use middle::def::DefFn; use middle::subst::{Subst, Substs, EnumeratedItems}; use middle::ty::{TransmuteRestriction, ctxt, TyBareFn}; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags}; use std::fmt; @@ -30,7 +30,7 @@ pub fn check_crate(tcx: &ctxt) { tcx: tcx, param_envs: Vec::new(), dummy_sized_ty: tcx.types.isize, - dummy_unsized_ty: ty::mk_vec(tcx, tcx.types.isize, None), + dummy_unsized_ty: tcx.mk_slice(tcx.types.isize), }; visit::walk_crate(&mut visitor, tcx.map.krate()); } @@ -54,7 +54,7 @@ struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { - let intrinsic = match ty::lookup_item_type(self.tcx, def_id).ty.sty { + let intrinsic = match self.tcx.lookup_item_type(def_id).ty.sty { ty::TyBareFn(_, ref bfty) => bfty.abi == RustIntrinsic, _ => return false }; @@ -92,8 +92,8 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> { // Simple case: no type parameters involved. if - !ty::type_has_params(from) && !ty::type_has_self(from) && - !ty::type_has_params(to) && !ty::type_has_self(to) + !from.has_param_types() && !from.has_self_ty() && + !to.has_param_types() && !to.has_self_ty() { let restriction = TransmuteRestriction { span: span, @@ -160,8 +160,8 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> { // In all cases, we keep the original unsubstituted types // around for error reporting. - let from_tc = ty::type_contents(self.tcx, from); - let to_tc = ty::type_contents(self.tcx, to); + let from_tc = from.type_contents(self.tcx); + let to_tc = to.type_contents(self.tcx); if from_tc.interior_param() || to_tc.interior_param() { span_err!(self.tcx.sess, span, E0139, "cannot transmute to or from a type that contains \ @@ -213,7 +213,7 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> { debug!("with_each_combination: space={:?}, index={}, param_ty={:?}", space, index, param_ty); - if !ty::type_is_sized(Some(param_env), self.tcx, span, param_ty) { + if !param_ty.is_sized(param_env, span) { debug!("with_each_combination: param_ty is not known to be sized"); substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty; @@ -253,9 +253,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &ast::Expr) { if let ast::ExprPath(..) = expr.node { - match ty::resolve_expr(self.tcx, expr) { + match self.tcx.resolve_expr(expr) { DefFn(did, _) if self.def_id_is_transmute(did) => { - let typ = ty::node_id_to_type(self.tcx, expr.id); + let typ = self.tcx.node_id_to_type(expr.id); match typ.sty { TyBareFn(_, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { if let ty::FnConverging(to) = bare_fn_ty.sig.0.output { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 9bcc251725c00..37460531dbdbf 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -110,11 +110,9 @@ use self::LiveNodeKind::*; use self::VarKind::*; use middle::def::*; -use middle::mem_categorization::Typer; use middle::pat_util; use middle::region; use middle::ty; -use middle::ty::ClosureTyper; use lint; use util::nodemap::NodeMap; @@ -465,7 +463,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { // in better error messages than just pointing at the closure // construction site. let mut call_caps = Vec::new(); - ty::with_freevars(ir.tcx, expr.id, |freevars| { + ir.tcx.with_freevars(expr.id, |freevars| { for fv in freevars { if let DefLocal(rv) = fv.def { let fv_ln = ir.add_live_node(FreeVarNode(fv.span)); @@ -1137,9 +1135,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } ast::ExprCall(ref f, ref args) => { - let diverges = !self.ir.tcx.is_method_call(expr.id) && { - ty::ty_fn_ret(ty::expr_ty_adjusted(self.ir.tcx, &**f)).diverges() - }; + let diverges = !self.ir.tcx.is_method_call(expr.id) && + self.ir.tcx.expr_ty_adjusted(&**f).fn_ret().diverges(); let succ = if diverges { self.s.exit_ln } else { @@ -1151,9 +1148,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ast::ExprMethodCall(_, _, ref args) => { let method_call = ty::MethodCall::expr(expr.id); - let method_ty = self.ir.tcx.method_map.borrow().get(&method_call).unwrap().ty; - let diverges = ty::ty_fn_ret(method_ty).diverges(); - let succ = if diverges { + let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty; + let succ = if method_ty.fn_ret().diverges() { self.s.exit_ln } else { succ @@ -1496,12 +1492,11 @@ fn check_fn(_v: &Liveness, impl<'a, 'tcx> Liveness<'a, 'tcx> { fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> { - let fn_ty = ty::node_id_to_type(self.ir.tcx, id); + let fn_ty = self.ir.tcx.node_id_to_type(id); match fn_ty.sty { ty::TyClosure(closure_def_id, substs) => self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), - _ => - ty::ty_fn_ret(fn_ty), + _ => fn_ty.fn_ret() } } @@ -1514,8 +1509,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { { // within the fn body, late-bound regions are liberated: let fn_ret = - ty::liberate_late_bound_regions( - self.ir.tcx, + self.ir.tcx.liberate_late_bound_regions( region::DestructionScopeData::new(body.id), &self.fn_ret(id)); @@ -1523,14 +1517,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ty::FnConverging(t_ret) if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() => { - if ty::type_is_nil(t_ret) { + if t_ret.is_nil() { // for nil return types, it is ok to not return a value expl. } else { let ends_with_stmt = match body.expr { None if !body.stmts.is_empty() => match body.stmts.first().unwrap().node { ast::StmtSemi(ref e, _) => { - ty::expr_ty(self.ir.tcx, &**e) == t_ret + self.ir.tcx.expr_ty(&**e) == t_ret }, _ => false }, diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index ca8de74b35bda..f506de525ff9c 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -73,17 +73,16 @@ pub use self::categorization::*; use self::Aliasability::*; use ast_map; +use middle::infer; use middle::check_const; use middle::def; use middle::region; use middle::ty::{self, Ty}; -use util::nodemap::NodeMap; use syntax::ast::{MutImmutable, MutMutable}; use syntax::ast; use syntax::codemap::Span; -use std::cell::RefCell; use std::fmt; use std::rc::Rc; @@ -255,46 +254,13 @@ impl ast_node for ast::Pat { fn span(&self) -> Span { self.span } } -pub struct MemCategorizationContext<'t,TYPER:'t> { - typer: &'t TYPER -} - -impl<'t,TYPER:'t> Copy for MemCategorizationContext<'t,TYPER> {} -impl<'t,TYPER:'t> Clone for MemCategorizationContext<'t,TYPER> { - fn clone(&self) -> MemCategorizationContext<'t,TYPER> { *self } +#[derive(Copy, Clone)] +pub struct MemCategorizationContext<'t, 'a: 't, 'tcx : 'a> { + pub typer: &'t infer::InferCtxt<'a, 'tcx>, } pub type McResult = Result; -/// The `Typer` trait provides the interface for the mem-categorization -/// module to the results of the type check. It can be used to query -/// the type assigned to an expression node, to inquire after adjustments, -/// and so on. -/// -/// This interface is needed because mem-categorization is used from -/// two places: `regionck` and `borrowck`. `regionck` executes before -/// type inference is complete, and hence derives types and so on from -/// intermediate tables. This also implies that type errors can occur, -/// and hence `node_ty()` and friends return a `Result` type -- any -/// error will propagate back up through the mem-categorization -/// routines. -/// -/// In the borrow checker, in contrast, type checking is complete and we -/// know that no errors have occurred, so we simply consult the tcx and we -/// can be sure that only `Ok` results will occur. -pub trait Typer<'tcx> : ty::ClosureTyper<'tcx> { - fn node_ty(&self, id: ast::NodeId) -> McResult>; - fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult>; - fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool; - fn node_method_ty(&self, method_call: ty::MethodCall) -> Option>; - fn node_method_origin(&self, method_call: ty::MethodCall) - -> Option>; - fn adjustments<'a>(&'a self) -> &'a RefCell>>; - fn is_method_call(&self, id: ast::NodeId) -> bool; - fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option; - fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option; -} - impl MutabilityCategory { pub fn from_mutbl(m: ast::Mutability) -> MutabilityCategory { let ret = match m { @@ -391,13 +357,13 @@ impl MutabilityCategory { } } -impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { - pub fn new(typer: &'t TYPER) -> MemCategorizationContext<'t,TYPER> { +impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { + pub fn new(typer: &'t infer::InferCtxt<'a, 'tcx>) -> MemCategorizationContext<'t, 'a, 'tcx> { MemCategorizationContext { typer: typer } } - fn tcx(&self) -> &'t ty::ctxt<'tcx> { - self.typer.tcx() + fn tcx(&self) -> &'a ty::ctxt<'tcx> { + self.typer.tcx } fn expr_ty(&self, expr: &ast::Expr) -> McResult> { @@ -406,9 +372,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult> { let unadjusted_ty = try!(self.expr_ty(expr)); - Ok(ty::adjust_ty(self.tcx(), expr.span, expr.id, unadjusted_ty, - self.typer.adjustments().borrow().get(&expr.id), - |method_call| self.typer.node_method_ty(method_call))) + Ok(unadjusted_ty.adjust( + self.tcx(), expr.span, expr.id, + self.typer.adjustments().get(&expr.id), + |method_call| self.typer.node_method_ty(method_call))) } fn node_ty(&self, id: ast::NodeId) -> McResult> { @@ -426,7 +393,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { // a bind-by-ref means that the base_ty will be the type of the ident itself, // but what we want here is the type of the underlying value being borrowed. // So peel off one-level, turning the &T into T. - match ty::deref(base_ty, false) { + match base_ty.builtin_deref(false) { Some(t) => t.ty, None => { return Err(()); } } @@ -439,7 +406,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } pub fn cat_expr(&self, expr: &ast::Expr) -> McResult> { - match self.typer.adjustments().borrow().get(&expr.id) { + match self.typer.adjustments().get(&expr.id) { None => { // No adjustments. self.cat_expr_unadjusted(expr) @@ -927,14 +894,13 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { let base_cmt = match method_ty { Some(method_ty) => { let ref_ty = - ty::no_late_bound_regions( - self.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap(); + self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap(); self.cat_rvalue_node(node.id(), node.span(), ref_ty) } None => base_cmt }; let base_cmt_ty = base_cmt.ty; - match ty::deref(base_cmt_ty, true) { + match base_cmt_ty.builtin_deref(true) { Some(mt) => { let ret = self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, @@ -1023,11 +989,11 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty); // FIXME(#20649) -- why are we using the `self_ty` as the element type...? - let self_ty = ty::ty_fn_sig(method_ty).input(0); - ty::no_late_bound_regions(self.tcx(), &self_ty).unwrap() + let self_ty = method_ty.fn_sig().input(0); + self.tcx().no_late_bound_regions(&self_ty).unwrap() } None => { - match ty::array_element_ty(self.tcx(), base_cmt.ty) { + match base_cmt.ty.builtin_index() { Some(ty) => ty, None => { return Err(()); @@ -1081,7 +1047,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { span:elt.span(), cat:cat_deref(base_cmt.clone(), 0, ptr), mutbl:m, - ty: match ty::deref(base_cmt.ty, false) { + ty: match base_cmt.ty.builtin_deref(false) { Some(mt) => mt.ty, None => self.tcx().sess.bug("Found non-derefable type") }, @@ -1175,7 +1141,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } pub fn cat_pattern(&self, cmt: cmt<'tcx>, pat: &ast::Pat, mut op: F) -> McResult<()> - where F: FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat), + where F: FnMut(&MemCategorizationContext<'t, 'a, 'tcx>, cmt<'tcx>, &ast::Pat), { self.cat_pattern_(cmt, pat, &mut op) } @@ -1183,7 +1149,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { // FIXME(#19596) This is a workaround, but there should be a better way to do this fn cat_pattern_(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F) -> McResult<()> - where F : FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat), + where F : FnMut(&MemCategorizationContext<'t, 'a, 'tcx>, cmt<'tcx>, &ast::Pat), { // Here, `cmt` is the categorization for the value being // matched and pat is the pattern it is being matched against. @@ -1244,7 +1210,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { let cmt = match opt_def { Some(def::DefVariant(enum_did, variant_did, _)) // univariant enums do not need downcasts - if !ty::enum_is_univariant(self.tcx(), enum_did) => { + if !self.tcx().enum_is_univariant(enum_did) => { self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) } _ => cmt @@ -1375,7 +1341,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { // types are generated by method resolution and always have // all late-bound regions fully instantiated, so we just want // to skip past the binder. - ty::no_late_bound_regions(self.tcx(), &ty::ty_fn_ret(method_ty)) + self.tcx().no_late_bound_regions(&method_ty.fn_ret()) .unwrap() .unwrap() // overloaded ops do not diverge, either } @@ -1583,7 +1549,7 @@ impl<'tcx> fmt::Debug for categorization<'tcx> { cat_static_item => write!(f, "static"), cat_rvalue(r) => write!(f, "rvalue({:?})", r), cat_local(id) => { - let name = ty::tls::with(|tcx| ty::local_var_name_str(tcx, id)); + let name = ty::tls::with(|tcx| tcx.local_var_name_str(id)); write!(f, "local({})", name) } cat_upvar(upvar) => { diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 0cb302d79b866..15a1ba853245b 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -192,7 +192,7 @@ pub fn simple_identifier<'a>(pat: &'a ast::Pat) -> Option<&'a ast::Ident> { } pub fn def_to_path(tcx: &ty::ctxt, id: ast::DefId) -> ast::Path { - ty::with_path(tcx, id, |path| ast::Path { + tcx.with_path(id, |path| ast::Path { global: false, segments: path.last().map(|elem| ast::PathSegment { identifier: ast::Ident::new(elem.name()), diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 0bbcfa700388c..d588f7c6070ce 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -128,8 +128,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { } ast::ExprMethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); - match (*self.tcx.method_map.borrow()).get(&method_call).unwrap().origin { - ty::MethodStatic(def_id) => { + let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id; + match self.tcx.impl_or_trait_item(def_id).container() { + ty::ImplContainer(_) => { if is_local(def_id) { if self.def_id_represents_local_inlined_item(def_id) { self.worklist.push(def_id.node) @@ -137,7 +138,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { self.reachable_symbols.insert(def_id.node); } } - _ => {} + ty::TraitContainer(_) => {} } } _ => {} diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index dad41bdd3a394..46be4b752266e 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -382,7 +382,7 @@ pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool, // items. ast::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => { let trait_did = tcx.def_map.borrow().get(&t.ref_id).unwrap().def_id(); - let trait_items = ty::trait_items(tcx, trait_did); + let trait_items = tcx.trait_items(trait_did); for impl_item in impl_items { let item = trait_items.iter().find(|item| { @@ -406,37 +406,13 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, ast::ExprMethodCall(i, _, _) => { span = i.span; let method_call = ty::MethodCall::expr(e.id); - match tcx.method_map.borrow().get(&method_call) { - Some(method) => { - match method.origin { - ty::MethodStatic(def_id) => { - def_id - } - ty::MethodStaticClosure(def_id) => { - def_id - } - ty::MethodTypeParam(ty::MethodParam { - ref trait_ref, - method_num: index, - .. - }) | - ty::MethodTraitObject(ty::MethodObject { - ref trait_ref, - method_num: index, - .. - }) => { - ty::trait_item(tcx, trait_ref.def_id, index).def_id() - } - } - } - None => return - } + tcx.tables.borrow().method_map[&method_call].def_id } ast::ExprField(ref base_e, ref field) => { span = field.span; - match ty::expr_ty_adjusted(tcx, base_e).sty { + match tcx.expr_ty_adjusted(base_e).sty { ty::TyStruct(did, _) => { - ty::lookup_struct_fields(tcx, did) + tcx.lookup_struct_fields(did) .iter() .find(|f| f.name == field.node.name) .unwrap_or_else(|| { @@ -451,9 +427,9 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, } ast::ExprTupField(ref base_e, ref field) => { span = field.span; - match ty::expr_ty_adjusted(tcx, base_e).sty { + match tcx.expr_ty_adjusted(base_e).sty { ty::TyStruct(did, _) => { - ty::lookup_struct_fields(tcx, did) + tcx.lookup_struct_fields(did) .get(field.node) .unwrap_or_else(|| { tcx.sess.span_bug(field.span, @@ -468,10 +444,10 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, } } ast::ExprStruct(_, ref expr_fields, _) => { - let type_ = ty::expr_ty(tcx, e); + let type_ = tcx.expr_ty(e); match type_.sty { ty::TyStruct(did, _) => { - let struct_fields = ty::lookup_struct_fields(tcx, did); + let struct_fields = tcx.lookup_struct_fields(did); // check the stability of each field that appears // in the construction expression. for field in expr_fields { @@ -525,11 +501,11 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat, debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } - let did = match ty::pat_ty_opt(tcx, pat) { + let did = match tcx.pat_ty_opt(pat) { Some(&ty::TyS { sty: ty::TyStruct(did, _), .. }) => did, Some(_) | None => return, }; - let struct_fields = ty::lookup_struct_fields(tcx, did); + let struct_fields = tcx.lookup_struct_fields(did); match pat.node { // Foo(a, b, c) ast::PatEnum(_, Some(ref pat_fields)) => { @@ -574,7 +550,7 @@ fn is_internal(tcx: &ty::ctxt, span: Span) -> bool { } fn is_staged_api(tcx: &ty::ctxt, id: DefId) -> bool { - match ty::trait_item_of_item(tcx, id) { + match tcx.trait_item_of_item(id) { Some(ty::MethodTraitItemId(trait_method_id)) if trait_method_id != id => { is_staged_api(tcx, trait_method_id) @@ -602,7 +578,7 @@ fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stabil debug!("lookup(id={:?})", id); // is this definition the implementation of a trait method? - match ty::trait_item_of_item(tcx, id) { + match tcx.trait_item_of_item(id) { Some(ty::MethodTraitItemId(trait_method_id)) if trait_method_id != id => { debug!("lookup: trait_method_id={:?}", trait_method_id); return lookup(tcx, trait_method_id) @@ -617,8 +593,8 @@ fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stabil }; item_stab.or_else(|| { - if ty::is_impl(tcx, id) { - if let Some(trait_id) = ty::trait_id_of_impl(tcx, id) { + if tcx.is_impl(id) { + if let Some(trait_id) = tcx.trait_id_of_impl(id) { // FIXME (#18969): for the time being, simply use the // stability of the trait to determine the stability of any // unmarked impls for it. See FIXME above for more details. diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index c3c29d0ade8df..4e98ef2753105 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -13,7 +13,7 @@ pub use self::ParamSpace::*; pub use self::RegionSubsts::*; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags, RegionEscape}; use middle::ty_fold::{self, TypeFoldable, TypeFolder}; use std::fmt; @@ -100,17 +100,6 @@ impl<'tcx> Substs<'tcx> { *self.types.get(ty_param_def.space, ty_param_def.index as usize) } - pub fn has_regions_escaping_depth(&self, depth: u32) -> bool { - self.types.iter().any(|&t| ty::type_escapes_depth(t, depth)) || { - match self.regions { - ErasedRegions => - false, - NonerasedRegions(ref regions) => - regions.iter().any(|r| r.escapes_depth(depth)), - } - } - } - pub fn self_ty(&self) -> Option> { self.types.get_self().cloned() } @@ -152,19 +141,25 @@ impl<'tcx> Substs<'tcx> { { let Substs { types, regions } = self; let types = types.with_vec(FnSpace, m_types); - let regions = regions.map(m_regions, - |r, m_regions| r.with_vec(FnSpace, m_regions)); + let regions = regions.map(|r| r.with_vec(FnSpace, m_regions)); + Substs { types: types, regions: regions } + } + + pub fn method_to_trait(self) -> Substs<'tcx> { + let Substs { mut types, regions } = self; + types.truncate(FnSpace, 0); + let regions = regions.map(|mut r| { r.truncate(FnSpace, 0); r }); Substs { types: types, regions: regions } } } impl RegionSubsts { - fn map(self, a: A, op: F) -> RegionSubsts where - F: FnOnce(VecPerParamSpace, A) -> VecPerParamSpace, + fn map(self, op: F) -> RegionSubsts where + F: FnOnce(VecPerParamSpace) -> VecPerParamSpace, { match self { ErasedRegions => ErasedRegions, - NonerasedRegions(r) => NonerasedRegions(op(r, a)) + NonerasedRegions(r) => NonerasedRegions(op(r)) } } @@ -632,7 +627,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_needs_subst(t) { + if !t.needs_subst() { return t; } @@ -729,10 +724,10 @@ impl<'a,'tcx> SubstFolder<'a,'tcx> { /// first case we do not increase the Debruijn index and in the second case we do. The reason /// is that only in the second case have we passed through a fn binder. fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - debug!("shift_regions(ty={:?}, region_binders_passed={:?}, type_has_escaping_regions={:?})", - ty, self.region_binders_passed, ty::type_has_escaping_regions(ty)); + debug!("shift_regions(ty={:?}, region_binders_passed={:?}, has_escaping_regions={:?})", + ty, self.region_binders_passed, ty.has_escaping_regions()); - if self.region_binders_passed == 0 || !ty::type_has_escaping_regions(ty) { + if self.region_binders_passed == 0 || !ty.has_escaping_regions() { return ty; } diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index a826836b10c62..977d0577e480f 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -38,8 +38,7 @@ pub fn overlapping_impls(infcx: &InferCtxt, impl1_def_id, impl2_def_id); - let param_env = &ty::empty_parameter_environment(infcx.tcx); - let selcx = &mut SelectionContext::intercrate(infcx, param_env); + let selcx = &mut SelectionContext::intercrate(infcx); infcx.probe(|_| { overlap(selcx, impl1_def_id, impl2_def_id) || overlap(selcx, impl2_def_id, impl1_def_id) }) @@ -111,7 +110,7 @@ pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRe // already if trait_ref.def_id.krate != ast::LOCAL_CRATE && - !ty::has_attr(tcx, trait_ref.def_id, "fundamental") + !tcx.has_attr(trait_ref.def_id, "fundamental") { debug!("trait_ref_is_knowable: trait is neither local nor fundamental"); return false; @@ -142,13 +141,13 @@ fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, let impl_substs = &substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id); let impl_trait_ref = - ty::impl_trait_ref(selcx.tcx(), impl_def_id).unwrap(); + 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 } = project::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); - let predicates = ty::lookup_predicates(selcx.tcx(), impl_def_id); + let predicates = selcx.tcx().lookup_predicates(impl_def_id); let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let Normalized { value: predicates, obligations: normalization_obligations2 } = project::normalize(selcx, ObligationCause::dummy(), &predicates); @@ -183,7 +182,7 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>, // We only except this routine to be invoked on implementations // of a trait, not inherent implementations. - let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap(); + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); debug!("orphan_check: trait_ref={:?}", trait_ref); // If the *trait* is local to the crate, ok. @@ -280,9 +279,9 @@ fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool ty::TyBox(..) | ty::TyRef(..) => true, ty::TyEnum(def_id, _) | ty::TyStruct(def_id, _) => - ty::has_attr(tcx, def_id, "fundamental"), + tcx.has_attr(def_id, "fundamental"), ty::TyTrait(ref data) => - ty::has_attr(tcx, data.principal_def_id(), "fundamental"), + tcx.has_attr(data.principal_def_id(), "fundamental"), _ => false } diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 8618f52152907..582873082a68b 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -25,7 +25,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use middle::infer::InferCtxt; -use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef, TraitRef}; +use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef}; use middle::ty_fold::TypeFoldable; use std::collections::HashMap; use std::fmt; @@ -79,14 +79,14 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, span: Span) -> Option { let def_id = trait_ref.def_id; let mut report = None; - for item in ty::get_attrs(infcx.tcx, def_id).iter() { + for item in infcx.tcx.get_attrs(def_id).iter() { if item.check_name("rustc_on_unimplemented") { let err_sp = if item.meta().span == DUMMY_SP { span } else { item.meta().span }; - let def = ty::lookup_trait_def(infcx.tcx, def_id); + let def = infcx.tcx.lookup_trait_def(def_id); let trait_str = def.trait_ref.to_string(); if let Some(ref istring) = item.value_str() { let mut generic_map = def.generics.types.iter_enumerated() @@ -245,7 +245,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref); let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref); - if !ty::type_is_error(actual_trait_ref.self_ty()) { + if !actual_trait_ref.self_ty().references_error() { span_err!(infcx.tcx.sess, obligation.cause.span, E0281, "type mismatch: the type `{}` implements the trait `{}`, \ but the trait `{}` is required ({})", @@ -260,7 +260,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, TraitNotObjectSafe(did) => { span_err!(infcx.tcx.sess, obligation.cause.span, E0038, "cannot convert to a trait object because trait `{}` is not object-safe", - ty::item_path_str(infcx.tcx, did)); + infcx.tcx.item_path_str(did)); for violation in object_safety_violations(infcx.tcx, did) { match violation { @@ -325,8 +325,8 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, let trait_ref = data.to_poly_trait_ref(); let self_ty = trait_ref.self_ty(); let all_types = &trait_ref.substs().types; - if all_types.iter().any(|&t| ty::type_is_error(t)) { - } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) { + if all_types.references_error() { + } else if all_types.needs_infer() { // This is kind of a hack: it frequently happens that some earlier // error prevents types from being fully inferred, and then we get // a bunch of uninteresting errors saying something like "(infcx: &InferCtxt<'a, 'tcx>, match *cause_code { ObligationCauseCode::MiscObligation => { } ObligationCauseCode::ItemObligation(item_def_id) => { - let item_name = ty::item_path_str(tcx, item_def_id); + let item_name = tcx.item_path_str(item_def_id); tcx.sess.span_note( cause_span, &format!("required by `{}`", item_name)); @@ -442,8 +442,8 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, } ObligationCauseCode::ClosureCapture(var_id, closure_span, builtin_bound) => { let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); - let trait_name = ty::item_path_str(tcx, def_id); - let name = ty::local_var_name_str(tcx, var_id); + let trait_name = tcx.item_path_str(def_id); + let name = tcx.local_var_name_str(var_id); span_note!(tcx.sess, closure_span, "the closure that captures `{}` requires that all captured variables \ implement the trait `{}`", @@ -464,7 +464,7 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, span_note!(tcx.sess, cause_span, "required because it appears within the type `{}`", parent_trait_ref.0.self_ty()); - let parent_predicate = parent_trait_ref.as_predicate(); + let parent_predicate = parent_trait_ref.to_predicate(); note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code); } ObligationCauseCode::ImplDerivedObligation(ref data) => { @@ -473,7 +473,7 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, "required because of the requirements on the impl of `{}` for `{}`", parent_trait_ref, parent_trait_ref.0.self_ty()); - let parent_predicate = parent_trait_ref.as_predicate(); + let parent_predicate = parent_trait_ref.to_predicate(); note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code); } ObligationCauseCode::CompareImplMethodObligation => { diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 593a71a30fe2a..08cb3e5701569 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::infer::InferCtxt; -use middle::ty::{self, RegionEscape, Ty}; +use middle::ty::{self, RegionEscape, Ty, HasTypeFlags}; use std::collections::HashSet; use std::fmt; @@ -85,7 +85,7 @@ pub struct FulfillmentContext<'tcx> { // particular node-id). region_obligations: NodeMap>>, - errors_will_be_reported: bool, + pub errors_will_be_reported: bool, } #[derive(Clone)] @@ -132,7 +132,6 @@ impl<'tcx> FulfillmentContext<'tcx> { /// `projection_ty` again. pub fn normalize_projection_type<'a>(&mut self, infcx: &InferCtxt<'a,'tcx>, - typer: &ty::ClosureTyper<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>) -> Ty<'tcx> @@ -144,7 +143,7 @@ impl<'tcx> FulfillmentContext<'tcx> { // FIXME(#20304) -- cache - let mut selcx = SelectionContext::new(infcx, typer); + let mut selcx = SelectionContext::new(infcx); let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0); for obligation in normalized.obligations { @@ -208,11 +207,10 @@ impl<'tcx> FulfillmentContext<'tcx> { } pub fn select_all_or_error<'a>(&mut self, - infcx: &InferCtxt<'a,'tcx>, - typer: &ty::ClosureTyper<'tcx>) + infcx: &InferCtxt<'a,'tcx>) -> Result<(),Vec>> { - try!(self.select_where_possible(infcx, typer)); + try!(self.select_where_possible(infcx)); // Anything left is ambiguous. let errors: Vec = @@ -233,20 +231,18 @@ impl<'tcx> FulfillmentContext<'tcx> { /// gaining type information. It'd be equally valid to use `select_where_possible` but it /// results in `O(n^2)` performance (#18208). pub fn select_new_obligations<'a>(&mut self, - infcx: &InferCtxt<'a,'tcx>, - typer: &ty::ClosureTyper<'tcx>) + infcx: &InferCtxt<'a,'tcx>) -> Result<(),Vec>> { - let mut selcx = SelectionContext::new(infcx, typer); + let mut selcx = SelectionContext::new(infcx); self.select(&mut selcx, true) } pub fn select_where_possible<'a>(&mut self, - infcx: &InferCtxt<'a,'tcx>, - typer: &ty::ClosureTyper<'tcx>) + infcx: &InferCtxt<'a,'tcx>) -> Result<(),Vec>> { - let mut selcx = SelectionContext::new(infcx, typer); + let mut selcx = SelectionContext::new(infcx); self.select(&mut selcx, false) } @@ -421,16 +417,18 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, // regions. If there are, we will call this obligation an // error. Eventually we should be able to support some // cases here, I imagine (e.g., `for<'a> int : 'a`). - if ty::count_late_bound_regions(selcx.tcx(), binder) != 0 { - errors.push( - FulfillmentError::new( - obligation.clone(), - CodeSelectionError(Unimplemented))); - } else { - let ty::OutlivesPredicate(t_a, r_b) = binder.0; - register_region_obligation(t_a, r_b, - obligation.cause.clone(), - region_obligations); + match selcx.tcx().no_late_bound_regions(binder) { + None => { + errors.push( + FulfillmentError::new( + obligation.clone(), + CodeSelectionError(Unimplemented))) + } + Some(ty::OutlivesPredicate(t_a, r_b)) => { + register_region_obligation(t_a, r_b, + obligation.cause.clone(), + region_obligations); + } } true } @@ -501,5 +499,3 @@ impl<'tcx> FulfilledPredicates<'tcx> { !self.set.insert(p.clone()) } } - - diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index e3c122e2f1f59..b5f01ada7e178 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -17,7 +17,7 @@ pub use self::ObligationCauseCode::*; use middle::free_region::FreeRegionMap; use middle::subst; -use middle::ty::{self, HasProjectionTypes, Ty}; +use middle::ty::{self, HasTypeFlags, Ty}; use middle::ty_fold::TypeFoldable; use middle::infer::{self, fixup_err_to_string, InferCtxt}; use std::rc::Rc; @@ -291,11 +291,13 @@ pub struct VtableBuiltinData { /// for the object type `Foo`. #[derive(PartialEq,Eq,Clone)] pub struct VtableObjectData<'tcx> { - /// the object type `Foo`. - pub object_ty: Ty<'tcx>, - /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, + + /// The vtable is formed by concatenating together the method lists of + /// the base object trait and all supertraits; this is the start of + /// `upcast_trait_ref`'s methods in that vtable. + pub vtable_base: usize } /// Creates predicate obligations from the generic bounds. @@ -312,7 +314,6 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, /// conservative towards *no impl*, which is the opposite of the /// `evaluate` methods). pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, - typer: &ty::ClosureTyper<'tcx>, ty: Ty<'tcx>, bound: ty::BuiltinBound, span: Span) @@ -334,7 +335,7 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, // Note: we only assume something is `Copy` if we can // *definitively* show that it implements `Copy`. Otherwise, // assume it is move; linear is always ok. - match fulfill_cx.select_all_or_error(infcx, typer) { + match fulfill_cx.select_all_or_error(infcx) { Ok(()) => { debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success", ty, @@ -351,6 +352,7 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, } } +// FIXME: this is gonna need to be removed ... /// Normalizes the parameter environment, reporting errors if they occur. pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvironment<'a,'tcx>, cause: ObligationCause<'tcx>) @@ -396,13 +398,13 @@ 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); - let predicates = match fully_normalize(&infcx, &elaborated_env, cause, - &elaborated_env.caller_bounds) { + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(elaborated_env), false); + let predicates = match fully_normalize(&infcx, cause, + &infcx.parameter_environment.caller_bounds) { Ok(predicates) => predicates, Err(errors) => { report_fulfillment_errors(&infcx, &errors); - return unnormalized_env; // an unnormalized env is better than nothing + return infcx.parameter_environment; // an unnormalized env is better than nothing } }; @@ -420,24 +422,37 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi // all things considered. let err_msg = fixup_err_to_string(fixup_err); tcx.sess.span_err(span, &err_msg); - return elaborated_env; // an unnormalized env is better than nothing + return infcx.parameter_environment; // an unnormalized env is better than nothing } }; - elaborated_env.with_caller_bounds(predicates) + infcx.parameter_environment.with_caller_bounds(predicates) } pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, - closure_typer: &ty::ClosureTyper<'tcx>, cause: ObligationCause<'tcx>, value: &T) -> Result>> - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { debug!("normalize_param_env(value={:?})", value); - let mut selcx = &mut SelectionContext::new(infcx, closure_typer); + let mut selcx = &mut SelectionContext::new(infcx); + // FIXME (@jroesch) ISSUE 26721 + // I'm not sure if this is a bug or not, needs further investigation. + // It appears that by reusing the fulfillment_cx here we incur more + // obligations and later trip an asssertion on regionck.rs line 337. + // + // The two possibilities I see is: + // - normalization is not actually fully happening and we + // have a bug else where + // - we are adding a duplicate bound into the list causing + // its size to change. + // + // I think we should probably land this refactor and then come + // back to this is a follow-up patch. let mut fulfill_cx = FulfillmentContext::new(false); + let Normalized { value: normalized_value, obligations } = project::normalize(selcx, cause, value); debug!("normalize_param_env: normalized_value={:?} obligations={:?}", @@ -446,7 +461,8 @@ pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, for obligation in obligations { fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); } - try!(fulfill_cx.select_all_or_error(infcx, closure_typer)); + + try!(fulfill_cx.select_all_or_error(infcx)); let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value); debug!("normalize_param_env: resolved_value={:?}", resolved_value); Ok(resolved_value) diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index afb30716c3669..e7f11b06bd132 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -57,7 +57,7 @@ pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>, -> bool { // Because we query yes/no results frequently, we keep a cache: - let def = ty::lookup_trait_def(tcx, trait_def_id); + let def = tcx.lookup_trait_def(trait_def_id); let result = def.object_safety().unwrap_or_else(|| { let result = object_safety_violations(tcx, trait_def_id).is_empty(); @@ -90,7 +90,7 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>, { // Check methods for violations. let mut violations: Vec<_> = - ty::trait_items(tcx, trait_def_id).iter() + tcx.trait_items(trait_def_id).iter() .flat_map(|item| { match *item { ty::MethodTraitItem(ref m) => { @@ -122,10 +122,10 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, trait_def_id: ast::DefId) -> bool { - let trait_def = ty::lookup_trait_def(tcx, trait_def_id); + let trait_def = tcx.lookup_trait_def(trait_def_id); let trait_ref = trait_def.trait_ref.clone(); let trait_ref = trait_ref.to_poly_trait_ref(); - let predicates = ty::lookup_super_predicates(tcx, trait_def_id); + let predicates = tcx.lookup_super_predicates(trait_def_id); predicates .predicates .into_iter() @@ -153,8 +153,8 @@ fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>, trait_def_id: ast::DefId) -> bool { - let trait_def = ty::lookup_trait_def(tcx, trait_def_id); - let trait_predicates = ty::lookup_predicates(tcx, trait_def_id); + let trait_def = tcx.lookup_trait_def(trait_def_id); + let trait_predicates = tcx.lookup_predicates(trait_def_id); generics_require_sized_self(tcx, &trait_def.generics, &trait_predicates) } @@ -169,7 +169,7 @@ fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>, }; // Search for a predicate like `Self : Sized` amongst the trait bounds. - let free_substs = ty::construct_free_substs(tcx, generics, ast::DUMMY_NODE_ID); + let free_substs = tcx.construct_free_substs(generics, ast::DUMMY_NODE_ID); let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec(); elaborate_predicates(tcx, predicates) .any(|predicate| { @@ -306,7 +306,7 @@ fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>, let mut supertraits: Option>> = None; let mut error = false; - ty::maybe_walk_ty(ty, |ty| { + ty.maybe_walk(|ty| { match ty.sty { ty::TyParam(ref param_ty) => { if param_ty.space == SelfSpace { @@ -321,7 +321,7 @@ fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>, // Compute supertraits of current trait lazily. if supertraits.is_none() { - let trait_def = ty::lookup_trait_def(tcx, trait_def_id); + let trait_def = tcx.lookup_trait_def(trait_def_id); let trait_ref = ty::Binder(trait_def.trait_ref.clone()); supertraits = Some(traits::supertraits(tcx, trait_ref).collect()); } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 3ac58dafa4a7a..e29d9646509f9 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -23,8 +23,7 @@ use super::util; use middle::infer; use middle::subst::Subst; -use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape, - HasProjectionTypes, ToPolyTraitRef, Ty}; +use middle::ty::{self, ToPredicate, RegionEscape, HasTypeFlags, ToPolyTraitRef, Ty}; use middle::ty_fold::{self, TypeFoldable, TypeFolder}; use syntax::parse::token; use util::common::FN_OUTPUT_NAME; @@ -195,7 +194,7 @@ pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>, cause: ObligationCause<'tcx>, value: &T) -> Normalized<'tcx, T> - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { normalize_with_depth(selcx, cause, 0, value) } @@ -206,7 +205,7 @@ pub fn normalize_with_depth<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tc depth: usize, value: &T) -> Normalized<'tcx, T> - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth); let result = normalizer.fold(value); @@ -238,7 +237,7 @@ impl<'a,'b,'tcx> AssociatedTypeNormalizer<'a,'b,'tcx> { } } - fn fold + HasProjectionTypes>(&mut self, value: &T) -> T { + fn fold + HasTypeFlags>(&mut self, value: &T) -> T { let value = self.selcx.infcx().resolve_type_vars_if_possible(value); if !value.has_projection_types() { @@ -336,7 +335,7 @@ pub fn normalize_projection_type<'a,'b,'tcx>( projection_ty: projection_ty, ty: ty_var }); - let obligation = Obligation::with_depth(cause, depth+1, projection.as_predicate()); + let obligation = Obligation::with_depth(cause, depth+1, projection.to_predicate()); Normalized { value: ty_var, obligations: vec!(obligation) @@ -374,7 +373,7 @@ fn opt_normalize_projection_type<'a,'b,'tcx>( depth, obligations); - if ty::type_has_projection(projected_ty) { + if projected_ty.has_projection_types() { let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth); let normalized_ty = normalizer.fold(&projected_ty); @@ -432,7 +431,7 @@ fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, let trait_ref = projection_ty.trait_ref.to_poly_trait_ref(); let trait_obligation = Obligation { cause: cause, recursion_depth: depth, - predicate: trait_ref.as_predicate() }; + predicate: trait_ref.to_predicate() }; Normalized { value: selcx.tcx().types.err, obligations: vec!(trait_obligation) @@ -525,9 +524,9 @@ fn project_type<'cx,'tcx>( Ok(ProjectedTy::Progress(ty, obligations)) } None => { - Ok(ProjectedTy::NoProgress(ty::mk_projection(selcx.tcx(), - obligation.predicate.trait_ref.clone(), - obligation.predicate.item_name))) + Ok(ProjectedTy::NoProgress(selcx.tcx().mk_projection( + obligation.predicate.trait_ref.clone(), + obligation.predicate.item_name))) } } } @@ -575,7 +574,7 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>( }; // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = ty::lookup_predicates(selcx.tcx(), trait_ref.def_id); + let trait_predicates = selcx.tcx().lookup_predicates(trait_ref.def_id); let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs); let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates.into_vec()); assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref, @@ -630,9 +629,10 @@ fn assemble_candidates_from_object_type<'cx,'tcx>( selcx: &mut SelectionContext<'cx,'tcx>, obligation: &ProjectionTyObligation<'tcx>, obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, - object_ty: Ty<'tcx>) + candidate_set: &mut ProjectionTyCandidateSet<'tcx>) { + let self_ty = obligation_trait_ref.self_ty(); + let object_ty = selcx.infcx().shallow_resolve(self_ty); debug!("assemble_candidates_from_object_type(object_ty={:?})", object_ty); let data = match object_ty.sty { @@ -646,7 +646,7 @@ fn assemble_candidates_from_object_type<'cx,'tcx>( }; let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty); let env_predicates = projection_bounds.iter() - .map(|p| p.as_predicate()) + .map(|p| p.to_predicate()) .collect(); let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref, @@ -685,10 +685,9 @@ fn assemble_candidates_from_impls<'cx,'tcx>( candidate_set.vec.push( ProjectionTyCandidate::Impl(data)); } - super::VtableObject(data) => { + super::VtableObject(_) => { assemble_candidates_from_object_type( - selcx, obligation, obligation_trait_ref, candidate_set, - data.object_ty); + selcx, obligation, obligation_trait_ref, candidate_set); } super::VtableClosure(data) => { candidate_set.vec.push( @@ -774,7 +773,7 @@ fn confirm_fn_pointer_candidate<'cx,'tcx>( -> (Ty<'tcx>, Vec>) { let fn_type = selcx.infcx().shallow_resolve(fn_type); - let sig = ty::ty_fn_sig(fn_type); + let sig = fn_type.fn_sig(); confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) } @@ -893,7 +892,7 @@ fn confirm_impl_candidate<'cx,'tcx>( // It is not in the impl - get the default from the trait. let trait_ref = obligation.predicate.trait_ref; - for trait_item in ty::trait_items(selcx.tcx(), trait_ref.def_id).iter() { + 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 { @@ -905,6 +904,9 @@ fn confirm_impl_candidate<'cx,'tcx>( // 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!()); } } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 1653cac68e6e0..ad91f664af2db 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -38,7 +38,7 @@ use super::util; use middle::fast_reject; use middle::subst::{Subst, Substs, TypeSpace}; -use middle::ty::{self, AsPredicate, RegionEscape, ToPolyTraitRef, Ty}; +use middle::ty::{self, ToPredicate, RegionEscape, ToPolyTraitRef, Ty, HasTypeFlags}; use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; @@ -54,7 +54,6 @@ use util::nodemap::FnvHashMap; pub struct SelectionContext<'cx, 'tcx:'cx> { infcx: &'cx InferCtxt<'cx, 'tcx>, - closure_typer: &'cx (ty::ClosureTyper<'tcx>+'cx), /// Freshener used specifically for skolemizing entries on the /// obligation stack. This ensures that all entries on the stack @@ -77,6 +76,7 @@ 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, } @@ -242,23 +242,19 @@ enum EvaluationResult<'tcx> { } impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { - pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, - closure_typer: &'cx ty::ClosureTyper<'tcx>) + pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { infcx: infcx, - closure_typer: closure_typer, freshener: infcx.freshener(), intercrate: false, } } - pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>, - closure_typer: &'cx ty::ClosureTyper<'tcx>) + pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { infcx: infcx, - closure_typer: closure_typer, freshener: infcx.freshener(), intercrate: true, } @@ -273,11 +269,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'cx, 'tcx> { - self.closure_typer.param_env() + self.infcx.param_env() } - pub fn closure_typer(&self) -> &'cx (ty::ClosureTyper<'tcx>+'cx) { - self.closure_typer + pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> { + self.infcx } /////////////////////////////////////////////////////////////////////////// @@ -540,7 +536,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // terms of `Fn` etc, but we could probably make this more // precise still. let input_types = stack.fresh_trait_ref.0.input_types(); - let unbound_input_types = input_types.iter().any(|&t| ty::type_is_fresh(t)); + let unbound_input_types = input_types.iter().any(|ty| ty.is_fresh()); if unbound_input_types && (self.intercrate || @@ -675,7 +671,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if ty::type_is_error(stack.obligation.predicate.0.self_ty()) { + if stack.obligation.predicate.0.self_ty().references_error() { return Ok(Some(ErrorCandidate)); } @@ -773,7 +769,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match candidate { ImplCandidate(def_id) => { - match ty::trait_impl_polarity(self.tcx(), def_id) { + match self.tcx().trait_impl_polarity(def_id) { Some(ast::ImplPolarity::Negative) => return Err(Unimplemented), _ => {} } @@ -886,7 +882,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match *candidate { Ok(Some(_)) | Err(_) => true, Ok(None) => { - cache_fresh_trait_pred.0.input_types().iter().any(|&t| ty::type_has_ty_infer(t)) + cache_fresh_trait_pred.0.input_types().has_infer_types() } } } @@ -1024,7 +1020,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { projection_trait_ref={:?}", projection_trait_ref); - let trait_predicates = ty::lookup_predicates(self.tcx(), projection_trait_ref.def_id); + let trait_predicates = self.tcx().lookup_predicates(projection_trait_ref.def_id); let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs); debug!("match_projection_obligation_against_bounds_from_trait: \ bounds={:?}", @@ -1161,7 +1157,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { kind, obligation); - match self.closure_typer.closure_kind(closure_def_id) { + match self.infcx.closure_kind(closure_def_id) { Some(closure_kind) => { debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); if closure_kind.extends(kind) { @@ -1224,7 +1220,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - let def = ty::lookup_trait_def(self.tcx(), obligation.predicate.def_id()); + let def = self.tcx().lookup_trait_def(obligation.predicate.def_id()); def.for_each_relevant_impl( self.tcx(), @@ -1252,7 +1248,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let def_id = obligation.predicate.def_id(); - if ty::trait_has_default_impl(self.tcx(), def_id) { + if self.tcx().trait_has_default_impl(def_id) { match self_ty.sty { ty::TyTrait(..) => { // For object types, we don't know what the closed @@ -1264,7 +1260,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // object types, because it just lets you reflect // onto the object type, not into the object's // interior. - if ty::has_attr(self.tcx(), def_id, "rustc_reflect_like") { + if self.tcx().has_attr(def_id, "rustc_reflect_like") { candidates.vec.push(DefaultImplObjectCandidate(def_id)); } } @@ -1366,12 +1362,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref); - // see whether the object trait can be upcast to the trait we are looking for - let upcast_trait_refs = self.upcast(poly_trait_ref, obligation); - if upcast_trait_refs.len() > 1 { + // Count only those upcast versions that match the trait-ref + // we are looking for. Specifically, do not only check for the + // correct trait, but also the correct type parameters. + // For example, we may be trying to upcast `Foo` to `Bar`, + // but `Foo` is declared as `trait Foo : Bar`. + let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref) + .filter(|upcast_trait_ref| self.infcx.probe(|_| { + let upcast_trait_ref = upcast_trait_ref.clone(); + self.match_poly_trait_ref(obligation, upcast_trait_ref).is_ok() + })).count(); + + if upcast_trait_refs > 1 { // can be upcast in many ways; need more type information candidates.ambiguous = true; - } else if upcast_trait_refs.len() == 1 { + } else if upcast_trait_refs == 1 { candidates.vec.push(ObjectCandidate); } @@ -1397,7 +1402,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // T: Trait // so it seems ok if we (conservatively) fail to accept that `Unsize` // obligation above. Should be possible to extend this in the future. - let self_ty = match ty::no_late_bound_regions(self.tcx(), &obligation.self_ty()) { + let self_ty = match self.tcx().no_late_bound_regions(&obligation.self_ty()) { Some(t) => t, None => { // Don't add any candidates if there are bound regions. @@ -1725,7 +1730,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return ok_if(Vec::new()); } - match self.closure_typer.closure_upvars(def_id, substs) { + match self.infcx.closure_upvars(def_id, substs) { Some(upvars) => ok_if(upvars.iter().map(|c| c.ty).collect()), None => { debug!("assemble_builtin_bound_candidates: no upvar types available yet"); @@ -1736,7 +1741,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyStruct(def_id, substs) => { let types: Vec = - ty::struct_fields(self.tcx(), def_id, substs).iter() + self.tcx().struct_fields(def_id, substs).iter() .map(|f| f.mt.ty) .collect(); nominal(bound, types) @@ -1744,7 +1749,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyEnum(def_id, substs) => { let types: Vec = - ty::substd_enum_variants(self.tcx(), def_id, substs) + self.tcx().substd_enum_variants(def_id, substs) .iter() .flat_map(|variant| &variant.args) .cloned() @@ -1863,7 +1868,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyClosure(def_id, substs) => { assert_eq!(def_id.krate, ast::LOCAL_CRATE); - match self.closure_typer.closure_upvars(def_id, substs) { + match self.infcx.closure_upvars(def_id, substs) { Some(upvars) => { Some(upvars.iter().map(|c| c.ty).collect()) } @@ -1881,13 +1886,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::TyStruct(def_id, substs) => { - Some(ty::struct_fields(self.tcx(), def_id, substs).iter() + Some(self.tcx().struct_fields(def_id, substs).iter() .map(|f| f.mt.ty) .collect()) } ty::TyEnum(def_id, substs) => { - Some(ty::substd_enum_variants(self.tcx(), def_id, substs) + Some(self.tcx().substd_enum_variants(def_id, substs) .iter() .flat_map(|variant| &variant.args) .map(|&ty| ty) @@ -2161,7 +2166,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation, trait_def_id); - assert!(ty::has_attr(self.tcx(), trait_def_id, "rustc_reflect_like")); + assert!(self.tcx().has_attr(trait_def_id, "rustc_reflect_like")); // OK to skip binder, it is reintroduced below let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); @@ -2178,7 +2183,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // reintroduce the two binding levels we skipped, then flatten into one let all_types = ty::Binder(ty::Binder(all_types)); - let all_types = ty::flatten_late_bound_regions(self.tcx(), &all_types); + let all_types = self.tcx().flatten_late_bound_regions(&all_types); self.vtable_default_impl(obligation, trait_def_id, all_types) } @@ -2309,20 +2314,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // be exactly one applicable trait-reference; if this were not // the case, we would have reported an ambiguity error rather // than successfully selecting one of the candidates. - let upcast_trait_refs = self.upcast(poly_trait_ref.clone(), obligation); - assert_eq!(upcast_trait_refs.len(), 1); - let upcast_trait_ref = upcast_trait_refs.into_iter().next().unwrap(); + let mut upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref) + .map(|upcast_trait_ref| { + (upcast_trait_ref.clone(), self.infcx.probe(|_| { + self.match_poly_trait_ref(obligation, upcast_trait_ref) + }).is_ok()) + }); + let mut upcast_trait_ref = None; + let mut vtable_base = 0; - match self.match_poly_trait_ref(obligation, upcast_trait_ref.clone()) { - Ok(()) => { } - Err(()) => { - self.tcx().sess.span_bug(obligation.cause.span, - "failed to match trait refs"); + while let Some((supertrait, matches)) = upcast_trait_refs.next() { + if matches { + upcast_trait_ref = Some(supertrait); + break; } + vtable_base += util::count_own_vtable_entries(self.tcx(), supertrait); } + assert!(upcast_trait_refs.all(|(_, matches)| !matches)); - VtableObjectData { object_ty: self_ty, - upcast_trait_ref: upcast_trait_ref } + VtableObjectData { + upcast_trait_ref: upcast_trait_ref.unwrap(), + vtable_base: vtable_base + } } fn confirm_fn_pointer_candidate(&mut self, @@ -2334,7 +2347,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // ok to skip binder; it is reintroduced below let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let sig = ty::ty_fn_sig(self_ty); + let sig = self_ty.fn_sig(); let trait_ref = util::closure_trait_ref_and_return_type(self.tcx(), obligation.predicate.def_id(), @@ -2434,7 +2447,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // assemble_candidates_for_unsizing should ensure there are no late bound // regions here. See the comment there for more details. let source = self.infcx.shallow_resolve( - ty::no_late_bound_regions(tcx, &obligation.self_ty()).unwrap()); + tcx.no_late_bound_regions(&obligation.self_ty()).unwrap()); let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", @@ -2449,9 +2462,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { region_bound: data_b.bounds.region_bound, builtin_bounds: data_b.bounds.builtin_bounds, projection_bounds: data_a.bounds.projection_bounds.clone(), + region_bound_will_change: data_b.bounds.region_bound_will_change, }; - let new_trait = ty::mk_trait(tcx, data_a.principal.clone(), bounds); + let new_trait = tcx.mk_trait(data_a.principal.clone(), bounds); let origin = infer::Misc(obligation.cause.span); if self.infcx.sub_types(false, origin, new_trait, target).is_err() { return Err(Unimplemented); @@ -2465,7 +2479,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { data_b.bounds.region_bound); nested.push(Obligation::with_depth(cause, obligation.recursion_depth + 1, - ty::Binder(outlives).as_predicate())); + ty::Binder(outlives).to_predicate())); } // T -> Trait. @@ -2485,7 +2499,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; // Create the obligation for casting from T to Trait. - push(data.principal_trait_ref_with_self_ty(tcx, source).as_predicate()); + push(data.principal_trait_ref_with_self_ty(tcx, source).to_predicate()); // We can only make objects from sized types. let mut builtin_bounds = data.bounds.builtin_bounds; @@ -2497,7 +2511,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // for the Send check.) for bound in &builtin_bounds { if let Ok(tr) = util::trait_ref_for_builtin_bound(tcx, bound, source) { - push(tr.as_predicate()); + push(tr.to_predicate()); } else { return Err(Unimplemented); } @@ -2505,14 +2519,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Create obligations for the projection predicates. for bound in data.projection_bounds_with_self_ty(tcx, source) { - push(bound.as_predicate()); + push(bound.to_predicate()); } // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` outlives `'a`: let outlives = ty::OutlivesPredicate(source, data.bounds.region_bound); - push(ty::Binder(outlives).as_predicate()); + push(ty::Binder(outlives).to_predicate()); } // [T; n] -> [T]. @@ -2525,8 +2539,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Struct -> Struct. (&ty::TyStruct(def_id, substs_a), &ty::TyStruct(_, substs_b)) => { - let fields = ty::lookup_struct_fields(tcx, def_id).iter().map(|f| { - ty::lookup_field_type_unsubstituted(tcx, def_id, f.id) + let fields = tcx.lookup_struct_fields(def_id).iter().map(|f| { + tcx.lookup_field_type_unsubstituted(def_id, f.id) }).collect::>(); // The last field of the structure has to exist and contain type parameters. @@ -2536,7 +2550,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(Unimplemented); }; let mut ty_params = vec![]; - ty::walk_ty(field, |ty| { + for ty in field.walk() { if let ty::TyParam(p) = ty.sty { assert!(p.space == TypeSpace); let idx = p.idx as usize; @@ -2544,7 +2558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty_params.push(idx); } } - }); + } if ty_params.is_empty() { return Err(Unimplemented); } @@ -2558,7 +2572,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err; } for &ty in fields.init() { - if ty::type_is_error(ty.subst(tcx, &new_substs)) { + if ty.subst(tcx, &new_substs).references_error() { return Err(Unimplemented); } } @@ -2573,7 +2587,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let param_b = *substs_b.types.get(TypeSpace, i); new_substs.types.get_mut_slice(TypeSpace)[i] = param_b; } - let new_struct = ty::mk_struct(tcx, def_id, tcx.mk_substs(new_substs)); + let new_struct = tcx.mk_struct(def_id, tcx.mk_substs(new_substs)); let origin = infer::Misc(obligation.cause.span); if self.infcx.sub_types(false, origin, new_struct, target).is_err() { return Err(Unimplemented); @@ -2628,7 +2642,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { -> Result<(Normalized<'tcx, Substs<'tcx>>, infer::SkolemizationMap), ()> { - let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap(); + let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); // Before we create the substitutions and everything, first // consider a "quick reject". This avoids creating more types @@ -2722,7 +2736,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Returns `Ok` if `poly_trait_ref` being true implies that the /// obligation is satisfied. - fn match_poly_trait_ref(&mut self, + fn match_poly_trait_ref(&self, obligation: &TraitObligation<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Result<(),()> @@ -2765,7 +2779,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id); // Find the self type for the impl. - let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty; + let impl_self_ty = self.tcx().lookup_item_type(impl_def_id).ty; let impl_self_ty = impl_self_ty.subst(self.tcx(), &impl_substs); debug!("match_impl_self_types(obligation_self_ty={:?}, impl_self_ty={:?})", @@ -2842,7 +2856,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs: &Substs<'tcx>) -> ty::PolyTraitRef<'tcx> { - let closure_type = self.closure_typer.closure_type(closure_def_id, substs); + let closure_type = self.infcx.closure_type(closure_def_id, substs); let ty::Binder((trait_ref, _)) = util::closure_trait_ref_and_return_type(self.tcx(), obligation.predicate.def_id(), @@ -2890,7 +2904,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { debug!("impl_or_trait_obligations(def_id={:?})", def_id); - let predicates = ty::lookup_predicates(self.tcx(), def_id); + let predicates = self.tcx().lookup_predicates(def_id); let predicates = predicates.instantiate(self.tcx(), substs); let predicates = normalize_with_depth(self, cause.clone(), recursion_depth, &predicates); let mut predicates = self.infcx().plug_leaks(skol_map, snapshot, &predicates); @@ -2933,32 +2947,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.clone() } } - - /// Upcasts an object trait-reference into those that match the obligation. - fn upcast(&mut self, obj_trait_ref: ty::PolyTraitRef<'tcx>, obligation: &TraitObligation<'tcx>) - -> Vec> - { - debug!("upcast(obj_trait_ref={:?}, obligation={:?})", - obj_trait_ref, - obligation); - - let obligation_def_id = obligation.predicate.def_id(); - let mut upcast_trait_refs = util::upcast(self.tcx(), obj_trait_ref, obligation_def_id); - - // Retain only those upcast versions that match the trait-ref - // we are looking for. In particular, we know that all of - // `upcast_trait_refs` apply to the correct trait, but - // possibly with incorrect type parameters. For example, we - // may be trying to upcast `Foo` to `Bar`, but `Foo` is - // declared as `trait Foo : Bar`. - upcast_trait_refs.retain(|upcast_trait_ref| { - let upcast_trait_ref = upcast_trait_ref.clone(); - self.infcx.probe(|_| self.match_poly_trait_ref(obligation, upcast_trait_ref)).is_ok() - }); - - debug!("upcast: upcast_trait_refs={:?}", upcast_trait_refs); - upcast_trait_refs - } } impl<'tcx> SelectionCache<'tcx> { diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 54bcd9d7e66ab..af9d5e5157d28 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -10,7 +10,7 @@ use middle::subst::Substs; use middle::infer::InferCtxt; -use middle::ty::{self, Ty, AsPredicate, ToPolyTraitRef}; +use middle::ty::{self, Ty, ToPredicate, ToPolyTraitRef}; use std::fmt; use syntax::ast; use syntax::codemap::Span; @@ -43,19 +43,19 @@ impl<'a,'tcx> PredicateSet<'a,'tcx> { // regions before we throw things into the underlying set. let normalized_pred = match *pred { ty::Predicate::Trait(ref data) => - ty::Predicate::Trait(ty::anonymize_late_bound_regions(self.tcx, data)), + ty::Predicate::Trait(self.tcx.anonymize_late_bound_regions(data)), ty::Predicate::Equate(ref data) => - ty::Predicate::Equate(ty::anonymize_late_bound_regions(self.tcx, data)), + ty::Predicate::Equate(self.tcx.anonymize_late_bound_regions(data)), ty::Predicate::RegionOutlives(ref data) => - ty::Predicate::RegionOutlives(ty::anonymize_late_bound_regions(self.tcx, data)), + ty::Predicate::RegionOutlives(self.tcx.anonymize_late_bound_regions(data)), ty::Predicate::TypeOutlives(ref data) => - ty::Predicate::TypeOutlives(ty::anonymize_late_bound_regions(self.tcx, data)), + ty::Predicate::TypeOutlives(self.tcx.anonymize_late_bound_regions(data)), ty::Predicate::Projection(ref data) => - ty::Predicate::Projection(ty::anonymize_late_bound_regions(self.tcx, data)), + ty::Predicate::Projection(self.tcx.anonymize_late_bound_regions(data)), }; self.set.insert(normalized_pred) } @@ -83,7 +83,7 @@ pub fn elaborate_trait_ref<'cx, 'tcx>( trait_ref: ty::PolyTraitRef<'tcx>) -> Elaborator<'cx, 'tcx> { - elaborate_predicates(tcx, vec![trait_ref.as_predicate()]) + elaborate_predicates(tcx, vec![trait_ref.to_predicate()]) } pub fn elaborate_trait_refs<'cx, 'tcx>( @@ -92,7 +92,7 @@ pub fn elaborate_trait_refs<'cx, 'tcx>( -> Elaborator<'cx, 'tcx> { let predicates = trait_refs.iter() - .map(|trait_ref| trait_ref.as_predicate()) + .map(|trait_ref| trait_ref.to_predicate()) .collect(); elaborate_predicates(tcx, predicates) } @@ -116,7 +116,7 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { match *predicate { ty::Predicate::Trait(ref data) => { // Predicates declared on the trait. - let predicates = ty::lookup_super_predicates(self.tcx, data.def_id()); + let predicates = self.tcx.lookup_super_predicates(data.def_id()); let mut predicates: Vec<_> = predicates.predicates @@ -236,7 +236,7 @@ impl<'cx, 'tcx> Iterator for SupertraitDefIds<'cx, 'tcx> { None => { return None; } }; - let predicates = ty::lookup_super_predicates(self.tcx, def_id); + let predicates = self.tcx.lookup_super_predicates(def_id); let visited = &mut self.visited; self.stack.extend( predicates.predicates @@ -297,7 +297,7 @@ pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, -> Substs<'tcx> { let tcx = infcx.tcx; - let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics; + let impl_generics = tcx.lookup_item_type(impl_def_id).generics; infcx.fresh_substs_for_generics(span, &impl_generics) } @@ -347,7 +347,7 @@ pub fn predicate_for_trait_ref<'tcx>( Obligation { cause: cause, recursion_depth: recursion_depth, - predicate: trait_ref.as_predicate(), + predicate: trait_ref.to_predicate(), } } @@ -396,52 +396,50 @@ pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>, .collect() } -/// Given an object of type `object_trait_ref`, returns the index of -/// the method `n_method` found in the trait `trait_def_id` (which -/// should be a supertrait of `object_trait_ref`) within the vtable -/// for `object_trait_ref`. -pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>, - object_trait_ref: ty::PolyTraitRef<'tcx>, - trait_def_id: ast::DefId, - method_offset_in_trait: usize) -> usize { - // We need to figure the "real index" of the method in a - // listing of all the methods of an object. We do this by - // iterating down the supertraits of the object's trait until - // we find the trait the method came from, counting up the - // methods from them. - let mut method_count = 0; - - for bound_ref in transitive_bounds(tcx, &[object_trait_ref]) { - if bound_ref.def_id() == trait_def_id { - break; - } - - let trait_items = ty::trait_items(tcx, bound_ref.def_id()); - for trait_item in trait_items.iter() { - match *trait_item { - ty::MethodTraitItem(_) => method_count += 1, - _ => {} - } +/// Given an trait `trait_ref`, returns the number of vtable entries +/// that come from `trait_ref`, excluding its supertraits. Used in +/// computing the vtable base for an upcast trait of a trait object. +pub fn count_own_vtable_entries<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>) + -> usize { + let mut entries = 0; + // Count number of methods and add them to the total offset. + // Skip over associated types and constants. + for trait_item in &tcx.trait_items(trait_ref.def_id())[..] { + if let ty::MethodTraitItem(_) = *trait_item { + entries += 1; } } + entries +} - // count number of methods preceding the one we are selecting and - // add them to the total offset; skip over associated types. - let trait_items = ty::trait_items(tcx, trait_def_id); - for trait_item in trait_items.iter().take(method_offset_in_trait) { - match *trait_item { - ty::MethodTraitItem(_) => method_count += 1, - _ => {} +/// Given an upcast trait object described by `object`, returns the +/// index of the method `method_def_id` (which should be part of +/// `object.upcast_trait_ref`) within the vtable for `object`. +pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>, + object: &super::VtableObjectData<'tcx>, + method_def_id: ast::DefId) -> usize { + // Count number of methods preceding the one we are selecting and + // add them to the total offset. + // Skip over associated types and constants. + let mut entries = object.vtable_base; + for trait_item in &tcx.trait_items(object.upcast_trait_ref.def_id())[..] { + if trait_item.def_id() == method_def_id { + // The item with the ID we were given really ought to be a method. + assert!(match *trait_item { + ty::MethodTraitItem(_) => true, + _ => false + }); + + return entries; + } + if let ty::MethodTraitItem(_) = *trait_item { + entries += 1; } } - // the item at the offset we were given really ought to be a method - assert!(match trait_items[method_offset_in_trait] { - ty::MethodTraitItem(_) => true, - _ => false - }); - - method_count + tcx.sess.bug(&format!("get_vtable_index_of_object_method: {:?} was not found", + method_def_id)); } pub enum TupleArgumentsFlag { Yes, No } @@ -456,14 +454,14 @@ pub fn closure_trait_ref_and_return_type<'tcx>( { let arguments_tuple = match tuple_arguments { TupleArgumentsFlag::No => sig.0.inputs[0], - TupleArgumentsFlag::Yes => ty::mk_tup(tcx, sig.0.inputs.to_vec()), + TupleArgumentsFlag::Yes => tcx.mk_tup(sig.0.inputs.to_vec()), }; let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty); let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs(trait_substs), }; - ty::Binder((trait_ref, sig.0.output.unwrap_or(ty::mk_nil(tcx)))) + ty::Binder((trait_ref, sig.0.output.unwrap_or(tcx.mk_nil()))) } impl<'tcx,O:fmt::Debug> fmt::Debug for super::Obligation<'tcx, O> { @@ -490,7 +488,7 @@ impl<'tcx, N:fmt::Debug> fmt::Debug for super::Vtable<'tcx, N> { write!(f, "VtableFnPointer({:?})", d), super::VtableObject(ref d) => - write!(f, "VtableObject({:?})", d), + write!(f, "{:?}", d), super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n), @@ -535,7 +533,9 @@ impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableDefaultImplData { impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableObject(object_ty={:?})", self.object_ty) + write!(f, "VtableObject(upcast={:?}, vtable_base={})", + self.upcast_trait_ref, + self.vtable_base) } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e32da7837ec17..715072a12ebd0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -30,7 +30,6 @@ pub use self::ImplOrTraitItem::*; pub use self::BoundRegion::*; pub use self::TypeVariants::*; pub use self::IntVarValue::*; -pub use self::MethodOrigin::*; pub use self::CopyImplementationError::*; pub use self::BuiltinBound::Send as BoundSend; @@ -51,9 +50,7 @@ use middle::def::{self, DefMap, ExportMap}; use middle::dependency_format; use middle::fast_reject; use middle::free_region::FreeRegionMap; -use middle::infer::error_reporting::note_and_explain_region; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; -use middle::mem_categorization as mc; use middle::region; use middle::resolve_lifetime; use middle::infer; @@ -85,7 +82,7 @@ use std::collections::{HashMap, HashSet}; use syntax::abi; use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE}; use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId}; -use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility}; +use syntax::ast::{StructField, UnnamedField, Visibility}; use syntax::ast_util::{self, is_local, local_def}; use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; use syntax::codemap::Span; @@ -117,7 +114,222 @@ pub struct field<'tcx> { pub mt: mt<'tcx> } -#[derive(Clone, Copy, Debug)] + + +// Enum information +#[derive(Clone)] +pub struct VariantInfo<'tcx> { + pub args: Vec>, + pub arg_names: Option>, + pub ctor_ty: Option>, + pub name: ast::Name, + pub id: ast::DefId, + pub disr_val: Disr, + pub vis: Visibility +} + +impl<'tcx> VariantInfo<'tcx> { + + /// Creates a new VariantInfo from the corresponding ast representation. + /// + /// Does not do any caching of the value in the type context. + pub fn from_ast_variant(cx: &ctxt<'tcx>, + ast_variant: &ast::Variant, + discriminant: Disr) -> VariantInfo<'tcx> { + let ctor_ty = cx.node_id_to_type(ast_variant.node.id); + + match ast_variant.node.kind { + ast::TupleVariantKind(ref args) => { + let arg_tys = if !args.is_empty() { + // the regions in the argument types come from the + // enum def'n, and hence will all be early bound + cx.no_late_bound_regions(&ctor_ty.fn_args()).unwrap() + } else { + Vec::new() + }; + + return VariantInfo { + args: arg_tys, + arg_names: None, + ctor_ty: Some(ctor_ty), + name: ast_variant.node.name.name, + id: ast_util::local_def(ast_variant.node.id), + disr_val: discriminant, + vis: ast_variant.node.vis + }; + }, + ast::StructVariantKind(ref struct_def) => { + let fields: &[StructField] = &struct_def.fields; + + assert!(!fields.is_empty()); + + let arg_tys = struct_def.fields.iter() + .map(|field| cx.node_id_to_type(field.node.id)).collect(); + let arg_names = fields.iter().map(|field| { + match field.node.kind { + NamedField(ident, _) => ident.name, + UnnamedField(..) => cx.sess.bug( + "enum_variants: all fields in struct must have a name") + } + }).collect(); + + return VariantInfo { + args: arg_tys, + arg_names: Some(arg_names), + ctor_ty: None, + name: ast_variant.node.name.name, + id: ast_util::local_def(ast_variant.node.id), + disr_val: discriminant, + vis: ast_variant.node.vis + }; + } + } + } +} + +#[derive(Copy, Clone)] +pub enum DtorKind { + NoDtor, + TraitDtor(DefId, bool) +} + +impl DtorKind { + pub fn is_present(&self) -> bool { + match *self { + TraitDtor(..) => true, + _ => false + } + } + + pub fn has_drop_flag(&self) -> bool { + match self { + &NoDtor => false, + &TraitDtor(_, flag) => flag + } + } +} + +trait IntTypeExt { + fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx>; + fn i64_to_disr(&self, val: i64) -> Option; + fn u64_to_disr(&self, val: u64) -> Option; + fn disr_incr(&self, val: Disr) -> Option; + fn disr_string(&self, val: Disr) -> String; + fn disr_wrap_incr(&self, val: Option) -> Disr; +} + +impl IntTypeExt for attr::IntType { + fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> { + match *self { + SignedInt(ast::TyI8) => cx.types.i8, + SignedInt(ast::TyI16) => cx.types.i16, + SignedInt(ast::TyI32) => cx.types.i32, + SignedInt(ast::TyI64) => cx.types.i64, + SignedInt(ast::TyIs) => cx.types.isize, + UnsignedInt(ast::TyU8) => cx.types.u8, + UnsignedInt(ast::TyU16) => cx.types.u16, + UnsignedInt(ast::TyU32) => cx.types.u32, + UnsignedInt(ast::TyU64) => cx.types.u64, + UnsignedInt(ast::TyUs) => cx.types.usize, + } + } + + fn i64_to_disr(&self, val: i64) -> Option { + match *self { + SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr), + SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr), + SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr), + SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr), + UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr), + UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr), + UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr), + UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr), + + UnsignedInt(ast::TyUs) | + SignedInt(ast::TyIs) => unreachable!(), + } + } + + fn u64_to_disr(&self, val: u64) -> Option { + match *self { + SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr), + SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr), + SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr), + SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr), + UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr), + UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr), + UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr), + UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr), + + UnsignedInt(ast::TyUs) | + SignedInt(ast::TyIs) => unreachable!(), + } + } + + fn disr_incr(&self, val: Disr) -> Option { + 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::TyI8) => add1!((val as i64).to_i8()), + SignedInt(ast::TyI16) => add1!((val as i64).to_i16()), + SignedInt(ast::TyI32) => add1!((val as i64).to_i32()), + SignedInt(ast::TyI64) => add1!(Some(val as i64)), + + UnsignedInt(ast::TyU8) => add1!(val.to_u8()), + UnsignedInt(ast::TyU16) => add1!(val.to_u16()), + UnsignedInt(ast::TyU32) => add1!(val.to_u32()), + UnsignedInt(ast::TyU64) => add1!(Some(val)), + + UnsignedInt(ast::TyUs) | + SignedInt(ast::TyIs) => 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::TyI8) => format!("{}", val as i8 ), + SignedInt(ast::TyI16) => format!("{}", val as i16), + SignedInt(ast::TyI32) => format!("{}", val as i32), + SignedInt(ast::TyI64) => format!("{}", val as i64), + UnsignedInt(ast::TyU8) => format!("{}", val as u8 ), + UnsignedInt(ast::TyU16) => format!("{}", val as u16), + UnsignedInt(ast::TyU32) => format!("{}", val as u32), + UnsignedInt(ast::TyU64) => format!("{}", val as u64), + + UnsignedInt(ast::TyUs) | + SignedInt(ast::TyIs) => unreachable!(), + } + } + + fn disr_wrap_incr(&self, val: Option) -> 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::TyI8) => add1!(val as i8 ), + SignedInt(ast::TyI16) => add1!(val as i16), + SignedInt(ast::TyI32) => add1!(val as i32), + SignedInt(ast::TyI64) => add1!(val as i64), + UnsignedInt(ast::TyU8) => add1!(val as u8 ), + UnsignedInt(ast::TyU16) => add1!(val as u16), + UnsignedInt(ast::TyU32) => add1!(val as u32), + UnsignedInt(ast::TyU64) => add1!(val as u64), + + UnsignedInt(ast::TyUs) | + SignedInt(ast::TyIs) => unreachable!(), + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum ImplOrTraitItemContainer { TraitContainer(ast::DefId), ImplContainer(ast::DefId), @@ -303,6 +515,17 @@ pub enum Variance { Bivariant, // T <: T -- e.g., unused type parameter } +impl fmt::Debug for Variance { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match *self { + Covariant => "+", + Contravariant => "-", + Invariant => "o", + Bivariant => "*", + }) + } +} + #[derive(Copy, Clone)] pub enum AutoAdjustment<'tcx> { AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type @@ -402,68 +625,12 @@ pub enum CustomCoerceUnsized { Struct(usize) } -#[derive(Clone)] -pub enum MethodOrigin<'tcx> { - // fully statically resolved method - MethodStatic(ast::DefId), - - // fully statically resolved closure invocation - MethodStaticClosure(ast::DefId), - - // method invoked on a type parameter with a bounded trait - MethodTypeParam(MethodParam<'tcx>), - - // method invoked on a trait instance - MethodTraitObject(MethodObject<'tcx>), - -} - -// details for a method invoked with a receiver whose type is a type parameter -// with a bounded trait. -#[derive(Clone)] -pub struct MethodParam<'tcx> { - // the precise trait reference that occurs as a bound -- this may - // be a supertrait of what the user actually typed. Note that it - // never contains bound regions; those regions should have been - // instantiated with fresh variables at this point. - pub trait_ref: ty::TraitRef<'tcx>, - - // index of usize in the list of trait items. Note that this is NOT - // the index into the vtable, because the list of trait items - // includes associated types. - pub method_num: usize, - - /// The impl for the trait from which the method comes. This - /// should only be used for certain linting/heuristic purposes - /// since there is no guarantee that this is Some in every - /// situation that it could/should be. - pub impl_def_id: Option, -} - -// details for a method invoked with a receiver whose type is an object -#[derive(Clone)] -pub struct MethodObject<'tcx> { - // the (super)trait containing the method to be invoked - pub trait_ref: TraitRef<'tcx>, - - // the actual base trait id of the object - pub object_trait_id: ast::DefId, - - // index of the method to be invoked amongst the trait's items - pub method_num: usize, - - // index into the actual runtime vtable. - // the vtable is formed by concatenating together the method lists of - // the base object trait and all supertraits; this is the index into - // that vtable - pub vtable_index: usize, -} - -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct MethodCallee<'tcx> { - pub origin: MethodOrigin<'tcx>, + /// Impl method ID, for inherent methods, or trait method ID, otherwise. + pub def_id: ast::DefId, pub ty: Ty<'tcx>, - pub substs: subst::Substs<'tcx> + pub substs: &'tcx subst::Substs<'tcx> } /// With method calls, we store some extra information in @@ -502,7 +669,7 @@ impl MethodCall { // maps from an expression id that corresponds to a method call to the details // of the method to be invoked -pub type MethodMap<'tcx> = RefCell>>; +pub type MethodMap<'tcx> = FnvHashMap>; // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. @@ -589,12 +756,54 @@ pub struct CommonTypes<'tcx> { pub err: Ty<'tcx>, } -/// The data structure to keep track of all the information that typechecker -/// generates so that so that it can be reused and doesn't have to be redone -/// later on. -pub struct ctxt<'tcx> { - /// The arenas that types etc are allocated from. - arenas: &'tcx CtxtArenas<'tcx>, +pub struct Tables<'tcx> { + /// Stores the types for various nodes in the AST. Note that this table + /// is not guaranteed to be populated until after typeck. See + /// typeck::check::fn_ctxt for details. + pub node_types: NodeMap>, + + /// Stores the type parameters which were substituted to obtain the type + /// of this node. This only applies to nodes that refer to entities + /// parameterized by type parameters, such as generic fns, types, or + /// other items. + pub item_substs: NodeMap>, + + pub adjustments: NodeMap>, + + pub method_map: MethodMap<'tcx>, + + /// Borrows + pub upvar_capture_map: UpvarCaptureMap, + + /// Records the type of each closure. The def ID is the ID of the + /// expression defining the closure. + pub closure_tys: DefIdMap>, + + /// Records the type of each closure. The def ID is the ID of the + /// expression defining the closure. + pub closure_kinds: DefIdMap, +} + +impl<'tcx> Tables<'tcx> { + pub fn empty() -> Tables<'tcx> { + Tables { + node_types: FnvHashMap(), + item_substs: NodeMap(), + adjustments: NodeMap(), + method_map: FnvHashMap(), + upvar_capture_map: FnvHashMap(), + closure_tys: DefIdMap(), + closure_kinds: DefIdMap(), + } + } +} + +/// The data structure to keep track of all the information that typechecker +/// generates so that so that it can be reused and doesn't have to be redone +/// later on. +pub struct ctxt<'tcx> { + /// The arenas that types etc are allocated from. + arenas: &'tcx CtxtArenas<'tcx>, /// Specifically use a speedy hash algorithm for this hash map, it's used /// quite often. @@ -624,17 +833,9 @@ pub struct ctxt<'tcx> { // borrowck. (They are not used during trans, and hence are not // serialized or needed for cross-crate fns.) free_region_maps: RefCell>, + // FIXME: jroesch make this a refcell - /// Stores the types for various nodes in the AST. Note that this table - /// is not guaranteed to be populated until after typeck. See - /// typeck::check::fn_ctxt for details. - node_types: RefCell>>, - - /// Stores the type parameters which were substituted to obtain the type - /// of this node. This only applies to nodes that refer to entities - /// parameterized by type parameters, such as generic fns, types, or - /// other items. - pub item_substs: RefCell>>, + pub tables: RefCell>, /// Maps from a trait item to the trait item "descriptor" pub impl_or_trait_items: RefCell>>, @@ -668,7 +869,6 @@ pub struct ctxt<'tcx> { pub ast_ty_to_ty_cache: RefCell>>, pub enum_var_cache: RefCell>>>>>, pub ty_param_defs: RefCell>>, - pub adjustments: RefCell>>, pub normalized_cache: RefCell, Ty<'tcx>>>, pub lang_items: middle::lang_items::LanguageItems, /// A mapping of fake provided method def_ids to the default implementation @@ -718,26 +918,13 @@ pub struct ctxt<'tcx> { /// FIXME(arielb1): why is this separate from populated_external_types? pub populated_external_primitive_impls: RefCell, - /// Borrows - pub upvar_capture_map: RefCell, - /// These caches are used by const_eval when decoding external constants. pub extern_const_statics: RefCell>, pub extern_const_variants: RefCell>, pub extern_const_fns: RefCell>, - pub method_map: MethodMap<'tcx>, - pub dependency_formats: RefCell, - /// Records the type of each closure. The def ID is the ID of the - /// expression defining the closure. - pub closure_kinds: RefCell>, - - /// Records the type of each closure. The def ID is the ID of the - /// expression defining the closure. - pub closure_tys: RefCell>>, - pub node_lint_levels: RefCell>, @@ -774,9 +961,16 @@ pub struct ctxt<'tcx> { } impl<'tcx> ctxt<'tcx> { - pub fn node_types(&self) -> Ref>> { self.node_types.borrow() } + pub fn node_types(&self) -> Ref>> { + fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap> { + &tables.node_types + } + + Ref::map(self.tables.borrow(), projection) + } + pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) { - self.node_types.borrow_mut().insert(id, ty); + self.tables.borrow_mut().node_types.insert(id, ty); } pub fn intern_trait_def(&self, def: TraitDef<'tcx>) -> &'tcx TraitDef<'tcx> { @@ -963,7 +1157,7 @@ pub mod tls { Some(ast_map::NodeTraitItem(..)) | Some(ast_map::NodeVariant(..)) | Some(ast_map::NodeStructCtor(..)) => { - return write!(f, "{}", ty::item_path_str(tcx, def_id)); + return write!(f, "{}", tcx.item_path_str(def_id)); } _ => {} } @@ -1180,64 +1374,6 @@ impl<'tcx> Borrow> for InternedTy<'tcx> { } } -pub fn type_has_params(ty: Ty) -> bool { - ty.flags.get().intersects(TypeFlags::HAS_PARAMS) -} -pub fn type_has_self(ty: Ty) -> bool { - ty.flags.get().intersects(TypeFlags::HAS_SELF) -} -pub fn type_has_ty_infer(ty: Ty) -> bool { - ty.flags.get().intersects(TypeFlags::HAS_TY_INFER) -} -pub fn type_needs_infer(ty: Ty) -> bool { - ty.flags.get().intersects(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) -} -pub fn type_is_global(ty: Ty) -> bool { - !ty.flags.get().intersects(TypeFlags::HAS_LOCAL_NAMES) -} -pub fn type_has_projection(ty: Ty) -> bool { - ty.flags.get().intersects(TypeFlags::HAS_PROJECTION) -} -pub fn type_has_ty_closure(ty: Ty) -> bool { - ty.flags.get().intersects(TypeFlags::HAS_TY_CLOSURE) -} - -pub fn type_has_erasable_regions(ty: Ty) -> bool { - ty.flags.get().intersects(TypeFlags::HAS_RE_EARLY_BOUND | - TypeFlags::HAS_RE_INFER | - TypeFlags::HAS_FREE_REGIONS) -} - -/// An "escaping region" is a bound region whose binder is not part of `t`. -/// -/// So, for example, consider a type like the following, which has two binders: -/// -/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope -/// -/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the -/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner -/// fn type*, that type has an escaping region: `'a`. -/// -/// Note that what I'm calling an "escaping region" is often just called a "free region". However, -/// we already use the term "free region". It refers to the regions that we use to represent bound -/// regions on a fn definition while we are typechecking its body. -/// -/// To clarify, conceptually there is no particular difference between an "escaping" region and a -/// "free" region. However, there is a big difference in practice. Basically, when "entering" a -/// binding level, one is generally required to do some sort of processing to a bound region, such -/// as replacing it with a fresh/skolemized region, or making an entry in the environment to -/// represent the scope to which it is attached, etc. An escaping region represents a bound region -/// for which this processing has not yet been done. -pub fn type_has_escaping_regions(ty: Ty) -> bool { - type_escapes_depth(ty, 0) -} - -pub fn type_escapes_depth(ty: Ty, depth: u32) -> bool { - ty.region_depth > depth -} - #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct BareFnTy<'tcx> { pub unsafety: ast::Unsafety, @@ -1496,16 +1632,14 @@ pub struct UpvarBorrow { pub type UpvarCaptureMap = FnvHashMap; -impl Region { - pub fn is_global(&self) -> bool { - // does this represent a region that can be named in a global - // way? used in fulfillment caching. - match *self { - ty::ReStatic | ty::ReEmpty => true, - _ => false, - } - } +#[derive(Copy, Clone)] +pub struct ClosureUpvar<'tcx> { + pub def: def::Def, + pub span: Span, + pub ty: Ty<'tcx>, +} +impl Region { pub fn is_bound(&self) -> bool { match *self { ty::ReEarlyBound(..) => true, @@ -1520,6 +1654,16 @@ impl Region { _ => false, } } + + /// Returns the depth of `self` from the (1-based) binding level `depth` + pub fn from_depth(&self, depth: u32) -> Region { + match *self { + ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex { + depth: debruijn.depth - (depth - 1) + }, r), + r => r + } + } } #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, @@ -1854,6 +1998,11 @@ pub struct ExistentialBounds<'tcx> { pub region_bound: ty::Region, pub builtin_bounds: BuiltinBounds, pub projection_bounds: Vec>, + + // If true, this TyTrait used a "default bound" in the surface + // syntax. This makes no difference to the type system but is + // handy for error reporting. + pub region_bound_will_change: bool, } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] @@ -1873,7 +2022,7 @@ impl BuiltinBounds { self_ty: Ty<'tcx>) -> Vec> { self.iter().filter_map(|builtin_bound| match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, self_ty) { - Ok(trait_ref) => Some(trait_ref.as_predicate()), + Ok(trait_ref) => Some(trait_ref.to_predicate()), Err(ErrorReported) => { None } } ).collect() @@ -1907,13 +2056,6 @@ pub enum BuiltinBound { Sync, } -/// An existential bound that does not implement any traits. -pub fn region_existential_bound<'tcx>(r: ty::Region) -> ExistentialBounds<'tcx> { - ty::ExistentialBounds { region_bound: r, - builtin_bounds: BuiltinBounds::empty(), - projection_bounds: Vec::new() } -} - impl CLike for BuiltinBound { fn to_usize(&self) -> usize { *self as usize @@ -2051,6 +2193,9 @@ pub enum ObjectLifetimeDefault { /// `T:'a` constraints are found. Ambiguous, + /// Use the base default, typically 'static, but in a fn body it is a fresh variable + BaseDefault, + /// Use the given region as the default. Specific(Region), } @@ -2062,7 +2207,7 @@ pub struct TypeParameterDef<'tcx> { pub space: subst::ParamSpace, pub index: u32, pub default: Option>, - pub object_lifetime_default: Option, + pub object_lifetime_default: ObjectLifetimeDefault, } #[derive(RustcEncodable, RustcDecodable, Clone, Debug)] @@ -2130,7 +2275,7 @@ impl<'tcx> GenericPredicates<'tcx> { } } - pub fn instantiate(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) + pub fn instantiate(&self, tcx: &ctxt<'tcx>, substs: &Substs<'tcx>) -> InstantiatedPredicates<'tcx> { InstantiatedPredicates { predicates: self.predicates.subst(tcx, substs), @@ -2138,7 +2283,7 @@ impl<'tcx> GenericPredicates<'tcx> { } pub fn instantiate_supertrait(&self, - tcx: &ty::ctxt<'tcx>, + tcx: &ctxt<'tcx>, poly_trait_ref: &ty::PolyTraitRef<'tcx>) -> InstantiatedPredicates<'tcx> { @@ -2176,7 +2321,7 @@ impl<'tcx> Predicate<'tcx> { /// substitution in terms of what happens with bound regions. See /// lengthy comment below for details. pub fn subst_supertrait(&self, - tcx: &ty::ctxt<'tcx>, + tcx: &ctxt<'tcx>, trait_ref: &ty::PolyTraitRef<'tcx>) -> ty::Predicate<'tcx> { @@ -2254,29 +2399,6 @@ impl<'tcx> Predicate<'tcx> { Predicate::Projection(ty::Binder(data.subst(tcx, substs))), } } - - // Indicates whether this predicate references only 'global' - // types/lifetimes that are the same regardless of what fn we are - // in. This is used for caching. Errs on the side of returning - // false. - pub fn is_global(&self) -> bool { - match *self { - ty::Predicate::Trait(ref data) => { - let substs = data.skip_binder().trait_ref.substs; - - substs.types.iter().all(|t| ty::type_is_global(t)) && { - match substs.regions { - subst::ErasedRegions => true, - subst::NonerasedRegions(ref r) => r.iter().all(|r| r.is_global()), - } - } - } - - _ => { - false - } - } - } } #[derive(Clone, PartialEq, Eq, Hash)] @@ -2390,12 +2512,12 @@ impl<'tcx> ToPolyTraitRef<'tcx> for PolyProjectionPredicate<'tcx> { } } -pub trait AsPredicate<'tcx> { - fn as_predicate(&self) -> Predicate<'tcx>; +pub trait ToPredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx>; } -impl<'tcx> AsPredicate<'tcx> for TraitRef<'tcx> { - fn as_predicate(&self) -> Predicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { // we're about to add a binder, so let's check that we don't // accidentally capture anything, or else that might be some // weird debruijn accounting. @@ -2407,32 +2529,32 @@ impl<'tcx> AsPredicate<'tcx> for TraitRef<'tcx> { } } -impl<'tcx> AsPredicate<'tcx> for PolyTraitRef<'tcx> { - fn as_predicate(&self) -> Predicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { ty::Predicate::Trait(self.to_poly_trait_predicate()) } } -impl<'tcx> AsPredicate<'tcx> for PolyEquatePredicate<'tcx> { - fn as_predicate(&self) -> Predicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyEquatePredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { Predicate::Equate(self.clone()) } } -impl<'tcx> AsPredicate<'tcx> for PolyRegionOutlivesPredicate { - fn as_predicate(&self) -> Predicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate { + fn to_predicate(&self) -> Predicate<'tcx> { Predicate::RegionOutlives(self.clone()) } } -impl<'tcx> AsPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { - fn as_predicate(&self) -> Predicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { Predicate::TypeOutlives(self.clone()) } } -impl<'tcx> AsPredicate<'tcx> for PolyProjectionPredicate<'tcx> { - fn as_predicate(&self) -> Predicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { + fn to_predicate(&self) -> Predicate<'tcx> { Predicate::Projection(self.clone()) } } @@ -2608,22 +2730,20 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { match impl_item.node { ast::ConstImplItem(_, _) => { let def_id = ast_util::local_def(id); - let scheme = lookup_item_type(cx, def_id); - let predicates = lookup_predicates(cx, def_id); - construct_parameter_environment(cx, - impl_item.span, - &scheme.generics, - &predicates, - id) + let scheme = cx.lookup_item_type(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(impl_item.span, + &scheme.generics, + &predicates, + id) } ast::MethodImplItem(_, ref body) => { let method_def_id = ast_util::local_def(id); - match ty::impl_or_trait_item(cx, method_def_id) { + match cx.impl_or_trait_item(method_def_id) { MethodTraitItem(ref method_ty) => { let method_generics = &method_ty.generics; let method_bounds = &method_ty.predicates; - construct_parameter_environment( - cx, + cx.construct_parameter_environment( impl_item.span, method_generics, method_bounds, @@ -2650,13 +2770,12 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { match *default { Some(_) => { let def_id = ast_util::local_def(id); - let scheme = lookup_item_type(cx, def_id); - let predicates = lookup_predicates(cx, def_id); - construct_parameter_environment(cx, - trait_item.span, - &scheme.generics, - &predicates, - id) + let scheme = cx.lookup_item_type(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(trait_item.span, + &scheme.generics, + &predicates, + id) } None => { cx.sess.bug("ParameterEnvironment::from_item(): \ @@ -2674,12 +2793,11 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } ast::MethodTraitItem(_, Some(ref body)) => { let method_def_id = ast_util::local_def(id); - match ty::impl_or_trait_item(cx, method_def_id) { + match cx.impl_or_trait_item(method_def_id) { MethodTraitItem(ref method_ty) => { let method_generics = &method_ty.generics; let method_bounds = &method_ty.predicates; - construct_parameter_environment( - cx, + cx.construct_parameter_environment( trait_item.span, method_generics, method_bounds, @@ -2705,14 +2823,13 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { ast::ItemFn(_, _, _, _, _, ref body) => { // We assume this is a function. let fn_def_id = ast_util::local_def(id); - let fn_scheme = lookup_item_type(cx, fn_def_id); - let fn_predicates = lookup_predicates(cx, fn_def_id); - - construct_parameter_environment(cx, - item.span, - &fn_scheme.generics, - &fn_predicates, - body.id) + let fn_scheme = cx.lookup_item_type(fn_def_id); + let fn_predicates = cx.lookup_predicates(fn_def_id); + + cx.construct_parameter_environment(item.span, + &fn_scheme.generics, + &fn_predicates, + body.id) } ast::ItemEnum(..) | ast::ItemStruct(..) | @@ -2720,13 +2837,12 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { ast::ItemConst(..) | ast::ItemStatic(..) => { let def_id = ast_util::local_def(id); - let scheme = lookup_item_type(cx, def_id); - let predicates = lookup_predicates(cx, def_id); - construct_parameter_environment(cx, - item.span, - &scheme.generics, - &predicates, - id) + let scheme = cx.lookup_item_type(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(item.span, + &scheme.generics, + &predicates, + id) } _ => { cx.sess.span_bug(item.span, @@ -2747,6 +2863,54 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } } } + + pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span) + -> Result<(),CopyImplementationError> { + let tcx = self.tcx; + + // FIXME: (@jroesch) float this code up + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()), false); + + let did = match self_type.sty { + ty::TyStruct(struct_did, substs) => { + let fields = tcx.struct_fields(struct_did, substs); + for field in &fields { + if infcx.type_moves_by_default(field.mt.ty, span) { + return Err(FieldDoesNotImplementCopy(field.name)) + } + } + struct_did + } + ty::TyEnum(enum_did, substs) => { + let enum_variants = tcx.enum_variants(enum_did); + for variant in enum_variants.iter() { + for variant_arg_type in &variant.args { + let substd_arg_type = + variant_arg_type.subst(tcx, substs); + if infcx.type_moves_by_default(substd_arg_type, span) { + return Err(VariantDoesNotImplementCopy(variant.name)) + } + } + } + enum_did + } + _ => return Err(TypeIsStructural), + }; + + if tcx.has_dtor(did) { + return Err(TypeHasDestructor) + } + + Ok(()) + } +} + +#[derive(Copy, Clone)] +pub enum CopyImplementationError { + FieldDoesNotImplementCopy(ast::Name), + VariantDoesNotImplementCopy(ast::Name), + TypeIsStructural, + TypeHasDestructor, } /// A "type scheme", in ML terminology, is a type combined with some @@ -2874,7 +3038,7 @@ impl<'tcx> TraitDef<'tcx> { pub fn for_each_impl(&self, tcx: &ctxt<'tcx>, mut f: F) { - ty::populate_implementations_for_trait_if_necessary(tcx, self.trait_ref.def_id); + tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id); for &impl_def_id in self.blanket_impls.borrow().iter() { f(impl_def_id); @@ -2892,7 +3056,7 @@ impl<'tcx> TraitDef<'tcx> { self_ty: Ty<'tcx>, mut f: F) { - ty::populate_implementations_for_trait_if_necessary(tcx, self.trait_ref.def_id); + tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id); for &impl_def_id in self.blanket_impls.borrow().iter() { f(impl_def_id); @@ -2965,247 +3129,30 @@ impl ClosureKind { } } -pub trait ClosureTyper<'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.param_env().tcx - } - - fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx>; - - /// Is this a `Fn`, `FnMut` or `FnOnce` closure? During typeck, - /// returns `None` if the kind of this closure has not yet been - /// inferred. - fn closure_kind(&self, - def_id: ast::DefId) - -> Option; - - /// Returns the argument/return types of this closure. - fn closure_type(&self, - def_id: ast::DefId, - substs: &subst::Substs<'tcx>) - -> ty::ClosureTy<'tcx>; - - /// Returns the set of all upvars and their transformed - /// types. During typeck, maybe return `None` if the upvar types - /// have not yet been inferred. - fn closure_upvars(&self, - def_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option>>; -} - impl<'tcx> CommonTypes<'tcx> { fn new(arena: &'tcx TypedArena>, - interner: &mut FnvHashMap, Ty<'tcx>>) + interner: &RefCell, Ty<'tcx>>>) -> CommonTypes<'tcx> { + let mk = |sty| ctxt::intern_ty(arena, interner, sty); CommonTypes { - bool: intern_ty(arena, interner, TyBool), - char: intern_ty(arena, interner, TyChar), - err: intern_ty(arena, interner, TyError), - isize: intern_ty(arena, interner, TyInt(ast::TyIs)), - i8: intern_ty(arena, interner, TyInt(ast::TyI8)), - i16: intern_ty(arena, interner, TyInt(ast::TyI16)), - i32: intern_ty(arena, interner, TyInt(ast::TyI32)), - i64: intern_ty(arena, interner, TyInt(ast::TyI64)), - usize: intern_ty(arena, interner, TyUint(ast::TyUs)), - u8: intern_ty(arena, interner, TyUint(ast::TyU8)), - u16: intern_ty(arena, interner, TyUint(ast::TyU16)), - u32: intern_ty(arena, interner, TyUint(ast::TyU32)), - u64: intern_ty(arena, interner, TyUint(ast::TyU64)), - f32: intern_ty(arena, interner, TyFloat(ast::TyF32)), - f64: intern_ty(arena, interner, TyFloat(ast::TyF64)), - } - } -} - -/// Create a type context and call the closure with a `&ty::ctxt` reference -/// to the context. The closure enforces that the type context and any interned -/// value (types, substs, etc.) can only be used while `ty::tls` has a valid -/// reference to the context, to allow formatting values that need it. -pub fn with_ctxt<'tcx, F, R>(s: Session, - arenas: &'tcx CtxtArenas<'tcx>, - def_map: DefMap, - named_region_map: resolve_lifetime::NamedRegionMap, - map: ast_map::Map<'tcx>, - freevars: RefCell, - region_maps: RegionMaps, - lang_items: middle::lang_items::LanguageItems, - stability: stability::Index<'tcx>, - f: F) -> (Session, R) - where F: FnOnce(&ctxt<'tcx>) -> R -{ - let mut interner = FnvHashMap(); - let common_types = CommonTypes::new(&arenas.type_, &mut interner); - - tls::enter(ctxt { - arenas: arenas, - interner: RefCell::new(interner), - substs_interner: RefCell::new(FnvHashMap()), - bare_fn_interner: RefCell::new(FnvHashMap()), - region_interner: RefCell::new(FnvHashMap()), - stability_interner: RefCell::new(FnvHashMap()), - types: common_types, - named_region_map: named_region_map, - region_maps: region_maps, - free_region_maps: RefCell::new(FnvHashMap()), - item_variance_map: RefCell::new(DefIdMap()), - variance_computed: Cell::new(false), - sess: s, - def_map: def_map, - node_types: RefCell::new(FnvHashMap()), - item_substs: RefCell::new(NodeMap()), - impl_trait_refs: RefCell::new(DefIdMap()), - trait_defs: RefCell::new(DefIdMap()), - predicates: RefCell::new(DefIdMap()), - super_predicates: RefCell::new(DefIdMap()), - fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()), - map: map, - freevars: freevars, - tcache: RefCell::new(DefIdMap()), - rcache: RefCell::new(FnvHashMap()), - tc_cache: RefCell::new(FnvHashMap()), - ast_ty_to_ty_cache: RefCell::new(NodeMap()), - enum_var_cache: RefCell::new(DefIdMap()), - impl_or_trait_items: RefCell::new(DefIdMap()), - trait_item_def_ids: RefCell::new(DefIdMap()), - trait_items_cache: RefCell::new(DefIdMap()), - ty_param_defs: RefCell::new(NodeMap()), - adjustments: RefCell::new(NodeMap()), - normalized_cache: RefCell::new(FnvHashMap()), - lang_items: lang_items, - provided_method_sources: RefCell::new(DefIdMap()), - struct_fields: RefCell::new(DefIdMap()), - destructor_for_type: RefCell::new(DefIdMap()), - destructors: RefCell::new(DefIdSet()), - inherent_impls: RefCell::new(DefIdMap()), - impl_items: RefCell::new(DefIdMap()), - used_unsafe: RefCell::new(NodeSet()), - used_mut_nodes: RefCell::new(NodeSet()), - populated_external_types: RefCell::new(DefIdSet()), - populated_external_primitive_impls: RefCell::new(DefIdSet()), - upvar_capture_map: RefCell::new(FnvHashMap()), - extern_const_statics: RefCell::new(DefIdMap()), - extern_const_variants: RefCell::new(DefIdMap()), - extern_const_fns: RefCell::new(DefIdMap()), - method_map: RefCell::new(FnvHashMap()), - dependency_formats: RefCell::new(FnvHashMap()), - closure_kinds: RefCell::new(DefIdMap()), - closure_tys: RefCell::new(DefIdMap()), - node_lint_levels: RefCell::new(FnvHashMap()), - transmute_restrictions: RefCell::new(Vec::new()), - stability: RefCell::new(stability), - selection_cache: traits::SelectionCache::new(), - repr_hint_cache: RefCell::new(DefIdMap()), - const_qualif_map: RefCell::new(NodeMap()), - custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), - cast_kinds: RefCell::new(NodeMap()), - }, f) -} - -// Type constructors - -impl<'tcx> ctxt<'tcx> { - pub fn mk_substs(&self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> { - if let Some(substs) = self.substs_interner.borrow().get(&substs) { - return *substs; - } - - let substs = self.arenas.substs.alloc(substs); - self.substs_interner.borrow_mut().insert(substs, substs); - substs - } - - /// Create an unsafe fn ty based on a safe fn ty. - pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> { - assert_eq!(bare_fn.unsafety, ast::Unsafety::Normal); - let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy { - unsafety: ast::Unsafety::Unsafe, - abi: bare_fn.abi, - sig: bare_fn.sig.clone() - }); - ty::mk_bare_fn(self, None, unsafe_fn_ty_a) - } - - pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> { - if let Some(bare_fn) = self.bare_fn_interner.borrow().get(&bare_fn) { - return *bare_fn; + bool: mk(TyBool), + char: mk(TyChar), + err: mk(TyError), + isize: mk(TyInt(ast::TyIs)), + i8: mk(TyInt(ast::TyI8)), + i16: mk(TyInt(ast::TyI16)), + i32: mk(TyInt(ast::TyI32)), + i64: mk(TyInt(ast::TyI64)), + usize: mk(TyUint(ast::TyUs)), + u8: mk(TyUint(ast::TyU8)), + u16: mk(TyUint(ast::TyU16)), + u32: mk(TyUint(ast::TyU32)), + u64: mk(TyUint(ast::TyU64)), + f32: mk(TyFloat(ast::TyF32)), + f64: mk(TyFloat(ast::TyF64)), } - - let bare_fn = self.arenas.bare_fn.alloc(bare_fn); - self.bare_fn_interner.borrow_mut().insert(bare_fn, bare_fn); - bare_fn - } - - pub fn mk_region(&self, region: Region) -> &'tcx Region { - if let Some(region) = self.region_interner.borrow().get(®ion) { - return *region; - } - - let region = self.arenas.region.alloc(region); - self.region_interner.borrow_mut().insert(region, region); - region - } - - pub fn closure_kind(&self, def_id: ast::DefId) -> ty::ClosureKind { - *self.closure_kinds.borrow().get(&def_id).unwrap() - } - - pub fn closure_type(&self, - def_id: ast::DefId, - substs: &subst::Substs<'tcx>) - -> ty::ClosureTy<'tcx> - { - self.closure_tys.borrow().get(&def_id).unwrap().subst(self, substs) - } - - pub fn type_parameter_def(&self, - node_id: ast::NodeId) - -> TypeParameterDef<'tcx> - { - self.ty_param_defs.borrow().get(&node_id).unwrap().clone() - } - - pub fn pat_contains_ref_binding(&self, pat: &ast::Pat) -> Option { - pat_util::pat_contains_ref_binding(&self.def_map, pat) - } - - pub fn arm_contains_ref_binding(&self, arm: &ast::Arm) -> Option { - pat_util::arm_contains_ref_binding(&self.def_map, arm) - } -} - -// Interns a type/name combination, stores the resulting box in cx.interner, -// and returns the box as cast to an unsafe ptr (see comments for Ty above). -pub fn mk_t<'tcx>(cx: &ctxt<'tcx>, st: TypeVariants<'tcx>) -> Ty<'tcx> { - let mut interner = cx.interner.borrow_mut(); - intern_ty(&cx.arenas.type_, &mut *interner, st) -} - -fn intern_ty<'tcx>(type_arena: &'tcx TypedArena>, - interner: &mut FnvHashMap, Ty<'tcx>>, - st: TypeVariants<'tcx>) - -> Ty<'tcx> -{ - match interner.get(&st) { - Some(ty) => return *ty, - _ => () } - - let flags = FlagComputation::for_sty(&st); - - let ty = match () { - () => type_arena.alloc(TyS { sty: st, - flags: Cell::new(flags.flags), - region_depth: flags.depth, }), - }; - - debug!("Interned type: {:?} Pointer: {:?}", - ty, ty as *const TyS); - - interner.insert(InternedTy { ty: ty }, ty); - - ty } struct FlagComputation { @@ -3399,201 +3346,377 @@ impl FlagComputation { } } -pub fn mk_mach_int<'tcx>(tcx: &ctxt<'tcx>, tm: ast::IntTy) -> Ty<'tcx> { - match tm { - ast::TyIs => tcx.types.isize, - ast::TyI8 => tcx.types.i8, - ast::TyI16 => tcx.types.i16, - ast::TyI32 => tcx.types.i32, - ast::TyI64 => tcx.types.i64, +impl<'tcx> ctxt<'tcx> { + /// Create a type context and call the closure with a `&ty::ctxt` reference + /// to the context. The closure enforces that the type context and any interned + /// value (types, substs, etc.) can only be used while `ty::tls` has a valid + /// reference to the context, to allow formatting values that need it. + pub fn create_and_enter(s: Session, + arenas: &'tcx CtxtArenas<'tcx>, + def_map: DefMap, + named_region_map: resolve_lifetime::NamedRegionMap, + map: ast_map::Map<'tcx>, + freevars: RefCell, + region_maps: RegionMaps, + lang_items: middle::lang_items::LanguageItems, + stability: stability::Index<'tcx>, + f: F) -> (Session, R) + where F: FnOnce(&ctxt<'tcx>) -> R + { + let interner = RefCell::new(FnvHashMap()); + let common_types = CommonTypes::new(&arenas.type_, &interner); + + tls::enter(ctxt { + arenas: arenas, + interner: interner, + substs_interner: RefCell::new(FnvHashMap()), + bare_fn_interner: RefCell::new(FnvHashMap()), + region_interner: RefCell::new(FnvHashMap()), + stability_interner: RefCell::new(FnvHashMap()), + types: common_types, + named_region_map: named_region_map, + region_maps: region_maps, + free_region_maps: RefCell::new(FnvHashMap()), + item_variance_map: RefCell::new(DefIdMap()), + variance_computed: Cell::new(false), + sess: s, + def_map: def_map, + tables: RefCell::new(Tables::empty()), + impl_trait_refs: RefCell::new(DefIdMap()), + trait_defs: RefCell::new(DefIdMap()), + predicates: RefCell::new(DefIdMap()), + super_predicates: RefCell::new(DefIdMap()), + fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()), + map: map, + freevars: freevars, + tcache: RefCell::new(DefIdMap()), + rcache: RefCell::new(FnvHashMap()), + tc_cache: RefCell::new(FnvHashMap()), + ast_ty_to_ty_cache: RefCell::new(NodeMap()), + enum_var_cache: RefCell::new(DefIdMap()), + impl_or_trait_items: RefCell::new(DefIdMap()), + trait_item_def_ids: RefCell::new(DefIdMap()), + trait_items_cache: RefCell::new(DefIdMap()), + ty_param_defs: RefCell::new(NodeMap()), + normalized_cache: RefCell::new(FnvHashMap()), + lang_items: lang_items, + provided_method_sources: RefCell::new(DefIdMap()), + struct_fields: RefCell::new(DefIdMap()), + destructor_for_type: RefCell::new(DefIdMap()), + destructors: RefCell::new(DefIdSet()), + inherent_impls: RefCell::new(DefIdMap()), + impl_items: RefCell::new(DefIdMap()), + used_unsafe: RefCell::new(NodeSet()), + used_mut_nodes: RefCell::new(NodeSet()), + populated_external_types: RefCell::new(DefIdSet()), + populated_external_primitive_impls: RefCell::new(DefIdSet()), + extern_const_statics: RefCell::new(DefIdMap()), + extern_const_variants: RefCell::new(DefIdMap()), + extern_const_fns: RefCell::new(DefIdMap()), + dependency_formats: RefCell::new(FnvHashMap()), + node_lint_levels: RefCell::new(FnvHashMap()), + transmute_restrictions: RefCell::new(Vec::new()), + stability: RefCell::new(stability), + selection_cache: traits::SelectionCache::new(), + repr_hint_cache: RefCell::new(DefIdMap()), + const_qualif_map: RefCell::new(NodeMap()), + custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), + cast_kinds: RefCell::new(NodeMap()), + }, f) } -} -pub fn mk_mach_uint<'tcx>(tcx: &ctxt<'tcx>, tm: ast::UintTy) -> Ty<'tcx> { - match tm { - ast::TyUs => tcx.types.usize, - ast::TyU8 => tcx.types.u8, - ast::TyU16 => tcx.types.u16, - ast::TyU32 => tcx.types.u32, - ast::TyU64 => tcx.types.u64, + // Type constructors + + pub fn mk_substs(&self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> { + if let Some(substs) = self.substs_interner.borrow().get(&substs) { + return *substs; + } + + let substs = self.arenas.substs.alloc(substs); + self.substs_interner.borrow_mut().insert(substs, substs); + substs } -} -pub fn mk_mach_float<'tcx>(tcx: &ctxt<'tcx>, tm: ast::FloatTy) -> Ty<'tcx> { - match tm { - ast::TyF32 => tcx.types.f32, - ast::TyF64 => tcx.types.f64, + /// Create an unsafe fn ty based on a safe fn ty. + pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> { + assert_eq!(bare_fn.unsafety, ast::Unsafety::Normal); + let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: bare_fn.abi, + sig: bare_fn.sig.clone() + }); + self.mk_fn(None, unsafe_fn_ty_a) } -} -pub fn mk_str<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> { - mk_t(cx, TyStr) -} + pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> { + if let Some(bare_fn) = self.bare_fn_interner.borrow().get(&bare_fn) { + return *bare_fn; + } -pub fn mk_str_slice<'tcx>(cx: &ctxt<'tcx>, r: &'tcx Region, m: ast::Mutability) -> Ty<'tcx> { - mk_rptr(cx, r, - mt { - ty: mk_t(cx, TyStr), - mutbl: m - }) -} + let bare_fn = self.arenas.bare_fn.alloc(bare_fn); + self.bare_fn_interner.borrow_mut().insert(bare_fn, bare_fn); + bare_fn + } -pub fn mk_enum<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - mk_t(cx, TyEnum(did, substs)) -} + pub fn mk_region(&self, region: Region) -> &'tcx Region { + if let Some(region) = self.region_interner.borrow().get(®ion) { + return *region; + } -pub fn mk_uniq<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { mk_t(cx, TyBox(ty)) } + let region = self.arenas.region.alloc(region); + self.region_interner.borrow_mut().insert(region, region); + region + } -pub fn mk_ptr<'tcx>(cx: &ctxt<'tcx>, tm: mt<'tcx>) -> Ty<'tcx> { mk_t(cx, TyRawPtr(tm)) } + pub fn closure_kind(&self, def_id: ast::DefId) -> ty::ClosureKind { + *self.tables.borrow().closure_kinds.get(&def_id).unwrap() + } -pub fn mk_rptr<'tcx>(cx: &ctxt<'tcx>, r: &'tcx Region, tm: mt<'tcx>) -> Ty<'tcx> { - mk_t(cx, TyRef(r, tm)) -} + pub fn closure_type(&self, + def_id: ast::DefId, + substs: &subst::Substs<'tcx>) + -> ty::ClosureTy<'tcx> + { + self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, substs) + } -pub fn mk_mut_rptr<'tcx>(cx: &ctxt<'tcx>, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> { - mk_rptr(cx, r, mt {ty: ty, mutbl: ast::MutMutable}) -} -pub fn mk_imm_rptr<'tcx>(cx: &ctxt<'tcx>, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> { - mk_rptr(cx, r, mt {ty: ty, mutbl: ast::MutImmutable}) -} + pub fn type_parameter_def(&self, + node_id: ast::NodeId) + -> TypeParameterDef<'tcx> + { + self.ty_param_defs.borrow().get(&node_id).unwrap().clone() + } -pub fn mk_mut_ptr<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - mk_ptr(cx, mt {ty: ty, mutbl: ast::MutMutable}) -} + pub fn pat_contains_ref_binding(&self, pat: &ast::Pat) -> Option { + pat_util::pat_contains_ref_binding(&self.def_map, pat) + } -pub fn mk_imm_ptr<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - mk_ptr(cx, mt {ty: ty, mutbl: ast::MutImmutable}) -} + pub fn arm_contains_ref_binding(&self, arm: &ast::Arm) -> Option { + pat_util::arm_contains_ref_binding(&self.def_map, arm) + } -pub fn mk_nil_ptr<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> { - mk_ptr(cx, mt {ty: mk_nil(cx), mutbl: ast::MutImmutable}) -} + fn intern_ty(type_arena: &'tcx TypedArena>, + interner: &RefCell, Ty<'tcx>>>, + st: TypeVariants<'tcx>) + -> Ty<'tcx> { + let ty: Ty /* don't be &mut TyS */ = { + let mut interner = interner.borrow_mut(); + match interner.get(&st) { + Some(ty) => return *ty, + _ => () + } -pub fn mk_vec<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>, sz: Option) -> Ty<'tcx> { - match sz { - Some(n) => mk_t(cx, TyArray(ty, n)), - None => mk_t(cx, TySlice(ty)) + let flags = FlagComputation::for_sty(&st); + + let ty = match () { + () => type_arena.alloc(TyS { sty: st, + flags: Cell::new(flags.flags), + region_depth: flags.depth, }), + }; + + interner.insert(InternedTy { ty: ty }, ty); + ty + }; + + debug!("Interned type: {:?} Pointer: {:?}", + ty, ty as *const TyS); + ty } -} -pub fn mk_slice<'tcx>(cx: &ctxt<'tcx>, r: &'tcx Region, tm: mt<'tcx>) -> Ty<'tcx> { - mk_rptr(cx, r, - mt { - ty: mk_vec(cx, tm.ty, None), - mutbl: tm.mutbl - }) -} + // Interns a type/name combination, stores the resulting box in cx.interner, + // and returns the box as cast to an unsafe ptr (see comments for Ty above). + pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> { + ctxt::intern_ty(&self.arenas.type_, &self.interner, st) + } -pub fn mk_tup<'tcx>(cx: &ctxt<'tcx>, ts: Vec>) -> Ty<'tcx> { - mk_t(cx, TyTuple(ts)) -} + pub fn mk_mach_int(&self, tm: ast::IntTy) -> Ty<'tcx> { + match tm { + ast::TyIs => self.types.isize, + ast::TyI8 => self.types.i8, + ast::TyI16 => self.types.i16, + ast::TyI32 => self.types.i32, + ast::TyI64 => self.types.i64, + } + } -pub fn mk_nil<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> { - mk_tup(cx, Vec::new()) -} + pub fn mk_mach_uint(&self, tm: ast::UintTy) -> Ty<'tcx> { + match tm { + ast::TyUs => self.types.usize, + ast::TyU8 => self.types.u8, + ast::TyU16 => self.types.u16, + ast::TyU32 => self.types.u32, + ast::TyU64 => self.types.u64, + } + } -pub fn mk_bool<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> { - mk_t(cx, TyBool) -} + pub fn mk_mach_float(&self, tm: ast::FloatTy) -> Ty<'tcx> { + match tm { + ast::TyF32 => self.types.f32, + ast::TyF64 => self.types.f64, + } + } -pub fn mk_bare_fn<'tcx>(cx: &ctxt<'tcx>, - opt_def_id: Option, - fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> { - mk_t(cx, TyBareFn(opt_def_id, fty)) -} + pub fn mk_str(&self) -> Ty<'tcx> { + self.mk_ty(TyStr) + } -pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>, - def_id: ast::DefId, - input_tys: &[Ty<'tcx>], - output: Ty<'tcx>) -> Ty<'tcx> { - let input_args = input_tys.iter().cloned().collect(); - mk_bare_fn(cx, - Some(def_id), - cx.mk_bare_fn(BareFnTy { - unsafety: ast::Unsafety::Normal, - abi: abi::Rust, - sig: ty::Binder(FnSig { - inputs: input_args, - output: ty::FnConverging(output), - variadic: false - }) - })) -} - -pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, - principal: ty::PolyTraitRef<'tcx>, - bounds: ExistentialBounds<'tcx>) - -> Ty<'tcx> -{ - assert!(bound_list_is_sorted(&bounds.projection_bounds)); + pub fn mk_static_str(&self) -> Ty<'tcx> { + self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) + } - let inner = box TraitTy { - principal: principal, - bounds: bounds - }; - mk_t(cx, TyTrait(inner)) -} + pub fn mk_enum(&self, did: ast::DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + self.mk_ty(TyEnum(did, substs)) + } -fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool { - bounds.is_empty() || - bounds[1..].iter().enumerate().all( - |(index, bound)| bounds[index].sort_key() <= bound.sort_key()) -} + pub fn mk_box(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyBox(ty)) + } -pub fn sort_bounds_list(bounds: &mut [ty::PolyProjectionPredicate]) { - bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())) -} + pub fn mk_ptr(&self, tm: mt<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyRawPtr(tm)) + } -pub fn mk_projection<'tcx>(cx: &ctxt<'tcx>, - trait_ref: TraitRef<'tcx>, - item_name: ast::Name) - -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name }; - mk_t(cx, TyProjection(inner)) -} + pub fn mk_ref(&self, r: &'tcx Region, tm: mt<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyRef(r, tm)) + } -pub fn mk_struct<'tcx>(cx: &ctxt<'tcx>, struct_id: ast::DefId, - substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - mk_t(cx, TyStruct(struct_id, substs)) -} + pub fn mk_mut_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ref(r, mt {ty: ty, mutbl: ast::MutMutable}) + } -pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, closure_id: ast::DefId, substs: &'tcx Substs<'tcx>) - -> Ty<'tcx> { - mk_t(cx, TyClosure(closure_id, substs)) -} + pub fn mk_imm_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ref(r, mt {ty: ty, mutbl: ast::MutImmutable}) + } -pub fn mk_var<'tcx>(cx: &ctxt<'tcx>, v: TyVid) -> Ty<'tcx> { - mk_infer(cx, TyVar(v)) -} + pub fn mk_mut_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ptr(mt {ty: ty, mutbl: ast::MutMutable}) + } -pub fn mk_int_var<'tcx>(cx: &ctxt<'tcx>, v: IntVid) -> Ty<'tcx> { - mk_infer(cx, IntVar(v)) -} + pub fn mk_imm_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ptr(mt {ty: ty, mutbl: ast::MutImmutable}) + } -pub fn mk_float_var<'tcx>(cx: &ctxt<'tcx>, v: FloatVid) -> Ty<'tcx> { - mk_infer(cx, FloatVar(v)) -} + pub fn mk_nil_ptr(&self) -> Ty<'tcx> { + self.mk_imm_ptr(self.mk_nil()) + } -pub fn mk_infer<'tcx>(cx: &ctxt<'tcx>, it: InferTy) -> Ty<'tcx> { - mk_t(cx, TyInfer(it)) -} + pub fn mk_array(&self, ty: Ty<'tcx>, n: usize) -> Ty<'tcx> { + self.mk_ty(TyArray(ty, n)) + } + + pub fn mk_slice(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.mk_ty(TySlice(ty)) + } + + pub fn mk_tup(&self, ts: Vec>) -> Ty<'tcx> { + self.mk_ty(TyTuple(ts)) + } + + pub fn mk_nil(&self) -> Ty<'tcx> { + self.mk_tup(Vec::new()) + } + + pub fn mk_bool(&self) -> Ty<'tcx> { + self.mk_ty(TyBool) + } + + pub fn mk_fn(&self, + opt_def_id: Option, + fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyBareFn(opt_def_id, fty)) + } + + pub fn mk_ctor_fn(&self, + def_id: ast::DefId, + input_tys: &[Ty<'tcx>], + output: Ty<'tcx>) -> Ty<'tcx> { + let input_args = input_tys.iter().cloned().collect(); + self.mk_fn(Some(def_id), self.mk_bare_fn(BareFnTy { + unsafety: ast::Unsafety::Normal, + abi: abi::Rust, + sig: ty::Binder(FnSig { + inputs: input_args, + output: ty::FnConverging(output), + variadic: false + }) + })) + } + + pub fn mk_trait(&self, + principal: ty::PolyTraitRef<'tcx>, + bounds: ExistentialBounds<'tcx>) + -> Ty<'tcx> + { + assert!(bound_list_is_sorted(&bounds.projection_bounds)); + + let inner = box TraitTy { + principal: principal, + bounds: bounds + }; + self.mk_ty(TyTrait(inner)) + } + + pub fn mk_projection(&self, + trait_ref: TraitRef<'tcx>, + item_name: ast::Name) + -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name }; + self.mk_ty(TyProjection(inner)) + } + + pub fn mk_struct(&self, struct_id: ast::DefId, + substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + self.mk_ty(TyStruct(struct_id, substs)) + } + + pub fn mk_closure(&self, closure_id: ast::DefId, substs: &'tcx Substs<'tcx>) + -> Ty<'tcx> { + self.mk_ty(TyClosure(closure_id, substs)) + } + + pub fn mk_var(&self, v: TyVid) -> Ty<'tcx> { + self.mk_infer(TyVar(v)) + } + + pub fn mk_int_var(&self, v: IntVid) -> Ty<'tcx> { + self.mk_infer(IntVar(v)) + } + + pub fn mk_float_var(&self, v: FloatVid) -> Ty<'tcx> { + self.mk_infer(FloatVar(v)) + } + + pub fn mk_infer(&self, it: InferTy) -> Ty<'tcx> { + self.mk_ty(TyInfer(it)) + } + + pub fn mk_param(&self, + space: subst::ParamSpace, + index: u32, + name: ast::Name) -> Ty<'tcx> { + self.mk_ty(TyParam(ParamTy { space: space, idx: index, name: name })) + } + + pub fn mk_self_type(&self) -> Ty<'tcx> { + self.mk_param(subst::SelfSpace, 0, special_idents::type_self.name) + } -pub fn mk_param<'tcx>(cx: &ctxt<'tcx>, - space: subst::ParamSpace, - index: u32, - name: ast::Name) -> Ty<'tcx> { - mk_t(cx, TyParam(ParamTy { space: space, idx: index, name: name })) + pub fn mk_param_from_def(&self, def: &TypeParameterDef) -> Ty<'tcx> { + self.mk_param(def.space, def.index, def.name) + } } -pub fn mk_self_type<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> { - mk_param(cx, subst::SelfSpace, 0, special_idents::type_self.name) +fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool { + bounds.is_empty() || + bounds[1..].iter().enumerate().all( + |(index, bound)| bounds[index].sort_key() <= bound.sort_key()) } -pub fn mk_param_from_def<'tcx>(cx: &ctxt<'tcx>, def: &TypeParameterDef) -> Ty<'tcx> { - mk_param(cx, def.space, def.index, def.name) +pub fn sort_bounds_list(bounds: &mut [ty::PolyProjectionPredicate]) { + bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())) } impl<'tcx> TyS<'tcx> { @@ -3631,42 +3754,24 @@ impl<'tcx> TyS<'tcx> { _ => false, } } -} - -pub fn walk_ty<'tcx, F>(ty_root: Ty<'tcx>, mut f: F) - where F: FnMut(Ty<'tcx>), -{ - for ty in ty_root.walk() { - f(ty); - } -} -/// Walks `ty` and any types appearing within `ty`, invoking the -/// callback `f` on each type. If the callback returns false, then the -/// children of the current type are ignored. -/// -/// Note: prefer `ty.walk()` where possible. -pub fn maybe_walk_ty<'tcx,F>(ty_root: Ty<'tcx>, mut f: F) - where F : FnMut(Ty<'tcx>) -> bool -{ - let mut walker = ty_root.walk(); - while let Some(ty) = walker.next() { - if !f(ty) { - walker.skip_current_subtree(); + /// Walks `ty` and any types appearing within `ty`, invoking the + /// callback `f` on each type. If the callback returns false, then the + /// children of the current type are ignored. + /// + /// Note: prefer `ty.walk()` where possible. + pub fn maybe_walk(&'tcx self, mut f: F) + where F : FnMut(Ty<'tcx>) -> bool + { + let mut walker = self.walk(); + while let Some(ty) = walker.next() { + if !f(ty) { + walker.skip_current_subtree(); + } } } } -// Folds types from the bottom up. -pub fn fold_ty<'tcx, F>(cx: &ctxt<'tcx>, t0: Ty<'tcx>, - fldop: F) - -> Ty<'tcx> where - F: FnMut(Ty<'tcx>) -> Ty<'tcx>, -{ - let mut f = ty_fold::BottomUpFolder {tcx: cx, fldop: fldop}; - f.fold_ty(t0) -} - impl ParamTy { pub fn new(space: subst::ParamSpace, index: u32, @@ -3683,8 +3788,8 @@ impl ParamTy { ParamTy::new(def.space, def.index, def.name) } - pub fn to_ty<'tcx>(self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { - ty::mk_param(tcx, self.space, self.idx, self.name) + pub fn to_ty<'tcx>(self, tcx: &ctxt<'tcx>) -> Ty<'tcx> { + tcx.mk_param(self.space, self.idx, self.name) } pub fn is_self(&self) -> bool { @@ -3703,140 +3808,142 @@ impl<'tcx> ItemSubsts<'tcx> { } // Type utilities - -pub fn type_is_nil(ty: Ty) -> bool { - match ty.sty { - TyTuple(ref tys) => tys.is_empty(), - _ => false +impl<'tcx> TyS<'tcx> { + pub fn is_nil(&self) -> bool { + match self.sty { + TyTuple(ref tys) => tys.is_empty(), + _ => false + } } -} - -pub fn type_is_error(ty: Ty) -> bool { - ty.flags.get().intersects(TypeFlags::HAS_TY_ERR) -} - -pub fn type_needs_subst(ty: Ty) -> bool { - ty.flags.get().intersects(TypeFlags::NEEDS_SUBST) -} -pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool { - tref.substs.types.any(|&ty| type_is_error(ty)) -} + pub fn is_empty(&self, cx: &ctxt) -> bool { + match self.sty { + TyEnum(did, _) => cx.enum_variants(did).is_empty(), + _ => false + } + } -pub fn type_is_ty_var(ty: Ty) -> bool { - match ty.sty { - TyInfer(TyVar(_)) => true, - _ => false + pub fn is_ty_var(&self) -> bool { + match self.sty { + TyInfer(TyVar(_)) => true, + _ => false + } } -} -pub fn type_is_bool(ty: Ty) -> bool { ty.sty == TyBool } + pub fn is_bool(&self) -> bool { self.sty == TyBool } -pub fn type_is_self(ty: Ty) -> bool { - match ty.sty { - TyParam(ref p) => p.space == subst::SelfSpace, - _ => false + pub fn is_self(&self) -> bool { + match self.sty { + TyParam(ref p) => p.space == subst::SelfSpace, + _ => false + } } -} -fn type_is_slice(ty: Ty) -> bool { - match ty.sty { - TyRawPtr(mt) | TyRef(_, mt) => match mt.ty.sty { - TySlice(_) | TyStr => true, - _ => false, - }, - _ => false + fn is_slice(&self) -> bool { + match self.sty { + TyRawPtr(mt) | TyRef(_, mt) => match mt.ty.sty { + TySlice(_) | TyStr => true, + _ => false, + }, + _ => false + } } -} -pub fn type_is_structural(ty: Ty) -> bool { - match ty.sty { - TyStruct(..) | TyTuple(_) | TyEnum(..) | - TyArray(..) | TyClosure(..) => true, - _ => type_is_slice(ty) | type_is_trait(ty) + pub fn is_structural(&self) -> bool { + match self.sty { + TyStruct(..) | TyTuple(_) | TyEnum(..) | + TyArray(..) | TyClosure(..) => true, + _ => self.is_slice() | self.is_trait() + } } -} -pub fn type_is_simd(cx: &ctxt, ty: Ty) -> bool { - match ty.sty { - TyStruct(did, _) => lookup_simd(cx, did), - _ => false + pub fn is_simd(&self, cx: &ctxt) -> bool { + match self.sty { + TyStruct(did, _) => cx.lookup_simd(did), + _ => false + } } -} -pub fn sequence_element_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { - TyArray(ty, _) | TySlice(ty) => ty, - TyStr => mk_mach_uint(cx, ast::TyU8), - _ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}", - ty)), + pub fn sequence_element_type(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> { + match self.sty { + TyArray(ty, _) | TySlice(ty) => ty, + TyStr => cx.mk_mach_uint(ast::TyU8), + _ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}", + self)), + } } -} -pub fn simd_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { - TyStruct(did, substs) => { - let fields = lookup_struct_fields(cx, did); - lookup_field_type(cx, did, fields[0].id, substs) + pub fn simd_type(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> { + match self.sty { + TyStruct(did, substs) => { + let fields = cx.lookup_struct_fields(did); + cx.lookup_field_type(did, fields[0].id, substs) + } + _ => panic!("simd_type called on invalid type") } - _ => panic!("simd_type called on invalid type") } -} -pub fn simd_size(cx: &ctxt, ty: Ty) -> usize { - match ty.sty { - TyStruct(did, _) => { - let fields = lookup_struct_fields(cx, did); - fields.len() + pub fn simd_size(&self, cx: &ctxt) -> usize { + match self.sty { + TyStruct(did, _) => { + cx.lookup_struct_fields(did).len() + } + _ => panic!("simd_size called on invalid type") } - _ => panic!("simd_size called on invalid type") } -} -pub fn type_is_region_ptr(ty: Ty) -> bool { - match ty.sty { - TyRef(..) => true, - _ => false + pub fn is_region_ptr(&self) -> bool { + match self.sty { + TyRef(..) => true, + _ => false + } } -} -pub fn type_is_unsafe_ptr(ty: Ty) -> bool { - match ty.sty { - TyRawPtr(_) => return true, - _ => return false + pub fn is_unsafe_ptr(&self) -> bool { + match self.sty { + TyRawPtr(_) => return true, + _ => return false + } } -} -pub fn type_is_unique(ty: Ty) -> bool { - match ty.sty { - TyBox(_) => true, - _ => false + pub fn is_unique(&self) -> bool { + match self.sty { + TyBox(_) => true, + _ => false + } } -} -/* - A scalar type is one that denotes an atomic datum, with no sub-components. - (A TyRawPtr is scalar because it represents a non-managed pointer, so its - contents are abstract to rustc.) -*/ -pub fn type_is_scalar(ty: Ty) -> bool { - match ty.sty { - TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) | - TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) | - TyBareFn(..) | TyRawPtr(_) => true, - _ => false + /* + A scalar type is one that denotes an atomic datum, with no sub-components. + (A TyRawPtr is scalar because it represents a non-managed pointer, so its + contents are abstract to rustc.) + */ + pub fn is_scalar(&self) -> bool { + match self.sty { + TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) | + TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) | + TyBareFn(..) | TyRawPtr(_) => true, + _ => false + } } -} -/// Returns true if this type is a floating point type and false otherwise. -pub fn type_is_floating_point(ty: Ty) -> bool { - match ty.sty { - TyFloat(_) | - TyInfer(FloatVar(_)) => - true, + /// Returns true if this type is a floating point type and false otherwise. + pub fn is_floating_point(&self) -> bool { + match self.sty { + TyFloat(_) | + TyInfer(FloatVar(_)) => true, + _ => false, + } + } - _ => - false, + pub fn ty_to_def_id(&self) -> Option { + match self.sty { + TyTrait(ref tt) => Some(tt.principal_def_id()), + TyStruct(id, _) | + TyEnum(id, _) | + TyClosure(id, _) => Some(id), + _ => None + } } } @@ -3991,454 +4098,428 @@ impl fmt::Debug for TypeContents { } } -pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { - return memoized(&cx.tc_cache, ty, |ty| { - tc_ty(cx, ty, &mut FnvHashMap()) - }); +impl<'tcx> TyS<'tcx> { + pub fn type_contents(&'tcx self, cx: &ctxt<'tcx>) -> TypeContents { + return memoized(&cx.tc_cache, self, |ty| { + tc_ty(cx, ty, &mut FnvHashMap()) + }); - fn tc_ty<'tcx>(cx: &ctxt<'tcx>, - ty: Ty<'tcx>, - cache: &mut FnvHashMap, TypeContents>) -> TypeContents - { - // Subtle: Note that we are *not* using cx.tc_cache here but rather a - // private cache for this walk. This is needed in the case of cyclic - // types like: - // - // struct List { next: Box>, ... } - // - // When computing the type contents of such a type, we wind up deeply - // recursing as we go. So when we encounter the recursive reference - // to List, we temporarily use TC::None as its contents. Later we'll - // patch up the cache with the correct value, once we've computed it - // (this is basically a co-inductive process, if that helps). So in - // the end we'll compute TC::OwnsOwned, in this case. - // - // The problem is, as we are doing the computation, we will also - // compute an *intermediate* contents for, e.g., Option of - // TC::None. This is ok during the computation of List itself, but if - // we stored this intermediate value into cx.tc_cache, then later - // requests for the contents of Option would also yield TC::None - // which is incorrect. This value was computed based on the crutch - // value for the type contents of list. The correct value is - // TC::OwnsOwned. This manifested as issue #4821. - match cache.get(&ty) { - Some(tc) => { return *tc; } - None => {} - } - match cx.tc_cache.borrow().get(&ty) { // Must check both caches! - Some(tc) => { return *tc; } - None => {} - } - cache.insert(ty, TC::None); - - let result = match ty.sty { - // usize and isize are ffi-unsafe - TyUint(ast::TyUs) | TyInt(ast::TyIs) => { - TC::ReachesFfiUnsafe - } - - // Scalar and unique types are sendable, and durable - TyInfer(ty::FreshIntTy(_)) | TyInfer(ty::FreshFloatTy(_)) | - TyBool | TyInt(_) | TyUint(_) | TyFloat(_) | - TyBareFn(..) | ty::TyChar => { - TC::None - } - - TyBox(typ) => { - TC::ReachesFfiUnsafe | match typ.sty { - TyStr => TC::OwnsOwned, - _ => tc_ty(cx, typ, cache).owned_pointer(), + fn tc_ty<'tcx>(cx: &ctxt<'tcx>, + ty: Ty<'tcx>, + cache: &mut FnvHashMap, TypeContents>) -> TypeContents + { + // Subtle: Note that we are *not* using cx.tc_cache here but rather a + // private cache for this walk. This is needed in the case of cyclic + // types like: + // + // struct List { next: Box>, ... } + // + // When computing the type contents of such a type, we wind up deeply + // recursing as we go. So when we encounter the recursive reference + // to List, we temporarily use TC::None as its contents. Later we'll + // patch up the cache with the correct value, once we've computed it + // (this is basically a co-inductive process, if that helps). So in + // the end we'll compute TC::OwnsOwned, in this case. + // + // The problem is, as we are doing the computation, we will also + // compute an *intermediate* contents for, e.g., Option of + // TC::None. This is ok during the computation of List itself, but if + // we stored this intermediate value into cx.tc_cache, then later + // requests for the contents of Option would also yield TC::None + // which is incorrect. This value was computed based on the crutch + // value for the type contents of list. The correct value is + // TC::OwnsOwned. This manifested as issue #4821. + match cache.get(&ty) { + Some(tc) => { return *tc; } + None => {} + } + match cx.tc_cache.borrow().get(&ty) { // Must check both caches! + Some(tc) => { return *tc; } + None => {} + } + cache.insert(ty, TC::None); + + let result = match ty.sty { + // usize and isize are ffi-unsafe + TyUint(ast::TyUs) | TyInt(ast::TyIs) => { + TC::ReachesFfiUnsafe } - } - - TyTrait(box TraitTy { ref bounds, .. }) => { - object_contents(bounds) | TC::ReachesFfiUnsafe | TC::Nonsized - } - TyRawPtr(ref mt) => { - tc_ty(cx, mt.ty, cache).unsafe_pointer() - } + // Scalar and unique types are sendable, and durable + TyInfer(ty::FreshIntTy(_)) | TyInfer(ty::FreshFloatTy(_)) | + TyBool | TyInt(_) | TyUint(_) | TyFloat(_) | + TyBareFn(..) | ty::TyChar => { + TC::None + } - TyRef(r, ref mt) => { - TC::ReachesFfiUnsafe | match mt.ty.sty { - TyStr => borrowed_contents(*r, ast::MutImmutable), - TyArray(..) | - TySlice(_) => tc_ty(cx, mt.ty, cache).reference(borrowed_contents(*r, - mt.mutbl)), - _ => tc_ty(cx, mt.ty, cache).reference(borrowed_contents(*r, mt.mutbl)), + TyBox(typ) => { + TC::ReachesFfiUnsafe | tc_ty(cx, typ, cache).owned_pointer() } - } - TyArray(ty, _) => { - tc_ty(cx, ty, cache) - } + TyTrait(box TraitTy { ref bounds, .. }) => { + object_contents(bounds) | TC::ReachesFfiUnsafe | TC::Nonsized + } - TySlice(ty) => { - tc_ty(cx, ty, cache) | TC::Nonsized - } - TyStr => TC::Nonsized, + TyRawPtr(ref mt) => { + tc_ty(cx, mt.ty, cache).unsafe_pointer() + } - TyStruct(did, substs) => { - let flds = struct_fields(cx, did, substs); - let mut res = - TypeContents::union(&flds[..], - |f| tc_mt(cx, f.mt, cache)); + TyRef(r, ref mt) => { + tc_ty(cx, mt.ty, cache).reference(borrowed_contents(*r, mt.mutbl)) | + TC::ReachesFfiUnsafe + } - if !lookup_repr_hints(cx, did).contains(&attr::ReprExtern) { - res = res | TC::ReachesFfiUnsafe; + TyArray(ty, _) => { + tc_ty(cx, ty, cache) } - if ty::has_dtor(cx, did) { - res = res | TC::OwnsDtor; + TySlice(ty) => { + tc_ty(cx, ty, cache) | TC::Nonsized } - apply_lang_items(cx, did, res) - } + TyStr => TC::Nonsized, - TyClosure(did, substs) => { - // FIXME(#14449): `borrowed_contents` below assumes `&mut` closure. - let param_env = ty::empty_parameter_environment(cx); - let upvars = closure_upvars(¶m_env, did, substs).unwrap(); - TypeContents::union(&upvars, |f| tc_ty(cx, &f.ty, cache)) - } + TyStruct(did, substs) => { + let flds = cx.struct_fields(did, substs); + let mut res = + TypeContents::union(&flds[..], + |f| tc_mt(cx, f.mt, cache)); - TyTuple(ref tys) => { - TypeContents::union(&tys[..], - |ty| tc_ty(cx, *ty, cache)) - } + if !cx.lookup_repr_hints(did).contains(&attr::ReprExtern) { + res = res | TC::ReachesFfiUnsafe; + } - TyEnum(did, substs) => { - let variants = substd_enum_variants(cx, did, substs); - let mut res = - TypeContents::union(&variants[..], |variant| { - TypeContents::union(&variant.args, - |arg_ty| { - tc_ty(cx, *arg_ty, cache) - }) - }); + if cx.has_dtor(did) { + res = res | TC::OwnsDtor; + } + apply_lang_items(cx, did, res) + } - if ty::has_dtor(cx, did) { - res = res | TC::OwnsDtor; + TyClosure(did, substs) => { + // FIXME(#14449): `borrowed_contents` below assumes `&mut` closure. + let param_env = cx.empty_parameter_environment(); + let infcx = infer::new_infer_ctxt(cx, &cx.tables, Some(param_env), false); + let upvars = infcx.closure_upvars(did, substs).unwrap(); + TypeContents::union(&upvars, |f| tc_ty(cx, &f.ty, cache)) } - if !variants.is_empty() { - let repr_hints = lookup_repr_hints(cx, did); - if repr_hints.len() > 1 { - // this is an error later on, but this type isn't safe - res = res | TC::ReachesFfiUnsafe; + TyTuple(ref tys) => { + TypeContents::union(&tys[..], + |ty| tc_ty(cx, *ty, cache)) + } + + TyEnum(did, substs) => { + let variants = cx.substd_enum_variants(did, substs); + let mut res = + TypeContents::union(&variants[..], |variant| { + TypeContents::union(&variant.args, + |arg_ty| { + tc_ty(cx, *arg_ty, cache) + }) + }); + + if cx.has_dtor(did) { + res = res | TC::OwnsDtor; } - match repr_hints.get(0) { - Some(h) => if !h.is_ffi_safe() { - res = res | TC::ReachesFfiUnsafe; - }, - // ReprAny - None => { + if !variants.is_empty() { + let repr_hints = cx.lookup_repr_hints(did); + if repr_hints.len() > 1 { + // this is an error later on, but this type isn't safe res = res | TC::ReachesFfiUnsafe; + } - // We allow ReprAny enums if they are eligible for - // the nullable pointer optimization and the - // contained type is an `extern fn` + match repr_hints.get(0) { + Some(h) => if !h.is_ffi_safe() { + res = res | TC::ReachesFfiUnsafe; + }, + // ReprAny + None => { + res = res | TC::ReachesFfiUnsafe; - if variants.len() == 2 { - let mut data_idx = 0; + // We allow ReprAny enums if they are eligible for + // the nullable pointer optimization and the + // contained type is an `extern fn` - if variants[0].args.is_empty() { - data_idx = 1; - } + if variants.len() == 2 { + let mut data_idx = 0; + + if variants[0].args.is_empty() { + data_idx = 1; + } - if variants[data_idx].args.len() == 1 { - match variants[data_idx].args[0].sty { - TyBareFn(..) => { res = res - TC::ReachesFfiUnsafe; } - _ => { } + if variants[data_idx].args.len() == 1 { + match variants[data_idx].args[0].sty { + TyBareFn(..) => { res = res - TC::ReachesFfiUnsafe; } + _ => { } + } } } } } } - } - apply_lang_items(cx, did, res) - } + apply_lang_items(cx, did, res) + } - TyProjection(..) | - TyParam(_) => { - TC::All - } + TyProjection(..) | + TyParam(_) => { + TC::All + } - TyInfer(_) | - TyError => { - cx.sess.bug("asked to compute contents of error type"); - } - }; + TyInfer(_) | + TyError => { + cx.sess.bug("asked to compute contents of error type"); + } + }; - cache.insert(ty, result); - result - } + cache.insert(ty, result); + result + } - fn tc_mt<'tcx>(cx: &ctxt<'tcx>, - mt: mt<'tcx>, - cache: &mut FnvHashMap, TypeContents>) -> TypeContents - { - let mc = TC::ReachesMutable.when(mt.mutbl == MutMutable); - mc | tc_ty(cx, mt.ty, cache) - } + fn tc_mt<'tcx>(cx: &ctxt<'tcx>, + mt: mt<'tcx>, + cache: &mut FnvHashMap, TypeContents>) -> TypeContents + { + let mc = TC::ReachesMutable.when(mt.mutbl == MutMutable); + mc | tc_ty(cx, mt.ty, cache) + } - fn apply_lang_items(cx: &ctxt, did: ast::DefId, tc: TypeContents) - -> TypeContents { - if Some(did) == cx.lang_items.unsafe_cell_type() { - tc | TC::InteriorUnsafe - } else { - tc + fn apply_lang_items(cx: &ctxt, did: ast::DefId, tc: TypeContents) + -> TypeContents { + if Some(did) == cx.lang_items.unsafe_cell_type() { + tc | TC::InteriorUnsafe + } else { + tc + } } - } - /// Type contents due to containing a reference with the region `region` and borrow kind `bk` - fn borrowed_contents(region: ty::Region, - mutbl: ast::Mutability) - -> TypeContents { - let b = match mutbl { - ast::MutMutable => TC::ReachesMutable, - ast::MutImmutable => TC::None, - }; - b | (TC::ReachesBorrowed).when(region != ty::ReStatic) - } - - fn object_contents(bounds: &ExistentialBounds) -> TypeContents { - // These are the type contents of the (opaque) interior. We - // make no assumptions (other than that it cannot have an - // in-scope type parameter within, which makes no sense). - let mut tc = TC::All - TC::InteriorParam; - for bound in &bounds.builtin_bounds { - tc = tc - match bound { - BoundSync | BoundSend | BoundCopy => TC::None, - BoundSized => TC::Nonsized, + /// Type contents due to containing a reference with + /// the region `region` and borrow kind `bk`. + fn borrowed_contents(region: ty::Region, + mutbl: ast::Mutability) + -> TypeContents { + let b = match mutbl { + ast::MutMutable => TC::ReachesMutable, + ast::MutImmutable => TC::None, }; + b | (TC::ReachesBorrowed).when(region != ty::ReStatic) + } + + fn object_contents(bounds: &ExistentialBounds) -> TypeContents { + // These are the type contents of the (opaque) interior. We + // make no assumptions (other than that it cannot have an + // in-scope type parameter within, which makes no sense). + let mut tc = TC::All - TC::InteriorParam; + for bound in &bounds.builtin_bounds { + tc = tc - match bound { + BoundSync | BoundSend | BoundCopy => TC::None, + BoundSized => TC::Nonsized, + }; + } + return tc; } - return tc; } -} -fn type_impls_bound<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>, - tcx: &ty::ctxt<'tcx>, - ty: Ty<'tcx>, - bound: ty::BuiltinBound, - span: Span) - -> bool -{ - let pe; - let param_env = match param_env { - Some(e) => e, - None => { - pe = empty_parameter_environment(tcx); - &pe + fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + bound: ty::BuiltinBound, + span: Span) + -> bool + { + let tcx = param_env.tcx; + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()), false); + + let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, + self, bound, span); + + debug!("Ty::impls_bound({:?}, {:?}) = {:?}", + self, bound, is_impld); + + is_impld + } + + // FIXME (@jroesch): I made this public to use it, not sure if should be private + pub fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool { + if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) { + return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT); } - }; - let infcx = infer::new_infer_ctxt(tcx); - let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound, span); + assert!(!self.needs_infer()); - debug!("type_impls_bound({:?}, {:?}) = {:?}", - ty, - bound, - is_impld); + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyRawPtr(..) | TyBareFn(..) | TyRef(_, mt { + mutbl: ast::MutImmutable, .. + }) => Some(false), - is_impld -} + TyStr | TyBox(..) | TyRef(_, mt { + mutbl: ast::MutMutable, .. + }) => Some(true), -pub fn type_moves_by_default<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>, - span: Span, - ty: Ty<'tcx>) - -> bool -{ - if ty.flags.get().intersects(TypeFlags::MOVENESS_CACHED) { - return ty.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT); - } - - assert!(!ty::type_needs_infer(ty)); - - // Fast-path for primitive types - let result = match ty.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyRawPtr(..) | TyBareFn(..) | TyRef(_, mt { - mutbl: ast::MutImmutable, .. - }) => Some(false), - - TyStr | TyBox(..) | TyRef(_, mt { - mutbl: ast::MutMutable, .. - }) => Some(true), - - TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | - TyClosure(..) | TyEnum(..) | TyStruct(..) | - TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None - }.unwrap_or_else(|| !type_impls_bound(Some(param_env), - param_env.tcx, - ty, - ty::BoundCopy, - span)); - - if !type_has_params(ty) && !type_has_self(ty) { - ty.flags.set(ty.flags.get() | if result { - TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT - } else { - TypeFlags::MOVENESS_CACHED - }); + TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | + TyClosure(..) | TyEnum(..) | TyStruct(..) | + TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None + }.unwrap_or_else(|| !self.impls_bound(param_env, ty::BoundCopy, span)); + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT + } else { + TypeFlags::MOVENESS_CACHED + }); + } + + result } - result -} + #[inline] + pub fn is_sized<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool + { + if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) { + return self.flags.get().intersects(TypeFlags::IS_SIZED); + } -#[inline] -pub fn type_is_sized<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>, - tcx: &ty::ctxt<'tcx>, - span: Span, - ty: Ty<'tcx>) - -> bool -{ - if ty.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) { - let result = ty.flags.get().intersects(TypeFlags::IS_SIZED); - return result; + self.is_sized_uncached(param_env, span) } - type_is_sized_uncached(param_env, tcx, span, ty) -} + fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>, + span: Span) -> bool { + assert!(!self.needs_infer()); -fn type_is_sized_uncached<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>, - tcx: &ty::ctxt<'tcx>, - span: Span, - ty: Ty<'tcx>) -> bool { - assert!(!ty::type_needs_infer(ty)); + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) | + TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), - // Fast-path for primitive types - let result = match ty.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) | - TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), + TyStr | TyTrait(..) | TySlice(_) => Some(false), - TyStr | TyTrait(..) | TySlice(_) => Some(false), + TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) | + TyInfer(..) | TyError => None + }.unwrap_or_else(|| self.impls_bound(param_env, ty::BoundSized, span)); - TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) | - TyInfer(..) | TyError => None - }.unwrap_or_else(|| type_impls_bound(param_env, tcx, ty, ty::BoundSized, span)); + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED + } else { + TypeFlags::SIZEDNESS_CACHED + }); + } - if !type_has_params(ty) && !type_has_self(ty) { - ty.flags.set(ty.flags.get() | if result { - TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED - } else { - TypeFlags::SIZEDNESS_CACHED - }); + result } - result -} + pub fn is_ffi_safe(&'tcx self, cx: &ctxt<'tcx>) -> bool { + !self.type_contents(cx).intersects(TC::ReachesFfiUnsafe) + } -pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - !type_contents(cx, ty).intersects(TC::ReachesFfiUnsafe) -} + // True if instantiating an instance of `r_ty` requires an instance of `r_ty`. + pub fn is_instantiable(&'tcx self, cx: &ctxt<'tcx>) -> bool { + fn type_requires<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec, + r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool { + debug!("type_requires({:?}, {:?})?", + r_ty, ty); -// True if instantiating an instance of `r_ty` requires an instance of `r_ty`. -pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool { - fn type_requires<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec, - r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool { - debug!("type_requires({:?}, {:?})?", - r_ty, ty); + let r = r_ty == ty || subtypes_require(cx, seen, r_ty, ty); - let r = r_ty == ty || subtypes_require(cx, seen, r_ty, ty); + debug!("type_requires({:?}, {:?})? {:?}", + r_ty, ty, r); + return r; + } - debug!("type_requires({:?}, {:?})? {:?}", - r_ty, ty, r); - return r; - } + fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec, + r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool { + debug!("subtypes_require({:?}, {:?})?", + r_ty, ty); - fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec, - r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool { - debug!("subtypes_require({:?}, {:?})?", - r_ty, ty); + let r = match ty.sty { + // fixed length vectors need special treatment compared to + // normal vectors, since they don't necessarily have the + // possibility to have length zero. + TyArray(_, 0) => false, // don't need no contents + TyArray(ty, _) => type_requires(cx, seen, r_ty, ty), - let r = match ty.sty { - // fixed length vectors need special treatment compared to - // normal vectors, since they don't necessarily have the - // possibility to have length zero. - TyArray(_, 0) => false, // don't need no contents - TyArray(ty, _) => type_requires(cx, seen, r_ty, ty), + TyBool | + TyChar | + TyInt(_) | + TyUint(_) | + TyFloat(_) | + TyStr | + TyBareFn(..) | + TyParam(_) | + TyProjection(_) | + TySlice(_) => { + false + } + TyBox(typ) => { + type_requires(cx, seen, r_ty, typ) + } + TyRef(_, ref mt) => { + type_requires(cx, seen, r_ty, mt.ty) + } - TyBool | - TyChar | - TyInt(_) | - TyUint(_) | - TyFloat(_) | - TyStr | - TyBareFn(..) | - TyParam(_) | - TyProjection(_) | - TySlice(_) => { - false - } - TyBox(typ) => { - type_requires(cx, seen, r_ty, typ) - } - TyRef(_, ref mt) => { - type_requires(cx, seen, r_ty, mt.ty) - } + TyRawPtr(..) => { + false // unsafe ptrs can always be NULL + } - TyRawPtr(..) => { - false // unsafe ptrs can always be NULL - } + TyTrait(..) => { + false + } - TyTrait(..) => { - false - } + TyStruct(ref did, _) if seen.contains(did) => { + false + } - TyStruct(ref did, _) if seen.contains(did) => { - false - } + TyStruct(did, substs) => { + seen.push(did); + let fields = cx.struct_fields(did, substs); + let r = fields.iter().any(|f| type_requires(cx, seen, r_ty, f.mt.ty)); + seen.pop().unwrap(); + r + } - TyStruct(did, substs) => { - seen.push(did); - let fields = struct_fields(cx, did, substs); - let r = fields.iter().any(|f| type_requires(cx, seen, r_ty, f.mt.ty)); - seen.pop().unwrap(); - r - } + TyError | + TyInfer(_) | + TyClosure(..) => { + // this check is run on type definitions, so we don't expect to see + // inference by-products or closure types + cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty)) + } - TyError | - TyInfer(_) | - TyClosure(..) => { - // this check is run on type definitions, so we don't expect to see - // inference by-products or closure types - cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty)) - } + TyTuple(ref ts) => { + ts.iter().any(|ty| type_requires(cx, seen, r_ty, *ty)) + } - TyTuple(ref ts) => { - ts.iter().any(|ty| type_requires(cx, seen, r_ty, *ty)) - } + TyEnum(ref did, _) if seen.contains(did) => { + false + } - TyEnum(ref did, _) if seen.contains(did) => { - false - } + TyEnum(did, substs) => { + seen.push(did); + let vs = cx.enum_variants(did); + let r = !vs.is_empty() && vs.iter().all(|variant| { + variant.args.iter().any(|aty| { + let sty = aty.subst(cx, substs); + type_requires(cx, seen, r_ty, sty) + }) + }); + seen.pop().unwrap(); + r + } + }; - TyEnum(did, substs) => { - seen.push(did); - let vs = enum_variants(cx, did); - let r = !vs.is_empty() && vs.iter().all(|variant| { - variant.args.iter().any(|aty| { - let sty = aty.subst(cx, substs); - type_requires(cx, seen, r_ty, sty) - }) - }); - seen.pop().unwrap(); - r - } - }; + debug!("subtypes_require({:?}, {:?})? {:?}", + r_ty, ty, r); - debug!("subtypes_require({:?}, {:?})? {:?}", - r_ty, ty, r); + return r; + } - return r; + let mut seen = Vec::new(); + !subtypes_require(cx, &mut seen, self, self) } - - let mut seen = Vec::new(); - !subtypes_require(cx, &mut seen, r_ty, r_ty) } /// Describes whether a type is representable. For types that are not @@ -4456,781 +4537,448 @@ pub enum Representability { SelfRecursive, } -/// Check whether a type is representable. This means it cannot contain unboxed -/// structural recursion. This check is needed for structs and enums. -pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) - -> Representability { - - // Iterate until something non-representable is found - fn find_nonrepresentable<'tcx, It: Iterator>>(cx: &ctxt<'tcx>, sp: Span, - seen: &mut Vec>, - iter: It) - -> Representability { - iter.fold(Representable, - |r, ty| cmp::max(r, is_type_structurally_recursive(cx, sp, seen, ty))) - } - - fn are_inner_types_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span, - seen: &mut Vec>, ty: Ty<'tcx>) - -> Representability { - match ty.sty { - TyTuple(ref ts) => { - find_nonrepresentable(cx, sp, seen, ts.iter().cloned()) - } - // Fixed-length vectors. - // FIXME(#11924) Behavior undecided for zero-length vectors. - TyArray(ty, _) => { - is_type_structurally_recursive(cx, sp, seen, ty) - } - TyStruct(did, substs) => { - let fields = struct_fields(cx, did, substs); - find_nonrepresentable(cx, sp, seen, fields.iter().map(|f| f.mt.ty)) - } - TyEnum(did, substs) => { - let vs = enum_variants(cx, did); - let iter = vs.iter() - .flat_map(|variant| &variant.args) - .map(|aty| { aty.subst_spanned(cx, substs, Some(sp)) }); +impl<'tcx> TyS<'tcx> { + /// Check whether a type is representable. This means it cannot contain unboxed + /// structural recursion. This check is needed for structs and enums. + pub fn is_representable(&'tcx self, cx: &ctxt<'tcx>, sp: Span) -> Representability { + + // Iterate until something non-representable is found + fn find_nonrepresentable<'tcx, It: Iterator>>(cx: &ctxt<'tcx>, sp: Span, + seen: &mut Vec>, + iter: It) + -> Representability { + iter.fold(Representable, + |r, ty| cmp::max(r, is_type_structurally_recursive(cx, sp, seen, ty))) + } + + fn are_inner_types_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span, + seen: &mut Vec>, ty: Ty<'tcx>) + -> Representability { + match ty.sty { + TyTuple(ref ts) => { + find_nonrepresentable(cx, sp, seen, ts.iter().cloned()) + } + // Fixed-length vectors. + // FIXME(#11924) Behavior undecided for zero-length vectors. + TyArray(ty, _) => { + is_type_structurally_recursive(cx, sp, seen, ty) + } + TyStruct(did, substs) => { + let fields = cx.struct_fields(did, substs); + find_nonrepresentable(cx, sp, seen, fields.iter().map(|f| f.mt.ty)) + } + TyEnum(did, substs) => { + let vs = cx.enum_variants(did); + let iter = vs.iter() + .flat_map(|variant| &variant.args) + .map(|aty| { aty.subst_spanned(cx, substs, Some(sp)) }); - find_nonrepresentable(cx, sp, seen, iter) - } - TyClosure(..) => { - // this check is run on type definitions, so we don't expect - // to see closure types - cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty)) + find_nonrepresentable(cx, sp, seen, iter) + } + TyClosure(..) => { + // this check is run on type definitions, so we don't expect + // to see closure types + cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty)) + } + _ => Representable, } - _ => Representable, } - } - fn same_struct_or_enum_def_id(ty: Ty, did: DefId) -> bool { - match ty.sty { - TyStruct(ty_did, _) | TyEnum(ty_did, _) => { - ty_did == did + fn same_struct_or_enum_def_id(ty: Ty, did: DefId) -> bool { + match ty.sty { + TyStruct(ty_did, _) | TyEnum(ty_did, _) => { + ty_did == did + } + _ => false } - _ => false } - } - fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.sty, &b.sty) { - (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | - (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { - if did_a != did_b { - return false; - } + fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + match (&a.sty, &b.sty) { + (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | + (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { + if did_a != did_b { + return false; + } - let types_a = substs_a.types.get_slice(subst::TypeSpace); - let types_b = substs_b.types.get_slice(subst::TypeSpace); + let types_a = substs_a.types.get_slice(subst::TypeSpace); + let types_b = substs_b.types.get_slice(subst::TypeSpace); - let mut pairs = types_a.iter().zip(types_b); + let mut pairs = types_a.iter().zip(types_b); - pairs.all(|(&a, &b)| same_type(a, b)) - } - _ => { - a == b + pairs.all(|(&a, &b)| same_type(a, b)) + } + _ => { + a == b + } } } - } - // Does the type `ty` directly (without indirection through a pointer) - // contain any types on stack `seen`? - fn is_type_structurally_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span, - seen: &mut Vec>, - ty: Ty<'tcx>) -> Representability { - debug!("is_type_structurally_recursive: {:?}", ty); + // Does the type `ty` directly (without indirection through a pointer) + // contain any types on stack `seen`? + fn is_type_structurally_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span, + seen: &mut Vec>, + ty: Ty<'tcx>) -> Representability { + debug!("is_type_structurally_recursive: {:?}", ty); - match ty.sty { - TyStruct(did, _) | TyEnum(did, _) => { - { - // Iterate through stack of previously seen types. - let mut iter = seen.iter(); - - // The first item in `seen` is the type we are actually curious about. - // We want to return SelfRecursive if this type contains itself. - // It is important that we DON'T take generic parameters into account - // for this check, so that Bar in this example counts as SelfRecursive: - // - // struct Foo; - // struct Bar { x: Bar } + match ty.sty { + TyStruct(did, _) | TyEnum(did, _) => { + { + // Iterate through stack of previously seen types. + let mut iter = seen.iter(); + + // The first item in `seen` is the type we are actually curious about. + // We want to return SelfRecursive if this type contains itself. + // It is important that we DON'T take generic parameters into account + // for this check, so that Bar in this example counts as SelfRecursive: + // + // struct Foo; + // struct Bar { x: Bar } + + match iter.next() { + Some(&seen_type) => { + if same_struct_or_enum_def_id(seen_type, did) { + debug!("SelfRecursive: {:?} contains {:?}", + seen_type, + ty); + return SelfRecursive; + } + } + None => {} + } - match iter.next() { - Some(&seen_type) => { - if same_struct_or_enum_def_id(seen_type, did) { - debug!("SelfRecursive: {:?} contains {:?}", + // We also need to know whether the first item contains other types + // that are structurally recursive. If we don't catch this case, we + // will recurse infinitely for some inputs. + // + // It is important that we DO take generic parameters into account + // here, so that code like this is considered SelfRecursive, not + // ContainsRecursive: + // + // struct Foo { Option> } + + for &seen_type in iter { + if same_type(ty, seen_type) { + debug!("ContainsRecursive: {:?} contains {:?}", seen_type, ty); - return SelfRecursive; + return ContainsRecursive; } } - None => {} } - // We also need to know whether the first item contains other types that - // are structurally recursive. If we don't catch this case, we will recurse - // infinitely for some inputs. - // - // It is important that we DO take generic parameters into account here, - // so that code like this is considered SelfRecursive, not ContainsRecursive: - // - // struct Foo { Option> } - - for &seen_type in iter { - if same_type(ty, seen_type) { - debug!("ContainsRecursive: {:?} contains {:?}", - seen_type, - ty); - return ContainsRecursive; - } - } + // For structs and enums, track all previously seen types by pushing them + // onto the 'seen' stack. + seen.push(ty); + let out = are_inner_types_recursive(cx, sp, seen, ty); + seen.pop(); + out + } + _ => { + // No need to push in other cases. + are_inner_types_recursive(cx, sp, seen, ty) } - - // For structs and enums, track all previously seen types by pushing them - // onto the 'seen' stack. - seen.push(ty); - let out = are_inner_types_recursive(cx, sp, seen, ty); - seen.pop(); - out - } - _ => { - // No need to push in other cases. - are_inner_types_recursive(cx, sp, seen, ty) } } - } - - debug!("is_type_representable: {:?}", ty); - - // To avoid a stack overflow when checking an enum variant or struct that - // contains a different, structurally recursive type, maintain a stack - // of seen types and check recursion for each of them (issues #3008, #3779). - let mut seen: Vec = Vec::new(); - let r = is_type_structurally_recursive(cx, sp, &mut seen, ty); - debug!("is_type_representable: {:?} is {:?}", ty, r); - r -} - -pub fn type_is_trait(ty: Ty) -> bool { - match ty.sty { - TyTrait(..) => true, - _ => false - } -} -pub fn type_is_integral(ty: Ty) -> bool { - match ty.sty { - TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true, - _ => false - } -} + debug!("is_type_representable: {:?}", self); -pub fn type_is_fresh(ty: Ty) -> bool { - match ty.sty { - TyInfer(FreshTy(_)) => true, - TyInfer(FreshIntTy(_)) => true, - TyInfer(FreshFloatTy(_)) => true, - _ => false + // To avoid a stack overflow when checking an enum variant or struct that + // contains a different, structurally recursive type, maintain a stack + // of seen types and check recursion for each of them (issues #3008, #3779). + let mut seen: Vec = Vec::new(); + let r = is_type_structurally_recursive(cx, sp, &mut seen, self); + debug!("is_type_representable: {:?} is {:?}", self, r); + r } -} -pub fn type_is_uint(ty: Ty) -> bool { - match ty.sty { - TyInfer(IntVar(_)) | TyUint(ast::TyUs) => true, - _ => false + pub fn is_trait(&self) -> bool { + match self.sty { + TyTrait(..) => true, + _ => false + } } -} -pub fn type_is_char(ty: Ty) -> bool { - match ty.sty { - TyChar => true, - _ => false + pub fn is_integral(&self) -> bool { + match self.sty { + TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true, + _ => false + } } -} -pub fn type_is_bare_fn(ty: Ty) -> bool { - match ty.sty { - TyBareFn(..) => true, - _ => false + pub fn is_fresh(&self) -> bool { + match self.sty { + TyInfer(FreshTy(_)) => true, + TyInfer(FreshIntTy(_)) => true, + TyInfer(FreshFloatTy(_)) => true, + _ => false + } } -} -pub fn type_is_bare_fn_item(ty: Ty) -> bool { - match ty.sty { - TyBareFn(Some(_), _) => true, - _ => false + pub fn is_uint(&self) -> bool { + match self.sty { + TyInfer(IntVar(_)) | TyUint(ast::TyUs) => true, + _ => false + } } -} -pub fn type_is_fp(ty: Ty) -> bool { - match ty.sty { - TyInfer(FloatVar(_)) | TyFloat(_) => true, - _ => false + pub fn is_char(&self) -> bool { + match self.sty { + TyChar => true, + _ => false + } } -} - -pub fn type_is_numeric(ty: Ty) -> bool { - return type_is_integral(ty) || type_is_fp(ty); -} -pub fn type_is_signed(ty: Ty) -> bool { - match ty.sty { - TyInt(_) => true, - _ => false + pub fn is_bare_fn(&self) -> bool { + match self.sty { + TyBareFn(..) => true, + _ => false + } } -} -pub fn type_is_machine(ty: Ty) -> bool { - match ty.sty { - TyInt(ast::TyIs) | TyUint(ast::TyUs) => false, - TyInt(..) | TyUint(..) | TyFloat(..) => true, - _ => false + pub fn is_bare_fn_item(&self) -> bool { + match self.sty { + TyBareFn(Some(_), _) => true, + _ => false + } } -} -// Whether a type is enum like, that is an enum type with only nullary -// constructors -pub fn type_is_c_like_enum(cx: &ctxt, ty: Ty) -> bool { - match ty.sty { - TyEnum(did, _) => { - let variants = enum_variants(cx, did); - if variants.is_empty() { - false - } else { - variants.iter().all(|v| v.args.is_empty()) - } + pub fn is_fp(&self) -> bool { + match self.sty { + TyInfer(FloatVar(_)) | TyFloat(_) => true, + _ => false } - _ => false } -} -// Returns the type and mutability of *ty. -// -// The parameter `explicit` indicates if this is an *explicit* dereference. -// Some types---notably unsafe ptrs---can only be dereferenced explicitly. -pub fn deref<'tcx>(ty: Ty<'tcx>, explicit: bool) -> Option> { - match ty.sty { - TyBox(ty) => { - Some(mt { - ty: ty, - mutbl: ast::MutImmutable, - }) - }, - TyRef(_, mt) => Some(mt), - TyRawPtr(mt) if explicit => Some(mt), - _ => None + pub fn is_numeric(&self) -> bool { + self.is_integral() || self.is_fp() } -} -pub fn type_content<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { - TyBox(ty) => ty, - TyRef(_, mt) | TyRawPtr(mt) => mt.ty, - _ => ty + pub fn is_signed(&self) -> bool { + match self.sty { + TyInt(_) => true, + _ => false + } } -} -// Returns the type of ty[i] -pub fn index<'tcx>(ty: Ty<'tcx>) -> Option> { - match ty.sty { - TyArray(ty, _) | TySlice(ty) => Some(ty), - _ => None + pub fn is_machine(&self) -> bool { + match self.sty { + TyInt(ast::TyIs) | TyUint(ast::TyUs) => false, + TyInt(..) | TyUint(..) | TyFloat(..) => true, + _ => false + } } -} -// Returns the type of elements contained within an 'array-like' type. -// This is exactly the same as the above, except it supports strings, -// which can't actually be indexed. -pub fn array_element_ty<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Option> { - match ty.sty { - TyArray(ty, _) | TySlice(ty) => Some(ty), - TyStr => Some(tcx.types.u8), - _ => None + // Whether a type is enum like, that is an enum type with only nullary + // constructors + pub fn is_c_like_enum(&self, cx: &ctxt) -> bool { + match self.sty { + TyEnum(did, _) => { + let variants = cx.enum_variants(did); + if variants.is_empty() { + false + } else { + variants.iter().all(|v| v.args.is_empty()) + } + } + _ => false + } } -} - -/// Returns the type of element at index `i` in tuple or tuple-like type `t`. -/// For an enum `t`, `variant` is None only if `t` is a univariant enum. -pub fn positional_element_ty<'tcx>(cx: &ctxt<'tcx>, - ty: Ty<'tcx>, - i: usize, - variant: Option) -> Option> { - - match (&ty.sty, variant) { - (&TyTuple(ref v), None) => v.get(i).cloned(), - - (&TyStruct(def_id, substs), None) => lookup_struct_fields(cx, def_id) - .get(i) - .map(|&t|lookup_item_type(cx, t.id).ty.subst(cx, substs)), - - (&TyEnum(def_id, substs), Some(variant_def_id)) => { - let variant_info = enum_variant_with_id(cx, def_id, variant_def_id); - variant_info.args.get(i).map(|t|t.subst(cx, substs)) + // Returns the type and mutability of *ty. + // + // The parameter `explicit` indicates if this is an *explicit* dereference. + // Some types---notably unsafe ptrs---can only be dereferenced explicitly. + pub fn builtin_deref(&self, explicit: bool) -> Option> { + match self.sty { + TyBox(ty) => { + Some(mt { + ty: ty, + mutbl: ast::MutImmutable, + }) + }, + TyRef(_, mt) => Some(mt), + TyRawPtr(mt) if explicit => Some(mt), + _ => None } + } - (&TyEnum(def_id, substs), None) => { - assert!(enum_is_univariant(cx, def_id)); - let enum_variants = enum_variants(cx, def_id); - let variant_info = &(*enum_variants)[0]; - variant_info.args.get(i).map(|t|t.subst(cx, substs)) + // Returns the type of ty[i] + pub fn builtin_index(&self) -> Option> { + match self.sty { + TyArray(ty, _) | TySlice(ty) => Some(ty), + _ => None } - - _ => None } -} - -/// Returns the type of element at field `n` in struct or struct-like type `t`. -/// For an enum `t`, `variant` must be some def id. -pub fn named_element_ty<'tcx>(cx: &ctxt<'tcx>, - ty: Ty<'tcx>, - n: ast::Name, - variant: Option) -> Option> { - match (&ty.sty, variant) { - (&TyStruct(def_id, substs), None) => { - let r = lookup_struct_fields(cx, def_id); - r.iter().find(|f| f.name == n) - .map(|&f| lookup_field_type(cx, def_id, f.id, substs)) - } - (&TyEnum(def_id, substs), Some(variant_def_id)) => { - let variant_info = enum_variant_with_id(cx, def_id, variant_def_id); - variant_info.arg_names.as_ref() - .expect("must have struct enum variant if accessing a named fields") - .iter().zip(&variant_info.args) - .find(|&(&name, _)| name == n) - .map(|(_name, arg_t)| arg_t.subst(cx, substs)) + pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> { + match self.sty { + TyBareFn(_, ref f) => &f.sig, + _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self) } - _ => None } -} -pub fn node_id_to_type<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> Ty<'tcx> { - match node_id_to_type_opt(cx, id) { - Some(ty) => ty, - None => cx.sess.bug( - &format!("node_id_to_type: no type for node `{}`", - cx.map.node_to_string(id))) + /// Returns the ABI of the given function. + pub fn fn_abi(&self) -> abi::Abi { + match self.sty { + TyBareFn(_, ref f) => f.abi, + _ => panic!("Ty::fn_abi() called on non-fn type"), + } } -} -pub fn node_id_to_type_opt<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> Option> { - match cx.node_types.borrow().get(&id) { - Some(&ty) => Some(ty), - None => None + // Type accessors for substructures of types + pub fn fn_args(&self) -> ty::Binder>> { + self.fn_sig().inputs() } -} -pub fn node_id_item_substs<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> ItemSubsts<'tcx> { - match cx.item_substs.borrow().get(&id) { - None => ItemSubsts::empty(), - Some(ts) => ts.clone(), + pub fn fn_ret(&self) -> Binder> { + self.fn_sig().output() } -} -pub fn fn_is_variadic(fty: Ty) -> bool { - match fty.sty { - TyBareFn(_, ref f) => f.sig.0.variadic, - ref s => { - panic!("fn_is_variadic() called on non-fn type: {:?}", s) + pub fn is_fn(&self) -> bool { + match self.sty { + TyBareFn(..) => true, + _ => false } } -} -pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx PolyFnSig<'tcx> { - match fty.sty { - TyBareFn(_, ref f) => &f.sig, - ref s => { - panic!("ty_fn_sig() called on non-fn type: {:?}", s) + /// See `expr_ty_adjusted` + pub fn adjust(&'tcx self, cx: &ctxt<'tcx>, + span: Span, + expr_id: ast::NodeId, + adjustment: Option<&AutoAdjustment<'tcx>>, + mut method_type: F) + -> Ty<'tcx> where + F: FnMut(MethodCall) -> Option>, + { + if let TyError = self.sty { + return self; } - } -} -/// Returns the ABI of the given function. -pub fn ty_fn_abi(fty: Ty) -> abi::Abi { - match fty.sty { - TyBareFn(_, ref f) => f.abi, - _ => panic!("ty_fn_abi() called on non-fn type"), - } -} + return match adjustment { + Some(adjustment) => { + match *adjustment { + AdjustReifyFnPointer => { + match self.sty { + ty::TyBareFn(Some(_), b) => { + cx.mk_fn(None, b) + } + _ => { + cx.sess.bug( + &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ + {:?}", self)); + } + } + } -// Type accessors for substructures of types -pub fn ty_fn_args<'tcx>(fty: Ty<'tcx>) -> ty::Binder>> { - ty_fn_sig(fty).inputs() -} + AdjustUnsafeFnPointer => { + match self.sty { + ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b), + ref b => { + cx.sess.bug( + &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ + {:?}", + b)); + } + } + } + + AdjustDerefRef(ref adj) => { + let mut adjusted_ty = self; + + if !adjusted_ty.references_error() { + for i in 0..adj.autoderefs { + let method_call = MethodCall::autoderef(expr_id, i as u32); + match method_type(method_call) { + Some(method_ty) => { + // Overloaded deref operators have all late-bound + // regions fully instantiated and coverge. + let fn_ret = + cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); + adjusted_ty = fn_ret.unwrap(); + } + None => {} + } + match adjusted_ty.builtin_deref(true) { + Some(mt) => { adjusted_ty = mt.ty; } + None => { + cx.sess.span_bug( + span, + &format!("the {}th autoderef failed: {}", + i, + adjusted_ty) + ); + } + } + } + } -pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> Binder> { - match fty.sty { - TyBareFn(_, ref f) => f.sig.output(), - ref s => { - panic!("ty_fn_ret() called on non-fn type: {:?}", s) - } + if let Some(target) = adj.unsize { + target + } else { + adjusted_ty.adjust_for_autoref(cx, adj.autoref) + } + } + } + } + None => self + }; } -} -pub fn is_fn_ty(fty: Ty) -> bool { - match fty.sty { - TyBareFn(..) => true, - _ => false + pub fn adjust_for_autoref(&'tcx self, cx: &ctxt<'tcx>, + autoref: Option>) + -> Ty<'tcx> { + match autoref { + None => self, + Some(AutoPtr(r, m)) => { + cx.mk_ref(r, mt { ty: self, mutbl: m }) + } + Some(AutoUnsafe(m)) => { + cx.mk_ptr(mt { ty: self, mutbl: m }) + } + } } -} -pub fn ty_region(tcx: &ctxt, - span: Span, - ty: Ty) -> Region { - match ty.sty { - TyRef(r, _) => *r, - ref s => { - tcx.sess.span_bug( - span, - &format!("ty_region() invoked on an inappropriate ty: {:?}", - s)); + fn sort_string(&self, cx: &ctxt) -> String { + match self.sty { + TyBool | TyChar | TyInt(_) | + TyUint(_) | TyFloat(_) | TyStr => self.to_string(), + TyTuple(ref tys) if tys.is_empty() => self.to_string(), + + TyEnum(id, _) => format!("enum `{}`", cx.item_path_str(id)), + TyBox(_) => "box".to_string(), + TyArray(_, n) => format!("array of {} elements", n), + TySlice(_) => "slice".to_string(), + TyRawPtr(_) => "*-ptr".to_string(), + TyRef(_, _) => "&-ptr".to_string(), + TyBareFn(Some(_), _) => format!("fn item"), + TyBareFn(None, _) => "fn pointer".to_string(), + TyTrait(ref inner) => { + format!("trait {}", cx.item_path_str(inner.principal_def_id())) + } + TyStruct(id, _) => { + format!("struct `{}`", cx.item_path_str(id)) + } + TyClosure(..) => "closure".to_string(), + TyTuple(_) => "tuple".to_string(), + TyInfer(TyVar(_)) => "inferred type".to_string(), + TyInfer(IntVar(_)) => "integral variable".to_string(), + TyInfer(FloatVar(_)) => "floating-point variable".to_string(), + TyInfer(FreshTy(_)) => "skolemized type".to_string(), + TyInfer(FreshIntTy(_)) => "skolemized integral type".to_string(), + TyInfer(FreshFloatTy(_)) => "skolemized floating-point type".to_string(), + TyProjection(_) => "associated type".to_string(), + TyParam(ref p) => { + if p.space == subst::SelfSpace { + "Self".to_string() + } else { + "type parameter".to_string() + } + } + TyError => "type error".to_string(), } } } - -pub fn free_region_from_def(outlives_extent: region::DestructionScopeData, - def: &RegionParameterDef) - -> ty::Region -{ - let ret = - ty::ReFree(ty::FreeRegion { scope: outlives_extent, - bound_region: ty::BrNamed(def.def_id, - def.name) }); - debug!("free_region_from_def returns {:?}", ret); - ret -} - -// Returns the type of a pattern as a monotype. Like @expr_ty, this function -// doesn't provide type parameter substitutions. -pub fn pat_ty<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Ty<'tcx> { - return node_id_to_type(cx, pat.id); -} -pub fn pat_ty_opt<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Option> { - return node_id_to_type_opt(cx, pat.id); -} - - -// Returns the type of an expression as a monotype. -// -// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in -// some cases, we insert `AutoAdjustment` annotations such as auto-deref or -// auto-ref. The type returned by this function does not consider such -// adjustments. See `expr_ty_adjusted()` instead. -// -// NB (2): This type doesn't provide type parameter substitutions; e.g. if you -// ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" -// instead of "fn(ty) -> T with T = isize". -pub fn expr_ty<'tcx>(cx: &ctxt<'tcx>, expr: &ast::Expr) -> Ty<'tcx> { - return node_id_to_type(cx, expr.id); -} - -pub fn expr_ty_opt<'tcx>(cx: &ctxt<'tcx>, expr: &ast::Expr) -> Option> { - return node_id_to_type_opt(cx, expr.id); -} - -/// Returns the type of `expr`, considering any `AutoAdjustment` -/// entry recorded for that expression. -/// -/// It would almost certainly be better to store the adjusted ty in with -/// the `AutoAdjustment`, but I opted not to do this because it would -/// require serializing and deserializing the type and, although that's not -/// hard to do, I just hate that code so much I didn't want to touch it -/// unless it was to fix it properly, which seemed a distraction from the -/// thread at hand! -nmatsakis -pub fn expr_ty_adjusted<'tcx>(cx: &ctxt<'tcx>, expr: &ast::Expr) -> Ty<'tcx> { - adjust_ty(cx, expr.span, expr.id, expr_ty(cx, expr), - cx.adjustments.borrow().get(&expr.id), - |method_call| cx.method_map.borrow().get(&method_call).map(|method| method.ty)) -} - -pub fn expr_span(cx: &ctxt, id: NodeId) -> Span { - match cx.map.find(id) { - Some(ast_map::NodeExpr(e)) => { - e.span - } - Some(f) => { - cx.sess.bug(&format!("Node id {} is not an expr: {:?}", - id, - f)); - } - None => { - cx.sess.bug(&format!("Node id {} is not present \ - in the node map", id)); - } - } -} - -pub fn local_var_name_str(cx: &ctxt, id: NodeId) -> InternedString { - match cx.map.find(id) { - Some(ast_map::NodeLocal(pat)) => { - match pat.node { - ast::PatIdent(_, ref path1, _) => { - token::get_ident(path1.node) - } - _ => { - cx.sess.bug( - &format!("Variable id {} maps to {:?}, not local", - id, - pat)); - } - } - } - r => { - cx.sess.bug(&format!("Variable id {} maps to {:?}, not local", - id, - r)); - } - } -} - -/// See `expr_ty_adjusted` -pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, - span: Span, - expr_id: ast::NodeId, - unadjusted_ty: Ty<'tcx>, - adjustment: Option<&AutoAdjustment<'tcx>>, - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(MethodCall) -> Option>, -{ - if let TyError = unadjusted_ty.sty { - return unadjusted_ty; - } - - return match adjustment { - Some(adjustment) => { - match *adjustment { - AdjustReifyFnPointer => { - match unadjusted_ty.sty { - ty::TyBareFn(Some(_), b) => { - ty::mk_bare_fn(cx, None, b) - } - _ => { - cx.sess.bug( - &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ - {:?}", unadjusted_ty)); - } - } - } - - AdjustUnsafeFnPointer => { - match unadjusted_ty.sty { - ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b), - ref b => { - cx.sess.bug( - &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ - {:?}", - b)); - } - } - } - - AdjustDerefRef(ref adj) => { - let mut adjusted_ty = unadjusted_ty; - - if !ty::type_is_error(adjusted_ty) { - for i in 0..adj.autoderefs { - let method_call = MethodCall::autoderef(expr_id, i as u32); - match method_type(method_call) { - Some(method_ty) => { - // Overloaded deref operators have all late-bound - // regions fully instantiated and coverge. - let fn_ret = - ty::no_late_bound_regions(cx, - &ty_fn_ret(method_ty)).unwrap(); - adjusted_ty = fn_ret.unwrap(); - } - None => {} - } - match deref(adjusted_ty, true) { - Some(mt) => { adjusted_ty = mt.ty; } - None => { - cx.sess.span_bug( - span, - &format!("the {}th autoderef failed: {}", - i, - adjusted_ty) - ); - } - } - } - } - - if let Some(target) = adj.unsize { - target - } else { - adjust_ty_for_autoref(cx, adjusted_ty, adj.autoref) - } - } - } - } - None => unadjusted_ty - }; -} - -pub fn adjust_ty_for_autoref<'tcx>(cx: &ctxt<'tcx>, - ty: Ty<'tcx>, - autoref: Option>) - -> Ty<'tcx> { - match autoref { - None => ty, - Some(AutoPtr(r, m)) => { - mk_rptr(cx, r, mt { ty: ty, mutbl: m }) - } - Some(AutoUnsafe(m)) => { - mk_ptr(cx, mt { ty: ty, mutbl: m }) - } - } -} - -pub fn resolve_expr(tcx: &ctxt, expr: &ast::Expr) -> def::Def { - match tcx.def_map.borrow().get(&expr.id) { - Some(def) => def.full_def(), - None => { - tcx.sess.span_bug(expr.span, &format!( - "no def-map entry for expr {}", expr.id)); - } - } -} - -pub fn expr_is_lval(tcx: &ctxt, expr: &ast::Expr) -> bool { - match expr.node { - ast::ExprPath(..) => { - // We can't use resolve_expr here, as this needs to run on broken - // programs. We don't need to through - associated items are all - // rvalues. - match tcx.def_map.borrow().get(&expr.id) { - Some(&def::PathResolution { - base_def: def::DefStatic(..), .. - }) | Some(&def::PathResolution { - base_def: def::DefUpvar(..), .. - }) | Some(&def::PathResolution { - base_def: def::DefLocal(..), .. - }) => { - true - } - - Some(..) => false, - - None => tcx.sess.span_bug(expr.span, &format!( - "no def for path {}", expr.id)) - } - } - - ast::ExprUnary(ast::UnDeref, _) | - ast::ExprField(..) | - ast::ExprTupField(..) | - ast::ExprIndex(..) => { - true - } - - ast::ExprCall(..) | - ast::ExprMethodCall(..) | - ast::ExprStruct(..) | - ast::ExprRange(..) | - ast::ExprTup(..) | - ast::ExprIf(..) | - ast::ExprMatch(..) | - ast::ExprClosure(..) | - ast::ExprBlock(..) | - ast::ExprRepeat(..) | - ast::ExprVec(..) | - ast::ExprBreak(..) | - ast::ExprAgain(..) | - ast::ExprRet(..) | - ast::ExprWhile(..) | - ast::ExprLoop(..) | - ast::ExprAssign(..) | - ast::ExprInlineAsm(..) | - ast::ExprAssignOp(..) | - ast::ExprLit(_) | - ast::ExprUnary(..) | - ast::ExprBox(..) | - ast::ExprAddrOf(..) | - ast::ExprBinary(..) | - ast::ExprCast(..) => { - false - } - - ast::ExprParen(ref e) => expr_is_lval(tcx, e), - - ast::ExprIfLet(..) | - ast::ExprWhileLet(..) | - ast::ExprForLoop(..) | - ast::ExprMac(..) => { - tcx.sess.span_bug( - expr.span, - "macro expression remains after expansion"); - } - } -} - -pub fn stmt_node_id(s: &ast::Stmt) -> ast::NodeId { - match s.node { - ast::StmtDecl(_, id) | StmtExpr(_, id) | StmtSemi(_, id) => { - return id; - } - ast::StmtMac(..) => panic!("unexpanded macro in trans") - } -} - -pub fn field_idx_strict(tcx: &ctxt, name: ast::Name, fields: &[field]) - -> usize { - let mut i = 0; - for f in fields { if f.name == name { return i; } i += 1; } - tcx.sess.bug(&format!( - "no field named `{}` found in the list of fields `{:?}`", - token::get_name(name), - fields.iter() - .map(|f| token::get_name(f.name).to_string()) - .collect::>())); -} - -pub fn impl_or_trait_item_idx(id: ast::Name, trait_items: &[ImplOrTraitItem]) - -> Option { - trait_items.iter().position(|m| m.name() == id) -} - -pub fn ty_sort_string(cx: &ctxt, ty: Ty) -> String { - match ty.sty { - TyBool | TyChar | TyInt(_) | - TyUint(_) | TyFloat(_) | TyStr => ty.to_string(), - TyTuple(ref tys) if tys.is_empty() => ty.to_string(), - - TyEnum(id, _) => format!("enum `{}`", item_path_str(cx, id)), - TyBox(_) => "box".to_string(), - TyArray(_, n) => format!("array of {} elements", n), - TySlice(_) => "slice".to_string(), - TyRawPtr(_) => "*-ptr".to_string(), - TyRef(_, _) => "&-ptr".to_string(), - TyBareFn(Some(_), _) => format!("fn item"), - TyBareFn(None, _) => "fn pointer".to_string(), - TyTrait(ref inner) => { - format!("trait {}", item_path_str(cx, inner.principal_def_id())) - } - TyStruct(id, _) => { - format!("struct `{}`", item_path_str(cx, id)) - } - TyClosure(..) => "closure".to_string(), - TyTuple(_) => "tuple".to_string(), - TyInfer(TyVar(_)) => "inferred type".to_string(), - TyInfer(IntVar(_)) => "integral variable".to_string(), - TyInfer(FloatVar(_)) => "floating-point variable".to_string(), - TyInfer(FreshTy(_)) => "skolemized type".to_string(), - TyInfer(FreshIntTy(_)) => "skolemized integral type".to_string(), - TyInfer(FreshFloatTy(_)) => "skolemized floating-point type".to_string(), - TyProjection(_) => "associated type".to_string(), - TyParam(ref p) => { - if p.space == subst::SelfSpace { - "Self".to_string() - } else { - "type parameter".to_string() - } - } - TyError => "type error".to_string(), - } -} - /// Explains the source of a type err in a short, human readable way. This is meant to be placed /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` /// afterwards to present additional details, particularly when it comes to lifetime-related @@ -5298,8 +5046,8 @@ impl<'tcx> fmt::Display for type_err<'tcx> { terr_sorts(values) => tls::with(|tcx| { // A naive approach to making sure that we're not reporting silly errors such as: // (expected closure, found closure). - let expected_str = ty_sort_string(tcx, values.expected); - let found_str = ty_sort_string(tcx, values.found); + let expected_str = values.expected.sort_string(tcx); + let found_str = values.found.sort_string(tcx); if expected_str == found_str { write!(f, "expected {}, found a different {}", expected_str, found_str) } else { @@ -5308,8 +5056,8 @@ impl<'tcx> fmt::Display for type_err<'tcx> { }), terr_traits(values) => tls::with(|tcx| { write!(f, "expected trait `{}`, found trait `{}`", - item_path_str(tcx, values.expected), - item_path_str(tcx, values.found)) + tcx.item_path_str(values.expected), + tcx.item_path_str(values.found)) }), terr_builtin_bounds(values) => { if values.expected.is_empty() { @@ -5361,127 +5109,6 @@ impl<'tcx> fmt::Display for type_err<'tcx> { } } -pub fn note_and_explain_type_err<'tcx>(cx: &ctxt<'tcx>, err: &type_err<'tcx>, sp: Span) { - match *err { - terr_regions_does_not_outlive(subregion, superregion) => { - note_and_explain_region(cx, "", subregion, "..."); - note_and_explain_region(cx, "...does not necessarily outlive ", - superregion, ""); - } - terr_regions_not_same(region1, region2) => { - note_and_explain_region(cx, "", region1, "..."); - note_and_explain_region(cx, "...is not the same lifetime as ", - region2, ""); - } - terr_regions_no_overlap(region1, region2) => { - note_and_explain_region(cx, "", region1, "..."); - note_and_explain_region(cx, "...does not overlap ", - region2, ""); - } - terr_regions_insufficiently_polymorphic(_, conc_region) => { - note_and_explain_region(cx, - "concrete lifetime that was found is ", - conc_region, ""); - } - terr_regions_overly_polymorphic(_, ty::ReInfer(ty::ReVar(_))) => { - // don't bother to print out the message below for - // inference variables, it's not very illuminating. - } - terr_regions_overly_polymorphic(_, conc_region) => { - note_and_explain_region(cx, - "expected concrete lifetime is ", - conc_region, ""); - } - terr_sorts(values) => { - let expected_str = ty_sort_string(cx, values.expected); - let found_str = ty_sort_string(cx, values.found); - if expected_str == found_str && expected_str == "closure" { - cx.sess.span_note(sp, &format!("no two closures, even if identical, have the same \ - type")); - cx.sess.span_help(sp, &format!("consider boxing your closure and/or \ - using it as a trait object")); - } - } - _ => {} - } -} - -pub fn provided_source(cx: &ctxt, id: ast::DefId) -> Option { - cx.provided_method_sources.borrow().get(&id).cloned() -} - -pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) - -> Vec>> { - if is_local(id) { - if let ItemTrait(_, _, _, ref ms) = cx.map.expect_item(id.node).node { - ms.iter().filter_map(|ti| { - if let ast::MethodTraitItem(_, Some(_)) = ti.node { - match impl_or_trait_item(cx, ast_util::local_def(ti.id)) { - MethodTraitItem(m) => Some(m), - _ => { - cx.sess.bug("provided_trait_methods(): \ - non-method item found from \ - looking up provided method?!") - } - } - } else { - None - } - }).collect() - } else { - cx.sess.bug(&format!("provided_trait_methods: `{:?}` is not a trait", id)) - } - } else { - csearch::get_provided_trait_methods(cx, id) - } -} - -pub fn associated_consts<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) - -> Vec>> { - if is_local(id) { - match cx.map.expect_item(id.node).node { - ItemTrait(_, _, _, ref tis) => { - tis.iter().filter_map(|ti| { - if let ast::ConstTraitItem(_, _) = ti.node { - match impl_or_trait_item(cx, ast_util::local_def(ti.id)) { - ConstTraitItem(ac) => Some(ac), - _ => { - cx.sess.bug("associated_consts(): \ - non-const item found from \ - looking up a constant?!") - } - } - } else { - None - } - }).collect() - } - ItemImpl(_, _, _, _, _, ref iis) => { - iis.iter().filter_map(|ii| { - if let ast::ConstImplItem(_, _) = ii.node { - match impl_or_trait_item(cx, ast_util::local_def(ii.id)) { - ConstTraitItem(ac) => Some(ac), - _ => { - cx.sess.bug("associated_consts(): \ - non-const item found from \ - looking up a constant?!") - } - } - } else { - None - } - }).collect() - } - _ => { - cx.sess.bug(&format!("associated_consts: `{:?}` is not a trait \ - or impl", id)) - } - } - } else { - csearch::get_associated_consts(cx, id) - } -} - /// Helper for looking things up in the various maps that are populated during /// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc). All of /// these share the pattern that if the id is local, it should have been loaded @@ -5508,1524 +5135,1507 @@ fn lookup_locally_or_in_crate_store(descr: &str, v } -pub fn trait_item<'tcx>(cx: &ctxt<'tcx>, trait_did: ast::DefId, idx: usize) - -> ImplOrTraitItem<'tcx> { - let method_def_id = (*ty::trait_item_def_ids(cx, trait_did))[idx].def_id(); - impl_or_trait_item(cx, method_def_id) -} - -pub fn trait_items<'tcx>(cx: &ctxt<'tcx>, trait_did: ast::DefId) - -> Rc>> { - let mut trait_items = cx.trait_items_cache.borrow_mut(); - match trait_items.get(&trait_did).cloned() { - Some(trait_items) => trait_items, - None => { - let def_ids = ty::trait_item_def_ids(cx, trait_did); - let items: Rc> = - Rc::new(def_ids.iter() - .map(|d| impl_or_trait_item(cx, d.def_id())) - .collect()); - trait_items.insert(trait_did, items.clone()); - items - } - } -} - -pub fn trait_impl_polarity<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) - -> Option { - if id.krate == ast::LOCAL_CRATE { - match cx.map.find(id.node) { - Some(ast_map::NodeItem(item)) => { - match item.node { - ast::ItemImpl(_, polarity, _, _, _, _) => Some(polarity), - _ => None - } - } - _ => None - } - } else { - csearch::get_impl_polarity(cx, id) - } -} - -pub fn custom_coerce_unsized_kind<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) - -> CustomCoerceUnsized { - memoized(&cx.custom_coerce_unsized_kinds, did, |did: DefId| { - let (kind, src) = if did.krate != ast::LOCAL_CRATE { - (csearch::get_custom_coerce_unsized_kind(cx, did), "external") - } else { - (None, "local") - }; - - match kind { - Some(kind) => kind, - None => { - cx.sess.bug(&format!("custom_coerce_unsized_kind: \ - {} impl `{}` is missing its kind", - src, item_path_str(cx, did))); - } - } - }) -} - -pub fn impl_or_trait_item<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) - -> ImplOrTraitItem<'tcx> { - lookup_locally_or_in_crate_store( - "impl_or_trait_items", id, &cx.impl_or_trait_items, - || csearch::get_impl_or_trait_item(cx, id)) -} - -/// Returns the parameter index that the given associated type corresponds to. -pub fn associated_type_parameter_index(cx: &ctxt, - trait_def: &TraitDef, - associated_type_id: ast::DefId) - -> usize { - for type_parameter_def in &trait_def.generics.types { - if type_parameter_def.def_id == associated_type_id { - return type_parameter_def.index as usize +impl BorrowKind { + pub fn from_mutbl(m: ast::Mutability) -> BorrowKind { + match m { + ast::MutMutable => MutBorrow, + ast::MutImmutable => ImmBorrow, } } - cx.sess.bug("couldn't find associated type parameter index") -} - -pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId) - -> Rc> { - lookup_locally_or_in_crate_store( - "trait_item_def_ids", id, &cx.trait_item_def_ids, - || Rc::new(csearch::get_trait_item_def_ids(&cx.sess.cstore, id))) -} -/// Returns the trait-ref corresponding to a given impl, or None if it is -/// an inherent impl. -pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) - -> Option> -{ - lookup_locally_or_in_crate_store( - "impl_trait_refs", id, &cx.impl_trait_refs, - || csearch::get_impl_trait(cx, id)) -} + /// Returns a mutability `m` such that an `&m T` pointer could be used to obtain this borrow + /// kind. Because borrow kinds are richer than mutabilities, we sometimes have to pick a + /// mutability that is stronger than necessary so that it at least *would permit* the borrow in + /// question. + pub fn to_mutbl_lossy(self) -> ast::Mutability { + match self { + MutBorrow => ast::MutMutable, + ImmBorrow => ast::MutImmutable, -/// Returns whether this DefId refers to an impl -pub fn is_impl<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) -> bool { - if id.krate == ast::LOCAL_CRATE { - if let Some(ast_map::NodeItem( - &ast::Item { node: ast::ItemImpl(..), .. })) = cx.map.find(id.node) { - true - } else { - false + // We have no type corresponding to a unique imm borrow, so + // use `&mut`. It gives all the capabilities of an `&uniq` + // and hence is a safe "over approximation". + UniqueImmBorrow => ast::MutMutable, } - } else { - csearch::is_impl(&cx.sess.cstore, id) } -} -pub fn trait_ref_to_def_id(tcx: &ctxt, tr: &ast::TraitRef) -> ast::DefId { - tcx.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id() -} - -pub fn try_add_builtin_trait( - tcx: &ctxt, - trait_def_id: ast::DefId, - builtin_bounds: &mut EnumSet) - -> bool -{ - //! Checks whether `trait_ref` refers to one of the builtin - //! traits, like `Send`, and adds the corresponding - //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref` - //! is a builtin trait. - - match tcx.lang_items.to_builtin_kind(trait_def_id) { - Some(bound) => { builtin_bounds.insert(bound); true } - None => false - } -} - -pub fn ty_to_def_id(ty: Ty) -> Option { - match ty.sty { - TyTrait(ref tt) => - Some(tt.principal_def_id()), - TyStruct(id, _) | - TyEnum(id, _) | - TyClosure(id, _) => - Some(id), - _ => - None + pub fn to_user_str(&self) -> &'static str { + match *self { + MutBorrow => "mutable", + ImmBorrow => "immutable", + UniqueImmBorrow => "uniquely immutable", + } } } -// Enum information -#[derive(Clone)] -pub struct VariantInfo<'tcx> { - pub args: Vec>, - pub arg_names: Option>, - pub ctor_ty: Option>, - pub name: ast::Name, - pub id: ast::DefId, - pub disr_val: Disr, - pub vis: Visibility -} - -impl<'tcx> VariantInfo<'tcx> { - - /// Creates a new VariantInfo from the corresponding ast representation. - /// - /// Does not do any caching of the value in the type context. - pub fn from_ast_variant(cx: &ctxt<'tcx>, - ast_variant: &ast::Variant, - discriminant: Disr) -> VariantInfo<'tcx> { - let ctor_ty = node_id_to_type(cx, ast_variant.node.id); +impl<'tcx> ctxt<'tcx> { + /// Returns the type of element at index `i` in tuple or tuple-like type `t`. + /// For an enum `t`, `variant` is None only if `t` is a univariant enum. + pub fn positional_element_ty(&self, + ty: Ty<'tcx>, + i: usize, + variant: Option) -> Option> { - match ast_variant.node.kind { - ast::TupleVariantKind(ref args) => { - let arg_tys = if !args.is_empty() { - // the regions in the argument types come from the - // enum def'n, and hence will all be early bound - ty::no_late_bound_regions(cx, &ty_fn_args(ctor_ty)).unwrap() - } else { - Vec::new() - }; + match (&ty.sty, variant) { + (&TyTuple(ref v), None) => v.get(i).cloned(), - return VariantInfo { - args: arg_tys, - arg_names: None, - ctor_ty: Some(ctor_ty), - name: ast_variant.node.name.name, - id: ast_util::local_def(ast_variant.node.id), - disr_val: discriminant, - vis: ast_variant.node.vis - }; - }, - ast::StructVariantKind(ref struct_def) => { - let fields: &[StructField] = &struct_def.fields; - assert!(!fields.is_empty()); + (&TyStruct(def_id, substs), None) => self.lookup_struct_fields(def_id) + .get(i) + .map(|&t| self.lookup_item_type(t.id).ty.subst(self, substs)), - let arg_tys = struct_def.fields.iter() - .map(|field| node_id_to_type(cx, field.node.id)).collect(); - let arg_names = fields.iter().map(|field| { - match field.node.kind { - NamedField(ident, _) => ident.name, - UnnamedField(..) => cx.sess.bug( - "enum_variants: all fields in struct must have a name") - } - }).collect(); + (&TyEnum(def_id, substs), Some(variant_def_id)) => { + let variant_info = self.enum_variant_with_id(def_id, variant_def_id); + variant_info.args.get(i).map(|t|t.subst(self, substs)) + } - return VariantInfo { - args: arg_tys, - arg_names: Some(arg_names), - ctor_ty: None, - name: ast_variant.node.name.name, - id: ast_util::local_def(ast_variant.node.id), - disr_val: discriminant, - vis: ast_variant.node.vis - }; + (&TyEnum(def_id, substs), None) => { + assert!(self.enum_is_univariant(def_id)); + let enum_variants = self.enum_variants(def_id); + let variant_info = &enum_variants[0]; + variant_info.args.get(i).map(|t|t.subst(self, substs)) } + + _ => None } } -} - -pub fn substd_enum_variants<'tcx>(cx: &ctxt<'tcx>, - id: ast::DefId, - substs: &Substs<'tcx>) - -> Vec>> { - enum_variants(cx, id).iter().map(|variant_info| { - let substd_args = variant_info.args.iter() - .map(|aty| aty.subst(cx, substs)).collect::>(); - - let substd_ctor_ty = variant_info.ctor_ty.subst(cx, substs); - - Rc::new(VariantInfo { - args: substd_args, - ctor_ty: substd_ctor_ty, - ..(**variant_info).clone() - }) - }).collect() -} - -pub fn item_path_str(cx: &ctxt, id: ast::DefId) -> String { - with_path(cx, id, |path| ast_map::path_to_string(path)).to_string() -} -#[derive(Copy, Clone)] -pub enum DtorKind { - NoDtor, - TraitDtor(DefId, bool) -} + /// Returns the type of element at field `n` in struct or struct-like type `t`. + /// For an enum `t`, `variant` must be some def id. + pub fn named_element_ty(&self, + ty: Ty<'tcx>, + n: ast::Name, + variant: Option) -> Option> { -impl DtorKind { - pub fn is_present(&self) -> bool { - match *self { - TraitDtor(..) => true, - _ => false + match (&ty.sty, variant) { + (&TyStruct(def_id, substs), None) => { + let r = self.lookup_struct_fields(def_id); + r.iter().find(|f| f.name == n) + .map(|&f| self.lookup_field_type(def_id, f.id, substs)) + } + (&TyEnum(def_id, substs), Some(variant_def_id)) => { + let variant_info = self.enum_variant_with_id(def_id, variant_def_id); + variant_info.arg_names.as_ref() + .expect("must have struct enum variant if accessing a named fields") + .iter().zip(&variant_info.args) + .find(|&(&name, _)| name == n) + .map(|(_name, arg_t)| arg_t.subst(self, substs)) + } + _ => None } } - pub fn has_drop_flag(&self) -> bool { - match self { - &NoDtor => false, - &TraitDtor(_, flag) => flag + pub fn node_id_to_type(&self, id: ast::NodeId) -> Ty<'tcx> { + match self.node_id_to_type_opt(id) { + Some(ty) => ty, + None => self.sess.bug( + &format!("node_id_to_type: no type for node `{}`", + self.map.node_to_string(id))) } } -} -/* If struct_id names a struct with a dtor. */ -pub fn ty_dtor(cx: &ctxt, struct_id: DefId) -> DtorKind { - match cx.destructor_for_type.borrow().get(&struct_id) { - Some(&method_def_id) => { - let flag = !has_attr(cx, struct_id, "unsafe_no_drop_flag"); + pub fn node_id_to_type_opt(&self, id: ast::NodeId) -> Option> { + self.tables.borrow().node_types.get(&id).cloned() + } - TraitDtor(method_def_id, flag) + pub fn node_id_item_substs(&self, id: ast::NodeId) -> ItemSubsts<'tcx> { + match self.tables.borrow().item_substs.get(&id) { + None => ItemSubsts::empty(), + Some(ts) => ts.clone(), } - None => NoDtor, } -} -pub fn has_dtor(cx: &ctxt, struct_id: DefId) -> bool { - cx.destructor_for_type.borrow().contains_key(&struct_id) -} + // Returns the type of a pattern as a monotype. Like @expr_ty, this function + // doesn't provide type parameter substitutions. + pub fn pat_ty(&self, pat: &ast::Pat) -> Ty<'tcx> { + self.node_id_to_type(pat.id) + } + pub fn pat_ty_opt(&self, pat: &ast::Pat) -> Option> { + self.node_id_to_type_opt(pat.id) + } -pub fn with_path(cx: &ctxt, id: ast::DefId, f: F) -> T where - F: FnOnce(ast_map::PathElems) -> T, -{ - if id.krate == ast::LOCAL_CRATE { - cx.map.with_path(id.node, f) - } else { - f(csearch::get_item_path(cx, id).iter().cloned().chain(LinkedPath::empty())) + // Returns the type of an expression as a monotype. + // + // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in + // some cases, we insert `AutoAdjustment` annotations such as auto-deref or + // auto-ref. The type returned by this function does not consider such + // adjustments. See `expr_ty_adjusted()` instead. + // + // NB (2): This type doesn't provide type parameter substitutions; e.g. if you + // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" + // instead of "fn(ty) -> T with T = isize". + pub fn expr_ty(&self, expr: &ast::Expr) -> Ty<'tcx> { + self.node_id_to_type(expr.id) } -} -pub fn enum_is_univariant(cx: &ctxt, id: ast::DefId) -> bool { - enum_variants(cx, id).len() == 1 -} + pub fn expr_ty_opt(&self, expr: &ast::Expr) -> Option> { + self.node_id_to_type_opt(expr.id) + } -pub fn type_is_empty(cx: &ctxt, ty: Ty) -> bool { - match ty.sty { - TyEnum(did, _) => (*enum_variants(cx, did)).is_empty(), - _ => false - } -} + /// Returns the type of `expr`, considering any `AutoAdjustment` + /// entry recorded for that expression. + /// + /// It would almost certainly be better to store the adjusted ty in with + /// the `AutoAdjustment`, but I opted not to do this because it would + /// require serializing and deserializing the type and, although that's not + /// hard to do, I just hate that code so much I didn't want to touch it + /// unless it was to fix it properly, which seemed a distraction from the + /// thread at hand! -nmatsakis + pub fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> { + self.expr_ty(expr) + .adjust(self, expr.span, expr.id, + self.tables.borrow().adjustments.get(&expr.id), + |method_call| { + self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) + }) + } -trait IntTypeExt { - fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx>; - fn i64_to_disr(&self, val: i64) -> Option; - fn u64_to_disr(&self, val: u64) -> Option; - fn disr_incr(&self, val: Disr) -> Option; - fn disr_string(&self, val: Disr) -> String; - fn disr_wrap_incr(&self, val: Option) -> Disr; -} + pub fn expr_span(&self, id: NodeId) -> Span { + match self.map.find(id) { + Some(ast_map::NodeExpr(e)) => { + e.span + } + Some(f) => { + self.sess.bug(&format!("Node id {} is not an expr: {:?}", + id, f)); + } + None => { + self.sess.bug(&format!("Node id {} is not present \ + in the node map", id)); + } + } + } -impl IntTypeExt for attr::IntType { - fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> { - match *self { - SignedInt(ast::TyI8) => cx.types.i8, - SignedInt(ast::TyI16) => cx.types.i16, - SignedInt(ast::TyI32) => cx.types.i32, - SignedInt(ast::TyI64) => cx.types.i64, - SignedInt(ast::TyIs) => cx.types.isize, - UnsignedInt(ast::TyU8) => cx.types.u8, - UnsignedInt(ast::TyU16) => cx.types.u16, - UnsignedInt(ast::TyU32) => cx.types.u32, - UnsignedInt(ast::TyU64) => cx.types.u64, - UnsignedInt(ast::TyUs) => cx.types.usize, + pub fn local_var_name_str(&self, id: NodeId) -> InternedString { + match self.map.find(id) { + Some(ast_map::NodeLocal(pat)) => { + match pat.node { + ast::PatIdent(_, ref path1, _) => { + token::get_ident(path1.node) + } + _ => { + self.sess.bug(&format!("Variable id {} maps to {:?}, not local", + id, pat)); + } + } + } + r => { + self.sess.bug(&format!("Variable id {} maps to {:?}, not local", + id, r)); + } } } - fn i64_to_disr(&self, val: i64) -> Option { - match *self { - SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr), - SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr), - SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr), - SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr), - UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr), - UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr), - UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr), - UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr), + pub fn resolve_expr(&self, expr: &ast::Expr) -> def::Def { + match self.def_map.borrow().get(&expr.id) { + Some(def) => def.full_def(), + None => { + self.sess.span_bug(expr.span, &format!( + "no def-map entry for expr {}", expr.id)); + } + } + } + + pub fn expr_is_lval(&self, expr: &ast::Expr) -> bool { + match expr.node { + ast::ExprPath(..) => { + // We can't use resolve_expr here, as this needs to run on broken + // programs. We don't need to through - associated items are all + // rvalues. + match self.def_map.borrow().get(&expr.id) { + Some(&def::PathResolution { + base_def: def::DefStatic(..), .. + }) | Some(&def::PathResolution { + base_def: def::DefUpvar(..), .. + }) | Some(&def::PathResolution { + base_def: def::DefLocal(..), .. + }) => { + true + } - UnsignedInt(ast::TyUs) | - SignedInt(ast::TyIs) => unreachable!(), + Some(..) => false, + + None => self.sess.span_bug(expr.span, &format!( + "no def for path {}", expr.id)) + } + } + + ast::ExprUnary(ast::UnDeref, _) | + ast::ExprField(..) | + ast::ExprTupField(..) | + ast::ExprIndex(..) => { + true + } + + ast::ExprCall(..) | + ast::ExprMethodCall(..) | + ast::ExprStruct(..) | + ast::ExprRange(..) | + ast::ExprTup(..) | + ast::ExprIf(..) | + ast::ExprMatch(..) | + ast::ExprClosure(..) | + ast::ExprBlock(..) | + ast::ExprRepeat(..) | + ast::ExprVec(..) | + ast::ExprBreak(..) | + ast::ExprAgain(..) | + ast::ExprRet(..) | + ast::ExprWhile(..) | + ast::ExprLoop(..) | + ast::ExprAssign(..) | + ast::ExprInlineAsm(..) | + ast::ExprAssignOp(..) | + ast::ExprLit(_) | + ast::ExprUnary(..) | + ast::ExprBox(..) | + ast::ExprAddrOf(..) | + ast::ExprBinary(..) | + ast::ExprCast(..) => { + false + } + + ast::ExprParen(ref e) => self.expr_is_lval(e), + + ast::ExprIfLet(..) | + ast::ExprWhileLet(..) | + ast::ExprForLoop(..) | + ast::ExprMac(..) => { + self.sess.span_bug( + expr.span, + "macro expression remains after expansion"); + } + } + } + + pub fn field_idx_strict(&self, name: ast::Name, fields: &[field]) + -> usize { + let mut i = 0; + for f in fields { if f.name == name { return i; } i += 1; } + self.sess.bug(&format!( + "no field named `{}` found in the list of fields `{:?}`", + token::get_name(name), + fields.iter() + .map(|f| token::get_name(f.name).to_string()) + .collect::>())); + } + + pub fn note_and_explain_type_err(&self, err: &type_err<'tcx>, sp: Span) { + match *err { + terr_regions_does_not_outlive(subregion, superregion) => { + self.note_and_explain_region("", subregion, "..."); + self.note_and_explain_region("...does not necessarily outlive ", + superregion, ""); + } + terr_regions_not_same(region1, region2) => { + self.note_and_explain_region("", region1, "..."); + self.note_and_explain_region("...is not the same lifetime as ", + region2, ""); + } + terr_regions_no_overlap(region1, region2) => { + self.note_and_explain_region("", region1, "..."); + self.note_and_explain_region("...does not overlap ", + region2, ""); + } + terr_regions_insufficiently_polymorphic(_, conc_region) => { + self.note_and_explain_region("concrete lifetime that was found is ", + conc_region, ""); + } + terr_regions_overly_polymorphic(_, ty::ReInfer(ty::ReVar(_))) => { + // don't bother to print out the message below for + // inference variables, it's not very illuminating. + } + terr_regions_overly_polymorphic(_, conc_region) => { + self.note_and_explain_region("expected concrete lifetime is ", + conc_region, ""); + } + terr_sorts(values) => { + let expected_str = values.expected.sort_string(self); + let found_str = values.found.sort_string(self); + if expected_str == found_str && expected_str == "closure" { + self.sess.span_note(sp, + &format!("no two closures, even if identical, have the same type")); + self.sess.span_help(sp, + &format!("consider boxing your closure and/or \ + using it as a trait object")); + } + } + _ => {} } } - fn u64_to_disr(&self, val: u64) -> Option { - match *self { - SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr), - SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr), - SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr), - SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr), - UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr), - UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr), - UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr), - UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr), + pub fn provided_source(&self, id: ast::DefId) -> Option { + self.provided_method_sources.borrow().get(&id).cloned() + } - UnsignedInt(ast::TyUs) | - SignedInt(ast::TyIs) => unreachable!(), + pub fn provided_trait_methods(&self, id: ast::DefId) -> Vec>> { + if is_local(id) { + if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id.node).node { + ms.iter().filter_map(|ti| { + if let ast::MethodTraitItem(_, Some(_)) = ti.node { + match self.impl_or_trait_item(ast_util::local_def(ti.id)) { + MethodTraitItem(m) => Some(m), + _ => { + self.sess.bug("provided_trait_methods(): \ + non-method item found from \ + looking up provided method?!") + } + } + } else { + None + } + }).collect() + } else { + self.sess.bug(&format!("provided_trait_methods: `{:?}` is not a trait", id)) + } + } else { + csearch::get_provided_trait_methods(self, id) + } + } + + pub fn associated_consts(&self, id: ast::DefId) -> Vec>> { + if is_local(id) { + match self.map.expect_item(id.node).node { + ItemTrait(_, _, _, ref tis) => { + tis.iter().filter_map(|ti| { + if let ast::ConstTraitItem(_, _) = ti.node { + match self.impl_or_trait_item(ast_util::local_def(ti.id)) { + ConstTraitItem(ac) => Some(ac), + _ => { + self.sess.bug("associated_consts(): \ + non-const item found from \ + looking up a constant?!") + } + } + } else { + None + } + }).collect() + } + ItemImpl(_, _, _, _, _, ref iis) => { + iis.iter().filter_map(|ii| { + if let ast::ConstImplItem(_, _) = ii.node { + match self.impl_or_trait_item(ast_util::local_def(ii.id)) { + ConstTraitItem(ac) => Some(ac), + _ => { + self.sess.bug("associated_consts(): \ + non-const item found from \ + looking up a constant?!") + } + } + } else { + None + } + }).collect() + } + _ => { + self.sess.bug(&format!("associated_consts: `{:?}` is not a trait \ + or impl", id)) + } + } + } else { + csearch::get_associated_consts(self, id) } } - fn disr_incr(&self, val: Disr) -> Option { - macro_rules! add1 { - ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) } + pub fn trait_items(&self, trait_did: ast::DefId) -> Rc>> { + let mut trait_items = self.trait_items_cache.borrow_mut(); + match trait_items.get(&trait_did).cloned() { + Some(trait_items) => trait_items, + None => { + let def_ids = self.trait_item_def_ids(trait_did); + let items: Rc> = + Rc::new(def_ids.iter() + .map(|d| self.impl_or_trait_item(d.def_id())) + .collect()); + trait_items.insert(trait_did, items.clone()); + items + } } - 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::TyI8) => add1!((val as i64).to_i8()), - SignedInt(ast::TyI16) => add1!((val as i64).to_i16()), - SignedInt(ast::TyI32) => add1!((val as i64).to_i32()), - SignedInt(ast::TyI64) => add1!(Some(val as i64)), + } - UnsignedInt(ast::TyU8) => add1!(val.to_u8()), - UnsignedInt(ast::TyU16) => add1!(val.to_u16()), - UnsignedInt(ast::TyU32) => add1!(val.to_u32()), - UnsignedInt(ast::TyU64) => add1!(Some(val)), + pub fn trait_impl_polarity(&self, id: ast::DefId) -> Option { + if id.krate == ast::LOCAL_CRATE { + match self.map.find(id.node) { + Some(ast_map::NodeItem(item)) => { + match item.node { + ast::ItemImpl(_, polarity, _, _, _, _) => Some(polarity), + _ => None + } + } + _ => None + } + } else { + csearch::get_impl_polarity(self, id) + } + } - UnsignedInt(ast::TyUs) | - SignedInt(ast::TyIs) => unreachable!(), + pub fn custom_coerce_unsized_kind(&self, did: ast::DefId) -> CustomCoerceUnsized { + memoized(&self.custom_coerce_unsized_kinds, did, |did: DefId| { + let (kind, src) = if did.krate != ast::LOCAL_CRATE { + (csearch::get_custom_coerce_unsized_kind(self, did), "external") + } else { + (None, "local") + }; + + match kind { + Some(kind) => kind, + None => { + self.sess.bug(&format!("custom_coerce_unsized_kind: \ + {} impl `{}` is missing its kind", + src, self.item_path_str(did))); + } + } + }) + } + + pub fn impl_or_trait_item(&self, id: ast::DefId) -> ImplOrTraitItem<'tcx> { + lookup_locally_or_in_crate_store( + "impl_or_trait_items", id, &self.impl_or_trait_items, + || csearch::get_impl_or_trait_item(self, id)) + } + + pub fn trait_item_def_ids(&self, id: ast::DefId) -> Rc> { + lookup_locally_or_in_crate_store( + "trait_item_def_ids", id, &self.trait_item_def_ids, + || Rc::new(csearch::get_trait_item_def_ids(&self.sess.cstore, id))) + } + + /// Returns the trait-ref corresponding to a given impl, or None if it is + /// an inherent impl. + pub fn impl_trait_ref(&self, id: ast::DefId) -> Option> { + lookup_locally_or_in_crate_store( + "impl_trait_refs", id, &self.impl_trait_refs, + || csearch::get_impl_trait(self, id)) + } + + /// Returns whether this DefId refers to an impl + pub fn is_impl(&self, id: ast::DefId) -> bool { + if id.krate == ast::LOCAL_CRATE { + if let Some(ast_map::NodeItem( + &ast::Item { node: ast::ItemImpl(..), .. })) = self.map.find(id.node) { + true + } else { + false + } + } else { + csearch::is_impl(&self.sess.cstore, id) } } - // 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::TyI8) => format!("{}", val as i8 ), - SignedInt(ast::TyI16) => format!("{}", val as i16), - SignedInt(ast::TyI32) => format!("{}", val as i32), - SignedInt(ast::TyI64) => format!("{}", val as i64), - UnsignedInt(ast::TyU8) => format!("{}", val as u8 ), - UnsignedInt(ast::TyU16) => format!("{}", val as u16), - UnsignedInt(ast::TyU32) => format!("{}", val as u32), - UnsignedInt(ast::TyU64) => format!("{}", val as u64), + pub fn trait_ref_to_def_id(&self, tr: &ast::TraitRef) -> ast::DefId { + self.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id() + } - UnsignedInt(ast::TyUs) | - SignedInt(ast::TyIs) => unreachable!(), + pub fn try_add_builtin_trait(&self, + trait_def_id: ast::DefId, + builtin_bounds: &mut EnumSet) + -> bool + { + //! Checks whether `trait_ref` refers to one of the builtin + //! traits, like `Send`, and adds the corresponding + //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref` + //! is a builtin trait. + + match self.lang_items.to_builtin_kind(trait_def_id) { + Some(bound) => { builtin_bounds.insert(bound); true } + None => false } } - fn disr_wrap_incr(&self, val: Option) -> Disr { - macro_rules! add1 { - ($e:expr) => { ($e).wrapping_add(1) as Disr } + pub fn substd_enum_variants(&self, + id: ast::DefId, + substs: &Substs<'tcx>) + -> Vec>> { + self.enum_variants(id).iter().map(|variant_info| { + let substd_args = variant_info.args.iter() + .map(|aty| aty.subst(self, substs)).collect::>(); + + let substd_ctor_ty = variant_info.ctor_ty.subst(self, substs); + + Rc::new(VariantInfo { + args: substd_args, + ctor_ty: substd_ctor_ty, + ..(**variant_info).clone() + }) + }).collect() + } + + pub fn item_path_str(&self, id: ast::DefId) -> String { + self.with_path(id, |path| ast_map::path_to_string(path)) + } + + /* If struct_id names a struct with a dtor. */ + pub fn ty_dtor(&self, struct_id: DefId) -> DtorKind { + match self.destructor_for_type.borrow().get(&struct_id) { + Some(&method_def_id) => { + let flag = !self.has_attr(struct_id, "unsafe_no_drop_flag"); + + TraitDtor(method_def_id, flag) + } + None => NoDtor, } - let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE); - match *self { - SignedInt(ast::TyI8) => add1!(val as i8 ), - SignedInt(ast::TyI16) => add1!(val as i16), - SignedInt(ast::TyI32) => add1!(val as i32), - SignedInt(ast::TyI64) => add1!(val as i64), - UnsignedInt(ast::TyU8) => add1!(val as u8 ), - UnsignedInt(ast::TyU16) => add1!(val as u16), - UnsignedInt(ast::TyU32) => add1!(val as u32), - UnsignedInt(ast::TyU64) => add1!(val as u64), + } - UnsignedInt(ast::TyUs) | - SignedInt(ast::TyIs) => unreachable!(), + pub fn has_dtor(&self, struct_id: DefId) -> bool { + self.destructor_for_type.borrow().contains_key(&struct_id) + } + + pub fn with_path(&self, id: ast::DefId, f: F) -> T where + F: FnOnce(ast_map::PathElems) -> T, + { + if id.krate == ast::LOCAL_CRATE { + self.map.with_path(id.node, f) + } else { + f(csearch::get_item_path(self, id).iter().cloned().chain(LinkedPath::empty())) } } -} -/// 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<'tcx>(cx: &ctxt<'tcx>, - opt_hint: Option<&attr::ReprAttr>) - -> (attr::IntType, Ty<'tcx>) -{ - let repr_type = match opt_hint { - // Feed in the given type - Some(&attr::ReprInt(_, int_t)) => int_t, - // ... but provide sensible default if none provided - // - // NB. Historically `fn enum_variants` generate i64 here, while - // rustc_typeck::check would generate isize. - _ => SignedInt(ast::TyIs), - }; - - let repr_type_ty = repr_type.to_ty(cx); - let repr_type = match repr_type { - SignedInt(ast::TyIs) => - SignedInt(cx.sess.target.int_type), - UnsignedInt(ast::TyUs) => - UnsignedInt(cx.sess.target.uint_type), - other => other - }; - - (repr_type, repr_type_ty) -} - -fn report_discrim_overflow(cx: &ctxt, - variant_span: Span, - variant_name: &str, - repr_type: attr::IntType, - prev_val: 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(cx); - span_err!(cx.sess, variant_span, E0370, - "enum discriminant overflowed on value after {}: {}; \ - set explicitly via {} = {} if that is desired outcome", - prev_val, repr_type, variant_name, computed_value); -} - -// This computes the discriminant values for the sequence of Variants -// attached to a particular enum, taking into account the #[repr] (if -// any) provided via the `opt_hint`. -fn compute_enum_variants<'tcx>(cx: &ctxt<'tcx>, - vs: &'tcx [P], - opt_hint: Option<&attr::ReprAttr>) - -> Vec>> { - let mut variants: Vec> = Vec::new(); - let mut prev_disr_val: Option = None; - - let (repr_type, repr_type_ty) = ty::enum_repr_type(cx, opt_hint); - - for v in vs { - // If the discriminant value is specified explicitly in the - // enum, check whether the initialization expression is valid, - // otherwise use the last value plus one. - let current_disr_val; - - // This closure marks cases where, when an error occurs during - // the computation, attempt to assign a (hopefully) fresh - // value to avoid spurious error reports downstream. - let attempt_fresh_value = move || -> Disr { - repr_type.disr_wrap_incr(prev_disr_val) + pub fn enum_is_univariant(&self, id: ast::DefId) -> bool { + self.enum_variants(id).len() == 1 + } + + /// 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 { + // Feed in the given type + Some(&attr::ReprInt(_, int_t)) => int_t, + // ... but provide sensible default if none provided + // + // NB. Historically `fn enum_variants` generate i64 here, while + // rustc_typeck::check would generate isize. + _ => SignedInt(ast::TyIs), }; - match v.node.disr_expr { - Some(ref e) => { - debug!("disr expr, checking {}", pprust::expr_to_string(&**e)); - - // check_expr (from check_const pass) doesn't guarantee - // that the expression is in a form that eval_const_expr can - // handle, so we may still get an internal compiler error - // - // pnkfelix: The above comment was transcribed from - // the version of this code taken from rustc_typeck. - // Presumably the implication is that we need to deal - // with such ICE's as they arise. - // - // Since this can be called from `ty::enum_variants` - // anyway, best thing is to make `eval_const_expr` - // more robust (on case-by-case basis). - - match const_eval::eval_const_expr_partial(cx, &**e, Some(repr_type_ty)) { - Ok(ConstVal::Int(val)) => current_disr_val = val as Disr, - Ok(ConstVal::Uint(val)) => current_disr_val = val as Disr, - Ok(_) => { - let sign_desc = if repr_type.is_signed() { "signed" } else { "unsigned" }; - span_err!(cx.sess, e.span, E0079, - "expected {} integer constant", - sign_desc); - current_disr_val = attempt_fresh_value(); - } - Err(ref err) => { - span_err!(cx.sess, err.span, E0080, - "constant evaluation error: {}", - err.description()); - current_disr_val = attempt_fresh_value(); + let repr_type_ty = repr_type.to_ty(self); + let repr_type = match repr_type { + SignedInt(ast::TyIs) => + SignedInt(self.sess.target.int_type), + UnsignedInt(ast::TyUs) => + UnsignedInt(self.sess.target.uint_type), + other => other + }; + + (repr_type, repr_type_ty) + } + + fn report_discrim_overflow(&self, + variant_span: Span, + variant_name: &str, + repr_type: attr::IntType, + prev_val: 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(self); + span_err!(self.sess, variant_span, E0370, + "enum discriminant overflowed on value after {}: {}; \ + set explicitly via {} = {} if that is desired outcome", + prev_val, repr_type, variant_name, computed_value); + } + + // This computes the discriminant values for the sequence of Variants + // attached to a particular enum, taking into account the #[repr] (if + // any) provided via the `opt_hint`. + fn compute_enum_variants(&self, + vs: &'tcx [P], + opt_hint: Option<&attr::ReprAttr>) + -> Vec>> { + let mut variants: Vec> = Vec::new(); + let mut prev_disr_val: Option = None; + + let (repr_type, repr_type_ty) = self.enum_repr_type(opt_hint); + + for v in vs { + // If the discriminant value is specified explicitly in the + // enum, check whether the initialization expression is valid, + // otherwise use the last value plus one. + let current_disr_val; + + // This closure marks cases where, when an error occurs during + // the computation, attempt to assign a (hopefully) fresh + // value to avoid spurious error reports downstream. + let attempt_fresh_value = move || -> Disr { + repr_type.disr_wrap_incr(prev_disr_val) + }; + + match v.node.disr_expr { + Some(ref e) => { + debug!("disr expr, checking {}", pprust::expr_to_string(&**e)); + + // check_expr (from check_const pass) doesn't guarantee + // that the expression is in a form that eval_const_expr can + // handle, so we may still get an internal compiler error + // + // pnkfelix: The above comment was transcribed from + // the version of this code taken from rustc_typeck. + // Presumably the implication is that we need to deal + // with such ICE's as they arise. + // + // Since this can be called from `ty::enum_variants` + // anyway, best thing is to make `eval_const_expr` + // more robust (on case-by-case basis). + + match const_eval::eval_const_expr_partial(self, &**e, Some(repr_type_ty)) { + Ok(ConstVal::Int(val)) => current_disr_val = val as Disr, + Ok(ConstVal::Uint(val)) => current_disr_val = val as Disr, + Ok(_) => { + let sign_desc = if repr_type.is_signed() { + "signed" + } else { + "unsigned" + }; + span_err!(self.sess, e.span, E0079, + "expected {} integer constant", + sign_desc); + current_disr_val = attempt_fresh_value(); + } + Err(ref err) => { + span_err!(self.sess, err.span, E0080, + "constant evaluation error: {}", + err.description()); + current_disr_val = attempt_fresh_value(); + } } - } - }, - None => { - current_disr_val = match prev_disr_val { - Some(prev_disr_val) => { - if let Some(v) = repr_type.disr_incr(prev_disr_val) { - v - } else { - report_discrim_overflow(cx, v.span, v.node.name.as_str(), - repr_type, prev_disr_val); - attempt_fresh_value() + }, + None => { + current_disr_val = match prev_disr_val { + Some(prev_disr_val) => { + if let Some(v) = repr_type.disr_incr(prev_disr_val) { + v + } else { + self.report_discrim_overflow(v.span, v.node.name.as_str(), + repr_type, prev_disr_val); + attempt_fresh_value() + } } + None => ty::INITIAL_DISCRIMINANT_VALUE } - None => ty::INITIAL_DISCRIMINANT_VALUE } } - } - let variant_info = Rc::new(VariantInfo::from_ast_variant(cx, &**v, current_disr_val)); - prev_disr_val = Some(current_disr_val); + let variant_info = Rc::new(VariantInfo::from_ast_variant(self, &**v, current_disr_val)); + prev_disr_val = Some(current_disr_val); - variants.push(variant_info); - } + variants.push(variant_info); + } - return variants; -} + variants + } -pub fn enum_variants<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) - -> Rc>>> { - memoized(&cx.enum_var_cache, id, |id: ast::DefId| { - if ast::LOCAL_CRATE != id.krate { - Rc::new(csearch::get_enum_variants(cx, id)) - } else { - match cx.map.get(id.node) { - ast_map::NodeItem(ref item) => { - match item.node { - ast::ItemEnum(ref enum_definition, _) => { - Rc::new(compute_enum_variants( - cx, - &enum_definition.variants, - lookup_repr_hints(cx, id).get(0))) - } - _ => { - cx.sess.bug("enum_variants: id not bound to an enum") + pub fn enum_variants(&self, id: ast::DefId) -> Rc>>> { + memoized(&self.enum_var_cache, id, |id: ast::DefId| { + if ast::LOCAL_CRATE != id.krate { + Rc::new(csearch::get_enum_variants(self, id)) + } else { + match self.map.get(id.node) { + ast_map::NodeItem(ref item) => { + match item.node { + ast::ItemEnum(ref enum_definition, _) => { + Rc::new(self.compute_enum_variants( + &enum_definition.variants, + self.lookup_repr_hints(id).get(0))) + } + _ => { + self.sess.bug("enum_variants: id not bound to an enum") + } } } + _ => self.sess.bug("enum_variants: id not bound to an enum") } - _ => cx.sess.bug("enum_variants: id not bound to an enum") } - } - }) -} + }) + } -// Returns information about the enum variant with the given ID: -pub fn enum_variant_with_id<'tcx>(cx: &ctxt<'tcx>, - enum_id: ast::DefId, - variant_id: ast::DefId) - -> Rc> { - enum_variants(cx, enum_id).iter() - .find(|variant| variant.id == variant_id) - .expect("enum_variant_with_id(): no variant exists with that ID") - .clone() -} + // Returns information about the enum variant with the given ID: + pub fn enum_variant_with_id(&self, + enum_id: ast::DefId, + variant_id: ast::DefId) + -> Rc> { + self.enum_variants(enum_id).iter() + .find(|variant| variant.id == variant_id) + .expect("enum_variant_with_id(): no variant exists with that ID") + .clone() + } + // Register a given item type + pub fn register_item_type(&self, did: ast::DefId, ty: TypeScheme<'tcx>) { + self.tcache.borrow_mut().insert(did, ty); + } -// If the given item is in an external crate, looks up its type and adds it to -// the type cache. Returns the type parameters and type. -pub fn lookup_item_type<'tcx>(cx: &ctxt<'tcx>, - did: ast::DefId) - -> TypeScheme<'tcx> { - lookup_locally_or_in_crate_store( - "tcache", did, &cx.tcache, - || csearch::get_type(cx, did)) -} + // If the given item is in an external crate, looks up its type and adds it to + // the type cache. Returns the type parameters and type. + pub fn lookup_item_type(&self, did: ast::DefId) -> TypeScheme<'tcx> { + lookup_locally_or_in_crate_store( + "tcache", did, &self.tcache, + || csearch::get_type(self, did)) + } -/// Given the did of a trait, returns its canonical trait ref. -pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) - -> &'tcx TraitDef<'tcx> { - lookup_locally_or_in_crate_store( - "trait_defs", did, &cx.trait_defs, - || cx.arenas.trait_defs.alloc(csearch::get_trait_def(cx, did)) - ) -} + /// Given the did of a trait, returns its canonical trait ref. + pub fn lookup_trait_def(&self, did: ast::DefId) -> &'tcx TraitDef<'tcx> { + lookup_locally_or_in_crate_store( + "trait_defs", did, &self.trait_defs, + || self.arenas.trait_defs.alloc(csearch::get_trait_def(self, did)) + ) + } -/// Given the did of an item, returns its full set of predicates. -pub fn lookup_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) - -> GenericPredicates<'tcx> -{ - lookup_locally_or_in_crate_store( - "predicates", did, &cx.predicates, - || csearch::get_predicates(cx, did)) -} + /// Given the did of an item, returns its full set of predicates. + pub fn lookup_predicates(&self, did: ast::DefId) -> GenericPredicates<'tcx> { + lookup_locally_or_in_crate_store( + "predicates", did, &self.predicates, + || csearch::get_predicates(self, did)) + } -/// Given the did of a trait, returns its superpredicates. -pub fn lookup_super_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) - -> GenericPredicates<'tcx> -{ - lookup_locally_or_in_crate_store( - "super_predicates", did, &cx.super_predicates, - || csearch::get_super_predicates(cx, did)) -} + /// Given the did of a trait, returns its superpredicates. + pub fn lookup_super_predicates(&self, did: ast::DefId) -> GenericPredicates<'tcx> { + lookup_locally_or_in_crate_store( + "super_predicates", did, &self.super_predicates, + || csearch::get_super_predicates(self, did)) + } -/// Get the attributes of a definition. -pub fn get_attrs<'tcx>(tcx: &'tcx ctxt, did: DefId) - -> Cow<'tcx, [ast::Attribute]> { - if is_local(did) { - Cow::Borrowed(tcx.map.attrs(did.node)) - } else { - Cow::Owned(csearch::get_item_attrs(&tcx.sess.cstore, did)) + /// Get the attributes of a definition. + pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [ast::Attribute]> { + if is_local(did) { + Cow::Borrowed(self.map.attrs(did.node)) + } else { + Cow::Owned(csearch::get_item_attrs(&self.sess.cstore, did)) + } } -} -/// Determine whether an item is annotated with an attribute -pub fn has_attr(tcx: &ctxt, did: DefId, attr: &str) -> bool { - get_attrs(tcx, did).iter().any(|item| item.check_name(attr)) -} + /// Determine whether an item is annotated with an attribute + pub fn has_attr(&self, did: DefId, attr: &str) -> bool { + self.get_attrs(did).iter().any(|item| item.check_name(attr)) + } -/// Determine whether an item is annotated with `#[repr(packed)]` -pub fn lookup_packed(tcx: &ctxt, did: DefId) -> bool { - lookup_repr_hints(tcx, did).contains(&attr::ReprPacked) -} + /// Determine whether an item is annotated with `#[repr(packed)]` + pub fn lookup_packed(&self, did: DefId) -> bool { + self.lookup_repr_hints(did).contains(&attr::ReprPacked) + } -/// Determine whether an item is annotated with `#[simd]` -pub fn lookup_simd(tcx: &ctxt, did: DefId) -> bool { - has_attr(tcx, did, "simd") -} + /// Determine whether an item is annotated with `#[simd]` + pub fn lookup_simd(&self, did: DefId) -> bool { + self.has_attr(did, "simd") + } -/// Obtain the representation annotation for a struct definition. -pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Rc> { - memoized(&tcx.repr_hint_cache, did, |did: DefId| { - Rc::new(if did.krate == LOCAL_CRATE { - get_attrs(tcx, did).iter().flat_map(|meta| { - attr::find_repr_attrs(tcx.sess.diagnostic(), meta).into_iter() - }).collect() - } else { - csearch::get_repr_attrs(&tcx.sess.cstore, did) + /// Obtain the representation annotation for a struct definition. + pub fn lookup_repr_hints(&self, did: DefId) -> Rc> { + memoized(&self.repr_hint_cache, did, |did: DefId| { + Rc::new(if did.krate == LOCAL_CRATE { + self.get_attrs(did).iter().flat_map(|meta| { + attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter() + }).collect() + } else { + csearch::get_repr_attrs(&self.sess.cstore, did) + }) }) - }) -} + } -// Look up a field ID, whether or not it's local -pub fn lookup_field_type_unsubstituted<'tcx>(tcx: &ctxt<'tcx>, - struct_id: DefId, - id: DefId) - -> Ty<'tcx> { - if id.krate == ast::LOCAL_CRATE { - node_id_to_type(tcx, id.node) - } else { - let mut tcache = tcx.tcache.borrow_mut(); - tcache.entry(id).or_insert_with(|| csearch::get_field_type(tcx, struct_id, id)).ty + // Look up a field ID, whether or not it's local + pub fn lookup_field_type_unsubstituted(&self, + struct_id: DefId, + id: DefId) + -> Ty<'tcx> { + if id.krate == ast::LOCAL_CRATE { + self.node_id_to_type(id.node) + } else { + memoized(&self.tcache, id, + |id| csearch::get_field_type(self, struct_id, id)).ty + } } -} -// Look up a field ID, whether or not it's local -// Takes a list of type substs in case the struct is generic -pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>, - struct_id: DefId, - id: DefId, - substs: &Substs<'tcx>) - -> Ty<'tcx> { - lookup_field_type_unsubstituted(tcx, struct_id, id).subst(tcx, substs) -} + // Look up a field ID, whether or not it's local + // Takes a list of type substs in case the struct is generic + pub fn lookup_field_type(&self, + struct_id: DefId, + id: DefId, + substs: &Substs<'tcx>) + -> Ty<'tcx> { + self.lookup_field_type_unsubstituted(struct_id, id).subst(self, substs) + } -// Look up the list of field names and IDs for a given struct. -// Panics if the id is not bound to a struct. -pub fn lookup_struct_fields(cx: &ctxt, did: ast::DefId) -> Vec { - if did.krate == ast::LOCAL_CRATE { - let struct_fields = cx.struct_fields.borrow(); - match struct_fields.get(&did) { - Some(fields) => (**fields).clone(), - _ => { - cx.sess.bug( - &format!("ID not mapped to struct fields: {}", - cx.map.node_to_string(did.node))); + // Look up the list of field names and IDs for a given struct. + // Panics if the id is not bound to a struct. + pub fn lookup_struct_fields(&self, did: ast::DefId) -> Vec { + if did.krate == ast::LOCAL_CRATE { + let struct_fields = self.struct_fields.borrow(); + match struct_fields.get(&did) { + Some(fields) => (**fields).clone(), + _ => { + self.sess.bug( + &format!("ID not mapped to struct fields: {}", + self.map.node_to_string(did.node))); + } } + } else { + csearch::get_struct_fields(&self.sess.cstore, did) } - } else { - csearch::get_struct_fields(&cx.sess.cstore, did) } -} -pub fn is_tuple_struct(cx: &ctxt, did: ast::DefId) -> bool { - let fields = lookup_struct_fields(cx, did); - !fields.is_empty() && fields.iter().all(|f| f.name == token::special_names::unnamed_field) -} + pub fn is_tuple_struct(&self, did: ast::DefId) -> bool { + let fields = self.lookup_struct_fields(did); + !fields.is_empty() && fields.iter().all(|f| f.name == token::special_names::unnamed_field) + } -// Returns a list of fields corresponding to the struct's items. trans uses -// this. Takes a list of substs with which to instantiate field types. -pub fn struct_fields<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId, substs: &Substs<'tcx>) - -> Vec> { - lookup_struct_fields(cx, did).iter().map(|f| { - field { - name: f.name, - mt: mt { - ty: lookup_field_type(cx, did, f.id, substs), - mutbl: MutImmutable + // Returns a list of fields corresponding to the struct's items. trans uses + // this. Takes a list of substs with which to instantiate field types. + pub fn struct_fields(&self, did: ast::DefId, substs: &Substs<'tcx>) + -> Vec> { + self.lookup_struct_fields(did).iter().map(|f| { + field { + name: f.name, + mt: mt { + ty: self.lookup_field_type(did, f.id, substs), + mutbl: MutImmutable + } } - } - }).collect() -} + }).collect() + } -// Returns a list of fields corresponding to the tuple's items. trans uses -// this. -pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec> { - v.iter().enumerate().map(|(i, &f)| { - field { - name: token::intern(&i.to_string()), - mt: mt { - ty: f, - mutbl: MutImmutable + /// Returns the deeply last field of nested structures, or the same type, + /// if not a structure at all. Corresponds to the only possible unsized + /// field, and its type can be used to determine unsizing strategy. + pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + while let TyStruct(def_id, substs) = ty.sty { + match self.struct_fields(def_id, substs).last() { + Some(f) => ty = f.mt.ty, + None => break } } - }).collect() -} - -/// Returns the deeply last field of nested structures, or the same type, -/// if not a structure at all. Corresponds to the only possible unsized -/// field, and its type can be used to determine unsizing strategy. -pub fn struct_tail<'tcx>(cx: &ctxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> { - while let TyStruct(def_id, substs) = ty.sty { - match struct_fields(cx, def_id, substs).last() { - Some(f) => ty = f.mt.ty, - None => break - } + ty } - ty -} -/// Same as applying struct_tail on `source` and `target`, but only -/// keeps going as long as the two types are instances of the same -/// structure definitions. -/// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, -/// whereas struct_tail produces `T`, and `Trait`, respectively. -pub fn struct_lockstep_tails<'tcx>(cx: &ctxt<'tcx>, - source: Ty<'tcx>, - target: Ty<'tcx>) - -> (Ty<'tcx>, Ty<'tcx>) { - let (mut a, mut b) = (source, target); - while let (&TyStruct(a_did, a_substs), &TyStruct(b_did, b_substs)) = (&a.sty, &b.sty) { - if a_did != b_did { - continue; - } - if let Some(a_f) = struct_fields(cx, a_did, a_substs).last() { - if let Some(b_f) = struct_fields(cx, b_did, b_substs).last() { - a = a_f.mt.ty; - b = b_f.mt.ty; + /// Same as applying struct_tail on `source` and `target`, but only + /// keeps going as long as the two types are instances of the same + /// structure definitions. + /// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, + /// whereas struct_tail produces `T`, and `Trait`, respectively. + pub fn struct_lockstep_tails(&self, + source: Ty<'tcx>, + target: Ty<'tcx>) + -> (Ty<'tcx>, Ty<'tcx>) { + let (mut a, mut b) = (source, target); + while let (&TyStruct(a_did, a_substs), &TyStruct(b_did, b_substs)) = (&a.sty, &b.sty) { + if a_did != b_did { + break; + } + if let Some(a_f) = self.struct_fields(a_did, a_substs).last() { + if let Some(b_f) = self.struct_fields(b_did, b_substs).last() { + a = a_f.mt.ty; + b = b_f.mt.ty; + } else { + break; + } } else { break; } - } else { - break; } + (a, b) } - (a, b) -} -#[derive(Copy, Clone)] -pub struct ClosureUpvar<'tcx> { - pub def: def::Def, - pub span: Span, - pub ty: Ty<'tcx>, -} + // Returns a list of `ClosureUpvar`s for each upvar. + pub fn closure_upvars<'a>(typer: &infer::InferCtxt<'a, 'tcx>, + closure_id: ast::DefId, + substs: &Substs<'tcx>) + -> Option>> + { + // Presently an unboxed closure type cannot "escape" out of a + // function, so we will only encounter ones that originated in the + // local crate or were inlined into it along with some function. + // This may change if abstract return types of some sort are + // implemented. + assert!(closure_id.krate == ast::LOCAL_CRATE); + let tcx = typer.tcx; + match tcx.freevars.borrow().get(&closure_id.node) { + None => Some(vec![]), + Some(ref freevars) => { + freevars.iter() + .map(|freevar| { + let freevar_def_id = freevar.def.def_id(); + let freevar_ty = match typer.node_ty(freevar_def_id.node) { + Ok(t) => { t } + Err(()) => { return None; } + }; + let freevar_ty = freevar_ty.subst(tcx, substs); -// Returns a list of `ClosureUpvar`s for each upvar. -pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>, - closure_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option>> -{ - // Presently an unboxed closure type cannot "escape" out of a - // function, so we will only encounter ones that originated in the - // local crate or were inlined into it along with some function. - // This may change if abstract return types of some sort are - // implemented. - assert!(closure_id.krate == ast::LOCAL_CRATE); - let tcx = typer.tcx(); - match tcx.freevars.borrow().get(&closure_id.node) { - None => Some(vec![]), - Some(ref freevars) => { - freevars.iter() - .map(|freevar| { - let freevar_def_id = freevar.def.def_id(); - let freevar_ty = match typer.node_ty(freevar_def_id.node) { - Ok(t) => { t } - Err(()) => { return None; } - }; - let freevar_ty = freevar_ty.subst(tcx, substs); - - let upvar_id = ty::UpvarId { - var_id: freevar_def_id.node, - closure_expr_id: closure_id.node - }; - - typer.upvar_capture(upvar_id).map(|capture| { - let freevar_ref_ty = match capture { - UpvarCapture::ByValue => { - freevar_ty - } - UpvarCapture::ByRef(borrow) => { - mk_rptr(tcx, - tcx.mk_region(borrow.region), + let upvar_id = ty::UpvarId { + var_id: freevar_def_id.node, + closure_expr_id: closure_id.node + }; + + typer.upvar_capture(upvar_id).map(|capture| { + let freevar_ref_ty = match capture { + UpvarCapture::ByValue => { + freevar_ty + } + UpvarCapture::ByRef(borrow) => { + tcx.mk_ref(tcx.mk_region(borrow.region), ty::mt { ty: freevar_ty, mutbl: borrow.kind.to_mutbl_lossy(), }) - } - }; + } + }; - ClosureUpvar { - def: freevar.def, - span: freevar.span, - ty: freevar_ref_ty, - } + ClosureUpvar { + def: freevar.def, + span: freevar.span, + ty: freevar_ref_ty, + } + }) }) - }) - .collect() - } - } -} - -// Returns the repeat count for a repeating vector expression. -pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> usize { - match const_eval::eval_const_expr_partial(tcx, count_expr, Some(tcx.types.usize)) { - Ok(val) => { - let found = match val { - ConstVal::Uint(count) => return count as usize, - ConstVal::Int(count) if count >= 0 => return count as usize, - ConstVal::Int(_) => "negative integer", - ConstVal::Float(_) => "float", - ConstVal::Str(_) => "string", - ConstVal::Bool(_) => "boolean", - ConstVal::Binary(_) => "binary array", - ConstVal::Struct(..) => "struct", - ConstVal::Tuple(_) => "tuple" - }; - span_err!(tcx.sess, count_expr.span, E0306, - "expected positive integer for repeat count, found {}", - found); - } - Err(err) => { - let err_description = err.description(); - let found = match count_expr.node { - ast::ExprPath(None, ast::Path { - global: false, - ref segments, - .. - }) if segments.len() == 1 => - format!("{}", "found variable"), - _ => - format!("but {}", err_description), - }; - span_err!(tcx.sess, count_expr.span, E0307, - "expected constant integer for repeat count, {}", - found); + .collect() + } } } - 0 -} -// Iterate over a type parameter's bounded traits and any supertraits -// of those traits, ignoring kinds. -// Here, the supertraits are the transitive closure of the supertrait -// relation on the supertraits from each bounded trait's constraint -// list. -pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, - bounds: &[PolyTraitRef<'tcx>], - mut f: F) - -> bool where - F: FnMut(PolyTraitRef<'tcx>) -> bool, -{ - for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { - if !f(bound_trait_ref) { - return false; + // Returns the repeat count for a repeating vector expression. + pub fn eval_repeat_count(&self, count_expr: &ast::Expr) -> usize { + match const_eval::eval_const_expr_partial(self, count_expr, Some(self.types.usize)) { + Ok(val) => { + let found = match val { + ConstVal::Uint(count) => return count as usize, + ConstVal::Int(count) if count >= 0 => return count as usize, + ConstVal::Int(_) => "negative integer", + ConstVal::Float(_) => "float", + ConstVal::Str(_) => "string", + ConstVal::Bool(_) => "boolean", + ConstVal::Binary(_) => "binary array", + ConstVal::Struct(..) => "struct", + ConstVal::Tuple(_) => "tuple" + }; + span_err!(self.sess, count_expr.span, E0306, + "expected positive integer for repeat count, found {}", + found); + } + Err(err) => { + let err_description = err.description(); + let found = match count_expr.node { + ast::ExprPath(None, ast::Path { + global: false, + ref segments, + .. + }) if segments.len() == 1 => + format!("{}", "found variable"), + _ => + format!("but {}", err_description), + }; + span_err!(self.sess, count_expr.span, E0307, + "expected constant integer for repeat count, {}", + found); + } } + 0 } - return true; -} -/// Given a set of predicates that apply to an object type, returns -/// the region bounds that the (erased) `Self` type must -/// outlive. Precisely *because* the `Self` type is erased, the -/// parameter `erased_self_ty` must be supplied to indicate what type -/// has been used to represent `Self` in the predicates -/// themselves. This should really be a unique type; `FreshTy(0)` is a -/// popular choice. -/// -/// Requires that trait definitions have been processed so that we can -/// elaborate predicates and walk supertraits. -pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>, - erased_self_ty: Ty<'tcx>, - predicates: Vec>) - -> Vec -{ - debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", - erased_self_ty, - predicates); - - assert!(!erased_self_ty.has_escaping_regions()); - - traits::elaborate_predicates(tcx, predicates) - .filter_map(|predicate| { - match predicate { - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) => { - None - } - ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { - // Search for a bound of the form `erased_self_ty - // : 'a`, but be wary of something like `for<'a> - // erased_self_ty : 'a` (we interpret a - // higher-ranked bound like that as 'static, - // though at present the code in `fulfill.rs` - // considers such bounds to be unsatisfiable, so - // it's kind of a moot point since you could never - // construct such an object, but this seems - // correct even if that code changes). - if t == erased_self_ty && !r.has_escaping_regions() { - if r.has_escaping_regions() { - Some(ty::ReStatic) + // Iterate over a type parameter's bounded traits and any supertraits + // of those traits, ignoring kinds. + // Here, the supertraits are the transitive closure of the supertrait + // relation on the supertraits from each bounded trait's constraint + // list. + pub fn each_bound_trait_and_supertraits(&self, + bounds: &[PolyTraitRef<'tcx>], + mut f: F) + -> bool where + F: FnMut(PolyTraitRef<'tcx>) -> bool, + { + for bound_trait_ref in traits::transitive_bounds(self, bounds) { + if !f(bound_trait_ref) { + return false; + } + } + return true; + } + + /// Given a set of predicates that apply to an object type, returns + /// the region bounds that the (erased) `Self` type must + /// outlive. Precisely *because* the `Self` type is erased, the + /// parameter `erased_self_ty` must be supplied to indicate what type + /// has been used to represent `Self` in the predicates + /// themselves. This should really be a unique type; `FreshTy(0)` is a + /// popular choice. + /// + /// Requires that trait definitions have been processed so that we can + /// elaborate predicates and walk supertraits. + pub fn required_region_bounds(&self, + erased_self_ty: Ty<'tcx>, + predicates: Vec>) + -> Vec + { + debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", + erased_self_ty, + predicates); + + assert!(!erased_self_ty.has_escaping_regions()); + + traits::elaborate_predicates(self, predicates) + .filter_map(|predicate| { + match predicate { + ty::Predicate::Projection(..) | + ty::Predicate::Trait(..) | + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) => { + None + } + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + if t == erased_self_ty && !r.has_escaping_regions() { + if r.has_escaping_regions() { + Some(ty::ReStatic) + } else { + Some(r) + } } else { - Some(r) + None } - } else { - None } } - } - }) - .collect() -} - -pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc { - lookup_locally_or_in_crate_store( - "item_variance_map", item_id, &tcx.item_variance_map, - || Rc::new(csearch::get_item_variances(&tcx.sess.cstore, item_id))) -} - -pub fn trait_has_default_impl(tcx: &ctxt, trait_def_id: DefId) -> bool { - populate_implementations_for_trait_if_necessary(tcx, trait_def_id); + }) + .collect() + } - let def = lookup_trait_def(tcx, trait_def_id); - def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) -} + pub fn item_variances(&self, item_id: ast::DefId) -> Rc { + lookup_locally_or_in_crate_store( + "item_variance_map", item_id, &self.item_variance_map, + || Rc::new(csearch::get_item_variances(&self.sess.cstore, item_id))) + } -/// Records a trait-to-implementation mapping. -pub fn record_trait_has_default_impl(tcx: &ctxt, trait_def_id: DefId) { - let def = lookup_trait_def(tcx, trait_def_id); - def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL) -} + pub fn trait_has_default_impl(&self, trait_def_id: DefId) -> bool { + self.populate_implementations_for_trait_if_necessary(trait_def_id); -/// Load primitive inherent implementations if necessary -pub fn populate_implementations_for_primitive_if_necessary(tcx: &ctxt, - primitive_def_id: ast::DefId) { - if primitive_def_id.krate == LOCAL_CRATE { - return + let def = self.lookup_trait_def(trait_def_id); + def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) } - if tcx.populated_external_primitive_impls.borrow().contains(&primitive_def_id) { - return + /// Records a trait-to-implementation mapping. + pub fn record_trait_has_default_impl(&self, trait_def_id: DefId) { + let def = self.lookup_trait_def(trait_def_id); + def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL) } - debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", - primitive_def_id); + /// Load primitive inherent implementations if necessary + pub fn populate_implementations_for_primitive_if_necessary(&self, + primitive_def_id: ast::DefId) { + if primitive_def_id.krate == LOCAL_CRATE { + return + } - let impl_items = csearch::get_impl_items(&tcx.sess.cstore, primitive_def_id); + if self.populated_external_primitive_impls.borrow().contains(&primitive_def_id) { + return + } - // Store the implementation info. - tcx.impl_items.borrow_mut().insert(primitive_def_id, impl_items); - tcx.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); -} + debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", + primitive_def_id); -/// Populates the type context with all the inherent implementations for -/// the given type if necessary. -pub fn populate_inherent_implementations_for_type_if_necessary(tcx: &ctxt, - type_id: ast::DefId) { - if type_id.krate == LOCAL_CRATE { - return - } + let impl_items = csearch::get_impl_items(&self.sess.cstore, primitive_def_id); - if tcx.populated_external_types.borrow().contains(&type_id) { - return + // Store the implementation info. + self.impl_items.borrow_mut().insert(primitive_def_id, impl_items); + self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); } - debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", type_id); + /// Populates the type context with all the inherent implementations for + /// the given type if necessary. + pub fn populate_inherent_implementations_for_type_if_necessary(&self, + type_id: ast::DefId) { + if type_id.krate == LOCAL_CRATE { + return + } - let mut inherent_impls = Vec::new(); - csearch::each_inherent_implementation_for_type(&tcx.sess.cstore, type_id, |impl_def_id| { - // Record the implementation. - inherent_impls.push(impl_def_id); + if self.populated_external_types.borrow().contains(&type_id) { + return + } - // Store the implementation info. - let impl_items = csearch::get_impl_items(&tcx.sess.cstore, impl_def_id); - tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items); - }); + debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", + type_id); - tcx.inherent_impls.borrow_mut().insert(type_id, Rc::new(inherent_impls)); - tcx.populated_external_types.borrow_mut().insert(type_id); -} + let mut inherent_impls = Vec::new(); + csearch::each_inherent_implementation_for_type(&self.sess.cstore, type_id, |impl_def_id| { + // Record the implementation. + inherent_impls.push(impl_def_id); -/// Populates the type context with all the implementations for the given -/// trait if necessary. -pub fn populate_implementations_for_trait_if_necessary(tcx: &ctxt, trait_id: ast::DefId) { - if trait_id.krate == LOCAL_CRATE { - return - } + // Store the implementation info. + let impl_items = csearch::get_impl_items(&self.sess.cstore, impl_def_id); + self.impl_items.borrow_mut().insert(impl_def_id, impl_items); + }); - let def = lookup_trait_def(tcx, trait_id); - if def.flags.get().intersects(TraitFlags::IMPLS_VALID) { - return; + self.inherent_impls.borrow_mut().insert(type_id, Rc::new(inherent_impls)); + self.populated_external_types.borrow_mut().insert(type_id); } - debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def); + /// Populates the type context with all the implementations for the given + /// trait if necessary. + pub fn populate_implementations_for_trait_if_necessary(&self, trait_id: ast::DefId) { + if trait_id.krate == LOCAL_CRATE { + return + } - if csearch::is_defaulted_trait(&tcx.sess.cstore, trait_id) { - record_trait_has_default_impl(tcx, trait_id); - } + let def = self.lookup_trait_def(trait_id); + if def.flags.get().intersects(TraitFlags::IMPLS_VALID) { + return; + } + + debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def); + + if csearch::is_defaulted_trait(&self.sess.cstore, trait_id) { + self.record_trait_has_default_impl(trait_id); + } - csearch::each_implementation_for_trait(&tcx.sess.cstore, trait_id, |implementation_def_id| { - let impl_items = csearch::get_impl_items(&tcx.sess.cstore, implementation_def_id); - let trait_ref = impl_trait_ref(tcx, implementation_def_id).unwrap(); - // Record the trait->implementation mapping. - def.record_impl(tcx, implementation_def_id, trait_ref); + csearch::each_implementation_for_trait(&self.sess.cstore, trait_id, |impl_def_id| { + let impl_items = csearch::get_impl_items(&self.sess.cstore, 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); - // For any methods that use a default implementation, add them to - // the map. This is a bit unfortunate. - for impl_item_def_id in &impl_items { - let method_def_id = impl_item_def_id.def_id(); - match impl_or_trait_item(tcx, method_def_id) { - MethodTraitItem(method) => { - if let Some(source) = method.provided_source { - tcx.provided_method_sources - .borrow_mut() - .insert(method_def_id, source); + // For any methods that use a default implementation, add them to + // the map. This is a bit unfortunate. + for impl_item_def_id in &impl_items { + let method_def_id = impl_item_def_id.def_id(); + match self.impl_or_trait_item(method_def_id) { + MethodTraitItem(method) => { + if let Some(source) = method.provided_source { + self.provided_method_sources + .borrow_mut() + .insert(method_def_id, source); + } } + _ => {} } - _ => {} } - } - // Store the implementation info. - tcx.impl_items.borrow_mut().insert(implementation_def_id, impl_items); - }); - - def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); -} + // Store the implementation info. + self.impl_items.borrow_mut().insert(impl_def_id, impl_items); + }); -/// Given the def_id of an impl, return the def_id of the trait it implements. -/// If it implements no trait, return `None`. -pub fn trait_id_of_impl(tcx: &ctxt, - def_id: ast::DefId) - -> Option { - ty::impl_trait_ref(tcx, def_id).map(|tr| tr.def_id) -} + def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); + } -/// If the given def ID describes a method belonging to an impl, return the -/// ID of the impl that the method belongs to. Otherwise, return `None`. -pub fn impl_of_method(tcx: &ctxt, def_id: ast::DefId) - -> Option { - if def_id.krate != LOCAL_CRATE { - return match csearch::get_impl_or_trait_item(tcx, - def_id).container() { - TraitContainer(_) => None, - ImplContainer(def_id) => Some(def_id), - }; + /// Given the def_id of an impl, return the def_id of the trait it implements. + /// If it implements no trait, return `None`. + pub fn trait_id_of_impl(&self, def_id: ast::DefId) -> Option { + self.impl_trait_ref(def_id).map(|tr| tr.def_id) } - match tcx.impl_or_trait_items.borrow().get(&def_id).cloned() { - Some(trait_item) => { - match trait_item.container() { + + /// If the given def ID describes a method belonging to an impl, return the + /// ID of the impl that the method belongs to. Otherwise, return `None`. + pub fn impl_of_method(&self, def_id: ast::DefId) -> Option { + if def_id.krate != LOCAL_CRATE { + return match csearch::get_impl_or_trait_item(self, + def_id).container() { TraitContainer(_) => None, ImplContainer(def_id) => Some(def_id), - } + }; } - None => None - } -} - -/// If the given def ID describes an item belonging to a trait (either a -/// default method or an implementation of a trait method), return the ID of -/// the trait that the method belongs to. Otherwise, return `None`. -pub fn trait_of_item(tcx: &ctxt, def_id: ast::DefId) -> Option { - if def_id.krate != LOCAL_CRATE { - return csearch::get_trait_of_item(&tcx.sess.cstore, def_id, tcx); - } - match tcx.impl_or_trait_items.borrow().get(&def_id).cloned() { - Some(impl_or_trait_item) => { - match impl_or_trait_item.container() { - TraitContainer(def_id) => Some(def_id), - ImplContainer(def_id) => trait_id_of_impl(tcx, def_id), + match self.impl_or_trait_items.borrow().get(&def_id).cloned() { + Some(trait_item) => { + match trait_item.container() { + TraitContainer(_) => None, + ImplContainer(def_id) => Some(def_id), + } } + None => None } - None => None } -} -/// If the given def ID describes an item belonging to a trait, (either a -/// default method or an implementation of a trait method), return the ID of -/// the method inside trait definition (this means that if the given def ID -/// is already that of the original trait method, then the return value is -/// the same). -/// Otherwise, return `None`. -pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId) - -> Option { - let impl_item = match tcx.impl_or_trait_items.borrow().get(&def_id) { - Some(m) => m.clone(), - None => return None, - }; - let name = impl_item.name(); - match trait_of_item(tcx, def_id) { - Some(trait_did) => { - let trait_items = ty::trait_items(tcx, trait_did); - trait_items.iter() - .position(|m| m.name() == name) - .map(|idx| ty::trait_item(tcx, trait_did, idx).id()) + /// If the given def ID describes an item belonging to a trait (either a + /// default method or an implementation of a trait method), return the ID of + /// the trait that the method belongs to. Otherwise, return `None`. + pub fn trait_of_item(&self, def_id: ast::DefId) -> Option { + if def_id.krate != LOCAL_CRATE { + return csearch::get_trait_of_item(&self.sess.cstore, def_id, self); } - None => None - } -} - -/// Creates a hash of the type `Ty` which will be the same no matter what crate -/// context it's calculated within. This is used by the `type_id` intrinsic. -pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -> u64 { - let mut state = SipHasher::new(); - helper(tcx, ty, svh, &mut state); - return state.finish(); - - fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, - state: &mut SipHasher) { - macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } - macro_rules! hash { ($e:expr) => { $e.hash(state) } } - - let region = |state: &mut SipHasher, r: Region| { - match r { - ReStatic => {} - ReLateBound(db, BrAnon(i)) => { - db.hash(state); - i.hash(state); - } - ReEmpty | - ReEarlyBound(..) | - ReLateBound(..) | - ReFree(..) | - ReScope(..) | - ReInfer(..) => { - tcx.sess.bug("unexpected region found when hashing a type") + match self.impl_or_trait_items.borrow().get(&def_id).cloned() { + Some(impl_or_trait_item) => { + match impl_or_trait_item.container() { + TraitContainer(def_id) => Some(def_id), + ImplContainer(def_id) => self.trait_id_of_impl(def_id), } } + None => None + } + } + + /// If the given def ID describes an item belonging to a trait, (either a + /// default method or an implementation of a trait method), return the ID of + /// the method inside trait definition (this means that if the given def ID + /// is already that of the original trait method, then the return value is + /// the same). + /// Otherwise, return `None`. + pub fn trait_item_of_item(&self, def_id: ast::DefId) -> Option { + let impl_item = match self.impl_or_trait_items.borrow().get(&def_id) { + Some(m) => m.clone(), + None => return None, }; - let did = |state: &mut SipHasher, did: DefId| { - let h = if ast_util::is_local(did) { - svh.clone() - } else { - tcx.sess.cstore.get_crate_hash(did.krate) - }; - h.as_str().hash(state); - did.node.hash(state); - }; - let mt = |state: &mut SipHasher, mt: mt| { - mt.mutbl.hash(state); - }; - let fn_sig = |state: &mut SipHasher, sig: &Binder>| { - let sig = anonymize_late_bound_regions(tcx, sig).0; - for a in &sig.inputs { helper(tcx, *a, svh, state); } - if let ty::FnConverging(output) = sig.output { - helper(tcx, output, svh, state); - } - }; - maybe_walk_ty(ty, |ty| { - match ty.sty { - TyBool => byte!(2), - TyChar => byte!(3), - TyInt(i) => { - byte!(4); - hash!(i); - } - TyUint(u) => { - byte!(5); - hash!(u); - } - TyFloat(f) => { - byte!(6); - hash!(f); - } - TyStr => { - byte!(7); - } - TyEnum(d, _) => { - byte!(8); - did(state, d); - } - TyBox(_) => { - byte!(9); - } - TyArray(_, n) => { - byte!(10); - n.hash(state); - } - TySlice(_) => { - byte!(11); - } - TyRawPtr(m) => { - byte!(12); - mt(state, m); - } - TyRef(r, m) => { - byte!(13); - region(state, *r); - mt(state, m); + let name = impl_item.name(); + match self.trait_of_item(def_id) { + Some(trait_did) => { + self.trait_items(trait_did).iter() + .find(|item| item.name() == name) + .map(|item| item.id()) + } + None => None + } + } + + /// Creates a hash of the type `Ty` which will be the same no matter what crate + /// context it's calculated within. This is used by the `type_id` intrinsic. + pub fn hash_crate_independent(&self, ty: Ty<'tcx>, svh: &Svh) -> u64 { + let mut state = SipHasher::new(); + helper(self, ty, svh, &mut state); + return state.finish(); + + fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, + state: &mut SipHasher) { + macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } + macro_rules! hash { ($e:expr) => { $e.hash(state) } } + + let region = |state: &mut SipHasher, r: Region| { + match r { + ReStatic => {} + ReLateBound(db, BrAnon(i)) => { + db.hash(state); + i.hash(state); + } + ReEmpty | + ReEarlyBound(..) | + ReLateBound(..) | + ReFree(..) | + ReScope(..) | + ReInfer(..) => { + tcx.sess.bug("unexpected region found when hashing a type") + } } - TyBareFn(opt_def_id, ref b) => { - byte!(14); - hash!(opt_def_id); - hash!(b.unsafety); - hash!(b.abi); - fn_sig(state, &b.sig); - return false; + }; + let did = |state: &mut SipHasher, did: DefId| { + let h = if ast_util::is_local(did) { + svh.clone() + } else { + tcx.sess.cstore.get_crate_hash(did.krate) + }; + h.as_str().hash(state); + did.node.hash(state); + }; + let mt = |state: &mut SipHasher, mt: mt| { + mt.mutbl.hash(state); + }; + let fn_sig = |state: &mut SipHasher, sig: &Binder>| { + let sig = tcx.anonymize_late_bound_regions(sig).0; + for a in &sig.inputs { helper(tcx, *a, svh, state); } + if let ty::FnConverging(output) = sig.output { + helper(tcx, output, svh, state); } - TyTrait(ref data) => { - byte!(17); - did(state, data.principal_def_id()); - hash!(data.bounds); - - let principal = anonymize_late_bound_regions(tcx, &data.principal).0; - for subty in &principal.substs.types { - helper(tcx, subty, svh, state); + }; + ty.maybe_walk(|ty| { + match ty.sty { + TyBool => byte!(2), + TyChar => byte!(3), + TyInt(i) => { + byte!(4); + hash!(i); + } + TyUint(u) => { + byte!(5); + hash!(u); + } + TyFloat(f) => { + byte!(6); + hash!(f); + } + TyStr => { + byte!(7); + } + TyEnum(d, _) => { + byte!(8); + did(state, d); + } + TyBox(_) => { + byte!(9); + } + TyArray(_, n) => { + byte!(10); + n.hash(state); + } + TySlice(_) => { + byte!(11); } + TyRawPtr(m) => { + byte!(12); + mt(state, m); + } + TyRef(r, m) => { + byte!(13); + region(state, *r); + mt(state, m); + } + TyBareFn(opt_def_id, ref b) => { + byte!(14); + hash!(opt_def_id); + hash!(b.unsafety); + hash!(b.abi); + fn_sig(state, &b.sig); + return false; + } + TyTrait(ref data) => { + byte!(17); + did(state, data.principal_def_id()); + hash!(data.bounds); + + let principal = tcx.anonymize_late_bound_regions(&data.principal).0; + for subty in &principal.substs.types { + helper(tcx, subty, svh, state); + } - return false; - } - TyStruct(d, _) => { - byte!(18); - did(state, d); - } - TyTuple(ref inner) => { - byte!(19); - hash!(inner.len()); - } - TyParam(p) => { - byte!(20); - hash!(p.space); - hash!(p.idx); - hash!(token::get_name(p.name)); - } - TyInfer(_) => unreachable!(), - TyError => byte!(21), - TyClosure(d, _) => { - byte!(22); - did(state, d); - } - TyProjection(ref data) => { - byte!(23); - did(state, data.trait_ref.def_id); - hash!(token::get_name(data.item_name)); + return false; + } + TyStruct(d, _) => { + byte!(18); + did(state, d); + } + TyTuple(ref inner) => { + byte!(19); + hash!(inner.len()); + } + TyParam(p) => { + byte!(20); + hash!(p.space); + hash!(p.idx); + hash!(token::get_name(p.name)); + } + TyInfer(_) => unreachable!(), + TyError => byte!(21), + TyClosure(d, _) => { + byte!(22); + did(state, d); + } + TyProjection(ref data) => { + byte!(23); + did(state, data.trait_ref.def_id); + hash!(token::get_name(data.item_name)); + } } - } - true - }); - } -} - -impl fmt::Debug for Variance { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match *self { - Covariant => "+", - Contravariant => "-", - Invariant => "o", - Bivariant => "*", - }) - } -} - -/// Construct a parameter environment suitable for static contexts or other contexts where there -/// are no free type/lifetime parameters in scope. -pub fn empty_parameter_environment<'a,'tcx>(cx: &'a ctxt<'tcx>) -> ParameterEnvironment<'a,'tcx> { - ty::ParameterEnvironment { tcx: cx, - free_substs: Substs::empty(), - caller_bounds: Vec::new(), - implicit_region_bound: ty::ReEmpty, - selection_cache: traits::SelectionCache::new(), } -} - -/// Constructs and returns a substitution that can be applied to move from -/// the "outer" view of a type or method to the "inner" view. -/// In general, this means converting from bound parameters to -/// free parameters. Since we currently represent bound/free type -/// parameters in the same way, this only has an effect on regions. -pub fn construct_free_substs<'a,'tcx>( - tcx: &'a ctxt<'tcx>, - generics: &Generics<'tcx>, - free_id: ast::NodeId) - -> Substs<'tcx> -{ - // map T => T - let mut types = VecPerParamSpace::empty(); - push_types_from_defs(tcx, &mut types, generics.types.as_slice()); - - let free_id_outlive = region::DestructionScopeData::new(free_id); - - // map bound 'a => free 'a - let mut regions = VecPerParamSpace::empty(); - push_region_params(&mut regions, free_id_outlive, generics.regions.as_slice()); - - return Substs { - types: types, - regions: subst::NonerasedRegions(regions) - }; - - fn push_region_params(regions: &mut VecPerParamSpace, - all_outlive_extent: region::DestructionScopeData, - region_params: &[RegionParameterDef]) - { - for r in region_params { - regions.push(r.space, ty::free_region_from_def(all_outlive_extent, r)); - } - } - - fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>, - types: &mut VecPerParamSpace>, - defs: &[TypeParameterDef<'tcx>]) { - for def in defs { + true + }); + } + } + + /// Construct a parameter environment suitable for static contexts or other contexts where there + /// are no free type/lifetime parameters in scope. + pub fn empty_parameter_environment<'a>(&'a self) -> ParameterEnvironment<'a,'tcx> { + ty::ParameterEnvironment { tcx: self, + free_substs: Substs::empty(), + caller_bounds: Vec::new(), + implicit_region_bound: ty::ReEmpty, + selection_cache: traits::SelectionCache::new(), } + } + + /// Constructs and returns a substitution that can be applied to move from + /// the "outer" view of a type or method to the "inner" view. + /// In general, this means converting from bound parameters to + /// free parameters. Since we currently represent bound/free type + /// parameters in the same way, this only has an effect on regions. + pub fn construct_free_substs(&self, generics: &Generics<'tcx>, + free_id: ast::NodeId) -> Substs<'tcx> { + // map T => T + let mut types = VecPerParamSpace::empty(); + for def in generics.types.as_slice() { debug!("construct_parameter_environment(): push_types_from_defs: def={:?}", - def); - let ty = ty::mk_param_from_def(tcx, def); - types.push(def.space, ty); - } - } -} - -/// See `ParameterEnvironment` struct def'n for details -pub fn construct_parameter_environment<'a,'tcx>( - tcx: &'a ctxt<'tcx>, - span: Span, - generics: &ty::Generics<'tcx>, - generic_predicates: &ty::GenericPredicates<'tcx>, - free_id: ast::NodeId) - -> ParameterEnvironment<'a, 'tcx> -{ - // - // Construct the free substs. - // - - let free_substs = construct_free_substs(tcx, generics, free_id); - let free_id_outlive = region::DestructionScopeData::new(free_id); - - // - // Compute the bounds on Self and the type parameters. - // - - let bounds = generic_predicates.instantiate(tcx, &free_substs); - let bounds = liberate_late_bound_regions(tcx, free_id_outlive, &ty::Binder(bounds)); - let predicates = bounds.predicates.into_vec(); - - debug!("construct_parameter_environment: free_id={:?} free_subst={:?} predicates={:?}", - free_id, - free_substs, - predicates); - - // - // Finally, we have to normalize the bounds in the environment, in - // case they contain any associated type projections. This process - // can yield errors if the put in illegal associated types, like - // `::Bar` where `i32` does not implement `Foo`. We - // report these errors right here; this doesn't actually feel - // right to me, because constructing the environment feels like a - // kind of a "idempotent" action, but I'm not sure where would be - // a better place. In practice, we construct environments for - // every fn once during type checking, and we'll abort if there - // are any errors at that point, so after type checking you can be - // sure that this will succeed without errors anyway. - // - - let unnormalized_env = ty::ParameterEnvironment { - tcx: tcx, - free_substs: free_substs, - implicit_region_bound: ty::ReScope(free_id_outlive.to_code_extent()), - caller_bounds: predicates, - selection_cache: traits::SelectionCache::new(), - }; - - let cause = traits::ObligationCause::misc(span, free_id); - traits::normalize_param_env_or_error(unnormalized_env, cause) -} - -impl BorrowKind { - pub fn from_mutbl(m: ast::Mutability) -> BorrowKind { - match m { - ast::MutMutable => MutBorrow, - ast::MutImmutable => ImmBorrow, + def); + types.push(def.space, self.mk_param_from_def(def)); } - } - /// Returns a mutability `m` such that an `&m T` pointer could be used to obtain this borrow - /// kind. Because borrow kinds are richer than mutabilities, we sometimes have to pick a - /// mutability that is stronger than necessary so that it at least *would permit* the borrow in - /// question. - pub fn to_mutbl_lossy(self) -> ast::Mutability { - match self { - MutBorrow => ast::MutMutable, - ImmBorrow => ast::MutImmutable, + let free_id_outlive = region::DestructionScopeData::new(free_id); - // We have no type corresponding to a unique imm borrow, so - // use `&mut`. It gives all the capabilities of an `&uniq` - // and hence is a safe "over approximation". - UniqueImmBorrow => ast::MutMutable, + // map bound 'a => free 'a + let mut regions = VecPerParamSpace::empty(); + for def in generics.regions.as_slice() { + let region = + ReFree(FreeRegion { scope: free_id_outlive, + bound_region: BrNamed(def.def_id, def.name) }); + debug!("push_region_params {:?}", region); + regions.push(def.space, region); } - } - pub fn to_user_str(&self) -> &'static str { - match *self { - MutBorrow => "mutable", - ImmBorrow => "immutable", - UniqueImmBorrow => "uniquely immutable", + Substs { + types: types, + regions: subst::NonerasedRegions(regions) } } -} - -impl<'tcx> ctxt<'tcx> { - pub fn is_method_call(&self, expr_id: ast::NodeId) -> bool { - self.method_map.borrow().contains_key(&MethodCall::expr(expr_id)) - } - - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { - Some(self.upvar_capture_map.borrow().get(&upvar_id).unwrap().clone()) - } -} - -impl<'a,'tcx> mc::Typer<'tcx> for ParameterEnvironment<'a,'tcx> { - fn node_ty(&self, id: ast::NodeId) -> mc::McResult> { - Ok(ty::node_id_to_type(self.tcx, id)) - } - - fn expr_ty_adjusted(&self, expr: &ast::Expr) -> mc::McResult> { - Ok(ty::expr_ty_adjusted(self.tcx, expr)) - } - fn node_method_ty(&self, method_call: ty::MethodCall) -> Option> { - self.tcx.method_map.borrow().get(&method_call).map(|method| method.ty) - } - - fn node_method_origin(&self, method_call: ty::MethodCall) - -> Option> + /// See `ParameterEnvironment` struct def'n for details + pub fn construct_parameter_environment<'a>(&'a self, + span: Span, + generics: &ty::Generics<'tcx>, + generic_predicates: &ty::GenericPredicates<'tcx>, + free_id: ast::NodeId) + -> ParameterEnvironment<'a, 'tcx> { - self.tcx.method_map.borrow().get(&method_call).map(|method| method.origin.clone()) - } + // + // Construct the free substs. + // - fn adjustments(&self) -> &RefCell>> { - &self.tcx.adjustments - } + let free_substs = self.construct_free_substs(generics, free_id); + let free_id_outlive = region::DestructionScopeData::new(free_id); - fn is_method_call(&self, id: ast::NodeId) -> bool { - self.tcx.is_method_call(id) - } + // + // Compute the bounds on Self and the type parameters. + // - fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { - self.tcx.region_maps.temporary_scope(rvalue_id) - } + let bounds = generic_predicates.instantiate(self, &free_substs); + let bounds = self.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); + let predicates = bounds.predicates.into_vec(); - fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { - self.tcx.upvar_capture(upvar_id) - } + debug!("construct_parameter_environment: free_id={:?} free_subst={:?} predicates={:?}", + free_id, + free_substs, + predicates); - fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool { - type_moves_by_default(self, span, ty) - } -} + // + // Finally, we have to normalize the bounds in the environment, in + // case they contain any associated type projections. This process + // can yield errors if the put in illegal associated types, like + // `::Bar` where `i32` does not implement `Foo`. We + // report these errors right here; this doesn't actually feel + // right to me, because constructing the environment feels like a + // kind of a "idempotent" action, but I'm not sure where would be + // a better place. In practice, we construct environments for + // every fn once during type checking, and we'll abort if there + // are any errors at that point, so after type checking you can be + // sure that this will succeed without errors anyway. + // -impl<'a,'tcx> ClosureTyper<'tcx> for ty::ParameterEnvironment<'a,'tcx> { - fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> { - self - } + let unnormalized_env = ty::ParameterEnvironment { + tcx: self, + free_substs: free_substs, + implicit_region_bound: ty::ReScope(free_id_outlive.to_code_extent()), + caller_bounds: predicates, + selection_cache: traits::SelectionCache::new(), + }; - fn closure_kind(&self, - def_id: ast::DefId) - -> Option - { - Some(self.tcx.closure_kind(def_id)) + let cause = traits::ObligationCause::misc(span, free_id); + traits::normalize_param_env_or_error(unnormalized_env, cause) } - fn closure_type(&self, - def_id: ast::DefId, - substs: &subst::Substs<'tcx>) - -> ty::ClosureTy<'tcx> - { - self.tcx.closure_type(def_id, substs) + pub fn is_method_call(&self, expr_id: ast::NodeId) -> bool { + self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id)) } - fn closure_upvars(&self, - def_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option>> - { - closure_upvars(self, def_id, substs) + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { + Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) } } - /// The category of explicit self. #[derive(Clone, Copy, Eq, PartialEq, Debug)] pub enum ExplicitSelfCategory { @@ -7035,59 +6645,6 @@ pub enum ExplicitSelfCategory { ByBoxExplicitSelfCategory, } -/// Pushes all the lifetimes in the given type onto the given list. A -/// "lifetime in a type" is a lifetime specified by a reference or a lifetime -/// in a list of type substitutions. This does *not* traverse into nominal -/// types, nor does it resolve fictitious types. -pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, - ty: Ty) { - walk_ty(ty, |ty| { - match ty.sty { - TyRef(region, _) => { - accumulator.push(*region) - } - TyTrait(ref t) => { - accumulator.push_all(t.principal.0.substs.regions().as_slice()); - } - TyEnum(_, substs) | - TyStruct(_, substs) => { - accum_substs(accumulator, substs); - } - TyClosure(_, substs) => { - accum_substs(accumulator, substs); - } - TyBool | - TyChar | - TyInt(_) | - TyUint(_) | - TyFloat(_) | - TyBox(_) | - TyStr | - TyArray(_, _) | - TySlice(_) | - TyRawPtr(_) | - TyBareFn(..) | - TyTuple(_) | - TyProjection(_) | - TyParam(_) | - TyInfer(_) | - TyError => { - } - } - }); - - fn accum_substs(accumulator: &mut Vec, substs: &Substs) { - match substs.regions { - subst::ErasedRegions => {} - subst::NonerasedRegions(ref regions) => { - for region in regions { - accumulator.push(*region) - } - } - } - } -} - /// A free variable referred to in a function. #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct Freevar { @@ -7109,15 +6666,6 @@ pub type TraitMap = NodeMap>; // imported. pub type GlobMap = HashMap>; -pub fn with_freevars(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where - F: FnOnce(&[Freevar]) -> T, -{ - match tcx.freevars.borrow().get(&fid) { - None => f(&[]), - Some(d) => f(&d[..]) - } -} - impl<'tcx> AutoAdjustment<'tcx> { pub fn is_identity(&self) -> bool { match *self { @@ -7134,106 +6682,111 @@ impl<'tcx> AutoDerefRef<'tcx> { } } -/// Replace any late-bound regions bound in `value` with free variants attached to scope-id -/// `scope_id`. -pub fn liberate_late_bound_regions<'tcx, T>( - tcx: &ty::ctxt<'tcx>, - all_outlive_scope: region::DestructionScopeData, - value: &Binder) - -> T - where T : TypeFoldable<'tcx> -{ - ty_fold::replace_late_bound_regions( - tcx, value, - |br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0 -} - -pub fn count_late_bound_regions<'tcx, T>( - tcx: &ty::ctxt<'tcx>, - value: &Binder) - -> usize - where T : TypeFoldable<'tcx> -{ - let (_, skol_map) = ty_fold::replace_late_bound_regions(tcx, value, |_| ty::ReStatic); - skol_map.len() -} +impl<'tcx> ctxt<'tcx> { + pub fn with_freevars(&self, fid: ast::NodeId, f: F) -> T where + F: FnOnce(&[Freevar]) -> T, + { + match self.freevars.borrow().get(&fid) { + None => f(&[]), + Some(d) => f(&d[..]) + } + } -pub fn binds_late_bound_regions<'tcx, T>( - tcx: &ty::ctxt<'tcx>, - value: &Binder) - -> bool - where T : TypeFoldable<'tcx> -{ - count_late_bound_regions(tcx, value) > 0 -} + /// Replace any late-bound regions bound in `value` with free variants attached to scope-id + /// `scope_id`. + pub fn liberate_late_bound_regions(&self, + all_outlive_scope: region::DestructionScopeData, + value: &Binder) + -> T + where T : TypeFoldable<'tcx> + { + ty_fold::replace_late_bound_regions( + self, value, + |br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0 + } -/// Flattens two binding levels into one. So `for<'a> for<'b> Foo` -/// becomes `for<'a,'b> Foo`. -pub fn flatten_late_bound_regions<'tcx, T>( - tcx: &ty::ctxt<'tcx>, - bound2_value: &Binder>) - -> Binder - where T: TypeFoldable<'tcx> -{ - let bound0_value = bound2_value.skip_binder().skip_binder(); - let value = ty_fold::fold_regions(tcx, bound0_value, |region, current_depth| { - match region { - ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => { - // should be true if no escaping regions from bound2_value - assert!(debruijn.depth - current_depth <= 1); - ty::ReLateBound(DebruijnIndex::new(current_depth), br) - } - _ => { - region + /// Flattens two binding levels into one. So `for<'a> for<'b> Foo` + /// becomes `for<'a,'b> Foo`. + pub fn flatten_late_bound_regions(&self, bound2_value: &Binder>) + -> Binder + where T: TypeFoldable<'tcx> + { + let bound0_value = bound2_value.skip_binder().skip_binder(); + let value = ty_fold::fold_regions(self, bound0_value, &mut false, + |region, current_depth| { + match region { + ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => { + // should be true if no escaping regions from bound2_value + assert!(debruijn.depth - current_depth <= 1); + ty::ReLateBound(DebruijnIndex::new(current_depth), br) + } + _ => { + region + } } + }); + Binder(value) + } + + pub fn no_late_bound_regions(&self, value: &Binder) -> Option + where T : TypeFoldable<'tcx> + RegionEscape + { + if value.0.has_escaping_regions() { + None + } else { + Some(value.0.clone()) } - }); - Binder(value) -} + } -pub fn no_late_bound_regions<'tcx, T>( - tcx: &ty::ctxt<'tcx>, - value: &Binder) - -> Option - where T : TypeFoldable<'tcx> -{ - if binds_late_bound_regions(tcx, value) { - None - } else { - Some(value.0.clone()) + /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also + /// method lookup and a few other places where precise region relationships are not required. + pub fn erase_late_bound_regions(&self, value: &Binder) -> T + where T : TypeFoldable<'tcx> + { + ty_fold::replace_late_bound_regions(self, value, |_| ty::ReStatic).0 } -} -/// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also -/// method lookup and a few other places where precise region relationships are not required. -pub fn erase_late_bound_regions<'tcx, T>( - tcx: &ty::ctxt<'tcx>, - value: &Binder) - -> T - where T : TypeFoldable<'tcx> -{ - ty_fold::replace_late_bound_regions(tcx, value, |_| ty::ReStatic).0 -} + /// Rewrite any late-bound regions so that they are anonymous. Region numbers are + /// assigned starting at 1 and increasing monotonically in the order traversed + /// by the fold operation. + /// + /// The chief purpose of this function is to canonicalize regions so that two + /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become + /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and + /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization. + pub fn anonymize_late_bound_regions(&self, sig: &Binder) -> Binder + where T : TypeFoldable<'tcx>, + { + let mut counter = 0; + ty::Binder(ty_fold::replace_late_bound_regions(self, sig, |_| { + counter += 1; + ReLateBound(ty::DebruijnIndex::new(1), BrAnon(counter)) + }).0) + } -/// Rewrite any late-bound regions so that they are anonymous. Region numbers are -/// assigned starting at 1 and increasing monotonically in the order traversed -/// by the fold operation. -/// -/// The chief purpose of this function is to canonicalize regions so that two -/// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become -/// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and -/// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization. -pub fn anonymize_late_bound_regions<'tcx, T>( - tcx: &ctxt<'tcx>, - sig: &Binder) - -> Binder - where T : TypeFoldable<'tcx>, -{ - let mut counter = 0; - ty::Binder(ty_fold::replace_late_bound_regions(tcx, sig, |_| { - counter += 1; - ReLateBound(ty::DebruijnIndex::new(1), BrAnon(counter)) - }).0) + 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 = + method.generics.types.get_slice(subst::FnSpace) + .iter() + .map(|def| self.mk_param_from_def(def)) + .collect(); + let meth_regions: Vec = + 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) + } } impl DebruijnIndex { @@ -7290,83 +6843,33 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { } } -pub fn make_substs_for_receiver_types<'tcx>(tcx: &ty::ctxt<'tcx>, - 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 = - method.generics.types.get_slice(subst::FnSpace) - .iter() - .map(|def| ty::mk_param_from_def(tcx, def)) - .collect(); - let meth_regions: Vec = - 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) -} - -#[derive(Copy, Clone)] -pub enum CopyImplementationError { - FieldDoesNotImplementCopy(ast::Name), - VariantDoesNotImplementCopy(ast::Name), - TypeIsStructural, - TypeHasDestructor, -} - -pub fn can_type_implement_copy<'a,'tcx>(param_env: &ParameterEnvironment<'a, 'tcx>, - span: Span, - self_type: Ty<'tcx>) - -> Result<(),CopyImplementationError> -{ - let tcx = param_env.tcx; - - let did = match self_type.sty { - ty::TyStruct(struct_did, substs) => { - let fields = ty::struct_fields(tcx, struct_did, substs); - for field in &fields { - if type_moves_by_default(param_env, span, field.mt.ty) { - return Err(FieldDoesNotImplementCopy(field.name)) - } - } - struct_did - } - ty::TyEnum(enum_did, substs) => { - let enum_variants = ty::enum_variants(tcx, enum_did); - for variant in enum_variants.iter() { - for variant_arg_type in &variant.args { - let substd_arg_type = - variant_arg_type.subst(tcx, substs); - if type_moves_by_default(param_env, span, substd_arg_type) { - return Err(VariantDoesNotImplementCopy(variant.name)) - } - } - } - enum_did - } - _ => return Err(TypeIsStructural), - }; - - if ty::has_dtor(tcx, did) { - return Err(TypeHasDestructor) - } - - Ok(()) -} - -// FIXME(#20298) -- all of these types basically walk various +// FIXME(#20298) -- all of these traits basically walk various // structures to test whether types/regions are reachable with various // properties. It should be possible to express them in terms of one // common "walker" trait or something. +/// An "escaping region" is a bound region whose binder is not part of `t`. +/// +/// So, for example, consider a type like the following, which has two binders: +/// +/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope +/// +/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the +/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner +/// fn type*, that type has an escaping region: `'a`. +/// +/// Note that what I'm calling an "escaping region" is often just called a "free region". However, +/// we already use the term "free region". It refers to the regions that we use to represent bound +/// regions on a fn definition while we are typechecking its body. +/// +/// To clarify, conceptually there is no particular difference between an "escaping" region and a +/// "free" region. However, there is a big difference in practice. Basically, when "entering" a +/// binding level, one is generally required to do some sort of processing to a bound region, such +/// as replacing it with a fresh/skolemized region, or making an entry in the environment to +/// represent the scope to which it is attached, etc. An escaping region represents a bound region +/// for which this processing has not yet been done. pub trait RegionEscape { fn has_escaping_regions(&self) -> bool { self.has_regions_escaping_depth(0) @@ -7377,7 +6880,7 @@ pub trait RegionEscape { impl<'tcx> RegionEscape for Ty<'tcx> { fn has_regions_escaping_depth(&self, depth: u32) -> bool { - ty::type_escapes_depth(*self, depth) + self.region_depth > depth } } @@ -7388,6 +6891,19 @@ impl<'tcx> RegionEscape for Substs<'tcx> { } } +impl RegionEscape for Vec { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + self.iter().any(|t| t.has_regions_escaping_depth(depth)) + } +} + +impl<'tcx> RegionEscape for FnSig<'tcx> { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + self.inputs.has_regions_escaping_depth(depth) || + self.output.has_regions_escaping_depth(depth) + } +} + impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace { fn has_regions_escaping_depth(&self, depth: u32) -> bool { self.iter_enumerated().any(|(space, _, t)| { @@ -7460,6 +6976,15 @@ impl<'tcx,T:RegionEscape> RegionEscape for Binder { } } +impl<'tcx> RegionEscape for FnOutput<'tcx> { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + match *self { + FnConverging(t) => t.has_regions_escaping_depth(depth), + FnDiverging => false + } + } +} + impl<'tcx> RegionEscape for EquatePredicate<'tcx> { fn has_regions_escaping_depth(&self, depth: u32) -> bool { self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth) @@ -7491,237 +7016,221 @@ impl<'tcx> RegionEscape for ProjectionTy<'tcx> { } } -pub trait HasProjectionTypes { - fn has_projection_types(&self) -> bool; -} - -impl<'tcx,T:HasProjectionTypes> HasProjectionTypes for Vec { +pub trait HasTypeFlags { + fn has_type_flags(&self, flags: TypeFlags) -> bool; fn has_projection_types(&self) -> bool { - self.iter().any(|p| p.has_projection_types()) + self.has_type_flags(TypeFlags::HAS_PROJECTION) } -} - -impl<'tcx,T:HasProjectionTypes> HasProjectionTypes for VecPerParamSpace { - fn has_projection_types(&self) -> bool { - self.iter().any(|p| p.has_projection_types()) + fn references_error(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_ERR) } -} - -impl<'tcx> HasProjectionTypes for ClosureTy<'tcx> { - fn has_projection_types(&self) -> bool { - self.sig.has_projection_types() + fn has_param_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PARAMS) } -} - -impl<'tcx> HasProjectionTypes for ClosureUpvar<'tcx> { - fn has_projection_types(&self) -> bool { - self.ty.has_projection_types() + fn has_self_ty(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_SELF) } -} - -impl<'tcx> HasProjectionTypes for ty::InstantiatedPredicates<'tcx> { - fn has_projection_types(&self) -> bool { - self.predicates.has_projection_types() + fn has_infer_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INFER) } -} - -impl<'tcx> HasProjectionTypes for Predicate<'tcx> { - fn has_projection_types(&self) -> bool { - match *self { - Predicate::Trait(ref data) => data.has_projection_types(), - Predicate::Equate(ref data) => data.has_projection_types(), - Predicate::RegionOutlives(ref data) => data.has_projection_types(), - Predicate::TypeOutlives(ref data) => data.has_projection_types(), - Predicate::Projection(ref data) => data.has_projection_types(), - } + fn needs_infer(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) } -} - -impl<'tcx> HasProjectionTypes for TraitPredicate<'tcx> { - fn has_projection_types(&self) -> bool { - self.trait_ref.has_projection_types() + fn needs_subst(&self) -> bool { + self.has_type_flags(TypeFlags::NEEDS_SUBST) } -} - -impl<'tcx> HasProjectionTypes for EquatePredicate<'tcx> { - fn has_projection_types(&self) -> bool { - self.0.has_projection_types() || self.1.has_projection_types() + fn has_closure_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_CLOSURE) } -} - -impl HasProjectionTypes for Region { - fn has_projection_types(&self) -> bool { - false + fn has_erasable_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND | + TypeFlags::HAS_RE_INFER | + TypeFlags::HAS_FREE_REGIONS) } -} - -impl HasProjectionTypes for OutlivesPredicate { - fn has_projection_types(&self) -> bool { - self.0.has_projection_types() || self.1.has_projection_types() + /// Indicates whether this value references only 'global' + /// types/lifetimes that are the same regardless of what fn we are + /// in. This is used for caching. Errs on the side of returning + /// false. + fn is_global(&self) -> bool { + !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES) } } -impl<'tcx> HasProjectionTypes for ProjectionPredicate<'tcx> { - fn has_projection_types(&self) -> bool { - self.projection_ty.has_projection_types() || self.ty.has_projection_types() +impl<'tcx,T:HasTypeFlags> HasTypeFlags for Vec { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self[..].has_type_flags(flags) } } -impl<'tcx> HasProjectionTypes for ProjectionTy<'tcx> { - fn has_projection_types(&self) -> bool { - self.trait_ref.has_projection_types() +impl<'tcx,T:HasTypeFlags> HasTypeFlags for [T] { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.iter().any(|p| p.has_type_flags(flags)) } } -impl<'tcx> HasProjectionTypes for Ty<'tcx> { - fn has_projection_types(&self) -> bool { - ty::type_has_projection(*self) +impl<'tcx,T:HasTypeFlags> HasTypeFlags for VecPerParamSpace { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.iter().any(|p| p.has_type_flags(flags)) } } -impl<'tcx> HasProjectionTypes for TraitRef<'tcx> { - fn has_projection_types(&self) -> bool { - self.substs.has_projection_types() +impl<'tcx> HasTypeFlags for ClosureTy<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.sig.has_type_flags(flags) } } -impl<'tcx> HasProjectionTypes for subst::Substs<'tcx> { - fn has_projection_types(&self) -> bool { - self.types.iter().any(|t| t.has_projection_types()) +impl<'tcx> HasTypeFlags for ClosureUpvar<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.ty.has_type_flags(flags) } } -impl<'tcx,T> HasProjectionTypes for Option - where T : HasProjectionTypes -{ - fn has_projection_types(&self) -> bool { - self.iter().any(|t| t.has_projection_types()) +impl<'tcx> HasTypeFlags for ty::InstantiatedPredicates<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.predicates.has_type_flags(flags) } } -impl<'tcx,T> HasProjectionTypes for Rc - where T : HasProjectionTypes -{ - fn has_projection_types(&self) -> bool { - (**self).has_projection_types() +impl<'tcx> HasTypeFlags for Predicate<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + match *self { + Predicate::Trait(ref data) => data.has_type_flags(flags), + Predicate::Equate(ref data) => data.has_type_flags(flags), + Predicate::RegionOutlives(ref data) => data.has_type_flags(flags), + Predicate::TypeOutlives(ref data) => data.has_type_flags(flags), + Predicate::Projection(ref data) => data.has_type_flags(flags), + } } } -impl<'tcx,T> HasProjectionTypes for Box - where T : HasProjectionTypes -{ - fn has_projection_types(&self) -> bool { - (**self).has_projection_types() +impl<'tcx> HasTypeFlags for TraitPredicate<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.trait_ref.has_type_flags(flags) } } -impl HasProjectionTypes for Binder - where T : HasProjectionTypes -{ - fn has_projection_types(&self) -> bool { - self.0.has_projection_types() +impl<'tcx> HasTypeFlags for EquatePredicate<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.0.has_type_flags(flags) || self.1.has_type_flags(flags) } } -impl<'tcx> HasProjectionTypes for FnOutput<'tcx> { - fn has_projection_types(&self) -> bool { - match *self { - FnConverging(t) => t.has_projection_types(), - FnDiverging => false, +impl HasTypeFlags for Region { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + if flags.intersects(TypeFlags::HAS_LOCAL_NAMES) { + // does this represent a region that cannot be named in a global + // way? used in fulfillment caching. + match *self { + ty::ReStatic | ty::ReEmpty => {} + _ => return true + } } + if flags.intersects(TypeFlags::HAS_RE_INFER) { + if let ty::ReInfer(_) = *self { + return true; + } + } + false } } -impl<'tcx> HasProjectionTypes for FnSig<'tcx> { - fn has_projection_types(&self) -> bool { - self.inputs.iter().any(|t| t.has_projection_types()) || - self.output.has_projection_types() +impl HasTypeFlags for OutlivesPredicate { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.0.has_type_flags(flags) || self.1.has_type_flags(flags) } } -impl<'tcx> HasProjectionTypes for field<'tcx> { - fn has_projection_types(&self) -> bool { - self.mt.ty.has_projection_types() +impl<'tcx> HasTypeFlags for ProjectionPredicate<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.projection_ty.has_type_flags(flags) || self.ty.has_type_flags(flags) } } -impl<'tcx> HasProjectionTypes for BareFnTy<'tcx> { - fn has_projection_types(&self) -> bool { - self.sig.has_projection_types() +impl<'tcx> HasTypeFlags for ProjectionTy<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.trait_ref.has_type_flags(flags) } } -pub trait ReferencesError { - fn references_error(&self) -> bool; +impl<'tcx> HasTypeFlags for Ty<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.flags.get().intersects(flags) + } } -impl ReferencesError for Binder { - fn references_error(&self) -> bool { - self.0.references_error() +impl<'tcx> HasTypeFlags for TraitRef<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.substs.has_type_flags(flags) } } -impl ReferencesError for Rc { - fn references_error(&self) -> bool { - (&**self).references_error() +impl<'tcx> HasTypeFlags for subst::Substs<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.types.has_type_flags(flags) || match self.regions { + subst::ErasedRegions => false, + subst::NonerasedRegions(ref r) => r.has_type_flags(flags) + } } } -impl<'tcx> ReferencesError for TraitPredicate<'tcx> { - fn references_error(&self) -> bool { - self.trait_ref.references_error() +impl<'tcx,T> HasTypeFlags for Option + where T : HasTypeFlags +{ + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.iter().any(|t| t.has_type_flags(flags)) } } -impl<'tcx> ReferencesError for ProjectionPredicate<'tcx> { - fn references_error(&self) -> bool { - self.projection_ty.trait_ref.references_error() || self.ty.references_error() +impl<'tcx,T> HasTypeFlags for Rc + where T : HasTypeFlags +{ + fn has_type_flags(&self, flags: TypeFlags) -> bool { + (**self).has_type_flags(flags) } } -impl<'tcx> ReferencesError for TraitRef<'tcx> { - fn references_error(&self) -> bool { - self.input_types().iter().any(|t| t.references_error()) +impl<'tcx,T> HasTypeFlags for Box + where T : HasTypeFlags +{ + fn has_type_flags(&self, flags: TypeFlags) -> bool { + (**self).has_type_flags(flags) } } -impl<'tcx> ReferencesError for Ty<'tcx> { - fn references_error(&self) -> bool { - type_is_error(*self) +impl HasTypeFlags for Binder + where T : HasTypeFlags +{ + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.0.has_type_flags(flags) } } -impl<'tcx> ReferencesError for Predicate<'tcx> { - fn references_error(&self) -> bool { +impl<'tcx> HasTypeFlags for FnOutput<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { match *self { - Predicate::Trait(ref data) => data.references_error(), - Predicate::Equate(ref data) => data.references_error(), - Predicate::RegionOutlives(ref data) => data.references_error(), - Predicate::TypeOutlives(ref data) => data.references_error(), - Predicate::Projection(ref data) => data.references_error(), + FnConverging(t) => t.has_type_flags(flags), + FnDiverging => false, } } } -impl ReferencesError for OutlivesPredicate - where A : ReferencesError, B : ReferencesError -{ - fn references_error(&self) -> bool { - self.0.references_error() || self.1.references_error() +impl<'tcx> HasTypeFlags for FnSig<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.inputs.iter().any(|t| t.has_type_flags(flags)) || + self.output.has_type_flags(flags) } } -impl<'tcx> ReferencesError for EquatePredicate<'tcx> -{ - fn references_error(&self) -> bool { - self.0.references_error() || self.1.references_error() +impl<'tcx> HasTypeFlags for field<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.mt.ty.has_type_flags(flags) } } -impl ReferencesError for Region -{ - fn references_error(&self) -> bool { - false +impl<'tcx> HasTypeFlags for BareFnTy<'tcx> { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.sig.has_type_flags(flags) } } @@ -7764,6 +7273,7 @@ impl<'tcx> fmt::Debug for ObjectLifetimeDefault { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"), + ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"), ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r), } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index fe89ca751e7ce..7016c1484659b 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -36,7 +36,7 @@ use middle::subst; use middle::subst::VecPerParamSpace; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags, RegionEscape}; use middle::traits; use std::fmt; @@ -44,7 +44,7 @@ use std::rc::Rc; use syntax::abi; use syntax::ast; use syntax::owned_slice::OwnedSlice; -use util::nodemap::FnvHashMap; +use util::nodemap::{FnvHashMap, FnvHashSet}; /////////////////////////////////////////////////////////////////////////// // Two generic traits @@ -310,34 +310,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::MethodOrigin<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::MethodOrigin<'tcx> { - match *self { - ty::MethodStatic(def_id) => { - ty::MethodStatic(def_id) - } - ty::MethodStaticClosure(def_id) => { - ty::MethodStaticClosure(def_id) - } - ty::MethodTypeParam(ref param) => { - ty::MethodTypeParam(ty::MethodParam { - trait_ref: param.trait_ref.fold_with(folder), - method_num: param.method_num, - impl_def_id: param.impl_def_id, - }) - } - ty::MethodTraitObject(ref object) => { - ty::MethodTraitObject(ty::MethodObject { - trait_ref: object.trait_ref.fold_with(folder), - object_trait_id: object.object_trait_id, - method_num: object.method_num, - vtable_index: object.vtable_index, - }) - } - } - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds { fn fold_with>(&self, _folder: &mut F) -> ty::BuiltinBounds { *self @@ -369,6 +341,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault { ty::ObjectLifetimeDefault::Ambiguous => ty::ObjectLifetimeDefault::Ambiguous, + ty::ObjectLifetimeDefault::BaseDefault => + ty::ObjectLifetimeDefault::BaseDefault, + ty::ObjectLifetimeDefault::Specific(r) => ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)), } @@ -517,8 +492,8 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> { fn fold_with>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> { traits::VtableObjectData { - object_ty: self.object_ty.fold_with(folder), upcast_trait_ref: self.upcast_trait_ref.fold_with(folder), + vtable_base: self.vtable_base } } } @@ -641,7 +616,7 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, ty.sty.clone() } }; - ty::mk_t(this.tcx(), sty) + this.tcx().mk_ty(sty) } pub fn super_fold_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T, @@ -725,6 +700,7 @@ pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>( region_bound: bounds.region_bound.fold_with(this), builtin_bounds: bounds.builtin_bounds, projection_bounds: bounds.projection_bounds.fold_with(this), + region_bound_will_change: bounds.region_bound_will_change, } } @@ -783,38 +759,51 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where pub struct RegionFolder<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, + skipped_regions: &'a mut bool, current_depth: u32, fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a), } impl<'a, 'tcx> RegionFolder<'a, 'tcx> { - pub fn new(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionFolder<'a, 'tcx> + pub fn new(tcx: &'a ty::ctxt<'tcx>, + skipped_regions: &'a mut bool, + fld_r: &'a mut F) -> RegionFolder<'a, 'tcx> where F : FnMut(ty::Region, u32) -> ty::Region { RegionFolder { tcx: tcx, + skipped_regions: skipped_regions, current_depth: 1, fld_r: fld_r, } } } -pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec +/// Collects the free and escaping regions in `value` into `region_set`. Returns +/// whether any late-bound regions were skipped +pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, + value: &T, + region_set: &mut FnvHashSet) -> bool where T : TypeFoldable<'tcx> { - let mut vec = Vec::new(); - fold_regions(tcx, value, |r, _| { vec.push(r); r }); - vec + let mut have_bound_regions = false; + fold_regions(tcx, value, &mut have_bound_regions, + |r, d| { region_set.insert(r.from_depth(d)); r }); + have_bound_regions } +/// Folds the escaping and free regions in `value` using `f`, and +/// sets `skipped_regions` to true if any late-bound region was found +/// and skipped. pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>, value: &T, + skipped_regions: &mut bool, mut f: F) -> T where F : FnMut(ty::Region, u32) -> ty::Region, T : TypeFoldable<'tcx>, { - value.fold_with(&mut RegionFolder::new(tcx, &mut f)) + value.fold_with(&mut RegionFolder::new(tcx, skipped_regions, &mut f)) } impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> @@ -834,6 +823,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})", r, self.current_depth); + *self.skipped_regions = true; r } _ => { @@ -896,7 +886,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_escapes_depth(t, self.current_depth-1) { + if !t.has_regions_escaping_depth(self.current_depth-1) { return t; } @@ -946,7 +936,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_has_erasable_regions(t) { + if !t.has_erasable_regions() { return t; } @@ -989,7 +979,7 @@ pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>, debug!("shift_regions(value={:?}, amount={})", value, amount); - value.fold_with(&mut RegionFolder::new(tcx, &mut |region, _current_depth| { + value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { shift_region(region, amount) })) } diff --git a/src/librustc/middle/ty_match.rs b/src/librustc/middle/ty_match.rs index 135118820a771..5776235780a3a 100644 --- a/src/librustc/middle/ty_match.rs +++ b/src/librustc/middle/ty_match.rs @@ -42,6 +42,11 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> { fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.tcx } fn a_is_expected(&self) -> bool { true } // irrelevant + fn will_change(&mut self, _: bool, _: bool) -> bool { + // we're ignoring regions in this code + false + } + fn relate_with_variance>(&mut self, _: ty::Variance, a: &T, diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty_relate/mod.rs index b8c212fe3f20b..b8b2469b20667 100644 --- a/src/librustc/middle/ty_relate/mod.rs +++ b/src/librustc/middle/ty_relate/mod.rs @@ -22,6 +22,11 @@ use syntax::ast; pub type RelateResult<'tcx, T> = Result>; +#[derive(Clone, Debug)] +pub enum Cause { + ExistentialRegionBound(bool), // if true, this is a default, else explicit +} + pub trait TypeRelation<'a,'tcx> : Sized { fn tcx(&self) -> &'a ty::ctxt<'tcx>; @@ -32,6 +37,19 @@ pub trait TypeRelation<'a,'tcx> : Sized { /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; + fn with_cause(&mut self, _cause: Cause, f: F) -> R + where F: FnOnce(&mut Self) -> R + { + f(self) + } + + /// Hack for deciding whether the lifetime bound defaults change + /// will be a breaking change or not. The bools indicate whether + /// `a`/`b` have a default that will change to `'static`; the + /// result is true if this will potentially affect the affect of + /// relating `a` and `b`. + fn will_change(&mut self, a: bool, b: bool) -> bool; + /// Generic relation routine suitable for most anything. fn relate>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> { Relate::relate(self, a, b) @@ -113,7 +131,7 @@ fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R, let variances; let opt_variances = if relation.tcx().variance_computed.get() { - variances = ty::item_variances(relation.tcx(), item_def_id); + variances = relation.tcx().item_variances(item_def_id); Some(&*variances) } else { None @@ -366,14 +384,21 @@ impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ExistentialBounds<'tcx> { -> RelateResult<'tcx, ty::ExistentialBounds<'tcx>> where R: TypeRelation<'a,'tcx> { - let r = try!(relation.relate_with_variance(ty::Contravariant, - &a.region_bound, - &b.region_bound)); + let will_change = relation.will_change(a.region_bound_will_change, + b.region_bound_will_change); + + let r = + try!(relation.with_cause( + Cause::ExistentialRegionBound(will_change), + |relation| relation.relate_with_variance(ty::Contravariant, + &a.region_bound, + &b.region_bound))); let nb = try!(relation.relate(&a.builtin_bounds, &b.builtin_bounds)); let pb = try!(relation.relate(&a.projection_bounds, &b.projection_bounds)); Ok(ty::ExistentialBounds { region_bound: r, builtin_bounds: nb, - projection_bounds: pb }) + projection_bounds: pb, + region_bound_will_change: will_change }) } } @@ -469,21 +494,21 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, if a_id == b_id => { let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs)); - Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs))) + Ok(tcx.mk_enum(a_id, tcx.mk_substs(substs))) } (&ty::TyTrait(ref a_), &ty::TyTrait(ref b_)) => { let principal = try!(relation.relate(&a_.principal, &b_.principal)); let bounds = try!(relation.relate(&a_.bounds, &b_.bounds)); - Ok(ty::mk_trait(tcx, principal, bounds)) + Ok(tcx.mk_trait(principal, bounds)) } (&ty::TyStruct(a_id, a_substs), &ty::TyStruct(b_id, b_substs)) if a_id == b_id => { let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs)); - Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs))) + Ok(tcx.mk_struct(a_id, tcx.mk_substs(substs))) } (&ty::TyClosure(a_id, a_substs), @@ -494,33 +519,33 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, // the (anonymous) type of the same closure expression. So // all of their regions should be equated. let substs = try!(relate_substs(relation, None, a_substs, b_substs)); - Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs))) + Ok(tcx.mk_closure(a_id, tcx.mk_substs(substs))) } (&ty::TyBox(a_inner), &ty::TyBox(b_inner)) => { let typ = try!(relation.relate(&a_inner, &b_inner)); - Ok(ty::mk_uniq(tcx, typ)) + Ok(tcx.mk_box(typ)) } (&ty::TyRawPtr(ref a_mt), &ty::TyRawPtr(ref b_mt)) => { let mt = try!(relation.relate(a_mt, b_mt)); - Ok(ty::mk_ptr(tcx, mt)) + Ok(tcx.mk_ptr(mt)) } (&ty::TyRef(a_r, ref a_mt), &ty::TyRef(b_r, ref b_mt)) => { let r = try!(relation.relate_with_variance(ty::Contravariant, a_r, b_r)); let mt = try!(relation.relate(a_mt, b_mt)); - Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt)) + Ok(tcx.mk_ref(tcx.mk_region(r), mt)) } (&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) => { let t = try!(relation.relate(&a_t, &b_t)); if sz_a == sz_b { - Ok(ty::mk_vec(tcx, t, Some(sz_a))) + Ok(tcx.mk_array(t, sz_a)) } else { Err(ty::terr_fixed_array_size(expected_found(relation, &sz_a, &sz_b))) } @@ -529,7 +554,7 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, (&ty::TySlice(a_t), &ty::TySlice(b_t)) => { let t = try!(relation.relate(&a_t, &b_t)); - Ok(ty::mk_vec(tcx, t, None)) + Ok(tcx.mk_slice(t)) } (&ty::TyTuple(ref as_), &ty::TyTuple(ref bs)) => @@ -538,7 +563,7 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, let ts = try!(as_.iter().zip(bs) .map(|(a, b)| relation.relate(a, b)) .collect::>()); - Ok(ty::mk_tup(tcx, ts)) + Ok(tcx.mk_tup(ts)) } else if !(as_.is_empty() || bs.is_empty()) { Err(ty::terr_tuple_size( expected_found(relation, &as_.len(), &bs.len()))) @@ -551,13 +576,13 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, if a_opt_def_id == b_opt_def_id => { let fty = try!(relation.relate(a_fty, b_fty)); - Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty))) + Ok(tcx.mk_fn(a_opt_def_id, tcx.mk_bare_fn(fty))) } (&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) => { let projection_ty = try!(relation.relate(a_data, b_data)); - Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name)) + Ok(tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name)) } _ => diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty_walk.rs index b34eb2ddb1e91..3e9a402f9499c 100644 --- a/src/librustc/middle/ty_walk.rs +++ b/src/librustc/middle/ty_walk.rs @@ -9,6 +9,7 @@ // except according to those terms. //! An iterator over the type substructure. +//! WARNING: this does not keep track of the region depth. use middle::ty::{self, Ty}; use std::iter::Iterator; diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 8d5357fa6e417..162bf6ed9a97f 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -59,14 +59,50 @@ pub fn time(do_it: bool, what: &str, u: U, f: F) -> T where const NANOS_PER_SEC: f64 = 1_000_000_000.0; let secs = dur.secs() as f64; let secs = secs + dur.extra_nanos() as f64 / NANOS_PER_SEC; - println!("{}time: {:.3} \t{}", repeat(" ").take(old).collect::(), - secs, what); + + let mem_string = match get_resident() { + Some(n) => { + let mb = n as f64 / 1_000_000.0; + format!("; rss: {}MB", mb.round() as usize) + } + None => "".to_owned(), + }; + println!("{}time: {:.3}{}\t{}", repeat(" ").take(old).collect::(), + secs, mem_string, what); DEPTH.with(|slot| slot.set(old)); rv } +// Memory reporting +fn get_resident() -> Option { + if cfg!(unix) { + get_proc_self_statm_field(1) + } else { + None + } +} + +// Like std::macros::try!, but for Option<>. +macro_rules! option_try( + ($e:expr) => (match $e { Some(e) => e, None => return None }) +); + +fn get_proc_self_statm_field(field: usize) -> Option { + use std::fs::File; + use std::io::Read; + + assert!(cfg!(unix)); + + let mut f = option_try!(File::open("/proc/self/statm").ok()); + let mut contents = String::new(); + option_try!(f.read_to_string(&mut contents).ok()); + let s = option_try!(contents.split_whitespace().nth(field)); + let npages = option_try!(s.parse::().ok()); + Some(npages * ::std::env::page_size()) +} + pub fn indent(op: F) -> R where R: Debug, F: FnOnce() -> R, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0ae089df50dd2..9d82b0c2aa8a0 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -14,13 +14,12 @@ use middle::ty::{BoundRegion, BrAnon, BrNamed}; use middle::ty::{ReEarlyBound, BrFresh, ctxt}; use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty}; use middle::ty::{ReSkolemized, ReVar, BrEnv}; -use middle::ty::{mt, Ty}; use middle::ty::{TyBool, TyChar, TyStruct, TyEnum}; use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyBareFn}; use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple}; use middle::ty::TyClosure; use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer}; -use middle::ty; +use middle::ty::{self, mt, Ty, HasTypeFlags}; use middle::ty_fold::{self, TypeFoldable}; use std::fmt; @@ -52,7 +51,7 @@ fn fn_sig(f: &mut fmt::Formatter, match output { ty::FnConverging(ty) => { - if !ty::type_is_nil(ty) { + if !ty.is_nil() { try!(write!(f, " -> {}", ty)); } Ok(()) @@ -72,7 +71,7 @@ fn parameterized(f: &mut fmt::Formatter, where GG: for<'tcx> FnOnce(&ty::ctxt<'tcx>) -> ty::Generics<'tcx> { let (fn_trait_kind, verbose) = try!(ty::tls::with(|tcx| { - try!(write!(f, "{}", ty::item_path_str(tcx, did))); + try!(write!(f, "{}", tcx.item_path_str(did))); Ok((tcx.lang_items.fn_trait_kind(did), tcx.sess.verbose())) })); @@ -155,7 +154,7 @@ fn parameterized(f: &mut fmt::Formatter, ty_params.iter().zip(tps).rev().take_while(|&(def, &actual)| { match def.default { Some(default) => { - if !has_self && ty::type_has_self(default) { + if !has_self && default.has_self_ty() { // In an object type, there is no `Self`, and // thus if the default value references Self, // the user will be required to give an @@ -266,7 +265,7 @@ impl<'tcx> fmt::Display for TraitAndProjections<'tcx> { parameterized(f, trait_ref.substs, trait_ref.def_id, projection_bounds, - |tcx| ty::lookup_trait_def(tcx, trait_ref.def_id).generics.clone()) + |tcx| tcx.lookup_trait_def(trait_ref.def_id).generics.clone()) } } @@ -291,13 +290,18 @@ impl<'tcx> fmt::Display for ty::TraitTy<'tcx> { try!(write!(f, " + {:?}", bound)); } - // Region, if not obviously implied by builtin bounds. - if bounds.region_bound != ty::ReStatic { - // Region bound is implied by builtin bounds: - let bound = bounds.region_bound.to_string(); - if !bound.is_empty() { - try!(write!(f, " + {}", bound)); - } + // FIXME: It'd be nice to compute from context when this bound + // is implied, but that's non-trivial -- we'd perhaps have to + // use thread-local data of some kind? There are also + // advantages to just showing the region, since it makes + // people aware that it's there. + let bound = bounds.region_bound.to_string(); + if !bound.is_empty() { + try!(write!(f, " + {}", bound)); + } + + if bounds.region_bound_will_change && verbose() { + try!(write!(f, " [WILL-CHANGE]")); } Ok(()) @@ -490,38 +494,6 @@ impl<'tcx> fmt::Display for ty::FnSig<'tcx> { } } -impl<'tcx> fmt::Debug for ty::MethodOrigin<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ty::MethodStatic(def_id) => { - write!(f, "MethodStatic({:?})", def_id) - } - ty::MethodStaticClosure(def_id) => { - write!(f, "MethodStaticClosure({:?})", def_id) - } - ty::MethodTypeParam(ref p) => write!(f, "{:?}", p), - ty::MethodTraitObject(ref p) => write!(f, "{:?}", p) - } - } -} - -impl<'tcx> fmt::Debug for ty::MethodParam<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "MethodParam({:?},{})", - self.trait_ref, - self.method_num) - } -} - -impl<'tcx> fmt::Debug for ty::MethodObject<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "MethodObject({:?},{},{})", - self.trait_ref, - self.method_num, - self.vtable_index) - } -} - impl<'tcx> fmt::Debug for ty::ExistentialBounds<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut empty = true; @@ -617,7 +589,7 @@ impl fmt::Display for ty::Binder> impl<'tcx> fmt::Display for ty::TraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { parameterized(f, self.substs, self.def_id, &[], - |tcx| ty::lookup_trait_def(tcx, self.def_id).generics.clone()) + |tcx| tcx.lookup_trait_def(self.def_id).generics.clone()) } } @@ -672,7 +644,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { if let Some(def_id) = opt_def_id { try!(write!(f, " {{{}}}", ty::tls::with(|tcx| { - ty::item_path_str(tcx, def_id) + tcx.item_path_str(def_id) }))); } Ok(()) @@ -681,15 +653,22 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyError => write!(f, "[type error]"), TyParam(ref param_ty) => write!(f, "{}", param_ty), TyEnum(did, substs) | TyStruct(did, substs) => { - parameterized(f, substs, did, &[], - |tcx| ty::lookup_item_type(tcx, did).generics) + ty::tls::with(|tcx| { + if did.krate == ast::LOCAL_CRATE && + !tcx.tcache.borrow().contains_key(&did) { + write!(f, "{}<..>", tcx.item_path_str(did)) + } else { + parameterized(f, substs, did, &[], + |tcx| tcx.lookup_item_type(did).generics) + } + }) } TyTrait(ref data) => write!(f, "{}", data), ty::TyProjection(ref data) => write!(f, "{}", data), TyStr => write!(f, "str"), TyClosure(ref did, substs) => ty::tls::with(|tcx| { try!(write!(f, "[closure")); - let closure_tys = tcx.closure_tys.borrow(); + let closure_tys = &tcx.tables.borrow().closure_tys; try!(closure_tys.get(did).map(|cty| &cty.sig).and_then(|sig| { tcx.lift(&substs).map(|substs| sig.subst(tcx, substs)) }).map(|sig| { @@ -721,7 +700,7 @@ impl fmt::Debug for ty::UpvarId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "UpvarId({};`{}`;{})", self.var_id, - ty::tls::with(|tcx| ty::local_var_name_str(tcx, self.var_id)), + ty::tls::with(|tcx| tcx.local_var_name_str(self.var_id)), self.closure_expr_id) } } diff --git a/src/librustc_back/arm.rs b/src/librustc_back/arm.rs index 7325e4e7a2ece..9e288f6ddb2bf 100644 --- a/src/librustc_back/arm.rs +++ b/src/librustc_back/arm.rs @@ -61,7 +61,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -a:0:64-n32".to_string() } - abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd => { + abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd | abi::OsNetbsd => { "e-p:32:32:32\ -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ diff --git a/src/librustc_back/mips.rs b/src/librustc_back/mips.rs index b46150f75d084..e1edff817d6c1 100644 --- a/src/librustc_back/mips.rs +++ b/src/librustc_back/mips.rs @@ -56,7 +56,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -a:0:64-n32".to_string() } - abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd => { + abi::OsBitrig | abi::OsDragonfly | abi::OsFreebsd | abi::OsNetbsd | abi::OsOpenbsd => { "E-p:32:32:32\ -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ diff --git a/src/librustc_back/mipsel.rs b/src/librustc_back/mipsel.rs index c7fa7aa879ac2..ca52a9e56ff52 100644 --- a/src/librustc_back/mipsel.rs +++ b/src/librustc_back/mipsel.rs @@ -56,7 +56,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -a:0:64-n32".to_string() } - abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd => { + abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd | abi::OsNetbsd => { "e-p:32:32:32\ -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ diff --git a/src/librustc_back/target/i686_pc_windows_msvc.rs b/src/librustc_back/target/i686_pc_windows_msvc.rs new file mode 100644 index 0000000000000..d71aa1526660e --- /dev/null +++ b/src/librustc_back/target/i686_pc_windows_msvc.rs @@ -0,0 +1,27 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::Target; + +pub fn target() -> Target { + let mut base = super::windows_msvc_base::opts(); + base.cpu = "i686".to_string(); + + Target { + data_layout: "e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32".to_string(), + llvm_target: "i686-pc-windows-msvc".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + arch: "x86".to_string(), + target_os: "windows".to_string(), + target_env: "msvc".to_string(), + options: base, + } +} diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 402fbcd8d8d8e..bc5f306cd3568 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -58,6 +58,7 @@ mod dragonfly_base; mod freebsd_base; mod linux_base; mod openbsd_base; +mod netbsd_base; mod windows_base; mod windows_msvc_base; @@ -368,6 +369,7 @@ impl Target { x86_64_unknown_bitrig, x86_64_unknown_openbsd, + x86_64_unknown_netbsd, x86_64_apple_darwin, i686_apple_darwin, @@ -381,7 +383,8 @@ impl Target { x86_64_pc_windows_gnu, i686_pc_windows_gnu, - x86_64_pc_windows_msvc + x86_64_pc_windows_msvc, + i686_pc_windows_msvc ); diff --git a/src/librustc_back/target/netbsd_base.rs b/src/librustc_back/target/netbsd_base.rs new file mode 100644 index 0000000000000..0f2ab32be2431 --- /dev/null +++ b/src/librustc_back/target/netbsd_base.rs @@ -0,0 +1,32 @@ +// Copyright 2014-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::TargetOptions; +use std::default::Default; + +pub fn opts() -> TargetOptions { + TargetOptions { + linker: "cc".to_string(), + dynamic_linking: true, + executables: true, + morestack: false, + linker_is_gnu: true, + has_rpath: true, + pre_link_args: vec!( + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + ), + position_independent_executables: true, + .. Default::default() + } +} diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs new file mode 100644 index 0000000000000..3f5bd39949ab6 --- /dev/null +++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs @@ -0,0 +1,29 @@ +// Copyright 2014-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::Target; + +pub fn target() -> Target { + let mut base = super::netbsd_base::opts(); + base.pre_link_args.push("-m64".to_string()); + + Target { + data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ + s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(), + llvm_target: "x86_64-unknown-netbsd".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + arch: "x86_64".to_string(), + target_os: "netbsd".to_string(), + target_env: "".to_string(), + options: base, + } +} diff --git a/src/librustc_back/x86.rs b/src/librustc_back/x86.rs index 1c6eacc355947..46e0a83ac033b 100644 --- a/src/librustc_back/x86.rs +++ b/src/librustc_back/x86.rs @@ -45,7 +45,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string() } - abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd => { + abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd | abi::OsNetbsd => { "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string() } diff --git a/src/librustc_back/x86_64.rs b/src/librustc_back/x86_64.rs index d016bd12c698f..abdcd56444213 100644 --- a/src/librustc_back/x86_64.rs +++ b/src/librustc_back/x86_64.rs @@ -47,7 +47,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs s0:64:64-f80:128:128-n8:16:32:64-S128".to_string() } - abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd => { + abi::OsBitrig | abi::OsDragonfly | abi::OsFreebsd | abi::OsNetbsd | abi::OsOpenbsd => { "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string() diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 49933441cf01e..1be2b605dbdcc 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -21,6 +21,7 @@ use self::UseError::*; use borrowck::*; use borrowck::InteriorKind::{InteriorElement, InteriorField}; use rustc::middle::expr_use_visitor as euv; +use rustc::middle::infer; use rustc::middle::mem_categorization as mc; use rustc::middle::region; use rustc::middle::ty; @@ -182,7 +183,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { None => { } } - self.check_assignment(assignment_id, assignment_span, assignee_cmt, mode); + self.check_assignment(assignment_id, assignment_span, assignee_cmt); } fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) { } @@ -198,17 +199,18 @@ 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), false); let mut clcx = CheckLoanCtxt { bccx: bccx, dfcx_loans: dfcx_loans, move_data: move_data, all_loans: all_loans, - param_env: ¶m_env, + param_env: &infcx.parameter_environment }; { - let mut euv = euv::ExprUseVisitor::new(&mut clcx, ¶m_env); + let mut euv = euv::ExprUseVisitor::new(&mut clcx, &infcx); euv.walk_fn(decl, body); } } @@ -565,13 +567,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { true } - fn is_local_variable_or_arg(&self, cmt: mc::cmt<'tcx>) -> bool { - match cmt.cat { - mc::cat_local(_) => true, - _ => false - } - } - fn consume_common(&self, id: ast::NodeId, span: Span, @@ -752,7 +747,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => { match lp_base.to_type().sty { ty::TyStruct(def_id, _) | ty::TyEnum(def_id, _) => { - if ty::has_dtor(self.tcx(), def_id) { + if self.tcx().has_dtor(def_id) { // In the case where the owner implements drop, then // the path must be initialized to prevent a case of // partial reinitialization @@ -789,202 +784,35 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { fn check_assignment(&self, assignment_id: ast::NodeId, assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>, - mode: euv::MutateMode) { + assignee_cmt: mc::cmt<'tcx>) { debug!("check_assignment(assignee_cmt={:?})", assignee_cmt); - // Mutable values can be assigned, as long as they obey loans - // and aliasing restrictions: - if assignee_cmt.mutbl.is_mutable() { - if check_for_aliasable_mutable_writes(self, assignment_span, assignee_cmt.clone()) { - if mode != euv::Init { - check_for_assignment_to_borrowed_path( - self, assignment_id, assignment_span, assignee_cmt.clone()); - mark_variable_as_used_mut(self, assignee_cmt); - } - } - - return; - } - - // Initializations are OK if and only if they aren't partial - // reinitialization of a partially-uninitialized structure. - if mode == euv::Init { - return - } - - // For immutable local variables, assignments are legal - // if they cannot already have been assigned - if self.is_local_variable_or_arg(assignee_cmt.clone()) { - assert!(assignee_cmt.mutbl.is_immutable()); // no "const" locals - let lp = opt_loan_path(&assignee_cmt).unwrap(); - self.move_data.each_assignment_of(assignment_id, &lp, |assign| { - self.bccx.report_reassigned_immutable_variable( - assignment_span, - &*lp, - assign); + // Check that we don't invalidate any outstanding loans + if let Some(loan_path) = opt_loan_path(&assignee_cmt) { + let scope = region::CodeExtent::from_node_id(assignment_id); + self.each_in_scope_loan_affecting_path(scope, &*loan_path, |loan| { + self.report_illegal_mutation(assignment_span, &*loan_path, loan); false }); - return; } - // Otherwise, just a plain error. - match assignee_cmt.note { - mc::NoteClosureEnv(upvar_id) => { - // If this is an `Fn` closure, it simply can't mutate upvars. - // If it's an `FnMut` closure, the original variable was declared immutable. - // We need to determine which is the case here. - let kind = match assignee_cmt.upvar().unwrap().cat { - mc::cat_upvar(mc::Upvar { kind, .. }) => kind, - _ => unreachable!() - }; - if kind == ty::FnClosureKind { - self.bccx.span_err( - assignment_span, - &format!("cannot assign to {}", - self.bccx.cmt_to_string(&*assignee_cmt))); - self.bccx.span_help( - self.tcx().map.span(upvar_id.closure_expr_id), - "consider changing this closure to take self by mutable reference"); + // Check for reassignments to (immutable) local variables. This + // needs to be done here instead of in check_loans because we + // depend on move data. + if let mc::cat_local(local_id) = assignee_cmt.cat { + let lp = opt_loan_path(&assignee_cmt).unwrap(); + self.move_data.each_assignment_of(assignment_id, &lp, |assign| { + if assignee_cmt.mutbl.is_mutable() { + self.tcx().used_mut_nodes.borrow_mut().insert(local_id); } else { - self.bccx.span_err( + self.bccx.report_reassigned_immutable_variable( assignment_span, - &format!("cannot assign to {} {}", - assignee_cmt.mutbl.to_user_str(), - self.bccx.cmt_to_string(&*assignee_cmt))); - } - } - _ => match opt_loan_path(&assignee_cmt) { - Some(lp) => { - self.bccx.span_err( - assignment_span, - &format!("cannot assign to {} {} `{}`", - assignee_cmt.mutbl.to_user_str(), - self.bccx.cmt_to_string(&*assignee_cmt), - self.bccx.loan_path_to_string(&*lp))); - } - None => { - self.bccx.span_err( - assignment_span, - &format!("cannot assign to {} {}", - assignee_cmt.mutbl.to_user_str(), - self.bccx.cmt_to_string(&*assignee_cmt))); - } - } - } - return; - - fn mark_variable_as_used_mut<'a, 'tcx>(this: &CheckLoanCtxt<'a, 'tcx>, - mut cmt: mc::cmt<'tcx>) { - //! If the mutability of the `cmt` being written is inherited - //! from a local variable, liveness will - //! not have been able to detect that this variable's mutability - //! is important, so we must add the variable to the - //! `used_mut_nodes` table here. - - loop { - debug!("mark_variable_as_used_mut(cmt={:?})", cmt); - match cmt.cat.clone() { - mc::cat_upvar(mc::Upvar { id: ty::UpvarId { var_id: id, .. }, .. }) | - mc::cat_local(id) => { - this.tcx().used_mut_nodes.borrow_mut().insert(id); - return; - } - - mc::cat_rvalue(..) | - mc::cat_static_item | - mc::cat_deref(_, _, mc::UnsafePtr(..)) | - mc::cat_deref(_, _, mc::Implicit(..)) => { - assert_eq!(cmt.mutbl, mc::McDeclared); - return; - } - - mc::cat_deref(_, _, mc::BorrowedPtr(..)) => { - assert_eq!(cmt.mutbl, mc::McDeclared); - // We need to drill down to upvar if applicable - match cmt.upvar() { - Some(b) => cmt = b, - None => return - } - } - - mc::cat_deref(b, _, mc::Unique) => { - assert_eq!(cmt.mutbl, mc::McInherited); - cmt = b; - } - - mc::cat_downcast(b, _) | - mc::cat_interior(b, _) => { - assert_eq!(cmt.mutbl, mc::McInherited); - cmt = b; - } - } - } - } - - fn check_for_aliasable_mutable_writes<'a, 'tcx>(this: &CheckLoanCtxt<'a, 'tcx>, - span: Span, - cmt: mc::cmt<'tcx>) -> bool { - //! Safety checks related to writes to aliasable, mutable locations - - let guarantor = cmt.guarantor(); - debug!("check_for_aliasable_mutable_writes(cmt={:?}, guarantor={:?})", - cmt, guarantor); - if let mc::cat_deref(ref b, _, mc::BorrowedPtr(ty::MutBorrow, _)) = guarantor.cat { - // Statically prohibit writes to `&mut` when aliasable - check_for_aliasability_violation(this, span, b.clone()); - } - - return true; // no errors reported - } - - fn check_for_aliasability_violation<'a, 'tcx>(this: &CheckLoanCtxt<'a, 'tcx>, - span: Span, - cmt: mc::cmt<'tcx>) - -> bool { - match cmt.freely_aliasable(this.tcx()) { - mc::Aliasability::NonAliasable => { - return true; - } - mc::Aliasability::FreelyAliasable(mc::AliasableStaticMut(..)) => { - return true; - } - mc::Aliasability::ImmutableUnique(_) => { - this.bccx.report_aliasability_violation( - span, - MutabilityViolation, - mc::AliasableReason::UnaliasableImmutable); - return false; - } - mc::Aliasability::FreelyAliasable(cause) => { - this.bccx.report_aliasability_violation( - span, - MutabilityViolation, - cause); - return false; + &*lp, + assign); } - } - } - - fn check_for_assignment_to_borrowed_path<'a, 'tcx>( - this: &CheckLoanCtxt<'a, 'tcx>, - assignment_id: ast::NodeId, - assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>) - { - //! Check for assignments that violate the terms of an - //! outstanding loan. - - let loan_path = match opt_loan_path(&assignee_cmt) { - Some(lp) => lp, - None => { return; /* no loan path, can't be any loans */ } - }; - - let scope = region::CodeExtent::from_node_id(assignment_id); - this.each_in_scope_loan_affecting_path(scope, &*loan_path, |loan| { - this.report_illegal_mutation(assignment_span, &*loan_path, loan); false }); + return } } diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 93f5ac529d3fd..9bd4da28c99fb 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -353,7 +353,7 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>, } (&ty::TyStruct(def_id, ref _substs), None) => { - let fields = ty::lookup_struct_fields(tcx, def_id); + let fields = tcx.lookup_struct_fields(def_id); match *origin_field_name { mc::NamedField(ast_name) => { for f in &fields { @@ -378,7 +378,7 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>, (&ty::TyEnum(enum_def_id, substs), ref enum_variant_info) => { let variant_info = { - let mut variants = ty::substd_enum_variants(tcx, enum_def_id, substs); + let mut variants = tcx.substd_enum_variants(enum_def_id, substs); match *enum_variant_info { Some((variant_def_id, ref _lp2)) => variants.iter() @@ -442,9 +442,9 @@ fn add_fragment_sibling_core<'tcx>(this: &MoveData<'tcx>, let loan_path_elem = LpInterior(InteriorField(new_field_name)); let new_lp_type = match new_field_name { mc::NamedField(ast_name) => - ty::named_element_ty(tcx, parent.to_type(), ast_name, opt_variant_did), + tcx.named_element_ty(parent.to_type(), ast_name, opt_variant_did), mc::PositionalField(idx) => - ty::positional_element_ty(tcx, parent.to_type(), idx, opt_variant_did), + tcx.positional_element_ty(parent.to_type(), idx, opt_variant_did), }; let new_lp_variant = LpExtend(parent, mc, loan_path_elem); let new_lp = LoanPath::new(new_lp_variant, new_lp_type.unwrap()); diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 7b6c54dbaca44..2b33dde2cbe2d 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -35,7 +35,7 @@ pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, decl_id: ast::NodeId, _decl_span: Span, var_id: ast::NodeId) { - let ty = ty::node_id_to_type(bccx.tcx, var_id); + let ty = bccx.tcx.node_id_to_type(var_id); let loan_path = Rc::new(LoanPath::new(LpVar(var_id), ty)); move_data.add_move(bccx.tcx, loan_path, decl_id, Declared); } @@ -180,7 +180,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, mc::cat_interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { match b.ty.sty { ty::TyStruct(did, _) | ty::TyEnum(did, _) => { - if ty::has_dtor(bccx.tcx, did) { + if bccx.tcx.has_dtor(did) { Some(cmt.clone()) } else { check_and_get_illegal_move_origin(bccx, b) diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 427d78e89b3e2..919bc45f00ddf 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -137,7 +137,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { fn report_error(&self, code: bckerr_code) { self.bccx.report(BckError { cmt: self.cmt_original.clone(), span: self.span, - cause: self.cause, + cause: BorrowViolation(self.cause), code: code }); } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index f00eb872642f4..6899892a245ed 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -19,6 +19,7 @@ use borrowck::*; use borrowck::move_data::MoveData; use rustc::middle::expr_use_visitor as euv; +use rustc::middle::infer; use rustc::middle::mem_categorization as mc; use rustc::middle::region; use rustc::middle::ty; @@ -49,9 +50,9 @@ 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), false); { - let mut euv = euv::ExprUseVisitor::new(&mut glcx, ¶m_env); + let mut euv = euv::ExprUseVisitor::new(&mut glcx, &infcx); euv.walk_fn(decl, body); } @@ -151,22 +152,10 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { assignee_cmt: mc::cmt<'tcx>, mode: euv::MutateMode) { - let opt_lp = opt_loan_path(&assignee_cmt); - debug!("mutate(assignment_id={}, assignee_cmt={:?}) opt_lp={:?}", - assignment_id, assignee_cmt, opt_lp); - - match opt_lp { - Some(lp) => { - gather_moves::gather_assignment(self.bccx, &self.move_data, - assignment_id, assignment_span, - lp, assignee_cmt.id, mode); - } - None => { - // This can occur with e.g. `*foo() = 5`. In such - // cases, there is no need to check for conflicts - // with moves etc, just ignore. - } - } + self.guarantee_assignment_valid(assignment_id, + assignment_span, + assignee_cmt, + mode); } fn decl_without_init(&mut self, id: ast::NodeId, span: Span) { @@ -177,7 +166,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { /// Implements the A-* rules in README.md. fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, borrow_span: Span, - loan_cause: euv::LoanCause, + loan_cause: AliasableViolationKind, cmt: mc::cmt<'tcx>, req_kind: ty::BorrowKind) -> Result<(),()> { @@ -203,7 +192,7 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, (mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => { bccx.report_aliasability_violation( borrow_span, - BorrowViolation(loan_cause), + loan_cause, mc::AliasableReason::UnaliasableImmutable); Err(()) } @@ -211,7 +200,7 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, (mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => { bccx.report_aliasability_violation( borrow_span, - BorrowViolation(loan_cause), + loan_cause, alias_cause); Err(()) } @@ -221,9 +210,94 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, } } +/// Implements the M-* rules in README.md. +fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, + borrow_span: Span, + cause: AliasableViolationKind, + cmt: mc::cmt<'tcx>, + req_kind: ty::BorrowKind) + -> Result<(),()> { + debug!("check_mutability(cause={:?} cmt={:?} req_kind={:?}", + cause, cmt, req_kind); + match req_kind { + ty::UniqueImmBorrow | ty::ImmBorrow => { + match cmt.mutbl { + // I am intentionally leaving this here to help + // refactoring if, in the future, we should add new + // kinds of mutability. + mc::McImmutable | mc::McDeclared | mc::McInherited => { + // both imm and mut data can be lent as imm; + // for mutable data, this is a freeze + Ok(()) + } + } + } + + ty::MutBorrow => { + // Only mutable data can be lent as mutable. + if !cmt.mutbl.is_mutable() { + Err(bccx.report(BckError { span: borrow_span, + cause: cause, + cmt: cmt, + code: err_mutbl })) + } else { + Ok(()) + } + } + } +} + impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.bccx.tcx } + /// Guarantees that `cmt` is assignable, or reports an error. + fn guarantee_assignment_valid(&mut self, + assignment_id: ast::NodeId, + assignment_span: Span, + cmt: mc::cmt<'tcx>, + mode: euv::MutateMode) { + + let opt_lp = opt_loan_path(&cmt); + debug!("guarantee_assignment_valid(assignment_id={}, cmt={:?}) opt_lp={:?}", + assignment_id, cmt, opt_lp); + + if let mc::cat_local(..) = cmt.cat { + // Only re-assignments to locals require it to be + // mutable - this is checked in check_loans. + } else { + // Check that we don't allow assignments to non-mutable data. + if check_mutability(self.bccx, assignment_span, MutabilityViolation, + cmt.clone(), ty::MutBorrow).is_err() { + return; // reported an error, no sense in reporting more. + } + } + + // Check that we don't allow assignments to aliasable data + if check_aliasability(self.bccx, assignment_span, MutabilityViolation, + cmt.clone(), ty::MutBorrow).is_err() { + return; // reported an error, no sense in reporting more. + } + + match opt_lp { + Some(lp) => { + if let mc::cat_local(..) = cmt.cat { + // Only re-assignments to locals require it to be + // mutable - this is checked in check_loans. + } else { + self.mark_loan_path_as_mutated(&lp); + } + gather_moves::gather_assignment(self.bccx, &self.move_data, + assignment_id, assignment_span, + lp, cmt.id, mode); + } + None => { + // This can occur with e.g. `*foo() = 5`. In such + // cases, there is no need to check for conflicts + // with moves etc, just ignore. + } + } + } + /// Guarantees that `addr_of(cmt)` will be valid for the duration of `static_scope_r`, or /// reports an error. This may entail taking out loans, which will be added to the /// `req_loan_map`. @@ -256,13 +330,13 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } // Check that we don't allow mutable borrows of non-mutable data. - if check_mutability(self.bccx, borrow_span, cause, + if check_mutability(self.bccx, borrow_span, BorrowViolation(cause), cmt.clone(), req_kind).is_err() { return; // reported an error, no sense in reporting more. } // Check that we don't allow mutable borrows of aliasable data. - if check_aliasability(self.bccx, borrow_span, cause, + if check_aliasability(self.bccx, borrow_span, BorrowViolation(cause), cmt.clone(), req_kind).is_err() { return; // reported an error, no sense in reporting more. } @@ -368,43 +442,6 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { // restrictions: restrictions // } // } - - fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - borrow_span: Span, - cause: euv::LoanCause, - cmt: mc::cmt<'tcx>, - req_kind: ty::BorrowKind) - -> Result<(),()> { - //! Implements the M-* rules in README.md. - debug!("check_mutability(cause={:?} cmt={:?} req_kind={:?}", - cause, cmt, req_kind); - match req_kind { - ty::UniqueImmBorrow | ty::ImmBorrow => { - match cmt.mutbl { - // I am intentionally leaving this here to help - // refactoring if, in the future, we should add new - // kinds of mutability. - mc::McImmutable | mc::McDeclared | mc::McInherited => { - // both imm and mut data can be lent as imm; - // for mutable data, this is a freeze - Ok(()) - } - } - } - - ty::MutBorrow => { - // Only mutable data can be lent as mutable. - if !cmt.mutbl.is_mutable() { - Err(bccx.report(BckError { span: borrow_span, - cause: cause, - cmt: cmt, - code: err_mutbl })) - } else { - Ok(()) - } - } - } - } } pub fn mark_loan_path_as_mutated(&self, loan_path: &LoanPath) { @@ -490,12 +527,13 @@ struct StaticInitializerCtxt<'a, 'tcx: 'a> { impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> { fn visit_expr(&mut self, ex: &Expr) { if let ast::ExprAddrOf(mutbl, ref base) = ex.node { - let param_env = ty::empty_parameter_environment(self.bccx.tcx); - let mc = mc::MemCategorizationContext::new(¶m_env); + let infcx = infer::new_infer_ctxt(self.bccx.tcx, &self.bccx.tcx.tables, None, false); + let mc = mc::MemCategorizationContext::new(&infcx); let base_cmt = mc.cat_expr(&**base).unwrap(); let borrow_kind = ty::BorrowKind::from_mutbl(mutbl); // Check that we don't allow borrows of unsafe static items. - if check_aliasability(self.bccx, ex.span, euv::AddrOf, + if check_aliasability(self.bccx, ex.span, + BorrowViolation(euv::AddrOf), base_cmt, borrow_kind).is_err() { return; // reported an error, no sense in reporting more. } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 9a29ed91339e2..5baabebea116b 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -137,7 +137,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, mc::cat_interior(ref b, mc::InteriorField(_)) => { match b.ty.sty { ty::TyStruct(did, _) | - ty::TyEnum(did, _) if ty::has_dtor(bccx.tcx, did) => { + ty::TyEnum(did, _) if bccx.tcx.has_dtor(did) => { bccx.span_err( move_from.span, &format!("cannot move out of type `{}`, \ diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 345f5378f69e1..4c186dd840610 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -124,7 +124,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { self.bccx.report( BckError { span: self.span, - cause: self.cause, + cause: BorrowViolation(self.cause), cmt: cmt_base, code: err_borrowed_pointer_too_short( self.loan_region, lt)}); diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index ec92c2ed05a36..0d475e1257141 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -29,7 +29,6 @@ use rustc::middle::dataflow::DataFlowOperator; use rustc::middle::dataflow::KillFrom; use rustc::middle::expr_use_visitor as euv; use rustc::middle::free_region::FreeRegionMap; -use rustc::middle::infer::error_reporting::note_and_explain_region; use rustc::middle::mem_categorization as mc; use rustc::middle::region; use rustc::middle::ty::{self, Ty}; @@ -546,12 +545,12 @@ pub enum bckerr_code { #[derive(PartialEq)] pub struct BckError<'tcx> { span: Span, - cause: euv::LoanCause, + cause: AliasableViolationKind, cmt: mc::cmt<'tcx>, code: bckerr_code } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum AliasableViolationKind { MutabilityViolation, BorrowViolation(euv::LoanCause) @@ -576,8 +575,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { pub fn report(&self, err: BckError<'tcx>) { // Catch and handle some particular cases. match (&err.code, &err.cause) { - (&err_out_of_scope(ty::ReScope(_), ty::ReStatic), &euv::ClosureCapture(span)) | - (&err_out_of_scope(ty::ReScope(_), ty::ReFree(..)), &euv::ClosureCapture(span)) => { + (&err_out_of_scope(ty::ReScope(_), ty::ReStatic), + &BorrowViolation(euv::ClosureCapture(span))) | + (&err_out_of_scope(ty::ReScope(_), ty::ReFree(..)), + &BorrowViolation(euv::ClosureCapture(span))) => { return self.report_out_of_scope_escaping_closure_capture(&err, span); } _ => { } @@ -662,7 +663,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { .map .find(the_move.id) { Some(ast_map::NodeExpr(expr)) => { - (ty::expr_ty_adjusted(self.tcx, &*expr), expr.span) + (self.tcx.expr_ty_adjusted(&*expr), expr.span) } r => { self.tcx.sess.bug(&format!("MoveExpr({}) maps to \ @@ -696,7 +697,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } move_data::MovePat => { - let pat_ty = ty::node_id_to_type(self.tcx, the_move.id); + let pat_ty = self.tcx.node_id_to_type(the_move.id); let span = self.tcx.map.span(the_move.id); self.tcx.sess.span_note(span, &format!("`{}` moved here{} because it has type `{}`, \ @@ -713,7 +714,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { .map .find(the_move.id) { Some(ast_map::NodeExpr(expr)) => { - (ty::expr_ty_adjusted(self.tcx, &*expr), expr.span) + (self.tcx.expr_ty_adjusted(&*expr), expr.span) } r => { self.tcx.sess.bug(&format!("Captured({}) maps to \ @@ -747,7 +748,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { -> (&'static str, &'static str) { match ty.sty { _ => { - if ty::type_moves_by_default(param_env, span, ty) { + if ty.moves_by_default(param_env, span) { ("non-copyable", "perhaps you meant to use `clone()`?") } else { @@ -796,10 +797,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_end_note(s, m); } - pub fn span_help(&self, s: Span, m: &str) { - self.tcx.sess.span_help(s, m); - } - pub fn fileline_help(&self, s: Span, m: &str) { self.tcx.sess.fileline_help(s, m); } @@ -827,19 +824,22 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }; match err.cause { - euv::ClosureCapture(_) => { + MutabilityViolation => { + format!("cannot assign to {}", descr) + } + BorrowViolation(euv::ClosureCapture(_)) => { format!("closure cannot assign to {}", descr) } - euv::OverloadedOperator | - euv::AddrOf | - euv::RefBinding | - euv::AutoRef | - euv::AutoUnsafe | - euv::ForLoop | - euv::MatchDiscriminant => { + BorrowViolation(euv::OverloadedOperator) | + BorrowViolation(euv::AddrOf) | + BorrowViolation(euv::RefBinding) | + BorrowViolation(euv::AutoRef) | + BorrowViolation(euv::AutoUnsafe) | + BorrowViolation(euv::ForLoop) | + BorrowViolation(euv::MatchDiscriminant) => { format!("cannot borrow {} as mutable", descr) } - euv::ClosureInvocation => { + BorrowViolation(euv::ClosureInvocation) => { self.tcx.sess.span_bug(err.span, "err_mutbl with a closure invocation"); } @@ -997,13 +997,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } err_out_of_scope(super_scope, sub_scope) => { - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "reference must be valid for ", sub_scope, "..."); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( "...but borrowed value is only valid for ", super_scope, ""); @@ -1020,14 +1018,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } None => self.cmt_to_string(&*err.cmt), }; - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( &format!("{} would have to be valid for ", descr), loan_scope, "..."); - note_and_explain_region( - self.tcx, + self.tcx.note_and_explain_region( &format!("...but {} is only valid for ", descr), ptr_scope, ""); @@ -1041,14 +1037,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { match loan_path.kind { LpUpvar(ty::UpvarId{ var_id: id, closure_expr_id: _ }) | LpVar(id) => { - out.push_str(&ty::local_var_name_str(self.tcx, id)); + out.push_str(&self.tcx.local_var_name_str(id)); } LpDowncast(ref lp_base, variant_def_id) => { out.push('('); self.append_loan_path_to_string(&**lp_base, out); out.push_str(DOWNCAST_PRINTED_OPERATOR); - out.push_str(&ty::item_path_str(self.tcx, variant_def_id)); + out.push_str(&self.tcx.item_path_str(variant_def_id)); out.push(')'); } @@ -1094,7 +1090,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { out.push('('); self.append_autoderefd_loan_path_to_string(&**lp_base, out); out.push(':'); - out.push_str(&ty::item_path_str(self.tcx, variant_def_id)); + out.push_str(&self.tcx.item_path_str(variant_def_id)); out.push(')'); } @@ -1184,7 +1180,7 @@ impl<'tcx> fmt::Debug for LoanPath<'tcx> { LpDowncast(ref lp, variant_def_id) => { let variant_str = if variant_def_id.krate == ast::LOCAL_CRATE { - ty::tls::with(|tcx| ty::item_path_str(tcx, variant_def_id)) + ty::tls::with(|tcx| tcx.item_path_str(variant_def_id)) } else { format!("{:?}", variant_def_id) }; @@ -1216,7 +1212,7 @@ impl<'tcx> fmt::Display for LoanPath<'tcx> { LpDowncast(ref lp, variant_def_id) => { let variant_str = if variant_def_id.krate == ast::LOCAL_CRATE { - ty::tls::with(|tcx| ty::item_path_str(tcx, variant_def_id)) + ty::tls::with(|tcx| tcx.item_path_str(variant_def_id)) } else { format!("{:?}", variant_def_id) }; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d3297562aef16..80c4fc28703ac 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -602,7 +602,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, make_glob_map: resolve::MakeGlobMap, f: F) -> (Session, R) - where F: FnOnce(&ty::ctxt<'tcx>, + where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>, ty::CrateAnalysis) -> R { let time_passes = sess.time_passes(); @@ -648,16 +648,16 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, time(time_passes, "static item recursion checking", (), |_| middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map)); - ty::with_ctxt(sess, - arenas, - def_map, - named_region_map, - ast_map, - freevars, - region_map, - lang_items, - stability::Index::new(krate), - |tcx| { + ty::ctxt::create_and_enter(sess, + arenas, + def_map, + named_region_map, + ast_map, + freevars, + region_map, + lang_items, + stability::Index::new(krate), + |tcx| { // passes are timed inside typeck typeck::check_crate(tcx, trait_map); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 96d1ab23ad523..a9787987611f7 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -481,8 +481,7 @@ pub fn commit_date_str() -> Option<&'static str> { option_env!("CFG_VER_DATE") } -/// Prints version information and returns None on success or an error -/// message on panic. +/// Prints version information pub fn version(binary: &str, matches: &getopts::Matches) { let verbose = matches.opt_present("verbose"); diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index a40cb94204d9c..610f3f3a75ee6 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -317,7 +317,7 @@ impl<'a, 'tcx> pprust::PpAnn for TypedAnnotation<'a, 'tcx> { try!(pp::word(&mut s.s, "as")); try!(pp::space(&mut s.s)); try!(pp::word(&mut s.s, - &ty::expr_ty(self.tcx, expr).to_string())); + &self.tcx.expr_ty(expr).to_string())); s.pclose() } _ => Ok(()) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 62c8e0368d906..128b0b7baabc0 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -22,7 +22,7 @@ use rustc_typeck::middle::resolve_lifetime; use rustc_typeck::middle::stability; use rustc_typeck::middle::subst; use rustc_typeck::middle::subst::Subst; -use rustc_typeck::middle::ty::{self, Ty}; +use rustc_typeck::middle::ty::{self, Ty, RegionEscape}; use rustc_typeck::middle::ty_relate::TypeRelation; use rustc_typeck::middle::infer; use rustc_typeck::middle::infer::lub::Lub; @@ -130,17 +130,17 @@ fn test_env(source_string: &str, resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No); let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map); let region_map = region::resolve_crate(&sess, krate); - ty::with_ctxt(sess, - &arenas, - def_map, - named_region_map, - ast_map, - freevars, - region_map, - lang_items, - stability::Index::new(krate), - |tcx| { - let infcx = infer::new_infer_ctxt(tcx); + ty::ctxt::create_and_enter(sess, + &arenas, + def_map, + named_region_map, + ast_map, + freevars, + region_map, + lang_items, + stability::Index::new(krate), + |tcx| { + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); body(Env { infcx: &infcx }); let free_regions = FreeRegionMap::new(); infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID); @@ -256,30 +256,29 @@ impl<'a, 'tcx> Env<'a, 'tcx> { -> Ty<'tcx> { let input_args = input_tys.iter().cloned().collect(); - ty::mk_bare_fn(self.infcx.tcx, - None, - self.infcx.tcx.mk_bare_fn(ty::BareFnTy { - unsafety: ast::Unsafety::Normal, - abi: abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: input_args, - output: ty::FnConverging(output_ty), - variadic: false - }) - })) + self.infcx.tcx.mk_fn(None, + self.infcx.tcx.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Normal, + abi: abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: input_args, + output: ty::FnConverging(output_ty), + variadic: false + }) + })) } pub fn t_nil(&self) -> Ty<'tcx> { - ty::mk_nil(self.infcx.tcx) + self.infcx.tcx.mk_nil() } pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> { - ty::mk_tup(self.infcx.tcx, vec![ty1, ty2]) + self.infcx.tcx.mk_tup(vec![ty1, ty2]) } pub fn t_param(&self, space: subst::ParamSpace, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - ty::mk_param(self.infcx.tcx, space, index, token::intern(&name[..])) + self.infcx.tcx.mk_param(space, index, token::intern(&name[..])) } pub fn re_early_bound(&self, @@ -302,16 +301,14 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> { - ty::mk_imm_rptr(self.infcx.tcx, - self.infcx.tcx.mk_region(r), - self.tcx().types.isize) + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), + self.tcx().types.isize) } pub fn t_rptr_late_bound(&self, id: u32) -> Ty<'tcx> { let r = self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1)); - ty::mk_imm_rptr(self.infcx.tcx, - self.infcx.tcx.mk_region(r), - self.tcx().types.isize) + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), + self.tcx().types.isize) } pub fn t_rptr_late_bound_with_debruijn(&self, @@ -319,15 +316,14 @@ impl<'a, 'tcx> Env<'a, 'tcx> { debruijn: ty::DebruijnIndex) -> Ty<'tcx> { let r = self.re_late_bound_with_debruijn(id, debruijn); - ty::mk_imm_rptr(self.infcx.tcx, - self.infcx.tcx.mk_region(r), - self.tcx().types.isize) + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), + self.tcx().types.isize) } pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> { let r = ty::ReScope(CodeExtent::from_node_id(id)); - ty::mk_imm_rptr(self.infcx.tcx, self.infcx.tcx.mk_region(r), - self.tcx().types.isize) + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), + self.tcx().types.isize) } pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region { @@ -337,15 +333,13 @@ impl<'a, 'tcx> Env<'a, 'tcx> { pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> { let r = self.re_free(nid, id); - ty::mk_imm_rptr(self.infcx.tcx, - self.infcx.tcx.mk_region(r), - self.tcx().types.isize) + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), + self.tcx().types.isize) } pub fn t_rptr_static(&self) -> Ty<'tcx> { - ty::mk_imm_rptr(self.infcx.tcx, - self.infcx.tcx.mk_region(ty::ReStatic), - self.tcx().types.isize) + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReStatic), + self.tcx().types.isize) } pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> { @@ -745,22 +739,22 @@ fn escaping() { // Situation: // Theta = [A -> &'a foo] - assert!(!ty::type_has_escaping_regions(env.t_nil())); + assert!(!env.t_nil().has_escaping_regions()); let t_rptr_free1 = env.t_rptr_free(0, 1); - assert!(!ty::type_has_escaping_regions(t_rptr_free1)); + assert!(!t_rptr_free1.has_escaping_regions()); let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)); - assert!(ty::type_has_escaping_regions(t_rptr_bound1)); + assert!(t_rptr_bound1.has_escaping_regions()); let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2)); - assert!(ty::type_has_escaping_regions(t_rptr_bound2)); + assert!(t_rptr_bound2.has_escaping_regions()); // t_fn = fn(A) let t_param = env.t_param(subst::TypeSpace, 0); - assert!(!ty::type_has_escaping_regions(t_param)); + assert!(!t_param.has_escaping_regions()); let t_fn = env.t_fn(&[t_param], env.t_nil()); - assert!(!ty::type_has_escaping_regions(t_fn)); + assert!(!t_fn.has_escaping_regions()); }) } @@ -804,9 +798,9 @@ fn walk_ty() { let tcx = env.infcx.tcx; let int_ty = tcx.types.isize; let uint_ty = tcx.types.usize; - let tup1_ty = ty::mk_tup(tcx, vec!(int_ty, uint_ty, int_ty, uint_ty)); - let tup2_ty = ty::mk_tup(tcx, vec!(tup1_ty, tup1_ty, uint_ty)); - let uniq_ty = ty::mk_uniq(tcx, tup2_ty); + let tup1_ty = tcx.mk_tup(vec!(int_ty, uint_ty, int_ty, uint_ty)); + let tup2_ty = tcx.mk_tup(vec!(tup1_ty, tup1_ty, uint_ty)); + let uniq_ty = tcx.mk_box(tup2_ty); let walked: Vec<_> = uniq_ty.walk().collect(); assert_eq!(walked, [uniq_ty, tup2_ty, @@ -822,9 +816,9 @@ fn walk_ty_skip_subtree() { let tcx = env.infcx.tcx; let int_ty = tcx.types.isize; let uint_ty = tcx.types.usize; - let tup1_ty = ty::mk_tup(tcx, vec!(int_ty, uint_ty, int_ty, uint_ty)); - let tup2_ty = ty::mk_tup(tcx, vec!(tup1_ty, tup1_ty, uint_ty)); - let uniq_ty = ty::mk_uniq(tcx, tup2_ty); + let tup1_ty = tcx.mk_tup(vec!(int_ty, uint_ty, int_ty, uint_ty)); + let tup2_ty = tcx.mk_tup(vec!(tup1_ty, tup1_ty, uint_ty)); + let uniq_ty = tcx.mk_box(tup2_ty); // types we expect to see (in order), plus a boolean saying // whether to skip the subtree. diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ffb860283dd7e..fa86c0dde991d 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -28,10 +28,15 @@ //! Use the former for unit-like structs and the latter for structs with //! a `pub fn new()`. +// BitSet +#![allow(deprecated)] + use metadata::{csearch, decoder}; use middle::def::*; +use middle::infer; use middle::subst::Substs; use middle::ty::{self, Ty}; +use middle::traits; use middle::{def, pat_util, stability}; use middle::const_eval::{eval_const_expr_partial, ConstVal}; use middle::cfg; @@ -142,7 +147,7 @@ impl LintPass for TypeLimits { } }, _ => { - let t = ty::expr_ty(cx.tcx, &**expr); + let t = cx.tcx.expr_ty(&**expr); match t.sty { ty::TyUint(_) => { cx.span_lint(UNSIGNED_NEGATION, e.span, @@ -168,7 +173,7 @@ impl LintPass for TypeLimits { } if is_shift_binop(binop.node) { - let opt_ty_bits = match ty::expr_ty(cx.tcx, &**l).sty { + let opt_ty_bits = match cx.tcx.expr_ty(&**l).sty { ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)), ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)), _ => None @@ -193,7 +198,7 @@ impl LintPass for TypeLimits { } }, ast::ExprLit(ref lit) => { - match ty::expr_ty(cx.tcx, e).sty { + match cx.tcx.expr_ty(e).sty { ty::TyInt(t) => { match lit.node { ast::LitInt(v, ast::SignedIntLit(_, ast::Plus)) | @@ -343,7 +348,7 @@ impl LintPass for TypeLimits { } else { binop }; - match ty::expr_ty(tcx, expr).sty { + match tcx.expr_ty(expr).sty { ty::TyInt(int_ty) => { let (min, max) = int_ty_range(int_ty); let lit_val: i64 = match lit.node { @@ -412,7 +417,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { None => panic!("ast_ty_to_ty_cache was incomplete after typeck!") }; - if !ty::is_ffi_safe(self.cx.tcx, tty) { + if !tty.is_ffi_safe(self.cx.tcx) { self.cx.span_lint(IMPROPER_CTYPES, sp, "found type without foreign-function-safe \ representation annotation in foreign module, consider \ @@ -482,20 +487,11 @@ pub struct BoxPointers; impl BoxPointers { fn check_heap_type<'a, 'tcx>(&self, cx: &Context<'a, 'tcx>, span: Span, ty: Ty<'tcx>) { - let mut n_uniq: usize = 0; - ty::fold_ty(cx.tcx, ty, |t| { - match t.sty { - ty::TyBox(_) => { - n_uniq += 1; - } - _ => () - }; - t - }); - - if n_uniq > 0 { - let m = format!("type uses owned (Box type) pointers: {}", ty); - cx.span_lint(BOX_POINTERS, span, &m[..]); + for leaf_ty in ty.walk() { + if let ty::TyBox(_) = leaf_ty.sty { + let m = format!("type uses owned (Box type) pointers: {}", ty); + cx.span_lint(BOX_POINTERS, span, &m); + } } } } @@ -512,7 +508,7 @@ impl LintPass for BoxPointers { ast::ItemEnum(..) | ast::ItemStruct(..) => self.check_heap_type(cx, it.span, - ty::node_id_to_type(cx.tcx, it.id)), + cx.tcx.node_id_to_type(it.id)), _ => () } @@ -521,7 +517,7 @@ impl LintPass for BoxPointers { ast::ItemStruct(ref struct_def, _) => { for struct_field in &struct_def.fields { self.check_heap_type(cx, struct_field.span, - ty::node_id_to_type(cx.tcx, struct_field.node.id)); + cx.tcx.node_id_to_type(struct_field.node.id)); } } _ => () @@ -529,7 +525,7 @@ impl LintPass for BoxPointers { } fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { - let ty = ty::expr_ty(cx.tcx, e); + let ty = cx.tcx.expr_ty(e); self.check_heap_type(cx, e.span, ty); } } @@ -582,13 +578,13 @@ impl LintPass for RawPointerDerive { ast::ItemImpl(_, _, _, ref t_ref_opt, _, _) => { // Deriving the Copy trait does not cause a warning if let &Some(ref trait_ref) = t_ref_opt { - let def_id = ty::trait_ref_to_def_id(cx.tcx, trait_ref); + let def_id = cx.tcx.trait_ref_to_def_id(trait_ref); if Some(def_id) == cx.tcx.lang_items.copy_trait() { return; } } - match ty::node_id_to_type(cx.tcx, item.id).sty { + match cx.tcx.node_id_to_type(item.id).sty { ty::TyEnum(did, _) => did, ty::TyStruct(did, _) => did, _ => return, @@ -732,7 +728,7 @@ impl LintPass for UnusedResults { return; } - let t = ty::expr_ty(cx.tcx, expr); + let t = cx.tcx.expr_ty(expr); let warned = match t.sty { ty::TyTuple(ref tys) if tys.is_empty() => return, ty::TyBool => return, @@ -829,10 +825,12 @@ impl LintPass for NonCamelCaseTypes { } fn check_item(&mut self, cx: &Context, it: &ast::Item) { - let has_extern_repr = it.attrs.iter().any(|attr| { + let extern_repr_count = it.attrs.iter().filter(|attr| { attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter() .any(|r| r == &attr::ReprExtern) - }); + }).count(); + let has_extern_repr = extern_repr_count > 0; + if has_extern_repr { return; } @@ -877,7 +875,7 @@ fn method_context(cx: &Context, id: ast::NodeId, span: Span) -> MethodContext { Some(item) => match item.container() { ty::TraitContainer(..) => MethodContext::TraitDefaultImpl, ty::ImplContainer(cid) => { - match ty::impl_trait_ref(cx.tcx, cid) { + match cx.tcx.impl_trait_ref(cid) { Some(_) => MethodContext::TraitImpl, None => MethodContext::PlainImpl } @@ -1454,7 +1452,7 @@ impl LintPass for UnusedAllocation { _ => return } - if let Some(adjustment) = cx.tcx.adjustments.borrow().get(&e.id) { + if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) { if let ty::AdjustDerefRef(ty::AutoDerefRef { ref autoref, .. }) = *adjustment { match autoref { &Some(ty::AutoPtr(_, ast::MutImmutable)) => { @@ -1601,7 +1599,7 @@ impl LintPass for MissingDoc { ast::ItemImpl(_, _, _, Some(ref trait_ref), _, ref impl_items) => { // If the trait is private, add the impl items to private_traits so they don't get // reported for missing docs. - let real_trait = ty::trait_ref_to_def_id(cx.tcx, trait_ref); + let real_trait = cx.tcx.trait_ref_to_def_id(trait_ref); match cx.tcx.map.find(real_trait.node) { Some(ast_map::NodeItem(item)) => if item.vis == ast::Visibility::Inherited { for itm in impl_items { @@ -1699,23 +1697,25 @@ impl LintPass for MissingCopyImplementations { if ast_generics.is_parameterized() { return; } - ty::mk_struct(cx.tcx, local_def(item.id), - cx.tcx.mk_substs(Substs::empty())) + cx.tcx.mk_struct(local_def(item.id), + cx.tcx.mk_substs(Substs::empty())) } ast::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } - ty::mk_enum(cx.tcx, local_def(item.id), - cx.tcx.mk_substs(Substs::empty())) + cx.tcx.mk_enum(local_def(item.id), + cx.tcx.mk_substs(Substs::empty())) } _ => return, }; - let parameter_environment = ty::empty_parameter_environment(cx.tcx); - if !ty::type_moves_by_default(¶meter_environment, item.span, ty) { + let parameter_environment = cx.tcx.empty_parameter_environment(); + // FIXME (@jroesch) should probably inver this so that the parameter env still impls this + // method + if !ty.moves_by_default(¶meter_environment, item.span) { return; } - if ty::can_type_implement_copy(¶meter_environment, item.span, ty).is_ok() { + if parameter_environment.can_type_implement_copy(ty, item.span).is_ok() { cx.span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, "type could implement `Copy`; consider adding `impl \ @@ -1763,11 +1763,11 @@ impl LintPass for MissingDebugImplementations { }; if self.impling_types.is_none() { - let debug_def = ty::lookup_trait_def(cx.tcx, debug); + let debug_def = cx.tcx.lookup_trait_def(debug); let mut impls = NodeSet(); debug_def.for_each_impl(cx.tcx, |d| { if d.krate == ast::LOCAL_CRATE { - if let Some(ty_def) = ty::ty_to_def_id(ty::node_id_to_type(cx.tcx, d.node)) { + if let Some(ty_def) = cx.tcx.node_id_to_type(d.node).ty_to_def_id() { impls.insert(ty_def.node); } } @@ -1865,24 +1865,18 @@ impl LintPass for UnconditionalRecursion { fn check_fn(&mut self, cx: &Context, fn_kind: visit::FnKind, _: &ast::FnDecl, blk: &ast::Block, sp: Span, id: ast::NodeId) { - // FIXME(#23542) Replace with type ascription. - #![allow(trivial_casts)] - type F = for<'tcx> fn(&ty::ctxt<'tcx>, ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool; - let (name, checker) = match fn_kind { - visit::FkItemFn(name, _, _, _, _, _) => (name, id_refers_to_this_fn as F), - visit::FkMethod(name, _, _) => (name, id_refers_to_this_method as F), + let method = match fn_kind { + visit::FkItemFn(..) => None, + visit::FkMethod(..) => { + cx.tcx.impl_or_trait_item(local_def(id)).as_opt_method() + } // closures can't recur, so they don't matter. visit::FkFnBlock => return }; - let impl_def_id = ty::impl_of_method(cx.tcx, local_def(id)) - .unwrap_or(local_def(ast::DUMMY_NODE_ID)); - assert!(ast_util::is_local(impl_def_id)); - let impl_node_id = impl_def_id.node; - // Walk through this function (say `f`) looking to see if // every possible path references itself, i.e. the function is // called recursively unconditionally. This is done by trying @@ -1933,7 +1927,17 @@ impl LintPass for UnconditionalRecursion { let node_id = cfg.graph.node_data(idx).id(); // is this a recursive call? - if node_id != ast::DUMMY_NODE_ID && checker(cx.tcx, impl_node_id, id, name, node_id) { + let self_recursive = if node_id != ast::DUMMY_NODE_ID { + match method { + Some(ref method) => { + expr_refers_to_this_method(cx.tcx, method, node_id) + } + None => expr_refers_to_this_fn(cx.tcx, id, node_id) + } + } else { + false + }; + if self_recursive { self_call_spans.push(cx.tcx.map.span(node_id)); // this is a self call, so we shouldn't explore past // this node in the CFG. @@ -1972,68 +1976,83 @@ impl LintPass for UnconditionalRecursion { // all done return; - // Functions for identifying if the given NodeId `id` - // represents a call to the function `fn_id`/method - // `method_id`. + // Functions for identifying if the given Expr NodeId `id` + // represents a call to the function `fn_id`/method `method`. - fn id_refers_to_this_fn<'tcx>(tcx: &ty::ctxt<'tcx>, - _: ast::NodeId, - fn_id: ast::NodeId, - _: ast::Ident, + fn expr_refers_to_this_fn(tcx: &ty::ctxt, + fn_id: ast::NodeId, + id: ast::NodeId) -> bool { + match tcx.map.get(id) { + ast_map::NodeExpr(&ast::Expr { node: ast::ExprCall(ref callee, _), .. }) => { + tcx.def_map.borrow().get(&callee.id) + .map_or(false, |def| def.def_id() == local_def(fn_id)) + } + _ => false + } + } + + // Check if the method call `id` refers to method `method`. + fn expr_refers_to_this_method(tcx: &ty::ctxt, + method: &ty::Method, id: ast::NodeId) -> bool { - tcx.def_map.borrow().get(&id) - .map_or(false, |def| def.def_id() == local_def(fn_id)) - } - - // check if the method call `id` refers to method `method_id` - // (with name `method_name` contained in impl `impl_id`). - fn id_refers_to_this_method<'tcx>(tcx: &ty::ctxt<'tcx>, - impl_id: ast::NodeId, - method_id: ast::NodeId, - method_name: ast::Ident, - id: ast::NodeId) -> bool { - let did = match tcx.method_map.borrow().get(&ty::MethodCall::expr(id)) { - None => return false, - Some(m) => match m.origin { - // There's no way to know if a method call via a - // vtable is recursion, so we assume it's not. - ty::MethodTraitObject(_) => return false, - - // This `did` refers directly to the method definition. - ty::MethodStatic(did) | ty::MethodStaticClosure(did) => did, - - // MethodTypeParam are methods from traits: - - // The `impl ... for ...` of this method call - // isn't known, e.g. it might be a default method - // in a trait, so we get the def-id of the trait - // method instead. - ty::MethodTypeParam( - ty::MethodParam { ref trait_ref, method_num, impl_def_id: None, }) => { - ty::trait_item(tcx, trait_ref.def_id, method_num).def_id() - } + let method_call = ty::MethodCall::expr(id); + let callee = match tcx.tables.borrow().method_map.get(&method_call) { + Some(&m) => m, + None => return false + }; + let callee_item = tcx.impl_or_trait_item(callee.def_id); + + match callee_item.container() { + // This is an inherent method, so the `def_id` refers + // directly to the method definition. + ty::ImplContainer(_) => { + callee.def_id == method.def_id + } - // The `impl` is known, so we check that with a - // special case: - ty::MethodTypeParam( - ty::MethodParam { impl_def_id: Some(impl_def_id), .. }) => { + // A trait method, from any number of possible sources. + // Attempt to select a concrete impl before checking. + ty::TraitContainer(trait_def_id) => { + let trait_substs = callee.substs.clone().method_to_trait(); + let trait_substs = tcx.mk_substs(trait_substs); + let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs); + let trait_ref = ty::Binder(trait_ref); + let span = tcx.map.span(id); + let obligation = + traits::Obligation::new(traits::ObligationCause::misc(span, id), + trait_ref.to_poly_trait_predicate()); + + let param_env = ty::ParameterEnvironment::for_item(tcx, method.def_id.node); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env), false); + let mut selcx = traits::SelectionContext::new(&infcx); + match selcx.select(&obligation) { + // The method comes from a `T: Trait` bound. + // If `T` is `Self`, then this call is inside + // a default method definition. + Ok(Some(traits::VtableParam(_))) => { + let self_ty = callee.substs.self_ty(); + let on_self = self_ty.map_or(false, |t| t.is_self()); + // We can only be recurring in a default + // method if we're being called literally + // on the `Self` type. + on_self && callee.def_id == method.def_id + } - let name = match tcx.map.expect_expr(id).node { - ast::ExprMethodCall(ref sp_ident, _, _) => sp_ident.node, - _ => tcx.sess.span_bug( - tcx.map.span(id), - "non-method call expr behaving like a method call?") - }; - // It matches if it comes from the same impl, - // and has the same method name. - return ast_util::is_local(impl_def_id) - && impl_def_id.node == impl_id - && method_name.name == name.name + // The `impl` is known, so we check that with a + // special case: + Ok(Some(traits::VtableImpl(vtable_impl))) => { + let container = ty::ImplContainer(vtable_impl.impl_def_id); + // It matches if it comes from the same impl, + // and has the same method name. + container == method.container + && callee_item.name() == method.name + } + + // There's no way to know if this call is + // recursive, so we assume it's not. + _ => return false } } - }; - - ast_util::is_local(did) && did.node == method_id + } } } } @@ -2175,11 +2194,11 @@ impl LintPass for MutableTransmutes { ast::ExprPath(..) => (), _ => return None } - if let DefFn(did, _) = ty::resolve_expr(cx.tcx, expr) { + if let DefFn(did, _) = cx.tcx.resolve_expr(expr) { if !def_id_is_transmute(cx, did) { return None; } - let typ = ty::node_id_to_type(cx.tcx, expr.id); + let typ = cx.tcx.node_id_to_type(expr.id); match typ.sty { ty::TyBareFn(_, ref bare_fn) if bare_fn.abi == RustIntrinsic => { if let ty::FnConverging(to) = bare_fn.sig.0.output { @@ -2194,11 +2213,11 @@ impl LintPass for MutableTransmutes { } fn def_id_is_transmute(cx: &Context, def_id: DefId) -> bool { - match ty::lookup_item_type(cx.tcx, def_id).ty.sty { + match cx.tcx.lookup_item_type(def_id).ty.sty { ty::TyBareFn(_, ref bfty) if bfty.abi == RustIntrinsic => (), _ => return false } - ty::with_path(cx.tcx, def_id, |path| match path.last() { + cx.tcx.with_path(def_id, |path| match path.last() { Some(ref last) => last.name().as_str() == "transmute", _ => false }) @@ -2251,7 +2270,7 @@ impl LintPass for DropWithReprExtern { let (drop_impl_did, dtor_self_type) = if dtor_did.krate == ast::LOCAL_CRATE { let impl_did = ctx.tcx.map.get_parent_did(dtor_did.node); - let ty = ty::lookup_item_type(ctx.tcx, impl_did).ty; + let ty = ctx.tcx.lookup_item_type(impl_did).ty; (impl_did, ty) } else { continue; @@ -2261,9 +2280,9 @@ impl LintPass for DropWithReprExtern { ty::TyEnum(self_type_did, _) | ty::TyStruct(self_type_did, _) | ty::TyClosure(self_type_did, _) => { - let hints = ty::lookup_repr_hints(ctx.tcx, self_type_did); + let hints = ctx.tcx.lookup_repr_hints(self_type_did); if hints.iter().any(|attr| *attr == attr::ReprExtern) && - ty::ty_dtor(ctx.tcx, self_type_did).has_drop_flag() { + ctx.tcx.ty_dtor(self_type_did).has_drop_flag() { let drop_impl_span = ctx.tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP); let self_defn_span = ctx.tcx.map.def_id_span(self_type_did, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index cae93baaf74be..d90e5a033a187 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -40,10 +40,6 @@ use rustc::middle::privacy::ImportUse::*; use rustc::middle::privacy::LastPrivate::*; use rustc::middle::privacy::PrivateDep::*; use rustc::middle::privacy::{ExternalExports, ExportedItems, PublicItems}; -use rustc::middle::ty::{MethodTypeParam, MethodStatic}; -use rustc::middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam}; -use rustc::middle::ty::{MethodStaticClosure, MethodObject}; -use rustc::middle::ty::MethodTraitObject; use rustc::middle::ty::{self, Ty}; use rustc::util::nodemap::{NodeMap, NodeSet}; @@ -53,7 +49,7 @@ use syntax::codemap::Span; use syntax::parse::token; use syntax::visit::{self, Visitor}; -type Context<'a, 'tcx> = (&'a MethodMap<'tcx>, &'a def::ExportMap); +type Context<'a, 'tcx> = (&'a ty::MethodMap<'tcx>, &'a def::ExportMap); /// Result of a checking operation - None => no errors were found. Some => an /// error and contains the span and message for reporting that error and @@ -273,7 +269,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { } _ => true, }; - let tr = ty::impl_trait_ref(self.tcx, local_def(item.id)); + let tr = self.tcx.impl_trait_ref(local_def(item.id)); let public_trait = tr.clone().map_or(false, |tr| { !is_local(tr.def_id) || self.exported_items.contains(&tr.def_id.node) @@ -423,7 +419,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { self.def_privacy(id) } ty::ImplContainer(id) => { - match ty::impl_trait_ref(self.tcx, id) { + match self.tcx.impl_trait_ref(id) { Some(t) => { debug!("privacy - impl of trait {:?}", id); self.def_privacy(t.def_id) @@ -451,7 +447,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { self.def_privacy(id) } ty::ImplContainer(id) => { - match ty::impl_trait_ref(self.tcx, id) { + match self.tcx.impl_trait_ref(id) { Some(t) => { debug!("privacy - impl of trait {:?}", id); self.def_privacy(t.def_id) @@ -476,7 +472,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { self.def_privacy(id) } ty::ImplContainer(id) => { - match ty::impl_trait_ref(self.tcx, id) { + match self.tcx.impl_trait_ref(id) { Some(t) => { debug!("privacy - impl of trait {:?}", id); self.def_privacy(t.def_id) @@ -537,7 +533,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { ast::MethodImplItem(..) => { let imp = self.tcx.map .get_parent_did(closest_private_id); - match ty::impl_trait_ref(self.tcx, imp) { + match self.tcx.impl_trait_ref(imp) { Some(..) => return Allowable, _ if ii.vis == ast::Public => { return Allowable @@ -696,7 +692,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { span: Span, id: ast::DefId, name: FieldName) { - let fields = ty::lookup_struct_fields(self.tcx, id); + let fields = self.tcx.lookup_struct_fields(id); let field = match name { NamedField(f_name) => { debug!("privacy - check named field {} in struct {:?}", f_name, id); @@ -709,10 +705,10 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { return } - let struct_type = ty::lookup_item_type(self.tcx, id).ty; + let struct_type = self.tcx.lookup_item_type(id).ty; let struct_desc = match struct_type.sty { ty::TyStruct(_, _) => - format!("struct `{}`", ty::item_path_str(self.tcx, id)), + format!("struct `{}`", self.tcx.item_path_str(id)), // struct variant fields have inherited visibility ty::TyEnum(..) => return, _ => self.tcx.sess.span_bug(span, "can't find struct for field") @@ -733,7 +729,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { name: ast::Name) { // If the method is a default method, we need to use the def_id of // the default implementation. - let method_id = match ty::impl_or_trait_item(self.tcx, method_id) { + let method_id = match self.tcx.impl_or_trait_item(method_id) { ty::MethodTraitItem(method_type) => { method_type.provided_source.unwrap_or(method_id) } @@ -848,18 +844,16 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } // Checks that a method is in scope. - fn check_method(&mut self, span: Span, origin: &MethodOrigin, + fn check_method(&mut self, span: Span, method_def_id: ast::DefId, name: ast::Name) { - match *origin { - MethodStatic(method_id) => { - self.check_static_method(span, method_id, name) + match self.tcx.impl_or_trait_item(method_def_id).container() { + ty::ImplContainer(_) => { + self.check_static_method(span, method_def_id, name) } - MethodStaticClosure(_) => {} // Trait methods are always all public. The only controlling factor // is whether the trait itself is accessible or not. - MethodTypeParam(MethodParam { ref trait_ref, .. }) | - MethodTraitObject(MethodObject { ref trait_ref, .. }) => { - self.report_error(self.ensure_public(span, trait_ref.def_id, + ty::TraitContainer(trait_def_id) => { + self.report_error(self.ensure_public(span, trait_def_id, None, "source trait")); } } @@ -893,36 +887,28 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &ast::Expr) { match expr.node { ast::ExprField(ref base, ident) => { - if let ty::TyStruct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty { + if let ty::TyStruct(id, _) = self.tcx.expr_ty_adjusted(&**base).sty { self.check_field(expr.span, id, NamedField(ident.node.name)); } } ast::ExprTupField(ref base, idx) => { - if let ty::TyStruct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty { + if let ty::TyStruct(id, _) = self.tcx.expr_ty_adjusted(&**base).sty { self.check_field(expr.span, id, UnnamedField(idx.node)); } } ast::ExprMethodCall(ident, _, _) => { - let method_call = MethodCall::expr(expr.id); - match self.tcx.method_map.borrow().get(&method_call) { - None => { - self.tcx.sess.span_bug(expr.span, - "method call not in \ - method map"); - } - Some(method) => { - debug!("(privacy checking) checking impl method"); - self.check_method(expr.span, &method.origin, ident.node.name); - } - } + let method_call = ty::MethodCall::expr(expr.id); + let method = self.tcx.tables.borrow().method_map[&method_call]; + debug!("(privacy checking) checking impl method"); + self.check_method(expr.span, method.def_id, ident.node.name); } ast::ExprStruct(_, ref fields, _) => { - match ty::expr_ty(self.tcx, expr).sty { + match self.tcx.expr_ty(expr).sty { ty::TyStruct(ctor_id, _) => { // RFC 736: ensure all unmentioned fields are visible. // Rather than computing the set of unmentioned fields // (i.e. `all_fields - fields`), just check them all. - let all_fields = ty::lookup_struct_fields(self.tcx, ctor_id); + let all_fields = self.tcx.lookup_struct_fields(ctor_id); for field in all_fields { self.check_field(expr.span, ctor_id, NamedField(field.name)); @@ -950,7 +936,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } ast::ExprPath(..) => { let guard = |did: ast::DefId| { - let fields = ty::lookup_struct_fields(self.tcx, did); + let fields = self.tcx.lookup_struct_fields(did); let any_priv = fields.iter().any(|f| { f.vis != ast::Public && ( !is_local(f.id) || @@ -994,7 +980,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { match pattern.node { ast::PatStruct(_, ref fields, _) => { - match ty::pat_ty(self.tcx, pattern).sty { + match self.tcx.pat_ty(pattern).sty { ty::TyStruct(id, _) => { for field in fields { self.check_field(pattern.span, id, @@ -1025,7 +1011,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { // Patterns which bind no fields are allowable (the path is check // elsewhere). ast::PatEnum(_, Some(ref fields)) => { - match ty::pat_ty(self.tcx, pattern).sty { + match self.tcx.pat_ty(pattern).sty { ty::TyStruct(id, _) => { for (i, field) in fields.iter().enumerate() { if let ast::PatWild(..) = field.node { @@ -1337,7 +1323,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { let not_private_trait = trait_ref.as_ref().map_or(true, // no trait counts as public trait |tr| { - let did = ty::trait_ref_to_def_id(self.tcx, tr); + let did = self.tcx.trait_ref_to_def_id(tr); !is_local(did) || self.trait_is_public(did.node) }); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 6b8b59de3c253..cf5feabcc57e2 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -1214,11 +1214,13 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, // Just need to tell the linker about where the library lives and // what its name is - if let Some(dir) = cratepath.parent() { + let parent = cratepath.parent(); + if let Some(dir) = parent { cmd.include_path(&fix_windows_verbatim_for_gcc(dir)); } let filestem = cratepath.file_stem().unwrap().to_str().unwrap(); - cmd.link_dylib(&unlib(&sess.target, filestem)); + cmd.link_rust_dylib(&unlib(&sess.target, filestem), + parent.unwrap_or(Path::new(""))); } } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 1eacec46c87bb..7253334d69989 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -11,6 +11,7 @@ use std::ffi::OsString; use std::path::{Path, PathBuf}; use std::process::Command; +use std::fs; use rustc_back::archive; use session::Session; @@ -25,6 +26,7 @@ use session::config; /// MSVC linker (e.g. `link.exe`) is being used. pub trait Linker { fn link_dylib(&mut self, lib: &str); + fn link_rust_dylib(&mut self, lib: &str, path: &Path); fn link_framework(&mut self, framework: &str); fn link_staticlib(&mut self, lib: &str); fn link_rlib(&mut self, lib: &Path); @@ -67,6 +69,10 @@ impl<'a> Linker for GnuLinker<'a> { fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); } fn args(&mut self, args: &[String]) { self.cmd.args(args); } + fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + self.cmd.arg("-l").arg(lib); + } + fn link_framework(&mut self, framework: &str) { self.cmd.arg("-framework").arg(framework); } @@ -189,6 +195,18 @@ impl<'a> Linker for MsvcLinker<'a> { fn link_dylib(&mut self, lib: &str) { self.cmd.arg(&format!("{}.lib", lib)); } + + fn link_rust_dylib(&mut self, lib: &str, path: &Path) { + // When producing a dll, the MSVC linker may not actually emit a + // `foo.lib` file if the dll doesn't actually export any symbols, so we + // check to see if the file is there and just omit linking to it if it's + // not present. + let name = format!("{}.lib", lib); + if fs::metadata(&path.join(&name)).is_ok() { + self.cmd.arg(name); + } + } + fn link_staticlib(&mut self, lib: &str) { self.cmd.arg(&format!("{}.lib", lib)); } diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index 65d9d9809c926..e88b3980737ab 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -308,10 +308,10 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { debug!("process_method: {}:{}", id, token::get_name(name)); - let mut scope_id; + let scope_id; // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let qualname = match ty::impl_of_method(self.tcx, ast_util::local_def(id)) { + let qualname = match self.tcx.impl_of_method(ast_util::local_def(id)) { Some(impl_id) => match self.tcx.map.get(impl_id.node) { NodeItem(item) => { scope_id = item.id; @@ -320,11 +320,11 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let mut result = String::from("<"); result.push_str(&ty_to_string(&**ty)); - match ty::trait_of_item(self.tcx, ast_util::local_def(id)) { + match self.tcx.trait_of_item(ast_util::local_def(id)) { Some(def_id) => { result.push_str(" as "); result.push_str( - &ty::item_path_str(self.tcx, def_id)); + &self.tcx.item_path_str(def_id)); }, None => {} } @@ -344,12 +344,12 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { impl_id.node, id, self.tcx.map.get(impl_id.node))); }, }, - None => match ty::trait_of_item(self.tcx, ast_util::local_def(id)) { + None => match self.tcx.trait_of_item(ast_util::local_def(id)) { Some(def_id) => { scope_id = def_id.node; match self.tcx.map.get(def_id.node) { NodeItem(_) => { - format!("::{}", ty::item_path_str(self.tcx, def_id)) + format!("::{}", self.tcx.item_path_str(def_id)) } _ => { self.sess.span_bug(span, @@ -368,7 +368,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let qualname = &format!("{}::{}", qualname, &token::get_name(name)); // record the decl for this def (if it has one) - let decl_id = ty::trait_item_of_item(self.tcx, ast_util::local_def(id)) + let decl_id = self.tcx.trait_item_of_item(ast_util::local_def(id)) .and_then(|new_id| { let def_id = new_id.def_id(); if def_id.node != 0 && def_id != ast_util::local_def(id) { @@ -776,10 +776,10 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { def::DefMethod(declid, provenence) => { let sub_span = self.span.sub_span_for_meth_name(span); let defid = if declid.krate == ast::LOCAL_CRATE { - let ti = ty::impl_or_trait_item(self.tcx, declid); + let ti = self.tcx.impl_or_trait_item(declid); match provenence { def::FromTrait(def_id) => { - Some(ty::trait_items(self.tcx, def_id) + Some(self.tcx.trait_items(def_id) .iter() .find(|mr| { mr.name() == ti.name() @@ -793,10 +793,8 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { .unwrap() .iter() .find(|mr| { - ty::impl_or_trait_item( - self.tcx, - mr.def_id() - ).name() == ti.name() + self.tcx.impl_or_trait_item(mr.def_id()).name() + == ti.name() }) .unwrap() .def_id()) @@ -826,7 +824,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { // modules or types in the path prefix match def { def::DefMethod(did, _) => { - let ti = ty::impl_or_trait_item(self.tcx, did); + let ti = self.tcx.impl_or_trait_item(did); if let ty::MethodTraitItem(m) = ti { if m.explicit_self == ty::StaticExplicitSelfCategory { self.write_sub_path_trait_truncated(path); @@ -888,45 +886,11 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn process_method_call(&mut self, ex: &ast::Expr, args: &Vec>) { - let method_map = self.tcx.method_map.borrow(); - let method_callee = method_map.get(&ty::MethodCall::expr(ex.id)).unwrap(); - let (def_id, decl_id) = match method_callee.origin { - ty::MethodStatic(def_id) | - ty::MethodStaticClosure(def_id) => { - // method invoked on an object with a concrete type (not a static method) - let decl_id = - match ty::trait_item_of_item(self.tcx, def_id) { - None => None, - Some(decl_id) => Some(decl_id.def_id()), - }; - - // This incantation is required if the method referenced is a - // trait's default implementation. - let def_id = match ty::impl_or_trait_item(self.tcx, def_id) { - ty::MethodTraitItem(method) => { - method.provided_source.unwrap_or(def_id) - } - _ => self.sess - .span_bug(ex.span, - "save::process_method_call: non-method \ - DefId in MethodStatic or MethodStaticClosure"), - }; - (Some(def_id), decl_id) - } - ty::MethodTypeParam(ref mp) => { - // method invoked on a type parameter - let trait_item = ty::trait_item(self.tcx, - mp.trait_ref.def_id, - mp.method_num); - (None, Some(trait_item.def_id())) - } - ty::MethodTraitObject(ref mo) => { - // method invoked on a trait instance - let trait_item = ty::trait_item(self.tcx, - mo.trait_ref.def_id, - mo.method_num); - (None, Some(trait_item.def_id())) - } + let method_call = ty::MethodCall::expr(ex.id); + let method_id = self.tcx.tables.borrow().method_map[&method_call].def_id; + let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() { + ty::ImplContainer(_) => (Some(method_id), None), + ty::TraitContainer(_) => (None, Some(method_id)) }; let sub_span = self.span.sub_span_for_meth_name(ex.span); self.fmt.meth_call_str(ex.span, @@ -941,7 +905,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn process_pat(&mut self, p:&ast::Pat) { if generated_code(p.span) { - return + return; } match p.node { @@ -953,7 +917,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { def::DefConst(..) | def::DefAssociatedConst(..) => None, def::DefVariant(_, variant_id, _) => Some(variant_id), _ => { - match ty::ty_to_def_id(ty::node_id_to_type(self.tcx, p.id)) { + match self.tcx.node_id_to_type(p.id).ty_to_def_id() { None => { self.sess.span_bug(p.span, &format!("Could not find struct_def for `{}`", @@ -965,8 +929,12 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { }; if let Some(struct_def) = struct_def { - let struct_fields = ty::lookup_struct_fields(self.tcx, struct_def); + let struct_fields = self.tcx.lookup_struct_fields(struct_def); for &Spanned { node: ref field, span } in fields { + if generated_code(span) { + continue; + } + let sub_span = self.span.span_for_first_ident(span); for f in &struct_fields { if f.name == field.ident.name { @@ -978,7 +946,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { break; } } - self.visit_pat(&*field.pat); + self.visit_pat(&field.pat); } } } @@ -1252,10 +1220,10 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { self.visit_expr(&**sub_ex); - let ty = &ty::expr_ty_adjusted(self.tcx, &**sub_ex).sty; + let ty = &self.tcx.expr_ty_adjusted(&**sub_ex).sty; match *ty { ty::TyStruct(def_id, _) => { - let fields = ty::lookup_struct_fields(self.tcx, def_id); + let fields = self.tcx.lookup_struct_fields(def_id); for (i, f) in fields.iter().enumerate() { if i == idx.node { let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index fdfb101ed78cc..9d66e99df3057 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -172,7 +172,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, declaration: None, span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(item.id), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0), }) } ast::ItemStatic(ref typ, mt, ref expr) => { @@ -191,7 +191,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: get_ident(item.ident).to_string(), qualname: qualname, span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(item.id), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0), value: value, type_value: ty_to_string(&typ), }) @@ -205,7 +205,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: get_ident(item.ident).to_string(), qualname: qualname, span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(item.id), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0), value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), }) @@ -223,7 +223,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: get_ident(item.ident).to_string(), qualname: qualname, span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(item.id), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0), filename: filename, }) }, @@ -237,14 +237,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: val, span: sub_span.unwrap(), qualname: enum_name, - scope: self.tcx.map.get_parent(item.id), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0), }) }, ast::ItemImpl(_, _, _, ref trait_ref, ref typ, _) => { let mut type_data = None; let sub_span; - let parent = self.tcx.map.get_parent(item.id); + let parent = self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0); match typ.node { // Common case impl for a struct or something basic. @@ -327,17 +327,17 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { match expr.node { ast::ExprField(ref sub_ex, ident) => { - let ty = &ty::expr_ty_adjusted(self.tcx, &sub_ex).sty; + let ty = &self.tcx.expr_ty_adjusted(&sub_ex).sty; match *ty { ty::TyStruct(def_id, _) => { - let fields = ty::lookup_struct_fields(self.tcx, def_id); + let fields = self.tcx.lookup_struct_fields(def_id); for f in &fields { if f.name == ident.node.name { let sub_span = self.span_utils.span_for_last_ident(expr.span); return Some(Data::VariableRefData(VariableRefData { name: get_ident(ident.node).to_string(), span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(expr.id), + scope: self.tcx.map.get_enclosing_scope(expr.id).unwrap_or(0), ref_id: f.id, })); } @@ -354,13 +354,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } ast::ExprStruct(ref path, _, _) => { - let ty = &ty::expr_ty_adjusted(&self.tcx, expr).sty; + let ty = &self.tcx.expr_ty_adjusted(expr).sty; match *ty { ty::TyStruct(def_id, _) => { let sub_span = self.span_utils.span_for_last_ident(path.span); Some(Data::TypeRefData(TypeRefData { span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(expr.id), + scope: self.tcx.map.get_enclosing_scope(expr.id).unwrap_or(0), ref_id: def_id, })) } @@ -384,7 +384,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { struct_id: DefId, parent: NodeId) -> VariableRefData { - let fields = ty::lookup_struct_fields(&self.tcx, struct_id); + let fields = self.tcx.lookup_struct_fields(struct_id); let field_name = get_ident(field_ref.ident.node).to_string(); for f in &fields { if f.name == field_ref.ident.node.name { diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 4df10ee3d098e..c2397ec31cffa 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -195,6 +195,7 @@ use middle::check_match; use middle::const_eval; use middle::def::{self, DefMap}; use middle::expr_use_visitor as euv; +use middle::infer; use middle::lang_items::StrEqFnLangItem; use middle::mem_categorization as mc; use middle::pat_util::*; @@ -214,7 +215,7 @@ use trans::monomorphize; use trans::tvec; use trans::type_of; use middle::ty::{self, Ty}; -use session::config::{NoDebugInfo, FullDebugInfo}; +use session::config::NoDebugInfo; use util::common::indenter; use util::nodemap::FnvHashMap; use util::ppaux; @@ -235,7 +236,7 @@ struct ConstantExpr<'a>(&'a ast::Expr); impl<'a> ConstantExpr<'a> { fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool { match const_eval::compare_lit_exprs(tcx, self.0, other.0, None, - |id| {ty::node_id_item_substs(tcx, id).substs}) { + |id| {tcx.node_id_item_substs(id).substs}) { Some(result) => result == Ordering::Equal, None => panic!("compare_list_exprs: type mismatch"), } @@ -279,7 +280,7 @@ impl<'a, 'tcx> Opt<'a, 'tcx> { let ccx = bcx.ccx(); match *self { ConstantValue(ConstantExpr(lit_expr), _) => { - let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_expr.id); + let lit_ty = bcx.tcx().node_id_to_type(lit_expr.id); let (llval, _) = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs, None); let lit_datum = immediate_rvalue(llval, lit_ty); let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx)); @@ -562,7 +563,7 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>( check_match::Constructor::Variant(def_id) }; - let param_env = ty::empty_parameter_environment(bcx.tcx()); + let param_env = bcx.tcx().empty_parameter_environment(); let mcx = check_match::MatchCheckCtxt { tcx: bcx.tcx(), param_env: param_env, @@ -603,7 +604,7 @@ fn get_branches<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let opt_def = tcx.def_map.borrow().get(&cur.id).map(|d| d.full_def()); match opt_def { Some(def::DefVariant(enum_id, var_id, _)) => { - let variant = ty::enum_variant_with_id(tcx, enum_id, var_id); + let variant = tcx.enum_variant_with_id(enum_id, var_id); Variant(variant.disr_val, adt::represent_node(bcx, cur.id), var_id, @@ -662,16 +663,20 @@ fn bind_subslice_pat(bcx: Block, offset_right: usize) -> ValueRef { let _icx = push_ctxt("match::bind_subslice_pat"); let vec_ty = node_id_type(bcx, pat_id); - let unit_ty = ty::sequence_element_type(bcx.tcx(), ty::type_content(vec_ty)); + let vec_ty_contents = match vec_ty.sty { + ty::TyBox(ty) => ty, + ty::TyRef(_, mt) | ty::TyRawPtr(mt) => mt.ty, + _ => vec_ty + }; + let unit_ty = vec_ty_contents.sequence_element_type(bcx.tcx()); let vec_datum = match_datum(val, vec_ty); let (base, len) = vec_datum.get_vec_base_and_len(bcx); let slice_begin = InBoundsGEP(bcx, base, &[C_uint(bcx.ccx(), offset_left)]); let slice_len_offset = C_uint(bcx.ccx(), offset_left + offset_right); let slice_len = Sub(bcx, len, slice_len_offset, DebugLoc::None); - let slice_ty = ty::mk_slice(bcx.tcx(), - bcx.tcx().mk_region(ty::ReStatic), - ty::mt {ty: unit_ty, mutbl: ast::MutImmutable}); + let slice_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), + bcx.tcx().mk_slice(unit_ty)); let scratch = rvalue_scratch_datum(bcx, slice_ty, ""); Store(bcx, slice_begin, GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_ADDR])); @@ -836,7 +841,7 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, } let _icx = push_ctxt("compare_values"); - if ty::type_is_scalar(rhs_t) { + if rhs_t.is_scalar() { let cmp = compare_scalar_types(cx, lhs, rhs, rhs_t, ast::BiEq, debug_loc); return Result::new(cx, cmp); } @@ -849,9 +854,7 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, // NOTE: cast &[u8] and &[u8; N] to &str and abuse the str_eq lang item, // which calls memcmp(). let pat_len = val_ty(rhs).element_type().array_length(); - let ty_str_slice = ty::mk_str_slice(cx.tcx(), - cx.tcx().mk_region(ty::ReStatic), - ast::MutImmutable); + let ty_str_slice = cx.tcx().mk_static_str(); let rhs_str = alloc_ty(cx, ty_str_slice, "rhs_str"); Store(cx, GEPi(cx, rhs, &[0, 0]), expr::get_dataptr(cx, rhs_str)); @@ -1058,14 +1061,14 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, .unwrap_or(DUMMY_NODE_ID); let left_ty = if pat_id == DUMMY_NODE_ID { - ty::mk_nil(tcx) + tcx.mk_nil() } else { node_id_type(bcx, pat_id) }; let mcx = check_match::MatchCheckCtxt { tcx: bcx.tcx(), - param_env: ty::empty_parameter_environment(bcx.tcx()), + param_env: bcx.tcx().empty_parameter_environment(), }; let adt_vals = if any_irrefutable_adt_pat(bcx.tcx(), m, col) { let repr = adt::represent_type(bcx.ccx(), left_ty); @@ -1088,9 +1091,9 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // The last field is technically unsized but // since we can only ever match that field behind // a reference we construct a fat ptr here. - let fields = ty::lookup_struct_fields(bcx.tcx(), def_id); + let fields = bcx.tcx().lookup_struct_fields(def_id); let unsized_ty = fields.iter().last().map(|field| { - let fty = ty::lookup_field_type(bcx.tcx(), def_id, field.id, substs); + let fty = bcx.tcx().lookup_field_type(def_id, field.id, substs); monomorphize::normalize_associated_type(bcx.tcx(), &fty) }).unwrap(); let llty = type_of::type_of(bcx.ccx(), unsized_ty); @@ -1140,7 +1143,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, match opts[0] { ConstantValue(..) | ConstantRange(..) => { test_val = load_if_immediate(bcx, val, left_ty); - kind = if ty::type_is_integral(left_ty) { + kind = if left_ty.is_integral() { Switch } else { Compare @@ -1348,7 +1351,8 @@ fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool reassigned: false }; { - let mut visitor = euv::ExprUseVisitor::new(&mut rc, bcx); + let infcx = infer::new_infer_ctxt(bcx.tcx(), &bcx.tcx().tables, None, false); + let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx); visitor.walk_expr(body); } rc.reassigned @@ -1407,13 +1411,13 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat, let variable_ty = node_id_type(bcx, p_id); let llvariable_ty = type_of::type_of(ccx, variable_ty); let tcx = bcx.tcx(); - let param_env = ty::empty_parameter_environment(tcx); + let param_env = tcx.empty_parameter_environment(); let llmatch; let trmode; match bm { ast::BindByValue(_) - if !ty::type_moves_by_default(¶m_env, span, variable_ty) || reassigned => + if !variable_ty.moves_by_default(¶m_env, span) || reassigned => { llmatch = alloca_no_lifetime(bcx, llvariable_ty.ptr_to(), @@ -1466,7 +1470,7 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>, } let t = node_id_type(bcx, discr_expr.id); - let chk = if ty::type_is_empty(tcx, t) { + let chk = if t.is_empty(tcx) { Unreachable } else { Infallible @@ -1596,54 +1600,6 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -/// Generates code for argument patterns like `fn foo(: T)`. -/// Creates entries in the `lllocals` map for each of the bindings -/// in `pat`. -/// -/// # Arguments -/// -/// - `pat` is the argument pattern -/// - `llval` is a pointer to the argument value (in other words, -/// if the argument type is `T`, then `llval` is a `T*`). In some -/// cases, this code may zero out the memory `llval` points at. -pub fn store_arg<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - pat: &ast::Pat, - arg: Datum<'tcx, Rvalue>, - arg_scope: cleanup::ScopeId) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("match::store_arg"); - - match simple_identifier(&*pat) { - Some(ident) => { - // Generate nicer LLVM for the common case of fn a pattern - // like `x: T` - let arg_ty = node_id_type(bcx, pat.id); - if type_of::arg_is_indirect(bcx.ccx(), arg_ty) - && bcx.sess().opts.debuginfo != FullDebugInfo { - // Don't copy an indirect argument to an alloca, the caller - // already put it in a temporary alloca and gave it up, unless - // we emit extra-debug-info, which requires local allocas :(. - let arg_val = arg.add_clean(bcx.fcx, arg_scope); - bcx.fcx.lllocals.borrow_mut() - .insert(pat.id, Datum::new(arg_val, arg_ty, Lvalue)); - bcx - } else { - mk_binding_alloca( - bcx, pat.id, ident.name, arg_scope, arg, - |arg, bcx, llval, _| arg.store_to(bcx, llval)) - } - } - - None => { - // General path. Copy out the values that are used in the - // pattern. - let arg = unpack_datum!( - bcx, arg.to_lvalue_datum_in_scope(bcx, "__arg", arg_scope)); - bind_irrefutable_pat(bcx, pat, arg.val, arg_scope) - } - } -} - fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, p_id: ast::NodeId, name: ast::Name, @@ -1683,7 +1639,7 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, /// - bcx: starting basic block context /// - pat: the irrefutable pattern being matched. /// - val: the value being matched -- must be an lvalue (by ref, with cleanup) -fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat, val: ValueRef, cleanup_scope: cleanup::ScopeId) @@ -1745,9 +1701,7 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match opt_def { Some(def::DefVariant(enum_id, var_id, _)) => { let repr = adt::represent_node(bcx, pat.id); - let vinfo = ty::enum_variant_with_id(ccx.tcx(), - enum_id, - var_id); + let vinfo = ccx.tcx().enum_variant_with_id(enum_id, var_id); let args = extract_variant_args(bcx, &*repr, vinfo.disr_val, @@ -1787,7 +1741,7 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); expr::with_field_tys(tcx, pat_ty, Some(pat.id), |discr, field_tys| { for f in fields { - let ix = ty::field_idx_strict(tcx, f.node.ident.name, field_tys); + let ix = tcx.field_idx_strict(f.node.ident.name, field_tys); let fldptr = adt::trans_field_ptr(bcx, &*pat_repr, val, discr, ix); bcx = bind_irrefutable_pat(bcx, &*f.node.pat, fldptr, cleanup_scope); diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 2a1c2457b9d32..eca9891c57cb7 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -50,7 +50,8 @@ use std::rc::Rc; use llvm::{ValueRef, True, IntEQ, IntNE}; use back::abi::FAT_PTR_ADDR; use middle::subst; -use middle::ty::{self, Ty, ClosureTyper}; +use middle::infer; +use middle::ty::{self, Ty}; use middle::ty::Disr; use syntax::ast; use syntax::attr; @@ -209,13 +210,13 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Univariant(mk_struct(cx, &elems[..], false, t), 0) } ty::TyStruct(def_id, substs) => { - let fields = ty::lookup_struct_fields(cx.tcx(), def_id); + let fields = cx.tcx().lookup_struct_fields(def_id); let mut ftys = fields.iter().map(|field| { - let fty = ty::lookup_field_type(cx.tcx(), def_id, field.id, substs); + let fty = cx.tcx().lookup_field_type(def_id, field.id, substs); monomorphize::normalize_associated_type(cx.tcx(), &fty) }).collect::>(); - let packed = ty::lookup_packed(cx.tcx(), def_id); - let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag(); + let packed = cx.tcx().lookup_packed(def_id); + let dtor = cx.tcx().ty_dtor(def_id).has_drop_flag(); if dtor { ftys.push(cx.tcx().dtor_type()); } @@ -223,17 +224,17 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor)) } ty::TyClosure(def_id, substs) => { - let typer = NormalizingClosureTyper::new(cx.tcx()); - let upvars = typer.closure_upvars(def_id, substs).unwrap(); + let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); + let upvars = infcx.closure_upvars(def_id, substs).unwrap(); let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); Univariant(mk_struct(cx, &upvar_types[..], false, t), 0) } ty::TyEnum(def_id, substs) => { let cases = get_cases(cx.tcx(), def_id, substs); - let hint = *ty::lookup_repr_hints(cx.tcx(), def_id).get(0) + let hint = *cx.tcx().lookup_repr_hints(def_id).get(0) .unwrap_or(&attr::ReprAny); - let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag(); + let dtor = cx.tcx().ty_dtor(def_id).has_drop_flag(); if cases.is_empty() { // Uninhabitable; represent as unit @@ -261,9 +262,8 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // been rejected by a checker before this point. if !cases.iter().enumerate().all(|(i,c)| c.discr == (i as Disr)) { cx.sess().bug(&format!("non-C-like enum {} with specified \ - discriminants", - ty::item_path_str(cx.tcx(), - def_id))); + discriminants", + cx.tcx().item_path_str(def_id))); } if cases.len() == 1 { @@ -411,9 +411,9 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, // Is this the NonZero lang item wrapping a pointer or integer type? ty::TyStruct(did, substs) if Some(did) == tcx.lang_items.non_zero() => { - let nonzero_fields = ty::lookup_struct_fields(tcx, did); + let nonzero_fields = tcx.lookup_struct_fields(did); assert_eq!(nonzero_fields.len(), 1); - let nonzero_field = ty::lookup_field_type(tcx, did, nonzero_fields[0].id, substs); + let nonzero_field = tcx.lookup_field_type(did, nonzero_fields[0].id, substs); match nonzero_field.sty { ty::TyRawPtr(ty::mt { ty, .. }) if !type_is_sized(tcx, ty) => { path.push_all(&[0, FAT_PTR_ADDR]); @@ -430,9 +430,9 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, // Perhaps one of the fields of this struct is non-zero // let's recurse and find out ty::TyStruct(def_id, substs) => { - let fields = ty::lookup_struct_fields(tcx, def_id); + let fields = tcx.lookup_struct_fields(def_id); for (j, field) in fields.iter().enumerate() { - let field_ty = ty::lookup_field_type(tcx, def_id, field.id, substs); + let field_ty = tcx.lookup_field_type(def_id, field.id, substs); if let Some(mut fpath) = find_discr_field_candidate(tcx, field_ty, path.clone()) { fpath.push(j); return Some(fpath); @@ -444,8 +444,8 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, // Perhaps one of the upvars of this struct is non-zero // Let's recurse and find out! ty::TyClosure(def_id, substs) => { - let typer = NormalizingClosureTyper::new(tcx); - let upvars = typer.closure_upvars(def_id, substs).unwrap(); + let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables); + let upvars = infcx.closure_upvars(def_id, substs).unwrap(); let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); for (j, &ty) in upvar_types.iter().enumerate() { @@ -504,7 +504,7 @@ fn get_cases<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: ast::DefId, substs: &subst::Substs<'tcx>) -> Vec> { - ty::enum_variants(tcx, def_id).iter().map(|vi| { + tcx.enum_variants(def_id).iter().map(|vi| { let arg_tys = vi.args.iter().map(|&raw_ty| { monomorphize::apply_param_substs(tcx, substs, &raw_ty) }).collect(); @@ -623,8 +623,8 @@ fn bounds_usable(cx: &CrateContext, ity: IntType, bounds: &IntBounds) -> bool { pub fn ty_of_inttype<'tcx>(tcx: &ty::ctxt<'tcx>, ity: IntType) -> Ty<'tcx> { match ity { - attr::SignedInt(t) => ty::mk_mach_int(tcx, t), - attr::UnsignedInt(t) => ty::mk_mach_uint(tcx, t) + attr::SignedInt(t) => tcx.mk_mach_int(t), + attr::UnsignedInt(t) => tcx.mk_mach_uint(t) } } @@ -1078,7 +1078,7 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, -> datum::DatumBlock<'blk, 'tcx, datum::Expr> { let tcx = bcx.tcx(); - let ptr_ty = ty::mk_imm_ptr(bcx.tcx(), tcx.dtor_type()); + let ptr_ty = bcx.tcx().mk_imm_ptr(tcx.dtor_type()); match *r { Univariant(ref st, dtor) if dtor_active(dtor) => { let flag_ptr = GEPi(bcx, val, &[0, st.fields.len() - 1]); diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index 39e5670c975e0..25cde149df109 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -11,7 +11,8 @@ use libc::{c_uint, c_ulonglong}; use llvm::{self, ValueRef, AttrHelper}; -use middle::ty::{self, ClosureTyper}; +use middle::ty; +use middle::infer; use session::config::NoDebugInfo; use syntax::abi; use syntax::ast; @@ -145,15 +146,15 @@ 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::TyBareFn(_, ref f) => (&f.sig, f.abi, None), ty::TyClosure(closure_did, substs) => { - let typer = common::NormalizingClosureTyper::new(ccx.tcx()); - function_type = typer.closure_type(closure_did, substs); + let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); + 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)) } _ => ccx.sess().bug("expected closure or function.") }; - let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig); + let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); let mut attrs = llvm::AttrBuilder::new(); let ret_ty = fn_sig.output; @@ -262,7 +263,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); } else { attrs.arg(idx, llvm::NonNullAttribute); - if ty::type_is_trait(inner) { + if inner.is_trait() { attrs.arg(idx + 1, llvm::NonNullAttribute); } } @@ -274,7 +275,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as // both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely // on memory dependencies rather than pointer equality - let interior_unsafe = ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe(); + let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe(); if mt.mutbl == ast::MutMutable || !interior_unsafe { attrs.arg(idx, llvm::Attribute::NoAlias); @@ -291,7 +292,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); } else { attrs.arg(idx, llvm::NonNullAttribute); - if ty::type_is_trait(mt.ty) { + if mt.ty.is_trait() { attrs.arg(idx + 1, llvm::NonNullAttribute); } } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 461739a362d30..edb61b0d3cf38 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -37,12 +37,14 @@ use llvm; use metadata::{csearch, encoder, loader}; use middle::astencode; use middle::cfg; +use middle::infer; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::weak_lang_items; +use middle::pat_util::simple_identifier; use middle::subst::Substs; -use middle::ty::{self, Ty, ClosureTyper, type_is_simd, simd_size}; +use middle::ty::{self, Ty, HasTypeFlags}; use rustc::ast_map; -use session::config::{self, NoDebugInfo}; +use session::config::{self, NoDebugInfo, FullDebugInfo}; use session::Session; use trans::_match; use trans::adt; @@ -202,17 +204,17 @@ pub fn self_type_for_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let closure_kind = ccx.tcx().closure_kind(closure_id); match closure_kind { ty::FnClosureKind => { - ty::mk_imm_rptr(ccx.tcx(), ccx.tcx().mk_region(ty::ReStatic), fn_ty) + ccx.tcx().mk_imm_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty) } ty::FnMutClosureKind => { - ty::mk_mut_rptr(ccx.tcx(), ccx.tcx().mk_region(ty::ReStatic), fn_ty) + ccx.tcx().mk_mut_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty) } ty::FnOnceClosureKind => fn_ty } } pub fn kind_for_closure(ccx: &CrateContext, closure_id: ast::DefId) -> ty::ClosureKind { - *ccx.tcx().closure_kinds.borrow().get(&closure_id).unwrap() + *ccx.tcx().tables.borrow().closure_kinds.get(&closure_id).unwrap() } pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, @@ -232,7 +234,7 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, // don't do this then linker errors can be generated where the linker // complains that one object files has a thread local version of the // symbol and another one doesn't. - for attr in ty::get_attrs(ccx.tcx(), did).iter() { + for attr in ccx.tcx().get_attrs(did).iter() { if attr.check_name("thread_local") { llvm::set_thread_local(c, true); } @@ -434,8 +436,8 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, } ty::TyClosure(def_id, substs) => { let repr = adt::represent_type(cx.ccx(), t); - let typer = common::NormalizingClosureTyper::new(cx.tcx()); - let upvars = typer.closure_upvars(def_id, substs).unwrap(); + let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); + let upvars = infcx.closure_upvars(def_id, substs).unwrap(); for (i, upvar) in upvars.iter().enumerate() { let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i); cx = f(cx, llupvar, upvar.ty); @@ -443,11 +445,11 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, } ty::TyArray(_, n) => { let (base, len) = tvec::get_fixed_base_and_len(cx, data_ptr, n); - let unit_ty = ty::sequence_element_type(cx.tcx(), t); + let unit_ty = t.sequence_element_type(cx.tcx()); cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f); } ty::TySlice(_) | ty::TyStr => { - let unit_ty = ty::sequence_element_type(cx.tcx(), t); + let unit_ty = t.sequence_element_type(cx.tcx()); cx = tvec::iter_vec_raw(cx, data_ptr, unit_ty, info.unwrap(), f); } ty::TyTuple(ref args) => { @@ -462,7 +464,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, let ccx = fcx.ccx; let repr = adt::represent_type(ccx, t); - let variants = ty::enum_variants(ccx.tcx(), tid); + let variants = ccx.tcx().enum_variants(tid); let n_variants = (*variants).len(); // NB: we must hit the discriminant first so that structural @@ -626,9 +628,9 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>( let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0, false); (ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), false) } - ty::TyStruct(_, _) if type_is_simd(cx.tcx(), rhs_t) => { + ty::TyStruct(_, _) if rhs_t.is_simd(cx.tcx()) => { let mut res = C_bool(cx.ccx(), false); - for i in 0 .. simd_size(cx.tcx(), rhs_t) { + for i in 0 .. rhs_t.simd_size(cx.tcx()) { res = Or(cx, res, IsNull(cx, ExtractElement(cx, rhs, C_int(cx.ccx(), i as i64))), debug_loc); @@ -805,13 +807,13 @@ pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, } } - let val = if ty::type_is_bool(t) { + let val = if t.is_bool() { LoadRangeAssert(cx, ptr, 0, 2, llvm::False) - } else if ty::type_is_char(t) { + } else if t.is_char() { // a char is a Unicode codepoint, and so takes values from 0 // to 0x10FFFF inclusive only. LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False) - } else if (ty::type_is_region_ptr(t) || ty::type_is_unique(t)) + } else if (t.is_region_ptr() || t.is_unique()) && !common::type_is_fat_ptr(cx.tcx(), t) { LoadNonNull(cx, ptr) } else { @@ -832,14 +834,19 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t return; } - let store = Store(cx, from_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t)); - unsafe { - llvm::LLVMSetAlignment(store, type_of::align_of(cx.ccx(), t)); + if common::type_is_fat_ptr(cx.tcx(), t) { + Store(cx, ExtractValue(cx, v, abi::FAT_PTR_ADDR), expr::get_dataptr(cx, dst)); + Store(cx, ExtractValue(cx, v, abi::FAT_PTR_EXTRA), expr::get_len(cx, dst)); + } else { + let store = Store(cx, from_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t)); + unsafe { + llvm::LLVMSetAlignment(store, type_of::align_of(cx.ccx(), t)); + } } } pub fn from_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef { - if ty::type_is_bool(ty) { + if ty.is_bool() { ZExt(bcx, val, Type::i8(bcx.ccx())) } else { val @@ -847,7 +854,7 @@ pub fn from_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef { } pub fn to_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef { - if ty::type_is_bool(ty) { + if ty.is_bool() { Trunc(bcx, val, Type::i1(bcx.ccx())) } else { val @@ -953,7 +960,7 @@ pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>) { let _icx = push_ctxt("memcpy_ty"); let ccx = bcx.ccx(); - if ty::type_is_structural(t) { + if t.is_structural() { let llty = type_of::type_of(ccx, t); let llsz = llsize_of(ccx, llty); let llalign = type_of::align_of(ccx, t); @@ -1007,7 +1014,7 @@ pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, name: &str) -> let _icx = push_ctxt("alloc_ty"); let ccx = bcx.ccx(); let ty = type_of::type_of(ccx, t); - assert!(!ty::type_has_params(t)); + assert!(!t.has_param_types()); let val = alloca(bcx, ty, name); return val; } @@ -1029,6 +1036,13 @@ pub fn alloca_no_lifetime(cx: Block, ty: Type, name: &str) -> ValueRef { Alloca(cx, ty, name) } +pub fn set_value_name(val: ValueRef, name: &str) { + unsafe { + let name = CString::new(name).unwrap(); + llvm::LLVMSetValueName(val, name.as_ptr()); + } +} + // Creates the alloca slot which holds the pointer to the slot for the final return value pub fn make_return_slot_pointer<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, output_type: Ty<'tcx>) -> ValueRef { @@ -1216,7 +1230,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, llfn: llfndecl, llenv: None, llretslotptr: Cell::new(None), - param_env: ty::empty_parameter_environment(ccx.tcx()), + param_env: ccx.tcx().empty_parameter_environment(), alloca_insert_pt: Cell::new(None), llreturn: Cell::new(None), needs_ret_allocas: nested_returns, @@ -1291,78 +1305,70 @@ pub fn arg_kind<'a, 'tcx>(cx: &FunctionContext<'a, 'tcx>, t: Ty<'tcx>) } } -// work around bizarre resolve errors -pub type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>; - -// create_datums_for_fn_args: creates rvalue datums for each of the -// incoming function arguments. These will later be stored into -// appropriate lvalue datums. -pub fn create_datums_for_fn_args<'a, 'tcx>(bcx: Block<'a, 'tcx>, - arg_tys: &[Ty<'tcx>]) - -> Vec> { +// create_datums_for_fn_args: creates lvalue datums for each of the +// incoming function arguments. +pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, + args: &[ast::Arg], + arg_tys: &[Ty<'tcx>], + has_tupled_arg: bool, + arg_scope: cleanup::CustomScopeIndex) + -> Block<'a, 'tcx> { let _icx = push_ctxt("create_datums_for_fn_args"); let fcx = bcx.fcx; + let arg_scope_id = cleanup::CustomScope(arg_scope); // Return an array wrapping the ValueRefs that we get from `get_param` for // each argument into datums. - let mut i = fcx.arg_offset() as c_uint; - arg_tys.iter().map(|&arg_ty| { - if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { - let llty = type_of::type_of(bcx.ccx(), arg_ty); - let data = get_param(fcx.llfn, i); - let extra = get_param(fcx.llfn, i + 1); - let fat_ptr = expr::make_fat_ptr(bcx, llty, data, extra); - i += 2; - datum::Datum::new(fat_ptr, arg_ty, datum::Rvalue { mode: datum::ByValue }) - } else { - let llarg = get_param(fcx.llfn, i); - i += 1; - datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty)) - } - }).collect() -} - -/// Creates rvalue datums for each of the incoming function arguments and -/// tuples the arguments. These will later be stored into appropriate lvalue -/// datums. -/// -/// FIXME(pcwalton): Reduce the amount of code bloat this is responsible for. -fn create_datums_for_fn_args_under_call_abi<'blk, 'tcx>( - mut bcx: Block<'blk, 'tcx>, - arg_scope: cleanup::CustomScopeIndex, - arg_tys: &[Ty<'tcx>]) - -> Vec> { - let mut result = Vec::new(); - let mut idx = bcx.fcx.arg_offset() as c_uint; + // + // For certain mode/type combinations, the raw llarg values are passed + // by value. However, within the fn body itself, we want to always + // have all locals and arguments be by-ref so that we can cancel the + // cleanup and for better interaction with LLVM's debug info. So, if + // the argument would be passed by value, we store it into an alloca. + // This alloca should be optimized away by LLVM's mem-to-reg pass in + // the event it's not truly needed. + let mut idx = fcx.arg_offset() as c_uint; for (i, &arg_ty) in arg_tys.iter().enumerate() { - if i < arg_tys.len() - 1 { - // Regular argument. - result.push(if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { - let llty = type_of::type_of(bcx.ccx(), arg_ty); - let data = get_param(bcx.fcx.llfn, idx); - let extra = get_param(bcx.fcx.llfn, idx + 1); + let arg_datum = if !has_tupled_arg || i < arg_tys.len() - 1 { + if type_of::arg_is_indirect(bcx.ccx(), arg_ty) + && bcx.sess().opts.debuginfo != FullDebugInfo { + // Don't copy an indirect argument to an alloca, the caller + // already put it in a temporary alloca and gave it up, unless + // we emit extra-debug-info, which requires local allocas :(. + let llarg = get_param(fcx.llfn, idx); + idx += 1; + bcx.fcx.schedule_lifetime_end(arg_scope_id, llarg); + bcx.fcx.schedule_drop_mem(arg_scope_id, llarg, arg_ty); + + datum::Datum::new(llarg, arg_ty, datum::Lvalue) + } else if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { + let data = get_param(fcx.llfn, idx); + let extra = get_param(fcx.llfn, idx + 1); idx += 2; - let fat_ptr = expr::make_fat_ptr(bcx, llty, data, extra); - datum::Datum::new(fat_ptr, arg_ty, datum::Rvalue { mode: datum::ByValue }) + unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", + arg_scope_id, (data, extra), + |(data, extra), bcx, dst| { + Store(bcx, data, expr::get_dataptr(bcx, dst)); + Store(bcx, extra, expr::get_len(bcx, dst)); + bcx + })) } else { - let val = get_param(bcx.fcx.llfn, idx); + let llarg = get_param(fcx.llfn, idx); idx += 1; - datum::Datum::new(val, arg_ty, arg_kind(bcx.fcx, arg_ty)) - }); - - continue - } - - // This is the last argument. Tuple it. - match arg_ty.sty { - ty::TyTuple(ref tupled_arg_tys) => { - let tuple_args_scope_id = cleanup::CustomScope(arg_scope); - let tuple = + let tmp = datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty)); + unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", + arg_scope_id, tmp, + |tmp, bcx, dst| tmp.store_to(bcx, dst))) + } + } else { + // FIXME(pcwalton): Reduce the amount of code bloat this is responsible for. + match arg_ty.sty { + ty::TyTuple(ref tupled_arg_tys) => { unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "tupled_args", - tuple_args_scope_id, + arg_scope_id, (), |(), mut bcx, @@ -1386,46 +1392,27 @@ fn create_datums_for_fn_args_under_call_abi<'blk, 'tcx>( }; } bcx - })); - let tuple = unpack_datum!(bcx, - tuple.to_expr_datum() - .to_rvalue_datum(bcx, - "argtuple")); - result.push(tuple); - } - _ => { - bcx.tcx().sess.bug("last argument of a function with \ - `rust-call` ABI isn't a tuple?!") + })) + } + _ => { + bcx.tcx().sess.bug("last argument of a function with \ + `rust-call` ABI isn't a tuple?!") + } } }; - } - - result -} - -fn copy_args_to_allocas<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - arg_scope: cleanup::CustomScopeIndex, - args: &[ast::Arg], - arg_datums: Vec>) - -> Block<'blk, 'tcx> { - debug!("copy_args_to_allocas"); - - let _icx = push_ctxt("copy_args_to_allocas"); - let mut bcx = bcx; - - let arg_scope_id = cleanup::CustomScope(arg_scope); - - for (i, arg_datum) in arg_datums.into_iter().enumerate() { - // For certain mode/type combinations, the raw llarg values are passed - // by value. However, within the fn body itself, we want to always - // have all locals and arguments be by-ref so that we can cancel the - // cleanup and for better interaction with LLVM's debug info. So, if - // the argument would be passed by value, we store it into an alloca. - // This alloca should be optimized away by LLVM's mem-to-reg pass in - // the event it's not truly needed. - - bcx = _match::store_arg(bcx, &*args[i].pat, arg_datum, arg_scope_id); + let pat = &*args[i].pat; + bcx = if let Some(ident) = simple_identifier(&*pat) { + // Generate nicer LLVM for the common case of fn a pattern + // like `x: T` + set_value_name(arg_datum.val, &bcx.name(ident.name)); + bcx.fcx.lllocals.borrow_mut().insert(pat.id, arg_datum); + bcx + } else { + // General path. Copy out the values that are used in the + // pattern. + _match::bind_irrefutable_pat(bcx, pat, arg_datum.val, arg_scope_id) + }; debuginfo::create_argument_metadata(bcx, &args[i]); } @@ -1572,16 +1559,6 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, decl.inputs.iter() .map(|arg| node_id_type(bcx, arg.id)) .collect::>(); - let monomorphized_arg_types = match closure_env { - closure::ClosureEnv::NotClosure => { - monomorphized_arg_types - } - - // Tuple up closure argument types for the "rust-call" ABI. - closure::ClosureEnv::Closure(_) => { - vec![ty::mk_tup(ccx.tcx(), monomorphized_arg_types)] - } - }; for monomorphized_arg_type in &monomorphized_arg_types { debug!("trans_closure: monomorphized_arg_type: {:?}", monomorphized_arg_type); @@ -1589,17 +1566,13 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("trans_closure: function lltype: {}", bcx.fcx.ccx.tn().val_to_string(bcx.fcx.llfn)); - let arg_datums = match closure_env { - closure::ClosureEnv::NotClosure if abi == RustCall => { - create_datums_for_fn_args_under_call_abi(bcx, arg_scope, &monomorphized_arg_types[..]) - } - _ => { - let arg_tys = untuple_arguments_if_necessary(ccx, &monomorphized_arg_types, abi); - create_datums_for_fn_args(bcx, &arg_tys) - } + let has_tupled_arg = match closure_env { + closure::ClosureEnv::NotClosure => abi == RustCall, + _ => false }; - bcx = copy_args_to_allocas(bcx, arg_scope, &decl.inputs, arg_datums); + bcx = create_datums_for_fn_args(bcx, &decl.inputs, &monomorphized_arg_types, + has_tupled_arg, arg_scope); bcx = closure_env.load(bcx, cleanup::CustomScope(arg_scope)); @@ -1668,9 +1641,9 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let _s = StatRecorder::new(ccx, ccx.tcx().map.path_to_string(id).to_string()); debug!("trans_fn(param_substs={:?})", param_substs); let _icx = push_ctxt("trans_fn"); - let fn_ty = ty::node_id_to_type(ccx.tcx(), id); - let output_type = ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fn_ty)); - let abi = ty::ty_fn_abi(fn_ty); + let fn_ty = ccx.tcx().node_id_to_type(id); + let output_type = ccx.tcx().erase_late_bound_regions(&fn_ty.fn_ret()); + let abi = fn_ty.fn_abi(); trans_closure(ccx, decl, body, llfndecl, param_substs, id, attrs, output_type, abi, closure::ClosureEnv::NotClosure); } @@ -1704,7 +1677,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let result_ty = match ctor_ty.sty { ty::TyBareFn(_, ref bft) => { - ty::erase_late_bound_regions(bcx.tcx(), &bft.sig.output()).unwrap() + bcx.tcx().erase_late_bound_regions(&bft.sig.output()).unwrap() } _ => ccx.sess().bug( &format!("trans_enum_variant_constructor: \ @@ -1777,12 +1750,12 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx disr: ty::Disr, param_substs: &'tcx Substs<'tcx>, llfndecl: ValueRef) { - let ctor_ty = ty::node_id_to_type(ccx.tcx(), ctor_id); + let ctor_ty = ccx.tcx().node_id_to_type(ctor_id); let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty); let result_ty = match ctor_ty.sty { ty::TyBareFn(_, ref bft) => { - ty::erase_late_bound_regions(ccx.tcx(), &bft.sig.output()) + ccx.tcx().erase_late_bound_regions(&bft.sig.output()) } _ => ccx.sess().bug( &format!("trans_enum_variant_or_tuple_like_struct: \ @@ -1798,22 +1771,32 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx assert!(!fcx.needs_ret_allocas); - let arg_tys = - ty::erase_late_bound_regions( - ccx.tcx(), &ty::ty_fn_args(ctor_ty)); - - let arg_datums = create_datums_for_fn_args(bcx, &arg_tys[..]); + let arg_tys = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_args()); if !type_is_zero_size(fcx.ccx, result_ty.unwrap()) { let dest = fcx.get_ret_slot(bcx, result_ty, "eret_slot"); let repr = adt::represent_type(ccx, result_ty.unwrap()); - for (i, arg_datum) in arg_datums.into_iter().enumerate() { + let mut llarg_idx = fcx.arg_offset() as c_uint; + for (i, arg_ty) in arg_tys.into_iter().enumerate() { let lldestptr = adt::trans_field_ptr(bcx, &*repr, dest, disr, i); - arg_datum.store_to(bcx, lldestptr); + if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { + Store(bcx, get_param(fcx.llfn, llarg_idx), expr::get_dataptr(bcx, lldestptr)); + Store(bcx, get_param(fcx.llfn, llarg_idx + 1), expr::get_len(bcx, lldestptr)); + llarg_idx += 2; + } else { + let arg = get_param(fcx.llfn, llarg_idx); + llarg_idx += 1; + + if arg_is_indirect(ccx, arg_ty) { + memcpy_ty(bcx, lldestptr, arg, arg_ty); + } else { + store_ty(bcx, arg, lldestptr, arg_ty); + } + } } adt::trans_set_discr(bcx, &*repr, dest, disr); } @@ -1836,7 +1819,7 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span, return } - let ty = ty::node_id_to_type(ccx.tcx(), id); + let ty = ccx.tcx().node_id_to_type(id); let avar = adt::represent_type(ccx, ty); match *avar { adt::General(_, ref variants, _) => { @@ -2035,7 +2018,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { // error in trans. This is used to write compile-fail tests // that actually test that compilation succeeds without // reporting an error. - if ty::has_attr(ccx.tcx(), local_def(item.id), "rustc_error") { + if ccx.tcx().has_attr(local_def(item.id), "rustc_error") { ccx.tcx().sess.span_fatal(item.span, "compilation successful"); } } @@ -2115,7 +2098,7 @@ pub fn register_fn_llvmty(ccx: &CrateContext, debug!("register_fn_llvmty id={} sym={}", node_id, sym); let llfn = declare::define_fn(ccx, &sym[..], cc, llfty, - ty::FnConverging(ty::mk_nil(ccx.tcx()))).unwrap_or_else(||{ + ty::FnConverging(ccx.tcx().mk_nil())).unwrap_or_else(||{ ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym)); }); finish_register_fn(ccx, sym, node_id, llfn); @@ -2197,7 +2180,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext, &ccx.int_type()); let llfn = declare::define_cfn(ccx, "main", llfty, - ty::mk_nil(ccx.tcx())).unwrap_or_else(||{ + ccx.tcx().mk_nil()).unwrap_or_else(||{ ccx.sess().span_err(sp, "entry symbol `main` defined multiple times"); // FIXME: We should be smart and show a better diagnostic here. ccx.sess().help("did you use #[no_mangle] on `fn main`? Use #[start] instead"); @@ -2314,7 +2297,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { debug!("get_item_val: id={} item={:?}", id, item); let val = match item { ast_map::NodeItem(i) => { - let ty = ty::node_id_to_type(ccx.tcx(), i.id); + let ty = ccx.tcx().node_id_to_type(i.id); let sym = || exported_name(ccx, id, ty, &i.attrs); let v = match i.node { @@ -2334,7 +2317,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { unsafe { // boolean SSA values are i1, but they have to be stored in i8 slots, // otherwise some LLVM optimization passes don't work as expected - let llty = if ty::type_is_bool(ty) { + let llty = if ty.is_bool() { llvm::LLVMInt8TypeInContext(ccx.llcx()) } else { llvm::LLVMTypeOf(v) @@ -2421,7 +2404,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { match ni.node { ast::ForeignItemFn(..) => { let abi = ccx.tcx().map.get_foreign_abi(id); - let ty = ty::node_id_to_type(ccx.tcx(), ni.id); + let ty = ccx.tcx().node_id_to_type(ni.id); let name = foreign::link_name(&*ni); let llfn = foreign::register_foreign_item_fn(ccx, abi, ty, &name); attributes::from_fn_attrs(ccx, &ni.attrs, llfn); @@ -2442,7 +2425,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } }; assert!(!args.is_empty()); - let ty = ty::node_id_to_type(ccx.tcx(), id); + let ty = ccx.tcx().node_id_to_type(id); let parent = ccx.tcx().map.get_parent(id); let enm = ccx.tcx().map.expect_item(parent); let sym = exported_name(ccx, @@ -2471,7 +2454,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { }; let parent = ccx.tcx().map.get_parent(id); let struct_item = ccx.tcx().map.expect_item(parent); - let ty = ty::node_id_to_type(ccx.tcx(), ctor_id); + let ty = ccx.tcx().node_id_to_type(ctor_id); let sym = exported_name(ccx, id, ty, @@ -2503,7 +2486,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { fn register_method(ccx: &CrateContext, id: ast::NodeId, attrs: &[ast::Attribute], span: Span) -> ValueRef { - let mty = ty::node_id_to_type(ccx.tcx(), id); + let mty = ccx.tcx().node_id_to_type(id); let sym = exported_name(ccx, id, mty, &attrs); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 093b824701fa4..debc8dd59c04c 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -22,7 +22,6 @@ use arena::TypedArena; use back::link; use session; use llvm::{self, ValueRef, get_params}; -use metadata::csearch; use middle::def; use middle::subst; use middle::subst::{Subst, Substs}; @@ -49,7 +48,7 @@ use trans::meth; use trans::monomorphize; use trans::type_::Type; use trans::type_of; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags, RegionEscape}; use middle::ty::MethodCall; use rustc::ast_map; @@ -66,7 +65,7 @@ pub struct MethodData { pub enum CalleeData<'tcx> { // Constructor for enum variant/tuple-like-struct // i.e. Some, Ok - NamedTupleConstructor(subst::Substs<'tcx>, ty::Disr), + NamedTupleConstructor(ty::Disr), // Represents a (possibly monomorphized) top-level fn item or method // item. Note that this is just the fn-ptr and is not a Rust closure @@ -81,6 +80,7 @@ pub enum CalleeData<'tcx> { pub struct Callee<'blk, 'tcx: 'blk> { pub bcx: Block<'blk, 'tcx>, pub data: CalleeData<'tcx>, + pub ty: Ty<'tcx> } fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) @@ -104,11 +104,11 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr); match datum.ty.sty { ty::TyBareFn(..) => { - let llval = datum.to_llscalarish(bcx); - return Callee { + Callee { bcx: bcx, - data: Fn(llval), - }; + ty: datum.ty, + data: Fn(datum.to_llscalarish(bcx)) + } } _ => { bcx.tcx().sess.span_bug( @@ -119,12 +119,13 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) } } - fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, llfn: ValueRef) + fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Rvalue>) -> Callee<'blk, 'tcx> { - return Callee { + Callee { bcx: bcx, - data: Fn(llfn), - }; + data: Fn(datum.val), + ty: datum.ty + } } fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, @@ -143,12 +144,10 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) _ => false } } => { - let substs = common::node_id_substs(bcx.ccx(), - ExprId(ref_expr.id), - bcx.fcx.param_substs); Callee { bcx: bcx, - data: NamedTupleConstructor(substs, 0) + data: NamedTupleConstructor(0), + ty: expr_ty } } def::DefFn(did, _) if match expr_ty.sty { @@ -159,40 +158,36 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) ExprId(ref_expr.id), bcx.fcx.param_substs); let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did); - Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) } + Callee { bcx: bcx, data: Intrinsic(def_id.node, substs), ty: expr_ty } } def::DefFn(did, _) | def::DefMethod(did, def::FromImpl(_)) => { fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id), - bcx.fcx.param_substs).val) + bcx.fcx.param_substs)) } def::DefMethod(meth_did, def::FromTrait(trait_did)) => { fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(), meth_did, trait_did, ref_expr.id, - bcx.fcx.param_substs).val) + bcx.fcx.param_substs)) } def::DefVariant(tid, vid, _) => { - let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid); - let substs = common::node_id_substs(bcx.ccx(), - ExprId(ref_expr.id), - bcx.fcx.param_substs); + let vinfo = bcx.tcx().enum_variant_with_id(tid, vid); // Nullary variants are not callable assert!(!vinfo.args.is_empty()); Callee { bcx: bcx, - data: NamedTupleConstructor(substs, vinfo.disr_val) + data: NamedTupleConstructor(vinfo.disr_val), + ty: expr_ty } } def::DefStruct(_) => { - let substs = common::node_id_substs(bcx.ccx(), - ExprId(ref_expr.id), - bcx.fcx.param_substs); Callee { bcx: bcx, - data: NamedTupleConstructor(substs, 0) + data: NamedTupleConstructor(0), + ty: expr_ty } } def::DefStatic(..) | @@ -232,21 +227,6 @@ pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs) } -fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - def_id: ast::DefId, - ref_id: ast::NodeId, - substs: subst::Substs<'tcx>) - -> Callee<'blk, 'tcx> { - Callee { - bcx: bcx, - data: Fn(trans_fn_ref_with_substs(bcx.ccx(), - def_id, - ExprId(ref_id), - bcx.fcx.param_substs, - substs).val), - } -} - /// Translates an adapter that implements the `Fn` trait for a fn /// pointer. This is basically the equivalent of something like: /// @@ -277,7 +257,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( ty::FnOnceClosureKind => false, }; let bare_fn_ty_maybe_ref = if is_by_ref { - ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty) + tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), bare_fn_ty) } else { bare_fn_ty }; @@ -307,19 +287,18 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( bare_fn_ty)); } }; - let sig = ty::erase_late_bound_regions(tcx, sig); - let tuple_input_ty = ty::mk_tup(tcx, sig.inputs.to_vec()); - let tuple_fn_ty = ty::mk_bare_fn(tcx, - opt_def_id, - tcx.mk_bare_fn(ty::BareFnTy { - unsafety: ast::Unsafety::Normal, - abi: synabi::RustCall, - sig: ty::Binder(ty::FnSig { - inputs: vec![bare_fn_ty_maybe_ref, - tuple_input_ty], - output: sig.output, - variadic: false - })})); + let sig = tcx.erase_late_bound_regions(sig); + let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec()); + let tuple_fn_ty = tcx.mk_fn(opt_def_id, + tcx.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Normal, + abi: synabi::RustCall, + sig: ty::Binder(ty::FnSig { + inputs: vec![bare_fn_ty_maybe_ref, + tuple_input_ty], + output: sig.output, + variadic: false + })})); debug!("tuple_fn_ty: {:?}", tuple_fn_ty); // @@ -357,12 +336,13 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")) ); - bcx = trans_call_inner(bcx, - DebugLoc::None, - bare_fn_ty, - |bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) }, - ArgVals(&llargs[(self_idx + 1)..]), - dest).bcx; + bcx = trans_call_inner(bcx, DebugLoc::None, |bcx, _| { + Callee { + bcx: bcx, + data: Fn(llfnpointer), + ty: bare_fn_ty + } + }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; finish_fn(&fcx, bcx, sig.output, DebugLoc::None); @@ -402,22 +382,22 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( param_substs, substs); - assert!(substs.types.all(|t| !ty::type_needs_infer(*t))); - assert!(substs.types.all(|t| !ty::type_has_escaping_regions(*t))); + assert!(!substs.types.needs_infer()); + assert!(!substs.types.has_escaping_regions()); let substs = substs.erase_regions(); // Load the info for the appropriate trait if necessary. - match ty::trait_of_item(tcx, def_id) { + match tcx.trait_of_item(def_id) { None => {} Some(trait_id) => { - ty::populate_implementations_for_trait_if_necessary(tcx, trait_id) + tcx.populate_implementations_for_trait_if_necessary(trait_id) } } // We need to do a bunch of special handling for default methods. // We need to modify the def_id and our substs in order to monomorphize // the function. - let (is_default, def_id, substs) = match ty::provided_source(tcx, def_id) { + let (is_default, def_id, substs) = match tcx.provided_source(def_id) { None => { (false, def_id, tcx.mk_substs(substs)) } @@ -435,16 +415,16 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // So, what we need to do is find this substitution and // compose it with the one we already have. - let impl_id = ty::impl_or_trait_item(tcx, def_id).container() + let impl_id = tcx.impl_or_trait_item(def_id).container() .id(); - let impl_or_trait_item = ty::impl_or_trait_item(tcx, source_id); + let impl_or_trait_item = tcx.impl_or_trait_item(source_id); match impl_or_trait_item { ty::MethodTraitItem(method) => { - let trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap(); + let trait_ref = tcx.impl_trait_ref(impl_id).unwrap(); // Compute the first substitution let first_subst = - ty::make_substs_for_receiver_types(tcx, &trait_ref, &*method) + tcx.make_substs_for_receiver_types(&trait_ref, &*method) .erase_regions(); // And compose them @@ -517,9 +497,9 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // Monotype of the REFERENCE to the function (type params // are subst'd) let ref_ty = match node { - ExprId(id) => ty::node_id_to_type(tcx, id), + ExprId(id) => tcx.node_id_to_type(id), MethodCallKey(method_call) => { - tcx.method_map.borrow().get(&method_call).unwrap().ty + tcx.tables.borrow().method_map[&method_call].ty } }; let ref_ty = monomorphize::apply_param_substs(tcx, @@ -535,7 +515,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( } // Type scheme of the function item (may have type params) - let fn_type_scheme = ty::lookup_item_type(tcx, def_id); + let fn_type_scheme = tcx.lookup_item_type(def_id); let fn_type = monomorphize::normalize_associated_type(tcx, &fn_type_scheme.ty); // Find the actual function pointer. @@ -587,17 +567,16 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // ______________________________________________________________________ // Translating calls -pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>, +pub fn trans_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, call_expr: &ast::Expr, f: &ast::Expr, args: CallArgs<'a, 'tcx>, dest: expr::Dest) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_call"); - trans_call_inner(in_cx, + trans_call_inner(bcx, call_expr.debug_loc(), - common::expr_ty_adjusted(in_cx, f), - |cx, _| trans(cx, f), + |bcx, _| trans(bcx, f), args, Some(dest)).bcx } @@ -611,22 +590,9 @@ pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_method_call"); debug!("trans_method_call(call_expr={:?})", call_expr); let method_call = MethodCall::expr(call_expr.id); - let method_ty = match bcx.tcx().method_map.borrow().get(&method_call) { - Some(method) => match method.origin { - ty::MethodTraitObject(_) => match method.ty.sty { - ty::TyBareFn(_, ref fty) => { - ty::mk_bare_fn(bcx.tcx(), None, meth::opaque_method_ty(bcx.tcx(), fty)) - } - _ => method.ty - }, - _ => method.ty - }, - None => panic!("method not found in trans_method_call") - }; trans_call_inner( bcx, call_expr.debug_loc(), - common::monomorphize_type(bcx, method_ty), |cx, arg_cleanup_scope| { meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope) }, @@ -640,22 +606,18 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dest: Option, debug_loc: DebugLoc) -> Result<'blk, 'tcx> { - let fty = if did.krate == ast::LOCAL_CRATE { - ty::node_id_to_type(bcx.tcx(), did.node) - } else { - csearch::get_type(bcx.tcx(), did).ty - }; - callee::trans_call_inner(bcx, - debug_loc, - fty, - |bcx, _| { - trans_fn_ref_with_substs_to_callee(bcx, - did, - 0, - subst::Substs::trans_empty()) - }, - ArgVals(args), - dest) + callee::trans_call_inner(bcx, debug_loc, |bcx, _| { + let datum = trans_fn_ref_with_substs(bcx.ccx(), + did, + ExprId(0), + bcx.fcx.param_substs, + subst::Substs::trans_empty()); + Callee { + bcx: bcx, + data: Fn(datum.val), + ty: datum.ty + } + }, ArgVals(args), dest) } /// This behemoth of a function translates function calls. Unfortunately, in order to generate more @@ -670,7 +632,6 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// somewhere. Nonetheless we return the actual return value of the function. pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, debug_loc: DebugLoc, - callee_ty: Ty<'tcx>, get_callee: F, args: CallArgs<'a, 'tcx>, dest: Option) @@ -691,20 +652,20 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope)); let mut bcx = callee.bcx; - let (abi, ret_ty) = match callee_ty.sty { + let (abi, ret_ty) = match callee.ty.sty { ty::TyBareFn(_, ref f) => { - let output = ty::erase_late_bound_regions(bcx.tcx(), &f.sig.output()); + let output = bcx.tcx().erase_late_bound_regions(&f.sig.output()); (f.abi, output) } _ => panic!("expected bare rust fn or closure in trans_call_inner") }; - let (llfn, llenv, llself) = match callee.data { + let (llfn, llself) = match callee.data { Fn(llfn) => { - (llfn, None, None) + (llfn, None) } TraitItem(d) => { - (d.llfn, None, Some(d.llself)) + (d.llfn, Some(d.llself)) } Intrinsic(node, substs) => { assert!(abi == synabi::RustIntrinsic); @@ -717,18 +678,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } }; - return intrinsic::trans_intrinsic_call(bcx, node, callee_ty, + return intrinsic::trans_intrinsic_call(bcx, node, callee.ty, arg_cleanup_scope, args, dest.unwrap(), substs, call_info); } - NamedTupleConstructor(substs, disr) => { + NamedTupleConstructor(disr) => { assert!(dest.is_some()); fcx.pop_custom_cleanup_scope(arg_cleanup_scope); - let ctor_ty = callee_ty.subst(bcx.tcx(), &substs); return base::trans_named_tuple_constructor(bcx, - ctor_ty, + callee.ty, disr, args, dest.unwrap(), @@ -749,7 +709,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, expr::Ignore => { let ret_ty = match ret_ty { ty::FnConverging(ret_ty) => ret_ty, - ty::FnDiverging => ty::mk_nil(ccx.tcx()) + ty::FnDiverging => ccx.tcx().mk_nil() }; if !is_rust_fn || type_of::return_uses_outptr(ccx, ret_ty) || @@ -795,17 +755,15 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } } - // Push the environment (or a trait object's self). - match (llenv, llself) { - (Some(llenv), None) => llargs.push(llenv), - (None, Some(llself)) => llargs.push(llself), - _ => {} + // Push a trait object's self. + if let Some(llself) = llself { + llargs.push(llself); } // Push the arguments. bcx = trans_args(bcx, args, - callee_ty, + callee.ty, &mut llargs, cleanup::CustomScope(arg_cleanup_scope), llself.is_some(), @@ -817,7 +775,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let (llret, b) = base::invoke(bcx, llfn, &llargs[..], - callee_ty, + callee.ty, debug_loc); bcx = b; llresult = llret; @@ -846,7 +804,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, }; bcx = trans_args(bcx, args, - callee_ty, + callee.ty, &mut llargs, cleanup::CustomScope(arg_cleanup_scope), false, @@ -854,7 +812,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); bcx = foreign::trans_native_call(bcx, - callee_ty, + callee.ty, llfn, opt_llretslot.unwrap(), &llargs[..], @@ -895,11 +853,11 @@ pub enum CallArgs<'a, 'tcx> { // value. ArgVals(&'a [ValueRef]), - // For overloaded operators: `(lhs, Vec(rhs, rhs_id), autoref)`. `lhs` + // For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs` // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of - // the right-hand-side arguments (if any). `autoref` indicates whether the `rhs` + // the right-hand-side argument (if any). `autoref` indicates whether the `rhs` // arguments should be auto-referenced - ArgOverloadedOp(Datum<'tcx, Expr>, Vec<(Datum<'tcx, Expr>, ast::NodeId)>, bool), + ArgOverloadedOp(Datum<'tcx, Expr>, Option<(Datum<'tcx, Expr>, ast::NodeId)>, bool), // Supply value of arguments as a list of expressions that must be // translated, for overloaded call operators. @@ -915,9 +873,7 @@ fn trans_args_under_call_abi<'blk, 'tcx>( ignore_self: bool) -> Block<'blk, 'tcx> { - let args = - ty::erase_late_bound_regions( - bcx.tcx(), &ty::ty_fn_args(fn_ty)); + let args = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_args()); // Translate the `self` argument first. if !ignore_self { @@ -978,7 +934,7 @@ fn trans_overloaded_call_args<'blk, 'tcx>( ignore_self: bool) -> Block<'blk, 'tcx> { // Translate the `self` argument first. - let arg_tys = ty::erase_late_bound_regions(bcx.tcx(), &ty::ty_fn_args(fn_ty)); + let arg_tys = bcx.tcx().erase_late_bound_regions( &fn_ty.fn_args()); if !ignore_self { let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0])); bcx = trans_arg_datum(bcx, @@ -1024,8 +980,8 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, debug!("trans_args(abi={})", abi); let _icx = push_ctxt("trans_args"); - let arg_tys = ty::erase_late_bound_regions(cx.tcx(), &ty::ty_fn_args(fn_ty)); - let variadic = ty::fn_is_variadic(fn_ty); + let arg_tys = cx.tcx().erase_late_bound_regions(&fn_ty.fn_args()); + let variadic = fn_ty.fn_sig().0.variadic; let mut bcx = cx; @@ -1080,12 +1036,14 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, DontAutorefArg, llargs); - assert_eq!(arg_tys.len(), 1 + rhs.len()); - for (rhs, rhs_id) in rhs { + if let Some((rhs, rhs_id)) = rhs { + assert_eq!(arg_tys.len(), 2); bcx = trans_arg_datum(bcx, arg_tys[1], rhs, arg_cleanup_scope, if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg }, llargs); + } else { + assert_eq!(arg_tys.len(), 1); } } ArgVals(vs) => { diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 6355a713a2ce6..588e4cea5048b 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -199,7 +199,6 @@ pub struct CachedEarlyExit { pub trait Cleanup<'tcx> { fn must_unwind(&self) -> bool; - fn clean_on_unwind(&self) -> bool; fn is_lifetime_end(&self) -> bool; fn trans<'blk>(&self, bcx: Block<'blk, 'tcx>, @@ -389,7 +388,6 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { if !self.type_needs_drop(ty) { return; } let drop = box DropValue { is_immediate: false, - must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty), val: val, ty: ty, fill_on_drop: false, @@ -415,7 +413,6 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { let drop = box DropValue { is_immediate: false, - must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty), val: val, ty: ty, fill_on_drop: true, @@ -447,7 +444,6 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { let drop = box DropValue { is_immediate: false, - must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty), val: val, ty: ty, fill_on_drop: false, @@ -473,7 +469,6 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { if !self.type_needs_drop(ty) { return; } let drop = box DropValue { is_immediate: true, - must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty), val: val, ty: ty, fill_on_drop: false, @@ -780,29 +775,19 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx // // At this point, `popped_scopes` is empty, and so the final block // that we return to the user is `Cleanup(AST 24)`. - while !popped_scopes.is_empty() { - let mut scope = popped_scopes.pop().unwrap(); - - if scope.cleanups.iter().any(|c| cleanup_is_suitable_for(&**c, label)) - { - let name = scope.block_name("clean"); - debug!("generating cleanups for {}", name); - let bcx_in = self.new_block(label.is_unwind(), - &name[..], - None); - let mut bcx_out = bcx_in; - for cleanup in scope.cleanups.iter().rev() { - if cleanup_is_suitable_for(&**cleanup, label) { - bcx_out = cleanup.trans(bcx_out, - scope.debug_loc); - } - } - build::Br(bcx_out, prev_llbb, DebugLoc::None); - prev_llbb = bcx_in.llbb; - } else { - debug!("no suitable cleanups in {}", - scope.block_name("clean")); + while let Some(mut scope) = popped_scopes.pop() { + let name = scope.block_name("clean"); + debug!("generating cleanups for {}", name); + let bcx_in = self.new_block(label.is_unwind(), + &name[..], + None); + let mut bcx_out = bcx_in; + for cleanup in scope.cleanups.iter().rev() { + bcx_out = cleanup.trans(bcx_out, + scope.debug_loc); } + build::Br(bcx_out, prev_llbb, DebugLoc::None); + prev_llbb = bcx_in.llbb; scope.add_cached_early_exit(label, prev_llbb); self.push_scope(scope); @@ -856,18 +841,36 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx // this function, so we just codegen a generic reference to it. We don't // specify any of the types for the function, we just make it a symbol // that LLVM can later use. + // + // Note that MSVC is a little special here in that we don't use the + // `eh_personality` lang item at all. Currently LLVM has support for + // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the + // *name of the personality function* to decide what kind of unwind side + // tables/landing pads to emit. It looks like Dwarf is used by default, + // injecting a dependency on the `_Unwind_Resume` symbol for resuming + // an "exception", but for MSVC we want to force SEH. This means that we + // can't actually have the personality function be our standard + // `rust_eh_personality` function, but rather we wired it up to the + // CRT's custom `__C_specific_handler` personality funciton, which + // forces LLVM to consider landing pads as "landing pads for SEH". + let target = &self.ccx.sess().target.target; let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() { - Some(def_id) => { + Some(def_id) if !target.options.is_like_msvc => { callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0), pad_bcx.fcx.param_substs).val } - None => { + _ => { let mut personality = self.ccx.eh_personality().borrow_mut(); match *personality { Some(llpersonality) => llpersonality, None => { + let name = if target.options.is_like_msvc { + "__C_specific_handler" + } else { + "rust_eh_personality" + }; let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); - let f = declare::declare_cfn(self.ccx, "rust_eh_personality", fty, + let f = declare::declare_cfn(self.ccx, name, fty, self.ccx.tcx().types.i32); *personality = Some(f); f @@ -1013,7 +1016,6 @@ impl EarlyExitLabel { #[derive(Copy, Clone)] pub struct DropValue<'tcx> { is_immediate: bool, - must_unwind: bool, val: ValueRef, ty: Ty<'tcx>, fill_on_drop: bool, @@ -1022,11 +1024,7 @@ pub struct DropValue<'tcx> { impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { fn must_unwind(&self) -> bool { - self.must_unwind - } - - fn clean_on_unwind(&self) -> bool { - self.must_unwind + true } fn is_lifetime_end(&self) -> bool { @@ -1072,10 +1070,6 @@ impl<'tcx> Cleanup<'tcx> for FreeValue<'tcx> { true } - fn clean_on_unwind(&self) -> bool { - true - } - fn is_lifetime_end(&self) -> bool { false } @@ -1105,10 +1099,6 @@ impl<'tcx> Cleanup<'tcx> for LifetimeEnd { false } - fn clean_on_unwind(&self) -> bool { - true - } - fn is_lifetime_end(&self) -> bool { true } @@ -1147,11 +1137,6 @@ pub fn var_scope(tcx: &ty::ctxt, r } -fn cleanup_is_suitable_for(c: &Cleanup, - label: EarlyExitLabel) -> bool { - !label.is_unwind() || c.clean_on_unwind() -} - /////////////////////////////////////////////////////////////////////////// // These traits just exist to put the methods into this file. diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 61351847a830c..d813e9dbf40fa 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -11,7 +11,7 @@ use arena::TypedArena; use back::link::{self, mangle_internal_name_by_path_and_seq}; use llvm::{ValueRef, get_params}; -use middle::mem_categorization::Typer; +use middle::infer; use trans::adt; use trans::attributes; use trans::base::*; @@ -25,7 +25,7 @@ use trans::declare; use trans::expr; use trans::monomorphize::{self, MonoId}; use trans::type_of::*; -use middle::ty::{self, ClosureTyper}; +use middle::ty; use middle::subst::Substs; use session::config::FullDebugInfo; @@ -130,12 +130,12 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc closure_id: ast::DefId, substs: &Substs<'tcx>) -> Option> { - if !ccx.tcx().closure_kinds.borrow().contains_key(&closure_id) { + if !ccx.tcx().tables.borrow().closure_kinds.contains_key(&closure_id) { // Not a closure. return None } - let function_type = ty::node_id_to_type(ccx.tcx(), closure_id.node); + let function_type = ccx.tcx().node_id_to_type(closure_id.node); let function_type = monomorphize::apply_param_substs(ccx.tcx(), substs, &function_type); // Normalize type so differences in regions and typedefs don't cause @@ -214,13 +214,14 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, // takes the same set of type arguments as the enclosing fn, and // this function (`trans_closure`) is invoked at the point // of the closure expression. - let typer = NormalizingClosureTyper::new(tcx); - let function_type = typer.closure_type(closure_id, param_substs); + + let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); + let function_type = infcx.closure_type(closure_id, param_substs); let freevars: Vec = - ty::with_freevars(tcx, id, |fv| fv.iter().cloned().collect()); + tcx.with_freevars(id, |fv| fv.iter().cloned().collect()); - let sig = ty::erase_late_bound_regions(tcx, &function_type.sig); + let sig = tcx.erase_late_bound_regions(&function_type.sig); trans_closure(ccx, decl, @@ -358,21 +359,21 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( ccx.tn().val_to_string(llreffn)); let tcx = ccx.tcx(); - let typer = NormalizingClosureTyper::new(tcx); + let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); // Find a version of the closure type. Substitute static for the // region since it doesn't really matter. let substs = tcx.mk_substs(substs); - let closure_ty = ty::mk_closure(tcx, closure_def_id, substs); - let ref_closure_ty = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), closure_ty); + let closure_ty = tcx.mk_closure(closure_def_id, substs); + let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), closure_ty); // Make a version with the type of by-ref closure. - let ty::ClosureTy { unsafety, abi, mut sig } = typer.closure_type(closure_def_id, substs); + let ty::ClosureTy { unsafety, abi, mut sig } = infcx.closure_type(closure_def_id, substs); sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet let llref_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig.clone() }); - let llref_fn_ty = ty::mk_bare_fn(tcx, None, llref_bare_fn_ty); + let llref_fn_ty = tcx.mk_fn(None, llref_bare_fn_ty); debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", llref_fn_ty); @@ -383,7 +384,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( let llonce_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig }); - let llonce_fn_ty = ty::mk_bare_fn(tcx, None, llonce_bare_fn_ty); + let llonce_fn_ty = tcx.mk_fn(None, llonce_bare_fn_ty); // Create the by-value helper. let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); @@ -392,7 +393,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); }); - let sig = ty::erase_late_bound_regions(tcx, &llonce_bare_fn_ty.sig); + let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig); let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); fcx = new_fn_ctxt(ccx, @@ -428,12 +429,13 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( let callee_data = TraitItem(MethodData { llfn: llreffn, llself: env_datum.val }); - bcx = callee::trans_call_inner(bcx, - DebugLoc::None, - llref_fn_ty, - |bcx, _| Callee { bcx: bcx, data: callee_data }, - ArgVals(&llargs[(self_idx + 1)..]), - dest).bcx; + bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| { + Callee { + bcx: bcx, + data: callee_data, + ty: llref_fn_ty + } + }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; fcx.pop_custom_cleanup_scope(self_scope); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 403755c536d75..e1c1ac9a772eb 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -22,9 +22,7 @@ use middle::cfg; use middle::def; use middle::infer; use middle::lang_items::LangItem; -use middle::mem_categorization as mc; -use middle::region; -use middle::subst::{self, Subst, Substs}; +use middle::subst::{self, Substs}; use trans::base; use trans::build; use trans::cleanup; @@ -37,7 +35,7 @@ use trans::monomorphize; use trans::type_::Type; use trans::type_of; use middle::traits; -use middle::ty::{self, HasProjectionTypes, Ty}; +use middle::ty::{self, HasTypeFlags, Ty}; use middle::ty_fold; use middle::ty_fold::{TypeFolder, TypeFoldable}; use rustc::ast_map::{PathElem, PathName}; @@ -53,8 +51,6 @@ use syntax::ast; use syntax::codemap::{DUMMY_SP, Span}; use syntax::parse::token::InternedString; use syntax::parse::token; -use util::common::memoized; -use util::nodemap::FnvHashSet; pub use trans::context::CrateContext; @@ -86,10 +82,20 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T return t_norm; } + fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>) + -> ty::ExistentialBounds<'tcx> { + let mut s = ty_fold::super_fold_existential_bounds(self, s); + + // this annoying flag messes up trans normalization + s.region_bound_will_change = false; + + s + } + fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder where T : TypeFoldable<'tcx> { - let u = ty::anonymize_late_bound_regions(self.tcx(), t); + let u = self.tcx().anonymize_late_bound_regions(t); ty_fold::super_fold_binder(self, &u) } @@ -119,7 +125,7 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T /// Is the type's representation size known at compile time? pub fn type_is_sized<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - ty::type_is_sized(None, tcx, DUMMY_SP, ty) + ty.is_sized(&tcx.empty_parameter_environment(), DUMMY_SP) } pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { @@ -135,47 +141,6 @@ pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } } -// Some things don't need cleanups during unwinding because the -// thread can free them all at once later. Currently only things -// that only contain scalars and shared boxes can avoid unwind -// cleanups. -pub fn type_needs_unwind_cleanup<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { - return memoized(ccx.needs_unwind_cleanup_cache(), ty, |ty| { - type_needs_unwind_cleanup_(ccx.tcx(), ty, &mut FnvHashSet()) - }); - - fn type_needs_unwind_cleanup_<'tcx>(tcx: &ty::ctxt<'tcx>, - ty: Ty<'tcx>, - tycache: &mut FnvHashSet>) - -> bool - { - // Prevent infinite recursion - if !tycache.insert(ty) { - return false; - } - - let mut needs_unwind_cleanup = false; - ty::maybe_walk_ty(ty, |ty| { - needs_unwind_cleanup |= match ty.sty { - ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | - ty::TyFloat(_) | ty::TyTuple(_) | ty::TyRawPtr(_) => false, - - ty::TyEnum(did, substs) => - ty::enum_variants(tcx, did).iter().any(|v| - v.args.iter().any(|&aty| { - let t = aty.subst(tcx, substs); - type_needs_unwind_cleanup_(tcx, t, tycache) - }) - ), - - _ => true - }; - !needs_unwind_cleanup - }); - needs_unwind_cleanup - } -} - /// If `type_needs_drop` returns true, then `ty` is definitely /// non-copy and *might* have a destructor attached; if it returns /// false, then `ty` definitely has no destructor (i.e. no drop glue). @@ -183,7 +148,7 @@ pub fn type_needs_unwind_cleanup<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty< /// (Note that this implies that if `ty` has a destructor attached, /// then `type_needs_drop` will definitely return `true` for `ty`.) pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - type_needs_drop_given_env(cx, ty, &ty::empty_parameter_environment(cx)) + type_needs_drop_given_env(cx, ty, &cx.empty_parameter_environment()) } /// Core implementation of type_needs_drop, potentially making use of @@ -195,7 +160,7 @@ fn type_needs_drop_given_env<'a,'tcx>(cx: &ty::ctxt<'tcx>, // normalized version of the type, and therefore will definitely // know whether the type implements Copy (and thus needs no // cleanup/drop/zeroing) ... - let implements_copy = !ty::type_moves_by_default(¶m_env, DUMMY_SP, ty); + let implements_copy = !ty.moves_by_default(param_env, DUMMY_SP); if implements_copy { return false; } @@ -210,7 +175,7 @@ fn type_needs_drop_given_env<'a,'tcx>(cx: &ty::ctxt<'tcx>, // bound attached (see above), it is sound to treat it as having a // destructor (e.g. zero its memory on move). - let contents = ty::type_contents(cx, ty); + let contents = ty.type_contents(cx); debug!("type_needs_drop ty={:?} contents={:?}", ty, contents); contents.needs_drop(cx) } @@ -218,9 +183,9 @@ fn type_needs_drop_given_env<'a,'tcx>(cx: &ty::ctxt<'tcx>, fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { ty::TyStruct(def_id, substs) => { - let fields = ty::lookup_struct_fields(ccx.tcx(), def_id); + let fields = ccx.tcx().lookup_struct_fields(def_id); fields.len() == 1 && { - let ty = ty::lookup_field_type(ccx.tcx(), def_id, fields[0].id, substs); + let ty = ccx.tcx().lookup_field_type(def_id, fields[0].id, substs); let ty = monomorphize::normalize_associated_type(ccx.tcx(), &ty); type_is_immediate(ccx, ty) } @@ -234,10 +199,10 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - use trans::type_of::sizing_type_of; let tcx = ccx.tcx(); - let simple = ty::type_is_scalar(ty) || - ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) || + let simple = ty.is_scalar() || + ty.is_unique() || ty.is_region_ptr() || type_is_newtype_immediate(ccx, ty) || - ty::type_is_simd(tcx, ty); + ty.is_simd(tcx); if simple && !type_is_fat_ptr(tcx, ty) { return true; } @@ -267,7 +232,7 @@ pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - /// zero-size, but not all zero-size types use a `void` return type (in order to aid with C ABI /// compatibility). pub fn return_type_is_void(ccx: &CrateContext, ty: Ty) -> bool { - ty::type_is_nil(ty) || ty::type_is_empty(ccx.tcx(), ty) + ty.is_nil() || ty.is_empty(ccx.tcx()) } /// Generates a unique symbol based off the name given. This is used to create @@ -336,7 +301,7 @@ pub fn BuilderRef_res(b: BuilderRef) -> BuilderRef_res { pub type ExternMap = FnvHashMap; pub fn validate_substs(substs: &Substs) { - assert!(substs.types.all(|t| !ty::type_needs_infer(*t))); + assert!(!substs.types.needs_infer()); } // work around bizarre resolve errors @@ -352,7 +317,7 @@ pub struct FunctionContext<'a, 'tcx: 'a> { // section of the executable we're generating. pub llfn: ValueRef, - // always an empty parameter-environment + // always an empty parameter-environment NOTE: @jroesch another use of ParamEnv pub param_env: ty::ParameterEnvironment<'a, 'tcx>, // The environment argument in a closure. @@ -512,7 +477,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { } pub fn monomorphize(&self, value: &T) -> T - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { monomorphize::apply_param_substs(self.ccx.tcx(), self.param_substs, @@ -610,7 +575,7 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { } pub fn monomorphize(&self, value: &T) -> T - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { monomorphize::apply_param_substs(self.tcx(), self.fcx.param_substs, @@ -618,86 +583,6 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { } } -impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> { - fn node_ty(&self, id: ast::NodeId) -> mc::McResult> { - Ok(node_id_type(self, id)) - } - - fn expr_ty_adjusted(&self, expr: &ast::Expr) -> mc::McResult> { - Ok(expr_ty_adjusted(self, expr)) - } - - fn node_method_ty(&self, method_call: ty::MethodCall) -> Option> { - self.tcx() - .method_map - .borrow() - .get(&method_call) - .map(|method| monomorphize_type(self, method.ty)) - } - - fn node_method_origin(&self, method_call: ty::MethodCall) - -> Option> - { - self.tcx() - .method_map - .borrow() - .get(&method_call) - .map(|method| method.origin.clone()) - } - - fn adjustments<'a>(&'a self) -> &'a RefCell>> { - &self.tcx().adjustments - } - - fn is_method_call(&self, id: ast::NodeId) -> bool { - self.tcx().method_map.borrow().contains_key(&ty::MethodCall::expr(id)) - } - - fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { - self.tcx().region_maps.temporary_scope(rvalue_id) - } - - fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { - Some(self.tcx().upvar_capture_map.borrow().get(&upvar_id).unwrap().clone()) - } - - fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool { - self.fcx.param_env.type_moves_by_default(span, ty) - } -} - -impl<'blk, 'tcx> ty::ClosureTyper<'tcx> for BlockS<'blk, 'tcx> { - fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx> { - &self.fcx.param_env - } - - fn closure_kind(&self, - def_id: ast::DefId) - -> Option - { - let typer = NormalizingClosureTyper::new(self.tcx()); - typer.closure_kind(def_id) - } - - fn closure_type(&self, - def_id: ast::DefId, - substs: &subst::Substs<'tcx>) - -> ty::ClosureTy<'tcx> - { - let typer = NormalizingClosureTyper::new(self.tcx()); - typer.closure_type(def_id, substs) - } - - fn closure_upvars(&self, - def_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option>> - { - let typer = NormalizingClosureTyper::new(self.tcx()); - typer.closure_upvars(def_id, substs) - } -} - pub struct Result<'blk, 'tcx: 'blk> { pub bcx: Block<'blk, 'tcx>, pub val: ValueRef @@ -952,7 +837,7 @@ pub fn monomorphize_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, t: Ty<'tcx>) -> T pub fn node_id_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, id: ast::NodeId) -> Ty<'tcx> { let tcx = bcx.tcx(); - let t = ty::node_id_to_type(tcx, id); + let t = tcx.node_id_to_type(id); monomorphize_type(bcx, t) } @@ -961,7 +846,7 @@ pub fn expr_ty<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &ast::Expr) -> Ty<'tcx> } pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &ast::Expr) -> Ty<'tcx> { - monomorphize_type(bcx, ty::expr_ty_adjusted(bcx.tcx(), ex)) + monomorphize_type(bcx, bcx.tcx().expr_ty_adjusted(ex)) } /// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we @@ -989,13 +874,12 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}", trait_ref, trait_ref.def_id()); - ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id()); - let infcx = infer::new_infer_ctxt(tcx); // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - let typer = NormalizingClosureTyper::new(tcx); - let mut selcx = traits::SelectionContext::new(&infcx, &typer); + let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables); + let mut selcx = traits::SelectionContext::new(&infcx); + let obligation = traits::Obligation::new(traits::ObligationCause::misc(span, ast::DUMMY_NODE_ID), trait_ref.to_poly_trait_predicate()); @@ -1027,7 +911,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Currently, we use a fulfillment context to completely resolve // all nested obligations. This is because they can inform the // inference of the impl's type parameters. - let mut fulfill_cx = traits::FulfillmentContext::new(true); + let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut(); let vtable = selection.map(|predicate| { fulfill_cx.register_predicate_obligation(&infcx, predicate); }); @@ -1052,10 +936,9 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, predicates); let tcx = ccx.tcx(); - let infcx = infer::new_infer_ctxt(tcx); - let typer = NormalizingClosureTyper::new(tcx); - let mut selcx = traits::SelectionContext::new(&infcx, &typer); - let mut fulfill_cx = traits::FulfillmentContext::new(false); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, true); + let mut selcx = traits::SelectionContext::new(&infcx); + let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut(); let cause = traits::ObligationCause::dummy(); let traits::Normalized { value: predicates, obligations } = traits::normalize(&mut selcx, cause.clone(), &predicates); @@ -1069,53 +952,6 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()).is_ok() } -pub struct NormalizingClosureTyper<'a,'tcx:'a> { - param_env: ty::ParameterEnvironment<'a, 'tcx> -} - -impl<'a,'tcx> NormalizingClosureTyper<'a,'tcx> { - pub fn new(tcx: &'a ty::ctxt<'tcx>) -> NormalizingClosureTyper<'a,'tcx> { - // Parameter environment is used to give details about type parameters, - // but since we are in trans, everything is fully monomorphized. - NormalizingClosureTyper { param_env: ty::empty_parameter_environment(tcx) } - } -} - -impl<'a,'tcx> ty::ClosureTyper<'tcx> for NormalizingClosureTyper<'a,'tcx> { - fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> { - &self.param_env - } - - fn closure_kind(&self, - def_id: ast::DefId) - -> Option - { - self.param_env.closure_kind(def_id) - } - - fn closure_type(&self, - def_id: ast::DefId, - substs: &subst::Substs<'tcx>) - -> ty::ClosureTy<'tcx> - { - // the substitutions in `substs` are already monomorphized, - // but we still must normalize associated types - let closure_ty = self.param_env.tcx.closure_type(def_id, substs); - monomorphize::normalize_associated_type(self.param_env.tcx, &closure_ty) - } - - fn closure_upvars(&self, - def_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option>> - { - // the substitutions in `substs` are already monomorphized, - // but we still must normalize associated types - let result = ty::closure_upvars(&self.param_env, def_id, substs); - monomorphize::normalize_associated_type(self.param_env.tcx, &result) - } -} - pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span, infcx: &infer::InferCtxt<'a,'tcx>, fulfill_cx: &mut traits::FulfillmentContext<'tcx>, @@ -1153,8 +989,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &infer::InferCtxt<'a,'tcx>, // In principle, we only need to do this so long as `result` // contains unbound type parameters. It could be a slight // optimization to stop iterating early. - let typer = NormalizingClosureTyper::new(infcx.tcx); - match fulfill_cx.select_all_or_error(infcx, &typer) { + match fulfill_cx.select_all_or_error(infcx) { Ok(()) => { } Err(errors) => { return Err(errors); @@ -1187,14 +1022,14 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let substs = match node { ExprId(id) => { - ty::node_id_item_substs(tcx, id).substs + tcx.node_id_item_substs(id).substs } MethodCallKey(method_call) => { - tcx.method_map.borrow().get(&method_call).unwrap().substs.clone() + tcx.tables.borrow().method_map[&method_call].substs.clone() } }; - if substs.types.any(|t| ty::type_needs_infer(*t)) { + if substs.types.needs_infer() { tcx.sess.bug(&format!("type parameters for node {:?} include inference types: {:?}", node, substs)); } diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 7fbc86d7a8a3e..e7e2793fc7e9d 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -57,7 +57,7 @@ pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) C_integral(Type::uint_from_ty(cx, t), u, false) } ast::LitInt(i, ast::UnsuffixedIntLit(_)) => { - let lit_int_ty = ty::node_id_to_type(cx.tcx(), e.id); + let lit_int_ty = cx.tcx().node_id_to_type(e.id); match lit_int_ty.sty { ty::TyInt(t) => { C_integral(Type::int_from_ty(cx, t), i as u64, true) @@ -75,7 +75,7 @@ pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) C_floating(&fs, Type::float_from_ty(cx, t)) } ast::LitFloatUnsuffixed(ref fs) => { - let lit_float_ty = ty::node_id_to_type(cx.tcx(), e.id); + let lit_float_ty = cx.tcx().node_id_to_type(e.id); match lit_float_ty.sty { ty::TyFloat(t) => { C_floating(&fs, Type::float_from_ty(cx, t)) @@ -149,7 +149,7 @@ fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, v: ValueRef, ty: Ty<'tcx>) -> (ValueRef, Ty<'tcx>) { - match ty::deref(ty, true) { + match ty.builtin_deref(true) { Some(mt) => { if type_is_sized(cx.tcx(), mt.ty) { (const_deref_ptr(cx, v), mt.ty) @@ -228,7 +228,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def(); match def { def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => { - if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) { + if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) { debug!("get_const_expr_as_global ({:?}): found const {:?}", expr.id, def_id); return get_const_val(ccx, def_id, expr); @@ -249,7 +249,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Avoid autorefs as they would create global instead of stack // references, even when only the latter are correct. let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, - &ty::expr_ty(ccx.tcx(), expr)); + &ccx.tcx().expr_ty(expr)); const_expr_unadjusted(ccx, expr, ty, param_substs, None) } else { const_expr(ccx, expr, param_substs, None).0 @@ -276,12 +276,12 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn_args: FnArgMap) -> (ValueRef, Ty<'tcx>) { let ety = monomorphize::apply_param_substs(cx.tcx(), param_substs, - &ty::expr_ty(cx.tcx(), e)); + &cx.tcx().expr_ty(e)); let llconst = const_expr_unadjusted(cx, e, ety, param_substs, fn_args); let mut llconst = llconst; let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs, - &ty::expr_ty_adjusted(cx.tcx(), e)); - let opt_adj = cx.tcx().adjustments.borrow().get(&e.id).cloned(); + &cx.tcx().expr_ty_adjusted(e)); + let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned(); match opt_adj { Some(ty::AdjustReifyFnPointer) => { // FIXME(#19925) once fn item types are @@ -306,7 +306,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Don't copy data to do a deref+ref // (i.e., skip the last auto-deref). llconst = addr_of(cx, llconst, "autoref"); - ty = ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ty); + ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReStatic), ty); } } else { let (dv, dt) = const_deref(cx, llconst, ty); @@ -323,7 +323,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, param_substs, &target); - let pointee_ty = ty::deref(ty, true) + let pointee_ty = ty.builtin_deref(true) .expect("consts: unsizing got non-pointer type").ty; let (base, old_info) = if !type_is_sized(cx.tcx(), pointee_ty) { // Normally, the source is a thin pointer and we are @@ -338,7 +338,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, (llconst, None) }; - let unsized_ty = ty::deref(target, true) + let unsized_ty = target.builtin_deref(true) .expect("consts: unsizing got non-pointer target type").ty; let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); let base = ptrcast(base, ptr_ty); @@ -499,14 +499,14 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, debug!("const_expr_unadjusted: te1={}, ty={:?}", cx.tn().val_to_string(te1), ty); - let is_simd = ty::type_is_simd(cx.tcx(), ty); + let is_simd = ty.is_simd(cx.tcx()); let intype = if is_simd { - ty::simd_type(cx.tcx(), ty) + ty.simd_type(cx.tcx()) } else { ty }; - let is_float = ty::type_is_fp(intype); - let signed = ty::type_is_signed(intype); + let is_float = intype.is_fp(); + let signed = intype.is_signed(); let (te2, _) = const_expr(cx, &**e2, param_substs, fn_args); @@ -572,7 +572,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, check_unary_expr_validity(cx, e, ty, te); - let is_float = ty::type_is_fp(ty); + let is_float = ty.is_fp(); match u { ast::UnUniq | ast::UnDeref => { const_deref(cx, te, ty).0 @@ -588,7 +588,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); let brepr = adt::represent_type(cx, bt); expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| { - let ix = ty::field_idx_strict(cx.tcx(), field.node.name, field_tys); + let ix = cx.tcx().field_idx_strict(field.node.name, field_tys); adt::const_get_field(cx, &*brepr, bv, discr, ix) }) } @@ -660,7 +660,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } if type_is_fat_ptr(cx.tcx(), t_expr) { // Fat pointer casts. - let t_cast_inner = ty::deref(t_cast, true).expect("cast to non-pointer").ty; + let t_cast_inner = t_cast.builtin_deref(true).expect("cast to non-pointer").ty; let ptr_ty = type_of::in_memory_type_of(cx, t_cast_inner).ptr_to(); let addr = ptrcast(const_get_elt(cx, v, &[abi::FAT_PTR_ADDR as u32]), ptr_ty); @@ -681,11 +681,11 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, llvm::LLVMConstIntCast(iv, llty.to_ref(), s) } (CastTy::Int(_), CastTy::Int(_)) => { - let s = ty::type_is_signed(t_expr) as Bool; + let s = t_expr.is_signed() as Bool; llvm::LLVMConstIntCast(v, llty.to_ref(), s) } (CastTy::Int(_), CastTy::Float) => { - if ty::type_is_signed(t_expr) { + if t_expr.is_signed() { llvm::LLVMConstSIToFP(v, llty.to_ref()) } else { llvm::LLVMConstUIToFP(v, llty.to_ref()) @@ -781,7 +781,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } }).collect::>(); - if ty::type_is_simd(cx.tcx(), ety) { + if ety.is_simd(cx.tcx()) { C_vector(&cs[..]) } else { adt::trans_const(cx, &*repr, discr, &cs[..]) @@ -789,7 +789,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }) } ast::ExprVec(ref es) => { - let unit_ty = ty::sequence_element_type(cx.tcx(), ety); + let unit_ty = ety.sequence_element_type(cx.tcx()); let llunitty = type_of::type_of(cx, unit_ty); let vs = es.iter().map(|e| const_expr(cx, &**e, param_substs, fn_args).0) .collect::>(); @@ -801,9 +801,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } ast::ExprRepeat(ref elem, ref count) => { - let unit_ty = ty::sequence_element_type(cx.tcx(), ety); + let unit_ty = ety.sequence_element_type(cx.tcx()); let llunitty = type_of::type_of(cx, unit_ty); - let n = ty::eval_repeat_count(cx.tcx(), count); + let n = cx.tcx().eval_repeat_count(count); let unit_val = const_expr(cx, &**elem, param_substs, fn_args).0; let vs: Vec<_> = repeat(unit_val).take(n).collect(); if val_ty(unit_val) != llunitty { @@ -829,9 +829,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, const_deref_ptr(cx, get_const_val(cx, def_id, e)) } def::DefVariant(enum_did, variant_did, _) => { - let vinfo = ty::enum_variant_with_id(cx.tcx(), - enum_did, - variant_did); + let vinfo = cx.tcx().enum_variant_with_id(enum_did, variant_did); if !vinfo.args.is_empty() { // N-ary variant. expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val @@ -875,7 +873,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs) } def::DefStruct(_) => { - if ty::type_is_simd(cx.tcx(), ety) { + if ety.is_simd(cx.tcx()) { C_vector(&arg_vals[..]) } else { let repr = adt::represent_type(cx, ety); @@ -884,9 +882,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } def::DefVariant(enum_did, variant_did, _) => { let repr = adt::represent_type(cx, ety); - let vinfo = ty::enum_variant_with_id(cx.tcx(), - enum_did, - variant_did); + let vinfo = cx.tcx().enum_variant_with_id(enum_did, variant_did); adt::trans_const(cx, &*repr, vinfo.disr_val, @@ -898,10 +894,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ast::ExprMethodCall(_, _, ref args) => { let arg_vals = map_list(args); let method_call = ty::MethodCall::expr(e.id); - let method_did = match cx.tcx().method_map.borrow()[&method_call].origin { - ty::MethodStatic(did) => did, - _ => cx.sess().span_bug(e.span, "expected a const method def") - }; + let method_did = cx.tcx().tables.borrow().method_map[&method_call].def_id; const_fn_call(cx, MethodCallKey(method_call), method_did, &arg_vals, param_substs) } @@ -945,8 +938,8 @@ pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) -> // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. if m != ast::MutMutable { - let node_ty = ty::node_id_to_type(ccx.tcx(), id); - let tcontents = ty::type_contents(ccx.tcx(), node_ty); + let node_ty = ccx.tcx().node_id_to_type(id); + let tcontents = node_ty.type_contents(ccx.tcx()); if !tcontents.interior_unsafe() { llvm::LLVMSetGlobalConstant(g, True); } diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 0ae69682f914a..cf9d70cc65727 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -791,7 +791,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option $ret:expr) => ( if *key == $name { let f = declare::declare_cfn(ccx, $name, Type::func(&[], &$ret), - ty::mk_nil(ccx.tcx())); + ccx.tcx().mk_nil()); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } @@ -799,7 +799,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option $ret:expr) => ( if *key == $name { let f = declare::declare_cfn(ccx, $name, Type::func(&[$($arg),*], &$ret), - ty::mk_nil(ccx.tcx())); + ccx.tcx().mk_nil()); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } @@ -939,7 +939,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option Option Datum<'tcx, K> { * affine values (since they must never be duplicated). */ - assert!(!ty::type_moves_by_default(&ty::empty_parameter_environment(bcx.tcx()), - DUMMY_SP, - self.ty)); + assert!(!self.ty + .moves_by_default(&bcx.tcx().empty_parameter_environment(), DUMMY_SP)); self.shallow_copy_raw(bcx, dst) } @@ -640,7 +639,7 @@ impl<'tcx, K: KindOps + fmt::Debug> Datum<'tcx, K> { } pub fn to_llbool<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef { - assert!(ty::type_is_bool(self.ty)); + assert!(self.ty.is_bool()); self.to_llscalarish(bcx) } } diff --git a/src/librustc_trans/trans/debuginfo/gdb.rs b/src/librustc_trans/trans/debuginfo/gdb.rs index a6f1199d0ffe7..f7b0f37c9ff78 100644 --- a/src/librustc_trans/trans/debuginfo/gdb.rs +++ b/src/librustc_trans/trans/debuginfo/gdb.rs @@ -16,7 +16,6 @@ use llvm::ValueRef; use trans::common::{C_bytes, CrateContext}; use trans::declare; use trans::type_::Type; -use middle::ty::ClosureTyper; use session::config::NoDebugInfo; use std::ffi::CString; diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 7660f59e1d08b..45349969a0b3e 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -26,12 +26,13 @@ use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType}; use metadata::csearch; use middle::pat_util; use middle::subst::{self, Substs}; +use middle::infer; use rustc::ast_map; use trans::{type_of, adt, machine, monomorphize}; -use trans::common::{self, CrateContext, FunctionContext, NormalizingClosureTyper, Block}; +use trans::common::{self, CrateContext, FunctionContext, Block}; use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef}; use trans::type_::Type; -use middle::ty::{self, Ty, ClosureTyper}; +use middle::ty::{self, Ty}; use session::config::{self, FullDebugInfo}; use util::nodemap::FnvHashMap; use util::common::path2cstr; @@ -242,9 +243,7 @@ impl<'tcx> TypeMap<'tcx> { ty::TyTrait(ref trait_data) => { unique_type_id.push_str("trait "); - let principal = - ty::erase_late_bound_regions(cx.tcx(), - &trait_data.principal); + let principal = cx.tcx().erase_late_bound_regions(&trait_data.principal); from_def_id_and_substs(self, cx, @@ -261,7 +260,7 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push_str(" fn("); - let sig = ty::erase_late_bound_regions(cx.tcx(), sig); + let sig = cx.tcx().erase_late_bound_regions(sig); for ¶meter_type in &sig.inputs { let parameter_type_id = @@ -289,8 +288,8 @@ impl<'tcx> TypeMap<'tcx> { } }, ty::TyClosure(def_id, substs) => { - let typer = NormalizingClosureTyper::new(cx.tcx()); - let closure_ty = typer.closure_type(def_id, substs); + let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); + let closure_ty = infcx.closure_type(def_id, substs); self.get_unique_type_id_of_closure_type(cx, closure_ty, &mut unique_type_id); @@ -376,7 +375,7 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push_str("|"); - let sig = ty::erase_late_bound_regions(cx.tcx(), sig); + let sig = cx.tcx().erase_late_bound_regions(sig); for ¶meter_type in &sig.inputs { let parameter_type_id = @@ -562,7 +561,7 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id: UniqueTypeId, span: Span) -> MetadataCreationResult { - let data_ptr_type = ty::mk_ptr(cx.tcx(), ty::mt { + let data_ptr_type = cx.tcx().mk_ptr(ty::mt { ty: element_type, mutbl: ast::MutImmutable }); @@ -626,7 +625,7 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, span: Span) -> MetadataCreationResult { - let signature = ty::erase_late_bound_regions(cx.tcx(), signature); + let signature = cx.tcx().erase_late_bound_regions(signature); let mut signature_metadata: Vec = Vec::with_capacity(signature.inputs.len() + 1); @@ -798,8 +797,8 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span) } ty::TyClosure(def_id, substs) => { - let typer = NormalizingClosureTyper::new(cx.tcx()); - let sig = typer.closure_type(def_id, substs).sig; + let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); + let sig = infcx.closure_type(def_id, substs).sig; subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span) } ty::TyStruct(def_id, substs) => { @@ -1176,7 +1175,7 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, containing_scope); - let mut fields = ty::struct_fields(cx.tcx(), def_id, substs); + let mut fields = cx.tcx().struct_fields(def_id, substs); // The `Ty` values returned by `ty::struct_fields` can still contain // `TyProjection` variants, so normalize those away. @@ -1192,7 +1191,7 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, struct_llvm_type, StructMDF(StructMemberDescriptionFactory { fields: fields, - is_simd: ty::type_is_simd(cx.tcx(), struct_type), + is_simd: struct_type.is_simd(cx.tcx()), span: span, }) ) @@ -1588,7 +1587,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let loc = span_start(cx, definition_span); let file_metadata = file_metadata(cx, &loc.file.name); - let variants = ty::enum_variants(cx.tcx(), enum_def_id); + let variants = cx.tcx().enum_variants(enum_def_id); let enumerators_metadata: Vec = variants .iter() @@ -1891,7 +1890,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, }; let is_local_to_unit = is_node_local_to_unit(cx, node_id); - let variable_type = ty::node_id_to_type(cx.tcx(), node_id); + let variable_type = cx.tcx().node_id_to_type(node_id); let type_metadata = type_metadata(cx, variable_type, span); let namespace_node = namespace_for_item(cx, ast_util::local_def(node_id)); let var_name = token::get_name(name).to_string(); diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index 06f1a56c6ef1f..3d1b384c2d915 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -30,7 +30,7 @@ use rustc::ast_map; use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block}; use trans; use trans::monomorphize; -use middle::ty::{self, Ty, ClosureTyper}; +use middle::ty::Ty; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet}; @@ -412,11 +412,11 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Return type -- llvm::DIBuilder wants this at index 0 assert_type_for_node_id(cx, fn_ast_id, error_reporting_span); - let return_type = ty::node_id_to_type(cx.tcx(), fn_ast_id); + let return_type = cx.tcx().node_id_to_type(fn_ast_id); let return_type = monomorphize::apply_param_substs(cx.tcx(), param_substs, &return_type); - if ty::type_is_nil(return_type) { + if return_type.is_nil() { signature.push(ptr::null_mut()) } else { signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP)); @@ -425,7 +425,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Arguments types for arg in &fn_decl.inputs { assert_type_for_node_id(cx, arg.pat.id, arg.pat.span); - let arg_type = ty::node_id_to_type(cx.tcx(), arg.pat.id); + let arg_type = cx.tcx().node_id_to_type(arg.pat.id); let arg_type = monomorphize::apply_param_substs(cx.tcx(), param_substs, &arg_type); diff --git a/src/librustc_trans/trans/debuginfo/namespace.rs b/src/librustc_trans/trans/debuginfo/namespace.rs index e6fe674f22057..8b33acdee8e25 100644 --- a/src/librustc_trans/trans/debuginfo/namespace.rs +++ b/src/librustc_trans/trans/debuginfo/namespace.rs @@ -16,7 +16,6 @@ use llvm; use llvm::debuginfo::DIScope; use rustc::ast_map; use trans::common::CrateContext; -use middle::ty::{self, ClosureTyper}; use std::ffi::CString; use std::ptr; @@ -56,7 +55,7 @@ pub fn crate_root_namespace<'a>(cx: &'a CrateContext) -> &'a str { } pub fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc { - ty::with_path(cx.tcx(), def_id, |path| { + cx.tcx().with_path(def_id, |path| { // prepend crate name if not already present let krate = if def_id.krate == ast::LOCAL_CRATE { let crate_namespace_name = token::intern(crate_root_namespace(cx)); diff --git a/src/librustc_trans/trans/debuginfo/type_names.rs b/src/librustc_trans/trans/debuginfo/type_names.rs index 5ba5ecb02c024..f411688319981 100644 --- a/src/librustc_trans/trans/debuginfo/type_names.rs +++ b/src/librustc_trans/trans/debuginfo/type_names.rs @@ -14,7 +14,7 @@ use super::namespace::crate_root_namespace; use trans::common::CrateContext; use middle::subst::{self, Substs}; -use middle::ty::{self, Ty, ClosureTyper}; +use middle::ty::{self, Ty}; use syntax::ast; use syntax::parse::token; @@ -106,7 +106,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(']'); }, ty::TyTrait(ref trait_data) => { - let principal = ty::erase_late_bound_regions(cx.tcx(), &trait_data.principal); + let principal = cx.tcx().erase_late_bound_regions(&trait_data.principal); push_item_name(cx, principal.def_id, false, output); push_type_params(cx, principal.substs, output); }, @@ -123,7 +123,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push_str("fn("); - let sig = ty::erase_late_bound_regions(cx.tcx(), sig); + let sig = cx.tcx().erase_late_bound_regions(sig); if !sig.inputs.is_empty() { for ¶meter_type in &sig.inputs { push_debuginfo_type_name(cx, parameter_type, true, output); @@ -144,7 +144,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(')'); match sig.output { - ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {} + ty::FnConverging(result_type) if result_type.is_nil() => {} ty::FnConverging(result_type) => { output.push_str(" -> "); push_debuginfo_type_name(cx, result_type, true, output); @@ -170,7 +170,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, def_id: ast::DefId, qualified: bool, output: &mut String) { - ty::with_path(cx.tcx(), def_id, |path| { + cx.tcx().with_path(def_id, |path| { if qualified { if def_id.krate == ast::LOCAL_CRATE { output.push_str(crate_root_namespace(cx)); @@ -225,4 +225,3 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push('>'); } } - diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index 8bc3326d30093..b29da9d560fea 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -20,11 +20,11 @@ //! * Use define_* family of methods when you might be defining the ValueRef. //! * When in doubt, define. use llvm::{self, ValueRef}; -use middle::ty::{self, ClosureTyper}; +use middle::ty; +use middle::infer; use syntax::abi; use trans::attributes; use trans::base; -use trans::common; use trans::context::CrateContext; use trans::monomorphize; use trans::type_::Type; @@ -117,8 +117,8 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, (&f.sig, f.abi, None) } ty::TyClosure(closure_did, substs) => { - let typer = common::NormalizingClosureTyper::new(ccx.tcx()); - function_type = typer.closure_type(closure_did, substs); + let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); + 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); debug!("declare_rust_fn function_type={:?} self_type={:?}", @@ -128,7 +128,7 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, _ => ccx.sess().bug("expected closure or fn") }; - let sig = ty::Binder(ty::erase_late_bound_regions(ccx.tcx(), sig)); + let sig = ty::Binder(ccx.tcx().erase_late_bound_regions(sig)); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); let llfty = type_of::type_of_rust_fn(ccx, env, &sig, abi); debug!("declare_rust_fn llfty={}", ccx.tn().type_to_string(llfty)); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 5ee7159493534..7722cb322c9e6 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -56,7 +56,6 @@ use llvm::{self, ValueRef, TypeKind}; use middle::check_const; use middle::def; use middle::lang_items::CoerceUnsizedTraitLangItem; -use middle::mem_categorization::Typer; use middle::subst::{Substs, VecPerParamSpace}; use middle::traits; use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; @@ -73,7 +72,6 @@ use trans::monomorphize; use trans::tvec; use trans::type_of; use middle::cast::{CastKind, CastTy}; -use middle::ty::{struct_fields, tup_fields}; use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer}; use middle::ty::{self, Ty}; use middle::ty::MethodCall; @@ -118,7 +116,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); - if bcx.tcx().adjustments.borrow().contains_key(&expr.id) { + if bcx.tcx().tables.borrow().adjustments.contains_key(&expr.id) { // use trans, which may be less efficient but // which will perform the adjustments: let datum = unpack_datum!(bcx, trans(bcx, expr)); @@ -252,7 +250,7 @@ pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llty = type_of::type_of(bcx.ccx(), const_ty); // HACK(eddyb) get around issues with lifetime intrinsics. let scratch = alloca_no_lifetime(bcx, llty, "const"); - let lldest = if !ty::type_is_structural(const_ty) { + let lldest = if !const_ty.is_structural() { // Cast pointer to slot, because constants have different types. PointerCast(bcx, scratch, val_ty(global)) } else { @@ -293,9 +291,6 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef { GEPi(bcx, fat_ptr, &[0, abi::FAT_PTR_ADDR]) } -pub fn make_fat_ptr(bcx: Block, ty: Type, data: ValueRef, extra: ValueRef) -> ValueRef { - InsertValue(bcx, InsertValue(bcx, C_undef(ty), data, 0), extra, 1) -} pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) { Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr)); Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr)); @@ -313,7 +308,7 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, old_info: Option, param_substs: &'tcx Substs<'tcx>) -> ValueRef { - let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target); + let (source, target) = ccx.tcx().struct_lockstep_tails(source, target); match (&source.sty, &target.sty) { (&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len), (&ty::TyTrait(_), &ty::TyTrait(_)) => { @@ -346,7 +341,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, { let mut bcx = bcx; let mut datum = datum; - let adjustment = match bcx.tcx().adjustments.borrow().get(&expr.id).cloned() { + let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() { None => { return DatumBlock::new(bcx, datum); } @@ -373,7 +368,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Don't skip a conversion from Box to &T, etc. ty::TyRef(..) => { let method_call = MethodCall::autoderef(expr.id, 0); - if bcx.tcx().method_map.borrow().contains_key(&method_call) { + if bcx.tcx().tables.borrow().method_map.contains_key(&method_call) { // Don't skip an overloaded deref. 0 } else { @@ -500,7 +495,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let kind = match fulfill_obligation(bcx.ccx(), span, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { - ty::custom_coerce_unsized_kind(bcx.tcx(), impl_def_id) + bcx.tcx().custom_coerce_unsized_kind(impl_def_id) } vtable => { bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {:?}", @@ -748,7 +743,7 @@ fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, base: &ast::Expr, field: ast::Name) -> DatumBlock<'blk, 'tcx, Expr> { - trans_field(bcx, base, |tcx, field_tys| ty::field_idx_strict(tcx, field, field_tys)) + trans_field(bcx, base, |tcx, field_tys| tcx.field_idx_strict(field, field_tys)) } /// Translates `base.`. @@ -775,8 +770,9 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Check for overloaded index. let method_ty = ccx.tcx() - .method_map + .tables .borrow() + .method_map .get(&method_call) .map(|method| method.ty); let elt_datum = match method_ty { @@ -789,9 +785,8 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ix_datum = unpack_datum!(bcx, trans(bcx, idx)); let ref_ty = // invoked methods have LB regions instantiated: - ty::no_late_bound_regions( - bcx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap(); - let elt_ty = match ty::deref(ref_ty, true) { + bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap(); + let elt_ty = match ref_ty.builtin_deref(true) { None => { bcx.tcx().sess.span_bug(index_expr.span, "index method didn't return a \ @@ -810,7 +805,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, index_expr, method_call, base_datum, - vec![(ix_datum, idx.id)], + Some((ix_datum, idx.id)), Some(SaveIn(scratch.val)), false)); let datum = scratch.to_expr_datum(); @@ -835,7 +830,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ccx.int_type()); let ix_val = { if ix_size < int_size { - if ty::type_is_signed(expr_ty(bcx, idx)) { + if expr_ty(bcx, idx).is_signed() { SExt(bcx, ix_val, ccx.int_type()) } else { ZExt(bcx, ix_val, ccx.int_type()) } } else if ix_size > int_size { @@ -845,7 +840,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } }; - let unit_ty = ty::sequence_element_type(bcx.tcx(), base_datum.ty); + let unit_ty = base_datum.ty.sequence_element_type(bcx.tcx()); let (base, len) = base_datum.get_vec_base_and_len(bcx); @@ -1110,7 +1105,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, None, expr.span, expr.id, - ty::mk_struct(tcx, did, tcx.mk_substs(substs)), + tcx.mk_struct(did, tcx.mk_substs(substs)), dest) } else { tcx.sess.span_bug(expr.span, @@ -1180,21 +1175,21 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let lhs = unpack_datum!(bcx, trans(bcx, &**lhs)); let rhs_datum = unpack_datum!(bcx, trans(bcx, &**rhs)); trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs, - vec![(rhs_datum, rhs.id)], Some(dest), + Some((rhs_datum, rhs.id)), Some(dest), !ast_util::is_by_value_binop(op.node)).bcx } ast::ExprUnary(op, ref subexpr) => { // if not overloaded, would be RvalueDatumExpr let arg = unpack_datum!(bcx, trans(bcx, &**subexpr)); trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), - arg, Vec::new(), Some(dest), !ast_util::is_by_value_unop(op)).bcx + arg, None, Some(dest), !ast_util::is_by_value_unop(op)).bcx } ast::ExprIndex(ref base, ref idx) => { // if not overloaded, would be RvalueDatumExpr let base = unpack_datum!(bcx, trans(bcx, &**base)); let idx_datum = unpack_datum!(bcx, trans(bcx, &**idx)); trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base, - vec![(idx_datum, idx.id)], Some(dest), true).bcx + Some((idx_datum, idx.id)), Some(dest), true).bcx } ast::ExprCast(..) => { // Trait casts used to come this way, now they should be coercions. @@ -1227,7 +1222,7 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match def { def::DefVariant(tid, vid, _) => { - let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid); + let variant_info = bcx.tcx().enum_variant_with_id(tid, vid); if !variant_info.args.is_empty() { // N-ary variant. let llfn = callee::trans_fn_ref(bcx.ccx(), vid, @@ -1247,7 +1242,7 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def::DefStruct(_) => { let ty = expr_ty(bcx, ref_expr); match ty.sty { - ty::TyStruct(did, _) if ty::has_dtor(bcx.tcx(), did) => { + ty::TyStruct(did, _) if bcx.tcx().has_dtor(did) => { let repr = adt::represent_type(bcx.ccx(), ty); adt::trans_set_discr(bcx, &*repr, lldest, 0); } @@ -1342,13 +1337,22 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>, { match ty.sty { ty::TyStruct(did, substs) => { - let fields = struct_fields(tcx, did, substs); + let fields = tcx.struct_fields(did, substs); let fields = monomorphize::normalize_associated_type(tcx, &fields); op(0, &fields[..]) } ty::TyTuple(ref v) => { - op(0, &tup_fields(&v[..])) + let fields: Vec<_> = v.iter().enumerate().map(|(i, &f)| { + ty::field { + name: token::intern(&i.to_string()), + mt: ty::mt { + ty: f, + mutbl: ast::MutImmutable + } + } + }).collect(); + op(0, &fields) } ty::TyEnum(_, substs) => { @@ -1364,8 +1368,8 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>, let def = tcx.def_map.borrow().get(&node_id).unwrap().full_def(); match def { def::DefVariant(enum_id, variant_id, _) => { - let variant_info = ty::enum_variant_with_id(tcx, enum_id, variant_id); - let fields = struct_fields(tcx, variant_id, substs); + let variant_info = tcx.enum_variant_with_id(enum_id, variant_id); + let fields = tcx.struct_fields(variant_id, substs); let fields = monomorphize::normalize_associated_type(tcx, &fields); op(variant_info.disr_val, &fields[..]) } @@ -1490,7 +1494,7 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // panic occur before the ADT as a whole is ready. let custom_cleanup_scope = fcx.push_custom_cleanup_scope(); - if ty::type_is_simd(bcx.tcx(), ty) { + if ty.is_simd(bcx.tcx()) { // Issue 23112: The original logic appeared vulnerable to same // order-of-eval bug. But, SIMD values are tuple-structs; // i.e. functional record update (FRU) syntax is unavailable. @@ -1610,7 +1614,7 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Otherwise, we should be in the RvalueDpsExpr path. assert!( op == ast::UnDeref || - !ccx.tcx().method_map.borrow().contains_key(&method_call)); + !ccx.tcx().tables.borrow().method_map.contains_key(&method_call)); let un_ty = expr_ty(bcx, expr); @@ -1626,11 +1630,11 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let datum = unpack_datum!(bcx, trans(bcx, sub_expr)); let val = datum.to_llscalarish(bcx); let (bcx, llneg) = { - if ty::type_is_fp(un_ty) { + if un_ty.is_fp() { let result = FNeg(bcx, val, debug_loc); (bcx, result) } else { - let is_signed = ty::type_is_signed(un_ty); + let is_signed = un_ty.is_signed(); let result = Neg(bcx, val, debug_loc); let bcx = if bcx.ccx().check_overflow() && is_signed { let (llty, min) = base::llty_and_min_for_signed_ty(bcx, un_ty); @@ -1697,7 +1701,7 @@ fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, lval: Datum<'tcx, Lvalue>) -> DatumBlock<'blk, 'tcx, Expr> { - let dest_ty = ty::mk_imm_rptr(bcx.tcx(), bcx.tcx().mk_region(ty::ReStatic), lval.ty); + let dest_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), lval.ty); let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr"); memcpy_ty(bcx, scratch.val, lval.val, scratch.ty); @@ -1735,14 +1739,14 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_eager_binop"); let tcx = bcx.tcx(); - let is_simd = ty::type_is_simd(tcx, lhs_t); + let is_simd = lhs_t.is_simd(tcx); let intype = if is_simd { - ty::simd_type(tcx, lhs_t) + lhs_t.simd_type(tcx) } else { lhs_t }; - let is_float = ty::type_is_fp(intype); - let is_signed = ty::type_is_signed(intype); + let is_float = intype.is_fp(); + let is_signed = intype.is_signed(); let info = expr_info(binop_expr); let binop_debug_loc = binop_expr.debug_loc(); @@ -1903,7 +1907,7 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ccx = bcx.ccx(); // if overloaded, would be RvalueDpsExpr - assert!(!ccx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id))); + assert!(!ccx.tcx().tables.borrow().method_map.contains_key(&MethodCall::expr(expr.id))); match op.node { ast::BiAnd => { @@ -1939,14 +1943,12 @@ fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr, method_call: MethodCall, lhs: Datum<'tcx, Expr>, - rhs: Vec<(Datum<'tcx, Expr>, ast::NodeId)>, + rhs: Option<(Datum<'tcx, Expr>, ast::NodeId)>, dest: Option, autoref: bool) -> Result<'blk, 'tcx> { - let method_ty = bcx.tcx().method_map.borrow().get(&method_call).unwrap().ty; callee::trans_call_inner(bcx, expr.debug_loc(), - monomorphize_type(bcx, method_ty), |bcx, arg_cleanup_scope| { meth::trans_method_callee(bcx, method_call, @@ -1965,19 +1967,11 @@ fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, -> Block<'blk, 'tcx> { debug!("trans_overloaded_call {}", expr.id); let method_call = MethodCall::expr(expr.id); - let method_type = bcx.tcx() - .method_map - .borrow() - .get(&method_call) - .unwrap() - .ty; let mut all_args = vec!(callee); all_args.extend(args.iter().map(|e| &**e)); unpack_result!(bcx, callee::trans_call_inner(bcx, expr.debug_loc(), - monomorphize_type(bcx, - method_type), |bcx, arg_cleanup_scope| { meth::trans_method_callee( bcx, @@ -1999,7 +1993,7 @@ pub fn cast_is_noop<'tcx>(tcx: &ty::ctxt<'tcx>, return true; } - match (ty::deref(t_in, true), ty::deref(t_out, true)) { + match (t_in.builtin_deref(true), t_out.builtin_deref(true)) { (Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: t_out, .. })) => { t_in == t_out } @@ -2108,7 +2102,7 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ll_t_in = val_ty(discr); (discr, adt::is_discr_signed(&*repr)) } else { - (datum.to_llscalarish(bcx), ty::type_is_signed(t_in)) + (datum.to_llscalarish(bcx), t_in.is_signed()) }; let newval = match (r_t_in, r_t_out) { @@ -2147,7 +2141,7 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("trans_assign_op(expr={:?})", expr); // User-defined operator methods cannot be used with `+=` etc right now - assert!(!bcx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id))); + assert!(!bcx.tcx().tables.borrow().method_map.contains_key(&MethodCall::expr(expr.id))); // Evaluate LHS (destination), which should be an lvalue let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op")); @@ -2180,7 +2174,7 @@ fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Compute final type. Note that we are loose with the region and // mutability, since those things don't matter in trans. let referent_ty = lv_datum.ty; - let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), bcx.tcx().mk_region(ty::ReStatic), referent_ty); + let ptr_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), referent_ty); // Get the pointer. let llref = lv_datum.to_llref(); @@ -2222,8 +2216,12 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let mut bcx = bcx; // Check for overloaded deref. - let method_ty = ccx.tcx().method_map.borrow() + let method_ty = ccx.tcx() + .tables + .borrow() + .method_map .get(&method_call).map(|method| method.ty); + let datum = match method_ty { Some(method_ty) => { let method_ty = monomorphize_type(bcx, method_ty); @@ -2241,12 +2239,11 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let ref_ty = // invoked methods have their LB regions instantiated - ty::no_late_bound_regions( - ccx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap(); + ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap(); let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref"); unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call, - datum, Vec::new(), Some(SaveIn(scratch.val)), + datum, None, Some(SaveIn(scratch.val)), false)); scratch.to_expr_datum() } @@ -2545,13 +2542,13 @@ fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // #1877, #10183: Ensure that input is always valid let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc); let tcx = bcx.tcx(); - let is_simd = ty::type_is_simd(tcx, lhs_t); + let is_simd = lhs_t.is_simd(tcx); let intype = if is_simd { - ty::simd_type(tcx, lhs_t) + lhs_t.simd_type(tcx) } else { lhs_t }; - let is_signed = ty::type_is_signed(intype); + let is_signed = intype.is_signed(); if is_signed { AShr(bcx, lhs, rhs, binop_debug_loc) } else { @@ -2609,7 +2606,7 @@ enum ExprKind { } fn expr_kind(tcx: &ty::ctxt, expr: &ast::Expr) -> ExprKind { - if tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)) { + if tcx.tables.borrow().method_map.contains_key(&MethodCall::expr(expr.id)) { // Overloaded operations are generally calls, and hence they are // generated via DPS, but there are a few exceptions: return match expr.node { @@ -2629,9 +2626,9 @@ fn expr_kind(tcx: &ty::ctxt, expr: &ast::Expr) -> ExprKind { match expr.node { ast::ExprPath(..) => { - match ty::resolve_expr(tcx, expr) { + match tcx.resolve_expr(expr) { def::DefStruct(_) | def::DefVariant(..) => { - if let ty::TyBareFn(..) = ty::node_id_to_type(tcx, expr.id).sty { + if let ty::TyBareFn(..) = tcx.node_id_to_type(expr.id).sty { // ctor function ExprKind::RvalueDatum } else { diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 4f3f13e4bed24..9e8c0189a9762 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -109,7 +109,7 @@ pub fn llvm_calling_convention(ccx: &CrateContext, pub fn register_static(ccx: &CrateContext, foreign_item: &ast::ForeignItem) -> ValueRef { - let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id); + let ty = ccx.tcx().node_id_to_type(foreign_item.id); let llty = type_of::type_of(ccx, ty); let ident = link_name(foreign_item); @@ -245,7 +245,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty::TyBareFn(_, ref fn_ty) => (fn_ty.abi, &fn_ty.sig), _ => ccx.sess().bug("trans_native_call called on non-function type") }; - let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig); + let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); let llsig = foreign_signature(ccx, &fn_sig, &passed_arg_tys[..]); let fn_type = cabi::compute_abi_info(ccx, &llsig.llarg_tys, @@ -324,7 +324,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llarg_foreign = if foreign_indirect { llarg_rust } else { - if ty::type_is_bool(passed_arg_tys[i]) { + if passed_arg_tys[i].is_bool() { let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, llvm::False); Trunc(bcx, val, Type::i1(bcx.ccx())) } else { @@ -450,7 +450,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn gate_simd_ffi(tcx: &ty::ctxt, decl: &ast::FnDecl, ty: &ty::BareFnTy) { if !tcx.sess.features.borrow().simd_ffi { let check = |ast_ty: &ast::Ty, ty: ty::Ty| { - if ty::type_is_simd(tcx, ty) { + if ty.is_simd(tcx) { tcx.sess.span_err(ast_ty.span, &format!("use of SIMD type `{}` in FFI is highly experimental and \ may result in invalid code", @@ -478,7 +478,7 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) { match foreign_mod.abi { Rust | RustIntrinsic => {} abi => { - let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id); + let ty = ccx.tcx().node_id_to_type(foreign_item.id); match ty.sty { ty::TyBareFn(_, bft) => gate_simd_ffi(ccx.tcx(), &**decl, bft), _ => ccx.tcx().sess.span_bug(foreign_item.span, @@ -538,7 +538,7 @@ pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi") }; let llfn = declare::declare_fn(ccx, name, cconv, llfn_ty, - ty::FnConverging(ty::mk_nil(ccx.tcx()))); + ty::FnConverging(ccx.tcx().mk_nil())); add_argument_attributes(&tys, llfn); debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})", ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn)); @@ -554,7 +554,7 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext, let tys = foreign_types_for_id(ccx, node_id); let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); - let t = ty::node_id_to_type(ccx.tcx(), node_id); + let t = ccx.tcx().node_id_to_type(node_id); let cconv = match t.sty { ty::TyBareFn(_, ref fn_ty) => { llvm_calling_convention(ccx, fn_ty.abi) @@ -578,7 +578,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, hash: Option<&str>) { let _icx = push_ctxt("foreign::build_foreign_fn"); - let fnty = ty::node_id_to_type(ccx.tcx(), id); + let fnty = ccx.tcx().node_id_to_type(id); let mty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fnty); let tys = foreign_types_for_fn_ty(ccx, mty); @@ -601,7 +601,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, { let _icx = push_ctxt("foreign::foreign::build_rust_fn"); let tcx = ccx.tcx(); - let t = ty::node_id_to_type(tcx, id); + let t = tcx.node_id_to_type(id); let t = monomorphize::apply_param_substs(tcx, param_substs, &t); let ps = ccx.tcx().map.with_path(id, |path| { @@ -777,7 +777,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // pointer). It makes adapting types easier, since we can // always just bitcast pointers. if !foreign_indirect { - llforeign_arg = if ty::type_is_bool(rust_ty) { + llforeign_arg = if rust_ty.is_bool() { let lltemp = builder.alloca(Type::bool(ccx), ""); builder.store(builder.zext(llforeign_arg, Type::bool(ccx)), lltemp); lltemp @@ -799,7 +799,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let llrust_arg = if rust_indirect || type_is_fat_ptr(ccx.tcx(), rust_ty) { llforeign_arg } else { - if ty::type_is_bool(rust_ty) { + if rust_ty.is_bool() { let tmp = builder.load_range_assert(llforeign_arg, 0, 2, llvm::False); builder.trunc(tmp, Type::i1(ccx)) } else if type_of::type_of(ccx, rust_ty).is_aggregate() { @@ -933,7 +933,7 @@ fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn foreign_types_for_id<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId) -> ForeignTypes<'tcx> { - foreign_types_for_fn_ty(ccx, ty::node_id_to_type(ccx.tcx(), id)) + foreign_types_for_fn_ty(ccx, ccx.tcx().node_id_to_type(id)) } fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -942,7 +942,7 @@ fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty::TyBareFn(_, ref fn_ty) => &fn_ty.sig, _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type") }; - let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig); + let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); let llsig = foreign_signature(ccx, &fn_sig, &fn_sig.inputs); let fn_ty = cabi::compute_abi_info(ccx, &llsig.llarg_tys, diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index b84475d915a4f..e530eb0de59b8 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -218,7 +218,7 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let llty = if type_is_sized(ccx.tcx(), t) { type_of(ccx, t).ptr_to() } else { - type_of(ccx, ty::mk_uniq(ccx.tcx(), t)).ptr_to() + type_of(ccx, ccx.tcx().mk_box(t)).ptr_to() }; let llfnty = Type::glue_fn(ccx, llty); @@ -226,13 +226,13 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // To avoid infinite recursion, don't `make_drop_glue` until after we've // added the entry to the `drop_glues` cache. if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&g) { - let llfn = declare::declare_cfn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx())); + let llfn = declare::declare_cfn(ccx, &old_sym, llfnty, ccx.tcx().mk_nil()); ccx.drop_glues().borrow_mut().insert(g, llfn); return llfn; }; let fn_nm = mangle_internal_name_by_type_and_seq(ccx, t, "drop"); - let llfn = declare::define_cfn(ccx, &fn_nm, llfnty, ty::mk_nil(ccx.tcx())).unwrap_or_else(||{ + let llfn = declare::define_cfn(ccx, &fn_nm, llfnty, ccx.tcx().mk_nil()).unwrap_or_else(||{ ccx.sess().bug(&format!("symbol `{}` already defined", fn_nm)); }); ccx.available_drop_glues().borrow_mut().insert(g, fn_nm); @@ -243,10 +243,10 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let (arena, fcx): (TypedArena<_>, FunctionContext); arena = TypedArena::new(); fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false, - ty::FnConverging(ty::mk_nil(ccx.tcx())), + ty::FnConverging(ccx.tcx().mk_nil()), empty_substs, None, &arena); - let bcx = init_function(&fcx, false, ty::FnConverging(ty::mk_nil(ccx.tcx()))); + let bcx = init_function(&fcx, false, ty::FnConverging(ccx.tcx().mk_nil())); update_linkage(ccx, llfn, None, OriginalTranslation); @@ -261,7 +261,7 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let llrawptr0 = get_param(llfn, fcx.arg_offset() as c_uint); let bcx = make_drop_glue(bcx, llrawptr0, g); - finish_fn(&fcx, bcx, ty::FnConverging(ty::mk_nil(ccx.tcx())), DebugLoc::None); + finish_fn(&fcx, bcx, ty::FnConverging(ccx.tcx().mk_nil()), DebugLoc::None); llfn } @@ -326,12 +326,11 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } else { let tcx = ccx.tcx(); let name = csearch::get_symbol(&ccx.sess().cstore, did); - let class_ty = ty::lookup_item_type(tcx, parent_id).ty.subst(tcx, substs); + let class_ty = tcx.lookup_item_type(parent_id).ty.subst(tcx, substs); let llty = type_of_dtor(ccx, class_ty); - let dtor_ty = ty::mk_ctor_fn(ccx.tcx(), - did, - &[get_drop_glue_type(ccx, t)], - ty::mk_nil(ccx.tcx())); + let dtor_ty = ccx.tcx().mk_ctor_fn(did, + &[get_drop_glue_type(ccx, t)], + ccx.tcx().mk_nil()); foreign::get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), &name[..], llvm::CCallConv, llty, dtor_ty) } @@ -356,7 +355,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr)); ty.element_type().func_params() }; - assert_eq!(params.len(), 1); + assert_eq!(params.len(), if type_is_sized(bcx.tcx(), t) { 1 } else { 2 }); // Be sure to put the contents into a scope so we can use an invoke // instruction to call the user destructor but still call the field @@ -371,8 +370,13 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.fcx.schedule_drop_adt_contents(cleanup::CustomScope(contents_scope), v0, t); let glue_type = get_drop_glue_type(bcx.ccx(), t); - let dtor_ty = ty::mk_ctor_fn(bcx.tcx(), class_did, &[glue_type], ty::mk_nil(bcx.tcx())); - let (_, bcx) = invoke(bcx, dtor_addr, &[v0], dtor_ty, DebugLoc::None); + let dtor_ty = bcx.tcx().mk_ctor_fn(class_did, &[glue_type], bcx.tcx().mk_nil()); + let (_, bcx) = if type_is_sized(bcx.tcx(), t) { + invoke(bcx, dtor_addr, &[v0], dtor_ty, DebugLoc::None) + } else { + let args = [Load(bcx, expr::get_dataptr(bcx, v0)), Load(bcx, expr::get_len(bcx, v0))]; + invoke(bcx, dtor_addr, &args, dtor_ty, DebugLoc::None) + }; bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope) } @@ -392,7 +396,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in let ccx = bcx.ccx(); // First get the size of all statically known fields. // Don't use type_of::sizing_type_of because that expects t to be sized. - assert!(!ty::type_is_simd(bcx.tcx(), t)); + assert!(!t.is_simd(bcx.tcx())); let repr = adt::represent_type(ccx, t); let sizing_type = adt::sizing_type_of(ccx, &*repr, true); let sized_size = C_uint(ccx, llsize_of_alloc(ccx, sizing_type)); @@ -400,7 +404,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in // Recurse to get the size of the dynamically sized field (must be // the last field). - let fields = ty::struct_fields(bcx.tcx(), id, substs); + let fields = bcx.tcx().struct_fields(id, substs); let last_field = fields[fields.len()-1]; let field_ty = last_field.mt.ty; let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info); @@ -426,7 +430,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in (Load(bcx, size_ptr), Load(bcx, align_ptr)) } ty::TySlice(_) | ty::TyStr => { - let unit_ty = ty::sequence_element_type(bcx.tcx(), t); + let unit_ty = t.sequence_element_type(bcx.tcx()); // The info in this case is the length of the str, so the size is that // times the unit size. let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty); @@ -496,7 +500,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK } ty::TyStruct(did, substs) | ty::TyEnum(did, substs) => { let tcx = bcx.tcx(); - match (ty::ty_dtor(tcx, did), skip_dtor) { + match (tcx.ty_dtor(did), skip_dtor) { (ty::TraitDtor(dtor, true), false) => { // FIXME(16758) Since the struct is unsized, it is hard to // find the drop flag (which is at the end of the struct). diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index f860fe44f28e7..75c80690f2ad4 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -14,7 +14,6 @@ use middle::astencode; use middle::subst::Substs; use trans::base::{push_ctxt, trans_item, get_item_val, trans_fn}; use trans::common::*; -use middle::ty; use syntax::ast; use syntax::ast_util::local_def; @@ -28,7 +27,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) Some(&Some(node_id)) => { // Already inline debug!("instantiate_inline({}): already inline as node id {}", - ty::item_path_str(ccx.tcx(), fn_id), node_id); + ccx.tcx().item_path_str(fn_id), node_id); return Some(local_def(node_id)); } Some(&None) => { @@ -104,8 +103,8 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) let mut my_id = 0; match item.node { ast::ItemEnum(_, _) => { - let vs_here = ty::enum_variants(ccx.tcx(), local_def(item.id)); - let vs_there = ty::enum_variants(ccx.tcx(), parent_id); + let vs_here = ccx.tcx().enum_variants(local_def(item.id)); + let vs_there = ccx.tcx().enum_variants(parent_id); for (here, there) in vs_here.iter().zip(vs_there.iter()) { if there.id == fn_id { my_id = here.id.node; } ccx.external().borrow_mut().insert(there.id, Some(here.id.node)); @@ -140,7 +139,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) // the logic to do that already exists in `middle`. In order to // reuse that code, it needs to be able to look up the traits for // inlined items. - let ty_trait_item = ty::impl_or_trait_item(ccx.tcx(), fn_id).clone(); + let ty_trait_item = ccx.tcx().impl_or_trait_item(fn_id).clone(); ccx.tcx().impl_or_trait_items.borrow_mut() .insert(local_def(trait_item.id), ty_trait_item); @@ -157,7 +156,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) // Translate monomorphic impl methods immediately. if let ast::MethodImplItem(ref sig, ref body) = impl_item.node { - let impl_tpt = ty::lookup_item_type(ccx.tcx(), impl_did); + let impl_tpt = ccx.tcx().lookup_item_type(impl_did); if impl_tpt.generics.types.is_empty() && sig.generics.ty_params.is_empty() { let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index dd97265e428ed..b449c3ad060b8 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -30,7 +30,7 @@ use trans::type_of; use trans::machine; use trans::machine::llsize_of; use trans::type_::Type; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags}; use syntax::abi::RustIntrinsic; use syntax::ast; use syntax::parse::token; @@ -103,8 +103,8 @@ pub fn check_intrinsics(ccx: &CrateContext) { debug!("transmute_restriction: {:?}", transmute_restriction); - assert!(!ty::type_has_params(transmute_restriction.substituted_from)); - assert!(!ty::type_has_params(transmute_restriction.substituted_to)); + assert!(!transmute_restriction.substituted_from.has_param_types()); + assert!(!transmute_restriction.substituted_to.has_param_types()); let llfromtype = type_of::sizing_type_of(ccx, transmute_restriction.substituted_from); @@ -163,7 +163,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let ret_ty = match callee_ty.sty { ty::TyBareFn(_, ref f) => { - ty::erase_late_bound_regions(bcx.tcx(), &f.sig.output()) + bcx.tcx().erase_late_bound_regions(&f.sig.output()) } _ => panic!("expected bare_fn in trans_intrinsic_call") }; @@ -411,10 +411,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_str_slice(ccx, ty_name) } (_, "type_id") => { - let hash = ty::hash_crate_independent( - ccx.tcx(), - *substs.types.get(FnSpace, 0), - &ccx.link_meta().crate_hash); + let hash = ccx.tcx().hash_crate_independent(*substs.types.get(FnSpace, 0), + &ccx.link_meta().crate_hash); C_u64(ccx, hash) } (_, "init_dropped") => { diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index e61770768db22..1fa996f76b9a2 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -17,7 +17,6 @@ use middle::subst::{Subst, Substs}; use middle::subst::VecPerParamSpace; use middle::subst; use middle::traits; -use middle::ty::ClosureTyper; use rustc::ast_map; use trans::base::*; use trans::build::*; @@ -37,10 +36,9 @@ use trans::machine; use trans::monomorphize; use trans::type_::Type; use trans::type_of::*; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty::MethodCall; -use syntax::abi::{Rust, RustCall}; use syntax::parse::token; use syntax::{ast, attr, visit}; use syntax::codemap::DUMMY_SP; @@ -108,32 +106,28 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, -> Callee<'blk, 'tcx> { let _icx = push_ctxt("meth::trans_method_callee"); - let (origin, method_ty) = - bcx.tcx().method_map - .borrow() - .get(&method_call) - .map(|method| (method.origin.clone(), method.ty)) - .unwrap(); - - match origin { - ty::MethodStatic(did) | - ty::MethodStaticClosure(did) => { - debug!("trans_method_callee: static, {:?}", did); + let method = bcx.tcx().tables.borrow().method_map[&method_call]; + + match bcx.tcx().impl_or_trait_item(method.def_id).container() { + ty::ImplContainer(_) => { + debug!("trans_method_callee: static, {:?}", method.def_id); + let datum = callee::trans_fn_ref(bcx.ccx(), + method.def_id, + MethodCallKey(method_call), + bcx.fcx.param_substs); Callee { bcx: bcx, - data: Fn(callee::trans_fn_ref(bcx.ccx(), - did, - MethodCallKey(method_call), - bcx.fcx.param_substs).val), + data: Fn(datum.val), + ty: datum.ty } } - ty::MethodTypeParam(ty::MethodParam { - ref trait_ref, - method_num, - impl_def_id: _ - }) => { - let trait_ref = ty::Binder(bcx.monomorphize(trait_ref)); + ty::TraitContainer(trait_def_id) => { + let trait_substs = method.substs.clone().method_to_trait(); + let trait_substs = bcx.tcx().mk_substs(trait_substs); + let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs); + + let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref)); let span = bcx.tcx().map.span(method_call.expr_id); debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}", method_call, @@ -146,25 +140,12 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("origin = {:?}", origin); trans_monomorphized_callee(bcx, method_call, - trait_ref.def_id(), - method_num, - origin) - } - - ty::MethodTraitObject(ref mt) => { - let self_expr = match self_expr { - Some(self_expr) => self_expr, - None => { - bcx.sess().span_bug(bcx.tcx().map.span(method_call.expr_id), - "self expr wasn't provided for trait object \ - callee (trying to call overloaded op?)") - } - }; - trans_trait_callee(bcx, - monomorphize_type(bcx, method_ty), - mt.vtable_index, - self_expr, - arg_cleanup_scope) + self_expr, + trait_def_id, + method.def_id, + method.ty, + origin, + arg_cleanup_scope) } } } @@ -182,7 +163,7 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("trans_static_method_callee(method_id={:?}, trait_id={}, \ expr_id={})", method_id, - ty::item_path_str(tcx, trait_id), + tcx.item_path_str(trait_id), expr_id); let mname = if method_id.krate == ast::LOCAL_CRATE { @@ -234,8 +215,7 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Vec::new())); let trait_substs = tcx.mk_substs(trait_substs); debug!("trait_substs={:?}", trait_substs); - let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id, - substs: trait_substs }); + let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs)); let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); @@ -248,7 +228,7 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, substs: impl_substs, nested: _ }) => { - assert!(impl_substs.types.all(|t| !ty::type_needs_infer(*t))); + assert!(!impl_substs.types.needs_infer()); // Create the substitutions that are in scope. This combines // the type parameters from the impl with those declared earlier. @@ -281,18 +261,11 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, callee_substs) } traits::VtableObject(ref data) => { - let trait_item_def_ids = - ty::trait_item_def_ids(ccx.tcx(), trait_id); - let method_offset_in_trait = - trait_item_def_ids.iter() - .position(|item| item.def_id() == method_id) - .unwrap(); - let (llfn, ty) = - trans_object_shim(ccx, - data.object_ty, - data.upcast_trait_ref.clone(), - method_offset_in_trait); - immediate_rvalue(llfn, ty) + let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id); + trans_object_shim(ccx, + data.upcast_trait_ref.clone(), + method_id, + idx) } _ => { tcx.sess.bug(&format!("static call to invalid vtable: {:?}", @@ -314,7 +287,7 @@ fn method_with_name(ccx: &CrateContext, impl_id: ast::DefId, name: ast::Name) .expect("could not find impl while translating"); let meth_did = impl_items.iter() .find(|&did| { - ty::impl_or_trait_item(ccx.tcx(), did.def_id()).name() == name + ccx.tcx().impl_or_trait_item(did.def_id()).name() == name }).expect("could not find method while \ translating"); @@ -325,16 +298,19 @@ fn method_with_name(ccx: &CrateContext, impl_id: ast::DefId, name: ast::Name) fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_call: MethodCall, + self_expr: Option<&ast::Expr>, trait_id: ast::DefId, - n_method: usize, - vtable: traits::Vtable<'tcx, ()>) + method_id: ast::DefId, + method_ty: Ty<'tcx>, + vtable: traits::Vtable<'tcx, ()>, + arg_cleanup_scope: cleanup::ScopeId) -> Callee<'blk, 'tcx> { let _icx = push_ctxt("meth::trans_monomorphized_callee"); match vtable { traits::VtableImpl(vtable_impl) => { let ccx = bcx.ccx(); let impl_did = vtable_impl.impl_def_id; - let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) { + let mname = match ccx.tcx().impl_or_trait_item(method_id) { ty::MethodTraitItem(method) => method.name, _ => { bcx.tcx().sess.bug("can't monomorphize a non-method trait \ @@ -350,13 +326,13 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx, MethodCallKey(method_call), vtable_impl.substs); // translate the function - let llfn = trans_fn_ref_with_substs(bcx.ccx(), - mth_id, - MethodCallKey(method_call), - bcx.fcx.param_substs, - callee_substs).val; + let datum = trans_fn_ref_with_substs(bcx.ccx(), + mth_id, + MethodCallKey(method_call), + bcx.fcx.param_substs, + callee_substs); - Callee { bcx: bcx, data: Fn(llfn) } + Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty } } traits::VtableClosure(vtable_closure) => { // The substitutions should have no type parameters remaining @@ -371,19 +347,31 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Callee { bcx: bcx, data: Fn(llfn), + ty: monomorphize_type(bcx, method_ty) } } traits::VtableFnPointer(fn_ty) => { let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty); - Callee { bcx: bcx, data: Fn(llfn) } + Callee { + bcx: bcx, + data: Fn(llfn), + ty: monomorphize_type(bcx, method_ty) + } } traits::VtableObject(ref data) => { - let (llfn, _) = trans_object_shim(bcx.ccx(), - data.object_ty, - data.upcast_trait_ref.clone(), - n_method); - Callee { bcx: bcx, data: Fn(llfn) } + let idx = traits::get_vtable_index_of_object_method(bcx.tcx(), data, method_id); + if let Some(self_expr) = self_expr { + if let ty::TyBareFn(_, ref fty) = monomorphize_type(bcx, method_ty).sty { + let ty = bcx.tcx().mk_fn(None, opaque_method_ty(bcx.tcx(), fty)); + return trans_trait_callee(bcx, ty, idx, self_expr, arg_cleanup_scope); + } + } + let datum = trans_object_shim(bcx.ccx(), + data.upcast_trait_ref.clone(), + method_id, + idx); + Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty } } traits::VtableBuiltin(..) | traits::VtableDefaultImpl(..) | @@ -437,7 +425,7 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// object. Objects are represented as a pair, so we first evaluate the self expression and then /// extract the self data and vtable out of the pair. fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - method_ty: Ty<'tcx>, + opaque_fn_ty: Ty<'tcx>, vtable_index: usize, self_expr: &ast::Expr, arg_cleanup_scope: cleanup::ScopeId) @@ -470,51 +458,39 @@ fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llself = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_ADDR])); let llvtable = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_EXTRA])); - trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llself, llvtable) + trans_trait_callee_from_llval(bcx, opaque_fn_ty, vtable_index, llself, llvtable) } /// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object /// pair. -pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - callee_ty: Ty<'tcx>, - vtable_index: usize, - llself: ValueRef, - llvtable: ValueRef) - -> Callee<'blk, 'tcx> { +fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + opaque_fn_ty: Ty<'tcx>, + vtable_index: usize, + llself: ValueRef, + llvtable: ValueRef) + -> Callee<'blk, 'tcx> { let _icx = push_ctxt("meth::trans_trait_callee"); let ccx = bcx.ccx(); // Load the data pointer from the object. debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})", - callee_ty, + opaque_fn_ty, vtable_index, bcx.val_to_string(llself), bcx.val_to_string(llvtable)); // Replace the self type (&Self or Box) with an opaque pointer. - let llcallee_ty = match callee_ty.sty { - ty::TyBareFn(_, ref f) if f.abi == Rust || f.abi == RustCall => { - let fake_sig = - ty::Binder(ty::FnSig { - inputs: f.sig.0.inputs[1..].to_vec(), - output: f.sig.0.output, - variadic: f.sig.0.variadic, - }); - type_of_rust_fn(ccx, Some(Type::i8p(ccx)), &fake_sig, f.abi) - } - _ => { - ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn"); - } - }; let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET])); + let llcallee_ty = type_of_fn_from_ty(ccx, opaque_fn_ty); - return Callee { + Callee { bcx: bcx, data: TraitItem(MethodData { llfn: PointerCast(bcx, mptr, llcallee_ty.ptr_to()), llself: PointerCast(bcx, llself, Type::i8p(ccx)), - }) - }; + }), + ty: opaque_fn_ty + } } /// Generate a shim function that allows an object type like `SomeTrait` to @@ -539,40 +515,27 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// /// In fact, all virtual calls can be thought of as normal trait calls /// that go through this shim function. -pub fn trans_object_shim<'a, 'tcx>( +fn trans_object_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, - object_ty: Ty<'tcx>, upcast_trait_ref: ty::PolyTraitRef<'tcx>, - method_offset_in_trait: usize) - -> (ValueRef, Ty<'tcx>) + method_id: ast::DefId, + vtable_index: usize) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_object_shim"); let tcx = ccx.tcx(); - let trait_id = upcast_trait_ref.def_id(); - debug!("trans_object_shim(object_ty={:?}, upcast_trait_ref={:?}, method_offset_in_trait={})", - object_ty, + debug!("trans_object_shim(upcast_trait_ref={:?}, method_id={:?})", upcast_trait_ref, - method_offset_in_trait); - - let object_trait_ref = - match object_ty.sty { - ty::TyTrait(ref data) => { - data.principal_trait_ref_with_self_ty(tcx, object_ty) - } - _ => { - tcx.sess.bug(&format!("trans_object_shim() called on non-object: {:?}", - object_ty)); - } - }; + method_id); // Upcast to the trait in question and extract out the substitutions. - let upcast_trait_ref = ty::erase_late_bound_regions(tcx, &upcast_trait_ref); + let upcast_trait_ref = tcx.erase_late_bound_regions(&upcast_trait_ref); let object_substs = upcast_trait_ref.substs.clone().erase_regions(); debug!("trans_object_shim: object_substs={:?}", object_substs); // Lookup the type of this method as declared in the trait and apply substitutions. - let method_ty = match ty::trait_item(tcx, trait_id, method_offset_in_trait) { + let method_ty = match tcx.impl_or_trait_item(method_id) { ty::MethodTraitItem(method) => method, _ => { tcx.sess.bug("can't create a method shim for a non-method item") @@ -584,14 +547,14 @@ pub fn trans_object_shim<'a, 'tcx>( debug!("trans_object_shim: fty={:?} method_ty={:?}", fty, method_ty); // - let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty); - let method_bare_fn_ty = ty::mk_bare_fn(tcx, None, method_ty); + let shim_fn_ty = tcx.mk_fn(None, fty); + let method_bare_fn_ty = tcx.mk_fn(None, method_ty); let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{ ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); }); - let sig = ty::erase_late_bound_regions(ccx.tcx(), &fty.sig); + let sig = ccx.tcx().erase_late_bound_regions(&fty.sig); let empty_substs = tcx.mk_substs(Substs::trans_empty()); let (block_arena, fcx): (TypedArena<_>, FunctionContext); @@ -621,27 +584,21 @@ pub fn trans_object_shim<'a, 'tcx>( fcx.llretslotptr.get().map( |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); - let method_offset_in_vtable = - traits::get_vtable_index_of_object_method(bcx.tcx(), - object_trait_ref.clone(), - trait_id, - method_offset_in_trait); debug!("trans_object_shim: method_offset_in_vtable={}", - method_offset_in_vtable); + vtable_index); bcx = trans_call_inner(bcx, DebugLoc::None, - method_bare_fn_ty, |bcx, _| trans_trait_callee_from_llval(bcx, method_bare_fn_ty, - method_offset_in_vtable, + vtable_index, llself, llvtable), ArgVals(&llargs[(self_idx + 2)..]), dest).bcx; finish_fn(&fcx, bcx, sig.output, DebugLoc::None); - (llfn, method_bare_fn_ty) + immediate_rvalue(llfn, shim_fn_ty) } /// Creates a returns a dynamic vtable for the given type and vtable origin. @@ -747,16 +704,16 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, substs, param_substs); - let trt_id = match ty::impl_trait_ref(tcx, impl_id) { + let trt_id = match tcx.impl_trait_ref(impl_id) { Some(t_id) => t_id.def_id, None => ccx.sess().bug("make_impl_vtable: don't know how to \ make a vtable for a type impl!") }; - ty::populate_implementations_for_trait_if_necessary(tcx, trt_id); + tcx.populate_implementations_for_trait_if_necessary(trt_id); let nullptr = C_null(Type::nil(ccx).ptr_to()); - let trait_item_def_ids = ty::trait_item_def_ids(tcx, trt_id); + let trait_item_def_ids = tcx.trait_item_def_ids(trt_id); trait_item_def_ids .iter() @@ -775,7 +732,7 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("emit_vtable_methods: trait_method_def_id={:?}", trait_method_def_id); - let trait_method_type = match ty::impl_or_trait_item(tcx, trait_method_def_id) { + let trait_method_type = match tcx.impl_or_trait_item(trait_method_def_id) { ty::MethodTraitItem(m) => m, _ => ccx.sess().bug("should be a method, not other assoc item"), }; @@ -793,7 +750,7 @@ fn emit_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 impl_method_def_id = method_with_name(ccx, impl_id, name); - let impl_method_type = match ty::impl_or_trait_item(tcx, impl_method_def_id) { + let impl_method_type = match tcx.impl_or_trait_item(impl_method_def_id) { ty::MethodTraitItem(m) => m, _ => ccx.sess().bug("should be a method, not other assoc item"), }; @@ -806,7 +763,7 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // particular set of type parameters. Note that this // method could then never be called, so we do not want to // try and trans it, in that case. Issue #23435. - if ty::provided_source(tcx, impl_method_def_id).is_some() { + if tcx.provided_source(impl_method_def_id).is_some() { let predicates = impl_method_type.predicates.predicates.subst(tcx, &substs); if !normalize_and_test_predicates(ccx, predicates.into_vec()) { debug!("emit_vtable_methods: predicates do not hold"); @@ -824,10 +781,10 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } /// Replace the self type (&Self or Box) with an opaque pointer. -pub fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>) - -> &'tcx ty::BareFnTy<'tcx> { +fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>) + -> &'tcx ty::BareFnTy<'tcx> { let mut inputs = method_ty.sig.0.inputs.clone(); - inputs[0] = ty::mk_mut_ptr(tcx, ty::mk_mach_int(tcx, ast::TyI8)); + inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(ast::TyI8)); tcx.mk_bare_fn(ty::BareFnTy { unsafety: method_ty.unsafety, diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index f4bad313bafb1..98fe57ec31446 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -25,7 +25,7 @@ use trans::base; use trans::common::*; use trans::declare; use trans::foreign; -use middle::ty::{self, HasProjectionTypes, Ty}; +use middle::ty::{self, HasTypeFlags, Ty}; use syntax::abi; use syntax::ast; @@ -47,9 +47,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, psubsts, ref_id); - assert!(psubsts.types.all(|t| { - !ty::type_needs_infer(*t) && !ty::type_has_params(*t) - })); + assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types()); let _icx = push_ctxt("monomorphic_fn"); @@ -58,15 +56,16 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, params: &psubsts.types }; - let item_ty = ty::lookup_item_type(ccx.tcx(), fn_id).ty; + let item_ty = ccx.tcx().lookup_item_type(fn_id).ty; debug!("monomorphic_fn about to subst into {:?}", item_ty); - let mono_ty = item_ty.subst(ccx.tcx(), psubsts); + let mono_ty = apply_param_substs(ccx.tcx(), psubsts, &item_ty); + debug!("mono_ty = {:?} (post-substitution)", mono_ty); match ccx.monomorphized().borrow().get(&hash_id) { Some(&val) => { debug!("leaving monomorphic fn {}", - ty::item_path_str(ccx.tcx(), fn_id)); + ccx.tcx().item_path_str(fn_id)); return (val, mono_ty, false); } None => () @@ -98,11 +97,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } - debug!("mono_ty = {:?} (post-substitution)", mono_ty); - - let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty); - debug!("mono_ty = {:?} (post-normalization)", mono_ty); - ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1); let depth; @@ -200,7 +194,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } ast_map::NodeVariant(v) => { let parent = ccx.tcx().map.get_parent(fn_id.node); - let tvs = ty::enum_variants(ccx.tcx(), local_def(parent)); + let tvs = ccx.tcx().enum_variants(local_def(parent)); let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap(); let d = mk_lldecl(abi::Rust); attributes::inline(d, attributes::InlineAttr::Hint); @@ -286,7 +280,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.monomorphizing().borrow_mut().insert(fn_id, depth); - debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id)); + debug!("leaving monomorphic fn {}", ccx.tcx().item_path_str(fn_id)); (lldecl, mono_ty, true) } @@ -302,7 +296,7 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>, param_substs: &Substs<'tcx>, value: &T) -> T - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { let substituted = value.subst(tcx, param_substs); normalize_associated_type(tcx, &substituted) @@ -313,7 +307,7 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>, /// and hence we can be sure that all associated types will be /// completely normalized away. pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { debug!("normalize_associated_type(t={:?})", value); @@ -324,10 +318,8 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T } // FIXME(#20304) -- cache - - let infcx = infer::new_infer_ctxt(tcx); - let typer = NormalizingClosureTyper::new(tcx); - let mut selcx = traits::SelectionContext::new(&infcx, &typer); + let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables); + let mut selcx = traits::SelectionContext::new(&infcx); let cause = traits::ObligationCause::dummy(); let traits::Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, &value); @@ -336,7 +328,8 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T result, obligations); - let mut fulfill_cx = traits::FulfillmentContext::new(true); + let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut(); + for obligation in obligations { fulfill_cx.register_predicate_obligation(&infcx, obligation); } diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index bba0f6d26083a..d94a0e235ee86 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -106,9 +106,7 @@ pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let count = elements_required(bcx, content_expr); debug!(" vt={}, count={}", vt.to_string(ccx), count); - let fixed_ty = ty::mk_vec(bcx.tcx(), - vt.unit_ty, - Some(count)); + let fixed_ty = bcx.tcx().mk_array(vt.unit_ty, count); let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty); // Always create an alloca even if zero-sized, to preserve @@ -227,7 +225,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return expr::trans_into(bcx, &**element, Ignore); } SaveIn(lldest) => { - match ty::eval_repeat_count(bcx.tcx(), &**count_expr) { + match bcx.tcx().eval_repeat_count(&**count_expr) { 0 => expr::trans_into(bcx, &**element, Ignore), 1 => expr::trans_into(bcx, &**element, SaveIn(lldest)), count => { @@ -253,7 +251,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn vec_types_from_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, vec_expr: &ast::Expr) -> VecTypes<'tcx> { let vec_ty = node_id_type(bcx, vec_expr.id); - vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty)) + vec_types(bcx, vec_ty.sequence_element_type(bcx.tcx())) } fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, unit_ty: Ty<'tcx>) @@ -279,7 +277,7 @@ fn elements_required(bcx: Block, content_expr: &ast::Expr) -> usize { }, ast::ExprVec(ref es) => es.len(), ast::ExprRepeat(_, ref count_expr) => { - ty::eval_repeat_count(bcx.tcx(), &**count_expr) + bcx.tcx().eval_repeat_count(&**count_expr) } _ => bcx.tcx().sess.span_bug(content_expr.span, "unexpected vec content") diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 49601ac6fe94d..4359a8d270da2 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -54,17 +54,11 @@ pub fn type_of_explicit_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -/// Yields the types of the "real" arguments for this function. For most -/// functions, these are simply the types of the arguments. For functions with -/// the `RustCall` ABI, however, this untuples the arguments of the function. -pub fn untuple_arguments_if_necessary<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - inputs: &[Ty<'tcx>], - abi: abi::Abi) - -> Vec> { - if abi != abi::RustCall { - return inputs.iter().cloned().collect() - } - +/// Yields the types of the "real" arguments for a function using the `RustCall` +/// ABI by untupling the arguments of the function. +pub fn untuple_arguments<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + inputs: &[Ty<'tcx>]) + -> Vec> { if inputs.is_empty() { return Vec::new() } @@ -78,7 +72,7 @@ pub fn untuple_arguments_if_necessary<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, match inputs[inputs.len() - 1].sty { ty::TyTuple(ref tupled_arguments) => { - debug!("untuple_arguments_if_necessary(): untupling arguments"); + debug!("untuple_arguments(): untupling arguments"); for &tupled_argument in tupled_arguments { result.push(tupled_argument); } @@ -102,13 +96,17 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, sig, abi); - let sig = ty::erase_late_bound_regions(cx.tcx(), sig); + let sig = cx.tcx().erase_late_bound_regions(sig); assert!(!sig.variadic); // rust fns are never variadic let mut atys: Vec = Vec::new(); // First, munge the inputs, if this has the `rust-call` ABI. - let inputs = untuple_arguments_if_necessary(cx, &sig.inputs, abi); + let inputs = &if abi == abi::RustCall { + untuple_arguments(cx, &sig.inputs) + } else { + sig.inputs + }; // Arg 0: Output pointer. // (if the output type is non-immediate) @@ -136,7 +134,7 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } // ... then explicit args. - for input in &inputs { + for input in inputs { let arg_ty = type_of_explicit_arg(cx, input); if type_is_fat_ptr(cx.tcx(), input) { @@ -222,9 +220,9 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ } ty::TyStruct(..) => { - if ty::type_is_simd(cx.tcx(), t) { - let llet = type_of(cx, ty::simd_type(cx.tcx(), t)); - let n = ty::simd_size(cx.tcx(), t) as u64; + if t.is_simd(cx.tcx()) { + let llet = type_of(cx, t.simd_type(cx.tcx())); + let n = t.simd_size(cx.tcx()) as u64; ensure_array_fits_in_address_space(cx, llet, n, t); Type::vector(&llet, n) } else { @@ -245,7 +243,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ } pub fn foreign_arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { - if ty::type_is_bool(t) { + if t.is_bool() { Type::i1(cx) } else { type_of(cx, t) @@ -253,7 +251,7 @@ pub fn foreign_arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) - } pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { - if ty::type_is_bool(t) { + if t.is_bool() { Type::i1(cx) } else if type_is_immediate(cx, t) && type_of(cx, t).is_aggregate() { // We want to pass small aggregates as immediate values, but using an aggregate LLVM type @@ -278,7 +276,7 @@ pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { /// For the raw type without far pointer indirection, see `in_memory_type_of`. pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { let ty = if !type_is_sized(cx.tcx(), ty) { - ty::mk_imm_ptr(cx.tcx(), ty) + cx.tcx().mk_imm_ptr(ty) } else { ty }; @@ -362,7 +360,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> cx.tn().find_type("str_slice").unwrap() } else { let ptr_ty = in_memory_type_of(cx, ty).ptr_to(); - let unsized_part = ty::struct_tail(cx.tcx(), ty); + let unsized_part = cx.tcx().struct_tail(ty); let info_ty = match unsized_part.sty { ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => { Type::uint_from_ty(cx, ast::TyUs) @@ -402,9 +400,9 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> adt::type_of(cx, &*repr) } ty::TyStruct(did, ref substs) => { - if ty::type_is_simd(cx.tcx(), t) { - let llet = in_memory_type_of(cx, ty::simd_type(cx.tcx(), t)); - let n = ty::simd_size(cx.tcx(), t) as u64; + if t.is_simd(cx.tcx()) { + let llet = in_memory_type_of(cx, t.simd_type(cx.tcx())); + let n = t.simd_size(cx.tcx()) as u64; ensure_array_fits_in_address_space(cx, llet, n, t); Type::vector(&llet, n) } else { @@ -434,7 +432,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // If this was an enum or struct, fill in the type now. match t.sty { ty::TyEnum(..) | ty::TyStruct(..) | ty::TyClosure(..) - if !ty::type_is_simd(cx.tcx(), t) => { + if !t.is_simd(cx.tcx()) => { let repr = adt::represent_type(cx, t); adt::finish_type_of(cx, &*repr, &mut llty); } @@ -454,7 +452,7 @@ fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, did: ast::DefId, tps: &[Ty<'tcx>]) -> String { - let base = ty::item_path_str(cx.tcx(), did); + let base = cx.tcx().item_path_str(did); let strings: Vec = tps.iter().map(|t| t.to_string()).collect(); let tstr = if strings.is_empty() { base diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index da7c262d63a65..7f29af0d84b2d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -56,10 +56,11 @@ use middle::resolve_lifetime as rl; use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; -use middle::ty::{self, RegionEscape, Ty, AsPredicate}; +use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags}; use middle::ty_fold; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope, - ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; + ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope, + ElisionFailureInfo, ElidedLifetime}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::FnvHashSet; @@ -124,14 +125,14 @@ pub trait AstConv<'tcx> { item_name: ast::Name) -> Ty<'tcx> { - if ty::binds_late_bound_regions(self.tcx(), &poly_trait_ref) { + if let Some(trait_ref) = self.tcx().no_late_bound_regions(&poly_trait_ref) { + self.projected_ty(span, trait_ref, item_name) + } else { + // no late-bound regions, we can just ignore the binder span_err!(self.tcx().sess, span, E0212, "cannot extract an associated type from a higher-ranked trait bound \ in this context"); self.tcx().types.err - } else { - // no late-bound regions, we can just ignore the binder - self.projected_ty(span, poly_trait_ref.0.clone(), item_name) } } @@ -186,6 +187,58 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) r } +fn report_elision_failure( + tcx: &ty::ctxt, + default_span: Span, + params: Vec) +{ + let mut m = String::new(); + let len = params.len(); + for (i, info) in params.into_iter().enumerate() { + let ElisionFailureInfo { + name, lifetime_count: n, have_bound_regions + } = info; + + let help_name = if name.is_empty() { + format!("argument {}", i + 1) + } else { + format!("`{}`", name) + }; + + m.push_str(&(if n == 1 { + help_name + } else { + format!("one of {}'s {} elided {}lifetimes", help_name, n, + if have_bound_regions { "free " } else { "" } ) + })[..]); + + if len == 2 && i == 0 { + m.push_str(" or "); + } else if i + 2 == len { + m.push_str(", or "); + } else if i + 1 != len { + m.push_str(", "); + } + } + if len == 1 { + fileline_help!(tcx.sess, default_span, + "this function's return type contains a borrowed value, but \ + the signature does not say which {} it is borrowed from", + m); + } else if len == 0 { + fileline_help!(tcx.sess, default_span, + "this function's return type contains a borrowed value, but \ + there is no value for it to be borrowed from"); + fileline_help!(tcx.sess, default_span, + "consider giving it a 'static lifetime"); + } else { + fileline_help!(tcx.sess, default_span, + "this function's return type contains a borrowed value, but \ + the signature does not say whether it is borrowed from {}", + m); + } +} + pub fn opt_ast_region_to_region<'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, @@ -197,61 +250,15 @@ pub fn opt_ast_region_to_region<'tcx>( ast_region_to_region(this.tcx(), lifetime) } - None => { - match rscope.anon_regions(default_span, 1) { - Err(v) => { - debug!("optional region in illegal location"); - span_err!(this.tcx().sess, default_span, E0106, - "missing lifetime specifier"); - match v { - Some(v) => { - let mut m = String::new(); - let len = v.len(); - for (i, (name, n)) in v.into_iter().enumerate() { - let help_name = if name.is_empty() { - format!("argument {}", i + 1) - } else { - format!("`{}`", name) - }; - - m.push_str(&(if n == 1 { - help_name - } else { - format!("one of {}'s {} elided lifetimes", help_name, n) - })[..]); - - if len == 2 && i == 0 { - m.push_str(" or "); - } else if i + 2 == len { - m.push_str(", or "); - } else if i + 1 != len { - m.push_str(", "); - } - } - if len == 1 { - fileline_help!(this.tcx().sess, default_span, - "this function's return type contains a borrowed value, but \ - the signature does not say which {} it is borrowed from", - m); - } else if len == 0 { - fileline_help!(this.tcx().sess, default_span, - "this function's return type contains a borrowed value, but \ - there is no value for it to be borrowed from"); - fileline_help!(this.tcx().sess, default_span, - "consider giving it a 'static lifetime"); - } else { - fileline_help!(this.tcx().sess, default_span, - "this function's return type contains a borrowed value, but \ - the signature does not say whether it is borrowed from {}", - m); - } - } - None => {}, - } - ty::ReStatic + None => match rscope.anon_regions(default_span, 1) { + Ok(rs) => rs[0], + Err(params) => { + span_err!(this.tcx().sess, default_span, E0106, + "missing lifetime specifier"); + if let Some(params) = params { + report_elision_failure(this.tcx(), default_span, params); } - - Ok(rs) => rs[0], + ty::ReStatic } } }; @@ -439,7 +446,7 @@ fn create_substs_for_ast_path<'tcx>( // other type parameters may reference `Self` in their // defaults. This will lead to an ICE if we are not // careful! - if self_ty.is_none() && ty::type_has_self(default) { + if self_ty.is_none() && default.has_self_ty() { span_err!(tcx.sess, span, E0393, "the type parameter `{}` must be explicitly specified \ in an object type because its default value `{}` references \ @@ -505,48 +512,54 @@ fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>, /// Returns the appropriate lifetime to use for any output lifetimes /// (if one exists) and a vector of the (pattern, number of lifetimes) /// corresponding to each input type/pattern. -fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec) - -> (Option, Vec<(String, usize)>) +fn find_implied_output_region<'tcx>(tcx: &ty::ctxt<'tcx>, + input_tys: &[Ty<'tcx>], + input_pats: Vec) -> ElidedLifetime { - let mut lifetimes_for_params: Vec<(String, usize)> = Vec::new(); + let mut lifetimes_for_params = Vec::new(); let mut possible_implied_output_region = None; for (input_type, input_pat) in input_tys.iter().zip(input_pats) { - let mut accumulator = Vec::new(); - ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type); + let mut regions = FnvHashSet(); + let have_bound_regions = ty_fold::collect_regions(tcx, + input_type, + &mut regions); + + debug!("find_implied_output_regions: collected {:?} from {:?} \ + have_bound_regions={:?}", ®ions, input_type, have_bound_regions); - if accumulator.len() == 1 { + if regions.len() == 1 { // there's a chance that the unique lifetime of this // iteration will be the appropriate lifetime for output // parameters, so lets store it. - possible_implied_output_region = Some(accumulator[0]) + possible_implied_output_region = regions.iter().cloned().next(); } - lifetimes_for_params.push((input_pat, accumulator.len())); + lifetimes_for_params.push(ElisionFailureInfo { + name: input_pat, + lifetime_count: regions.len(), + have_bound_regions: have_bound_regions + }); } - let implied_output_region = - if lifetimes_for_params.iter().map(|&(_, n)| n).sum::() == 1 { - assert!(possible_implied_output_region.is_some()); - possible_implied_output_region - } else { - None - }; - (implied_output_region, lifetimes_for_params) + if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::() == 1 { + Ok(possible_implied_output_region.unwrap()) + } else { + Err(Some(lifetimes_for_params)) + } } fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>, - implied_output_region: Option, - param_lifetimes: Vec<(String, usize)>, + elided_lifetime: ElidedLifetime, ty: &ast::Ty) -> Ty<'tcx> { - match implied_output_region { - Some(implied_output_region) => { + match elided_lifetime { + Ok(implied_output_region) => { let rb = ElidableRscope::new(implied_output_region); ast_ty_to_ty(this, &rb, ty) } - None => { + Err(param_lifetimes) => { // All regions must be explicitly specified in the output // if the lifetime elision rules do not apply. This saves // the user from potentially-confusing errors. @@ -576,21 +589,19 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>, .collect::>>(); let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect(); - let (implied_output_region, - params_lifetimes) = find_implied_output_region(&*inputs, input_params); + let implied_output_region = find_implied_output_region(this.tcx(), &inputs, input_params); - let input_ty = ty::mk_tup(this.tcx(), inputs); + let input_ty = this.tcx().mk_tup(inputs); let (output, output_span) = match data.output { Some(ref output_ty) => { (convert_ty_with_lifetime_elision(this, implied_output_region, - params_lifetimes, - &**output_ty), + &output_ty), output_ty.span) } None => { - (ty::mk_nil(this.tcx()), data.span) + (this.tcx().mk_nil(), data.span) } }; @@ -852,7 +863,7 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>( // this, we currently insert a dummy type and then remove it // later. Yuck. - let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0)); + let dummy_self_ty = tcx.mk_infer(ty::FreshTy(0)); if self_ty.is_none() { // if converting for an object type let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+ assert!(dummy_substs.self_ty().is_none()); // | @@ -924,7 +935,7 @@ fn ast_path_to_ty<'tcx>( // FIXME(#12938): This is a hack until we have full support for DST. if Some(did) == this.tcx().lang_items.owned_box() { assert_eq!(substs.types.len(TypeSpace), 1); - return ty::mk_uniq(this.tcx(), *substs.types.get(TypeSpace, 0)); + return this.tcx().mk_box(*substs.types.get(TypeSpace, 0)); } decl_ty.subst(this.tcx(), &substs) @@ -1060,7 +1071,7 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>, let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> = traits::supertraits(tcx, object_trait_ref) .flat_map(|tr| { - let trait_def = ty::lookup_trait_def(tcx, tr.def_id()); + let trait_def = tcx.lookup_trait_def(tr.def_id()); trait_def.associated_type_names .clone() .into_iter() @@ -1078,10 +1089,10 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>, span_err!(tcx.sess, span, E0191, "the value of the associated type `{}` (from the trait `{}`) must be specified", name, - ty::item_path_str(tcx, trait_def_id)); + tcx.item_path_str(trait_def_id)); } - ty::mk_trait(tcx, object.principal, object.bounds) + tcx.mk_trait(object.principal, object.bounds) } fn report_ambiguous_associated_type(tcx: &ty::ctxt, @@ -1265,7 +1276,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, _ => unreachable!() } } else { - let trait_items = ty::trait_items(tcx, trait_did); + let trait_items = tcx.trait_items(trait_did); let item = trait_items.iter().find(|i| i.name() == assoc_name); item.expect("missing associated type").def_id() }; @@ -1290,7 +1301,7 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, let self_ty = if let Some(ty) = opt_self_ty { ty } else { - let path_str = ty::item_path_str(tcx, trait_def_id); + let path_str = tcx.item_path_str(trait_def_id); report_ambiguous_associated_type(tcx, span, "Type", @@ -1393,7 +1404,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, } def::DefTyParam(space, index, _, name) => { check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); - ty::mk_param(tcx, space, index, name) + tcx.mk_param(space, index, name) } def::DefSelfTy(_, Some((_, self_ty_id))) => { // Self in impl (we know the concrete type). @@ -1411,7 +1422,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, def::DefSelfTy(Some(_), None) => { // Self in trait. check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); - ty::mk_self_type(tcx) + tcx.mk_self_type() } def::DefAssociatedTy(trait_did, _) => { check_path_args(tcx, &base_segments[..base_segments.len()-2], NO_TPS | NO_REGIONS); @@ -1509,7 +1520,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, let typ = match ast_ty.node { ast::TyVec(ref ty) => { - ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None) + tcx.mk_slice(ast_ty_to_ty(this, rscope, &**ty)) } ast::TyObjectSum(ref ty, ref bounds) => { match ast_ty_to_trait_ref(this, rscope, &**ty, bounds) { @@ -1527,7 +1538,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } } ast::TyPtr(ref mt) => { - ty::mk_ptr(tcx, ty::mt { + tcx.mk_ptr(ty::mt { ty: ast_ty_to_ty(this, rscope, &*mt.ty), mutbl: mt.mutbl }) @@ -1538,15 +1549,15 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, let rscope1 = &ObjectLifetimeDefaultRscope::new( rscope, - Some(ty::ObjectLifetimeDefault::Specific(r))); + ty::ObjectLifetimeDefault::Specific(r)); let t = ast_ty_to_ty(this, rscope1, &*mt.ty); - ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl}) + tcx.mk_ref(tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl}) } ast::TyTup(ref fields) => { let flds = fields.iter() .map(|t| ast_ty_to_ty(this, rscope, &**t)) .collect(); - ty::mk_tup(tcx, flds) + tcx.mk_tup(flds) } ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ), ast::TyBareFn(ref bf) => { @@ -1555,7 +1566,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, "variadic function must have C calling convention"); } let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl); - ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn)) + tcx.mk_fn(None, tcx.mk_bare_fn(bare_fn)) } ast::TyPolyTraitRef(ref bounds) => { conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds) @@ -1603,11 +1614,11 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, Ok(r) => { match r { ConstVal::Int(i) => - ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), - Some(i as usize)), + tcx.mk_array(ast_ty_to_ty(this, rscope, &**ty), + i as usize), ConstVal::Uint(i) => - ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), - Some(i as usize)), + 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 \ @@ -1705,7 +1716,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, // here), if self is by-reference, then the implied output region is the // region of the self parameter. let mut explicit_self_category_result = None; - let (self_ty, mut implied_output_region) = match opt_self_info { + let (self_ty, implied_output_region) = match opt_self_info { None => (None, None), Some(self_info) => { // This type comes from an impl or trait; no late-bound @@ -1724,7 +1735,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, (Some(self_info.untransformed_self_ty), None) } ty::ByReferenceExplicitSelfCategory(region, mutability) => { - (Some(ty::mk_rptr(this.tcx(), + (Some(this.tcx().mk_ref( this.tcx().mk_region(region), ty::mt { ty: self_info.untransformed_self_ty, @@ -1733,7 +1744,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, Some(region)) } ty::ByBoxExplicitSelfCategory => { - (Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty)), None) + (Some(this.tcx().mk_box(self_info.untransformed_self_ty)), None) } } } @@ -1756,19 +1767,18 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, // Second, if there was exactly one lifetime (either a substitution or a // reference) in the arguments, then any anonymous regions in the output // have that lifetime. - let lifetimes_for_params = if implied_output_region.is_none() { - let input_tys = if self_ty.is_some() { - // Skip the first argument if `self` is present. - &self_and_input_tys[1..] - } else { - &self_and_input_tys[..] - }; + let implied_output_region = match implied_output_region { + Some(r) => Ok(r), + None => { + let input_tys = if self_ty.is_some() { + // Skip the first argument if `self` is present. + &self_and_input_tys[1..] + } else { + &self_and_input_tys[..] + }; - let (ior, lfp) = find_implied_output_region(input_tys, input_pats); - implied_output_region = ior; - lfp - } else { - vec![] + find_implied_output_region(this.tcx(), input_tys, input_pats) + } }; let output_ty = match decl.output { @@ -1777,9 +1787,8 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, ast::Return(ref output) => ty::FnConverging(convert_ty_with_lifetime_elision(this, implied_output_region, - lifetimes_for_params, - &**output)), - ast::DefaultReturn(..) => ty::FnConverging(ty::mk_nil(this.tcx())), + &output)), + ast::DefaultReturn(..) => ty::FnConverging(this.tcx().mk_nil()), ast::NoReturn(..) => ty::FnDiverging }; @@ -2007,12 +2016,30 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( "only the builtin traits can be used as closure or object bounds"); } - let region_bound = compute_object_lifetime_bound(this, - rscope, - span, - ®ion_bounds, - principal_trait_ref, - builtin_bounds); + let region_bound = + compute_object_lifetime_bound(this, + span, + ®ion_bounds, + principal_trait_ref, + builtin_bounds); + + let (region_bound, will_change) = match region_bound { + Some(r) => (r, false), + None => { + match rscope.object_lifetime_default(span) { + Some(r) => (r, rscope.object_lifetime_default_will_change_in_1_3()), + None => { + span_err!(this.tcx().sess, span, E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound"); + (ty::ReStatic, false) + } + } + } + }; + + debug!("region_bound: {:?} will_change: {:?}", + region_bound, will_change); ty::sort_bounds_list(&mut projection_bounds); @@ -2020,6 +2047,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( region_bound: region_bound, builtin_bounds: builtin_bounds, projection_bounds: projection_bounds, + region_bound_will_change: will_change, } } @@ -2029,12 +2057,11 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( /// region bounds. It may be that we can derive no bound at all, in which case we return `None`. fn compute_object_lifetime_bound<'tcx>( this: &AstConv<'tcx>, - rscope: &RegionScope, span: Span, explicit_region_bounds: &[&ast::Lifetime], principal_trait_ref: ty::PolyTraitRef<'tcx>, builtin_bounds: ty::BuiltinBounds) - -> ty::Region + -> Option // if None, use the default { let tcx = this.tcx(); @@ -2052,11 +2079,11 @@ fn compute_object_lifetime_bound<'tcx>( if !explicit_region_bounds.is_empty() { // Explicitly specified region bound. Use that. let r = explicit_region_bounds[0]; - return ast_region_to_region(tcx, r); + return Some(ast_region_to_region(tcx, r)); } if let Err(ErrorReported) = this.ensure_super_predicates(span,principal_trait_ref.def_id()) { - return ty::ReStatic; + return Some(ty::ReStatic); } // No explicit region bound specified. Therefore, examine trait @@ -2065,23 +2092,15 @@ fn compute_object_lifetime_bound<'tcx>( object_region_bounds(tcx, &principal_trait_ref, builtin_bounds); // If there are no derived region bounds, then report back that we - // can find no region bound. + // can find no region bound. The caller will use the default. if derived_region_bounds.is_empty() { - match rscope.object_lifetime_default(span) { - Some(r) => { return r; } - None => { - span_err!(this.tcx().sess, span, E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound"); - return ty::ReStatic; - } - } + return None; } // If any of the derived region bounds are 'static, that is always // the best choice. if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) { - return ty::ReStatic; + return Some(ty::ReStatic); } // Determine whether there is exactly one unique region in the set @@ -2092,7 +2111,7 @@ fn compute_object_lifetime_bound<'tcx>( span_err!(tcx.sess, span, E0227, "ambiguous lifetime bound, explicit lifetime bound required"); } - return r; + return Some(r); } pub struct PartitionedBounds<'a> { @@ -2116,8 +2135,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => { match ::lookup_full_def(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) { def::DefTrait(trait_did) => { - if ty::try_add_builtin_trait(tcx, - trait_did, + if tcx.try_add_builtin_trait(trait_did, &mut builtin_bounds) { let segments = &b.trait_ref.path.segments; let parameters = &segments[segments.len() - 1].parameters; @@ -2213,7 +2231,7 @@ impl<'tcx> Bounds<'tcx> { for builtin_bound in &self.builtin_bounds { match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { - Ok(trait_ref) => { vec.push(trait_ref.as_predicate()); } + Ok(trait_ref) => { vec.push(trait_ref.to_predicate()); } Err(ErrorReported) => { } } } @@ -2222,15 +2240,15 @@ impl<'tcx> Bounds<'tcx> { // account for the binder being introduced below; no need to shift `param_ty` // because, at present at least, it can only refer to early-bound regions let region_bound = ty_fold::shift_region(region_bound, 1); - vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).as_predicate()); + vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).to_predicate()); } for bound_trait_ref in &self.trait_bounds { - vec.push(bound_trait_ref.as_predicate()); + vec.push(bound_trait_ref.to_predicate()); } for projection in &self.projection_bounds { - vec.push(projection.as_predicate()); + vec.push(projection.to_predicate()); } vec diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index cf086a32ae599..87f867d7f90ac 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -15,7 +15,7 @@ use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; use middle::pat_util::pat_is_resolved_const; use middle::privacy::{AllPublic, LastMod}; use middle::subst::Substs; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags}; use check::{check_expr, check_expr_has_type, check_expr_with_expectation}; use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation}; use check::{check_expr_with_lvalue_pref, LvaluePreference}; @@ -59,8 +59,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let expected_ty = structurally_resolved_type(fcx, pat.span, expected); if let ty::TyRef(_, mt) = expected_ty.sty { if let ty::TySlice(_) = mt.ty.sty { - pat_ty = ty::mk_slice(tcx, tcx.mk_region(ty::ReStatic), - ty::mt{ ty: tcx.types.u8, mutbl: ast::MutImmutable }) + pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), + tcx.mk_slice(tcx.types.u8)) } } } @@ -90,7 +90,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let rhs_ty = fcx.expr_ty(end); // Check that both end-points are of numeric or char type. - let numeric_or_char = |t| ty::type_is_numeric(t) || ty::type_is_char(t); + let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char(); let lhs_compat = numeric_or_char(lhs_ty); let rhs_compat = numeric_or_char(rhs_ty); @@ -147,7 +147,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } ast::PatEnum(..) | ast::PatIdent(..) if pat_is_resolved_const(&tcx.def_map, pat) => { let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id(); - let const_scheme = ty::lookup_item_type(tcx, const_did); + let const_scheme = tcx.lookup_item_type(const_did); assert!(const_scheme.generics.is_empty()); let const_ty = pcx.fcx.instantiate_type_scheme(pat.span, &Substs::empty(), @@ -171,7 +171,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // and T is the expected type. let region_var = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); let mt = ty::mt { ty: expected, mutbl: mutbl }; - let region_ty = ty::mk_rptr(tcx, tcx.mk_region(region_var), mt); + let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt); // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is // required. However, we use equality, which is stronger. See (*) for @@ -227,8 +227,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty), path, pat.span, pat.id) { if check_assoc_item_is_const(pcx, def, pat.span) { - let scheme = ty::lookup_item_type(tcx, def.def_id()); - let predicates = ty::lookup_predicates(tcx, def.def_id()); + let scheme = tcx.lookup_item_type(def.def_id()); + let predicates = tcx.lookup_predicates(def.def_id()); instantiate_path(fcx, segments, scheme, &predicates, opt_ty, def, pat.span, pat.id); @@ -246,7 +246,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let element_tys: Vec<_> = (0..elements.len()).map(|_| fcx.infcx().next_ty_var()) .collect(); - let pat_ty = ty::mk_tup(tcx, element_tys.clone()); + let pat_ty = tcx.mk_tup(element_tys.clone()); fcx.write_ty(pat.id, pat_ty); demand::eqtype(fcx, pat.span, expected, pat_ty); for (element_pat, element_ty) in elements.iter().zip(element_tys) { @@ -255,7 +255,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } ast::PatBox(ref inner) => { let inner_ty = fcx.infcx().next_ty_var(); - let uniq_ty = ty::mk_uniq(tcx, inner_ty); + let uniq_ty = tcx.mk_box(inner_ty); if check_dereferencable(pcx, pat.span, expected, &**inner) { // Here, `demand::subtype` is good enough, but I don't @@ -274,7 +274,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); - let rptr_ty = ty::mk_rptr(tcx, tcx.mk_region(region), mt); + let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt); if check_dereferencable(pcx, pat.span, expected, &**inner) { // `demand::subtype` would be good enough, but using @@ -292,19 +292,19 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let expected_ty = structurally_resolved_type(fcx, pat.span, expected); let inner_ty = fcx.infcx().next_ty_var(); let pat_ty = match expected_ty.sty { - ty::TyArray(_, size) => ty::mk_vec(tcx, inner_ty, Some({ + ty::TyArray(_, size) => tcx.mk_array(inner_ty, { let min_len = before.len() + after.len(); match *slice { Some(_) => cmp::max(min_len, size), None => min_len } - })), + }), _ => { let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); - ty::mk_slice(tcx, tcx.mk_region(region), ty::mt { - ty: inner_ty, - mutbl: ty::deref(expected_ty, true).map(|mt| mt.mutbl) - .unwrap_or(ast::MutImmutable) + tcx.mk_ref(tcx.mk_region(region), ty::mt { + ty: tcx.mk_slice(inner_ty), + mutbl: expected_ty.builtin_deref(true).map(|mt| mt.mutbl) + .unwrap_or(ast::MutImmutable) }) } }; @@ -321,11 +321,11 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } if let Some(ref slice) = *slice { let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); - let mutbl = ty::deref(expected_ty, true) + let mutbl = expected_ty.builtin_deref(true) .map_or(ast::MutImmutable, |mt| mt.mutbl); - let slice_ty = ty::mk_slice(tcx, tcx.mk_region(region), ty::mt { - ty: inner_ty, + let slice_ty = tcx.mk_ref(tcx.mk_region(region), ty::mt { + ty: tcx.mk_slice(inner_ty), mutbl: mutbl }); check_pat(pcx, &**slice, slice_ty); @@ -411,7 +411,7 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let tcx = pcx.fcx.ccx.tcx; if pat_is_binding(&tcx.def_map, inner) { let expected = fcx.infcx().shallow_resolve(expected); - ty::deref(expected, true).map_or(true, |mt| match mt.ty.sty { + expected.builtin_deref(true).map_or(true, |mt| match mt.ty.sty { ty::TyTrait(_) => { // This is "x = SomeTrait" being reduced from // "let &x = &SomeTrait" or "let box x = Box", an error. @@ -485,7 +485,7 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // us to give better error messages (pointing to a usually better // arm for inconsistent arms or to the whole match when a `()` type // is required). - Expectation::ExpectHasType(ety) if ety != ty::mk_nil(fcx.tcx()) => { + Expectation::ExpectHasType(ety) if ety != fcx.tcx().mk_nil() => { check_expr_coercable_to_type(fcx, &*arm.body, ety); ety } @@ -499,7 +499,7 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, check_expr_has_type(fcx, &**e, tcx.types.bool); } - if ty::type_is_error(result_ty) || ty::type_is_error(bty) { + if result_ty.references_error() || bty.references_error() { tcx.types.err } else { let (origin, expected, found) = match match_src { @@ -555,7 +555,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, return; }, _ => { - let def_type = ty::lookup_item_type(tcx, def.def_id()); + let def_type = tcx.lookup_item_type(def.def_id()); match def_type.ty.sty { ty::TyStruct(struct_def_id, _) => (struct_def_id, struct_def_id), @@ -579,8 +579,8 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, instantiate_path(pcx.fcx, &path.segments, - ty::lookup_item_type(tcx, enum_def_id), - &ty::lookup_predicates(tcx, enum_def_id), + tcx.lookup_item_type(enum_def_id), + &tcx.lookup_predicates(enum_def_id), None, def, pat.span, @@ -595,7 +595,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, .map(|substs| substs.substs.clone()) .unwrap_or_else(|| Substs::empty()); - let struct_fields = ty::struct_fields(tcx, variant_def_id, &item_substs); + let struct_fields = tcx.struct_fields(variant_def_id, &item_substs); check_struct_pat_fields(pcx, pat.span, fields, &struct_fields, variant_def_id, etc); } @@ -631,10 +631,10 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let enum_def = def.variant_def_ids() .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def); - let ctor_scheme = ty::lookup_item_type(tcx, enum_def); - let ctor_predicates = ty::lookup_predicates(tcx, enum_def); - let path_scheme = if ty::is_fn_ty(ctor_scheme.ty) { - let fn_ret = ty::no_late_bound_regions(tcx, &ty::ty_fn_ret(ctor_scheme.ty)).unwrap(); + let ctor_scheme = tcx.lookup_item_type(enum_def); + let ctor_predicates = tcx.lookup_predicates(enum_def); + let path_scheme = if ctor_scheme.ty.is_fn() { + let fn_ret = tcx.no_late_bound_regions(&ctor_scheme.ty.fn_ret()).unwrap(); ty::TypeScheme { ty: fn_ret.unwrap(), generics: ctor_scheme.generics, @@ -664,14 +664,14 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ty::TyEnum(enum_def_id, expected_substs) if def == def::DefVariant(enum_def_id, def.def_id(), false) => { - let variant = ty::enum_variant_with_id(tcx, enum_def_id, def.def_id()); + let variant = tcx.enum_variant_with_id(enum_def_id, def.def_id()); (variant.args.iter() .map(|t| fcx.instantiate_type_scheme(pat.span, expected_substs, t)) .collect(), "variant") } ty::TyStruct(struct_def_id, expected_substs) => { - let struct_fields = ty::struct_fields(tcx, struct_def_id, expected_substs); + let struct_fields = tcx.struct_fields(struct_def_id, expected_substs); (struct_fields.iter() .map(|field| fcx.instantiate_type_scheme(pat.span, expected_substs, @@ -761,7 +761,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, .unwrap_or_else(|| { span_err!(tcx.sess, span, E0026, "struct `{}` does not have a field named `{}`", - ty::item_path_str(tcx, struct_id), + tcx.item_path_str(struct_id), token::get_ident(field.ident)); tcx.types.err }) diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs index df9fe6b002efb..c80c48a96922d 100644 --- a/src/librustc_typeck/check/assoc.rs +++ b/src/librustc_typeck/check/assoc.rs @@ -11,22 +11,22 @@ use middle::infer::InferCtxt; use middle::traits::{self, FulfillmentContext, Normalized, MiscObligation, SelectionContext, ObligationCause}; -use middle::ty::{self, HasProjectionTypes}; +use middle::ty::HasTypeFlags; use middle::ty_fold::TypeFoldable; use syntax::ast; use syntax::codemap::Span; +//FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument. pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, - typer: &(ty::ClosureTyper<'tcx>+'a), fulfillment_cx: &mut FulfillmentContext<'tcx>, span: Span, body_id: ast::NodeId, value: &T) -> T - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { debug!("normalize_associated_types_in(value={:?})", value); - let mut selcx = SelectionContext::new(infcx, typer); + let mut selcx = SelectionContext::new(infcx); let cause = ObligationCause::new(span, body_id, MiscObligation); let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value); debug!("normalize_associated_types_in: result={:?} predicates={:?}", diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index e7271d2fa88cf..f32a4fe43d696 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -27,7 +27,7 @@ use super::write_call; use CrateCtxt; use middle::infer; -use middle::ty::{self, Ty, ClosureTyper}; +use middle::ty::{self, Ty}; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token; @@ -137,9 +137,9 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Check whether this is a call to a closure where we // haven't yet decided on whether the closure is fn vs // fnmut vs fnonce. If so, we have to defer further processing. - if fcx.closure_kind(def_id).is_none() { + if fcx.infcx().closure_kind(def_id).is_none() { let closure_ty = - fcx.closure_type(def_id, substs); + fcx.infcx().closure_type(def_id, substs); let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, @@ -324,7 +324,7 @@ fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr: &ast::Expr, method_callee: ty::MethodCallee<'tcx>) { let method_call = ty::MethodCall::expr(call_expr.id); - fcx.inh.method_map.borrow_mut().insert(method_call, method_callee); + fcx.inh.tables.borrow_mut().method_map.insert(method_call, method_callee); } #[derive(Debug)] @@ -344,7 +344,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { // we should not be invoked until the closure kind has been // determined by upvar inference - assert!(fcx.closure_kind(self.closure_def_id).is_some()); + assert!(fcx.infcx().closure_kind(self.closure_def_id).is_some()); // We may now know enough to figure out fn vs fnmut etc. match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr, @@ -358,9 +358,8 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { // can't because of the annoying need for a TypeTrace. // (This always bites me, should find a way to // refactor it.) - let method_sig = - ty::no_late_bound_regions(fcx.tcx(), - ty::ty_fn_sig(method_callee.ty)).unwrap(); + let method_sig = fcx.tcx().no_late_bound_regions(method_callee.ty.fn_sig()) + .unwrap(); debug!("attempt_resolution: method_callee={:?}", method_callee); @@ -371,7 +370,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty); } - let nilty = ty::mk_nil(fcx.tcx()); + let nilty = fcx.tcx().mk_nil(); demand::eqtype(fcx, self.call_expr.span, method_sig.output.unwrap_or(nilty), diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index c46a033c13f95..49b47da517720 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -45,8 +45,7 @@ use super::structurally_resolved_type; use lint; use middle::cast::{CastKind, CastTy}; -use middle::ty; -use middle::ty::Ty; +use middle::ty::{self, Ty, HasTypeFlags}; use syntax::ast; use syntax::ast::UintTy::{TyU8}; use syntax::codemap::Span; @@ -81,7 +80,7 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())), ty::TyStruct(did, substs) => { - match ty::struct_fields(fcx.tcx(), did, substs).pop() { + match fcx.tcx().struct_fields(did, substs).pop() { None => None, Some(f) => unsize_kind(fcx, f.mt.ty) } @@ -170,7 +169,7 @@ impl<'tcx> CastCheck<'tcx> { fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { let t_cast = self.cast_ty; let t_expr = self.expr_ty; - if ty::type_is_numeric(t_cast) && ty::type_is_numeric(t_expr) { + if t_cast.is_numeric() && t_expr.is_numeric() { fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, self.expr.id, self.span, @@ -199,7 +198,7 @@ impl<'tcx> CastCheck<'tcx> { debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty, self.cast_ty); - if ty::type_is_error(self.expr_ty) || ty::type_is_error(self.cast_ty) { + if self.expr_ty.references_error() || self.cast_ty.references_error() { // No sense in giving duplicate error messages } else if self.try_coercion_cast(fcx) { self.trivial_cast_lint(fcx); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 10b2459b220f2..6d1e9dfacf281 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -60,17 +60,13 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, abi::RustCall, expected_sig); - let closure_type = ty::mk_closure(fcx.ccx.tcx, - expr_def_id, - fcx.ccx.tcx.mk_substs( - fcx.inh.param_env.free_substs.clone())); + let closure_type = fcx.ccx.tcx.mk_closure(expr_def_id, + fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone())); fcx.write_ty(expr.id, closure_type); - let fn_sig = - ty::liberate_late_bound_regions(fcx.tcx(), - region::DestructionScopeData::new(body.id), - &fn_ty.sig); + let fn_sig = fcx.tcx().liberate_late_bound_regions( + region::DestructionScopeData::new(body.id), &fn_ty.sig); check_fn(fcx.ccx, ast::Unsafety::Normal, @@ -83,16 +79,16 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // Tuple up the arguments and insert the resulting function type into // the `closures` table. - fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)]; + fn_ty.sig.0.inputs = vec![fcx.tcx().mk_tup(fn_ty.sig.0.inputs)]; debug!("closure for {:?} --> sig={:?} opt_kind={:?}", expr_def_id, fn_ty.sig, opt_kind); - fcx.inh.closure_tys.borrow_mut().insert(expr_def_id, fn_ty); + fcx.inh.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty); match opt_kind { - Some(kind) => { fcx.inh.closure_kinds.borrow_mut().insert(expr_def_id, kind); } + Some(kind) => { fcx.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); } None => { } } } @@ -129,7 +125,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>( expected_vid: ty::TyVid) -> (Option>, Option) { - let fulfillment_cx = fcx.inh.fulfillment_cx.borrow(); + let fulfillment_cx = fcx.inh.infcx.fulfillment_cx.borrow(); // Here `expected_ty` is known to be a type inference variable. let expected_sig = diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 785202de92159..a0abef7490703 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -201,8 +201,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // &T to autoref to &&T. return None; } - let ty = ty::mk_rptr(self.tcx(), r_borrow, - mt {ty: inner_ty, mutbl: mutbl_b}); + let ty = self.tcx().mk_ref(r_borrow, + mt {ty: inner_ty, mutbl: mutbl_b}); if let Err(err) = self.subtype(ty, b) { if first_error.is_none() { first_error = Some(err); @@ -271,9 +271,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } _ => (source, None) }; - let source = ty::adjust_ty_for_autoref(self.tcx(), source, reborrow); + let source = source.adjust_for_autoref(self.tcx(), reborrow); - let mut selcx = traits::SelectionContext::new(self.fcx.infcx(), self.fcx); + let mut selcx = traits::SelectionContext::new(self.fcx.infcx()); // Use a FIFO queue for this custom fulfillment procedure. let mut queue = VecDeque::new(); @@ -384,7 +384,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match b.sty { ty::TyBareFn(None, _) => { - let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a); + let a_fn_pointer = self.tcx().mk_fn(None, fn_ty_a); try!(self.subtype(a_fn_pointer, b)); Ok(Some(ty::AdjustReifyFnPointer)) } @@ -411,7 +411,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }; // Check that the types which they point at are compatible. - let a_unsafe = ty::mk_ptr(self.tcx(), ty::mt{ mutbl: mutbl_b, ty: mt_a.ty }); + let a_unsafe = self.tcx().mk_ptr(ty::mt{ mutbl: mutbl_b, ty: mt_a.ty }); try!(self.subtype(a_unsafe, b)); try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 7cd5e4548ec2b..7926394ebb517 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -43,8 +43,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}", impl_trait_ref); - let infcx = infer::new_infer_ctxt(tcx); - let mut fulfillment_cx = traits::FulfillmentContext::new(true); + let mut infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, true); + let mut fulfillment_cx = infcx.fulfillment_cx.borrow_mut(); let trait_to_impl_substs = &impl_trait_ref.substs; @@ -100,7 +100,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, token::get_name(trait_m.name), impl_m.fty.sig.0.inputs.len(), if impl_m.fty.sig.0.inputs.len() == 1 {""} else {"s"}, - ty::item_path_str(tcx, trait_m.def_id), + tcx.item_path_str(trait_m.def_id), trait_m.fty.sig.0.inputs.len()); return; } @@ -240,11 +240,13 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.into_vec()); let trait_param_env = traits::normalize_param_env_or_error(trait_param_env, normalize_cause.clone()); + // FIXME(@jroesch) this seems ugly, but is a temporary change + infcx.parameter_environment = trait_param_env; debug!("compare_impl_method: trait_bounds={:?}", - trait_param_env.caller_bounds); + infcx.parameter_environment.caller_bounds); - let mut selcx = traits::SelectionContext::new(&infcx, &trait_param_env); + let mut selcx = traits::SelectionContext::new(&infcx); for predicate in impl_pred.fns { let traits::Normalized { value: predicate, .. } = @@ -275,9 +277,9 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // type. // Compute skolemized form of impl and trait method tys. - let impl_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_m.fty.clone())); + let impl_fty = tcx.mk_fn(None, tcx.mk_bare_fn(impl_m.fty.clone())); let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs); - let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone())); + let trait_fty = tcx.mk_fn(None, tcx.mk_bare_fn(trait_m.fty.clone())); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); let err = infcx.commit_if_ok(|snapshot| { @@ -291,17 +293,15 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, impl_sig.subst(tcx, impl_to_skol_substs); let impl_sig = assoc::normalize_associated_types_in(&infcx, - &impl_param_env, &mut fulfillment_cx, impl_m_span, impl_m_body_id, &impl_sig); - let impl_fty = - ty::mk_bare_fn(tcx, - None, - tcx.mk_bare_fn(ty::BareFnTy { unsafety: impl_m.fty.unsafety, - abi: impl_m.fty.abi, - sig: ty::Binder(impl_sig) })); + let impl_fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + unsafety: impl_m.fty.unsafety, + abi: impl_m.fty.abi, + sig: ty::Binder(impl_sig) + })); debug!("compare_impl_method: impl_fty={:?}", impl_fty); @@ -311,17 +311,15 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, trait_sig.subst(tcx, &trait_to_skol_substs); let trait_sig = assoc::normalize_associated_types_in(&infcx, - &impl_param_env, &mut fulfillment_cx, impl_m_span, impl_m_body_id, &trait_sig); - let trait_fty = - ty::mk_bare_fn(tcx, - None, - tcx.mk_bare_fn(ty::BareFnTy { unsafety: trait_m.fty.unsafety, - abi: trait_m.fty.abi, - sig: ty::Binder(trait_sig) })); + let trait_fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + unsafety: trait_m.fty.unsafety, + abi: trait_m.fty.abi, + sig: ty::Binder(trait_sig) + })); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -347,7 +345,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // Check that all obligations are satisfied by the implementation's // version. - match fulfillment_cx.select_all_or_error(&infcx, &trait_param_env) { + match fulfillment_cx.select_all_or_error(&infcx) { Err(ref errors) => { traits::report_fulfillment_errors(&infcx, errors) } Ok(_) => {} } @@ -362,7 +360,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // anyway, so it shouldn't be needed there either. Anyway, we can // always add more relations later (it's backwards compat). let mut free_regions = FreeRegionMap::new(); - free_regions.relate_free_regions_from_predicates(tcx, &trait_param_env.caller_bounds); + free_regions.relate_free_regions_from_predicates(tcx, + &infcx.parameter_environment.caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); @@ -418,8 +417,8 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); - let infcx = infer::new_infer_ctxt(tcx); - let mut fulfillment_cx = traits::FulfillmentContext::new(true); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, true); + let mut fulfillment_cx = infcx.fulfillment_cx.borrow_mut(); // The below is for the most part highly similar to the procedure // for methods above. It is simpler in many respects, especially @@ -455,21 +454,21 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>, // There is no "body" here, so just pass dummy id. let impl_ty = assoc::normalize_associated_types_in(&infcx, - &impl_param_env, &mut fulfillment_cx, impl_c_span, 0, &impl_ty); + debug!("compare_const_impl: impl_ty={:?}", impl_ty); let trait_ty = assoc::normalize_associated_types_in(&infcx, - &impl_param_env, &mut fulfillment_cx, impl_c_span, 0, &trait_ty); + debug!("compare_const_impl: trait_ty={:?}", trait_ty); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index fb17f41d88d9a..7d911cf8b03bc 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -37,8 +37,8 @@ use syntax::codemap::{self, Span}; /// pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(), ()> { let ty::TypeScheme { generics: ref dtor_generics, - ty: dtor_self_type } = ty::lookup_item_type(tcx, drop_impl_did); - let dtor_predicates = ty::lookup_predicates(tcx, drop_impl_did); + ty: dtor_self_type } = tcx.lookup_item_type(drop_impl_did); + let dtor_predicates = tcx.lookup_predicates(drop_impl_did); match dtor_self_type.sty { ty::TyEnum(self_type_did, self_to_impl_substs) | ty::TyStruct(self_type_did, self_to_impl_substs) | @@ -91,9 +91,10 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( let ty::TypeScheme { generics: ref named_type_generics, ty: named_type } = - ty::lookup_item_type(tcx, self_type_did); + tcx.lookup_item_type(self_type_did); + + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); - let infcx = infer::new_infer_ctxt(tcx); infcx.commit_if_ok(|snapshot| { let (named_type_to_skolem, skol_map) = infcx.construct_skolemized_subst(named_type_generics, snapshot); @@ -179,7 +180,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // We can assume the predicates attached to struct/enum definition // hold. - let generic_assumptions = ty::lookup_predicates(tcx, self_type_did); + let generic_assumptions = tcx.lookup_predicates(self_type_did); let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::SelfSpace)); @@ -288,7 +289,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> rcx.tcx().sess, span, "overflowed on enum {} variant {} argument {} type: {}", - ty::item_path_str(tcx, def_id), + tcx.item_path_str(def_id), variant, arg_index, detected_on_typ); @@ -298,7 +299,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> rcx.tcx().sess, span, "overflowed on struct {} field {} type: {}", - ty::item_path_str(tcx, def_id), + tcx.item_path_str(def_id), field, detected_on_typ); } @@ -365,7 +366,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( let (typ, xref_depth) = match typ.sty { ty::TyStruct(struct_did, substs) => { if opt_phantom_data_def_id == Some(struct_did) { - let item_type = ty::lookup_item_type(rcx.tcx(), struct_did); + let item_type = rcx.tcx().lookup_item_type(struct_did); let tp_def = item_type.generics.types .opt_get(subst::TypeSpace, 0).unwrap(); let new_typ = substs.type_for_def(tp_def); @@ -471,13 +472,11 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( walker.skip_current_subtree(); let fields = - ty::lookup_struct_fields(rcx.tcx(), struct_did); + rcx.tcx().lookup_struct_fields(struct_did); for field in &fields { - let field_type = - ty::lookup_field_type(rcx.tcx(), - struct_did, - field.id, - substs); + let field_type = rcx.tcx().lookup_field_type(struct_did, + field.id, + substs); try!(iterate_over_potentially_unsafe_regions_in_type( rcx, breadcrumbs, @@ -501,9 +500,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( walker.skip_current_subtree(); let all_variant_info = - ty::substd_enum_variants(rcx.tcx(), - enum_did, - substs); + rcx.tcx().substd_enum_variants(enum_did, substs); for variant_info in &all_variant_info { for (i, arg_type) in variant_info.args.iter().enumerate() { try!(iterate_over_potentially_unsafe_regions_in_type( @@ -591,13 +588,13 @@ fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>, } } DtorKind::KnownDropMethod(dtor_method_did) => { - let impl_did = ty::impl_of_method(tcx, dtor_method_did) + let impl_did = tcx.impl_of_method(dtor_method_did) .unwrap_or_else(|| { tcx.sess.span_bug( span, "no Drop impl found for drop method") }); - let dtor_typescheme = ty::lookup_item_type(tcx, impl_did); + let dtor_typescheme = tcx.lookup_item_type(impl_did); let dtor_generics = dtor_typescheme.generics; let mut has_pred_of_interest = false; @@ -609,7 +606,7 @@ fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>, continue; } - for pred in ty::lookup_predicates(tcx, item_def_id).predicates { + for pred in tcx.lookup_predicates(item_def_id).predicates { let result = match pred { ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | @@ -623,7 +620,7 @@ fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>, ty::Predicate::Trait(ty::Binder(ref t_pred)) => { let def_id = t_pred.trait_ref.def_id; - if ty::trait_items(tcx, def_id).len() != 0 { + if tcx.trait_items(def_id).len() != 0 { // If trait has items, assume it adds // capability to access borrowed data. true diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index fd93a2493db5a..8db5b5e7c508c 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -12,12 +12,9 @@ use super::probe; use check::{self, FnCtxt, NoPreference, PreferMutLvalue, callee, demand}; use check::UnresolvedTypeAction; -use middle::mem_categorization::Typer; use middle::subst::{self}; use middle::traits; use middle::ty::{self, Ty}; -use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin, - MethodParam, MethodStatic, MethodTraitObject, MethodTypeParam}; use middle::ty_fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; @@ -53,7 +50,7 @@ pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, supplied_method_types: Vec>) - -> MethodCallee<'tcx> + -> ty::MethodCallee<'tcx> { debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})", unadjusted_self_ty, @@ -78,7 +75,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, supplied_method_types: Vec>) - -> MethodCallee<'tcx> + -> ty::MethodCallee<'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); @@ -87,8 +84,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { self.enforce_illegal_method_limitations(&pick); // Create substitutions for the method's type parameters. - let (rcvr_substs, method_origin) = - self.fresh_receiver_substs(self_ty, &pick); + let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick); let (method_types, method_regions) = self.instantiate_method_substs(&pick, supplied_method_types); let all_substs = rcvr_substs.with_method(method_types, method_regions); @@ -108,15 +104,15 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Create the final `MethodCallee`. let method_ty = pick.item.as_opt_method().unwrap(); - let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy { + let fty = self.tcx().mk_fn(None, self.tcx().mk_bare_fn(ty::BareFnTy { sig: ty::Binder(method_sig), unsafety: method_ty.fty.unsafety, abi: method_ty.fty.abi.clone(), })); - let callee = MethodCallee { - origin: method_origin, + let callee = ty::MethodCallee { + def_id: pick.item.def_id(), ty: fty, - substs: all_substs + substs: self.tcx().mk_substs(all_substs) }; // If this is an `&mut self` method, bias the receiver @@ -139,7 +135,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let region = self.infcx().next_region_var(infer::Autoref(self.span)); let autoref = ty::AutoPtr(self.tcx().mk_region(region), mutbl); (Some(autoref), pick.unsize.map(|target| { - ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref)) + target.adjust_for_autoref(self.tcx(), Some(autoref)) })) } else { // No unsizing should be performed without autoref (at @@ -179,7 +175,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { if let Some(target) = unsize { target } else { - ty::adjust_ty_for_autoref(self.tcx(), autoderefd_ty, autoref) + autoderefd_ty.adjust_for_autoref(self.tcx(), autoref) } } @@ -195,18 +191,18 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn fresh_receiver_substs(&mut self, self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>) - -> (subst::Substs<'tcx>, MethodOrigin<'tcx>) + -> subst::Substs<'tcx> { match pick.kind { - probe::InherentImplPick(impl_def_id) => { - assert!(ty::impl_trait_ref(self.tcx(), impl_def_id).is_none(), + probe::InherentImplPick => { + let impl_def_id = pick.item.container().id(); + assert!(self.tcx().impl_trait_ref(impl_def_id).is_none(), "impl {:?} is not an inherent impl", impl_def_id); - let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id); - - (impl_polytype.substs, MethodStatic(pick.item.def_id())) + check::impl_self_ty(self.fcx, self.span, impl_def_id).substs } - probe::ObjectPick(trait_def_id, method_num, vtable_index) => { + probe::ObjectPick => { + let trait_def_id = pick.item.container().id(); self.extract_trait_ref(self_ty, |this, object_ty, data| { // The object data has no entry for the Self // Type. For the purposes of this method call, we @@ -228,18 +224,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { original_poly_trait_ref, upcast_trait_ref, trait_def_id); - let substs = upcast_trait_ref.substs.clone(); - let origin = MethodTraitObject(MethodObject { - trait_ref: upcast_trait_ref, - object_trait_id: trait_def_id, - method_num: method_num, - vtable_index: vtable_index, - }); - (substs, origin) + upcast_trait_ref.substs.clone() }) } - probe::ExtensionImplPick(impl_def_id, method_num) => { + probe::ExtensionImplPick(impl_def_id) => { // The method being invoked is the method as defined on the trait, // so return the substitutions from the trait. Consider: // @@ -254,42 +243,28 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { self.fcx.instantiate_type_scheme( self.span, &impl_polytype.substs, - &ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap()); - let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(), - method_num: method_num, - impl_def_id: Some(impl_def_id) }); - (impl_trait_ref.substs.clone(), origin) + &self.tcx().impl_trait_ref(impl_def_id).unwrap()); + impl_trait_ref.substs.clone() } - probe::TraitPick(trait_def_id, method_num) => { - let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id); + probe::TraitPick => { + let trait_def_id = pick.item.container().id(); + let trait_def = self.tcx().lookup_trait_def(trait_def_id); // Make a trait reference `$0 : Trait<$1...$n>` // consisting entirely of type variables. Later on in // the process we will unify the transformed-self-type // of the method with the actual type in order to // unify some of these variables. - let substs = self.infcx().fresh_substs_for_trait(self.span, - &trait_def.generics, - self.infcx().next_ty_var()); - - let trait_ref = - ty::TraitRef::new(trait_def_id, self.tcx().mk_substs(substs.clone())); - let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref, - method_num: method_num, - impl_def_id: None }); - (substs, origin) + self.infcx().fresh_substs_for_trait(self.span, + &trait_def.generics, + self.infcx().next_ty_var()) } - probe::WhereClausePick(ref poly_trait_ref, method_num) => { + probe::WhereClausePick(ref poly_trait_ref) => { // Where clauses can have bound regions in them. We need to instantiate // those to convert from a poly-trait-ref to a trait-ref. - let trait_ref = self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref); - let substs = trait_ref.substs.clone(); - let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref, - method_num: method_num, - impl_def_id: None }); - (substs, origin) + self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref).substs.clone() } } } @@ -451,7 +426,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut` /// respectively. fn fixup_derefs_on_method_receiver_if_necessary(&self, - method_callee: &MethodCallee) { + method_callee: &ty::MethodCallee) { let sig = match method_callee.ty.sty { ty::TyBareFn(_, ref f) => f.sig.clone(), _ => return, @@ -488,8 +463,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Count autoderefs. let autoderef_count = match self.fcx .inh - .adjustments + .tables .borrow() + .adjustments .get(&expr.id) { Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs, Some(_) | None => 0, @@ -527,7 +503,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // expects. This is annoying and horrible. We // ought to recode this routine so it doesn't // (ab)use the normal type checking paths. - let adj = self.fcx.inh.adjustments.borrow().get(&base_expr.id).cloned(); + let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id) + .cloned(); let (autoderefs, unsize) = match adj { Some(ty::AdjustDerefRef(adr)) => match adr.autoref { None => { @@ -536,8 +513,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } Some(ty::AutoPtr(_, _)) => { (adr.autoderefs, adr.unsize.map(|target| { - ty::deref(target, false) - .expect("fixup: AutoPtr is not &T").ty + target.builtin_deref(false) + .expect("fixup: AutoPtr is not &T").ty })) } Some(_) => { @@ -569,7 +546,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let result = check::try_index_step( self.fcx, - MethodCall::expr(expr.id), + ty::MethodCall::expr(expr.id), expr, &**base_expr, adjusted_base_ty, @@ -588,8 +565,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { ast::ExprUnary(ast::UnDeref, ref base_expr) => { // if this is an overloaded deref, then re-evaluate with // a preference for mut - let method_call = MethodCall::expr(expr.id); - if self.fcx.inh.method_map.borrow().contains_key(&method_call) { + let method_call = ty::MethodCall::expr(expr.id); + if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) { check::try_overloaded_deref( self.fcx, expr.span, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index e5a57fa9c138e..2117cba108730 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -16,7 +16,7 @@ use middle::def; use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod}; use middle::subst; use middle::traits; -use middle::ty::{self, AsPredicate, ToPolyTraitRef, TraitRef}; +use middle::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef}; use middle::infer; use syntax::ast::DefId; @@ -74,8 +74,6 @@ pub enum CandidateSource { TraitSource(/* trait id */ ast::DefId), } -type ItemIndex = usize; // just for doc purposes - /// Determines whether the type `self_ty` supports a method name `method_name` or not. pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, @@ -167,7 +165,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, m_name, trait_def_id); - let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_def_id); + let trait_def = fcx.tcx().lookup_trait_def(trait_def_id); let expected_number_of_input_types = trait_def.generics.types.len(subst::TypeSpace); let input_types = match opt_input_types { @@ -192,10 +190,10 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = traits::Obligation::misc(span, fcx.body_id, - poly_trait_ref.as_predicate()); + poly_trait_ref.to_predicate()); // Now we want to know if this can be matched - let mut selcx = traits::SelectionContext::new(fcx.infcx(), fcx); + let mut selcx = traits::SelectionContext::new(fcx.infcx()); if !selcx.evaluate_obligation(&obligation) { debug!("--> Cannot match obligation"); return None; // Cannot be matched, no such method resolution is possible. @@ -204,14 +202,13 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Trait must have a method named `m_name` and it should not have // type parameters or early-bound regions. let tcx = fcx.tcx(); - let (method_num, method_ty) = trait_item(tcx, trait_def_id, m_name) - .and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m))) - .unwrap(); + let method_item = trait_item(tcx, trait_def_id, m_name).unwrap(); + let method_ty = method_item.as_opt_method().unwrap(); assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0); assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0); - debug!("lookup_in_trait_adjusted: method_num={} method_ty={:?}", - method_num, method_ty); + debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}", + method_item, method_ty); // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. @@ -224,7 +221,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, &method_ty.fty.sig).0; let fn_sig = fcx.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); let transformed_self_ty = fn_sig.inputs[0]; - let fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(ty::BareFnTy { + let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { sig: ty::Binder(fn_sig), unsafety: method_ty.fty.unsafety, abi: method_ty.fty.abi.clone(), @@ -309,11 +306,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } let callee = ty::MethodCallee { - origin: ty::MethodTypeParam(ty::MethodParam{trait_ref: trait_ref.clone(), - method_num: method_num, - impl_def_id: None}), + def_id: method_item.def_id(), ty: fty, - substs: trait_ref.substs.clone() + substs: trait_ref.substs }; debug!("callee = {:?}", callee); @@ -332,14 +327,15 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id)); let def_id = pick.item.def_id(); let mut lp = LastMod(AllPublic); + let container_def_id = pick.item.container().id(); let provenance = match pick.kind { - probe::InherentImplPick(impl_def_id) => { + probe::InherentImplPick => { if pick.item.vis() != ast::Public { lp = LastMod(DependsOn(def_id)); } - def::FromImpl(impl_def_id) + def::FromImpl(container_def_id) } - _ => def::FromTrait(pick.item.container().id()) + _ => def::FromTrait(container_def_id) }; let def_result = match pick.item { ty::ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance), @@ -352,19 +348,17 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } -/// Find item with name `item_name` defined in `trait_def_id` and return it, along with its -/// index (or `None`, if no such item). +/// Find item with name `item_name` defined in `trait_def_id` +/// and return it, or `None`, if no such item. fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, trait_def_id: ast::DefId, item_name: ast::Name) - -> Option<(usize, ty::ImplOrTraitItem<'tcx>)> + -> Option> { - let trait_items = ty::trait_items(tcx, trait_def_id); - trait_items - .iter() - .enumerate() - .find(|&(_, ref item)| item.name() == item_name) - .map(|(num, item)| (num, (*item).clone())) + let trait_items = tcx.trait_items(trait_def_id); + trait_items.iter() + .find(|item| item.name() == item_name) + .cloned() } fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>, @@ -376,6 +370,6 @@ fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>, let impl_items = impl_items.get(&impl_def_id).unwrap(); impl_items .iter() - .map(|&did| ty::impl_or_trait_item(tcx, did.def_id())) + .map(|&did| tcx.impl_or_trait_item(did.def_id())) .find(|m| m.name() == item_name) } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 46bffa8ccabda..c43046ba0e716 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -10,7 +10,6 @@ use super::MethodError; use super::NoMatchData; -use super::ItemIndex; use super::{CandidateSource, ImplSource, TraitSource}; use super::suggest; @@ -21,6 +20,7 @@ use middle::subst; use middle::subst::Subst; use middle::traits; use middle::ty::{self, RegionEscape, Ty, ToPolyTraitRef, TraitRef}; +use middle::ty::HasTypeFlags; use middle::ty_fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; @@ -69,15 +69,13 @@ struct Candidate<'tcx> { #[derive(Debug)] enum CandidateKind<'tcx> { - InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>, + InherentImplCandidate(subst::Substs<'tcx>, /* Normalize obligations */ Vec>), - ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize), - ExtensionImplCandidate(/* Impl */ ast::DefId, ty::TraitRef<'tcx>, - subst::Substs<'tcx>, ItemIndex, + ExtensionImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>, /* Normalize obligations */ Vec>), - ClosureCandidate(/* Trait */ ast::DefId, ItemIndex), - WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex), - ProjectionCandidate(ast::DefId, ItemIndex), + ObjectCandidate, + TraitCandidate, + WhereClauseCandidate(/* Trait */ ty::PolyTraitRef<'tcx>), } #[derive(Debug)] @@ -105,11 +103,11 @@ pub struct Pick<'tcx> { #[derive(Clone,Debug)] pub enum PickKind<'tcx> { - InherentImplPick(/* Impl */ ast::DefId), - ObjectPick(/* Trait */ ast::DefId, /* method_num */ usize, /* real_index */ usize), - ExtensionImplPick(/* Impl */ ast::DefId, ItemIndex), - TraitPick(/* Trait */ ast::DefId, ItemIndex), - WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, ItemIndex), + InherentImplPick, + ExtensionImplPick(/* Impl */ ast::DefId), + ObjectPick, + TraitPick, + WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>), } pub type PickResult<'tcx> = Result, MethodError<'tcx>>; @@ -217,9 +215,8 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match final_ty.sty { ty::TyArray(elem_ty, _) => { - let slice_ty = ty::mk_vec(fcx.tcx(), elem_ty, None); steps.push(CandidateStep { - self_ty: slice_ty, + self_ty: fcx.tcx().mk_slice(elem_ty), autoderefs: dereferences, unsize: true }); @@ -377,7 +374,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option) { if let Some(impl_def_id) = lang_def_id { - ty::populate_implementations_for_primitive_if_necessary(self.tcx(), impl_def_id); + self.tcx().populate_implementations_for_primitive_if_necessary(impl_def_id); self.assemble_inherent_impl_probe(impl_def_id); } @@ -386,7 +383,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: ast::DefId) { // Read the inherent implementation candidates for this type from the // metadata if necessary. - ty::populate_inherent_implementations_for_type_if_necessary(self.tcx(), def_id); + self.tcx().populate_inherent_implementations_for_type_if_necessary(def_id); if let Some(impl_infos) = self.tcx().inherent_impls.borrow().get(&def_id) { for &impl_def_id in impl_infos.iter() { @@ -421,7 +418,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // We can't use normalize_associated_types_in as it will pollute the // fcx's fulfillment context after this probe is over. let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); - let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx); + let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx()); let traits::Normalized { value: xform_self_ty, obligations } = traits::normalize(selcx, cause, &xform_self_ty); debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}", @@ -430,7 +427,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: InherentImplCandidate(impl_def_id, impl_substs, obligations) + kind: InherentImplCandidate(impl_substs, obligations) }); } @@ -440,8 +437,6 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty); - let tcx = self.tcx(); - // It is illegal to invoke a method on a trait instance that // refers to the `Self` type. An error will be reported by // `enforce_object_limitations()` if the method refers to the @@ -450,15 +445,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // itself. Hence, a `&self` method will wind up with an // argument type like `&Trait`. let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty); - self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, item, item_num| { + self.elaborate_bounds(&[trait_ref], |this, new_trait_ref, item| { let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref); - let vtable_index = - traits::get_vtable_index_of_object_method(tcx, - trait_ref.clone(), - new_trait_ref.def_id, - item_num); - let xform_self_ty = this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); @@ -466,7 +455,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: ObjectCandidate(new_trait_ref.def_id, item_num, vtable_index) + kind: ObjectCandidate }); }); } @@ -477,7 +466,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // FIXME -- Do we want to commit to this behavior for param bounds? let bounds: Vec<_> = - self.fcx.inh.param_env.caller_bounds + self.fcx.inh.infcx.parameter_environment.caller_bounds .iter() .filter_map(|predicate| { match *predicate { @@ -499,7 +488,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { }) .collect(); - self.elaborate_bounds(&bounds, |this, poly_trait_ref, item, item_num| { + self.elaborate_bounds(&bounds, |this, poly_trait_ref, item| { let trait_ref = this.erase_late_bound_regions(&poly_trait_ref); @@ -528,12 +517,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // artifacts. This means it is safe to put into the // `WhereClauseCandidate` and (eventually) into the // `WhereClausePick`. - assert!(trait_ref.substs.types.iter().all(|&t| !ty::type_needs_infer(t))); + assert!(!trait_ref.substs.types.needs_infer()); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: WhereClauseCandidate(poly_trait_ref, item_num) + kind: WhereClauseCandidate(poly_trait_ref) }); }); } @@ -549,16 +538,15 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { &mut ProbeContext<'b, 'tcx>, ty::PolyTraitRef<'tcx>, ty::ImplOrTraitItem<'tcx>, - usize, ), { debug!("elaborate_bounds(bounds={:?})", bounds); let tcx = self.tcx(); for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { - let (pos, item) = match trait_item(tcx, - bound_trait_ref.def_id(), - self.item_name) { + let item = match trait_item(tcx, + bound_trait_ref.def_id(), + self.item_name) { Some(v) => v, None => { continue; } }; @@ -566,7 +554,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { if !self.has_applicable_self(&item) { self.record_static_candidate(TraitSource(bound_trait_ref.def_id())); } else { - mk_cand(self, bound_trait_ref, item, pos); + mk_cand(self, bound_trait_ref, item); } } } @@ -606,15 +594,14 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // Check whether `trait_def_id` defines a method with suitable name: let trait_items = - ty::trait_items(self.tcx(), trait_def_id); - let matching_index = + self.tcx().trait_items(trait_def_id); + let maybe_item = trait_items.iter() - .position(|item| item.name() == self.item_name); - let matching_index = match matching_index { + .find(|item| item.name() == self.item_name); + let item = match maybe_item { Some(i) => i, None => { return Ok(()); } }; - let ref item = (&*trait_items)[matching_index]; // Check whether `trait_def_id` defines a method with suitable name: if !self.has_applicable_self(item) { @@ -623,31 +610,22 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { return Ok(()); } - self.assemble_extension_candidates_for_trait_impls(trait_def_id, - item.clone(), - matching_index); + self.assemble_extension_candidates_for_trait_impls(trait_def_id, item.clone()); - try!(self.assemble_closure_candidates(trait_def_id, - item.clone(), - matching_index)); + try!(self.assemble_closure_candidates(trait_def_id, item.clone())); - self.assemble_projection_candidates(trait_def_id, - item.clone(), - matching_index); + self.assemble_projection_candidates(trait_def_id, item.clone()); - self.assemble_where_clause_candidates(trait_def_id, - item.clone(), - matching_index); + self.assemble_where_clause_candidates(trait_def_id, item.clone()); Ok(()) } fn assemble_extension_candidates_for_trait_impls(&mut self, trait_def_id: ast::DefId, - item: ty::ImplOrTraitItem<'tcx>, - item_index: usize) + item: ty::ImplOrTraitItem<'tcx>) { - let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id); + let trait_def = self.tcx().lookup_trait_def(trait_def_id); // FIXME(arielb1): can we use for_each_relevant_impl here? trait_def.for_each_impl(self.tcx(), |impl_def_id| { @@ -665,7 +643,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { debug!("impl_substs={:?}", impl_substs); let impl_trait_ref = - ty::impl_trait_ref(self.tcx(), impl_def_id) + self.tcx().impl_trait_ref(impl_def_id) .unwrap() // we know this is a trait impl .subst(self.tcx(), &impl_substs); @@ -681,7 +659,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // as it will pollute the fcx's fulfillment context after this probe // is over. let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); - let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx); + let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx()); let traits::Normalized { value: xform_self_ty, obligations } = traits::normalize(selcx, cause, &xform_self_ty); @@ -690,11 +668,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: ExtensionImplCandidate(impl_def_id, - impl_trait_ref, - impl_substs, - item_index, - obligations) + kind: ExtensionImplCandidate(impl_def_id, impl_substs, obligations) }); }); } @@ -705,7 +679,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { None => { return true; } }; - let impl_type = ty::lookup_item_type(self.tcx(), impl_def_id); + let impl_type = self.tcx().lookup_item_type(impl_def_id); let impl_simplified_type = match fast_reject::simplify_type(self.tcx(), impl_type.ty, false) { Some(simplified_type) => simplified_type, @@ -717,8 +691,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_closure_candidates(&mut self, trait_def_id: ast::DefId, - item: ty::ImplOrTraitItem<'tcx>, - item_index: usize) + item: ty::ImplOrTraitItem<'tcx>) -> Result<(), MethodError<'tcx>> { // Check if this is one of the Fn,FnMut,FnOnce traits. @@ -742,7 +715,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { _ => continue, }; - let closure_kinds = self.fcx.inh.closure_kinds.borrow(); + let closure_kinds = &self.fcx.inh.tables.borrow().closure_kinds; let closure_kind = match closure_kinds.get(&closure_def_id) { Some(&k) => k, None => { @@ -759,7 +732,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // for the purposes of our method lookup, we only take // receiver type into account, so we can just substitute // fresh types here to use during substitution and subtyping. - let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id); + let trait_def = self.tcx().lookup_trait_def(trait_def_id); let substs = self.infcx().fresh_substs_for_trait(self.span, &trait_def.generics, step.self_ty); @@ -770,7 +743,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: ClosureCandidate(trait_def_id, item_index) + kind: TraitCandidate }); } @@ -779,16 +752,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_projection_candidates(&mut self, trait_def_id: ast::DefId, - item: ty::ImplOrTraitItem<'tcx>, - item_index: usize) + item: ty::ImplOrTraitItem<'tcx>) { debug!("assemble_projection_candidates(\ trait_def_id={:?}, \ - item={:?}, \ - item_index={})", + item={:?})", trait_def_id, - item, - item_index); + item); for step in self.steps.iter() { debug!("assemble_projection_candidates: step={:?}", @@ -802,8 +772,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { debug!("assemble_projection_candidates: projection_trait_ref={:?}", projection_trait_ref); - let trait_predicates = ty::lookup_predicates(self.tcx(), - projection_trait_ref.def_id); + let trait_predicates = self.tcx().lookup_predicates(projection_trait_ref.def_id); let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs); let predicates = bounds.predicates.into_vec(); debug!("assemble_projection_candidates: predicates={:?}", @@ -831,7 +800,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: ProjectionCandidate(trait_def_id, item_index) + kind: TraitCandidate }); } } @@ -840,13 +809,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_where_clause_candidates(&mut self, trait_def_id: ast::DefId, - item: ty::ImplOrTraitItem<'tcx>, - item_index: usize) + item: ty::ImplOrTraitItem<'tcx>) { debug!("assemble_where_clause_candidates(trait_def_id={:?})", trait_def_id); - let caller_predicates = self.fcx.inh.param_env.caller_bounds.clone(); + let caller_predicates = self.fcx.inh.infcx.parameter_environment.caller_bounds.clone(); for poly_bound in traits::elaborate_predicates(self.tcx(), caller_predicates) .filter_map(|p| p.to_opt_poly_trait_ref()) .filter(|b| b.def_id() == trait_def_id) @@ -863,7 +831,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: WhereClauseCandidate(poly_bound, item_index) + kind: WhereClauseCandidate(poly_bound) }); } } @@ -894,7 +862,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { match source { TraitSource(id) => id, ImplSource(impl_id) => { - match ty::trait_id_of_impl(tcx, impl_id) { + match tcx.trait_id_of_impl(impl_id) { Some(id) => id, None => tcx.sess.span_bug(span, @@ -928,7 +896,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn pick_step(&mut self, step: &CandidateStep<'tcx>) -> Option> { debug!("pick_step: step={:?}", step); - if ty::type_is_error(step.self_ty) { + if step.self_ty.references_error() { return None; } @@ -983,7 +951,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // Search through mutabilities in order to find one where pick works: [ast::MutImmutable, ast::MutMutable].iter().filter_map(|&m| { - let autoref_ty = ty::mk_rptr(tcx, region, ty::mt { + let autoref_ty = tcx.mk_ref(region, ty::mt { ty: step.self_ty, mutbl: m }); @@ -1049,8 +1017,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } applicable_candidates.pop().map(|probe| { - let pick = probe.to_unadjusted_pick(); - Ok(pick) + Ok(probe.to_unadjusted_pick()) }) } @@ -1074,48 +1041,52 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // clauses) that must be considered. Make sure that those // match as well (or at least may match, sometimes we // don't have enough information to fully evaluate). - match probe.kind { - InherentImplCandidate(impl_def_id, ref substs, ref ref_obligations) | - ExtensionImplCandidate(impl_def_id, _, ref substs, _, ref ref_obligations) => { - let selcx = &mut traits::SelectionContext::new(self.infcx(), self.fcx); - let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); - - // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = ty::lookup_predicates(self.tcx(), impl_def_id); - let impl_bounds = impl_bounds.instantiate(self.tcx(), substs); - let traits::Normalized { value: impl_bounds, - obligations: norm_obligations } = - traits::normalize(selcx, cause.clone(), &impl_bounds); - - // Convert the bounds into obligations. - let obligations = - traits::predicates_for_generics(cause.clone(), - &impl_bounds); - debug!("impl_obligations={:?}", obligations); - - // Evaluate those obligations to see if they might possibly hold. - let mut all_true = true; - for o in obligations.iter() - .chain(norm_obligations.iter()) - .chain(ref_obligations.iter()) { - if !selcx.evaluate_obligation(o) { - all_true = false; - if let &ty::Predicate::Trait(ref pred) = &o.predicate { - possibly_unsatisfied_predicates.push(pred.0.trait_ref); - } - } - } - all_true + let (impl_def_id, substs, ref_obligations) = match probe.kind { + InherentImplCandidate(ref substs, ref ref_obligations) => { + (probe.item.container().id(), substs, ref_obligations) + } + + ExtensionImplCandidate(impl_def_id, ref substs, ref ref_obligations) => { + (impl_def_id, substs, ref_obligations) } - ProjectionCandidate(..) | ObjectCandidate(..) | - ClosureCandidate(..) | + TraitCandidate | WhereClauseCandidate(..) => { // These have no additional conditions to check. - true + return true; + } + }; + + let selcx = &mut traits::SelectionContext::new(self.infcx()); + let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); + + // Check whether the impl imposes obligations we have to worry about. + let impl_bounds = self.tcx().lookup_predicates(impl_def_id); + let impl_bounds = impl_bounds.instantiate(self.tcx(), substs); + let traits::Normalized { value: impl_bounds, + obligations: norm_obligations } = + traits::normalize(selcx, cause.clone(), &impl_bounds); + + // Convert the bounds into obligations. + let obligations = + traits::predicates_for_generics(cause.clone(), + &impl_bounds); + debug!("impl_obligations={:?}", obligations); + + // Evaluate those obligations to see if they might possibly hold. + let mut all_true = true; + for o in obligations.iter() + .chain(norm_obligations.iter()) + .chain(ref_obligations.iter()) { + if !selcx.evaluate_obligation(o) { + all_true = false; + if let &ty::Predicate::Trait(ref pred) = &o.predicate { + possibly_unsatisfied_predicates.push(pred.0.trait_ref); + } } } + all_true }) } @@ -1140,20 +1111,19 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { probes: &[&Candidate<'tcx>]) -> Option> { // Do all probes correspond to the same trait? - let trait_data = match probes[0].to_trait_data() { - Some(data) => data, - None => return None, - }; - if probes[1..].iter().any(|p| p.to_trait_data() != Some(trait_data)) { + let container = probes[0].item.container(); + match container { + ty::TraitContainer(_) => {} + ty::ImplContainer(_) => return None + } + if probes[1..].iter().any(|p| p.item.container() != container) { return None; } // If so, just use this trait and call it a day. - let (trait_def_id, item_num) = trait_data; - let item = probes[0].item.clone(); Some(Pick { - item: item, - kind: TraitPick(trait_def_id, item_num), + item: probes[0].item.clone(), + kind: TraitPick, autoderefs: 0, autoref: None, unsize: None @@ -1266,7 +1236,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { impl_def_id: ast::DefId) -> (Ty<'tcx>, subst::Substs<'tcx>) { - let impl_pty = ty::lookup_item_type(self.tcx(), impl_def_id); + let impl_pty = self.tcx().lookup_item_type(impl_def_id); let type_vars = impl_pty.generics.types.map( @@ -1301,7 +1271,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn erase_late_bound_regions(&self, value: &ty::Binder) -> T where T : TypeFoldable<'tcx> { - ty::erase_late_bound_regions(self.tcx(), value) + self.tcx().erase_late_bound_regions(value) } } @@ -1314,24 +1284,22 @@ fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>, let impl_items = impl_items.get(&impl_def_id).unwrap(); impl_items .iter() - .map(|&did| ty::impl_or_trait_item(tcx, did.def_id())) + .map(|&did| tcx.impl_or_trait_item(did.def_id())) .find(|item| item.name() == item_name) } -/// Find item with name `item_name` defined in `trait_def_id` and return it, -/// along with its index (or `None`, if no such item). +/// Find item with name `item_name` defined in `trait_def_id` +/// and return it, or `None`, if no such item. fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, trait_def_id: ast::DefId, item_name: ast::Name) - -> Option<(usize, ty::ImplOrTraitItem<'tcx>)> + -> Option> { - let trait_items = ty::trait_items(tcx, trait_def_id); + let trait_items = tcx.trait_items(trait_def_id); debug!("trait_method; items: {:?}", trait_items); - trait_items - .iter() - .enumerate() - .find(|&(_, ref item)| item.name() == item_name) - .map(|(num, ref item)| (num, (*item).clone())) + trait_items.iter() + .find(|item| item.name() == item_name) + .cloned() } impl<'tcx> Candidate<'tcx> { @@ -1339,30 +1307,21 @@ impl<'tcx> Candidate<'tcx> { Pick { item: self.item.clone(), kind: match self.kind { - InherentImplCandidate(def_id, _, _) => { - InherentImplPick(def_id) - } - ObjectCandidate(def_id, item_num, real_index) => { - ObjectPick(def_id, item_num, real_index) - } - ExtensionImplCandidate(def_id, _, _, index, _) => { - ExtensionImplPick(def_id, index) + InherentImplCandidate(_, _) => InherentImplPick, + ExtensionImplCandidate(def_id, _, _) => { + ExtensionImplPick(def_id) } - ClosureCandidate(trait_def_id, index) => { - TraitPick(trait_def_id, index) - } - WhereClauseCandidate(ref trait_ref, index) => { + ObjectCandidate => ObjectPick, + TraitCandidate => TraitPick, + WhereClauseCandidate(ref trait_ref) => { // Only trait derived from where-clauses should // appear here, so they should not contain any // inference variables or other artifacts. This // means they are safe to put into the // `WhereClausePick`. - assert!(trait_ref.substs().types.iter().all(|&t| !ty::type_needs_infer(t))); + assert!(!trait_ref.substs().types.needs_infer()); - WhereClausePick((*trait_ref).clone(), index) - } - ProjectionCandidate(def_id, index) => { - TraitPick(def_id, index) + WhereClausePick(trait_ref.clone()) } }, autoderefs: 0, @@ -1373,35 +1332,13 @@ impl<'tcx> Candidate<'tcx> { fn to_source(&self) -> CandidateSource { match self.kind { - InherentImplCandidate(def_id, _, _) => ImplSource(def_id), - ObjectCandidate(def_id, _, _) => TraitSource(def_id), - ExtensionImplCandidate(def_id, _, _, _, _) => ImplSource(def_id), - ClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id), - WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()), - ProjectionCandidate(trait_def_id, _) => TraitSource(trait_def_id), - } - } - - fn to_trait_data(&self) -> Option<(ast::DefId, ItemIndex)> { - match self.kind { - InherentImplCandidate(..) => { - None - } - ObjectCandidate(trait_def_id, item_num, _) => { - Some((trait_def_id, item_num)) - } - ClosureCandidate(trait_def_id, item_num) => { - Some((trait_def_id, item_num)) - } - ExtensionImplCandidate(_, ref trait_ref, _, item_num, _) => { - Some((trait_ref.def_id, item_num)) - } - WhereClauseCandidate(ref trait_ref, item_num) => { - Some((trait_ref.def_id(), item_num)) - } - ProjectionCandidate(trait_def_id, item_num) => { - Some((trait_def_id, item_num)) + InherentImplCandidate(_, _) => { + ImplSource(self.item.container().id()) } + ExtensionImplCandidate(def_id, _, _) => ImplSource(def_id), + ObjectCandidate | + TraitCandidate | + WhereClauseCandidate(_) => TraitSource(self.item.container().id()), } } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 2325b9852c73d..4d86a4f7c70ff 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -15,7 +15,7 @@ use CrateCtxt; use astconv::AstConv; use check::{self, FnCtxt}; -use middle::ty::{self, Ty, ToPolyTraitRef, AsPredicate}; +use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, HasTypeFlags}; use middle::def; use middle::lang_items::FnOnceTraitLangItem; use middle::subst::Substs; @@ -40,7 +40,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, error: MethodError<'tcx>) { // avoid suggestions when we don't know what's going on. - if ty::type_is_error(rcvr_ty) { + if rcvr_ty.references_error() { return } @@ -66,7 +66,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // If the item has the name of a field, give a help note if let (&ty::TyStruct(did, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { - let fields = ty::lookup_struct_fields(cx, did); + let fields = cx.lookup_struct_fields(did); if let Some(field) = fields.iter().find(|f| f.name == item_name) { let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) { @@ -89,7 +89,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }; // Determine if the field can be used as a function in some way - let field_ty = ty::lookup_field_type(cx, did, field.id, substs); + let field_ty = cx.lookup_field_type(did, field.id, substs); if let Ok(fn_once_trait_did) = cx.lang_items.require(FnOnceTraitLangItem) { let infcx = fcx.infcx(); infcx.probe(|_| { @@ -101,8 +101,8 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = Obligation::misc(span, fcx.body_id, - poly_trait_ref.as_predicate()); - let mut selcx = SelectionContext::new(infcx, fcx); + poly_trait_ref.to_predicate()); + let mut selcx = SelectionContext::new(infcx); if selcx.evaluate_obligation(&obligation) { span_stored_function(); @@ -159,7 +159,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, invoked on this closure as we have not yet inferred what \ kind of closure it is", item_name, - ty::item_path_str(fcx.tcx(), trait_def_id)); + fcx.tcx().item_path_str(trait_def_id)); let msg = if let Some(callee) = rcvr_expr { format!("{}; use overloaded call notation instead (e.g., `{}()`)", msg, pprust::expr_to_string(callee)) @@ -188,11 +188,12 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let impl_ty = check::impl_self_ty(fcx, span, impl_did).ty; - let insertion = match ty::impl_trait_ref(fcx.tcx(), impl_did) { + let insertion = match fcx.tcx().impl_trait_ref(impl_did) { None => format!(""), - Some(trait_ref) => format!(" of the trait `{}`", - ty::item_path_str(fcx.tcx(), - trait_ref.def_id)), + Some(trait_ref) => { + format!(" of the trait `{}`", + fcx.tcx().item_path_str(trait_ref.def_id)) + } }; span_note!(fcx.sess(), item_span, @@ -202,12 +203,12 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, impl_ty); } CandidateSource::TraitSource(trait_did) => { - let (_, item) = trait_item(fcx.tcx(), trait_did, item_name).unwrap(); + let item = trait_item(fcx.tcx(), trait_did, item_name).unwrap(); let item_span = fcx.tcx().map.def_id_span(item.def_id(), span); span_note!(fcx.sess(), item_span, "candidate #{} is defined in the trait `{}`", idx + 1, - ty::item_path_str(fcx.tcx(), trait_did)); + fcx.tcx().item_path_str(trait_did)); } } } @@ -243,7 +244,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.sess().fileline_help(span, &*format!("candidate #{}: use `{}`", i + 1, - ty::item_path_str(fcx.tcx(), *trait_did))) + fcx.tcx().item_path_str(*trait_did))) } return @@ -289,7 +290,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.sess().fileline_help(span, &*format!("candidate #{}: `{}`", i + 1, - ty::item_path_str(fcx.tcx(), trait_info.def_id))) + fcx.tcx().item_path_str(trait_info.def_id))) } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 34df349b7a3db..9704bef648774 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,8 +87,6 @@ use fmt_macros::{Parser, Piece, Position}; use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS}; use middle::def; use middle::infer; -use middle::mem_categorization as mc; -use middle::mem_categorization::McResult; use middle::pat_util::{self, pat_id_map}; use middle::privacy::{AllPublic, LastMod}; use middle::region::{self, CodeExtent}; @@ -96,11 +94,10 @@ use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace use middle::traits::{self, report_fulfillment_errors}; use middle::ty::{FnSig, GenericPredicates, TypeScheme}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; -use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty}; -use middle::ty::liberate_late_bound_regions; -use middle::ty::{MethodCall, MethodCallee, MethodMap}; +use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty}; +use middle::ty::{MethodCall, MethodCallee}; use middle::ty_fold::{TypeFolder, TypeFoldable}; -use rscope::RegionScope; +use rscope::{ElisionFailureInfo, RegionScope}; use session::Session; use {CrateCtxt, lookup_full_def, require_same_types}; use TypeAndSubsts; @@ -153,25 +150,14 @@ mod op; pub struct Inherited<'a, 'tcx: 'a> { infcx: infer::InferCtxt<'a, 'tcx>, locals: RefCell>>, - param_env: ty::ParameterEnvironment<'a, 'tcx>, - // Temporary tables: - node_types: RefCell>>, - item_substs: RefCell>>, - adjustments: RefCell>>, - method_map: MethodMap<'tcx>, - upvar_capture_map: RefCell, - closure_tys: RefCell>>, - closure_kinds: RefCell>, + tables: &'a RefCell>, // A mapping from each fn's id to its signature, with all bound // regions replaced with free ones. Unlike the other tables, this // one is never copied into the tcx: it is only used by regionck. fn_sig_map: RefCell>>>, - // Tracks trait obligations incurred during this function body. - fulfillment_cx: RefCell>, - // When we process a call like `c()` where `c` is a closure type, // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or // `FnOnce` closure. In that case, we defer full resolution of the @@ -229,7 +215,7 @@ impl<'tcx> Expectation<'tcx> { match *self { ExpectHasType(ety) => { let ety = fcx.infcx().shallow_resolve(ety); - if !ty::type_is_ty_var(ety) { + if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation @@ -299,110 +285,33 @@ pub struct FnCtxt<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx>, } -impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> { - fn node_ty(&self, id: ast::NodeId) -> McResult> { - let ty = self.node_ty(id); - self.resolve_type_vars_or_error(&ty) - } - fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult> { - let ty = self.adjust_expr_ty(expr, self.inh.adjustments.borrow().get(&expr.id)); - self.resolve_type_vars_or_error(&ty) - } - fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool { - let ty = self.infcx().resolve_type_vars_if_possible(&ty); - !traits::type_known_to_meet_builtin_bound(self.infcx(), self, ty, ty::BoundCopy, span) - } - fn node_method_ty(&self, method_call: ty::MethodCall) - -> Option> { - self.inh.method_map.borrow() - .get(&method_call) - .map(|method| method.ty) - .map(|ty| self.infcx().resolve_type_vars_if_possible(&ty)) - } - fn node_method_origin(&self, method_call: ty::MethodCall) - -> Option> - { - self.inh.method_map.borrow() - .get(&method_call) - .map(|method| method.origin.clone()) - } - fn adjustments(&self) -> &RefCell>> { - &self.inh.adjustments - } - fn is_method_call(&self, id: ast::NodeId) -> bool { - self.inh.method_map.borrow().contains_key(&ty::MethodCall::expr(id)) - } - fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { - self.param_env().temporary_scope(rvalue_id) - } - fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { - self.inh.upvar_capture_map.borrow().get(&upvar_id).cloned() - } -} - -impl<'a, 'tcx> ty::ClosureTyper<'tcx> for FnCtxt<'a, 'tcx> { - fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> { - &self.inh.param_env - } - - fn closure_kind(&self, - def_id: ast::DefId) - -> Option - { - self.inh.closure_kinds.borrow().get(&def_id).cloned() - } - - fn closure_type(&self, - def_id: ast::DefId, - substs: &subst::Substs<'tcx>) - -> ty::ClosureTy<'tcx> - { - self.inh.closure_tys.borrow().get(&def_id).unwrap().subst(self.tcx(), substs) - } - - fn closure_upvars(&self, - def_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option>> - { - ty::closure_upvars(self, def_id, substs) - } -} - impl<'a, 'tcx> Inherited<'a, 'tcx> { fn new(tcx: &'a ty::ctxt<'tcx>, + tables: &'a RefCell>, param_env: ty::ParameterEnvironment<'a, 'tcx>) -> Inherited<'a, 'tcx> { + Inherited { - infcx: infer::new_infer_ctxt(tcx), + infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env), true), locals: RefCell::new(NodeMap()), - param_env: param_env, - node_types: RefCell::new(NodeMap()), - item_substs: RefCell::new(NodeMap()), - adjustments: RefCell::new(NodeMap()), - method_map: RefCell::new(FnvHashMap()), - upvar_capture_map: RefCell::new(FnvHashMap()), - closure_tys: RefCell::new(DefIdMap()), - closure_kinds: RefCell::new(DefIdMap()), + tables: tables, fn_sig_map: RefCell::new(NodeMap()), - fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(true)), deferred_call_resolutions: RefCell::new(DefIdMap()), deferred_cast_checks: RefCell::new(Vec::new()), } } fn normalize_associated_types_in(&self, - typer: &ty::ClosureTyper<'tcx>, span: Span, body_id: ast::NodeId, value: &T) -> T - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { - let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); + let mut fulfillment_cx = self.infcx.fulfillment_cx.borrow_mut(); assoc::normalize_associated_types_in(&self.infcx, - typer, - &mut *fulfillment_cx, span, + &mut fulfillment_cx, + span, body_id, value) } @@ -426,12 +335,13 @@ pub fn blank_fn_ctxt<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, } } -fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>) +fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, + tables: &'a RefCell>) -> Inherited<'a, 'tcx> { // It's kind of a kludge to manufacture a fake function context // and statement context, but we might as well do write the code only once - let param_env = ty::empty_parameter_environment(ccx.tcx); - Inherited::new(ccx.tcx, param_env) + let param_env = ccx.tcx.empty_parameter_environment(); + Inherited::new(ccx.tcx, &tables, param_env) } struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> } @@ -506,17 +416,19 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, { match raw_fty.sty { ty::TyBareFn(_, ref fn_ty) => { - let inh = Inherited::new(ccx.tcx, param_env); + let tables = RefCell::new(ty::Tables::empty()); + let inh = Inherited::new(ccx.tcx, &tables, param_env); // Compute the fty from point of view of inside fn. let fn_sig = - fn_ty.sig.subst(ccx.tcx, &inh.param_env.free_substs); + fn_ty.sig.subst(ccx.tcx, &inh.infcx.parameter_environment.free_substs); let fn_sig = - liberate_late_bound_regions(ccx.tcx, - region::DestructionScopeData::new(body.id), - &fn_sig); + ccx.tcx.liberate_late_bound_regions(region::DestructionScopeData::new(body.id), + &fn_sig); let fn_sig = - inh.normalize_associated_types_in(&inh.param_env, body.span, body.id, &fn_sig); + inh.normalize_associated_types_in(body.span, + body.id, + &fn_sig); let fcx = check_fn(ccx, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body, &inh); @@ -718,7 +630,7 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { check_representable(tcx, span, id, "struct"); check_instantiable(tcx, span, id); - if ty::lookup_simd(tcx, local_def(id)) { + if tcx.lookup_simd(local_def(id)) { check_simd(tcx, span, id); } } @@ -726,7 +638,7 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { debug!("check_item_type(it.id={}, it.ident={})", it.id, - ty::item_path_str(ccx.tcx, local_def(it.id))); + ccx.tcx.item_path_str(local_def(it.id))); let _indenter = indenter(); match it.node { // Consts can play a role in type-checking, so they are included here. @@ -741,7 +653,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { ast::ItemFn(..) => {} // entirely within check_item_body ast::ItemImpl(_, _, _, _, _, ref impl_items) => { debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); - match ty::impl_trait_ref(ccx.tcx, local_def(it.id)) { + match ccx.tcx.impl_trait_ref(local_def(it.id)) { Some(impl_trait_ref) => { check_impl_items_against_trait(ccx, it.span, @@ -758,7 +670,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { check_struct(ccx, it.id, it.span); } ast::ItemTy(ref t, ref generics) => { - let pty_ty = ty::node_id_to_type(ccx.tcx, it.id); + let pty_ty = ccx.tcx.node_id_to_type(it.id); check_bounds_are_used(ccx, t.span, &generics.ty_params, pty_ty); } ast::ItemForeignMod(ref m) => { @@ -768,7 +680,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { } } else { for item in &m.items { - let pty = ty::lookup_item_type(ccx.tcx, local_def(item.id)); + let pty = ccx.tcx.lookup_item_type(local_def(item.id)); if !pty.generics.types.is_empty() { span_err!(ccx.tcx.sess, item.span, E0044, "foreign items may not have type parameters"); @@ -790,18 +702,18 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { debug!("check_item_body(it.id={}, it.ident={})", it.id, - ty::item_path_str(ccx.tcx, local_def(it.id))); + ccx.tcx.item_path_str(local_def(it.id))); let _indenter = indenter(); match it.node { ast::ItemFn(ref decl, _, _, _, _, ref body) => { - let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); + let fn_pty = ccx.tcx.lookup_item_type(ast_util::local_def(it.id)); let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id); check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env); } ast::ItemImpl(_, _, _, _, _, ref impl_items) => { debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); - let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); + let impl_pty = ccx.tcx.lookup_item_type(ast_util::local_def(it.id)); for impl_item in impl_items { match impl_item.node { @@ -820,7 +732,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { } } ast::ItemTrait(_, _, _, ref trait_items) => { - let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id)); + let trait_def = ccx.tcx.lookup_trait_def(local_def(it.id)); for trait_item in trait_items { match trait_item.node { ast::ConstTraitItem(_, Some(ref expr)) => { @@ -921,7 +833,7 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, item_generics, id); let param_env = ParameterEnvironment::for_item(ccx.tcx, id); - let fty = ty::node_id_to_type(ccx.tcx, id); + let fty = ccx.tcx.node_id_to_type(id); debug!("check_method_body: fty={:?}", fty); check_bare_fn(ccx, &sig.decl, body, id, span, fty, param_env); @@ -933,132 +845,83 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_items: &[P]) { // Locate trait methods let tcx = ccx.tcx; - let trait_items = ty::trait_items(tcx, impl_trait_ref.def_id); + let trait_items = tcx.trait_items(impl_trait_ref.def_id); + let mut overridden_associated_type = None; // Check existing impl methods to see if they are both present in trait // and compatible with trait signature for impl_item in impl_items { + let ty_impl_item = ccx.tcx.impl_or_trait_item(local_def(impl_item.id)); + let ty_trait_item = trait_items.iter() + .find(|ac| ac.name() == ty_impl_item.name()) + .unwrap_or_else(|| { + // This is checked by resolve + tcx.sess.span_bug(impl_item.span, + &format!("impl-item `{}` is not a member of `{:?}`", + token::get_name(ty_impl_item.name()), + impl_trait_ref)); + }); match impl_item.node { ast::ConstImplItem(..) => { - let impl_const_def_id = local_def(impl_item.id); - let impl_const_ty = ty::impl_or_trait_item(ccx.tcx, - impl_const_def_id); + let impl_const = match ty_impl_item { + ty::ConstTraitItem(ref cti) => cti, + _ => tcx.sess.span_bug(impl_item.span, "non-const impl-item for const") + }; // Find associated const definition. - let opt_associated_const = - trait_items.iter() - .find(|ac| ac.name() == impl_const_ty.name()); - match opt_associated_const { - Some(associated_const) => { - match (associated_const, &impl_const_ty) { - (&ty::ConstTraitItem(ref const_trait), - &ty::ConstTraitItem(ref const_impl)) => { - compare_const_impl(ccx.tcx, - &const_impl, - impl_item.span, - &const_trait, - &*impl_trait_ref); - } - _ => { - span_err!(tcx.sess, impl_item.span, E0323, - "item `{}` is an associated const, \ - which doesn't match its trait `{:?}`", - token::get_name(impl_const_ty.name()), - impl_trait_ref) - } - } - } - None => { - // This is `span_bug` as it should have already been - // caught in resolve. - tcx.sess.span_bug( - impl_item.span, - &format!( - "associated const `{}` is not a member of \ - trait `{:?}`", - token::get_name(impl_const_ty.name()), - impl_trait_ref)); - } + if let &ty::ConstTraitItem(ref trait_const) = ty_trait_item { + compare_const_impl(ccx.tcx, + &impl_const, + impl_item.span, + trait_const, + &*impl_trait_ref); + } else { + span_err!(tcx.sess, impl_item.span, E0323, + "item `{}` is an associated const, \ + which doesn't match its trait `{:?}`", + token::get_name(impl_const.name), + impl_trait_ref) } } ast::MethodImplItem(ref sig, ref body) => { check_trait_fn_not_const(ccx, impl_item.span, sig.constness); - let impl_method_def_id = local_def(impl_item.id); - let impl_item_ty = ty::impl_or_trait_item(ccx.tcx, - impl_method_def_id); - - // If this is an impl of a trait method, find the - // corresponding method definition in the trait. - let opt_trait_method_ty = - trait_items.iter() - .find(|ti| ti.name() == impl_item_ty.name()); - match opt_trait_method_ty { - Some(trait_method_ty) => { - match (trait_method_ty, &impl_item_ty) { - (&ty::MethodTraitItem(ref trait_method_ty), - &ty::MethodTraitItem(ref impl_method_ty)) => { - compare_impl_method(ccx.tcx, - &**impl_method_ty, - impl_item.span, - body.id, - &**trait_method_ty, - &*impl_trait_ref); - } - _ => { - span_err!(tcx.sess, impl_item.span, E0324, - "item `{}` is an associated method, \ - which doesn't match its trait `{:?}`", - token::get_name(impl_item_ty.name()), - impl_trait_ref) - } - } - } - None => { - // This is span_bug as it should have already been - // caught in resolve. - tcx.sess.span_bug( - impl_item.span, - &format!("method `{}` is not a member of trait `{:?}`", - token::get_name(impl_item_ty.name()), - impl_trait_ref)); - } + let impl_method = match ty_impl_item { + ty::MethodTraitItem(ref mti) => mti, + _ => tcx.sess.span_bug(impl_item.span, "non-method impl-item for method") + }; + + if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item { + compare_impl_method(ccx.tcx, + &impl_method, + impl_item.span, + body.id, + &trait_method, + &impl_trait_ref); + } else { + span_err!(tcx.sess, impl_item.span, E0324, + "item `{}` is an associated method, \ + which doesn't match its trait `{:?}`", + token::get_name(impl_method.name), + impl_trait_ref) } } ast::TypeImplItem(_) => { - let typedef_def_id = local_def(impl_item.id); - let typedef_ty = ty::impl_or_trait_item(ccx.tcx, - typedef_def_id); - - // If this is an impl of an associated type, find the - // corresponding type definition in the trait. - let opt_associated_type = - trait_items.iter() - .find(|ti| ti.name() == typedef_ty.name()); - match opt_associated_type { - Some(associated_type) => { - match (associated_type, &typedef_ty) { - (&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {} - _ => { - span_err!(tcx.sess, impl_item.span, E0325, - "item `{}` is an associated type, \ - which doesn't match its trait `{:?}`", - token::get_name(typedef_ty.name()), - impl_trait_ref) - } - } - } - None => { - // This is `span_bug` as it should have already been - // caught in resolve. - tcx.sess.span_bug( - impl_item.span, - &format!( - "associated type `{}` is not a member of \ - trait `{:?}`", - token::get_name(typedef_ty.name()), - impl_trait_ref)); + let impl_type = match ty_impl_item { + ty::TypeTraitItem(ref tti) => tti, + _ => tcx.sess.span_bug(impl_item.span, "non-type impl-item for type") + }; + + if let &ty::TypeTraitItem(ref at) = ty_trait_item { + if let Some(_) = at.ty { + overridden_associated_type = Some(impl_item); } + } else { + span_err!(tcx.sess, impl_item.span, E0325, + "item `{}` is an associated type, \ + which doesn't match its trait `{:?}`", + token::get_name(impl_type.name), + impl_trait_ref) } } ast::MacImplItem(_) => tcx.sess.span_bug(impl_item.span, @@ -1067,9 +930,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } // Check for missing items from trait - let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id); - let associated_consts = ty::associated_consts(tcx, impl_trait_ref.def_id); + let provided_methods = tcx.provided_trait_methods(impl_trait_ref.def_id); + let associated_consts = tcx.associated_consts(impl_trait_ref.def_id); let mut missing_items = Vec::new(); + let mut invalidated_items = Vec::new(); + let associated_type_overridden = overridden_associated_type.is_some(); for trait_item in trait_items.iter() { match *trait_item { ty::ConstTraitItem(ref associated_const) => { @@ -1084,9 +949,12 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let is_provided = associated_consts.iter().any(|ac| ac.default.is_some() && ac.name == associated_const.name); - if !is_implemented && !is_provided { - missing_items.push(format!("`{}`", - token::get_name(associated_const.name))); + 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) => { @@ -1101,8 +969,12 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }); let is_provided = provided_methods.iter().any(|m| m.name == trait_method.name); - if !is_implemented && !is_provided { - missing_items.push(format!("`{}`", token::get_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); + } } } ty::TypeTraitItem(ref associated_type) => { @@ -1115,8 +987,12 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }); let is_provided = associated_type.ty.is_some(); - if !is_implemented && !is_provided { - missing_items.push(format!("`{}`", token::get_name(associated_type.name))); + if !is_implemented { + if !is_provided { + missing_items.push(associated_type.name); + } else if associated_type_overridden { + invalidated_items.push(associated_type.name); + } } } } @@ -1124,8 +1000,21 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, if !missing_items.is_empty() { span_err!(tcx.sess, impl_span, E0046, - "not all trait items implemented, missing: {}", - missing_items.connect(", ")); + "not all trait items implemented, missing: `{}`", + missing_items.iter() + .map(::as_str) + .collect::>().connect("`, `")) + } + + if !invalidated_items.is_empty() { + let invalidator = overridden_associated_type.unwrap(); + span_err!(tcx.sess, invalidator.span, E0399, + "the following trait items need to be reimplemented \ + as `{}` was overridden: `{}`", + invalidator.ident.as_str(), + invalidated_items.iter() + .map(::as_str) + .collect::>().connect("`, `")) } } @@ -1146,7 +1035,7 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ast::MutMutable => "mut ", ast::MutImmutable => "" }; - if ty::type_is_trait(t_cast) { + if t_cast.is_trait() { match fcx.tcx().sess.codemap().span_to_snippet(t_span) { Ok(s) => { fcx.tcx().sess.span_suggestion(t_span, @@ -1189,13 +1078,13 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn get_item_type_scheme(&self, _: Span, id: ast::DefId) -> Result, ErrorReported> { - Ok(ty::lookup_item_type(self.tcx(), id)) + Ok(self.tcx().lookup_item_type(id)) } fn get_trait_def(&self, _: Span, id: ast::DefId) -> Result<&'tcx ty::TraitDef<'tcx>, ErrorReported> { - Ok(ty::lookup_trait_def(self.tcx(), id)) + Ok(self.tcx().lookup_trait_def(id)) } fn ensure_super_predicates(&self, _: Span, _: ast::DefId) -> Result<(), ErrorReported> { @@ -1204,7 +1093,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } fn get_free_substs(&self) -> Option<&Substs<'tcx>> { - Some(&self.inh.param_env.free_substs) + Some(&self.inh.infcx.parameter_environment.free_substs) } fn get_type_parameter_bounds(&self, @@ -1213,7 +1102,8 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { -> Result>, ErrorReported> { let def = self.tcx().type_parameter_def(node_id); - let r = self.inh.param_env.caller_bounds + let r = self.inh.infcx.parameter_environment + .caller_bounds .iter() .filter_map(|predicate| { match *predicate { @@ -1238,7 +1128,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { assoc_name: ast::Name) -> bool { - let trait_def = ty::lookup_trait_def(self.ccx.tcx, trait_def_id); + let trait_def = self.ccx.tcx.lookup_trait_def(trait_def_id); trait_def.associated_type_names.contains(&assoc_name) } @@ -1279,7 +1169,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn param_env(&self) -> &ty::ParameterEnvironment<'a,'tcx> { - &self.inh.param_env + &self.inh.infcx.parameter_environment } pub fn sess(&self) -> &Session { @@ -1296,15 +1186,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn resolve_type_vars_if_possible(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { debug!("resolve_type_vars_if_possible(ty={:?})", ty); - // No ty::infer()? Nothing needs doing. - if !ty::type_has_ty_infer(ty) { + // No TyInfer()? Nothing needs doing. + if !ty.has_infer_types() { debug!("resolve_type_vars_if_possible: ty={:?}", ty); return ty; } // If `ty` is a type variable, see whether we already know what it is. ty = self.infcx().resolve_type_vars_if_possible(&ty); - if !ty::type_has_ty_infer(ty) { + if !ty.has_infer_types() { debug!("resolve_type_vars_if_possible: ty={:?}", ty); return ty; } @@ -1312,7 +1202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If not, try resolving any new fcx obligations that have cropped up. self.select_new_obligations(); ty = self.infcx().resolve_type_vars_if_possible(&ty); - if !ty::type_has_ty_infer(ty) { + if !ty.has_infer_types() { debug!("resolve_type_vars_if_possible: ty={:?}", ty); return ty; } @@ -1328,16 +1218,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - /// Resolves all type variables in `t` and then, if any were left - /// unresolved, substitutes an error type. This is used after the - /// main checking when doing a second pass before writeback. The - /// justification is that writeback will produce an error for - /// these unconstrained type variables. - fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult> { - let t = self.infcx().resolve_type_vars_if_possible(t); - if ty::type_has_ty_infer(t) || ty::type_is_error(t) { Err(()) } else { Ok(t) } - } - fn record_deferred_call_resolution(&self, closure_def_id: ast::DefId, r: DeferredCallResolutionHandler<'tcx>) { @@ -1374,10 +1254,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64. pub fn default_type_parameters(&self) { use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - for (_, &mut ref ty) in &mut *self.inh.node_types.borrow_mut() { + for (_, &mut ref ty) in &mut self.inh.tables.borrow_mut().node_types { let resolved = self.infcx().resolve_type_vars_if_possible(ty); if self.infcx().type_var_diverges(resolved) { - demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx())); + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { match self.infcx().type_is_unconstrained_numeric(resolved) { UnconstrainedInt => { @@ -1396,7 +1276,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) { debug!("write_ty({}, {:?}) in fcx {}", node_id, ty, self.tag()); - self.inh.node_types.borrow_mut().insert(node_id, ty); + self.inh.tables.borrow_mut().node_types.insert(node_id, ty); } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -1406,7 +1286,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { substs, self.tag()); - self.inh.item_substs.borrow_mut().insert(node_id, substs); + self.inh.tables.borrow_mut().item_substs.insert(node_id, substs); } } @@ -1432,7 +1312,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - self.inh.adjustments.borrow_mut().insert(node_id, adj); + self.inh.tables.borrow_mut().adjustments.insert(node_id, adj); } /// Basically whenever we are converting from a type scheme into @@ -1443,7 +1323,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { substs: &Substs<'tcx>, value: &T) -> T - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { let value = value.subst(self.tcx(), substs); let result = self.normalize_associated_types_in(span, &value); @@ -1469,9 +1349,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn normalize_associated_types_in(&self, span: Span, value: &T) -> T - where T : TypeFoldable<'tcx> + HasProjectionTypes + where T : TypeFoldable<'tcx> + HasTypeFlags { - self.inh.normalize_associated_types_in(self, span, self.body_id, value) + self.inh.normalize_associated_types_in(span, self.body_id, value) } fn normalize_associated_type(&self, @@ -1483,10 +1363,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = traits::ObligationCause::new(span, self.body_id, traits::ObligationCauseCode::MiscObligation); - self.inh.fulfillment_cx + self.inh + .infcx + .fulfillment_cx .borrow_mut() .normalize_projection_type(self.infcx(), - self, ty::ProjectionTy { trait_ref: trait_ref, item_name: item_name, @@ -1506,9 +1387,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { -> TypeAndSubsts<'tcx> { let type_scheme = - ty::lookup_item_type(self.tcx(), def_id); + self.tcx().lookup_item_type(def_id); let type_predicates = - ty::lookup_predicates(self.tcx(), def_id); + self.tcx().lookup_predicates(def_id); let substs = self.infcx().fresh_substs_for_generics( span, @@ -1543,7 +1424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx(); let ty::TypeScheme { generics, ty: decl_ty } = - ty::lookup_item_type(tcx, did); + tcx.lookup_item_type(did); let substs = astconv::ast_path_substs_for_ty(self, self, path.span, @@ -1557,7 +1438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn write_nil(&self, node_id: ast::NodeId) { - self.write_ty(node_id, ty::mk_nil(self.tcx())); + self.write_ty(node_id, self.tcx().mk_nil()); } pub fn write_error(&self, node_id: ast::NodeId) { self.write_ty(node_id, self.tcx().types.err); @@ -1596,7 +1477,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { -> bool { traits::type_known_to_meet_builtin_bound(self.infcx(), - self.param_env(), ty, ty::BoundSized, span) @@ -1607,7 +1487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { builtin_bound: ty::BuiltinBound, cause: traits::ObligationCause<'tcx>) { - self.inh.fulfillment_cx.borrow_mut() + self.inh.infcx.fulfillment_cx.borrow_mut() .register_builtin_bound(self.infcx(), ty, builtin_bound, cause); } @@ -1616,7 +1496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { debug!("register_predicate({:?})", obligation); - self.inh.fulfillment_cx + self.inh.infcx.fulfillment_cx .borrow_mut() .register_predicate_obligation(self.infcx(), obligation); } @@ -1633,7 +1513,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn expr_ty(&self, ex: &ast::Expr) -> Ty<'tcx> { - match self.inh.node_types.borrow().get(&ex.id) { + match self.inh.tables.borrow().node_types.get(&ex.id) { Some(&t) => t, None => { self.tcx().sess.bug(&format!("no type for expr in fcx {}", @@ -1651,18 +1531,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let raw_ty = self.expr_ty(expr); let raw_ty = self.infcx().shallow_resolve(raw_ty); let resolve_ty = |ty: Ty<'tcx>| self.infcx().resolve_type_vars_if_possible(&ty); - ty::adjust_ty(self.tcx(), - expr.span, - expr.id, - raw_ty, - adjustment, - |method_call| self.inh.method_map.borrow() - .get(&method_call) - .map(|method| resolve_ty(method.ty))) + raw_ty.adjust(self.tcx(), expr.span, expr.id, adjustment, |method_call| { + self.inh.tables.borrow().method_map.get(&method_call) + .map(|method| resolve_ty(method.ty)) + }) } pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> { - match self.inh.node_types.borrow().get(&id) { + match self.inh.tables.borrow().node_types.get(&id) { Some(&t) => t, None if self.err_count_since_creation() != 0 => self.tcx().types.err, None => { @@ -1675,7 +1551,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn item_substs(&self) -> Ref>> { - self.inh.item_substs.borrow() + // NOTE: @jroesch this is hack that appears to be fixed on nightly, will monitor if + // it changes when we upgrade the snapshot compiler + fn project_item_susbts<'a, 'tcx>(tables: &'a ty::Tables<'tcx>) + -> &'a NodeMap> { + &tables.item_substs + } + + Ref::map(self.inh.tables.borrow(), project_item_susbts) } pub fn opt_node_ty_substs(&self, @@ -1683,7 +1566,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { f: F) where F: FnOnce(&ty::ItemSubsts<'tcx>), { - match self.inh.item_substs.borrow().get(&id) { + match self.inh.tables.borrow().item_substs.get(&id) { Some(s) => { f(s) } None => { } } @@ -1739,7 +1622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { region: ty::Region, cause: traits::ObligationCause<'tcx>) { - let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); + let mut fulfillment_cx = self.inh.infcx.fulfillment_cx.borrow_mut(); fulfillment_cx.register_region_obligation(ty, region, cause); } @@ -1798,7 +1681,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { -> Option> { let o_field = items.iter().find(|f| f.name == fieldname); - o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs)) + o_field.map(|f| self.tcx().lookup_field_type(class_id, f.id, substs)) .map(|t| self.normalize_associated_types_in(span, &t)) } @@ -1811,7 +1694,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { -> Option> { let o_field = if idx < items.len() { Some(&items[idx]) } else { None }; - o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs)) + o_field.map(|f| self.tcx().lookup_field_type(class_id, f.id, substs)) .map(|t| self.normalize_associated_types_in(span, &t)) } @@ -1838,8 +1721,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert!(self.inh.deferred_call_resolutions.borrow().is_empty()); self.select_all_obligations_and_apply_defaults(); - let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); - match fulfillment_cx.select_all_or_error(self.infcx(), self) { + let mut fulfillment_cx = self.inh.infcx.fulfillment_cx.borrow_mut(); + match fulfillment_cx.select_all_or_error(self.infcx()) { Ok(()) => { } Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } } @@ -1848,9 +1731,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Select as many obligations as we can at present. fn select_obligations_where_possible(&self) { match - self.inh.fulfillment_cx + self.inh.infcx.fulfillment_cx .borrow_mut() - .select_where_possible(self.infcx(), self) + .select_where_possible(self.infcx()) { Ok(()) => { } Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } @@ -1863,9 +1746,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// work. fn select_new_obligations(&self) { match - self.inh.fulfillment_cx + self.inh.infcx.fulfillment_cx .borrow_mut() - .select_new_obligations(self.infcx(), self) + .select_new_obligations(self.infcx()) { Ok(()) => { } Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } @@ -1876,6 +1759,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { fn object_lifetime_default(&self, span: Span) -> Option { + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, span: Span) -> ty::Region { // RFC #599 specifies that object lifetime defaults take // precedence over other defaults. But within a fn body we // don't have a *default* region, rather we use inference to @@ -1883,11 +1770,11 @@ impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { // (and anyway, within a fn body the right region may not even // be something the user can write explicitly, since it might // be some expression). - Some(self.infcx().next_region_var(infer::MiscVariable(span))) + self.infcx().next_region_var(infer::MiscVariable(span)) } fn anon_regions(&self, span: Span, count: usize) - -> Result, Option>> { + -> Result, Option>> { Ok((0..count).map(|_| { self.infcx().next_region_var(infer::MiscVariable(span)) }).collect()) @@ -1948,13 +1835,13 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, } UnresolvedTypeAction::Ignore => { // We can continue even when the type cannot be resolved - // (i.e. it is an inference variable) because `ty::deref` + // (i.e. it is an inference variable) because `Ty::builtin_deref` // and `try_overloaded_deref` both simply return `None` // in such a case without producing spurious errors. fcx.resolve_type_vars_if_possible(t) } }; - if ty::type_is_error(resolved_t) { + if resolved_t.references_error() { return (resolved_t, autoderefs, None); } @@ -1964,7 +1851,7 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, } // Otherwise, deref if type is derefable: - let mt = match ty::deref(resolved_t, false) { + let mt = match resolved_t.builtin_deref(false) { Some(mt) => Some(mt), None => { let method_call = @@ -2045,15 +1932,15 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(method) => { // extract method method return type, which will be &T; // all LB regions should have been instantiated during method lookup - let ret_ty = ty::ty_fn_ret(method.ty); - let ret_ty = ty::no_late_bound_regions(fcx.tcx(), &ret_ty).unwrap().unwrap(); + let ret_ty = method.ty.fn_ret(); + let ret_ty = fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap(); if let Some(method_call) = method_call { - fcx.inh.method_map.borrow_mut().insert(method_call, method); + fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); } // method returns &T, but the type as visible to user is T, so deref - ty::deref(ret_ty, true) + ret_ty.builtin_deref(true) } None => None, } @@ -2089,7 +1976,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // After we have fully autoderef'd, if the resulting type is [T; n], then // do a final unsized coercion to yield [T]. if let ty::TyArray(element_ty, _) = ty.sty { - let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None); + let adjusted_ty = fcx.tcx().mk_slice(element_ty); try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, adjusted_ty, autoderefs, true, lvalue_pref, idx_ty) } else { @@ -2125,7 +2012,7 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let input_ty = fcx.infcx().next_ty_var(); // First, try built-in indexing. - match (ty::index(adjusted_ty), &index_ty.sty) { + match (adjusted_ty.builtin_index(), &index_ty.sty) { (Some(ty), &ty::TyUint(ast::TyUs)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => { debug!("try_index_step: success, using built-in indexing"); // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. @@ -2186,12 +2073,12 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, tuple_arguments: TupleArgumentsFlag, expected: Expectation<'tcx>) -> ty::FnOutput<'tcx> { - if ty::type_is_error(method_fn_ty) { + if method_fn_ty.references_error() { let err_inputs = err_args(fcx.tcx(), args_no_rcvr.len()); let err_inputs = match tuple_arguments { DontTupleArguments => err_inputs, - TupleArguments => vec![ty::mk_tup(fcx.tcx(), err_inputs)], + TupleArguments => vec![fcx.tcx().mk_tup(err_inputs)], }; check_argument_types(fcx, @@ -2433,17 +2320,15 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let tcx = fcx.ccx.tcx; match lit.node { - ast::LitStr(..) => ty::mk_str_slice(tcx, tcx.mk_region(ty::ReStatic), ast::MutImmutable), + ast::LitStr(..) => tcx.mk_static_str(), ast::LitBinary(ref v) => { - ty::mk_rptr(tcx, tcx.mk_region(ty::ReStatic), ty::mt { - ty: ty::mk_vec(tcx, tcx.types.u8, Some(v.len())), - mutbl: ast::MutImmutable, - }) + tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), + tcx.mk_array(tcx.types.u8, v.len())) } ast::LitByte(_) => tcx.types.u8, ast::LitChar(_) => tcx.types.char, - ast::LitInt(_, ast::SignedIntLit(t, _)) => ty::mk_mach_int(tcx, t), - ast::LitInt(_, ast::UnsignedIntLit(t)) => ty::mk_mach_uint(tcx, t), + ast::LitInt(_, ast::SignedIntLit(t, _)) => tcx.mk_mach_int(t), + ast::LitInt(_, ast::UnsignedIntLit(t)) => tcx.mk_mach_uint(t), ast::LitInt(_, ast::UnsuffixedIntLit(_)) => { let opt_ty = expected.to_option(fcx).and_then(|ty| { match ty.sty { @@ -2455,9 +2340,9 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } }); opt_ty.unwrap_or_else( - || ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())) + || tcx.mk_int_var(fcx.infcx().next_int_var_id())) } - ast::LitFloat(_, t) => ty::mk_mach_float(tcx, t), + ast::LitFloat(_, t) => tcx.mk_mach_float(t), ast::LitFloatUnsuffixed(_) => { let opt_ty = expected.to_option(fcx).and_then(|ty| { match ty.sty { @@ -2466,7 +2351,7 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } }); opt_ty.unwrap_or_else( - || ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())) + || tcx.mk_float_var(fcx.infcx().next_float_var_id())) } ast::LitBool(_) => tcx.types.bool } @@ -2530,7 +2415,7 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> TypeAndSubsts<'tcx> { let tcx = fcx.tcx(); - let ity = ty::lookup_item_type(tcx, did); + let ity = tcx.lookup_item_type(did); let (n_tps, rps, raw_ty) = (ity.generics.types.len(subst::TypeSpace), ity.generics.regions.get_slice(subst::TypeSpace), @@ -2607,7 +2492,7 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Invariant: /// If an expression has any sub-expressions that result in a type error, -/// inspecting that expression's type with `ty::type_is_error` will return +/// inspecting that expression's type with `ty.references_error()` will return /// true. Likewise, if an expression is known to diverge, inspecting its /// type with `ty::type_is_bot` will return true (n.b.: since Rust is /// strict, _|_ can appear in the type of an expression that does not, @@ -2652,7 +2537,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, Ok(method) => { let method_ty = method.ty; let method_call = MethodCall::expr(expr.id); - fcx.inh.method_map.borrow_mut().insert(method_call, method); + fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); method_ty } Err(error) => { @@ -2705,12 +2590,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, infer::IfExpressionWithNoElse(sp), false, then_ty, - ty::mk_nil(fcx.tcx())) + fcx.tcx().mk_nil()) } }; let cond_ty = fcx.expr_ty(cond_expr); - let if_ty = if ty::type_is_error(cond_ty) { + let if_ty = if cond_ty.references_error() { fcx.tcx().types.err } else { branches_ty @@ -2740,7 +2625,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, match base_t.sty { ty::TyStruct(base_id, substs) => { debug!("struct named {:?}", base_t); - let fields = ty::lookup_struct_fields(tcx, base_id); + let fields = tcx.lookup_struct_fields(base_id); fcx.lookup_field_ty(expr.span, base_id, &fields[..], field.node.name, &(*substs)) } @@ -2796,7 +2681,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let name = &ident; // only find fits with at least one matching letter let mut best_dist = name.len(); - let fields = ty::lookup_struct_fields(tcx, id); + let fields = tcx.lookup_struct_fields(id); let mut best = None; for elem in &fields { let n = elem.name.as_str(); @@ -2841,10 +2726,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, |base_t, _| { match base_t.sty { ty::TyStruct(base_id, substs) => { - tuple_like = ty::is_tuple_struct(tcx, base_id); + tuple_like = tcx.is_tuple_struct(base_id); if tuple_like { debug!("tuple struct named {:?}", base_t); - let fields = ty::lookup_struct_fields(tcx, base_id); + let fields = tcx.lookup_struct_fields(base_id); fcx.lookup_tup_field_ty(expr.span, base_id, &fields[..], idx.node, &(*substs)) } else { @@ -2917,8 +2802,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, field.ident.span, |actual| match enum_id_opt { Some(enum_id) => { - let variant_type = ty::enum_variant_with_id(tcx, - enum_id, + let variant_type = tcx.enum_variant_with_id(enum_id, class_id); format!("struct variant `{}::{}` has no field named `{}`", actual, variant_type.name.as_str(), @@ -2936,7 +2820,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let skip_fields = ast_fields.iter().map(|ref x| x.ident.node.name.as_str()); let actual_id = match enum_id_opt { Some(_) => class_id, - None => ty::ty_to_def_id(struct_ty).unwrap() + None => struct_ty.ty_to_def_id().unwrap() }; suggest_field_names(actual_id, &field.ident, tcx, skip_fields.collect()); error_happened = true; @@ -2949,8 +2833,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } Some((field_id, false)) => { expected_field_type = - ty::lookup_field_type( - tcx, class_id, field_id, substitutions); + tcx.lookup_field_type(class_id, field_id, substitutions); expected_field_type = fcx.normalize_associated_types_in( field.span, &expected_field_type); @@ -2991,8 +2874,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } if !error_happened { - fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx, - class_id, substitutions)); + fcx.write_ty(node_id, fcx.ccx.tcx.mk_struct(class_id, substitutions)); } } @@ -3011,7 +2893,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } = fcx.instantiate_type(span, class_id); // Look up and check the fields. - let class_fields = ty::lookup_struct_fields(tcx, class_id); + let class_fields = tcx.lookup_struct_fields(class_id); check_struct_or_variant_fields(fcx, struct_type, span, @@ -3022,7 +2904,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fields, base_expr.is_none(), None); - if ty::type_is_error(fcx.node_ty(id)) { + if fcx.node_ty(id).references_error() { struct_type = tcx.types.err; } @@ -3054,7 +2936,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } = fcx.instantiate_type(span, enum_id); // Look up and check the enum variant fields. - let variant_fields = ty::lookup_struct_fields(tcx, variant_id); + let variant_fields = tcx.lookup_struct_fields(variant_id); check_struct_or_variant_fields(fcx, enum_type, span, @@ -3102,7 +2984,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let def_id = definition.def_id(); let referent_ty = fcx.expr_ty(&**subexpr); if tcx.lang_items.exchange_heap() == Some(def_id) { - fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty)); + fcx.write_ty(id, tcx.mk_box(referent_ty)); checked = true } } @@ -3153,14 +3035,14 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx, &**oprnd, expected_inner, lvalue_pref); let mut oprnd_t = fcx.expr_ty(&**oprnd); - if !ty::type_is_error(oprnd_t) { + if !oprnd_t.references_error() { match unop { ast::UnUniq => { - oprnd_t = ty::mk_uniq(tcx, oprnd_t); + oprnd_t = tcx.mk_box(oprnd_t); } ast::UnDeref => { oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t); - oprnd_t = match ty::deref(oprnd_t, true) { + oprnd_t = match oprnd_t.builtin_deref(true) { Some(mt) => mt.ty, None => match try_overloaded_deref(fcx, expr.span, Some(MethodCall::expr(expr.id)), @@ -3179,8 +3061,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ast::UnNot => { oprnd_t = structurally_resolved_type(fcx, oprnd.span, oprnd_t); - if !(ty::type_is_integral(oprnd_t) || - oprnd_t.sty == ty::TyBool) { + if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) { oprnd_t = op::check_user_unop(fcx, "!", "not", tcx.lang_items.not_trait(), expr, &**oprnd, oprnd_t, unop); @@ -3189,8 +3070,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ast::UnNeg => { oprnd_t = structurally_resolved_type(fcx, oprnd.span, oprnd_t); - if !(ty::type_is_integral(oprnd_t) || - ty::type_is_fp(oprnd_t)) { + if !(oprnd_t.is_integral() || oprnd_t.is_fp()) { oprnd_t = op::check_user_unop(fcx, "-", "neg", tcx.lang_items.neg_trait(), expr, &**oprnd, oprnd_t, unop); @@ -3213,7 +3093,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let hint = expected.only_has_type(fcx).map_or(NoExpectation, |ty| { match ty.sty { ty::TyRef(_, ref mt) | ty::TyRawPtr(ref mt) => { - if ty::expr_is_lval(fcx.tcx(), &**oprnd) { + if fcx.tcx().expr_is_lval(&**oprnd) { // Lvalues may legitimately have unsized types. // For example, dereferences of a fat pointer and // the last field of a struct can be unsized. @@ -3232,7 +3112,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lvalue_pref); let tm = ty::mt { ty: fcx.expr_ty(&**oprnd), mutbl: mutbl }; - let oprnd_t = if ty::type_is_error(tm.ty) { + let oprnd_t = if tm.ty.references_error() { tcx.types.err } else { // Note: at this point, we cannot say what the best lifetime @@ -3249,7 +3129,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // value whose address was taken can actually be made to live // as long as it needs to live. let region = fcx.infcx().next_region_var(infer::AddrOfRegion(expr.span)); - ty::mk_rptr(tcx, tcx.mk_region(region), tm) + tcx.mk_ref(tcx.mk_region(region), tm) }; fcx.write_ty(id, oprnd_t); } @@ -3310,7 +3190,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, match *expr_opt { None => if let Err(_) = fcx.mk_eqty(false, infer::Misc(expr.span), - result_type, ty::mk_nil(fcx.tcx())) { + result_type, fcx.tcx().mk_nil()) { span_err!(tcx.sess, expr.span, E0069, "`return;` in a function whose return type is \ not `()`"); @@ -3341,7 +3221,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, check_expr_with_lvalue_pref(fcx, &**lhs, PreferMutLvalue); let tcx = fcx.tcx(); - if !ty::expr_is_lval(tcx, &**lhs) { + if !tcx.expr_is_lval(&**lhs) { span_err!(tcx.sess, expr.span, E0070, "illegal left-hand side expression"); } @@ -3352,7 +3232,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.require_expr_have_sized_type(&**lhs, traits::AssignmentLhsSized); - if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) { + if lhs_ty.references_error() || rhs_ty.references_error() { fcx.write_error(id); } else { fcx.write_nil(id); @@ -3370,7 +3250,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, check_block_no_value(fcx, &**body); let cond_ty = fcx.expr_ty(&**cond); let body_ty = fcx.node_ty(body.id); - if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) { + if cond_ty.references_error() || body_ty.references_error() { fcx.write_error(id); } else { @@ -3409,7 +3289,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let arg_tys = args.iter().map(|a| fcx.expr_ty(&**a)); let args_err = arg_tys.fold(false, |rest_err, a| { - rest_err || ty::type_is_error(a)}); + rest_err || a.references_error()}); if args_err { fcx.write_error(id); } @@ -3427,7 +3307,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let t_expr = fcx.expr_ty(e); // Eagerly check for some obvious errors. - if ty::type_is_error(t_expr) { + if t_expr.references_error() { fcx.write_error(id); } else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) { report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id); @@ -3465,12 +3345,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, t } }; - let typ = ty::mk_vec(tcx, typ, Some(args.len())); + let typ = tcx.mk_array(typ, args.len()); fcx.write_ty(id, typ); } ast::ExprRepeat(ref element, ref count_expr) => { check_expr_has_type(fcx, &**count_expr, tcx.types.usize); - let count = ty::eval_repeat_count(fcx.tcx(), &**count_expr); + let count = fcx.tcx().eval_repeat_count(&**count_expr); let uty = match expected { ExpectHasType(uty) => { @@ -3504,10 +3384,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ty::BoundCopy); } - if ty::type_is_error(element_ty) { + if element_ty.references_error() { fcx.write_error(id); } else { - let t = ty::mk_vec(tcx, t, Some(count)); + let t = tcx.mk_array(t, count); fcx.write_ty(id, t); } } @@ -3532,13 +3412,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.expr_ty(&**e) } }; - err_field = err_field || ty::type_is_error(t); + err_field = err_field || t.references_error(); t }).collect(); if err_field { fcx.write_error(id); } else { - let typ = ty::mk_tup(tcx, elt_ts); + let typ = tcx.mk_tup(elt_ts); fcx.write_ty(id, typ); } } @@ -3563,7 +3443,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }, def => { // Verify that this was actually a struct. - let typ = ty::lookup_item_type(fcx.ccx.tcx, def.def_id()); + let typ = fcx.ccx.tcx.lookup_item_type(def.def_id()); match typ.ty.sty { ty::TyStruct(struct_did, _) => { check_struct_constructor(fcx, @@ -3592,7 +3472,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // the resulting structure type. This is needed to handle type // parameters correctly. let actual_structure_type = fcx.expr_ty(&*expr); - if !ty::type_is_error(actual_structure_type) { + if !actual_structure_type.references_error() { let type_and_substs = fcx.instantiate_struct_literal_ty(struct_id, path); match fcx.mk_subty(false, infer::Misc(path.span), @@ -3610,7 +3490,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, .ty_to_string( actual_structure_type), type_error); - ty::note_and_explain_type_err(tcx, &type_error, path.span); + tcx.note_and_explain_type_err(&type_error, path.span); } } } @@ -3630,9 +3510,9 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let base_t = fcx.expr_ty(&**base); let idx_t = fcx.expr_ty(&**idx); - if ty::type_is_error(base_t) { + if base_t.references_error() { fcx.write_ty(id, base_t); - } else if ty::type_is_error(idx_t) { + } else if idx_t.references_error() { fcx.write_ty(id, idx_t); } else { let base_t = structurally_resolved_type(fcx, expr.span, base_t); @@ -3671,8 +3551,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, (Some(ty), None) | (None, Some(ty)) => { Some(ty) } - (Some(t_start), Some(t_end)) if (ty::type_is_error(t_start) || - ty::type_is_error(t_end)) => { + (Some(t_start), Some(t_end)) if (t_start.references_error() || + t_end.references_error()) => { Some(fcx.tcx().types.err) } (Some(t_start), Some(t_end)) => { @@ -3690,7 +3570,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // some bounds, then we'll need to check `t_start` against them here. let range_type = match idx_type { - Some(idx_type) if ty::type_is_error(idx_type) => { + Some(idx_type) if idx_type.references_error() => { fcx.tcx().types.err } Some(idx_type) => { @@ -3705,7 +3585,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }; if let Some(did) = did { - let predicates = ty::lookup_predicates(tcx, did); + let predicates = tcx.lookup_predicates(did); let substs = Substs::new_type(vec![idx_type], vec![]); let bounds = fcx.instantiate_bounds(expr.span, &substs, &predicates); fcx.add_obligations_for_parameters( @@ -3714,7 +3594,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, traits::ItemObligation(did)), &bounds); - ty::mk_struct(tcx, did, tcx.mk_substs(substs)) + tcx.mk_struct(did, tcx.mk_substs(substs)) } else { span_err!(tcx.sess, expr.span, E0236, "no lang item for range syntax"); fcx.tcx().types.err @@ -3724,7 +3604,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Neither start nor end => RangeFull if let Some(did) = tcx.lang_items.range_full_struct() { let substs = Substs::new_type(vec![], vec![]); - ty::mk_struct(tcx, did, tcx.mk_substs(substs)) + tcx.mk_struct(did, tcx.mk_substs(substs)) } else { span_err!(tcx.sess, expr.span, E0237, "no lang item for range syntax"); fcx.tcx().types.err @@ -3765,7 +3645,7 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, node_id: ast::NodeId) -> bool { match def { def::DefAssociatedConst(..) => { - if ty::type_has_params(ty) || ty::type_has_self(ty) { + if ty.has_param_types() || ty.has_self_ty() { span_err!(fcx.sess(), span, E0329, "Associated consts cannot depend \ on type parameters or Self."); @@ -3933,7 +3813,7 @@ pub fn check_decl_local<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, local: &'tcx ast::Local) if let Some(ref init) = local.init { check_decl_initializer(fcx, local, &**init); let init_ty = fcx.expr_ty(&**init); - if ty::type_is_error(init_ty) { + if init_ty.references_error() { fcx.write_ty(local.id, init_ty); } } @@ -3944,7 +3824,7 @@ pub fn check_decl_local<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, local: &'tcx ast::Local) }; _match::check_pat(&pcx, &*local.pat, t); let pat_ty = fcx.node_ty(local.pat.id); - if ty::type_is_error(pat_ty) { + if pat_ty.references_error() { fcx.write_ty(local.id, pat_ty); } } @@ -3961,7 +3841,7 @@ pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx ast::Stmt) { check_decl_local(fcx, &**l); let l_t = fcx.node_ty(l.id); saw_bot = saw_bot || fcx.infcx().type_var_diverges(l_t); - saw_err = saw_err || ty::type_is_error(l_t); + saw_err = saw_err || l_t.references_error(); } ast::DeclItem(_) => {/* ignore for now */ } } @@ -3969,17 +3849,17 @@ pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx ast::Stmt) { ast::StmtExpr(ref expr, id) => { node_id = id; // Check with expected type of () - check_expr_has_type(fcx, &**expr, ty::mk_nil(fcx.tcx())); + check_expr_has_type(fcx, &**expr, fcx.tcx().mk_nil()); let expr_ty = fcx.expr_ty(&**expr); saw_bot = saw_bot || fcx.infcx().type_var_diverges(expr_ty); - saw_err = saw_err || ty::type_is_error(expr_ty); + saw_err = saw_err || expr_ty.references_error(); } ast::StmtSemi(ref expr, id) => { node_id = id; check_expr(fcx, &**expr); let expr_ty = fcx.expr_ty(&**expr); saw_bot |= fcx.infcx().type_var_diverges(expr_ty); - saw_err |= ty::type_is_error(expr_ty); + saw_err |= expr_ty.references_error(); } ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro") } @@ -3995,12 +3875,12 @@ pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx ast::Stmt) { } pub fn check_block_no_value<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, blk: &'tcx ast::Block) { - check_block_with_expected(fcx, blk, ExpectHasType(ty::mk_nil(fcx.tcx()))); + check_block_with_expected(fcx, blk, ExpectHasType(fcx.tcx().mk_nil())); let blkty = fcx.node_ty(blk.id); - if ty::type_is_error(blkty) { + if blkty.references_error() { fcx.write_error(blk.id); } else { - let nilty = ty::mk_nil(fcx.tcx()); + let nilty = fcx.tcx().mk_nil(); demand::suptype(fcx, blk.span, nilty, blkty); } } @@ -4041,7 +3921,7 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, warned = true; } any_diverges = any_diverges || fcx.infcx().type_var_diverges(s_ty); - any_err = any_err || ty::type_is_error(s_ty); + any_err = any_err || s_ty.references_error(); } match blk.expr { None => if any_err { @@ -4091,7 +3971,8 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>, expr: &'tcx ast::Expr, expected_type: Ty<'tcx>) { - let inh = static_inherited_fields(ccx); + let tables = RefCell::new(ty::Tables::empty()); + let inh = static_inherited_fields(ccx, &tables); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(expected_type), expr.id); check_const_with_ty(&fcx, expr.span, expr, expected_type); } @@ -4100,10 +3981,11 @@ fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, sp: Span, e: &'tcx ast::Expr, id: ast::NodeId) { - let inh = static_inherited_fields(ccx); - let rty = ty::node_id_to_type(ccx.tcx, id); + let tables = RefCell::new(ty::Tables::empty()); + let inh = static_inherited_fields(ccx, &tables); + let rty = ccx.tcx.node_id_to_type(id); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id); - let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).unwrap().ty; + let declty = fcx.ccx.tcx.lookup_item_type(local_def(id)).ty; check_const_with_ty(&fcx, sp, e, declty); } @@ -4134,14 +4016,14 @@ pub fn check_representable(tcx: &ty::ctxt, sp: Span, item_id: ast::NodeId, designation: &str) -> bool { - let rty = ty::node_id_to_type(tcx, item_id); + let rty = tcx.node_id_to_type(item_id); // Check that it is possible to represent this type. This call identifies // (1) types that contain themselves and (2) types that contain a different // recursive type. It is only necessary to throw an error on those that // contain themselves. For case 2, there must be an inner type that will be // caught by case 1. - match ty::is_type_representable(tcx, sp, rty) { + match rty.is_representable(tcx, sp) { ty::SelfRecursive => { span_err!(tcx.sess, sp, E0072, "illegal recursive {} type; \ @@ -4169,8 +4051,8 @@ pub fn check_instantiable(tcx: &ty::ctxt, sp: Span, item_id: ast::NodeId) -> bool { - let item_ty = ty::node_id_to_type(tcx, item_id); - if !ty::is_instantiable(tcx, item_ty) { + let item_ty = tcx.node_id_to_type(item_id); + if !item_ty.is_instantiable(tcx) { span_err!(tcx.sess, sp, E0073, "this type cannot be instantiated without an \ instance of itself"); @@ -4183,25 +4065,25 @@ pub fn check_instantiable(tcx: &ty::ctxt, } pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { - let t = ty::node_id_to_type(tcx, id); - if ty::type_needs_subst(t) { + let t = tcx.node_id_to_type(id); + if t.needs_subst() { span_err!(tcx.sess, sp, E0074, "SIMD vector cannot be generic"); return; } match t.sty { ty::TyStruct(did, substs) => { - let fields = ty::lookup_struct_fields(tcx, did); + let fields = tcx.lookup_struct_fields(did); if fields.is_empty() { span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty"); return; } - let e = ty::lookup_field_type(tcx, did, fields[0].id, substs); + let e = tcx.lookup_field_type(did, fields[0].id, substs); if !fields.iter().all( - |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) { + |f| tcx.lookup_field_type(did, f.id, substs) == e) { span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous"); return; } - if !ty::type_is_machine(e) { + if !e.is_machine() { span_err!(tcx.sess, sp, E0077, "SIMD vector element type should be machine type"); return; @@ -4249,13 +4131,14 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, hint: attr::ReprAttr) { #![allow(trivial_numeric_casts)] - let rty = ty::node_id_to_type(ccx.tcx, id); + let rty = ccx.tcx.node_id_to_type(id); let mut disr_vals: Vec = Vec::new(); - let inh = static_inherited_fields(ccx); + let tables = RefCell::new(ty::Tables::empty()); + let inh = static_inherited_fields(ccx, &tables); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id); - let (_, repr_type_ty) = ty::enum_repr_type(ccx.tcx, Some(&hint)); + let (_, repr_type_ty) = ccx.tcx.enum_repr_type(Some(&hint)); for v in vs { if let Some(ref e) = v.node.disr_expr { check_const_with_ty(&fcx, e.span, e, repr_type_ty); @@ -4266,7 +4149,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, // ty::enum_variants guards against discriminant overflows, so // we need not check for that. - let variants = ty::enum_variants(ccx.tcx, def_id); + let variants = ccx.tcx.enum_variants(def_id); for (v, variant) in vs.iter().zip(variants.iter()) { let current_disr_val = variant.disr_val; @@ -4300,7 +4183,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } - let hint = *ty::lookup_repr_hints(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id }) + let hint = *ccx.tcx.lookup_repr_hints(ast::DefId { krate: ast::LOCAL_CRATE, node: id }) .get(0).unwrap_or(&attr::ReprAny); if hint != attr::ReprAny && vs.len() <= 1 { @@ -4338,7 +4221,7 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefFn(id, _) | def::DefMethod(id, _) | def::DefStatic(id, _) | def::DefVariant(_, id, _) | def::DefStruct(id) | def::DefConst(id) | def::DefAssociatedConst(id, _) => { - (ty::lookup_item_type(fcx.tcx(), id), ty::lookup_predicates(fcx.tcx(), id)) + (fcx.tcx().lookup_item_type(id), fcx.tcx().lookup_predicates(id)) } def::DefTrait(_) | def::DefTy(..) | @@ -4600,7 +4483,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // is inherent, there is no `Self` parameter, instead, the impl needs // type parameters, which we can infer by unifying the provided `Self` // with the substituted impl type. - let impl_scheme = ty::lookup_item_type(fcx.tcx(), impl_def_id); + let impl_scheme = fcx.tcx().lookup_item_type(impl_def_id); assert_eq!(substs.types.len(subst::TypeSpace), impl_scheme.generics.types.len(subst::TypeSpace)); assert_eq!(substs.regions().len(subst::TypeSpace), @@ -4736,8 +4619,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let input_tys: Vec = data.inputs.iter().map(|ty| fcx.to_ty(&**ty)).collect(); - let tuple_ty = - ty::mk_tup(fcx.tcx(), input_tys); + let tuple_ty = fcx.tcx().mk_tup(input_tys); if type_count >= 1 { substs.types.push(space, tuple_ty); @@ -4747,7 +4629,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, data.output.as_ref().map(|ty| fcx.to_ty(&**ty)); let output_ty = - output_ty.unwrap_or(ty::mk_nil(fcx.tcx())); + output_ty.unwrap_or(fcx.tcx().mk_nil()); if type_count >= 2 { substs.types.push(space, output_ty); @@ -4870,11 +4752,11 @@ fn structurally_resolve_type_or_else<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, { let mut ty = fcx.resolve_type_vars_if_possible(ty); - if ty::type_is_ty_var(ty) { + if ty.is_ty_var() { let alternative = f(); // If not, error. - if ty::type_is_ty_var(alternative) || ty::type_is_error(alternative) { + if alternative.is_ty_var() || alternative.references_error() { fcx.type_error_message(sp, |_actual| { "the type of this value must be known in this context".to_string() }, ty, None); @@ -4933,15 +4815,12 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, if tps.is_empty() { return; } let mut tps_used: Vec<_> = repeat(false).take(tps.len()).collect(); - ty::walk_ty(ty, |t| { - match t.sty { - ty::TyParam(ParamTy {idx, ..}) => { - debug!("Found use of ty param num {}", idx); - tps_used[idx as usize] = true; - } - _ => () - } - }); + for leaf_ty in ty.walk() { + if let ty::TyParam(ParamTy {idx, ..}) = leaf_ty.sty { + debug!("Found use of ty param num {}", idx); + tps_used[idx as usize] = true; + } + } for (i, b) in tps_used.iter().enumerate() { if !*b { @@ -4957,7 +4836,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> { let name = token::intern(&format!("P{}", n)); - ty::mk_param(ccx.tcx, subst::FnSpace, n, name) + ccx.tcx.mk_param(subst::FnSpace, n, name) } let tcx = ccx.tcx; @@ -4968,22 +4847,22 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { //We only care about the operation here let (n_tps, inputs, output) = match split[1] { - "cxchg" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), + "cxchg" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0), param(ccx, 0)), param(ccx, 0)), - "load" => (1, vec!(ty::mk_imm_ptr(tcx, param(ccx, 0))), + "load" => (1, vec!(tcx.mk_imm_ptr(param(ccx, 0))), param(ccx, 0)), - "store" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)), - ty::mk_nil(tcx)), + "store" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)), + tcx.mk_nil()), "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax" | "umin" => { - (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)), + (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)), param(ccx, 0)) } "fence" | "singlethreadfence" => { - (0, Vec::new(), ty::mk_nil(tcx)) + (0, Vec::new(), tcx.mk_nil()) } op => { span_err!(tcx.sess, it.span, E0092, @@ -4996,50 +4875,47 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { (0, Vec::new(), ty::FnDiverging) } else { let (n_tps, inputs, output) = match &name[..] { - "breakpoint" => (0, Vec::new(), ty::mk_nil(tcx)), + "breakpoint" => (0, Vec::new(), tcx.mk_nil()), "size_of" | "pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.usize), "size_of_val" | "min_align_of_val" => { (1, vec![ - ty::mk_imm_rptr(tcx, - tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), + tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(0))), param(ccx, 0)) ], ccx.tcx.types.usize) } "init" | "init_dropped" => (1, Vec::new(), param(ccx, 0)), "uninit" => (1, Vec::new(), param(ccx, 0)), - "forget" => (1, vec!( param(ccx, 0) ), ty::mk_nil(tcx)), + "forget" => (1, vec!( param(ccx, 0) ), tcx.mk_nil()), "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)), "move_val_init" => { (1, vec!( - ty::mk_mut_rptr(tcx, - tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), + tcx.mk_mut_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(0))), param(ccx, 0)), param(ccx, 0) ), - ty::mk_nil(tcx)) + tcx.mk_nil()) } "drop_in_place" => { - (1, vec![ty::mk_mut_ptr(tcx, param(ccx, 0))], ty::mk_nil(tcx)) + (1, vec![tcx.mk_mut_ptr(param(ccx, 0))], tcx.mk_nil()) } "needs_drop" => (1, Vec::new(), ccx.tcx.types.bool), - "type_name" => (1, Vec::new(), ty::mk_str_slice(tcx, tcx.mk_region(ty::ReStatic), - ast::MutImmutable)), + "type_name" => (1, Vec::new(), tcx.mk_static_str()), "type_id" => (1, Vec::new(), ccx.tcx.types.u64), "offset" | "arith_offset" => { (1, vec!( - ty::mk_ptr(tcx, ty::mt { + tcx.mk_ptr(ty::mt { ty: param(ccx, 0), mutbl: ast::MutImmutable }), ccx.tcx.types.isize ), - ty::mk_ptr(tcx, ty::mt { + tcx.mk_ptr(ty::mt { ty: param(ccx, 0), mutbl: ast::MutImmutable })) @@ -5047,44 +4923,44 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "copy" | "copy_nonoverlapping" => { (1, vec!( - ty::mk_ptr(tcx, ty::mt { + tcx.mk_ptr(ty::mt { ty: param(ccx, 0), mutbl: ast::MutImmutable }), - ty::mk_ptr(tcx, ty::mt { + tcx.mk_ptr(ty::mt { ty: param(ccx, 0), mutbl: ast::MutMutable }), tcx.types.usize, ), - ty::mk_nil(tcx)) + tcx.mk_nil()) } "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => { (1, vec!( - ty::mk_ptr(tcx, ty::mt { + tcx.mk_ptr(ty::mt { ty: param(ccx, 0), mutbl: ast::MutMutable }), - ty::mk_ptr(tcx, ty::mt { + tcx.mk_ptr(ty::mt { ty: param(ccx, 0), mutbl: ast::MutImmutable }), tcx.types.usize, ), - ty::mk_nil(tcx)) + tcx.mk_nil()) } "write_bytes" | "volatile_set_memory" => { (1, vec!( - ty::mk_ptr(tcx, ty::mt { + tcx.mk_ptr(ty::mt { ty: param(ccx, 0), mutbl: ast::MutMutable }), tcx.types.u8, tcx.types.usize, ), - ty::mk_nil(tcx)) + tcx.mk_nil()) } "sqrtf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), "sqrtf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), @@ -5165,41 +5041,41 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "bswap64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), "volatile_load" => - (1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)), + (1, vec!( tcx.mk_imm_ptr(param(ccx, 0)) ), param(ccx, 0)), "volatile_store" => - (1, vec!( ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ), ty::mk_nil(tcx)), + (1, vec!( tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) ), tcx.mk_nil()), "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" => (0, vec!(tcx.types.i8, tcx.types.i8), - ty::mk_tup(tcx, vec!(tcx.types.i8, tcx.types.bool))), + tcx.mk_tup(vec!(tcx.types.i8, tcx.types.bool))), "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" => (0, vec!(tcx.types.i16, tcx.types.i16), - ty::mk_tup(tcx, vec!(tcx.types.i16, tcx.types.bool))), + tcx.mk_tup(vec!(tcx.types.i16, tcx.types.bool))), "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" => (0, vec!(tcx.types.i32, tcx.types.i32), - ty::mk_tup(tcx, vec!(tcx.types.i32, tcx.types.bool))), + tcx.mk_tup(vec!(tcx.types.i32, tcx.types.bool))), "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" => (0, vec!(tcx.types.i64, tcx.types.i64), - ty::mk_tup(tcx, vec!(tcx.types.i64, tcx.types.bool))), + tcx.mk_tup(vec!(tcx.types.i64, tcx.types.bool))), "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" => (0, vec!(tcx.types.u8, tcx.types.u8), - ty::mk_tup(tcx, vec!(tcx.types.u8, tcx.types.bool))), + tcx.mk_tup(vec!(tcx.types.u8, tcx.types.bool))), "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" => (0, vec!(tcx.types.u16, tcx.types.u16), - ty::mk_tup(tcx, vec!(tcx.types.u16, tcx.types.bool))), + tcx.mk_tup(vec!(tcx.types.u16, tcx.types.bool))), "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=> (0, vec!(tcx.types.u32, tcx.types.u32), - ty::mk_tup(tcx, vec!(tcx.types.u32, tcx.types.bool))), + tcx.mk_tup(vec!(tcx.types.u32, tcx.types.bool))), "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" => (0, vec!(tcx.types.u64, tcx.types.u64), - ty::mk_tup(tcx, vec!(tcx.types.u64, tcx.types.bool))), + tcx.mk_tup(vec!(tcx.types.u64, tcx.types.bool))), "unchecked_udiv" | "unchecked_sdiv" | "unchecked_urem" | "unchecked_srem" => (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), @@ -5207,13 +5083,12 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "overflowing_add" | "overflowing_sub" | "overflowing_mul" => (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), - "return_address" => (0, vec![], ty::mk_imm_ptr(tcx, tcx.types.u8)), + "return_address" => (0, vec![], tcx.mk_imm_ptr(tcx.types.u8)), - "assume" => (0, vec![tcx.types.bool], ty::mk_nil(tcx)), + "assume" => (0, vec![tcx.types.bool], tcx.mk_nil()), "discriminant_value" => (1, vec![ - ty::mk_imm_rptr(tcx, - tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), + tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(0))), param(ccx, 0))], tcx.types.u64), @@ -5225,7 +5100,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { }; (n_tps, inputs, ty::FnConverging(output)) }; - let fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(ty::BareFnTy { + let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { unsafety: ast::Unsafety::Unsafe, abi: abi::RustIntrinsic, sig: ty::Binder(FnSig { @@ -5234,7 +5109,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { variadic: false, }), })); - let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); + let i_ty = ccx.tcx.lookup_item_type(local_def(it.id)); let i_n_tps = i_ty.generics.types.len(subst::FnSpace); if i_n_tps != n_tps { span_err!(tcx.sess, it.span, E0094, diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index a5e4e0fab5963..c419a986f95b1 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -21,7 +21,7 @@ use super::{ structurally_resolved_type, }; use middle::traits; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags}; use syntax::ast; use syntax::ast_util; use syntax::parse::token; @@ -46,7 +46,7 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, fcx.write_nil(expr.id); } else { // error types are considered "builtin" - assert!(!ty::type_is_error(lhs_ty) || !ty::type_is_error(rhs_ty)); + assert!(!lhs_ty.references_error() || !rhs_ty.references_error()); span_err!(tcx.sess, lhs_expr.span, E0368, "binary assignment operation `{}=` cannot be applied to types `{}` and `{}`", ast_util::binop_to_string(op.node), @@ -56,7 +56,7 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, } let tcx = fcx.tcx(); - if !ty::expr_is_lval(tcx, lhs_expr) { + if !tcx.expr_is_lval(lhs_expr) { span_err!(tcx.sess, lhs_expr.span, E0067, "illegal left-hand side expression"); } @@ -86,7 +86,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // traits, because their return type is not bool. Perhaps this // should change, but for now if LHS is SIMD we go down a // different path that bypassess all traits. - if ty::type_is_simd(fcx.tcx(), lhs_ty) { + if lhs_ty.is_simd(fcx.tcx()) { check_expr_coercable_to_type(fcx, rhs_expr, lhs_ty); let rhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); let return_ty = enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); @@ -97,9 +97,9 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { // && and || are a simple case. - demand::suptype(fcx, lhs_expr.span, ty::mk_bool(tcx), lhs_ty); - check_expr_coercable_to_type(fcx, rhs_expr, ty::mk_bool(tcx)); - fcx.write_ty(expr.id, ty::mk_bool(tcx)); + demand::suptype(fcx, lhs_expr.span, tcx.mk_bool(), lhs_ty); + check_expr_coercable_to_type(fcx, rhs_expr, tcx.mk_bool()); + fcx.write_ty(expr.id, tcx.mk_bool()); } _ => { // Otherwise, we always treat operators as if they are @@ -122,8 +122,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // can't pin this down to a specific impl. let rhs_ty = fcx.resolve_type_vars_if_possible(rhs_ty); if - !ty::type_is_ty_var(lhs_ty) && - !ty::type_is_ty_var(rhs_ty) && + !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(fcx.tcx(), lhs_ty, rhs_ty, op) { let builtin_return_ty = @@ -149,15 +148,15 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let tcx = fcx.tcx(); match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { - demand::suptype(fcx, lhs_expr.span, ty::mk_bool(tcx), lhs_ty); - demand::suptype(fcx, rhs_expr.span, ty::mk_bool(tcx), rhs_ty); - ty::mk_bool(tcx) + demand::suptype(fcx, lhs_expr.span, tcx.mk_bool(), lhs_ty); + demand::suptype(fcx, rhs_expr.span, tcx.mk_bool(), rhs_ty); + tcx.mk_bool() } BinOpCategory::Shift => { // For integers, the shift amount can be of any integral // type. For simd, the type must match exactly. - if ty::type_is_simd(tcx, lhs_ty) { + if lhs_ty.is_simd(tcx) { demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty); } @@ -177,12 +176,12 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty); // if this is simd, result is same as lhs, else bool - if ty::type_is_simd(tcx, lhs_ty) { - let unit_ty = ty::simd_type(tcx, lhs_ty); + if lhs_ty.is_simd(tcx) { + let unit_ty = lhs_ty.simd_type(tcx); debug!("enforce_builtin_binop_types: lhs_ty={:?} unit_ty={:?}", lhs_ty, unit_ty); - if !ty::type_is_integral(unit_ty) { + if !unit_ty.is_integral() { tcx.sess.span_err( lhs_expr.span, &format!("binary comparison operation `{}` not supported \ @@ -194,7 +193,7 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, lhs_ty } } else { - ty::mk_bool(tcx) + tcx.mk_bool() } } } @@ -228,7 +227,7 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Ok(return_ty) => return_ty, Err(()) => { // error types are considered "builtin" - if !ty::type_is_error(lhs_ty) { + if !lhs_ty.references_error() { span_err!(fcx.tcx().sess, lhs_expr.span, E0369, "binary operation `{}` cannot be applied to type `{}`", ast_util::binop_to_string(op.node), @@ -331,12 +330,12 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // HACK(eddyb) Fully qualified path to work around a resolve bug. let method_call = ::middle::ty::MethodCall::expr(expr.id); - fcx.inh.method_map.borrow_mut().insert(method_call, method); + fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); // extract return type for method; all late bound regions // should have been instantiated by now - let ret_ty = ty::ty_fn_ret(method_ty); - Ok(ty::no_late_bound_regions(fcx.tcx(), &ret_ty).unwrap().unwrap()) + let ret_ty = method_ty.fn_ret(); + Ok(fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap()) } None => { Err(()) @@ -428,31 +427,30 @@ fn is_builtin_binop<'tcx>(cx: &ty::ctxt<'tcx>, } BinOpCategory::Shift => { - ty::type_is_error(lhs) || ty::type_is_error(rhs) || - ty::type_is_integral(lhs) && ty::type_is_integral(rhs) || - ty::type_is_simd(cx, lhs) && ty::type_is_simd(cx, rhs) + lhs.references_error() || rhs.references_error() || + lhs.is_integral() && rhs.is_integral() || + lhs.is_simd(cx) && rhs.is_simd(cx) } BinOpCategory::Math => { - ty::type_is_error(lhs) || ty::type_is_error(rhs) || - ty::type_is_integral(lhs) && ty::type_is_integral(rhs) || - ty::type_is_floating_point(lhs) && ty::type_is_floating_point(rhs) || - ty::type_is_simd(cx, lhs) && ty::type_is_simd(cx, rhs) + lhs.references_error() || rhs.references_error() || + lhs.is_integral() && rhs.is_integral() || + lhs.is_floating_point() && rhs.is_floating_point() || + lhs.is_simd(cx) && rhs.is_simd(cx) } BinOpCategory::Bitwise => { - ty::type_is_error(lhs) || ty::type_is_error(rhs) || - ty::type_is_integral(lhs) && ty::type_is_integral(rhs) || - ty::type_is_floating_point(lhs) && ty::type_is_floating_point(rhs) || - ty::type_is_simd(cx, lhs) && ty::type_is_simd(cx, rhs) || - ty::type_is_bool(lhs) && ty::type_is_bool(rhs) + lhs.references_error() || rhs.references_error() || + lhs.is_integral() && rhs.is_integral() || + lhs.is_floating_point() && rhs.is_floating_point() || + lhs.is_simd(cx) && rhs.is_simd(cx) || + lhs.is_bool() && rhs.is_bool() } BinOpCategory::Comparison => { - ty::type_is_error(lhs) || ty::type_is_error(rhs) || - ty::type_is_scalar(lhs) && ty::type_is_scalar(rhs) || - ty::type_is_simd(cx, lhs) && ty::type_is_simd(cx, rhs) + lhs.references_error() || rhs.references_error() || + lhs.is_scalar() && rhs.is_scalar() || + lhs.is_simd(cx) && rhs.is_simd(cx) } } } - diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index a96e7864fe679..bb3c9f9fb5425 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -91,7 +91,7 @@ use middle::mem_categorization as mc; use middle::region::CodeExtent; use middle::subst::Substs; use middle::traits; -use middle::ty::{self, ClosureTyper, ReScope, Ty, MethodCall}; +use middle::ty::{self, ReScope, Ty, MethodCall, HasTypeFlags}; use middle::infer::{self, GenericKind}; use middle::pat_util; @@ -124,7 +124,8 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) { let mut rcx = Rcx::new(fcx, RepeatingScope(item.id), item.id, Subject(item.id)); let tcx = fcx.tcx(); - rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds); + rcx.free_region_map + .relate_free_regions_from_predicates(tcx, &fcx.infcx().parameter_environment.caller_bounds); rcx.visit_region_obligations(item.id); rcx.resolve_regions_and_report_errors(); } @@ -143,7 +144,8 @@ pub fn regionck_fn(fcx: &FnCtxt, } let tcx = fcx.tcx(); - rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds); + rcx.free_region_map + .relate_free_regions_from_predicates(tcx, &fcx.infcx().parameter_environment.caller_bounds); rcx.resolve_regions_and_report_errors(); @@ -254,7 +256,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { } fn resolve_method_type(&self, method_call: MethodCall) -> Option> { - let method_ty = self.fcx.inh.method_map.borrow() + let method_ty = self.fcx.inh.tables.borrow().method_map .get(&method_call).map(|method| method.ty); method_ty.map(|method_ty| self.resolve_type(method_ty)) } @@ -262,13 +264,13 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { /// Try to resolve the type for the given node. pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> Ty<'tcx> { let ty_unadjusted = self.resolve_node_type(expr.id); - if ty::type_is_error(ty_unadjusted) { + if ty_unadjusted.references_error() { ty_unadjusted } else { - let tcx = self.fcx.tcx(); - ty::adjust_ty(tcx, expr.span, expr.id, ty_unadjusted, - self.fcx.inh.adjustments.borrow().get(&expr.id), - |method_call| self.resolve_method_type(method_call)) + ty_unadjusted.adjust( + self.fcx.tcx(), expr.span, expr.id, + self.fcx.inh.tables.borrow().adjustments.get(&expr.id), + |method_call| self.resolve_method_type(method_call)) } } @@ -315,9 +317,13 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { // Make a copy of the region obligations vec because we'll need // to be able to borrow the fulfillment-cx below when projecting. let region_obligations = - self.fcx.inh.fulfillment_cx.borrow() - .region_obligations(node_id) - .to_vec(); + self.fcx + .inh + .infcx + .fulfillment_cx + .borrow() + .region_obligations(node_id) + .to_vec(); for r_o in ®ion_obligations { debug!("visit_region_obligations: r_o={:?}", @@ -329,7 +335,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { // Processing the region obligations should not cause the list to grow further: assert_eq!(region_obligations.len(), - self.fcx.inh.fulfillment_cx.borrow().region_obligations(node_id).len()); + self.fcx.inh.infcx.fulfillment_cx.borrow().region_obligations(node_id).len()); } /// This method populates the region map's `free_region_map`. It walks over the transformed @@ -353,7 +359,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { debug!("relate_free_regions(t={:?})", ty); let body_scope = CodeExtent::from_node_id(body_id); let body_scope = ty::ReScope(body_scope); - let implications = implicator::implications(self.fcx.infcx(), self.fcx, body_id, + let implications = implicator::implications(self.fcx.infcx(), body_id, ty, body_scope, span); // Record any relations between free regions that we observe into the free-region-map. @@ -511,12 +517,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { expr_ty, ty::ReScope(CodeExtent::from_node_id(expr.id))); let method_call = MethodCall::expr(expr.id); - let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call); + let has_method_map = rcx.fcx.inh.tables.borrow().method_map.contains_key(&method_call); // Check any autoderefs or autorefs that appear. - if let Some(adjustment) = rcx.fcx.inh.adjustments.borrow().get(&expr.id) { + let adjustment = rcx.fcx.inh.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone()); + if let Some(adjustment) = adjustment { debug!("adjustment={:?}", adjustment); - match *adjustment { + match adjustment { ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => { let expr_ty = rcx.resolve_node_type(expr.id); constrain_autoderefs(rcx, expr, autoderefs, expr_ty); @@ -548,7 +555,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // If necessary, constrain destructors in the unadjusted form of this // expression. let cmt_result = { - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); mc.cat_expr_unadjusted(expr) }; match cmt_result { @@ -567,7 +574,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // If necessary, constrain destructors in this expression. This will be // the adjusted form if there is an adjustment. let cmt_result = { - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); mc.cat_expr(expr) }; match cmt_result { @@ -657,12 +664,12 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { ast::ExprUnary(ast::UnDeref, ref base) => { // For *a, the lifetime of a must enclose the deref let method_call = MethodCall::expr(expr.id); - let base_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) { + let base_ty = match rcx.fcx.inh.tables.borrow().method_map.get(&method_call) { Some(method) => { constrain_call(rcx, expr, Some(&**base), None::.iter(), true); let fn_ret = // late-bound regions in overloaded method calls are instantiated - ty::no_late_bound_regions(rcx.tcx(), &ty::ty_fn_ret(method.ty)).unwrap(); + rcx.tcx().no_late_bound_regions(&method.ty.fn_ret()).unwrap(); fn_ret.unwrap() } None => rcx.resolve_node_type(base.id) @@ -884,16 +891,18 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, let method_call = MethodCall::autoderef(deref_expr.id, i as u32); debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs); - derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) { + let method = rcx.fcx.inh.tables.borrow().method_map.get(&method_call).map(|m| m.clone()); + + derefd_ty = match method { Some(method) => { debug!("constrain_autoderefs: #{} is overloaded, method={:?}", i, method); // Treat overloaded autoderefs as if an AutoRef adjustment // was applied on the base type, as that is always the case. - let fn_sig = ty::ty_fn_sig(method.ty); + let fn_sig = method.ty.fn_sig(); let fn_sig = // late-bound regions should have been instantiated - ty::no_late_bound_regions(rcx.tcx(), fn_sig).unwrap(); + rcx.tcx().no_late_bound_regions(fn_sig).unwrap(); let self_ty = fn_sig.inputs[0]; let (m, r) = match self_ty.sty { ty::TyRef(r, ref m) => (m.mutbl, r), @@ -909,7 +918,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, r, m); { - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); debug!("constrain_autoderefs: self_cmt={:?}", self_cmt); @@ -937,7 +946,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, r_deref_expr, *r_ptr); } - match ty::deref(derefd_ty, true) { + match derefd_ty.builtin_deref(true) { Some(mt) => derefd_ty = mt.ty, /* if this type can't be dereferenced, then there's already an error in the session saying so. Just bail out for now */ @@ -1017,9 +1026,9 @@ fn type_of_node_must_outlive<'a, 'tcx>( // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. let ty0 = rcx.resolve_node_type(id); - let ty = ty::adjust_ty(tcx, origin.span(), id, ty0, - rcx.fcx.inh.adjustments.borrow().get(&id), - |method_call| rcx.resolve_method_type(method_call)); + let ty = ty0.adjust(tcx, origin.span(), id, + rcx.fcx.inh.tables.borrow().adjustments.get(&id), + |method_call| rcx.resolve_method_type(method_call)); debug!("constrain_regions_in_type_of_node(\ ty={}, ty0={}, id={}, minimum_lifetime={:?})", ty, ty0, @@ -1034,7 +1043,7 @@ fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr, debug!("link_addr_of(expr={:?}, base={:?})", expr, base); let cmt = { - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); ignore_err!(mc.cat_expr(base)) }; @@ -1052,7 +1061,7 @@ fn link_local(rcx: &Rcx, local: &ast::Local) { None => { return; } Some(ref expr) => &**expr, }; - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); let discr_cmt = ignore_err!(mc.cat_expr(init_expr)); link_pattern(rcx, mc, discr_cmt, &*local.pat); } @@ -1062,7 +1071,7 @@ fn link_local(rcx: &Rcx, local: &ast::Local) { /// linked to the lifetime of its guarantor (if any). fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) { debug!("regionck::for_match()"); - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); let discr_cmt = ignore_err!(mc.cat_expr(discr)); debug!("discr_cmt={:?}", discr_cmt); for arm in arms { @@ -1077,7 +1086,7 @@ fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) { /// linked to the lifetime of its guarantor (if any). fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[ast::Arg]) { debug!("regionck::link_fn_args(body_scope={:?})", body_scope); - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); for arg in args { let arg_ty = rcx.fcx.node_ty(arg.id); let re_scope = ty::ReScope(body_scope); @@ -1091,8 +1100,8 @@ fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[ast::Arg]) { /// Link lifetimes of any ref bindings in `root_pat` to the pointers found in the discriminant, if /// needed. -fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, - mc: mc::MemCategorizationContext>, +fn link_pattern<'t, 'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, + mc: mc::MemCategorizationContext<'t, 'a, 'tcx>, discr_cmt: mc::cmt<'tcx>, root_pat: &ast::Pat) { debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", @@ -1131,7 +1140,7 @@ fn link_autoref(rcx: &Rcx, autoref: &ty::AutoRef) { debug!("link_autoref(autoref={:?})", autoref); - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); debug!("expr_cmt={:?}", expr_cmt); @@ -1155,7 +1164,7 @@ fn link_by_ref(rcx: &Rcx, callee_scope: CodeExtent) { debug!("link_by_ref(expr={:?}, callee_scope={:?})", expr, callee_scope); - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx()); let expr_cmt = ignore_err!(mc.cat_expr(expr)); let borrow_region = ty::ReScope(callee_scope); link_region(rcx, expr.span, &borrow_region, ty::ImmBorrow, expr_cmt); @@ -1172,10 +1181,8 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, id, mutbl, cmt_borrowed); let rptr_ty = rcx.resolve_node_type(id); - if !ty::type_is_error(rptr_ty) { - let tcx = rcx.fcx.ccx.tcx; + if let ty::TyRef(&r, _) = rptr_ty.sty { debug!("rptr_ty={}", rptr_ty); - let r = ty::ty_region(tcx, span, rptr_ty); link_region(rcx, span, &r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); } @@ -1294,7 +1301,7 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, // Detect by-ref upvar `x`: let cause = match note { mc::NoteUpvarRef(ref upvar_id) => { - let upvar_capture_map = rcx.fcx.inh.upvar_capture_map.borrow_mut(); + let upvar_capture_map = &rcx.fcx.inh.tables.borrow_mut().upvar_capture_map; match upvar_capture_map.get(upvar_id) { Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => { // The mutability of the upvar may have been modified @@ -1401,7 +1408,7 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, ty, region); - let implications = implicator::implications(rcx.fcx.infcx(), rcx.fcx, rcx.body_id, + let implications = implicator::implications(rcx.fcx.infcx(), rcx.body_id, ty, region, origin.span()); for implication in implications { debug!("implication: {:?}", implication); @@ -1442,7 +1449,7 @@ fn closure_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, debug!("closure_must_outlive(region={:?}, def_id={:?}, substs={:?})", region, def_id, substs); - let upvars = rcx.fcx.closure_upvars(def_id, substs).unwrap(); + let upvars = rcx.fcx.infcx().closure_upvars(def_id, substs).unwrap(); for upvar in upvars { let var_id = upvar.def.def_id().local_id(); type_must_outlive( @@ -1455,17 +1462,15 @@ fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region, generic: &GenericKind<'tcx>) { - let param_env = &rcx.fcx.inh.param_env; + let param_env = &rcx.fcx.inh.infcx.parameter_environment; debug!("param_must_outlive(region={:?}, generic={:?})", region, generic); // To start, collect bounds from user: - let mut param_bounds = - ty::required_region_bounds(rcx.tcx(), - generic.to_ty(rcx.tcx()), - param_env.caller_bounds.clone()); + let mut param_bounds = rcx.tcx().required_region_bounds(generic.to_ty(rcx.tcx()), + param_env.caller_bounds.clone()); // In the case of a projection T::Foo, we may be able to extract bounds from the trait def: match *generic { @@ -1520,7 +1525,7 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>, debug!("projection_bounds(projection_ty={:?})", projection_ty); - let ty = ty::mk_projection(tcx, projection_ty.trait_ref.clone(), projection_ty.item_name); + let ty = tcx.mk_projection(projection_ty.trait_ref.clone(), projection_ty.item_name); // Say we have a projection `>::SomeType`. We are interested // in looking for a trait definition like: @@ -1532,7 +1537,7 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>, // ``` // // we can thus deduce that `>::SomeType : 'a`. - let trait_predicates = ty::lookup_predicates(tcx, projection_ty.trait_ref.def_id); + let trait_predicates = tcx.lookup_predicates(projection_ty.trait_ref.def_id); let predicates = trait_predicates.predicates.as_slice().to_vec(); traits::elaborate_predicates(tcx, predicates) .filter_map(|predicate| { diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 99e6309918c97..c7f084e27cda0 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -129,14 +129,15 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> { _body: &ast::Block) { let closure_def_id = ast_util::local_def(expr.id); - if !self.fcx.inh.closure_kinds.borrow().contains_key(&closure_def_id) { + if !self.fcx.inh.tables.borrow().closure_kinds.contains_key(&closure_def_id) { self.closures_with_inferred_kinds.insert(expr.id); - self.fcx.inh.closure_kinds.borrow_mut().insert(closure_def_id, ty::FnClosureKind); + self.fcx.inh.tables.borrow_mut().closure_kinds + .insert(closure_def_id, ty::FnClosureKind); debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds", closure_def_id); } - ty::with_freevars(self.tcx(), expr.id, |freevars| { + self.tcx().with_freevars(expr.id, |freevars| { for freevar in freevars { let var_node_id = freevar.def.local_node_id(); let upvar_id = ty::UpvarId { var_id: var_node_id, @@ -156,7 +157,7 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> { } }; - self.fcx.inh.upvar_capture_map.borrow_mut().insert(upvar_id, capture_kind); + self.fcx.inh.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind); } }); } @@ -186,7 +187,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { debug!("analyzing closure `{}` with fn body id `{}`", id, body.id); - let mut euv = euv::ExprUseVisitor::new(self, self.fcx); + let mut euv = euv::ExprUseVisitor::new(self, self.fcx.infcx()); euv.walk_fn(decl, body); // If we had not yet settled on a closure kind for this closure, @@ -267,7 +268,10 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { // to move out of an upvar, this must be a FnOnce closure self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind); - let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut(); + let upvar_capture_map = &mut self.fcx + .inh + .tables.borrow_mut() + .upvar_capture_map; upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue); } mc::NoteClosureEnv(upvar_id) => { @@ -374,9 +378,11 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { // upvar, then we need to modify the // borrow_kind of the upvar to make sure it // is inferred to mutable if necessary - let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut(); - let ub = upvar_capture_map.get_mut(&upvar_id).unwrap(); - self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind); + { + let upvar_capture_map = &mut self.fcx.inh.tables.borrow_mut().upvar_capture_map; + let ub = upvar_capture_map.get_mut(&upvar_id).unwrap(); + self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind); + } // also need to be in an FnMut closure since this is not an ImmBorrow self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnMutClosureKind); @@ -442,7 +448,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { } let closure_def_id = ast_util::local_def(closure_id); - let mut closure_kinds = self.fcx.inh.closure_kinds.borrow_mut(); + let closure_kinds = &mut self.fcx.inh.tables.borrow_mut().closure_kinds; let existing_kind = *closure_kinds.get(&closure_def_id).unwrap(); debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index c048845892c4b..7cf7d73a5668c 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -16,9 +16,9 @@ use middle::region; use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use middle::traits; use middle::ty::{self, Ty}; -use middle::ty::liberate_late_bound_regions; use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty}; +use std::cell::RefCell; use std::collections::HashSet; use syntax::ast; use syntax::ast_util::local_def; @@ -56,7 +56,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let ccx = self.ccx; debug!("check_item_well_formed(it.id={}, it.ident={})", item.id, - ty::item_path_str(ccx.tcx, local_def(item.id))); + ccx.tcx.item_path_str(local_def(item.id))); match item.node { /// Right now we check that every default trait implementation @@ -80,13 +80,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { self.check_impl(item); } ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(_), _, _) => { - let trait_ref = ty::impl_trait_ref(ccx.tcx, - local_def(item.id)).unwrap(); - ty::populate_implementations_for_trait_if_necessary(ccx.tcx, trait_ref.def_id); + let trait_ref = ccx.tcx.impl_trait_ref(local_def(item.id)).unwrap(); + ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id); match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { Some(ty::BoundSend) | Some(ty::BoundSync) => {} Some(_) | None => { - if !ty::trait_has_default_impl(ccx.tcx, trait_ref.def_id) { + if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) { span_err!(ccx.tcx.sess, item.span, E0192, "negative impls are only allowed for traits with \ default impls (e.g., `Send` and `Sync`)") @@ -119,9 +118,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } ast::ItemTrait(_, _, _, ref items) => { let trait_predicates = - ty::lookup_predicates(ccx.tcx, local_def(item.id)); + ccx.tcx.lookup_predicates(local_def(item.id)); reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates); - if ty::trait_has_default_impl(ccx.tcx, local_def(item.id)) { + if ccx.tcx.trait_has_default_impl(local_def(item.id)) { if !items.is_empty() { span_err!(ccx.tcx.sess, item.span, E0380, "traits with default impls (`e.g. unsafe impl \ @@ -138,16 +137,15 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { { let ccx = self.ccx; let item_def_id = local_def(item.id); - let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id); - let type_predicates = ty::lookup_predicates(ccx.tcx, item_def_id); + let type_scheme = ccx.tcx.lookup_item_type(item_def_id); + let type_predicates = ccx.tcx.lookup_predicates(item_def_id); reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates); - let param_env = - ty::construct_parameter_environment(ccx.tcx, - item.span, - &type_scheme.generics, - &type_predicates, - item.id); - let inh = Inherited::new(ccx.tcx, param_env); + let param_env = ccx.tcx.construct_parameter_environment(item.span, + &type_scheme.generics, + &type_predicates, + item.id); + let tables = RefCell::new(ty::Tables::empty()); + let inh = Inherited::new(ccx.tcx, &tables, param_env); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id); f(self, &fcx); fcx.select_all_obligations_or_error(); @@ -201,9 +199,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { Some(&mut this.cache)); debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope); - let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id)); + let type_scheme = fcx.tcx().lookup_item_type(local_def(item.id)); let item_ty = fcx.instantiate_type_scheme(item.span, - &fcx.inh.param_env.free_substs, + &fcx.inh + .infcx + .parameter_environment + .free_substs, &type_scheme.ty); bounds_checker.check_traits_in_ty(item_ty, item.span); @@ -222,22 +223,28 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // Find the impl self type as seen from the "inside" -- // that is, with all type parameters converted from bound // to free. - let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); + let self_ty = fcx.tcx().node_id_to_type(item.id); let self_ty = fcx.instantiate_type_scheme(item.span, - &fcx.inh.param_env.free_substs, + &fcx.inh + .infcx + .parameter_environment + .free_substs, &self_ty); bounds_checker.check_traits_in_ty(self_ty, item.span); // Similarly, obtain an "inside" reference to the trait // that the impl implements. - let trait_ref = match ty::impl_trait_ref(fcx.tcx(), local_def(item.id)) { + let trait_ref = match fcx.tcx().impl_trait_ref(local_def(item.id)) { None => { return; } Some(t) => { t } }; let trait_ref = fcx.instantiate_type_scheme(item.span, - &fcx.inh.param_env.free_substs, + &fcx.inh + .infcx + .parameter_environment + .free_substs, &trait_ref); // We are stricter on the trait-ref in an impl than the @@ -258,10 +265,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // Find the supertrait bounds. This will add `int:Bar`. let poly_trait_ref = ty::Binder(trait_ref); - let predicates = ty::lookup_super_predicates(fcx.tcx(), poly_trait_ref.def_id()); + let predicates = fcx.tcx().lookup_super_predicates(poly_trait_ref.def_id()); let predicates = predicates.instantiate_supertrait(fcx.tcx(), &poly_trait_ref); let predicates = { - let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx); + let selcx = &mut traits::SelectionContext::new(fcx.infcx()); traits::normalize(selcx, cause.clone(), &predicates) }; for predicate in predicates.value.predicates { @@ -278,8 +285,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { ast_generics: &ast::Generics) { let item_def_id = local_def(item.id); - let ty_predicates = ty::lookup_predicates(self.tcx(), item_def_id); - let variances = ty::item_variances(self.tcx(), item_def_id); + let ty_predicates = self.tcx().lookup_predicates(item_def_id); + let variances = self.tcx().item_variances(item_def_id); let mut constrained_parameters: HashSet<_> = variances.types @@ -358,7 +365,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { span, &format!("consider removing `{}` or using a marker such as `{}`", param_name, - ty::item_path_str(self.tcx(), def_id))); + self.tcx().item_path_str(def_id))); } None => { // no lang items, no help! @@ -432,7 +439,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { match fk { visit::FkFnBlock | visit::FkItemFn(..) => {} visit::FkMethod(..) => { - match ty::impl_or_trait_item(self.tcx(), local_def(id)) { + match self.tcx().impl_or_trait_item(local_def(id)) { ty::ImplOrTraitItem::MethodTraitItem(ty_method) => { reject_shadowing_type_parameters(self.tcx(), span, &ty_method.generics) } @@ -445,7 +452,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn visit_trait_item(&mut self, trait_item: &'v ast::TraitItem) { if let ast::MethodTraitItem(_, None) = trait_item.node { - match ty::impl_or_trait_item(self.tcx(), local_def(trait_item.id)) { + match self.tcx().impl_or_trait_item(local_def(trait_item.id)) { ty::ImplOrTraitItem::MethodTraitItem(ty_method) => { reject_non_type_param_bounds( self.tcx(), @@ -496,7 +503,7 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { /// Note that it does not (currently, at least) check that `A : Copy` (that check is delegated /// to the point where impl `A : Trait` is implemented). pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, span: Span) { - let trait_predicates = ty::lookup_predicates(self.fcx.tcx(), trait_ref.def_id); + let trait_predicates = self.fcx.tcx().lookup_predicates(trait_ref.def_id); let bounds = self.fcx.instantiate_bounds(span, trait_ref.substs, @@ -538,8 +545,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { where T : TypeFoldable<'tcx> { self.binding_count += 1; - let value = liberate_late_bound_regions( - self.fcx.tcx(), + let value = self.fcx.tcx().liberate_late_bound_regions( region::DestructionScopeData::new(self.scope), binder); debug!("BoundsChecker::fold_binder: late-bound regions replaced: {:?} at scope: {:?}", @@ -567,7 +573,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { match t.sty{ ty::TyStruct(type_id, substs) | ty::TyEnum(type_id, substs) => { - let type_predicates = ty::lookup_predicates(self.fcx.tcx(), type_id); + let type_predicates = self.fcx.tcx().lookup_predicates(type_id); let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_predicates); @@ -638,9 +644,12 @@ fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, struct_def.fields .iter() .map(|field| { - let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id); + let field_ty = fcx.tcx().node_id_to_type(field.node.id); let field_ty = fcx.instantiate_type_scheme(field.span, - &fcx.inh.param_env.free_substs, + &fcx.inh + .infcx + .parameter_environment + .free_substs, &field_ty); AdtField { ty: field_ty, span: field.span } }) @@ -655,19 +664,20 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, .map(|variant| { match variant.node.kind { ast::TupleVariantKind(ref args) if !args.is_empty() => { - let ctor_ty = ty::node_id_to_type(fcx.tcx(), variant.node.id); + let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id); // the regions in the argument types come from the // enum def'n, and hence will all be early bound - let arg_tys = - ty::no_late_bound_regions( - fcx.tcx(), &ty::ty_fn_args(ctor_ty)).unwrap(); + let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap(); AdtVariant { fields: args.iter().enumerate().map(|(index, arg)| { let arg_ty = arg_tys[index]; let arg_ty = fcx.instantiate_type_scheme(variant.span, - &fcx.inh.param_env.free_substs, + &fcx.inh + .infcx + .parameter_environment + .free_substs, &arg_ty); AdtField { ty: arg_ty, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 05cc3077fc9fb..419fa9e160a47 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -95,15 +95,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let rhs_ty = self.fcx.node_ty(rhs.id); let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty); - if ty::type_is_scalar(lhs_ty) && ty::type_is_scalar(rhs_ty) { - self.fcx.inh.method_map.borrow_mut().remove(&MethodCall::expr(e.id)); + if lhs_ty.is_scalar() && rhs_ty.is_scalar() { + self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id)); // weird but true: the by-ref binops put an // adjustment on the lhs but not the rhs; the // adjustment for rhs is kind of baked into the // system. if !ast_util::is_by_value_binop(op.node) { - self.fcx.inh.adjustments.borrow_mut().remove(&lhs.id); + self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id); } } } @@ -128,7 +128,7 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> { return; } - self.visit_node_id(ResolvingExpr(s.span), ty::stmt_node_id(s)); + self.visit_node_id(ResolvingExpr(s.span), ast_util::stmt_id(s)); visit::walk_stmt(self, s); } @@ -171,7 +171,7 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> { debug!("Type for pattern binding {} (id {}) resolved to {:?}", pat_to_string(p), p.id, - ty::node_id_to_type(self.tcx(), p.id)); + self.tcx().node_id_to_type(p.id)); visit::walk_pat(self, p); } @@ -204,7 +204,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { return; } - for (upvar_id, upvar_capture) in self.fcx.inh.upvar_capture_map.borrow().iter() { + for (upvar_id, upvar_capture) in self.fcx.inh.tables.borrow().upvar_capture_map.iter() { let new_upvar_capture = match *upvar_capture { ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, ty::UpvarCapture::ByRef(ref upvar_borrow) => { @@ -217,7 +217,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { debug!("Upvar capture for {:?} resolved to {:?}", upvar_id, new_upvar_capture); - self.fcx.tcx().upvar_capture_map.borrow_mut().insert(*upvar_id, new_upvar_capture); + self.fcx.tcx() + .tables + .borrow_mut() + .upvar_capture_map + .insert(*upvar_id, new_upvar_capture); } } @@ -226,13 +230,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { return } - for (def_id, closure_ty) in self.fcx.inh.closure_tys.borrow().iter() { + for (def_id, closure_ty) in self.fcx.inh.tables.borrow().closure_tys.iter() { let closure_ty = self.resolve(closure_ty, ResolvingClosure(*def_id)); - self.fcx.tcx().closure_tys.borrow_mut().insert(*def_id, closure_ty); + self.fcx.tcx().tables.borrow_mut().closure_tys.insert(*def_id, closure_ty); } - for (def_id, &closure_kind) in self.fcx.inh.closure_kinds.borrow().iter() { - self.fcx.tcx().closure_kinds.borrow_mut().insert(*def_id, closure_kind); + for (def_id, &closure_kind) in self.fcx.inh.tables.borrow().closure_kinds.iter() { + self.fcx.tcx().tables.borrow_mut().closure_kinds.insert(*def_id, closure_kind); } } @@ -254,7 +258,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) { - match self.fcx.inh.adjustments.borrow_mut().remove(&id) { + let adjustments = self.fcx.inh.tables.borrow_mut().adjustments.remove(&id); + match adjustments { None => { debug!("No adjustments for node {}", id); } @@ -281,7 +286,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } }; debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); - self.tcx().adjustments.borrow_mut().insert( + self.tcx().tables.borrow_mut().adjustments.insert( id, resolved_adjustment); } } @@ -291,20 +296,28 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { reason: ResolveReason, method_call: MethodCall) { // Resolve any method map entry - match self.fcx.inh.method_map.borrow_mut().remove(&method_call) { + let new_method = match self.fcx.inh.tables.borrow_mut().method_map.remove(&method_call) { Some(method) => { debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})", method_call, method); let new_method = MethodCallee { - origin: self.resolve(&method.origin, reason), + def_id: method.def_id, ty: self.resolve(&method.ty, reason), - substs: self.resolve(&method.substs, reason), + substs: self.tcx().mk_substs(self.resolve(method.substs, reason)), }; - self.tcx().method_map.borrow_mut().insert( + Some(new_method) + } + None => None + }; + + //NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE + match new_method { + Some(method) => { + self.tcx().tables.borrow_mut().method_map.insert( method_call, - new_method); + method); } None => {} } @@ -334,11 +347,11 @@ impl ResolveReason { ResolvingLocal(s) => s, ResolvingPattern(s) => s, ResolvingUpvar(upvar_id) => { - ty::expr_span(tcx, upvar_id.closure_expr_id) + tcx.expr_span(upvar_id.closure_expr_id) } ResolvingClosure(did) => { if did.krate == ast::LOCAL_CRATE { - ty::expr_span(tcx, did.node) + tcx.expr_span(did.node) } else { DUMMY_SP } @@ -403,7 +416,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { let span = self.reason.span(self.tcx); span_err!(self.tcx.sess, span, E0104, "cannot resolve lifetime for captured variable `{}`: {}", - ty::local_var_name_str(self.tcx, upvar_id.var_id).to_string(), + self.tcx.local_var_name_str(upvar_id.var_id).to_string(), infer::fixup_err_to_string(e)); } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index b66c76048c639..20407e927f7ff 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -139,15 +139,14 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { fn check_implementation(&self, item: &Item) { let tcx = self.crate_context.tcx; let impl_did = local_def(item.id); - let self_type = ty::lookup_item_type(tcx, impl_did); + let self_type = tcx.lookup_item_type(impl_did); // If there are no traits, then this implementation must have a // base type. let impl_items = self.create_impl_from_item(item); - if let Some(trait_ref) = ty::impl_trait_ref(self.crate_context.tcx, - impl_did) { + if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) { debug!("(checking implementation) adding impl for trait '{:?}', item '{}'", trait_ref, item.ident); @@ -181,9 +180,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { debug!("instantiate_default_methods(impl_id={:?}, trait_ref={:?})", impl_id, trait_ref); - let impl_type_scheme = ty::lookup_item_type(tcx, impl_id); + let impl_type_scheme = tcx.lookup_item_type(impl_id); - let prov = ty::provided_trait_methods(tcx, trait_ref.def_id); + let prov = tcx.provided_trait_methods(trait_ref.def_id); for trait_method in &prov { // Synthesize an ID. let new_id = tcx.sess.next_node_id(); @@ -210,12 +209,12 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { // impl, plus its own. let new_polytype = ty::TypeScheme { generics: new_method_ty.generics.clone(), - ty: ty::mk_bare_fn(tcx, Some(new_did), - tcx.mk_bare_fn(new_method_ty.fty.clone())) + ty: tcx.mk_fn(Some(new_did), + tcx.mk_bare_fn(new_method_ty.fty.clone())) }; debug!("new_polytype={:?}", new_polytype); - tcx.tcache.borrow_mut().insert(new_did, new_polytype); + tcx.register_item_type(new_did, new_polytype); tcx.predicates.borrow_mut().insert(new_did, new_method_ty.predicates.clone()); tcx.impl_or_trait_items .borrow_mut() @@ -245,8 +244,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { 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 = ty::lookup_trait_def(self.crate_context.tcx, - impl_trait_ref.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); } @@ -273,11 +271,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } }).collect(); - if let Some(trait_ref) = ty::impl_trait_ref(self.crate_context.tcx, - local_def(item.id)) { - self.instantiate_default_methods(local_def(item.id), - &trait_ref, - &mut items); + let def_id = local_def(item.id); + if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(def_id) { + self.instantiate_default_methods(def_id, &trait_ref, &mut items); } items @@ -299,8 +295,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let drop_trait = match tcx.lang_items.drop_trait() { Some(id) => id, None => { return } }; - ty::populate_implementations_for_trait_if_necessary(tcx, drop_trait); - let drop_trait = ty::lookup_trait_def(tcx, drop_trait); + tcx.populate_implementations_for_trait_if_necessary(drop_trait); + let drop_trait = tcx.lookup_trait_def(drop_trait); let impl_items = tcx.impl_items.borrow(); @@ -312,7 +308,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } let method_def_id = items[0]; - let self_type = ty::lookup_item_type(tcx, impl_did); + let self_type = tcx.lookup_item_type(impl_did); match self_type.ty.sty { ty::TyEnum(type_def_id, _) | ty::TyStruct(type_def_id, _) | @@ -355,8 +351,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { Some(id) => id, None => return, }; - ty::populate_implementations_for_trait_if_necessary(tcx, copy_trait); - let copy_trait = ty::lookup_trait_def(tcx, copy_trait); + tcx.populate_implementations_for_trait_if_necessary(copy_trait); + let copy_trait = tcx.lookup_trait_def(copy_trait); copy_trait.for_each_impl(tcx, |impl_did| { debug!("check_implementations_of_copy: impl_did={:?}", @@ -368,7 +364,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { return } - let self_type = ty::lookup_item_type(tcx, impl_did); + let self_type = tcx.lookup_item_type(impl_did); debug!("check_implementations_of_copy: self_type={:?} (bound)", self_type); @@ -380,7 +376,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { debug!("check_implementations_of_copy: self_type={:?} (free)", self_type); - match ty::can_type_implement_copy(¶m_env, span, self_type) { + match param_env.can_type_implement_copy(self_type, span) { Ok(()) => {} Err(ty::FieldDoesNotImplementCopy(name)) => { span_err!(tcx.sess, span, E0204, @@ -425,7 +421,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } }; - let trait_def = ty::lookup_trait_def(tcx, coerce_unsized_trait); + let trait_def = tcx.lookup_trait_def(coerce_unsized_trait); trait_def.for_each_impl(tcx, |impl_did| { debug!("check_implementations_of_coerce_unsized: impl_did={:?}", @@ -437,9 +433,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { return; } - let source = ty::lookup_item_type(tcx, impl_did).ty; - let trait_ref = ty::impl_trait_ref(self.crate_context.tcx, - impl_did).unwrap(); + let source = tcx.lookup_item_type(impl_did).ty; + let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap(); let target = *trait_ref.substs.types.get(subst::TypeSpace, 0); debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); @@ -453,7 +448,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)", source, target); - let infcx = new_infer_ctxt(tcx); + let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env), true); let check_mutbl = |mt_a: ty::mt<'tcx>, mt_b: ty::mt<'tcx>, mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| { @@ -468,18 +463,18 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => { infer::mk_subr(&infcx, infer::RelateObjectBound(span), *r_b, *r_a); - check_mutbl(mt_a, mt_b, &|ty| ty::mk_imm_rptr(tcx, r_b, ty)) + check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) } (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) | (&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => { - check_mutbl(mt_a, mt_b, &|ty| ty::mk_imm_ptr(tcx, ty)) + check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) } (&ty::TyStruct(def_id_a, substs_a), &ty::TyStruct(def_id_b, substs_b)) => { if def_id_a != def_id_b { - let source_path = ty::item_path_str(tcx, def_id_a); - let target_path = ty::item_path_str(tcx, def_id_b); + let source_path = tcx.item_path_str(def_id_a); + let target_path = tcx.item_path_str(def_id_b); span_err!(tcx.sess, span, E0377, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with the same \ @@ -489,9 +484,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } let origin = infer::Misc(span); - let fields = ty::lookup_struct_fields(tcx, def_id_a); + let fields = tcx.lookup_struct_fields(def_id_a); let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| { - let ty = ty::lookup_field_type_unsubstituted(tcx, def_id_a, f.id); + let ty = tcx.lookup_field_type_unsubstituted(def_id_a, f.id); let (a, b) = (ty.subst(tcx, substs_a), ty.subst(tcx, substs_b)); if infcx.sub_types(false, origin, b, a).is_ok() { None @@ -536,7 +531,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } }; - let mut fulfill_cx = traits::FulfillmentContext::new(true); + let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut(); // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_did.node); @@ -545,13 +540,14 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { fulfill_cx.register_predicate_obligation(&infcx, predicate); // Check that all transitive obligations are satisfied. - if let Err(errors) = fulfill_cx.select_all_or_error(&infcx, ¶m_env) { + if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) { traits::report_fulfillment_errors(&infcx, &errors); } // Finally, resolve all regions. let mut free_regions = FreeRegionMap::new(); - free_regions.relate_free_regions_from_predicates(tcx, ¶m_env.caller_bounds); + free_regions.relate_free_regions_from_predicates(tcx, &infcx.parameter_environment + .caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_did.node); if let Some(kind) = kind { @@ -592,7 +588,7 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, provided_source: Option) -> ty::Method<'tcx> { - let combined_substs = ty::make_substs_for_receiver_types(tcx, trait_ref, method); + let combined_substs = tcx.make_substs_for_receiver_types(trait_ref, method); debug!("subst_receiver_types_in_method_ty: combined_substs={:?}", combined_substs); @@ -635,7 +631,7 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, pub fn check_coherence(crate_context: &CrateCtxt) { CoherenceChecker { crate_context: crate_context, - inference_context: new_infer_ctxt(crate_context.tcx), + inference_context: new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None, true), inherent_impls: RefCell::new(FnvHashMap()), }.check(crate_context.tcx.map.krate()); unsafety::check(crate_context.tcx); diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 8376b92da3dea..e585b8cd2bde0 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -67,7 +67,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { // defined in this crate. debug!("coherence2::orphan check: inherent impl {}", self.tcx.map.node_to_string(item.id)); - let self_ty = ty::lookup_item_type(self.tcx, def_id).ty; + let self_ty = self.tcx.lookup_item_type(def_id).ty; match self_ty.sty { ty::TyEnum(def_id, _) | ty::TyStruct(def_id, _) => { @@ -210,7 +210,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { // "Trait" impl debug!("coherence2::orphan check: trait impl {}", self.tcx.map.node_to_string(item.id)); - let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap(); + let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap(); let trait_def_id = trait_ref.def_id; match traits::orphan_check(self.tcx, def_id) { Ok(()) => { } @@ -269,9 +269,9 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { debug!("trait_ref={:?} trait_def_id={:?} trait_has_default_impl={}", trait_ref, trait_def_id, - ty::trait_has_default_impl(self.tcx, trait_def_id)); + self.tcx.trait_has_default_impl(trait_def_id)); if - ty::trait_has_default_impl(self.tcx, trait_def_id) && + self.tcx.trait_has_default_impl(trait_def_id) && trait_def_id.krate != ast::LOCAL_CRATE { let self_ty = trait_ref.self_ty(); @@ -297,7 +297,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { "cross-crate traits with a default impl, like `{}`, \ can only be implemented for a struct/enum type \ defined in the current crate", - ty::item_path_str(self.tcx, trait_def_id))) + self.tcx.item_path_str(trait_def_id))) } } _ => { @@ -305,7 +305,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { "cross-crate traits with a default impl, like `{}`, \ can only be implemented for a struct/enum type, \ not `{}`", - ty::item_path_str(self.tcx, trait_def_id), + self.tcx.item_path_str(trait_def_id), self_ty)) } }; @@ -332,7 +332,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { // "Trait" impl debug!("coherence2::orphan check: default trait impl {}", self.tcx.map.node_to_string(item.id)); - let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap(); + let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap(); if trait_ref.def_id.krate != ast::LOCAL_CRATE { span_err!(self.tcx.sess, item.span, E0318, "cannot create default implementations for traits outside the \ diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 0e8067e7181bd..42c6bcbfbb999 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -50,9 +50,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { let trait_defs: Vec<_> = self.tcx.trait_defs.borrow().values().cloned().collect(); for trait_def in trait_defs { - ty::populate_implementations_for_trait_if_necessary( - self.tcx, - trait_def.trait_ref.def_id); + self.tcx.populate_implementations_for_trait_if_necessary(trait_def.trait_ref.def_id); self.check_for_overlapping_impls_of_trait(trait_def); } } @@ -135,7 +133,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { impl1_def_id, impl2_def_id); - let infcx = infer::new_infer_ctxt(self.tcx); + let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false); if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) { self.report_overlap_error(trait_def_id, impl1_def_id, impl2_def_id); } @@ -147,7 +145,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119, "conflicting implementations for trait `{}`", - ty::item_path_str(self.tcx, trait_def_id)); + self.tcx.item_path_str(trait_def_id)); self.report_overlap_note(impl1, impl2); } @@ -181,7 +179,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { // general orphan/coherence rules, it must always be // in this crate. let impl_def_id = ast_util::local_def(item.id); - let trait_ref = ty::impl_trait_ref(self.tcx, impl_def_id).unwrap(); + let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id); match prev_default_impl { Some(prev_id) => { @@ -194,7 +192,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { } ast::ItemImpl(_, _, _, Some(_), ref self_ty, _) => { let impl_def_id = ast_util::local_def(item.id); - let trait_ref = ty::impl_trait_ref(self.tcx, impl_def_id).unwrap(); + let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); let trait_def_id = trait_ref.def_id; match trait_ref.self_ty().sty { ty::TyTrait(ref data) => { @@ -208,7 +206,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { // giving a misleading message below. span_err!(self.tcx.sess, self_ty.span, E0372, "the trait `{}` cannot be made into an object", - ty::item_path_str(self.tcx, data.principal_def_id())); + self.tcx.item_path_str(data.principal_def_id())); } else { let mut supertrait_def_ids = traits::supertrait_def_ids(self.tcx, data.principal_def_id()); @@ -217,7 +215,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { "the object type `{}` automatically \ implements the trait `{}`", trait_ref.self_ty(), - ty::item_path_str(self.tcx, trait_def_id)); + self.tcx.item_path_str(trait_def_id)); } } } diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index fa39e9d0491f9..c0323ba60fc47 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -30,7 +30,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { fn check_unsafety_coherence(&mut self, item: &'v ast::Item, unsafety: ast::Unsafety, polarity: ast::ImplPolarity) { - match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) { + match self.tcx.impl_trait_ref(ast_util::local_def(item.id)) { None => { // Inherent impl. match unsafety { @@ -43,7 +43,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { } Some(trait_ref) => { - let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id); + let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id); match (trait_def.unsafety, unsafety, polarity) { (ast::Unsafety::Unsafe, ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 22926126f7ab3..e170808ad07d6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -72,7 +72,7 @@ use middle::free_region::FreeRegionMap; use middle::region; use middle::resolve_lifetime; use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; -use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; +use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; use middle::infer; @@ -242,12 +242,12 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { AstConvRequest::GetTraitDef(def_id) => { tcx.sess.note( &format!("the cycle begins when processing `{}`...", - ty::item_path_str(tcx, def_id))); + tcx.item_path_str(def_id))); } AstConvRequest::EnsureSuperPredicates(def_id) => { tcx.sess.note( &format!("the cycle begins when computing the supertraits of `{}`...", - ty::item_path_str(tcx, def_id))); + tcx.item_path_str(def_id))); } AstConvRequest::GetTypeParameterBounds(id) => { let def = tcx.type_parameter_def(id); @@ -264,12 +264,12 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { AstConvRequest::GetTraitDef(def_id) => { tcx.sess.note( &format!("...which then requires processing `{}`...", - ty::item_path_str(tcx, def_id))); + tcx.item_path_str(def_id))); } AstConvRequest::EnsureSuperPredicates(def_id) => { tcx.sess.note( &format!("...which then requires computing the supertraits of `{}`...", - ty::item_path_str(tcx, def_id))); + tcx.item_path_str(def_id))); } AstConvRequest::GetTypeParameterBounds(id) => { let def = tcx.type_parameter_def(id); @@ -286,13 +286,13 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { AstConvRequest::GetTraitDef(def_id) => { tcx.sess.note( &format!("...which then again requires processing `{}`, completing the cycle.", - ty::item_path_str(tcx, def_id))); + tcx.item_path_str(def_id))); } AstConvRequest::EnsureSuperPredicates(def_id) => { tcx.sess.note( &format!("...which then again requires computing the supertraits of `{}`, \ completing the cycle.", - ty::item_path_str(tcx, def_id))); + tcx.item_path_str(def_id))); } AstConvRequest::GetTypeParameterBounds(id) => { let def = tcx.type_parameter_def(id); @@ -311,7 +311,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { let tcx = self.tcx; if trait_id.krate != ast::LOCAL_CRATE { - return ty::lookup_trait_def(tcx, trait_id) + return tcx.lookup_trait_def(trait_id) } let item = match tcx.map.get(trait_id.node) { @@ -399,7 +399,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { if trait_def_id.krate == ast::LOCAL_CRATE { trait_defines_associated_type_named(self.ccx, trait_def_id.node, assoc_name) } else { - let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id); + let trait_def = self.tcx().lookup_trait_def(trait_def_id); trait_def.associated_type_names.contains(&assoc_name) } } @@ -416,7 +416,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { item_name: ast::Name) -> Ty<'tcx> { - ty::mk_projection(self.tcx(), trait_ref, item_name) + self.tcx().mk_projection(trait_ref, item_name) } } @@ -508,7 +508,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics { // `where T:Foo`. let def = astconv.tcx().type_parameter_def(node_id); - let ty = ty::mk_param_from_def(astconv.tcx(), &def); + let ty = astconv.tcx().mk_param_from_def(&def); let from_ty_params = self.ty_params @@ -577,7 +577,7 @@ fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast::TupleVariantKind(ref args) if !args.is_empty() => { let rs = ExplicitRscope; let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect(); - ty::mk_ctor_fn(tcx, variant_def_id, &input_tys, enum_scheme.ty) + tcx.mk_ctor_fn(variant_def_id, &input_tys, enum_scheme.ty) } ast::TupleVariantKind(_) => { @@ -596,7 +596,7 @@ fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty: result_ty }; - tcx.tcache.borrow_mut().insert(variant_def_id, variant_scheme.clone()); + tcx.register_item_type(variant_def_id, variant_scheme.clone()); tcx.predicates.borrow_mut().insert(variant_def_id, enum_predicates.clone()); write_ty_to_tcx(tcx, variant.node.id, result_ty); } @@ -631,11 +631,11 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container, None); - let fty = ty::mk_bare_fn(ccx.tcx, Some(def_id), - ccx.tcx.mk_bare_fn(ty_method.fty.clone())); + let fty = ccx.tcx.mk_fn(Some(def_id), + ccx.tcx.mk_bare_fn(ty_method.fty.clone())); debug!("method {} (id {}) has type {:?}", ident, id, fty); - ccx.tcx.tcache.borrow_mut().insert(def_id,TypeScheme { + ccx.tcx.register_item_type(def_id, TypeScheme { generics: ty_method.generics.clone(), ty: fty }); @@ -661,11 +661,11 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, write_ty_to_tcx(ccx.tcx, v.node.id, tt); /* add the field to the tcache */ - ccx.tcx.tcache.borrow_mut().insert(local_def(v.node.id), - ty::TypeScheme { - generics: struct_generics.clone(), - ty: tt - }); + ccx.tcx.register_item_type(local_def(v.node.id), + ty::TypeScheme { + generics: struct_generics.clone(), + ty: tt + }); ccx.tcx.predicates.borrow_mut().insert(local_def(v.node.id), struct_predicates.clone()); @@ -822,7 +822,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { ast_trait_ref, None); - ty::record_trait_has_default_impl(tcx, trait_ref.def_id); + tcx.record_trait_has_default_impl(trait_ref.def_id); tcx.impl_trait_refs.borrow_mut().insert(local_def(it.id), Some(trait_ref)); } @@ -841,9 +841,9 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &**selfty); write_ty_to_tcx(tcx, it.id, selfty); - tcx.tcache.borrow_mut().insert(local_def(it.id), - TypeScheme { generics: ty_generics.clone(), - ty: selfty }); + tcx.register_item_type(local_def(it.id), + TypeScheme { generics: ty_generics.clone(), + ty: selfty }); tcx.predicates.borrow_mut().insert(local_def(it.id), ty_predicates.clone()); @@ -863,11 +863,11 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { if let ast::ConstImplItem(ref ty, ref expr) = impl_item.node { let ty = ccx.icx(&ty_predicates) .to_ty(&ExplicitRscope, &*ty); - tcx.tcache.borrow_mut().insert(local_def(impl_item.id), - TypeScheme { - generics: ty_generics.clone(), - ty: ty, - }); + tcx.register_item_type(local_def(impl_item.id), + TypeScheme { + generics: ty_generics.clone(), + ty: ty, + }); convert_associated_const(ccx, ImplContainer(local_def(it.id)), impl_item.ident, impl_item.id, impl_item.vis.inherit_from(parent_visibility), @@ -944,7 +944,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { let _: Result<(), ErrorReported> = // any error is already reported, can ignore ccx.ensure_super_predicates(it.span, local_def(it.id)); convert_trait_predicates(ccx, it); - let trait_predicates = ty::lookup_predicates(tcx, local_def(it.id)); + let trait_predicates = tcx.lookup_predicates(local_def(it.id)); debug!("convert: trait_bounds={:?}", trait_predicates); @@ -954,11 +954,11 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { ast::ConstTraitItem(ref ty, ref default) => { let ty = ccx.icx(&trait_predicates) .to_ty(&ExplicitRscope, ty); - tcx.tcache.borrow_mut().insert(local_def(trait_item.id), - TypeScheme { - generics: trait_def.generics.clone(), - ty: ty, - }); + tcx.register_item_type(local_def(trait_item.id), + TypeScheme { + generics: trait_def.generics.clone(), + ty: ty, + }); convert_associated_const(ccx, TraitContainer(local_def(it.id)), trait_item.ident, trait_item.id, ast::Public, ty, default.as_ref().map(|d| &**d)); @@ -995,7 +995,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { convert_methods(ccx, TraitContainer(local_def(it.id)), methods, - ty::mk_self_type(tcx), + tcx.mk_self_type(), &trait_def.generics, &trait_predicates); @@ -1026,7 +1026,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { check_method_self_type(ccx, &BindingRscope::new(), ccx.method_ty(trait_item.id), - ty::mk_self_type(tcx), + tcx.mk_self_type(), &sig.explicit_self, it.id) } @@ -1088,7 +1088,7 @@ fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, tcx.struct_fields.borrow_mut().insert(local_def(id), Rc::new(field_tys)); let substs = mk_item_substs(ccx, &scheme.generics); - let selfty = ty::mk_struct(tcx, local_def(id), tcx.mk_substs(substs)); + let selfty = tcx.mk_struct(local_def(id), tcx.mk_substs(substs)); // If this struct is enum-like or tuple-like, create the type of its // constructor. @@ -1099,27 +1099,25 @@ fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Enum-like. write_ty_to_tcx(tcx, ctor_id, selfty); - tcx.tcache.borrow_mut().insert(local_def(ctor_id), scheme); + tcx.register_item_type(local_def(ctor_id), scheme); tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); } else if struct_def.fields[0].node.kind.is_unnamed() { // Tuple-like. let inputs: Vec<_> = struct_def.fields .iter() - .map(|field| tcx.tcache.borrow().get(&local_def(field.node.id)) - .unwrap() - .ty) + .map(|field| tcx.lookup_item_type( + local_def(field.node.id)).ty) .collect(); - let ctor_fn_ty = ty::mk_ctor_fn(tcx, - local_def(ctor_id), + let ctor_fn_ty = tcx.mk_ctor_fn(local_def(ctor_id), &inputs[..], selfty); write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); - tcx.tcache.borrow_mut().insert(local_def(ctor_id), - TypeScheme { - generics: scheme.generics, - ty: ctor_fn_ty - }); + tcx.register_item_type(local_def(ctor_id), + TypeScheme { + generics: scheme.generics, + ty: ctor_fn_ty + }); tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); } } @@ -1171,13 +1169,13 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, let trait_def = trait_def_of_item(ccx, item); let self_predicate = ty::GenericPredicates { predicates: VecPerParamSpace::new(vec![], - vec![trait_def.trait_ref.as_predicate()], + vec![trait_def.trait_ref.to_predicate()], vec![]) }; let scope = &(generics, &self_predicate); // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`. - let self_param_ty = ty::mk_self_type(tcx); + let self_param_ty = tcx.mk_self_type(); let superbounds1 = compute_bounds(&ccx.icx(scope), self_param_ty, bounds, @@ -1231,7 +1229,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, _ => tcx.sess.span_bug(it.span, "trait_def_of_item invoked on non-trait"), }; - let paren_sugar = ty::has_attr(tcx, def_id, "rustc_paren_sugar"); + let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar"); if paren_sugar && !ccx.tcx.sess.features.borrow().unboxed_closures { ccx.tcx.sess.span_err( it.span, @@ -1295,12 +1293,12 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics.ty_params .iter() .enumerate() - .map(|(i, def)| ty::mk_param(tcx, TypeSpace, + .map(|(i, def)| tcx.mk_param(TypeSpace, i as u32, def.ident.name)) .collect(); // ...and also create the `Self` parameter. - let self_ty = ty::mk_self_type(tcx); + let self_ty = tcx.mk_self_type(); Substs::new_trait(types, regions, self_ty) } @@ -1344,7 +1342,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) } }; - let super_predicates = ty::lookup_super_predicates(ccx.tcx, def_id); + let super_predicates = ccx.tcx.lookup_super_predicates(def_id); // `ty_generic_predicates` below will consider the bounds on the type // parameters (including `Self`) and the explicit where-clauses, @@ -1355,7 +1353,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) // Add in a predicate that `Self:Trait` (where `Trait` is the // current trait). This is needed for builtin bounds. - let self_predicate = trait_def.trait_ref.to_poly_trait_ref().as_predicate(); + let self_predicate = trait_def.trait_ref.to_poly_trait_ref().to_predicate(); base_predicates.predicates.push(SelfSpace, self_predicate); // add in the explicit where-clauses @@ -1389,9 +1387,8 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) } }; - let assoc_ty = ty::mk_projection(ccx.tcx, - self_trait_ref, - trait_item.ident.name); + let assoc_ty = ccx.tcx.mk_projection(self_trait_ref, + trait_item.ident.name); let bounds = compute_bounds(&ccx.icx(&(ast_generics, trait_predicates)), assoc_ty, @@ -1409,7 +1406,7 @@ fn type_scheme_of_def_id<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, -> ty::TypeScheme<'tcx> { if def_id.krate != ast::LOCAL_CRATE { - return ty::lookup_item_type(ccx.tcx, def_id); + return ccx.tcx.lookup_item_type(def_id); } match ccx.tcx.map.find(def_id.node) { @@ -1450,7 +1447,7 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, ast::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty()); let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &**decl); - let ty = ty::mk_bare_fn(tcx, Some(local_def(it.id)), tcx.mk_bare_fn(tofd)); + let ty = tcx.mk_fn(Some(local_def(it.id)), tcx.mk_bare_fn(tofd)); ty::TypeScheme { ty: ty, generics: ty_generics } } ast::ItemTy(ref t, ref generics) => { @@ -1462,13 +1459,13 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, // Create a new generic polytype. let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); - let t = ty::mk_enum(tcx, local_def(it.id), tcx.mk_substs(substs)); + let t = tcx.mk_enum(local_def(it.id), tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } ast::ItemStruct(_, ref generics) => { let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); - let t = ty::mk_struct(tcx, local_def(it.id), tcx.mk_substs(substs)); + let t = tcx.mk_struct(local_def(it.id), tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } ast::ItemDefaultImpl(..) | @@ -1531,12 +1528,11 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, assert!(prev_predicates.is_none()); // Debugging aid. - if ty::has_attr(tcx, local_def(it.id), "rustc_object_lifetime_default") { + if tcx.has_attr(local_def(it.id), "rustc_object_lifetime_default") { let object_lifetime_default_reprs: String = scheme.generics.types.iter() .map(|t| match t.object_lifetime_default { - Some(ty::ObjectLifetimeDefault::Specific(r)) => - r.to_string(), + ty::ObjectLifetimeDefault::Specific(r) => r.to_string(), d => format!("{:?}", d), }) .collect::>() @@ -1640,7 +1636,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, name: special_idents::type_self.name, def_id: local_def(param_id), default: None, - object_lifetime_default: None, + object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, }; ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); @@ -1693,20 +1689,20 @@ fn add_unsized_bound<'tcx>(astconv: &AstConv<'tcx>, match unbound { Some(ref tpb) => { // FIXME(#8559) currently requires the unbound to be built-in. - let trait_def_id = ty::trait_ref_to_def_id(tcx, tpb); + let trait_def_id = tcx.trait_ref_to_def_id(tpb); match kind_id { Ok(kind_id) if trait_def_id != kind_id => { tcx.sess.span_warn(span, "default bound relaxed for a type parameter, but \ this does nothing because the given bound is not \ a default. Only `?Sized` is supported"); - ty::try_add_builtin_trait(tcx, kind_id, bounds); + tcx.try_add_builtin_trait(kind_id, bounds); } _ => {} } } _ if kind_id.is_ok() => { - ty::try_add_builtin_trait(tcx, kind_id.unwrap(), bounds); + tcx.try_add_builtin_trait(kind_id.unwrap(), bounds); } // No lang item for Sized, so we can't add it as a bound. None => {} @@ -1767,7 +1763,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, for bound in ¶m.bounds { let bound_region = ast_region_to_region(ccx.tcx, bound); let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); - result.predicates.push(space, outlives.as_predicate()); + result.predicates.push(space, outlives.to_predicate()); } } @@ -1791,10 +1787,10 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, poly_trait_ref, &mut projections); - result.predicates.push(space, trait_ref.as_predicate()); + result.predicates.push(space, trait_ref.to_predicate()); for projection in &projections { - result.predicates.push(space, projection.as_predicate()); + result.predicates.push(space, projection.to_predicate()); } } @@ -1862,6 +1858,29 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, result } +fn convert_default_type_parameter<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + path: &P, + space: ParamSpace, + index: u32) + -> Ty<'tcx> +{ + let ty = ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, &path); + + for leaf_ty in ty.walk() { + if let ty::TyParam(p) = leaf_ty.sty { + if p.space == space && p.idx >= index { + span_err!(ccx.tcx.sess, path.span, E0128, + "type parameters with a default cannot use \ + forward declared identifiers"); + + return ccx.tcx.types.err + } + } + } + + ty +} + fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, ast_generics: &ast::Generics, space: ParamSpace, @@ -1876,26 +1895,9 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, None => { } } - let default = match param.default { - None => None, - Some(ref path) => { - let ty = ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, &**path); - let cur_idx = index; - - ty::walk_ty(ty, |t| { - match t.sty { - ty::TyParam(p) => if p.idx > cur_idx { - span_err!(tcx.sess, path.span, E0128, - "type parameters with a default cannot use \ - forward declared identifiers"); - }, - _ => {} - } - }); - - Some(ty) - } - }; + let default = param.default.as_ref().map( + |def| convert_default_type_parameter(ccx, def, space, index) + ); let object_lifetime_default = compute_object_lifetime_default(ccx, param.id, @@ -1925,7 +1927,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, param_id: ast::NodeId, param_bounds: &[ast::TyParamBound], where_clause: &ast::WhereClause) - -> Option + -> ty::ObjectLifetimeDefault { let inline_bounds = from_bounds(ccx, param_bounds); let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates); @@ -1933,11 +1935,12 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, .chain(where_bounds) .collect(); return if all_bounds.len() > 1 { - Some(ty::ObjectLifetimeDefault::Ambiguous) + ty::ObjectLifetimeDefault::Ambiguous + } else if all_bounds.len() == 0 { + ty::ObjectLifetimeDefault::BaseDefault } else { - all_bounds.into_iter() - .next() - .map(ty::ObjectLifetimeDefault::Specific) + ty::ObjectLifetimeDefault::Specific( + all_bounds.into_iter().next().unwrap()) }; fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, @@ -2028,8 +2031,8 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx>, let mut projections = Vec::new(); let pred = conv_poly_trait_ref(astconv, param_ty, tr, &mut projections); projections.into_iter() - .map(|p| p.as_predicate()) - .chain(Some(pred.as_predicate())) + .map(|p| p.to_predicate()) + .chain(Some(pred.to_predicate())) .collect() } ast::RegionTyParamBound(ref lifetime) => { @@ -2122,14 +2125,12 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( ast::Return(ref ty) => ty::FnConverging(ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &**ty)), ast::DefaultReturn(..) => - ty::FnConverging(ty::mk_nil(ccx.tcx)), + ty::FnConverging(ccx.tcx.mk_nil()), ast::NoReturn(..) => ty::FnDiverging }; - let t_fn = ty::mk_bare_fn( - ccx.tcx, - None, + let t_fn = ccx.tcx.mk_fn(None, ccx.tcx.mk_bare_fn(ty::BareFnTy { abi: abi, unsafety: ast::Unsafety::Unsafe, @@ -2150,7 +2151,7 @@ fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, { let types = ty_generics.types.map( - |def| ty::mk_param_from_def(ccx.tcx, def)); + |def| ccx.tcx.mk_param_from_def(def)); let regions = ty_generics.regions.map( @@ -2192,8 +2193,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( let required_type_free = liberate_early_bound_regions( tcx, body_scope, - &ty::liberate_late_bound_regions( - tcx, body_scope, &ty::Binder(required_type))); + &tcx.liberate_late_bound_regions(body_scope, &ty::Binder(required_type))); // The "base type" comes from the impl. It too may have late-bound // regions from the method. @@ -2201,8 +2201,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( let base_type_free = liberate_early_bound_regions( tcx, body_scope, - &ty::liberate_late_bound_regions( - tcx, body_scope, &ty::Binder(base_type))); + &tcx.liberate_late_bound_regions(body_scope, &ty::Binder(base_type))); debug!("required_type={:?} required_type_free={:?} \ base_type={:?} base_type_free={:?}", @@ -2211,7 +2210,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( base_type, base_type_free); - let infcx = infer::new_infer_ctxt(tcx); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); drop(::require_same_types(tcx, Some(&infcx), false, @@ -2248,7 +2247,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( * before we really have a `ParameterEnvironment` to check. */ - ty_fold::fold_regions(tcx, value, |region, _| { + ty_fold::fold_regions(tcx, value, &mut false, |region, _| { match region { ty::ReEarlyBound(data) => { let def_id = local_def(data.param_id); @@ -2267,9 +2266,9 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, impl_def_id: ast::DefId, impl_items: &[P]) { - let impl_scheme = ty::lookup_item_type(tcx, impl_def_id); - let impl_predicates = ty::lookup_predicates(tcx, impl_def_id); - let impl_trait_ref = ty::impl_trait_ref(tcx, impl_def_id); + let impl_scheme = tcx.lookup_item_type(impl_def_id); + let impl_predicates = tcx.lookup_predicates(impl_def_id); + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); // The trait reference is an input, so find all type parameters // reachable from there, to start (if this is an inherent impl, @@ -2298,7 +2297,7 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, let lifetimes_in_associated_types: HashSet<_> = impl_items.iter() - .map(|item| ty::impl_or_trait_item(tcx, local_def(item.id))) + .map(|item| tcx.impl_or_trait_item(local_def(item.id))) .filter_map(|item| match item { ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index b1580a74876c1..7844d71462cfc 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -24,7 +24,7 @@ pub enum Parameter { /// by `ty` (see RFC 447). pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>) -> Vec { let mut result = vec![]; - ty::maybe_walk_ty(ty, |t| { + ty.maybe_walk(|t| { if let ty::TyProjection(..) = t.sty { false // projections are not injective. } else { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 5a7f3026ee0dc..549c89599ecd8 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -934,6 +934,51 @@ The number of supplied parameters much exactly match the number of defined type parameters. "##, +E0088: r##" +You gave too many lifetime parameters. Erroneous code example: + +``` +fn f() {} + +fn main() { + f::<'static>() // error: too many lifetime parameters provided +} +``` + +Please check you give the right number of lifetime parameters. Example: + +``` +fn f() {} + +fn main() { + f() // ok! +} +``` + +It's also important to note that the Rust compiler can generally +determine the lifetime by itself. Example: + +``` +struct Foo { + value: String +} + +impl Foo { + // it can be written like this + fn get_value<'a>(&'a self) -> &'a str { &self.value } + // but the compiler works fine with this too: + fn without_lifetime(&self) -> &str { &self.value } +} + +fn main() { + let f = Foo { value: "hello".to_owned() }; + + println!("{}", f.get_value()); + println!("{}", f.without_lifetime()); +} +``` +"##, + E0089: r##" Not enough type parameters were supplied for a function. For example: @@ -959,6 +1004,138 @@ fn main() { ``` "##, +E0091: r##" +You gave an unnecessary type parameter in a type alias. Erroneous code +example: + +``` +type Foo = u32; // error: type parameter `T` is unused +// or: +type Foo = Box; // error: type parameter `B` is unused +``` + +Please check you didn't write too many type parameters. Example: + +``` +type Foo = u32; // ok! +type Foo = Box; // ok! +``` +"##, + +E0092: r##" +You tried to declare an undefined atomic operation function. +Erroneous code example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn atomic_foo(); // error: unrecognized atomic operation + // function +} +``` + +Please check you didn't make a mistake in the function's name. All intrinsic +functions are defined in librustc_trans/trans/intrinsic.rs and in +libcore/intrinsics.rs in the Rust source code. Example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn atomic_fence(); // ok! +} +``` +"##, + +E0093: r##" +You declared an unknown intrinsic function. Erroneous code example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn foo(); // error: unrecognized intrinsic function: `foo` +} + +fn main() { + unsafe { + foo(); + } +} +``` + +Please check you didn't make a mistake in the function's name. All intrinsic +functions are defined in librustc_trans/trans/intrinsic.rs and in +libcore/intrinsics.rs in the Rust source code. Example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn atomic_fence(); // ok! +} + +fn main() { + unsafe { + atomic_fence(); + } +} +``` +"##, + +E0094: r##" +You gave an invalid number of type parameters to an intrinsic function. +Erroneous code example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn size_of() -> usize; // error: intrinsic has wrong number + // of type parameters +} +``` + +Please check that you provided the right number of lifetime parameters +and verify with the function declaration in the Rust source code. +Example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn size_of() -> usize; // ok! +} +``` +"##, + +E0101: r##" +You hit this error because the compiler the compiler lacks information +to determine a type for this expression. Erroneous code example: + +``` +fn main() { + let x = |_| {}; // error: cannot determine a type for this expression +} +``` + +You have two possibilities to solve this situation: + * Give an explicit definition of the expression + * Infer the expression + +Examples: + +``` +fn main() { + let x = |_ : u32| {}; // ok! + // or: + let x = |_| {}; + x(0u32); +} +``` +"##, + E0106: r##" This error indicates that a lifetime is missing from a type. If it is an error inside a function signature, the problem may be with failing to adhere to the @@ -1067,6 +1244,96 @@ impl Bytes { ... } // error, same as above ``` "##, +E0117: r##" +You got this error because because you tried to implement a foreign +trait for a foreign type (with maybe a foreign type parameter). Erroneous +code example: + +``` +impl Drop for u32 {} +``` + +The type, trait or the type parameter (or all of them) has to be defined +in your crate. Example: + +``` +pub struct Foo; // you define your type in your crate + +impl Drop for Foo { // and you can implement the trait on it! + // code of trait implementation here +} + +trait Bar { // or define your trait in your crate + fn get(&self) -> usize; +} + +impl Bar for u32 { // and then you implement it on a foreign type + fn get(&self) -> usize { 0 } +} + +impl From for i32 { // or you use a type from your crate as + // a type parameter + fn from(i: Foo) -> i32 { + 0 + } +} +``` +"##, + +E0119: r##" +There are conflicting trait implementations for the same type. +Erroneous code example: + +``` +trait MyTrait { + fn get(&self) -> usize; +} + +impl MyTrait for T { + fn get(&self) -> usize { 0 } +} + +struct Foo { + value: usize +} + +impl MyTrait for Foo { // error: conflicting implementations for trait + // `MyTrait` + fn get(&self) -> usize { self.value } +} +``` + +When you write: + +``` +impl MyTrait for T { + fn get(&self) -> usize { 0 } +} +``` + +This makes the trait implemented on all types in the scope. So if you +try to implement it on another one after that, the implementations will +conflict. Example: + +``` +trait MyTrait { + fn get(&self) -> usize; +} + +impl MyTrait for T { + fn get(&self) -> usize { 0 } +} + +struct Foo; + +fn main() { + let f = Foo; + + f.get(); // the trait is implemented so we can use it +} +``` +"##, + E0121: r##" In order to be consistent with Rust's lack of global type inference, type placeholders are disallowed by design in item signatures. @@ -1080,6 +1347,27 @@ static BAR: _ = "test"; // error, explicitly write out the type instead ``` "##, +E0124: r##" +You declared two fields of a struct with the same name. Erroneous code +example: + +``` +struct Foo { + field1: i32, + field1: i32 // error: field is already declared +} +``` + +Please verify that the field names have been correctly spelled. Example: + +``` +struct Foo { + field1: i32, + field2: i32 // ok! +} +``` +"##, + E0131: r##" It is not possible to define `main` with type parameters, or even with function parameters. When `main` is present, it must take no arguments and return `()`. @@ -1187,6 +1475,43 @@ information see the [opt-in builtin traits RFC](https://github.com/rust-lang/ rfcs/blob/master/text/0019-opt-in-builtin-traits.md). "##, +E0195: r##" +Your method's lifetime parameters do not match the trait declaration. +Erroneous code example: + +``` +trait Trait { + fn bar<'a,'b:'a>(x: &'a str, y: &'b str); +} + +struct Foo; + +impl Trait for Foo { + fn bar<'a,'b>(x: &'a str, y: &'b str) { + // error: lifetime parameters or bounds on method `bar` + // do not match the trait declaration + } +} +``` + +The lifetime constraint `'b` for bar() implementation does not match the +trait declaration. Ensure lifetime declarations match exactly in both trait +declaration and implementation. Example: + +``` +trait Trait { + fn t<'a,'b:'a>(x: &'a str, y: &'b str); +} + +struct Foo; + +impl Trait for Foo { + fn t<'a,'b:'a>(x: &'a str, y: &'b str) { // ok! + } +} +``` +"##, + E0197: r##" Inherent implementations (one that do not implement a trait but provide methods associated with a type) are always safe because they are not @@ -1366,6 +1691,65 @@ impl Copy for &'static Bar { } // error ``` "##, +E0207: r##" +You declared an unused type parameter when implementing a trait on an object. +Erroneous code example: + +``` +trait MyTrait { + fn get(&self) -> usize; +} + +struct Foo; + +impl MyTrait for Foo { + fn get(&self) -> usize { + 0 + } +} +``` + +Please check your object definition and remove unused type +parameter(s). Example: + +``` +trait MyTrait { + fn get(&self) -> usize; +} + +struct Foo; + +impl MyTrait for Foo { + fn get(&self) -> usize { + 0 + } +} +``` +"##, + +E0211: r##" +You used an intrinsic function which doesn't correspond to its +definition. Erroneous code example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn size_of(); // error: intrinsic has wrong type +} +``` + +Please check the function definition. Example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn size_of() -> usize; +} +``` +"##, + E0243: r##" This error indicates that not enough type parameters were found in a type or trait. @@ -1585,23 +1969,14 @@ register_diagnostics! { E0077, E0085, E0086, - E0088, E0090, - E0091, - E0092, - E0093, - E0094, - E0101, E0102, E0103, E0104, - E0117, E0118, - E0119, E0120, E0122, E0123, - E0124, E0127, E0128, E0129, @@ -1625,15 +2000,12 @@ register_diagnostics! { E0193, // cannot bound type where clause bounds may only be attached to types // involving type parameters E0194, - E0195, // lifetime parameters or bounds on method do not match the trait declaration E0196, // cannot determine a type for this closure E0203, // type parameter has more than one relaxed default bound, // and only one is supported - E0207, // type parameter is not constrained by the impl trait, self type, or predicate E0208, E0209, // builtin traits can only be implemented on structs or enums E0210, // type parameter is not constrained by any local type - E0211, E0212, // cannot extract an associated type from a higher-ranked trait bound E0213, // associated types are not accepted in this context E0214, // parenthesized parameters may only be used with a trait @@ -1694,6 +2066,8 @@ register_diagnostics! { // `#[lang = \"{}\"]` is allowed for the `{}` primitive E0391, // unsupported cyclic reference between types/traits detected E0392, // parameter `{}` is never used - E0393 // the type parameter `{}` must be explicitly specified in an object + E0393, // the type parameter `{}` must be explicitly specified in an object // type because its default value `{}` references the type `Self`" + E0399 // trait items need to be implemented because the associated + // type `{}` was overridden } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 8feecd1561311..8c3ef4ae631c3 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -88,6 +88,7 @@ This API is completely unstable and subject to change. #![feature(slice_extras)] #![feature(staged_api)] #![feature(vec_push_all)] +#![feature(cell_extras)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -105,7 +106,7 @@ pub use rustc::util; use middle::def; use middle::infer; use middle::subst; -use middle::ty::{self, Ty}; +use middle::ty::{self, Ty, HasTypeFlags}; use rustc::ast_map; use session::config; use util::common::time; @@ -148,7 +149,7 @@ pub struct CrateCtxt<'a, 'tcx: 'a> { // Functions that write types into the node type table fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) { debug!("write_ty_to_tcx({}, {:?})", node_id, ty); - assert!(!ty::type_needs_infer(ty)); + assert!(!ty.needs_infer()); tcx.node_type_insert(node_id, ty); } @@ -160,9 +161,9 @@ fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id, item_substs); - assert!(item_substs.substs.types.all(|t| !ty::type_needs_infer(*t))); + assert!(!item_substs.substs.types.needs_infer()); - tcx.item_substs.borrow_mut().insert(node_id, item_substs); + tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs); } } @@ -187,7 +188,7 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>, { let result = match maybe_infcx { None => { - let infcx = infer::new_infer_ctxt(tcx); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); infer::mk_eqty(&infcx, t1_is_expected, infer::Misc(span), t1, t2) } Some(infcx) => { @@ -199,7 +200,7 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>, Ok(_) => true, Err(ref terr) => { span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr); - ty::note_and_explain_type_err(tcx, terr, span); + tcx.note_and_explain_type_err(terr, span); false } } @@ -209,7 +210,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, main_id: ast::NodeId, main_span: Span) { let tcx = ccx.tcx; - let main_t = ty::node_id_to_type(tcx, main_id); + let main_t = tcx.node_id_to_type(main_id); match main_t.sty { ty::TyBareFn(..) => { match tcx.map.find(main_id) { @@ -226,12 +227,12 @@ fn check_main_fn_ty(ccx: &CrateCtxt, } _ => () } - let se_ty = ty::mk_bare_fn(tcx, Some(local_def(main_id)), tcx.mk_bare_fn(ty::BareFnTy { + let se_ty = tcx.mk_fn(Some(local_def(main_id)), tcx.mk_bare_fn(ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, sig: ty::Binder(ty::FnSig { inputs: Vec::new(), - output: ty::FnConverging(ty::mk_nil(tcx)), + output: ty::FnConverging(tcx.mk_nil()), variadic: false }) })); @@ -254,7 +255,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, start_id: ast::NodeId, start_span: Span) { let tcx = ccx.tcx; - let start_t = ty::node_id_to_type(tcx, start_id); + let start_t = tcx.node_id_to_type(start_id); match start_t.sty { ty::TyBareFn(..) => { match tcx.map.find(start_id) { @@ -272,13 +273,13 @@ fn check_start_fn_ty(ccx: &CrateCtxt, _ => () } - let se_ty = ty::mk_bare_fn(tcx, Some(local_def(start_id)), tcx.mk_bare_fn(ty::BareFnTy { + let se_ty = tcx.mk_fn(Some(local_def(start_id)), tcx.mk_bare_fn(ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, sig: ty::Binder(ty::FnSig { inputs: vec!( tcx.types.isize, - ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, tcx.types.u8)) + tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8)) ), output: ty::FnConverging(tcx.types.isize), variadic: false, diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index c908e21626e56..d2c982b3099e7 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -16,6 +16,15 @@ use std::cell::Cell; use std::iter::repeat; use syntax::codemap::Span; +#[derive(Clone)] +pub struct ElisionFailureInfo { + pub name: String, + pub lifetime_count: usize, + pub have_bound_regions: bool +} + +pub type ElidedLifetime = Result>>; + /// Defines strategies for handling regions that are omitted. For /// example, if one writes the type `&Foo`, then the lifetime of /// this reference has been omitted. When converting this @@ -30,12 +39,32 @@ pub trait RegionScope { fn anon_regions(&self, span: Span, count: usize) - -> Result, Option>>; + -> Result, Option>>; /// If an object omits any explicit lifetime bound, and none can /// be derived from the object traits, what should we use? If /// `None` is returned, an explicit annotation is required. fn object_lifetime_default(&self, span: Span) -> Option; + + /// The "base" default is the initial default for a scope. This is + /// 'static except for in fn bodies, where it is a fresh inference + /// variable. You shouldn't call this except for as part of + /// computing `object_lifetime_default` (in particular, in legacy + /// modes, it may not be relevant). + fn base_object_lifetime_default(&self, span: Span) -> ty::Region; + + /// Used to issue warnings in Rust 1.2, not needed after that. + /// True if the result of `object_lifetime_default` will change in 1.3. + fn object_lifetime_default_will_change_in_1_3(&self) -> bool { + false + } + + /// Used to issue warnings in Rust 1.2, not needed after that. + /// True if the result of `base_object_lifetime_default` differs + /// from the result of `object_lifetime_default`. + fn base_object_lifetime_default_differs(&self) -> bool { + false + } } // A scope in which all regions must be explicitly named. This is used @@ -44,38 +73,46 @@ pub trait RegionScope { pub struct ExplicitRscope; impl RegionScope for ExplicitRscope { - fn object_lifetime_default(&self, _span: Span) -> Option { - Some(ty::ReStatic) - } - fn anon_regions(&self, _span: Span, _count: usize) - -> Result, Option>> { + -> Result, Option>> { Err(None) } + + fn object_lifetime_default(&self, span: Span) -> Option { + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { + ty::ReStatic + } } // Same as `ExplicitRscope`, but provides some extra information for diagnostics -pub struct UnelidableRscope(Vec<(String, usize)>); +pub struct UnelidableRscope(Option>); impl UnelidableRscope { - pub fn new(v: Vec<(String, usize)>) -> UnelidableRscope { + pub fn new(v: Option>) -> UnelidableRscope { UnelidableRscope(v) } } impl RegionScope for UnelidableRscope { - fn object_lifetime_default(&self, _span: Span) -> Option { - Some(ty::ReStatic) - } - fn anon_regions(&self, _span: Span, _count: usize) - -> Result, Option>> { + -> Result, Option>> { let UnelidableRscope(ref v) = *self; - Err(Some(v.clone())) + Err(v.clone()) + } + + fn object_lifetime_default(&self, span: Span) -> Option { + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { + ty::ReStatic } } @@ -94,17 +131,21 @@ impl ElidableRscope { } impl RegionScope for ElidableRscope { - fn object_lifetime_default(&self, _span: Span) -> Option { + fn object_lifetime_default(&self, span: Span) -> Option { // Per RFC #599, object-lifetimes default to 'static unless // overridden by context, and this takes precedence over // lifetime elision. - Some(ty::ReStatic) + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { + ty::ReStatic } fn anon_regions(&self, _span: Span, count: usize) - -> Result, Option>> + -> Result, Option>> { Ok(repeat(self.default).take(count).collect()) } @@ -131,17 +172,21 @@ impl BindingRscope { } impl RegionScope for BindingRscope { - fn object_lifetime_default(&self, _span: Span) -> Option { + fn object_lifetime_default(&self, span: Span) -> Option { // Per RFC #599, object-lifetimes default to 'static unless // overridden by context, and this takes precedence over the - // binding defaults. - Some(ty::ReStatic) + // binding defaults in a fn signature. + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { + ty::ReStatic } fn anon_regions(&self, _: Span, count: usize) - -> Result, Option>> + -> Result, Option>> { Ok((0..count).map(|_| self.next_region()).collect()) } @@ -150,12 +195,12 @@ impl RegionScope for BindingRscope { /// A scope which overrides the default object lifetime but has no other effect. pub struct ObjectLifetimeDefaultRscope<'r> { base_scope: &'r (RegionScope+'r), - default: Option, + default: ty::ObjectLifetimeDefault, } impl<'r> ObjectLifetimeDefaultRscope<'r> { pub fn new(base_scope: &'r (RegionScope+'r), - default: Option) + default: ty::ObjectLifetimeDefault) -> ObjectLifetimeDefaultRscope<'r> { ObjectLifetimeDefaultRscope { @@ -168,16 +213,56 @@ impl<'r> ObjectLifetimeDefaultRscope<'r> { impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { fn object_lifetime_default(&self, span: Span) -> Option { match self.default { - None => self.base_scope.object_lifetime_default(span), - Some(ty::ObjectLifetimeDefault::Ambiguous) => None, - Some(ty::ObjectLifetimeDefault::Specific(r)) => Some(r), + ty::ObjectLifetimeDefault::Ambiguous => + None, + + ty::ObjectLifetimeDefault::BaseDefault => + if false { // this will become the behavior in Rust 1.3 + Some(self.base_object_lifetime_default(span)) + } else { + self.base_scope.object_lifetime_default(span) + }, + + ty::ObjectLifetimeDefault::Specific(r) => + Some(r), + } + } + + fn base_object_lifetime_default(&self, span: Span) -> ty::Region { + assert!(false, "this code should not execute until Rust 1.3"); + self.base_scope.base_object_lifetime_default(span) + } + + fn object_lifetime_default_will_change_in_1_3(&self) -> bool { + debug!("object_lifetime_default_will_change_in_1_3: {:?}", self.default); + + match self.default { + ty::ObjectLifetimeDefault::Ambiguous | + ty::ObjectLifetimeDefault::Specific(_) => + false, + + ty::ObjectLifetimeDefault::BaseDefault => + self.base_scope.base_object_lifetime_default_differs() + } + } + + fn base_object_lifetime_default_differs(&self) -> bool { + debug!("base_object_lifetime_default_differs: {:?}", self.default); + + match self.default { + ty::ObjectLifetimeDefault::Ambiguous | + ty::ObjectLifetimeDefault::Specific(_) => + true, + + ty::ObjectLifetimeDefault::BaseDefault => + self.base_scope.base_object_lifetime_default_differs(), } } fn anon_regions(&self, span: Span, count: usize) - -> Result, Option>> + -> Result, Option>> { self.base_scope.anon_regions(span, count) } @@ -201,10 +286,14 @@ impl<'r> RegionScope for ShiftedRscope<'r> { .map(|r| ty_fold::shift_region(r, 1)) } + fn base_object_lifetime_default(&self, span: Span) -> ty::Region { + ty_fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1) + } + fn anon_regions(&self, span: Span, count: usize) - -> Result, Option>> + -> Result, Option>> { match self.base_scope.anon_regions(span, count) { Ok(mut v) => { diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 1f4e134365121..c1f9725fc8134 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -485,7 +485,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { param_id={}, \ inf_index={:?}, \ initial_variance={:?})", - ty::item_path_str(self.tcx, ast_util::local_def(item_id)), + self.tcx.item_path_str(ast_util::local_def(item_id)), item_id, kind, space, index, param_id, inf_index, initial_variance); } @@ -603,7 +603,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { match item.node { ast::ItemEnum(ref enum_definition, _) => { - let scheme = ty::lookup_item_type(tcx, did); + let scheme = tcx.lookup_item_type(did); // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion @@ -633,7 +633,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { } ast::ItemStruct(..) => { - let scheme = ty::lookup_item_type(tcx, did); + let scheme = tcx.lookup_item_type(did); // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion @@ -641,16 +641,16 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { // // self.add_constraints_from_generics(&scheme.generics); - let struct_fields = ty::lookup_struct_fields(tcx, did); + let struct_fields = tcx.lookup_struct_fields(did); for field_info in &struct_fields { assert_eq!(field_info.id.krate, ast::LOCAL_CRATE); - let field_ty = ty::node_id_to_type(tcx, field_info.id.node); + let field_ty = tcx.node_id_to_type(field_info.id.node); self.add_constraints_from_ty(&scheme.generics, field_ty, self.covariant); } } ast::ItemTrait(..) => { - let trait_def = ty::lookup_trait_def(tcx, did); + let trait_def = tcx.lookup_trait_def(did); self.add_constraints_from_trait_ref(&trait_def.generics, trait_def.trait_ref, self.invariant); @@ -781,7 +781,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } else { // Parameter on an item defined within another crate: // variance already inferred, just look it up. - let variances = ty::item_variances(self.tcx(), item_def_id); + let variances = self.tcx().item_variances(item_def_id); let variance = match kind { TypeParam => *variances.types.get(space, index), RegionParam => *variances.regions.get(space, index), @@ -848,7 +848,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { trait_ref, variance); - let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id); + let trait_def = self.tcx().lookup_trait_def(trait_ref.def_id); self.add_constraints_from_substs( generics, @@ -904,7 +904,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyEnum(def_id, substs) | ty::TyStruct(def_id, substs) => { - let item_type = ty::lookup_item_type(self.tcx(), def_id); + let item_type = self.tcx().lookup_item_type(def_id); // All type parameters on enums and structs should be // in the TypeSpace. @@ -924,7 +924,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyProjection(ref data) => { let trait_ref = &data.trait_ref; - let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id); + let trait_def = self.tcx().lookup_trait_def(trait_ref.def_id); self.add_constraints_from_substs( generics, trait_ref.def_id, @@ -1200,7 +1200,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { // For unit testing: check for a special "rustc_variance" // attribute and report an error with various results if found. - if ty::has_attr(tcx, item_def_id, "rustc_variance") { + if tcx.has_attr(item_def_id, "rustc_variance") { span_err!(tcx.sess, tcx.map.span(item_id), E0208, "{:?}", item_variances); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 53063c6247efb..e80fd360e04fd 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -150,9 +150,9 @@ pub fn record_extern_fqn(cx: &DocContext, did: ast::DefId, kind: clean::TypeKind pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait { - let def = ty::lookup_trait_def(tcx, did); - let trait_items = ty::trait_items(tcx, did).clean(cx); - let predicates = ty::lookup_predicates(tcx, did); + let def = tcx.lookup_trait_def(did); + let trait_items = tcx.trait_items(did).clean(cx); + let predicates = tcx.lookup_predicates(did); let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); @@ -165,12 +165,12 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt, } fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Function { - let t = ty::lookup_item_type(tcx, did); + let t = tcx.lookup_item_type(did); let (decl, style, abi) = match t.ty.sty { ty::TyBareFn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi), _ => panic!("bad function"), }; - let predicates = ty::lookup_predicates(tcx, did); + let predicates = tcx.lookup_predicates(did); clean::Function { decl: decl, generics: (&t.generics, &predicates, subst::FnSpace).clean(cx), @@ -183,9 +183,9 @@ fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Struct { use syntax::parse::token::special_idents::unnamed_field; - let t = ty::lookup_item_type(tcx, did); - let predicates = ty::lookup_predicates(tcx, did); - let fields = ty::lookup_struct_fields(tcx, did); + let t = tcx.lookup_item_type(did); + let predicates = tcx.lookup_predicates(did); + let fields = tcx.lookup_struct_fields(did); clean::Struct { struct_type: match &*fields { @@ -201,14 +201,14 @@ fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Stru } fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum { - let t = ty::lookup_item_type(tcx, did); - let predicates = ty::lookup_predicates(tcx, did); + let t = tcx.lookup_item_type(did); + let predicates = tcx.lookup_predicates(did); match t.ty.sty { ty::TyEnum(edid, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => { return clean::EnumItem(clean::Enum { generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), variants_stripped: false, - variants: ty::enum_variants(tcx, edid).clean(cx), + variants: tcx.enum_variants(edid).clean(cx), }) } _ => {} @@ -222,7 +222,7 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> Vec { - ty::populate_inherent_implementations_for_type_if_necessary(tcx, did); + tcx.populate_inherent_implementations_for_type_if_necessary(did); let mut impls = Vec::new(); match tcx.inherent_impls.borrow().get(&did) { @@ -307,16 +307,16 @@ pub fn build_impl(cx: &DocContext, }); } - let predicates = ty::lookup_predicates(tcx, did); + let predicates = tcx.lookup_predicates(did); let trait_items = csearch::get_impl_items(&tcx.sess.cstore, did) .iter() .filter_map(|did| { let did = did.def_id(); - let impl_item = ty::impl_or_trait_item(tcx, did); + let impl_item = tcx.impl_or_trait_item(did); match impl_item { ty::ConstTraitItem(ref assoc_const) => { let did = assoc_const.def_id; - let type_scheme = ty::lookup_item_type(tcx, did); + let type_scheme = tcx.lookup_item_type(did); let default = match assoc_const.default { Some(_) => Some(const_eval::lookup_const_by_id(tcx, did, None) .unwrap().span.to_src(cx)), @@ -383,7 +383,7 @@ pub fn build_impl(cx: &DocContext, } }).collect::>(); let polarity = csearch::get_impl_polarity(tcx, did); - let ty = ty::lookup_item_type(tcx, did); + let ty = tcx.lookup_item_type(did); let trait_ = associated_trait.clean(cx).map(|bound| { match bound { clean::TraitBound(polyt, _) => polyt.trait_, @@ -477,7 +477,7 @@ fn build_const(cx: &DocContext, tcx: &ty::ctxt, debug!("got snippet {}", sn); clean::Constant { - type_: ty::lookup_item_type(tcx, did).ty.clean(cx), + type_: tcx.lookup_item_type(did).ty.clean(cx), expr: sn } } @@ -486,7 +486,7 @@ fn build_static(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId, mutable: bool) -> clean::Static { clean::Static { - type_: ty::lookup_item_type(tcx, did).ty.clean(cx), + type_: tcx.lookup_item_type(did).ty.clean(cx), mutability: if mutable {clean::Mutable} else {clean::Immutable}, expr: "\n\n\n".to_string(), // trigger the "[definition]" links } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8ba4470c3efbd..c25267520ccd8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1332,7 +1332,7 @@ impl<'tcx> Clean for ty::Method<'tcx> { let provided = match self.container { ty::ImplContainer(..) => false, ty::TraitContainer(did) => { - ty::provided_trait_methods(cx.tcx(), did).iter().any(|m| { + cx.tcx().provided_trait_methods(did).iter().any(|m| { m.def_id == self.def_id }) } @@ -1742,7 +1742,7 @@ impl Clean for ty::field_ty { (Some(self.name), Some(attr_map.get(&self.id.node).unwrap())) }; - let ty = ty::lookup_item_type(cx.tcx(), self.id); + let ty = cx.tcx().lookup_item_type(self.id); Item { name: name.clean(cx), @@ -2731,8 +2731,8 @@ impl<'tcx> Clean for ty::AssociatedType<'tcx> { // are actually located on the trait/impl itself, so we need to load // all of the generics from there and then look for bounds that are // applied to this associated type in question. - let def = ty::lookup_trait_def(cx.tcx(), did); - let predicates = ty::lookup_predicates(cx.tcx(), did); + let def = cx.tcx().lookup_trait_def(did); + let predicates = cx.tcx().lookup_predicates(did); let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 2bde8d5bfb5fc..e65cdd8ff5de6 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -30,7 +30,6 @@ use std::mem; use std::collections::HashMap; use rustc::middle::subst; -use rustc::middle::ty; use syntax::ast; use clean::PathParameters as PP; @@ -154,8 +153,8 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: ast::DefId, if child == trait_ { return true } - let def = ty::lookup_trait_def(cx.tcx(), child); - let predicates = ty::lookup_predicates(cx.tcx(), child); + let def = cx.tcx().lookup_trait_def(child); + let predicates = cx.tcx().lookup_predicates(child); let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); generics.where_predicates.iter().filter_map(|pred| { match *pred { diff --git a/src/librustdoc/flock.rs b/src/librustdoc/flock.rs index 760fa329fd986..847e28d2bc510 100644 --- a/src/librustdoc/flock.rs +++ b/src/librustdoc/flock.rs @@ -68,6 +68,7 @@ mod imp { #[cfg(any(target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod os { use libc; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 0080b5e5f223f..5b0109290e6c3 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -552,7 +552,7 @@ fn write_shared(cx: &Context, // Add all the static files. These may already exist, but we just // overwrite them anyway to make sure that they're fresh and up-to-date. try!(write(cx.dst.join("jquery.js"), - include_bytes!("static/jquery-2.1.0.min.js"))); + include_bytes!("static/jquery-2.1.4.min.js"))); try!(write(cx.dst.join("main.js"), include_bytes!("static/main.js"))); try!(write(cx.dst.join("playpen.js"), include_bytes!("static/playpen.js"))); try!(write(cx.dst.join("main.css"), include_bytes!("static/main.css"))); diff --git a/src/librustdoc/html/static/jquery-2.1.0.min.js b/src/librustdoc/html/static/jquery-2.1.0.min.js deleted file mode 100644 index cbe6abe59a815..0000000000000 --- a/src/librustdoc/html/static/jquery-2.1.0.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v2.1.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m=a.document,n="2.1.0",o=function(a,b){return new o.fn.init(a,b)},p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};o.fn=o.prototype={jquery:n,constructor:o,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=o.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return o.each(this,a,b)},map:function(a){return this.pushStack(o.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},o.extend=o.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||o.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(o.isPlainObject(d)||(e=o.isArray(d)))?(e?(e=!1,f=c&&o.isArray(c)?c:[]):f=c&&o.isPlainObject(c)?c:{},g[b]=o.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},o.extend({expando:"jQuery"+(n+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===o.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isPlainObject:function(a){if("object"!==o.type(a)||a.nodeType||o.isWindow(a))return!1;try{if(a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(b){return!1}return!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=o.trim(a),a&&(1===a.indexOf("use strict")?(b=m.createElement("script"),b.text=a,m.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":k.call(a)},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?o.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),o.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||o.guid++,f):void 0},now:Date.now,support:l}),o.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=o.type(a);return"function"===c||o.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="
","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);o.find=t,o.expr=t.selectors,o.expr[":"]=o.expr.pseudos,o.unique=t.uniqueSort,o.text=t.getText,o.isXMLDoc=t.isXML,o.contains=t.contains;var u=o.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(o.isFunction(b))return o.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return o.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return o.filter(b,a,c);b=o.filter(b,a)}return o.grep(a,function(a){return g.call(b,a)>=0!==c})}o.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?o.find.matchesSelector(d,a)?[d]:[]:o.find.matches(a,o.grep(b,function(a){return 1===a.nodeType}))},o.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(o(a).filter(function(){for(b=0;c>b;b++)if(o.contains(e[b],this))return!0}));for(b=0;c>b;b++)o.find(a,e[b],d);return d=this.pushStack(c>1?o.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?o(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=o.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof o?b[0]:b,o.merge(this,o.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:m,!0)),v.test(c[1])&&o.isPlainObject(b))for(c in b)o.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=m.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=m,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):o.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(o):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),o.makeArray(a,this))};A.prototype=o.fn,y=o(m);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};o.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&o(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),o.fn.extend({has:function(a){var b=o(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(o.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?o(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&o.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?o.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(o(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(o.unique(o.merge(this.get(),o(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}o.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return o.dir(a,"parentNode")},parentsUntil:function(a,b,c){return o.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return o.dir(a,"nextSibling")},prevAll:function(a){return o.dir(a,"previousSibling")},nextUntil:function(a,b,c){return o.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return o.dir(a,"previousSibling",c)},siblings:function(a){return o.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return o.sibling(a.firstChild)},contents:function(a){return a.contentDocument||o.merge([],a.childNodes)}},function(a,b){o.fn[a]=function(c,d){var e=o.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=o.filter(d,e)),this.length>1&&(C[a]||o.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return o.each(a.match(E)||[],function(a,c){b[c]=!0}),b}o.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):o.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){o.each(b,function(b,c){var d=o.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&o.each(arguments,function(a,b){var c;while((c=o.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?o.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},o.extend({Deferred:function(a){var b=[["resolve","done",o.Callbacks("once memory"),"resolved"],["reject","fail",o.Callbacks("once memory"),"rejected"],["notify","progress",o.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return o.Deferred(function(c){o.each(b,function(b,f){var g=o.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&o.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?o.extend(a,d):d}},e={};return d.pipe=d.then,o.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&o.isFunction(a.promise)?e:0,g=1===f?a:o.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&o.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;o.fn.ready=function(a){return o.ready.promise().done(a),this},o.extend({isReady:!1,readyWait:1,holdReady:function(a){a?o.readyWait++:o.ready(!0)},ready:function(a){(a===!0?--o.readyWait:o.isReady)||(o.isReady=!0,a!==!0&&--o.readyWait>0||(H.resolveWith(m,[o]),o.fn.trigger&&o(m).trigger("ready").off("ready")))}});function I(){m.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),o.ready()}o.ready.promise=function(b){return H||(H=o.Deferred(),"complete"===m.readyState?setTimeout(o.ready):(m.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},o.ready.promise();var J=o.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===o.type(c)){e=!0;for(h in c)o.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,o.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(o(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};o.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=o.expando+Math.random()}K.uid=1,K.accepts=o.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,o.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(o.isEmptyObject(f))o.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,o.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{o.isArray(b)?d=b.concat(b.map(o.camelCase)):(e=o.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!o.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?o.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}o.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),o.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length; -while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=o.camelCase(d.slice(5)),P(f,d,e[d]));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=o.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),o.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||o.isArray(c)?d=L.access(a,b,o.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=o.queue(a,b),d=c.length,e=c.shift(),f=o._queueHooks(a,b),g=function(){o.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:o.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),o.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";l.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return m.activeElement}catch(a){}}o.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=o.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof o!==U&&o.event.triggered!==b.type?o.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n&&(l=o.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=o.event.special[n]||{},k=o.extend({type:n,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&o.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(n,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),o.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n){l=o.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||o.removeEvent(a,n,r.handle),delete i[n])}else for(n in i)o.event.remove(a,n+b[j],c,d,!0);o.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,p=[d||m],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||m,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+o.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[o.expando]?b:new o.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:o.makeArray(c,[b]),n=o.event.special[q]||{},e||!n.trigger||n.trigger.apply(d,c)!==!1)){if(!e&&!n.noBubble&&!o.isWindow(d)){for(i=n.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||m)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:n.bindType||q,l=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),l&&l.apply(g,c),l=k&&g[k],l&&l.apply&&o.acceptData(g)&&(b.result=l.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||n._default&&n._default.apply(p.pop(),c)!==!1||!o.acceptData(d)||k&&o.isFunction(d[q])&&!o.isWindow(d)&&(h=d[k],h&&(d[k]=null),o.event.triggered=q,d[q](),o.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=o.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=o.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=o.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((o.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?o(e,this).index(i)>=0:o.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return o.nodeName(a,"table")&&o.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)o.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=o.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&o.nodeName(a,b)?o.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}o.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=o.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||o.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,n=a.length;n>m;m++)if(e=a[m],e||0===e)if("object"===o.type(e))o.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;o.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===o.inArray(e,d))&&(i=o.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f,g,h=o.event.special,i=0;void 0!==(c=a[i]);i++){if(o.acceptData(c)&&(f=c[L.expando],f&&(b=L.cache[f]))){if(d=Object.keys(b.events||{}),d.length)for(g=0;void 0!==(e=d[g]);g++)h[e]?o.event.remove(c,e):o.removeEvent(c,e,b.handle);L.cache[f]&&delete L.cache[f]}delete M.cache[c[M.expando]]}}}),o.fn.extend({text:function(a){return J(this,function(a){return void 0===a?o.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?o.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||o.cleanData(ob(c)),c.parentNode&&(b&&o.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(o.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return o.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(o.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,o.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,n=k-1,p=a[0],q=o.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(c=o.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=o.map(ob(c,"script"),kb),g=f.length;k>j;j++)h=c,j!==n&&(h=o.clone(h,!0,!0),g&&o.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,o.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&o.contains(i,h)&&(h.src?o._evalUrl&&o._evalUrl(h.src):o.globalEval(h.textContent.replace(hb,"")))}return this}}),o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){o.fn[a]=function(a){for(var c,d=[],e=o(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),o(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d=o(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:o.css(d[0],"display");return d.detach(),e}function tb(a){var b=m,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||o("